diff --git a/src/test/org/apache/commons/logging/jdk14/CustomConfigAPITestCase.java b/src/test/org/apache/commons/logging/jdk14/CustomConfigAPITestCase.java index 83f86d1..34431aa 100644 --- a/src/test/org/apache/commons/logging/jdk14/CustomConfigAPITestCase.java +++ b/src/test/org/apache/commons/logging/jdk14/CustomConfigAPITestCase.java @@ -19,8 +19,8 @@ package org.apache.commons.logging.jdk14; import junit.framework.Test; -import org.apache.commons.logging.PathableTestSuite; import org.apache.commons.logging.PathableClassLoader; +import org.apache.commons.logging.PathableTestSuite; /** @@ -30,12 +30,10 @@ import org.apache.commons.logging.PathableClassLoader; public class CustomConfigAPITestCase extends CustomConfigTestCase { - public CustomConfigAPITestCase(String name) { super(name); } - /** * Return the tests included in this test suite. */ @@ -48,7 +46,9 @@ public class CustomConfigAPITestCase extends CustomConfigTestCase { // be able to instantiate it. And this test case must see the same // class in order to be able to access its data. Yes this is ugly // but the whole jdk14 API is a ******* mess anyway. - parent.useSystemLoader("org.apache.commons.logging.jdk14.TestHandler"); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + loadTestHandler(HANDLER_NAME, scl); + parent.useExplicitLoader(HANDLER_NAME, scl); parent.addLogicalLib("commons-logging-api"); PathableClassLoader child = new PathableClassLoader(parent); diff --git a/src/test/org/apache/commons/logging/jdk14/CustomConfigFullTestCase.java b/src/test/org/apache/commons/logging/jdk14/CustomConfigFullTestCase.java index 12bf8bd..310e9c6 100644 --- a/src/test/org/apache/commons/logging/jdk14/CustomConfigFullTestCase.java +++ b/src/test/org/apache/commons/logging/jdk14/CustomConfigFullTestCase.java @@ -49,7 +49,9 @@ public class CustomConfigFullTestCase extends CustomConfigTestCase { // be able to instantiate it. And this test case must see the same // class in order to be able to access its data. Yes this is ugly // but the whole jdk14 API is a ******* mess anyway. - parent.useSystemLoader("org.apache.commons.logging.jdk14.TestHandler"); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + loadTestHandler(HANDLER_NAME, scl); + parent.useExplicitLoader(HANDLER_NAME, scl); parent.addLogicalLib("commons-logging"); PathableClassLoader child = new PathableClassLoader(parent); diff --git a/src/test/org/apache/commons/logging/jdk14/CustomConfigTestCase.java b/src/test/org/apache/commons/logging/jdk14/CustomConfigTestCase.java index c536197..d1f3ec9 100644 --- a/src/test/org/apache/commons/logging/jdk14/CustomConfigTestCase.java +++ b/src/test/org/apache/commons/logging/jdk14/CustomConfigTestCase.java @@ -18,7 +18,9 @@ package org.apache.commons.logging.jdk14; +import java.io.ByteArrayOutputStream; import java.io.InputStream; +import java.lang.reflect.Method; import java.util.Iterator; import java.util.logging.Handler; import java.util.logging.Level; @@ -27,7 +29,9 @@ import java.util.logging.LogRecord; import java.util.logging.Logger; import junit.framework.Test; -import junit.framework.TestSuite; + +import org.apache.commons.logging.PathableClassLoader; +import org.apache.commons.logging.PathableTestSuite; /** @@ -41,6 +45,8 @@ import junit.framework.TestSuite; public class CustomConfigTestCase extends DefaultConfigTestCase { + protected static final String HANDLER_NAME + = "org.apache.commons.logging.jdk14.TestHandler"; // ----------------------------------------------------------- Constructors @@ -99,6 +105,65 @@ public class CustomConfigTestCase extends DefaultConfigTestCase { // ------------------------------------------- JUnit Infrastructure Methods + /** + * Given the name of a class that is somewhere in the classpath of the provided + * classloader, return the contents of the corresponding .class file. + */ + protected static byte[] readClass(String name, ClassLoader srcCL) throws Exception { + String resName = name.replace('.', '/') + ".class"; + System.err.println("Trying to load resource [" + resName + "]"); + InputStream is = srcCL.getResourceAsStream(resName); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + System.err.println("Reading resource [" + resName + "]"); + byte[] buf = new byte[1000]; + for(;;) { + int read = is.read(buf); + if (read <= 0) { + break; + } + baos.write(buf, 0, read); + } + is.close(); + return baos.toByteArray(); + } + + /** + * Make a class available in the system classloader even when its classfile is + * not present in the classpath configured for that classloader. This only + * works for classes for which all dependencies are already loaded in + * that classloader. + */ + protected static void loadTestHandler(String className, ClassLoader targetCL) { + try { + targetCL.loadClass(className); + // fail("Class already in target classloader"); + return; + } catch(ClassNotFoundException ex) { + // ok, go ahead and load it + } + + try { + ClassLoader srcCL = CustomConfigAPITestCase.class.getClassLoader(); + byte[] classData = readClass(className, srcCL); + + Class[] params = new Class[] { + String.class, classData.getClass(), + Integer.TYPE, Integer.TYPE}; + Method m = ClassLoader.class.getDeclaredMethod("defineClass", params); + + Object[] args = new Object[4]; + args[0] = className; + args[1] = classData; + args[2] = new Integer(0); + args[3] = new Integer(classData.length); + m.setAccessible(true); + m.invoke(targetCL, args); + } catch(Exception e) { + e.printStackTrace(); + fail("Unable to load class " + className); + } + } + /** * Set up instance variables required by this test case. */ @@ -116,18 +181,22 @@ public class CustomConfigTestCase extends DefaultConfigTestCase { * Return the tests included in this test suite. */ public static Test suite() throws Exception { - /* - PathableClassLoader loader = new PathableClassLoader(null); - loader.useSystemLoader("junit."); + PathableClassLoader cl = new PathableClassLoader(null); + cl.useExplicitLoader("junit.", Test.class.getClassLoader()); - PathableClassLoader child = new PathableClassLoader(parent); - child.addLogicalLib("testclasses"); - child.addLogicalLib("commons-logging"); + // the TestHandler class must be accessable from the System classloader + // in order for java.util.logging.LogManager.readConfiguration to + // be able to instantiate it. And this test case must see the same + // class in order to be able to access its data. Yes this is ugly + // but the whole jdk14 API is a ******* mess anyway. + ClassLoader scl = ClassLoader.getSystemClassLoader(); + loadTestHandler(HANDLER_NAME, scl); + cl.useExplicitLoader(HANDLER_NAME, scl); + cl.addLogicalLib("commons-logging"); + cl.addLogicalLib("testclasses"); - Class testClass = child.loadClass(CustomConfigTestCase.class.getName()); - return new PathableTestSuite(testClass, child); - */ - return new TestSuite(CustomConfigTestCase.class); + Class testClass = cl.loadClass(CustomConfigTestCase.class.getName()); + return new PathableTestSuite(testClass, cl); } /**