package net.sourceforge.retroweaver; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.StringTokenizer; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class RetroWeaverClassLoader extends ClassLoader { private RetroWeaver retroWeaver; private List<ClassPathElement> classPathElements; protected void setWeaver(RetroWeaver retroWeaver) { this.retroWeaver = retroWeaver; } protected void setClassPath(List<String> classPath) { classPathElements = new LinkedList<ClassPathElement>(); for(String pathEntry: classPath) { File f = new File(pathEntry); if (f.exists()) { if (f.isDirectory()) { addDirectoryClassPathElement(pathEntry); } else { addJarClassPathElement(pathEntry); } } } } protected void setClassPath(String classPath) { List<String> l = new LinkedList<String>(); if (classPath != null) { StringTokenizer t = new StringTokenizer(classPath, File.pathSeparator); while (t.hasMoreTokens()) { l.add(t.nextToken()); } } setClassPath(l); } protected void addDirectoryClassPathElement(String dirName) { DirectoryElement e = new DirectoryElement(dirName); classPathElements.add(e); } protected void addJarClassPathElement(String jarName) { try { JarElement e = new JarElement(jarName); classPathElements.add(e); } catch (IOException ioe) { } } protected Class<?> findClass(String name) throws ClassNotFoundException { String resourceName = name.replace('.', '/') + ".class"; for (ClassPathElement e : classPathElements) { if (e.hasResource(resourceName)) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); InputStream is = e.getResourceStream(resourceName); byte b[]; boolean weaved; try { weaved = retroWeaver.weave(is, name, bos); } catch (IOException ioe) { throw new RetroWeaverException("Problem weaving class " + name + ": " + ioe.getMessage()); } if (weaved) { b = bos.toByteArray(); } else { b = e.getResourceData(resourceName); } Class clazz = defineClass(name.replace('/', '.'), b, 0, b.length); return clazz; } } throw new ClassNotFoundException(name); } protected byte[] getClassData(String name) throws ClassNotFoundException { String resourceName = name.replace('.', '/') + ".class"; for (ClassPathElement e : classPathElements) { if (e.hasResource(resourceName)) { byte b[] = e.getResourceData(resourceName); return b; } } throw new ClassNotFoundException(name); } protected URL findResource(String name) { for (ClassPathElement e : classPathElements) { if (e.hasResource(name)) { return e.getResourceURL(name); } } return null; } protected Enumeration<URL> findResources(String name) throws IOException { ArrayList<URL> l = new ArrayList<URL>(); for (ClassPathElement e : classPathElements) { if (e.hasResource(name)) { l.add(e.getResourceURL(name)); } } return Collections.enumeration(l); } private static abstract class ClassPathElement { protected abstract boolean hasResource(String name); protected abstract URL getResourceURL(String name); protected abstract InputStream getResourceStream(String name); protected byte[] getResourceData(String name) { assert (hasResource(name)); InputStream is = getResourceStream(name); ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataInputStream ds = new DataInputStream(is); byte b[] = new byte[2048]; int i; try { while((i = ds.read(b)) != -1) { bos.write(b, 0, i); } return bos.toByteArray(); } catch (IOException e) { return null; } finally { try { ds.close(); } catch (IOException e) { } } } } private static class DirectoryElement extends ClassPathElement { private final String dirName; DirectoryElement(String dirName) { super(); this.dirName = dirName; } protected boolean hasResource(String name) { String fullPath = dirName + File.separatorChar + name; File f = new File(fullPath); return f.exists() && f.isFile(); } protected URL getResourceURL(String name) { assert (hasResource(name)); String fullPath = dirName + File.separatorChar + name; try { return new URL("file:" + fullPath); } catch (MalformedURLException e) { return null; } } protected InputStream getResourceStream(String name) { assert (hasResource(name)); try { File f = new File(dirName + File.separatorChar + name); return new FileInputStream(f); } catch (IOException ioe) { return null; } } } private static class JarElement extends ClassPathElement { private final String jarName; private final ZipFile jarFile; JarElement(String jarName) throws IOException { super(); this.jarName = jarName; jarFile = new ZipFile(jarName); } protected boolean hasResource(String name) { ZipEntry entry = jarFile.getEntry(name); return entry != null; } protected URL getResourceURL(String name) { assert (hasResource(name)); try { return new URL("jar:file:" + jarName + "!/" + name); } catch (MalformedURLException e) { return null; } } protected InputStream getResourceStream(String name) { assert (hasResource(name)); try { ZipEntry entry = jarFile.getEntry(name); return jarFile.getInputStream(entry); } catch (IOException ioe) { return null; } } } }