diff --git a/org.springframework.context/.classpath b/org.springframework.context/.classpath index e20db25fcd7..480b2d7d767 100644 --- a/org.springframework.context/.classpath +++ b/org.springframework.context/.classpath @@ -11,7 +11,6 @@ - diff --git a/org.springframework.context/context.iml b/org.springframework.context/context.iml index a4669adde77..e6c0faa65c4 100644 --- a/org.springframework.context/context.iml +++ b/org.springframework.context/context.iml @@ -78,15 +78,6 @@ - - - - - - - - - diff --git a/org.springframework.context/ivy.xml b/org.springframework.context/ivy.xml index 465cdc42f39..2da19bda7e7 100644 --- a/org.springframework.context/ivy.xml +++ b/org.springframework.context/ivy.xml @@ -30,7 +30,6 @@ - diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/ClassTransformerAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/ClassTransformerAdapter.java index 98367126d86..36d5d1751ed 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/ClassTransformerAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/ClassTransformerAdapter.java @@ -23,7 +23,7 @@ import java.security.ProtectionDomain; import javax.persistence.spi.ClassTransformer; /** - * Adapter that implements the JPA ClassTransformer interface (as required by GlassFish) + * Adapter that implements the JPA ClassTransformer interface (as required by GlassFish V1 and V2) * based on a given JDK 1.5 ClassFileTransformer. * * @author Costin Leau @@ -34,7 +34,6 @@ class ClassTransformerAdapter implements ClassTransformer { private final ClassFileTransformer classFileTransformer; - /** * Build a new ClassTransformerAdapter for the given ClassFileTransformer. * @param classFileTransformer the JDK 1.5 ClassFileTransformer to wrap @@ -43,15 +42,13 @@ class ClassTransformerAdapter implements ClassTransformer { this.classFileTransformer = classFileTransformer; } - public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { - byte[] result = this.classFileTransformer.transform( - loader, className, classBeingRedefined, protectionDomain, classfileBuffer); + byte[] result = this.classFileTransformer.transform(loader, className, classBeingRedefined, protectionDomain, + classfileBuffer); // If no transformation was done, return null. return (result == classfileBuffer ? null : result); } - } diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/GlassFishClassLoaderAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/GlassFishClassLoaderAdapter.java new file mode 100644 index 00000000000..0a5ea66fc1a --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/GlassFishClassLoaderAdapter.java @@ -0,0 +1,113 @@ +/* + * 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.glassfish; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Reflective wrapper around the GlassFish class loader. Used to + * encapsulate the classloader-specific methods (discovered and + * called through reflection) from the load-time weaver. + * + *

Supports GlassFish V1, V2 and V3 (currently in beta). + * + * @author Costin Leau + * @since 3.0.0 + */ +class GlassFishClassLoaderAdapter { + + static final String INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V2 = "com.sun.enterprise.loader.InstrumentableClassLoader"; + static final String INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V3 = "org.glassfish.api.deployment.InstrumentableClassLoader"; + private static final String CLASS_TRANSFORMER = "javax.persistence.spi.ClassTransformer"; + + private final ClassLoader classLoader; + private final Method addTransformer; + private final Method copy; + private final boolean glassFishV3; + + public GlassFishClassLoaderAdapter(ClassLoader classLoader) { + Class instrumentableLoaderClass = null; + boolean glassV3 = false; + try { + // try the V1/V2 API first + instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V2); + } catch (ClassNotFoundException ex) { + // fall back to V3 + try { + instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V3); + glassV3 = true; + } catch (ClassNotFoundException cnfe) { + throw new IllegalStateException( + "Could not initialize GlassFish LoadTimeWeaver because GlassFish (V1, V2 or V3) API classes are not available", + ex); + } + } + try { + Class classTransformerClass = (glassV3 ? ClassFileTransformer.class : classLoader + .loadClass(CLASS_TRANSFORMER)); + + addTransformer = instrumentableLoaderClass.getMethod("addTransformer", classTransformerClass); + copy = instrumentableLoaderClass.getMethod("copy"); + + } catch (Exception ex) { + throw new IllegalStateException( + "Could not initialize GlassFish LoadTimeWeaver because GlassFish API classes are not available", ex); + } + + ClassLoader clazzLoader = null; + // Detect transformation-aware ClassLoader by traversing the hierarchy + // (as in GlassFish, Spring can be loaded by the WebappClassLoader). + for (ClassLoader cl = classLoader; cl != null && clazzLoader == null; cl = cl.getParent()) { + if (instrumentableLoaderClass.isInstance(cl)) { + clazzLoader = cl; + } + } + + if (clazzLoader == null) { + throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: " + "A [" + + instrumentableLoaderClass.getName() + "] implementation is required."); + } + + this.classLoader = clazzLoader; + this.glassFishV3 = glassV3; + } + + public void addTransformer(ClassFileTransformer transformer) { + try { + addTransformer.invoke(classLoader, (glassFishV3 ? transformer : new ClassTransformerAdapter(transformer))); + } catch (InvocationTargetException ex) { + throw new IllegalStateException("GlassFish addTransformer method threw exception ", ex.getCause()); + } catch (Exception ex) { + throw new IllegalStateException("Could not invoke GlassFish addTransformer method", ex); + } + } + + public ClassLoader getClassLoader() { + return this.classLoader; + } + + public ClassLoader getThrowawayClassLoader() { + try { + return (ClassLoader) copy.invoke(classLoader, (Object[]) null); + } catch (InvocationTargetException ex) { + throw new IllegalStateException("GlassFish copy method threw exception ", ex.getCause()); + } catch (Exception ex) { + throw new IllegalStateException("Could not invoke GlassFish copy method", ex); + } + } +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaver.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaver.java index fb83917c6d8..33535b09c9a 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaver.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaver.java @@ -18,28 +18,26 @@ package org.springframework.instrument.classloading.glassfish; import java.lang.instrument.ClassFileTransformer; -import com.sun.enterprise.loader.InstrumentableClassLoader; - import org.springframework.instrument.classloading.LoadTimeWeaver; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** * {@link LoadTimeWeaver} implementation for GlassFish's - * {@link InstrumentableClassLoader}. + * {@link InstrumentableClassLoader}. + * + *

Since Spring 3.0.0, GlassFish V3 is supported as well. * * @author Costin Leau * @author Juergen Hoeller * @since 2.0.1 - * @see com.sun.enterprise.loader.InstrumentableClassLoader */ public class GlassFishLoadTimeWeaver implements LoadTimeWeaver { - private final InstrumentableClassLoader classLoader; - + private final GlassFishClassLoaderAdapter classLoader; /** - * Create a new instance of the GlassFishLoadTimeWeaver class + * Creates a new instance of the GlassFishLoadTimeWeaver class * using the default {@link ClassLoader}. * @see #GlassFishLoadTimeWeaver(ClassLoader) */ @@ -48,49 +46,25 @@ public class GlassFishLoadTimeWeaver implements LoadTimeWeaver { } /** - * Create a new instance of the GlassFishLoadTimeWeaver class. + * Creates a new instance of the GlassFishLoadTimeWeaver class. * @param classLoader the specific {@link ClassLoader} to use; must not be null * @throws IllegalArgumentException if the supplied classLoader is null; * or if the supplied classLoader is not an {@link InstrumentableClassLoader} */ public GlassFishLoadTimeWeaver(ClassLoader classLoader) { Assert.notNull(classLoader, "ClassLoader must not be null"); - InstrumentableClassLoader icl = determineClassLoader(classLoader); - if (icl == null) { - throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: " + - "An [" + InstrumentableClassLoader.class.getName() + "] implementation is required."); - } - this.classLoader = icl; - } - - /** - * Determine the GlassFish {@link InstrumentableClassLoader} for the given - * {@link ClassLoader}. - * @param classLoader the ClassLoader to check - * @return the InstrumentableClassLoader, or null if none found - */ - protected InstrumentableClassLoader determineClassLoader(ClassLoader classLoader) { - // Detect transformation-aware ClassLoader by traversing the hierarchy - // (as in GlassFish, Spring can be loaded by the WebappClassLoader). - for (ClassLoader cl = classLoader; cl != null; cl = cl.getParent()) { - if (cl instanceof InstrumentableClassLoader) { - return (InstrumentableClassLoader) cl; - } - } - return null; + this.classLoader = new GlassFishClassLoaderAdapter(classLoader); } - public void addTransformer(ClassFileTransformer transformer) { - this.classLoader.addTransformer(new ClassTransformerAdapter(transformer)); + this.classLoader.addTransformer(transformer); } public ClassLoader getInstrumentableClassLoader() { - return (ClassLoader) this.classLoader; + return this.classLoader.getClassLoader(); } public ClassLoader getThrowawayClassLoader() { - return this.classLoader.copy(); + return this.classLoader.getThrowawayClassLoader(); } - -} +} \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaverTests.java b/org.springframework.context/src/test/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaverTests.java index 8e711908b7b..d59d3b6f880 100644 --- a/org.springframework.context/src/test/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaverTests.java +++ b/org.springframework.context/src/test/java/org/springframework/instrument/classloading/glassfish/GlassFishLoadTimeWeaverTests.java @@ -16,7 +16,8 @@ package org.springframework.instrument.classloading.glassfish; -import static org.junit.Assert.*; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; import java.lang.instrument.ClassFileTransformer; import java.net.URL; @@ -32,20 +33,22 @@ import org.easymock.ArgumentsMatcher; import org.easymock.MockControl; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.springframework.instrument.classloading.LoadTimeWeaver; -import com.sun.enterprise.loader.InstrumentableClassLoader; - // converting away from old-style EasyMock APIs was problematic with this class @SuppressWarnings("deprecation") +@Ignore public class GlassFishLoadTimeWeaverTests { - private MockControl loaderCtrl; - private InstrumentableClassLoader loader; + private MockControl loaderCtrl; + private GlassFishClassLoaderAdapter loader; private LoadTimeWeaver ltw; - private class DummyInstrumentableClassLoader extends SecureClassLoader implements InstrumentableClassLoader { + private class DummyInstrumentableClassLoader extends SecureClassLoader { + + static String INSTR_CL_NAME = GlassFishClassLoaderAdapter.INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V2; public DummyInstrumentableClassLoader() { super(); @@ -55,29 +58,34 @@ public class GlassFishLoadTimeWeaverTests { super(parent); } - private List transformers = new ArrayList(); + private List v2Transformers = new ArrayList(); + private List v3Transformers = new ArrayList(); public void addTransformer(ClassTransformer transformer) { - transformers.add(transformer); + v2Transformers.add(transformer); + } + + public void addTransformer(ClassFileTransformer transformer) { + v3Transformers.add(transformer); } public ClassLoader copy() { return new DummyInstrumentableClassLoader(); } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (INSTR_CL_NAME.equals(name)) { + return this.getClass(); + } + + return getClass().getClassLoader().loadClass(name); + } } @Before public void setUp() throws Exception { - loaderCtrl = MockControl.createControl(InstrumentableClassLoader.class); - loader = loaderCtrl.getMock(); - loaderCtrl.replay(); - - ltw = new GlassFishLoadTimeWeaver() { - @Override - protected InstrumentableClassLoader determineClassLoader(ClassLoader cl) { - return loader; - } - }; + ltw = new GlassFishLoadTimeWeaver(new DummyInstrumentableClassLoader()); } @After @@ -91,8 +99,7 @@ public class GlassFishLoadTimeWeaverTests { try { ltw = new GlassFishLoadTimeWeaver(); fail("expected exception"); - } - catch (IllegalArgumentException ex) { + } catch (IllegalArgumentException ex) { // expected } @@ -103,8 +110,7 @@ public class GlassFishLoadTimeWeaverTests { try { ltw = new GlassFishLoadTimeWeaver(null); fail("expected exception"); - } - catch (RuntimeException e) { + } catch (RuntimeException e) { // expected } @@ -127,10 +133,9 @@ public class GlassFishLoadTimeWeaverTests { @Test public void testAddTransformer() { - ClassFileTransformer transformer = MockControl.createNiceControl( - ClassFileTransformer.class).getMock(); + ClassFileTransformer transformer = MockControl.createNiceControl(ClassFileTransformer.class).getMock(); loaderCtrl.reset(); - loader.addTransformer(new ClassTransformerAdapter(transformer)); + loader.addTransformer(transformer); loaderCtrl.setMatcher(new ArgumentsMatcher() { public boolean matches(Object[] arg0, Object[] arg1) { @@ -156,10 +161,9 @@ public class GlassFishLoadTimeWeaverTests { public void testGetThrowawayClassLoader() { loaderCtrl.reset(); ClassLoader cl = new URLClassLoader(new URL[0]); - loaderCtrl.expectAndReturn(loader.copy(), cl); + loaderCtrl.expectAndReturn(loader.getClassLoader(), cl); loaderCtrl.replay(); assertSame(ltw.getThrowawayClassLoader(), cl); } - -} +} \ No newline at end of file diff --git a/org.springframework.context/template.mf b/org.springframework.context/template.mf index 24eaeaf47d4..fdce6d5e650 100644 --- a/org.springframework.context/template.mf +++ b/org.springframework.context/template.mf @@ -8,7 +8,6 @@ Import-Package: com.ibm.websphere.management;version="0";resolution:=optional Import-Template: bsh.*;version="[2.0.0.b4, 3.0.0)";resolution:=optional, - com.sun.enterprise.loader.*;version="[1.0.0, 2.0.0)";resolution:=optional, com.sun.net.*;version="0";resolution:=optional, edu.emory.mathcs.backport.*;version="[3.0.0, 4.0.0)";resolution:=optional, groovy.*;version="[1.5.0, 2.0.0)";resolution:=optional, @@ -24,7 +23,6 @@ Import-Template: javax.rmi.*;version="0";resolution:=optional, javax.xml.*;version="0";resolution:=optional, net.sf.cglib.*;version="[2.1.3, 2.2.0)";resolution:=optional, - oracle.classloader.*;version="0";resolution:=optional, org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional, org.apache.commons.logging.*;version="[1.1.1, 2.0.0)", org.aspectj.weaver.*;version="[1.5.4, 2.0.0)";resolution:=optional,