/* * This file is part of JGAP. * * JGAP offers a dual license model containing the LGPL as well as the MPL. * * For licensing information please see the file license.txt included with JGAP * or have a look at the top of class org.jgap.Chromosome which representatively * includes the JGAP license policy applicable for any file delivered with JGAP. */ package org.jgap.util; import java.util.*; /** * A simple test class loader capable of loading from multiple sources, such as * local files or a URL. * * This class is derived from an article by Chuck McManis * http://www.javaworld.com/javaworld/jw-10-1996/indepth.src.html * with large modifications. * * Note that this has been updated to use the non-deprecated version of * defineClass() -- JDM. * * @author Jack Harich - 8/18/97 * @author John D. Mitchell - 99.03.04 * @author Klaus Meffert (integrated into JGAP) * * @since 3.2 */ public abstract class MultiClassLoader extends ClassLoader { /** String containing the CVS revision. Read out via reflection!*/ private final static String CVS_REVISION = "$Revision: 1.2 $"; //---------- Fields -------------------------------------- private Hashtable classes = new Hashtable(); private char classNameReplacementChar; protected boolean monitorOn = false; protected boolean sourceMonitorOn = true; public MultiClassLoader() { } /** * This is a simple version for external clients since they * will always want the class resolved before it is returned * to them. */ public Class loadClass(String className) throws ClassNotFoundException { return (loadClass(className, true)); } public synchronized Class loadClass(String className, boolean resolveIt) throws ClassNotFoundException { Class result; byte[] classBytes; monitor(">> MultiClassLoader.loadClass(" + className + ", " + resolveIt + ")"); //----- Check our local cache of classes result = (Class) classes.get(className); if (result != null) { monitor(">> returning cached result."); return result; } //----- Check with the primordial class loader try { result = super.findSystemClass(className); monitor(">> returning system class (in CLASSPATH)."); return result; } catch (ClassNotFoundException e) { monitor(">> Not a system class."); } //----- Try to load it from preferred source // Note loadClassBytes() is an abstract method classBytes = loadClassBytes(className); if (classBytes == null) { throw new ClassNotFoundException(); } //----- Define it (parse the class file) result = defineClass(className, classBytes, 0, classBytes.length); if (result == null) { throw new ClassFormatError(); } //----- Resolve if necessary if (resolveIt) resolveClass(result); // Done classes.put(className, result); monitor(">> Returning newly loaded class."); return result; } /** * This optional call allows a class name such as * "COM.test.Hello" to be changed to "COM_test_Hello", * which is useful for storing classes from different * packages in the same retrival directory. * In the above example the char would be '_'. */ public void setClassNameReplacementChar(char replacement) { classNameReplacementChar = replacement; } protected abstract byte[] loadClassBytes(String className); protected String formatClassName(String className) { if (classNameReplacementChar == '\u0000') { // '/' is used to map the package to the path return className.replace('.', '/') + ".class"; } else { // Replace '.' with custom char, such as '_' return className.replace('.', classNameReplacementChar) + ".class"; } } protected void monitor(String text) { if (monitorOn) print(text); } protected static void print(String text) { System.out.println(text); } }