From ab5e4a4ff39161bff450cdc38d870a9381389fbe Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Thu, 19 Nov 2009 20:28:16 +0000 Subject: [PATCH] SPR-6333 SPR-6393 + eliminated compile-time dependency on oc4j classes --- org.springframework.context/.classpath | 5 +- org.springframework.context/context.iml | 29 --- org.springframework.context/ivy.xml | 5 - org.springframework.context/pom.xml | 18 -- .../oc4j/OC4JClassLoaderAdapter.java | 88 +++++++++ .../oc4j/OC4JClassPreprocessorAdapter.java | 176 ++++++++++-------- .../classloading/oc4j/OC4JLoadTimeWeaver.java | 17 +- 7 files changed, 190 insertions(+), 148 deletions(-) create mode 100644 org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassLoaderAdapter.java diff --git a/org.springframework.context/.classpath b/org.springframework.context/.classpath index e084c31e49..e20db25fcd 100644 --- a/org.springframework.context/.classpath +++ b/org.springframework.context/.classpath @@ -11,7 +11,6 @@ - @@ -38,8 +37,6 @@ - - - + diff --git a/org.springframework.context/context.iml b/org.springframework.context/context.iml index f614880199..a4669adde7 100644 --- a/org.springframework.context/context.iml +++ b/org.springframework.context/context.iml @@ -98,15 +98,6 @@ - - - - - - - - - @@ -127,26 +118,6 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/org.springframework.context/ivy.xml b/org.springframework.context/ivy.xml index 45c5950d70..465cdc42f3 100644 --- a/org.springframework.context/ivy.xml +++ b/org.springframework.context/ivy.xml @@ -30,7 +30,6 @@ - @@ -46,10 +45,6 @@ - diff --git a/org.springframework.context/pom.xml b/org.springframework.context/pom.xml index aa0e30b9f4..3e8d86b82d 100644 --- a/org.springframework.context/pom.xml +++ b/org.springframework.context/pom.xml @@ -15,12 +15,6 @@ - - com.oracle.oc4j - com.springsource.oracle.classloader - 10.1.3.1 - provided - com.sun.enterprise com.springsource.com.sun.enterprise.loader @@ -129,18 +123,6 @@ 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/instrument/classloading/oc4j/OC4JClassLoaderAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassLoaderAdapter.java new file mode 100644 index 0000000000..d67d9550cf --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassLoaderAdapter.java @@ -0,0 +1,88 @@ +/* + * 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.oc4j; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import org.springframework.util.Assert; + +/** + * Reflective wrapper around a OC4J class loader. Used to + * encapsulate the classloader-specific methods (discovered and + * called through reflection) from the load-time weaver. + * + * @author Costin Leau + */ +class OC4JClassLoaderAdapter { + + private static final String CL_UTILS = "oracle.classloader.util.ClassLoaderUtilities"; + private static final String PREPROCESS_UTILS = "oracle.classloader.util.ClassPreprocessor"; + + private final ClassLoader classLoader; + private final Class processorClass; + private final Method addTransformer; + private final Method copy; + + public OC4JClassLoaderAdapter(ClassLoader classLoader) { + try { + // Since OC4J 10.1.3's PolicyClassLoader is going to be removed, + // we rely on the ClassLoaderUtilities API instead. + Class utilClass = classLoader.loadClass(CL_UTILS); + this.processorClass = classLoader.loadClass(PREPROCESS_UTILS); + + this.addTransformer = utilClass.getMethod("addPreprocessor", new Class[] { ClassLoader.class, + this.processorClass }); + this.copy = utilClass.getMethod("copy", new Class[] { ClassLoader.class }); + + } catch (Exception ex) { + throw new IllegalStateException( + "Could not initialize OC4J LoadTimeWeaver because OC4J API classes are not available", ex); + } + + this.classLoader = classLoader; + } + + public void addTransformer(ClassFileTransformer transformer) { + Assert.notNull(transformer, "ClassFileTransformer must not be null"); + try { + OC4JClassPreProcessorAdapter adapter = new OC4JClassPreProcessorAdapter(transformer); + Object adapterInstance = Proxy.newProxyInstance(this.processorClass.getClassLoader(), + new Class[] { this.processorClass }, adapter); + this.addTransformer.invoke(null, new Object[] { this.classLoader, adapterInstance }); + } catch (InvocationTargetException ex) { + throw new IllegalStateException("OC4J addPreprocessor method threw exception", ex.getCause()); + } catch (Exception ex) { + throw new IllegalStateException("Could not invoke OC4J addPreprocessor method", ex); + } + } + + public ClassLoader getClassLoader() { + return this.classLoader; + } + + public ClassLoader getThrowawayClassLoader() { + try { + return (ClassLoader) this.copy.invoke(null, new Object[] { this.classLoader }); + } catch (InvocationTargetException ex) { + throw new IllegalStateException("OC4J copy method failed", ex.getCause()); + } catch (Exception ex) { + throw new IllegalStateException("Could not copy OC4J classloader", ex); + } + } +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapter.java index 4368bd16f1..0ba3179060 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapter.java @@ -1,81 +1,95 @@ -/* - * Copyright 2002-2006 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.oc4j; - -import oracle.classloader.util.ClassPreprocessor; -import org.springframework.util.Assert; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.instrument.IllegalClassFormatException; -import java.security.ProtectionDomain; - -/** - * {@link ClassPreprocessor} adapter for OC4J, delegating to a standard - * JDK {@link ClassFileTransformer} underneath. - * - *

Many thanks to Mike Keith - * for his assistance. - * - * @author Costin Leau - * @since 2.0 - */ -class OC4JClassPreprocessorAdapter implements ClassPreprocessor { - - private final ClassFileTransformer transformer; - - - /** - * Creates a new instance of the {@link OC4JClassPreprocessorAdapter} class. - * @param transformer the {@link ClassFileTransformer} to be adapted (must not be null) - * @throws IllegalArgumentException if the supplied transformer is null - */ - public OC4JClassPreprocessorAdapter(ClassFileTransformer transformer) { - Assert.notNull(transformer, "Transformer must not be null"); - this.transformer = transformer; - } - - - public ClassPreprocessor initialize(ClassLoader loader) { - return this; - } - - public byte[] processClass(String className, byte origClassBytes[], int offset, int length, ProtectionDomain pd, - ClassLoader loader) { - try { - byte[] tempArray = new byte[length]; - System.arraycopy(origClassBytes, offset, tempArray, 0, length); - - // NB: OC4J passes className as "." without class while the - // transformer expects a VM, "/" format - byte[] result = this.transformer.transform(loader, className.replace('.', '/'), null, pd, tempArray); - return (result != null ? result : origClassBytes); - } - catch (IllegalClassFormatException ex) { - throw new IllegalStateException("Cannot transform because of illegal class format", ex); - } - } - - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(getClass().getName()); - builder.append(" for transformer: "); - builder.append(this.transformer); - return builder.toString(); - } - -} +/* + * 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.oc4j; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.security.ProtectionDomain; + +/** + * Adapter that implements OC4J ClassPreProcessor interface, delegating to a + * standard JDK {@link ClassFileTransformer} underneath. + * + *

To avoid compile time checks again the vendor API, a dynamic proxy is + * being used. + * + * @author Costin Leau + */ +class OC4JClassPreProcessorAdapter implements InvocationHandler { + + private final ClassFileTransformer transformer; + + /** + * Creates a new {@link OC4JClassPreProcessorAdapter}. + * @param transformer the {@link ClassFileTransformer} to be adapted (must + * not be null) + */ + public OC4JClassPreProcessorAdapter(ClassFileTransformer transformer) { + this.transformer = transformer; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String name = method.getName(); + + if ("equals".equals(name)) { + return (Boolean.valueOf(proxy == args[0])); + } else if ("hashCode".equals(name)) { + return hashCode(); + } else if ("toString".equals(name)) { + return toString(); + } else if ("initialize".equals(name)) { + initialize(proxy, (ClassLoader) args[0]); + return null; + } else if ("processClass".equals(name)) { + return processClass((String) args[0], (byte[]) args[1], (Integer) args[2], (Integer) args[3], + (ProtectionDomain) args[4], (ClassLoader) args[5]); + } else { + throw new IllegalArgumentException("Unknown method: " + method); + } + } + + // maps to oracle.classloader.util.ClassPreprocessor#initialize + // the proxy is passed since it implements the Oracle interface which + // is asked as a return type + public Object initialize(Object proxy, ClassLoader loader) { + return proxy; + } + + public byte[] processClass(String className, byte origClassBytes[], int offset, int length, ProtectionDomain pd, + ClassLoader loader) { + try { + byte[] tempArray = new byte[length]; + System.arraycopy(origClassBytes, offset, tempArray, 0, length); + + // NB: OC4J passes className as "." without class while the + // transformer expects a VM, "/" format + byte[] result = this.transformer.transform(loader, className.replace('.', '/'), null, pd, tempArray); + return (result != null ? result : origClassBytes); + } catch (IllegalClassFormatException ex) { + throw new IllegalStateException("Cannot transform because of illegal class format", ex); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(getClass().getName()); + builder.append(" for transformer: "); + builder.append(this.transformer); + return builder.toString(); + } +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JLoadTimeWeaver.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JLoadTimeWeaver.java index 656debd767..4a6dd449d7 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JLoadTimeWeaver.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JLoadTimeWeaver.java @@ -18,8 +18,6 @@ package org.springframework.instrument.classloading.oc4j; import java.lang.instrument.ClassFileTransformer; -import oracle.classloader.util.ClassLoaderUtilities; - import org.springframework.instrument.classloading.LoadTimeWeaver; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -38,8 +36,7 @@ import org.springframework.util.ClassUtils; */ public class OC4JLoadTimeWeaver implements LoadTimeWeaver { - private final ClassLoader classLoader; - + private final OC4JClassLoaderAdapter classLoader; /** * Creates a new instance of thie {@link OC4JLoadTimeWeaver} class @@ -49,7 +46,7 @@ public class OC4JLoadTimeWeaver implements LoadTimeWeaver { public OC4JLoadTimeWeaver() { this(ClassUtils.getDefaultClassLoader()); } - + /** * Creates a new instance of the {@link OC4JLoadTimeWeaver} class * using the supplied {@link ClassLoader}. @@ -57,23 +54,21 @@ public class OC4JLoadTimeWeaver implements LoadTimeWeaver { */ public OC4JLoadTimeWeaver(ClassLoader classLoader) { Assert.notNull(classLoader, "ClassLoader must not be null"); - this.classLoader = classLoader; + this.classLoader = new OC4JClassLoaderAdapter(classLoader); } - public void addTransformer(ClassFileTransformer transformer) { Assert.notNull(transformer, "Transformer must not be null"); // Since OC4J 10.1.3's PolicyClassLoader is going to be removed, // we rely on the ClassLoaderUtilities API instead. - OC4JClassPreprocessorAdapter processor = new OC4JClassPreprocessorAdapter(transformer); - ClassLoaderUtilities.addPreprocessor(this.classLoader, processor); + classLoader.addTransformer(transformer); } public ClassLoader getInstrumentableClassLoader() { - return this.classLoader; + return classLoader.getClassLoader(); } public ClassLoader getThrowawayClassLoader() { - return ClassLoaderUtilities.copy(this.classLoader); + return classLoader.getThrowawayClassLoader(); } } \ No newline at end of file -- GitLab