diff --git a/org.springframework.context/ivy.xml b/org.springframework.context/ivy.xml
index b531ca58618..e6e58d9690c 100644
--- a/org.springframework.context/ivy.xml
+++ b/org.springframework.context/ivy.xml
@@ -46,6 +46,8 @@
+
+
diff --git a/org.springframework.context/pom.xml b/org.springframework.context/pom.xml
index 333233bcef7..aa0e30b9f49 100644
--- a/org.springframework.context/pom.xml
+++ b/org.springframework.context/pom.xml
@@ -129,6 +129,18 @@
1.6
true
+
+ org.jboss.cl
+ com.springsource.org.jboss.classloader
+ 2.0.5.GA
+ provided
+
+
+ org.jboss.util
+ com.springsource.org.jboss.util
+ 2.2.13.GA
+ provided
+
org.springframework
spring-asm
diff --git a/org.springframework.context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java b/org.springframework.context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java
index e67116c484b..78047eebafe 100644
--- a/org.springframework.context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java
+++ b/org.springframework.context/src/main/java/org/springframework/context/weaving/DefaultContextLoadTimeWeaver.java
@@ -27,6 +27,7 @@ import org.springframework.instrument.InstrumentationSavingAgent;
import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver;
+import org.springframework.instrument.classloading.jboss.JBoss5LoadTimeWeaver;
import org.springframework.instrument.classloading.glassfish.GlassFishLoadTimeWeaver;
import org.springframework.instrument.classloading.oc4j.OC4JLoadTimeWeaver;
import org.springframework.instrument.classloading.weblogic.WebLogicLoadTimeWeaver;
@@ -105,6 +106,9 @@ public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLo
else if (classLoader.getClass().getName().startsWith("com.sun.enterprise")) {
return new GlassFishLoadTimeWeaver(classLoader);
}
+ else if (classLoader.getClass().getName().startsWith("org.jboss")) {
+ return new JBoss5LoadTimeWeaver(classLoader);
+ }
}
catch (IllegalStateException ex) {
logger.info("Could not obtain server-specific LoadTimeWeaver: " + ex.getMessage());
diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/ClassFileTransformer2Translator.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/ClassFileTransformer2Translator.java
new file mode 100644
index 00000000000..b7a139cef58
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/ClassFileTransformer2Translator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2002-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.security.ProtectionDomain;
+import java.lang.instrument.ClassFileTransformer;
+
+import org.jboss.util.loading.Translator;
+
+/**
+ * ClassFileTransfomer to Translator bridge.
+ *
+ * @author Ales Justin
+ */
+public class ClassFileTransformer2Translator implements Translator {
+
+ private ClassFileTransformer transformer;
+
+ public ClassFileTransformer2Translator(ClassFileTransformer transformer) {
+ if (transformer == null) {
+ throw new IllegalArgumentException("Null transformer");
+ }
+
+ this.transformer = transformer;
+ }
+
+ public byte[] transform(ClassLoader loader,
+ String className,
+ Class> classBeingRedefined,
+ ProtectionDomain protectionDomain,
+ byte[] classfileBuffer) throws Exception {
+ return transformer.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
+ }
+
+ public void unregisterClassLoader(ClassLoader loader) {
+ }
+}
diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss50ClassLoader.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss50ClassLoader.java
new file mode 100644
index 00000000000..e520154c6bc
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss50ClassLoader.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2002-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.reflect.Method;
+
+import org.jboss.classloader.spi.ClassLoaderSystem;
+import org.jboss.classloader.spi.base.BaseClassLoader;
+import org.jboss.classloader.spi.base.BaseClassLoaderDomain;
+import org.jboss.classloader.spi.base.BaseClassLoaderPolicy;
+import org.jboss.classloader.spi.base.BaseClassLoaderSystem;
+import org.jboss.util.loading.Translator;
+
+/**
+ * Reflective wrapper around a JBoss_5.0.x class loader. Used to encapsulate the classloader-specific methods
+ * (discovered and called through reflection) from the load-time weaver.
+ *
+ * @author Ales Justin
+ */
+public class JBoss50ClassLoader extends JBoss5ClassLoader {
+
+ private Method addTranslator;
+
+ private ClassLoaderSystem system;
+
+ public JBoss50ClassLoader(BaseClassLoader classLoader) {
+ super(classLoader);
+ }
+
+ protected void fallbackStrategy() throws Exception {
+ try {
+ // let's check if we have a patched policy, with translator per policy
+ addTranslator = getMethod(BaseClassLoaderPolicy.class, "addTranslator");
+ }
+ catch (Exception ignored) {
+ //log.info("Policy doesn't have addTranslator, falling back to ClassLoaderSystem.");
+
+ Method getClassLoaderDomain = getMethod(BaseClassLoaderPolicy.class, "getClassLoaderDomain");
+ BaseClassLoaderDomain domain = invokeMethod(getClassLoaderDomain, getPolicy(), BaseClassLoaderDomain.class);
+ Method getClassLoaderSystem = getMethod(BaseClassLoaderDomain.class, "getClassLoaderSystem");
+ BaseClassLoaderSystem system = invokeMethod(getClassLoaderSystem, domain, BaseClassLoaderSystem.class);
+ if (system instanceof ClassLoaderSystem) {
+ this.system = ClassLoaderSystem.class.cast(system);
+ }
+ else {
+ throw new IllegalArgumentException(
+ "ClassLoaderSystem must be instance of [" + ClassLoaderSystem.class.getName() + "]");
+ }
+ }
+ }
+
+ protected void addTranslator(Translator translator) {
+ if (addTranslator != null) {
+ try {
+ addTranslator.invoke(translator);
+ }
+ catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+ else {
+ system.setTranslator(translator);
+ }
+ }
+}
diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss51ClassLoader.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss51ClassLoader.java
new file mode 100644
index 00000000000..a792c427248
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss51ClassLoader.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2002-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 org.jboss.classloader.spi.base.BaseClassLoader;
+import org.jboss.util.loading.Translator;
+
+/**
+ * Reflective wrapper around a JBoss_5.1.x class loader. Used to encapsulate the classloader-specific methods
+ * (discovered and called through reflection) from the load-time weaver.
+ *
+ * @author Ales Justin
+ */
+public class JBoss51ClassLoader extends JBoss5ClassLoader {
+
+ public JBoss51ClassLoader(BaseClassLoader classLoader) {
+ super(classLoader);
+ }
+
+ protected void addTranslator(Translator translator) {
+
+ getPolicy().addTranslator(translator);
+ }
+}
diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss5ClassLoader.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss5ClassLoader.java
new file mode 100644
index 00000000000..3bea1c9fae9
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss5ClassLoader.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2002-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.Method;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+
+import org.jboss.classloader.spi.ClassLoaderPolicy;
+import org.jboss.classloader.spi.base.BaseClassLoader;
+import org.jboss.util.loading.Translator;
+
+import org.springframework.util.Assert;
+import org.springframework.instrument.classloading.SimpleThrowawayClassLoader;
+
+/**
+ * Reflective wrapper around a JBoss5 class loader. Used to encapsulate the classloader-specific methods (discovered and
+ * called through reflection) from the load-time weaver.
+ *
+ * @author Ales Justin
+ * @author Marius Bogoevici
+ */
+public abstract class JBoss5ClassLoader extends ReflectionHelper {
+
+ private final BaseClassLoader classLoader;
+
+ private ClassLoaderPolicy policy;
+
+ @SuppressWarnings("unchecked")
+ protected JBoss5ClassLoader(BaseClassLoader classLoader) {
+ Assert.notNull(classLoader, "ClassLoader must not be null");
+ this.classLoader = classLoader;
+
+ try {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ AccessController.doPrivileged(new InstantiationAction());
+ }
+ else {
+ doInstantiate();
+ }
+ }
+ catch (Exception e) {
+ throw new IllegalStateException(
+ "Could not initialize JBoss ClassLoader because JBoss5 API classes are not available", e);
+ }
+ }
+
+ /**
+ * Get the policy.
+ *
+ * @return the policy
+ */
+ protected ClassLoaderPolicy getPolicy() {
+ return policy;
+ }
+
+ /**
+ * Do instantiate method, variables.
+ *
+ * @throws Exception for any error
+ */
+ private void doInstantiate() throws Exception {
+ Method getPolicy = getMethod(BaseClassLoader.class, "getPolicy");
+ policy = invokeMethod(getPolicy, classLoader, ClassLoaderPolicy.class);
+ fallbackStrategy();
+ }
+
+ /**
+ * The fallback strategy.
+ *
+ * @throws Exception for any error
+ */
+ protected void fallbackStrategy() throws Exception {
+ }
+
+ public void addTransformer(ClassFileTransformer transformer) {
+ Assert.notNull(transformer, "ClassFileTransformer must not be null");
+ Translator translator = new ClassFileTransformer2Translator(transformer);
+ addTranslator(translator);
+ }
+
+ /**
+ * Add the translator.
+ *
+ * @param translator the translator
+ */
+ protected abstract void addTranslator(Translator translator);
+
+ public ClassLoader getInternalClassLoader() {
+ return classLoader;
+ }
+
+ public ClassLoader getThrowawayClassLoader() {
+ return new SimpleThrowawayClassLoader(classLoader);
+ }
+
+ /** Instantiation action. */
+ private class InstantiationAction implements PrivilegedExceptionAction {
+
+ public Object run() throws Exception {
+ doInstantiate();
+ return null;
+ }
+ }
+}
diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss5LoadTimeWeaver.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss5LoadTimeWeaver.java
new file mode 100644
index 00000000000..6be70ce4633
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBoss5LoadTimeWeaver.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2002-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.Method;
+
+import org.jboss.classloader.spi.base.BaseClassLoader;
+
+import org.springframework.instrument.classloading.LoadTimeWeaver;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+
+/**
+ * {@link LoadTimeWeaver} implementation for JBoss5's instrumentable ClassLoader.
+ *
+ * @author Ales Justin
+ */
+public class JBoss5LoadTimeWeaver extends ReflectionHelper implements LoadTimeWeaver {
+
+ private JBoss5ClassLoader classLoader;
+
+ public JBoss5LoadTimeWeaver() {
+ this(ClassUtils.getDefaultClassLoader());
+ }
+
+ public JBoss5LoadTimeWeaver(ClassLoader classLoader) {
+ Assert.notNull(classLoader, "ClassLoader must not be null");
+ BaseClassLoader bcl = determineClassLoader(classLoader);
+ if (bcl == null) {
+ throw new IllegalArgumentException(
+ classLoader + " and its parents are not suitable ClassLoaders: " + "An [" +
+ BaseClassLoader.class.getName() + "] implementation is required.");
+ }
+ this.classLoader = createClassLoaderWrapper(bcl);
+ }
+
+ /**
+ * Create a JBoss5 classloader wrapper based on the underlying JBossAS version.
+ *
+ * @param bcl the base classloader
+ * @return new JBoss5 classloader wrapper
+ */
+ protected JBoss5ClassLoader createClassLoaderWrapper(BaseClassLoader bcl) {
+ int versionNumber = 0;
+ String tag;
+
+ try {
+ // BCL should see Version class
+ Class> versionClass = bcl.loadClass("org.jboss.Version");
+ Method getInstance = getMethod(versionClass, "getInstance");
+ Object version = getInstance.invoke(null); // static method
+
+ Method getMajor = getMethod(versionClass, "getMajor");
+ versionNumber += 100 * invokeMethod(getMajor, version, Integer.class);
+ Method getMinor = getMethod(versionClass, "getMinor");
+ versionNumber += 10 * invokeMethod(getMinor, version, Integer.class);
+ Method getRevision = getMethod(versionClass, "getRevision");
+ versionNumber += invokeMethod(getRevision, version, Integer.class);
+ Method getTag = getMethod(versionClass, "getTag");
+ tag = invokeMethod(getTag, version, String.class);
+ }
+ catch (Exception e) {
+ //log.warn("Exception creating JBoss5 CL wrapper: " + e + ", falling back to JBoss50ClassLoader wrapper.");
+ return new JBoss50ClassLoader(bcl);
+ }
+
+ if (versionNumber < 500) // this only works on new MC code
+ {
+ throw new IllegalArgumentException(
+ "JBoss5LoadTimeWeaver can only be used on new JBoss Microcontainer ClassLoader.");
+ }
+ else if (versionNumber <= 501 || (versionNumber == 510 && "Beta1".equals(tag))) {
+ return new JBoss50ClassLoader(bcl);
+ }
+ else {
+ return new JBoss51ClassLoader(bcl);
+ }
+ }
+
+ /**
+ * Find first BaseClassLoader implementation.
+ *
+ * @param classLoader the classloader
+ * @return BaseClassLoader instance or null if not found
+ */
+ private BaseClassLoader determineClassLoader(ClassLoader classLoader) {
+ for (ClassLoader cl = classLoader; cl != null; cl = cl.getParent()) {
+ if (cl instanceof BaseClassLoader) {
+ return (BaseClassLoader) cl;
+ }
+ }
+ return null;
+ }
+
+ public void addTransformer(ClassFileTransformer transformer) {
+ classLoader.addTransformer(transformer);
+ }
+
+ public ClassLoader getInstrumentableClassLoader() {
+ return classLoader.getInternalClassLoader();
+ }
+
+ public ClassLoader getThrowawayClassLoader() {
+ return classLoader.getThrowawayClassLoader();
+ }
+}
diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/ReflectionHelper.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/ReflectionHelper.java
new file mode 100644
index 00000000000..a882bbdc2df
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/ReflectionHelper.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2002-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.reflect.Method;
+
+/**
+ * Reflection helper.
+ *
+ * @author Ales Justin
+ */
+public abstract class ReflectionHelper {
+
+ /**
+ * Get method from class.
+ *
+ * @param clazz the owner class
+ * @param name the method name
+ * @return declared method
+ * @throws Exception for any error
+ */
+ protected static Method getMethod(Class> clazz, String name) throws Exception {
+ Method method = clazz.getDeclaredMethod(name);
+ method.setAccessible(true);
+ return method;
+ }
+
+ /**
+ * Invoke method and check the result.
+ *
+ * @param method the method
+ * @param target the target
+ * @param expectedType the expected type
+ * @param the exact type
+ * @return invocation's result
+ * @throws Exception for any error
+ */
+ protected static T invokeMethod(Method method, Object target, Class expectedType) throws Exception {
+ Object result = method.invoke(target);
+ if (expectedType.isInstance(result) == false) {
+ throw new IllegalArgumentException("Returned result must be instance of [" + expectedType.getName() + "]");
+ }
+
+ return expectedType.cast(result);
+ }
+}
diff --git a/org.springframework.context/template.mf b/org.springframework.context/template.mf
index 24eaeaf47d4..99980952a81 100644
--- a/org.springframework.context/template.mf
+++ b/org.springframework.context/template.mf
@@ -30,6 +30,8 @@ Import-Template:
org.aspectj.weaver.*;version="[1.5.4, 2.0.0)";resolution:=optional,
org.codehaus.groovy.*;version="[1.5.0, 2.0.0)";resolution:=optional,
org.joda.*;version="[1.6.0, 2.0.0)";resolution:=optional,
+ org.jboss.classloader.*;version="[2.0.5, 3.0.0)";resolution:=optional,
+ org.jboss.util.*;version="[2.2.13, 3.0.0)";resolution:=optional,
org.jruby.*;version="[1.1.0, 2.0.0)";resolution:=optional,
org.omg.CORBA.*;version="0";resolution:=optional,
org.springframework.aop.*;version="[3.0.0, 3.0.1)";resolution:=optional,