diff options
author | mwebster <mwebster> | 2006-06-09 10:56:50 +0000 |
---|---|---|
committer | mwebster <mwebster> | 2006-06-09 10:56:50 +0000 |
commit | 75afb31e38f75e61de5c15058d3332f3dac0df15 (patch) | |
tree | bf0be856748d641f3dfcc0d49f80524c8d65b6a3 /loadtime | |
parent | 4db50ddb1edbae0baa447a22eb18b1c60e26d5a5 (diff) | |
download | aspectj-75afb31e38f75e61de5c15058d3332f3dac0df15.tar.gz aspectj-75afb31e38f75e61de5c15058d3332f3dac0df15.zip |
Fix for 122580 "Circularity Failure for Verbose Loading on JRockit 1.4.2_08 Agent"
1. New JRockitAgent
2. New lib/ext/jrocket/jrockit.jar for dependencies
3. New JRockitAgent tests
Diffstat (limited to 'loadtime')
-rw-r--r-- | loadtime/.classpath | 2 | ||||
-rw-r--r-- | loadtime/src/org/aspectj/weaver/loadtime/Aj.java | 2 | ||||
-rw-r--r-- | loadtime/src/org/aspectj/weaver/loadtime/JRockitAgent.java | 129 | ||||
-rw-r--r-- | loadtime/testsrc/LoadtimeModuleTests.java | 2 | ||||
-rw-r--r-- | loadtime/testsrc/org/aspectj/bea/jvm/ClassLibraryImpl.java | 29 | ||||
-rw-r--r-- | loadtime/testsrc/org/aspectj/bea/jvm/JVMImpl.java | 24 | ||||
-rw-r--r-- | loadtime/testsrc/org/aspectj/weaver/loadtime/JRockitAgentTest.java | 199 |
7 files changed, 324 insertions, 63 deletions
diff --git a/loadtime/.classpath b/loadtime/.classpath index cbc24de0f..6883ab9e0 100644 --- a/loadtime/.classpath +++ b/loadtime/.classpath @@ -7,11 +7,11 @@ <classpathentry combineaccessrules="false" kind="src" path="/bridge"/> <classpathentry combineaccessrules="false" kind="src" path="/util"/> <classpathentry combineaccessrules="false" kind="src" path="/weaver"/> - <classpathentry kind="lib" path="/lib/ext/jrockit/managementapi-jrockit81.jar"/> <classpathentry sourcepath="/lib/junit/junit-src.jar" kind="lib" path="/lib/junit/junit.jar"/> <classpathentry kind="lib" path="/lib/ant/lib/xml-apis.jar"/> <classpathentry kind="lib" path="/lib/ant/lib/xercesImpl.jar"/> <classpathentry combineaccessrules="false" kind="src" path="/testing-util"/> <classpathentry sourcepath="/lib/bcel/bcel-src.zip" kind="lib" path="/lib/bcel/bcel.jar"/> + <classpathentry kind="lib" path="/lib/ext/jrockit/jrockit.jar"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/loadtime/src/org/aspectj/weaver/loadtime/Aj.java b/loadtime/src/org/aspectj/weaver/loadtime/Aj.java index fd045c3e6..5c8336135 100644 --- a/loadtime/src/org/aspectj/weaver/loadtime/Aj.java +++ b/loadtime/src/org/aspectj/weaver/loadtime/Aj.java @@ -63,7 +63,7 @@ public class Aj implements ClassPreProcessor { return bytes; } return weavingAdaptor.weaveClass(className, bytes); - } catch (Throwable t) { + } catch (Exception t) { //FIXME AV wondering if we should have the option to fail (throw runtime exception) here // would make sense at least in test f.e. see TestHelper.handleMessage() t.printStackTrace(); diff --git a/loadtime/src/org/aspectj/weaver/loadtime/JRockitAgent.java b/loadtime/src/org/aspectj/weaver/loadtime/JRockitAgent.java index 3d29089bd..667b74e04 100644 --- a/loadtime/src/org/aspectj/weaver/loadtime/JRockitAgent.java +++ b/loadtime/src/org/aspectj/weaver/loadtime/JRockitAgent.java @@ -1,77 +1,84 @@ /******************************************************************************* - * Copyright (c) 2005 Contributors. - * All rights reserved. - * This program and the accompanying materials are made available - * under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution and is available at - * http://eclipse.org/legal/epl-v10.html + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Alexandre Vasseur initial implementation (derivative from AspectWerkz) + * Matthew Webster - initial implementation *******************************************************************************/ package org.aspectj.weaver.loadtime; +import java.util.Stack; + +import com.bea.jvm.ClassLibrary; import com.bea.jvm.JVMFactory; -import com.jrockit.management.rmp.RmpSocketListener; /** - * JRockit (tested with 7SP4 and 8.1) preprocessor Adapter based on JMAPI <p/>JRockit has a low - * level API for hooking ClassPreProcessor, allowing the use of online weaving at full speed. - * Moreover, JRockit does not allow java.lang.ClassLoader overriding thru -Xbootclasspath/p option. - * <p/>The ClassPreProcessor - * implementation and all third party jars CAN reside in the standard classpath. <p/>The command - * line will look like: - * <code>"%JAVA_COMMAND%" -Xmanagement:class=org.aspectj.weaver.loadtime.JRockitAgent -cp ...</code> - * Note: there can be some NoClassDefFoundError due to classpath limitation - as described in - * http://edocs.bea.com/wls/docs81/adminguide/winservice.html <p/>In order to use the BEA JRockit - * management server (for further connection of management console or runtime analyzer), the regular - * option -Xmanagement will not have any effect prior to JRockit 8.1 SP2. Instead, use <code>-Dmanagement</code>. - * - * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> + * BEA JRocket JMAPI agent. + * + * Use "-Xmanagement:class=org.aspectj.weaver.loadtime.JRockitAgent" */ public class JRockitAgent implements com.bea.jvm.ClassPreProcessor { - /** - * Concrete preprocessor - */ - private final static ClassPreProcessor s_preProcessor; + private ClassPreProcessor preProcessor; + + /* + * This is used to implement the recursion protection offered by JVMTI + * but not by JRockit JMAPI. I we are called to preProcess a class while + * already preProcessing another we will return immediately + */ + private static ThreadLocalStack stack = new ThreadLocalStack(); + + + public JRockitAgent () { + this.preProcessor = new Aj(); + + ClassLibrary cl = JVMFactory.getJVM().getClassLibrary(); + cl.setClassPreProcessor(this); + } + + public byte[] preProcess(ClassLoader loader, String className, byte[] bytes) { + byte[] newBytes = bytes; + + if (stack.empty()) { + stack.push(className); + newBytes = preProcessor.preProcess(className, bytes, loader); + stack.pop(); + } + + return newBytes; + } - private static boolean START_RMP_SERVER = false; + private static class ThreadLocalStack extends ThreadLocal { - static { - START_RMP_SERVER = System.getProperties().containsKey("management"); - try { - s_preProcessor = new Aj(); - s_preProcessor.initialize(); - } catch (Exception e) { - throw new ExceptionInInitializerError("could not initialize JRockitAgent preprocessor due to: " + e.toString()); - } - } + public boolean empty () { + Stack stack = (Stack)get(); + return stack.empty(); + } - /** - * The JMAPI ClassPreProcessor must be self registrating - */ - public JRockitAgent() { - if (START_RMP_SERVER) { - // the management server will be spawned in a new thread - /*RmpSocketListener management = */new RmpSocketListener(); - } - JVMFactory.getJVM().getClassLibrary().setClassPreProcessor(this); - } + public Object peek () { + Object obj = null; + Stack stack = (Stack)get(); + if (!stack.empty()) obj = stack.peek(); + return obj; + } + + public void push (Object obj) { + Stack stack = (Stack)get(); + if (!stack.empty() && obj == stack.peek()) throw new RuntimeException(obj.toString()); + stack.push(obj); + } + + public Object pop () { + Stack stack = (Stack)get(); + return stack.pop(); + } + + protected Object initialValue() { + return new Stack(); + } + } - /** - * Weave a class - * - * @param caller classloader - * @param name of the class to weave - * @param bytecode original - * @return bytecode weaved - */ - public byte[] preProcess(ClassLoader caller, String name, byte[] bytecode) { - if (caller == null || caller.getParent() == null) { - return bytecode; - } else { - return s_preProcessor.preProcess(name, bytecode, caller); - } - } -}
\ No newline at end of file +} diff --git a/loadtime/testsrc/LoadtimeModuleTests.java b/loadtime/testsrc/LoadtimeModuleTests.java index ba89bb113..fe0ef3338 100644 --- a/loadtime/testsrc/LoadtimeModuleTests.java +++ b/loadtime/testsrc/LoadtimeModuleTests.java @@ -15,6 +15,7 @@ import junit.framework.Test; import junit.framework.TestSuite; import junit.textui.TestRunner; +import org.aspectj.weaver.loadtime.JRockitAgentTest; import org.aspectj.weaver.loadtime.WeavingURLClassLoaderTest; import org.aspectj.weaver.loadtime.test.DocumentParserTest; @@ -28,6 +29,7 @@ public class LoadtimeModuleTests extends TestCase { suite.addTestSuite(DocumentParserTest.class); suite.addTestSuite(WeavingURLClassLoaderTest.class); + suite.addTestSuite(JRockitAgentTest.class); return suite; } diff --git a/loadtime/testsrc/org/aspectj/bea/jvm/ClassLibraryImpl.java b/loadtime/testsrc/org/aspectj/bea/jvm/ClassLibraryImpl.java new file mode 100644 index 000000000..8b4c58446 --- /dev/null +++ b/loadtime/testsrc/org/aspectj/bea/jvm/ClassLibraryImpl.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthew Webster - initial implementation + *******************************************************************************/ +package org.aspectj.bea.jvm; + +import com.bea.jvm.ClassLibrary; +import com.bea.jvm.ClassPreProcessor; +import com.bea.jvm.NotAvailableException; + +public class ClassLibraryImpl implements ClassLibrary { + + private ClassPreProcessor preProcessor; + + public ClassPreProcessor getClassPreProcessor() throws NotAvailableException { + return preProcessor; + } + + public void setClassPreProcessor(ClassPreProcessor classPreProcessor) { + this.preProcessor = classPreProcessor; + } + +} diff --git a/loadtime/testsrc/org/aspectj/bea/jvm/JVMImpl.java b/loadtime/testsrc/org/aspectj/bea/jvm/JVMImpl.java new file mode 100644 index 000000000..caae32e6f --- /dev/null +++ b/loadtime/testsrc/org/aspectj/bea/jvm/JVMImpl.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthew Webster - initial implementation + *******************************************************************************/ +package org.aspectj.bea.jvm; + +import com.bea.jvm.ClassLibrary; +import com.bea.jvm.JVM; + +public class JVMImpl implements JVM { + + private ClassLibrary libarary = new ClassLibraryImpl(); + + public ClassLibrary getClassLibrary() { + return libarary; + } + +} diff --git a/loadtime/testsrc/org/aspectj/weaver/loadtime/JRockitAgentTest.java b/loadtime/testsrc/org/aspectj/weaver/loadtime/JRockitAgentTest.java new file mode 100644 index 000000000..a3fd2cd10 --- /dev/null +++ b/loadtime/testsrc/org/aspectj/weaver/loadtime/JRockitAgentTest.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Matthew Webster - initial implementation + *******************************************************************************/ +package org.aspectj.weaver.loadtime; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; + +import com.bea.jvm.ClassPreProcessor; +import com.bea.jvm.JVMFactory; + +import junit.framework.TestCase; + +public class JRockitAgentTest extends TestCase { + + protected void setUp() throws Exception { + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testJRockitAgent() { + ClassPreProcessor preProcessor = new JRockitAgent(); + ClassPreProcessor expectedPreProcessor = JVMFactory.getJVM().getClassLibrary().getClassPreProcessor(); + assertEquals("JRocketAgent must be registered",expectedPreProcessor,preProcessor); + } + + public void testPreProcess() { + ClassPreProcessor preProcessor = new JRockitAgent(); + preProcessor.preProcess(null,"foo.Bar",new byte[] {}); + } + + public void testJrockitRecursionProtection () { + URLClassLoader thisLoader = (URLClassLoader)getClass().getClassLoader(); + try { + ClassLoader loader = new JRockitClassLoader(thisLoader); + Class clazz; + + clazz = Class.forName("java.lang.Object",false,loader); + clazz = Class.forName("junit.framework.TestCase",false,loader); + } + catch (Exception ex) { + ex.printStackTrace(); + fail(ex.toString()); + } + } + + private class JRockitClassLoader extends ClassLoader { + + public final static boolean debug = false; + + private List path = new LinkedList(); +// private com.bea.jvm.ClassPreProcessor agent; + private Object agent; + private Method preProcess; + + public JRockitClassLoader (URLClassLoader clone) throws Exception { + /* Use extensions loader */ + super(clone.getParent()); + + URL[] urls = clone.getURLs(); + for (int i = 0; i < urls.length; i++) { + Object pathElement; + URL url = urls[i]; + File file = new File(url.getFile()); + if (debug) System.out.println("JRockitClassLoader.JRockitClassLoader() file" + file); + if (file.isDirectory()) pathElement = file; + else if (file.getName().endsWith(".jar")) pathElement = new JarFile(file); + else throw new RuntimeException(file.getAbsolutePath().toString()); + path.add(pathElement); + } + + Class agentClazz = Class.forName("org.aspectj.weaver.loadtime.JRockitAgent",false,this); + Object obj = agentClazz.newInstance(); + if (debug) System.out.println("JRockitClassLoader.JRockitClassLoader() obj=" + obj); + this.agent = obj; + byte[] bytes = new byte[] {}; + Class[] parameterTypes = new Class[] { java.lang.ClassLoader.class, java.lang.String.class, bytes.getClass() }; + preProcess = agentClazz.getMethod("preProcess",parameterTypes); + } + + protected Class findClass(String name) throws ClassNotFoundException { + if (debug) System.out.println("> JRockitClassLoader.findClass() name=" + name); + Class clazz = null; + try { + clazz = super.findClass(name); + } + catch (ClassNotFoundException ex) { + for (Iterator i = path.iterator(); clazz == null && i.hasNext();) { + byte[] classBytes = null; + try { + Object pathElement = i.next(); + if (pathElement instanceof File) { + File dir = (File)pathElement; + String className = name.replace('.','/') + ".class"; + File classFile = new File(dir,className); + if (classFile.exists()) classBytes = loadClassFromFile(name,classFile); + } + else { + JarFile jar = (JarFile)pathElement; + String className = name.replace('.','/') + ".class"; + ZipEntry entry = jar.getEntry(className); + if (entry != null) classBytes = loadBytesFromZipEntry(jar,entry); + } + + if (classBytes != null) { + clazz = defineClass(name,classBytes); + } + } + catch (IOException ioException) { + ex.printStackTrace(); + } + } + } + + if (debug) System.out.println("< JRockitClassLoader.findClass() name=" + name); + return clazz; + } + + private Class defineClass (String name, byte[] bytes) { + if (debug) System.out.println("> JRockitClassLoader.defineClass() name=" + name); + try { + if (agent != null) preProcess.invoke(agent,new Object[] { this, name, bytes }); + } + catch (IllegalAccessException iae) { + iae.printStackTrace(); + throw new ClassFormatError(iae.getMessage()); + } + catch (InvocationTargetException ite) { + ite.printStackTrace(); + throw new ClassFormatError(ite.getTargetException().getMessage()); + } + if (debug) System.out.println("< JRockitClassLoader.defineClass() name=" + name); + return super.defineClass(name,bytes,0,bytes.length); + } + + private byte[] loadClassFromFile (String name, File file) throws IOException { + if (debug) System.out.println("JRockitClassLoader.loadClassFromFile() file=" + file); + + byte[] bytes; + bytes = new byte[(int)file.length()]; + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + bytes = readBytes(fis,bytes); + } + finally { + if (fis != null) fis.close(); + } + + return bytes; + } + + private byte[] loadBytesFromZipEntry (JarFile jar, ZipEntry entry) throws IOException { + if (debug) System.out.println("JRockitClassLoader.loadBytesFromZipEntry() entry=" + entry); + + byte[] bytes; + bytes = new byte[(int)entry.getSize()]; + InputStream is = null; + try { + is = jar.getInputStream(entry); + bytes = readBytes(is,bytes); + } + finally { + if (is != null) is.close(); + } + + return bytes; + } + + private byte[] readBytes (InputStream is, byte[] bytes) throws IOException { + for (int offset = 0; offset < bytes.length;) { + int read = is.read(bytes,offset,bytes.length - offset); + offset += read; + } + return bytes; + } + } +} |