package kilim; import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import kilim.analysis.ClassInfo; import kilim.analysis.FileLister; import kilim.tools.Weaver; /** * Classloader that loads classes from the classpath spec given by the system property * "kilim.class.path" and weaves them dynamically. */ public class WeavingClassLoader extends KilimClassLoader { public static final String KILIM_CLASSPATH = "kilim.class.path"; /** * List of paths in kilim.class.path */ ArrayList<FileLister> fileContainers; /** * Weaver instance. There is a mutually recursive dependency between the weaver and * this class loader. See {@link #findClass(String)} */ Weaver weaver; public WeavingClassLoader(ClassLoader parent) { super(parent); String classPath = System.getProperty(KILIM_CLASSPATH, ""); String[] classPaths = classPath.split(":"); fileContainers = new ArrayList<FileLister>(classPaths.length); for (String name : classPaths) { name = name.trim(); if (name.equals("")) continue; try { fileContainers.add(new FileLister(name)); } catch (IOException ioe) { // System.err.println( "'" + name + "' does not exist. See property " + // KILIM_CLASSPATH); } } weaver = new Weaver(this); // mutually recursive dependency. } /** * Check if class file exists in kilim.class.path. */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> ret = null; for (FileLister container : fileContainers) { try { String classFileName = name.replace('.', File.separatorChar) + ".class"; FileLister.Entry fe = container.open(classFileName); if (fe == null) continue; byte[] code = readFully(fe); List<ClassInfo> cis = weaver.weave(new ClassInfo(name, code)); for (ClassInfo ci : cis) { if (findLoadedClass(ci.className) != null) continue; Class<?> c = super.defineClass(ci.className, ci.bytes, 0, ci.bytes.length); if (ci.className.equals(name)) { ret = c; } else { // extra classes produced by the weaver. resolve them right away // That way, when the given class name is resolved, it'll find its // kilim related state object classes right away. if (ci.className.startsWith("kilim.S")) { super.resolveClass(c); } } } if (ret == null) { // code exists, but didn't need to be woven ret = super.defineClass(name, code, 0, code.length); } } catch (IOException ignore) { System.err.println(ignore.getMessage()); } } if (ret == null) { throw new ClassNotFoundException(name); } return ret; } private static byte[] readFully(FileLister.Entry fe) throws IOException { DataInputStream in = new DataInputStream(fe.getInputStream()); byte[] contents = new byte[(int)fe.getSize()]; in.readFully(contents); in.close(); return contents; } }