diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossClassLoaderAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossClassLoaderAdapter.java index b6f6fb4931..3fefc04ab3 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossClassLoaderAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossClassLoaderAdapter.java @@ -1,144 +1,32 @@ /* - * Copyright 2006-2009 the original author or authors. - * + * Copyright 2011 the original author or authors. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.instrument.classloading.jboss; import java.lang.instrument.ClassFileTransformer; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -import org.springframework.util.Assert; -import org.springframework.util.ReflectionUtils; /** - * Reflective wrapper around a JBoss 5 class loader methods (discovered and called - * through reflection) for load time weaving. + * Simple interface used for handling the different JBoss class loader adapters. * * @author Costin Leau */ -class JBossClassLoaderAdapter { +interface JBossClassLoaderAdapter { - private static final String TRANSLATOR_NAME = "org.jboss.util.loading.Translator"; - private static final String POLICY_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderPolicy"; - private static final String DOMAIN_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderDomain"; - private static final String DEDICATED_SYSTEM = "org.jboss.classloader.spi.ClassLoaderSystem"; - private static final String LOADER_NAME = "org.jboss.classloader.spi.base.BaseClassLoader"; - private static final String GET_POLICY = "getPolicy"; - private static final String GET_DOMAIN = "getClassLoaderDomain"; - private static final String GET_SYSTEM = "getClassLoaderSystem"; + void addTransformer(ClassFileTransformer transformer); - // available since JBoss AS 5.1.0 / MC 2.0.6 (allows multiple transformers to be added) - private static final String ADD_TRANSLATOR_NAME = "addTranslator"; - // available since JBoss AS 5.0.0 / MC 2.0.1 (allows only one transformer to be added) - private static final String SET_TRANSLATOR_NAME = "setTranslator"; + ClassLoader getInstrumentableClassLoader(); - private final ClassLoader classLoader; - private final Class> translatorClass; - - private final Method addTranslator; - private final Object target; - - JBossClassLoaderAdapter(ClassLoader classLoader) { - Class> clazzLoaderType = null; - try { - // resolve BaseClassLoader.class - clazzLoaderType = classLoader.loadClass(LOADER_NAME); - - ClassLoader clazzLoader = null; - // walk the hierarchy to detect the instrumentation aware classloader - for (ClassLoader cl = classLoader; cl != null && clazzLoader == null; cl = cl.getParent()) { - if (clazzLoaderType.isInstance(cl)) { - clazzLoader = cl; - } - } - - if (clazzLoader == null) { - throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: " - + "A [" + LOADER_NAME + "] implementation is required."); - } - - this.classLoader = clazzLoader; - // use the classloader that loaded the classloader to load - // the types for reflection purposes - classLoader = clazzLoader.getClass().getClassLoader(); - - // BaseClassLoader#getPolicy - Method method = clazzLoaderType.getDeclaredMethod(GET_POLICY); - ReflectionUtils.makeAccessible(method); - Object policy = method.invoke(this.classLoader); - - Object addTarget = null; - Method addMethod = null; - - // try the 5.1.x hooks - // check existence of BaseClassLoaderPolicy#addTranslator(Translator) - this.translatorClass = classLoader.loadClass(TRANSLATOR_NAME); - Class> clazz = classLoader.loadClass(POLICY_NAME); - try { - addMethod = clazz.getDeclaredMethod(ADD_TRANSLATOR_NAME, translatorClass); - addTarget = policy; - } catch (NoSuchMethodException ex) { - } - - // fall back to 5.0.x method - if (addMethod == null) { - - // BaseClassLoaderPolicy#getClassLoaderDomain - method = clazz.getDeclaredMethod(GET_DOMAIN); - ReflectionUtils.makeAccessible(method); - Object domain = method.invoke(policy); - - // BaseClassLoaderDomain#getClassLoaderSystem - clazz = classLoader.loadClass(DOMAIN_NAME); - method = clazz.getDeclaredMethod(GET_SYSTEM); - ReflectionUtils.makeAccessible(method); - Object system = method.invoke(domain); - - // resolve ClassLoaderSystem - clazz = classLoader.loadClass(DEDICATED_SYSTEM); - Assert.isInstanceOf(clazz, system, "JBoss LoadTimeWeaver requires JBoss loader system of type " - + clazz.getName() + " on JBoss 5.0.x"); - - // ClassLoaderSystem#setTranslator - addMethod = clazz.getDeclaredMethod(SET_TRANSLATOR_NAME, translatorClass); - addTarget = system; - } - - this.addTranslator = addMethod; - this.target = addTarget; - - } catch (Exception ex) { - throw new IllegalStateException( - "Could not initialize JBoss LoadTimeWeaver because the JBoss 5 API classes are not available", ex); - } - } - - public void addTransformer(ClassFileTransformer transformer) { - InvocationHandler adapter = new JBossTranslatorAdapter(transformer); - Object adapterInstance = Proxy.newProxyInstance(this.translatorClass.getClassLoader(), - new Class[] { this.translatorClass }, adapter); - - try { - addTranslator.invoke(target, adapterInstance); - } catch (Exception ex) { - throw new IllegalStateException("Could not add transformer on JBoss classloader " + classLoader, ex); - } - } - - public ClassLoader getClassLoader() { - return classLoader; - } -} \ No newline at end of file +} diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java index dbe14654dc..008deb56c3 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java @@ -25,6 +25,7 @@ import org.springframework.util.ClassUtils; /** * {@link LoadTimeWeaver} implementation for JBoss's instrumentable ClassLoader. + * Currently supports JBoss 5, 6 and 7 (since Spring 3.1). * *
NOTE: Requires JBoss AS version 5.0.0 or higher. *
NOTE: On JBoss 6.0.0, to avoid the container loading the classes before
@@ -41,8 +42,7 @@ import org.springframework.util.ClassUtils;
*/
public class JBossLoadTimeWeaver implements LoadTimeWeaver {
- private final JBossClassLoaderAdapter classLoader;
-
+ private final JBossClassLoaderAdapter adapter;
/**
* Create a new instance of the {@link JBossLoadTimeWeaver} class using
@@ -61,16 +61,25 @@ public class JBossLoadTimeWeaver implements LoadTimeWeaver {
*/
public JBossLoadTimeWeaver(ClassLoader classLoader) {
Assert.notNull(classLoader, "ClassLoader must not be null");
- this.classLoader = new JBossClassLoaderAdapter(classLoader);
+ String loaderClassName = classLoader.getClass().getName();
+
+ if (loaderClassName.startsWith("org.jboss.classloader")) {
+ // JBoss AS 5 or JBoss AS 6
+ this.adapter = new JBossMCAdapter(classLoader);
+ } else if (loaderClassName.startsWith("org.jboss.modules")) {
+ // JBoss AS 7
+ this.adapter = new JBossModulesAdapter(classLoader);
+ } else {
+ throw new IllegalArgumentException("Unexpected classloader type: " + loaderClassName);
+ }
}
-
public void addTransformer(ClassFileTransformer transformer) {
- this.classLoader.addTransformer(transformer);
+ this.adapter.addTransformer(transformer);
}
public ClassLoader getInstrumentableClassLoader() {
- return this.classLoader.getClassLoader();
+ return this.adapter.getInstrumentableClassLoader();
}
public ClassLoader getThrowawayClassLoader() {
diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCAdapter.java
new file mode 100644
index 0000000000..ec4ca6db09
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCAdapter.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2006-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.instrument.classloading.jboss;
+
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.springframework.util.Assert;
+import org.springframework.util.ReflectionUtils;
+
+/**
+ * Reflective wrapper around a JBoss 5 and 6 class loader methods (discovered and called
+ * through reflection) for load time weaving.
+ *
+ * @author Costin Leau
+ */
+class JBossMCAdapter implements JBossClassLoaderAdapter {
+
+ private static final String TRANSLATOR_NAME = "org.jboss.util.loading.Translator";
+ private static final String POLICY_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderPolicy";
+ private static final String DOMAIN_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderDomain";
+ private static final String DEDICATED_SYSTEM = "org.jboss.classloader.spi.ClassLoaderSystem";
+ private static final String LOADER_NAME = "org.jboss.classloader.spi.base.BaseClassLoader";
+ private static final String GET_POLICY = "getPolicy";
+ private static final String GET_DOMAIN = "getClassLoaderDomain";
+ private static final String GET_SYSTEM = "getClassLoaderSystem";
+
+ // available since JBoss AS 5.1.0 / MC 2.0.6 (allows multiple transformers to be added)
+ private static final String ADD_TRANSLATOR_NAME = "addTranslator";
+ // available since JBoss AS 5.0.0 / MC 2.0.1 (allows only one transformer to be added)
+ private static final String SET_TRANSLATOR_NAME = "setTranslator";
+
+ private final ClassLoader classLoader;
+ private final Class> translatorClass;
+
+ private final Method addTranslator;
+ private final Object target;
+
+ JBossMCAdapter(ClassLoader classLoader) {
+ Class> clazzLoaderType = null;
+ try {
+ // resolve BaseClassLoader.class
+ clazzLoaderType = classLoader.loadClass(LOADER_NAME);
+
+ ClassLoader clazzLoader = null;
+ // walk the hierarchy to detect the instrumentation aware classloader
+ for (ClassLoader cl = classLoader; cl != null && clazzLoader == null; cl = cl.getParent()) {
+ if (clazzLoaderType.isInstance(cl)) {
+ clazzLoader = cl;
+ }
+ }
+
+ if (clazzLoader == null) {
+ throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: "
+ + "A [" + LOADER_NAME + "] implementation is required.");
+ }
+
+ this.classLoader = clazzLoader;
+ // use the classloader that loaded the classloader to load
+ // the types for reflection purposes
+ classLoader = clazzLoader.getClass().getClassLoader();
+
+ // BaseClassLoader#getPolicy
+ Method method = clazzLoaderType.getDeclaredMethod(GET_POLICY);
+ ReflectionUtils.makeAccessible(method);
+ Object policy = method.invoke(this.classLoader);
+
+ Object addTarget = null;
+ Method addMethod = null;
+
+ // try the 5.1.x hooks
+ // check existence of BaseClassLoaderPolicy#addTranslator(Translator)
+ this.translatorClass = classLoader.loadClass(TRANSLATOR_NAME);
+ Class> clazz = classLoader.loadClass(POLICY_NAME);
+ try {
+ addMethod = clazz.getDeclaredMethod(ADD_TRANSLATOR_NAME, translatorClass);
+ addTarget = policy;
+ } catch (NoSuchMethodException ex) {
+ }
+
+ // fall back to 5.0.x method
+ if (addMethod == null) {
+
+ // BaseClassLoaderPolicy#getClassLoaderDomain
+ method = clazz.getDeclaredMethod(GET_DOMAIN);
+ ReflectionUtils.makeAccessible(method);
+ Object domain = method.invoke(policy);
+
+ // BaseClassLoaderDomain#getClassLoaderSystem
+ clazz = classLoader.loadClass(DOMAIN_NAME);
+ method = clazz.getDeclaredMethod(GET_SYSTEM);
+ ReflectionUtils.makeAccessible(method);
+ Object system = method.invoke(domain);
+
+ // resolve ClassLoaderSystem
+ clazz = classLoader.loadClass(DEDICATED_SYSTEM);
+ Assert.isInstanceOf(clazz, system, "JBoss LoadTimeWeaver requires JBoss loader system of type "
+ + clazz.getName() + " on JBoss 5.0.x");
+
+ // ClassLoaderSystem#setTranslator
+ addMethod = clazz.getDeclaredMethod(SET_TRANSLATOR_NAME, translatorClass);
+ addTarget = system;
+ }
+
+ this.addTranslator = addMethod;
+ this.target = addTarget;
+
+ } catch (Exception ex) {
+ throw new IllegalStateException(
+ "Could not initialize JBoss LoadTimeWeaver because the JBoss 5 API classes are not available", ex);
+ }
+ }
+
+ public void addTransformer(ClassFileTransformer transformer) {
+ InvocationHandler adapter = new JBossMCTranslatorAdapter(transformer);
+ Object adapterInstance = Proxy.newProxyInstance(this.translatorClass.getClassLoader(),
+ new Class[] { this.translatorClass }, adapter);
+
+ try {
+ addTranslator.invoke(target, adapterInstance);
+ } catch (Exception ex) {
+ throw new IllegalStateException("Could not add transformer on JBoss 5/6 classloader " + classLoader, ex);
+ }
+ }
+
+ public ClassLoader getInstrumentableClassLoader() {
+ return classLoader;
+ }
+}
\ No newline at end of file
diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossTranslatorAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCTranslatorAdapter.java
similarity index 90%
rename from org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossTranslatorAdapter.java
rename to org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCTranslatorAdapter.java
index 6b134afa18..4b65878cd6 100644
--- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossTranslatorAdapter.java
+++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCTranslatorAdapter.java
@@ -29,16 +29,16 @@ import java.security.ProtectionDomain;
*
* @author Costin Leau
*/
-class JBossTranslatorAdapter implements InvocationHandler {
+class JBossMCTranslatorAdapter implements InvocationHandler {
private final ClassFileTransformer transformer;
/**
- * Creates a new {@link JBossTranslatorAdapter}.
+ * Creates a new {@link JBossMCTranslatorAdapter}.
* @param transformer the {@link ClassFileTransformer} to be adapted (must
* not be null)
*/
- public JBossTranslatorAdapter(ClassFileTransformer transformer) {
+ public JBossMCTranslatorAdapter(ClassFileTransformer transformer) {
this.transformer = transformer;
}
diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossModulesAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossModulesAdapter.java
new file mode 100644
index 0000000000..a03889d104
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossModulesAdapter.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.instrument.classloading.jboss;
+
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import org.springframework.util.Assert;
+import org.springframework.util.ReflectionUtils;
+
+/**
+ * JBoss 7 Adapter.
+ *
+ * @author Costin Leau
+ */
+class JBossModulesAdapter implements JBossClassLoaderAdapter {
+
+ private static final String TRANSFORMER_FIELD_NAME = "transformer";
+ private static final String TRANSFORMER_ADD_METHOD_NAME = "addTransformer";
+ private static final String DELEGATING_TRANSFORMER_CLASS_NAME = "org.jboss.as.server.deployment.module.DelegatingClassFileTransformer";
+ private final ClassLoader classLoader;
+ private final Method addTransformer;
+ private final Object delegatingTransformer;
+
+ public JBossModulesAdapter(ClassLoader loader) {
+ this.classLoader = loader;
+
+ try {
+ Field transformers = ReflectionUtils.findField(classLoader.getClass(), TRANSFORMER_FIELD_NAME);
+ transformers.setAccessible(true);
+
+ delegatingTransformer = transformers.get(classLoader);
+
+ Assert.state(delegatingTransformer.getClass().getName().equals(DELEGATING_TRANSFORMER_CLASS_NAME),
+ "Transformer not of the expected type: " + delegatingTransformer.getClass().getName());
+ addTransformer = ReflectionUtils.findMethod(delegatingTransformer.getClass(), TRANSFORMER_ADD_METHOD_NAME,
+ ClassFileTransformer.class);
+ addTransformer.setAccessible(true);
+ } catch (Exception ex) {
+ throw new IllegalStateException("Could not initialize JBoss 7 LoadTimeWeaver", ex);
+ }
+ }
+
+ public void addTransformer(ClassFileTransformer transformer) {
+ try {
+ addTransformer.invoke(delegatingTransformer, transformer);
+ } catch (Exception ex) {
+ throw new IllegalStateException("Could not add transformer on JBoss 7 classloader " + classLoader, ex);
+ }
+ }
+
+ public ClassLoader getInstrumentableClassLoader() {
+ return classLoader;
+ }
+}
\ No newline at end of file