-
1. Re: HotSwap in standalone app with custom classloader
kabirkhan Jun 30, 2005 4:19 AM (in response to shane.bryzak)By using the -javaagent switch all classloaders will get intercepted with the chance to instrument classes. Maybe try getting it to work with the "main" classloader first, and come back to us with any issues that may arise with the custom classloaders.
-
2. Re: HotSwap in standalone app with custom classloader
shane.bryzak Jul 3, 2005 11:35 PM (in response to shane.bryzak)I've now got Aspects that are loaded with a custom classloader working with other classes loaded by the same classloader. What I still can't get working is an aspect defined with a custom-classloaded class to intercept a method in a class loaded by the system classloader. I don't know if what I'm trying to achieve is possible, because it requires runtime instrumentation of a class (though isn't that what the -hotSwap parameter enables?). I've hacked together a quick and nasty test case that demonstrates what I'm trying to achieve:
package aoptest; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jboss.aop.Aspect; import org.jboss.aop.AspectAnnotationLoader; import org.jboss.aop.AspectManager; import org.jboss.aop.Bind; import org.jboss.aop.joinpoint.MethodInvocation; @Aspect public class AOPTest { private static final String HELLO_CLASS_SRC = "package aoptest;\n" + "import org.jboss.aop.Aspect;\n " + "import org.jboss.aop.Bind;\n " + "import org.jboss.aop.joinpoint.MethodInvocation;\n " + "@Aspect public class HelloTest { \n" + " @Bind (pointcut=\"execution(void aoptest.AOPTest->test())\") \n" + " public Object injectionAdvice(MethodInvocation invocation) throws Throwable { \n" + " System.out.println(\"aoptest.HelloTest >>> Intercepted call to AOPTest.test()\"); \n" + " return invocation.invokeNext(); } \n" + " @Bind (pointcut=\"execution(void aoptest.AOPTest->test2())\") \n" + " public Object injection2Advice(MethodInvocation invocation) throws Throwable { \n" + " System.out.println(\"aoptest.HelloTest >>> Intercepted call to AOPTest.test2()\"); \n" + " return invocation.invokeNext(); } \n" + " @Bind (pointcut=\"execution(void aoptest.HelloTest->hello())\") \n" + " public Object helloInjectionAdvice(MethodInvocation invocation) throws Throwable { \n" + " System.out.println(\"aoptest.HelloTest >>> Intercepted call to HelloTest.hello()\"); \n" + " return invocation.invokeNext(); } \n" + " public void hello() { System.out.println(\"Hello\"); } \n}\n"; static Map<String,byte[]> classData = new HashMap<String,byte[]>(); static ClassLoader cl; public static void main(String[] args) throws Exception { compile(); Class helloClass = Class.forName("aoptest.HelloTest", true, cl); Method helloMethod = helloClass.getMethod("hello", new Class[] {}); // Have to include the following lines otherwise the aspects defined in // aoptest.HelloTest aren't loaded. ClassLoader sysCl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(cl); List<InputStream> cs = new ArrayList<InputStream>(); cs.add(cl.getResourceAsStream("aoptest.HelloTest")); AspectAnnotationLoader loader = new AspectAnnotationLoader(AspectManager.instance()); loader.deployInputStreamIterator(cs.iterator()); Thread.currentThread().setContextClassLoader(sysCl); AOPTest t = new AOPTest(); // Intercepted by both AOPTest and HelloTest, as expected. t.test(); // Intercepted by both AOPTest and HelloTest, as expected. helloMethod.invoke(helloClass.newInstance(), new Object[] {}); // Expected to be intercepted by HelloTest, but isn't. t.test2(); } public AOPTest() { cl = new CustomClassLoader(); } @Bind (pointcut="execution(void aoptest.AOPTest->test())") public Object injectionAdvice(MethodInvocation invocation) throws Throwable { System.out.println("aoptest.AOPTest >>> Intercepted call to AOPTest.test()"); return invocation.invokeNext(); } @Bind (pointcut="execution(void aoptest.HelloTest->hello())") public Object helloInjectionAdvice(MethodInvocation invocation) throws Throwable { System.out.println("aoptest.AOPTest >>> Intercepted call to HelloTest.hello()"); return invocation.invokeNext(); } public void test() { System.out.println("AOPTest.test()"); } public void test2() { System.out.println("AOPTest.test2()"); } static void compile() throws Exception { String tmpDir = System.getProperty("java.io.tmpdir").replaceAll("\\\\", "/"); // Create the source file File srcDir = new File(tmpDir + "/aoptest"); if (!srcDir.exists()) srcDir.mkdir(); File srcFile = new File(srcDir, "HelloTest.java"); FileOutputStream out = new FileOutputStream(srcFile); out.write(HELLO_CLASS_SRC.getBytes()); out.flush(); out.close(); // Compile HelloTest.java String classPath = org.jboss.aop.Aspect.class.getProtectionDomain().getCodeSource().getLocation().getPath(); String[] options = new String[] {"-sourcepath", tmpDir, "-source", "1.5", "-nowarn", "-classpath", classPath, tmpDir + "aoptest/HelloTest.java"}; com.sun.tools.javac.Main.compile(options); // Load the class data File clsFile = new File(srcDir + "/HelloTest.class"); byte[] data = new byte[(int) clsFile.length()]; InputStream in = new FileInputStream(clsFile); int read = 0; do { read += in.read(data, read, data.length - read); } while (read < data.length); classData.put("aoptest.HelloTest", data); } class CustomClassLoader extends ClassLoader { public Class findClass(String name) { try { return Class.forName(name); } catch (ClassNotFoundException ex) { } byte[] b = classData.get(name); if (b != null) { try { return defineClass(name, b, 0, b.length); } catch (Exception ex1) { } } return null; } public InputStream getResourceAsStream(String name) { if (classData.containsKey(name)) return new ByteArrayInputStream(classData.get(name)); else return getParent().getResourceAsStream(name); } } }
What I'm trying to determine is whether an aspect defined in aoptest.HelloTest (loaded by custom classloader) can intercept a method in AOPTest (loaded by system classloader) that hasn't been previously instrumented. The call to test1() is intercepted as aoptest.AOPTest itself defines an aspect that binds to this method. The call to test2() however doesn't get intercepted.