From 75afb31e38f75e61de5c15058d3332f3dac0df15 Mon Sep 17 00:00:00 2001 From: mwebster Date: Fri, 9 Jun 2006 10:56:50 +0000 Subject: [PATCH] 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 --- lib/ext/jrockit/jrockit-src.zip | Bin 0 -> 2570 bytes lib/ext/jrockit/jrockit.jar | Bin 0 -> 1969 bytes loadtime/.classpath | 2 +- .../src/org/aspectj/weaver/loadtime/Aj.java | 2 +- .../aspectj/weaver/loadtime/JRockitAgent.java | 129 ++++++------ loadtime/testsrc/LoadtimeModuleTests.java | 2 + .../org/aspectj/bea/jvm/ClassLibraryImpl.java | 29 +++ .../testsrc/org/aspectj/bea/jvm/JVMImpl.java | 24 +++ .../weaver/loadtime/JRockitAgentTest.java | 199 ++++++++++++++++++ 9 files changed, 324 insertions(+), 63 deletions(-) create mode 100644 lib/ext/jrockit/jrockit-src.zip create mode 100644 lib/ext/jrockit/jrockit.jar create mode 100644 loadtime/testsrc/org/aspectj/bea/jvm/ClassLibraryImpl.java create mode 100644 loadtime/testsrc/org/aspectj/bea/jvm/JVMImpl.java create mode 100644 loadtime/testsrc/org/aspectj/weaver/loadtime/JRockitAgentTest.java diff --git a/lib/ext/jrockit/jrockit-src.zip b/lib/ext/jrockit/jrockit-src.zip new file mode 100644 index 0000000000000000000000000000000000000000..dce223db8487bb97812efdc4df5fc4e884199531 GIT binary patch literal 2570 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 literal 0 HcmV?d00001 diff --git a/loadtime/.classpath b/loadtime/.classpath index cbc24de0f..6883ab9e0 100644 --- a/loadtime/.classpath +++ b/loadtime/.classpath @@ -7,11 +7,11 @@ - + 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

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. - *

The ClassPreProcessor - * implementation and all third party jars CAN reside in the standard classpath.

The command - * line will look like: - * "%JAVA_COMMAND%" -Xmanagement:class=org.aspectj.weaver.loadtime.JRockitAgent -cp ... - * Note: there can be some NoClassDefFoundError due to classpath limitation - as described in - * http://edocs.bea.com/wls/docs81/adminguide/winservice.html

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 -Dmanagement. - * - * @author Alexandre Vasseur + * 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; + } + } +} -- 2.39.5