<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>
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();
/*******************************************************************************
- * 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
+}
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;
suite.addTestSuite(DocumentParserTest.class);
suite.addTestSuite(WeavingURLClassLoaderTest.class);
+ suite.addTestSuite(JRockitAgentTest.class);
return suite;
}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+ }
+}