]> source.dussan.org Git - aspectj.git/commitdiff
Fix for 122580 "Circularity Failure for Verbose Loading on JRockit 1.4.2_08 Agent"
authormwebster <mwebster>
Fri, 9 Jun 2006 10:56:50 +0000 (10:56 +0000)
committermwebster <mwebster>
Fri, 9 Jun 2006 10:56:50 +0000 (10:56 +0000)
1. New JRockitAgent
2. New lib/ext/jrocket/jrockit.jar for dependencies
3. New JRockitAgent tests

lib/ext/jrockit/jrockit-src.zip [new file with mode: 0644]
lib/ext/jrockit/jrockit.jar [new file with mode: 0644]
loadtime/.classpath
loadtime/src/org/aspectj/weaver/loadtime/Aj.java
loadtime/src/org/aspectj/weaver/loadtime/JRockitAgent.java
loadtime/testsrc/LoadtimeModuleTests.java
loadtime/testsrc/org/aspectj/bea/jvm/ClassLibraryImpl.java [new file with mode: 0644]
loadtime/testsrc/org/aspectj/bea/jvm/JVMImpl.java [new file with mode: 0644]
loadtime/testsrc/org/aspectj/weaver/loadtime/JRockitAgentTest.java [new file with mode: 0644]

diff --git a/lib/ext/jrockit/jrockit-src.zip b/lib/ext/jrockit/jrockit-src.zip
new file mode 100644 (file)
index 0000000..dce223d
Binary files /dev/null and b/lib/ext/jrockit/jrockit-src.zip differ
diff --git a/lib/ext/jrockit/jrockit.jar b/lib/ext/jrockit/jrockit.jar
new file mode 100644 (file)
index 0000000..0395fce
Binary files /dev/null and b/lib/ext/jrockit/jrockit.jar differ
index cbc24de0f6ffed5a8b1005048ec5a24f182ecdb8..6883ab9e0295a8bb7f02ed3cabee4ad179f5a69f 100644 (file)
@@ -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>
index fd045c3e677d63878304017147beaef4d8aa76f4..5c83361355b3b4a5c08c4cc5452c98800eede6b9 100644 (file)
@@ -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();
index 3d29089bd2e542f20699480aa9c75468258c3435..667b74e04d3a5048a13f5cdb9f7edf38650835bd 100644 (file)
@@ -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
+}
index ba89bb113611c8287bf81ddb25a8ba14ea14f657..fe0ef33389ef086e204f33206fc1f6c713f5a9f8 100644 (file)
@@ -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 (file)
index 0000000..8b4c584
--- /dev/null
@@ -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 (file)
index 0000000..caae32e
--- /dev/null
@@ -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 (file)
index 0000000..a3fd2cd
--- /dev/null
@@ -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;
+               }
+       }
+}