001 package net.sourceforge.retroweaver; 002 003 import java.io.ByteArrayOutputStream; 004 import java.io.DataInputStream; 005 import java.io.File; 006 import java.io.FileInputStream; 007 import java.io.IOException; 008 import java.io.InputStream; 009 import java.net.MalformedURLException; 010 import java.net.URL; 011 import java.util.ArrayList; 012 import java.util.Collections; 013 import java.util.Enumeration; 014 import java.util.LinkedList; 015 import java.util.List; 016 import java.util.StringTokenizer; 017 import java.util.zip.ZipEntry; 018 import java.util.zip.ZipFile; 019 020 public class RetroWeaverClassLoader extends ClassLoader { 021 022 private RetroWeaver retroWeaver; 023 024 private List<ClassPathElement> classPathElements; 025 026 protected void setWeaver(RetroWeaver retroWeaver) { 027 this.retroWeaver = retroWeaver; 028 } 029 030 protected void setClassPath(List<String> classPath) { 031 classPathElements = new LinkedList<ClassPathElement>(); 032 033 for(String pathEntry: classPath) { 034 File f = new File(pathEntry); 035 if (f.exists()) { 036 if (f.isDirectory()) { 037 addDirectoryClassPathElement(pathEntry); 038 } else { 039 addJarClassPathElement(pathEntry); 040 } 041 } 042 } 043 } 044 045 protected void setClassPath(String classPath) { 046 List<String> l = new LinkedList<String>(); 047 048 if (classPath != null) { 049 StringTokenizer t = new StringTokenizer(classPath, File.pathSeparator); 050 while (t.hasMoreTokens()) { 051 l.add(t.nextToken()); 052 } 053 } 054 055 setClassPath(l); 056 } 057 058 protected void addDirectoryClassPathElement(String dirName) { 059 DirectoryElement e = new DirectoryElement(dirName); 060 classPathElements.add(e); 061 } 062 063 protected void addJarClassPathElement(String jarName) { 064 try { 065 JarElement e = new JarElement(jarName); 066 classPathElements.add(e); 067 } catch (IOException ioe) { 068 } 069 } 070 071 protected Class<?> findClass(String name) throws ClassNotFoundException { 072 String resourceName = name.replace('.', '/') + ".class"; 073 for (ClassPathElement e : classPathElements) { 074 if (e.hasResource(resourceName)) { 075 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 076 InputStream is = e.getResourceStream(resourceName); 077 078 byte b[]; 079 boolean weaved; 080 try { 081 weaved = retroWeaver.weave(is, name, bos); 082 } catch (IOException ioe) { 083 throw new RetroWeaverException("Problem weaving class " + name 084 + ": " + ioe.getMessage()); 085 } 086 if (weaved) { 087 b = bos.toByteArray(); 088 } else { 089 b = e.getResourceData(resourceName); 090 } 091 092 Class clazz = defineClass(name.replace('/', '.'), b, 0, b.length); 093 094 return clazz; 095 } 096 } 097 098 throw new ClassNotFoundException(name); 099 } 100 101 protected byte[] getClassData(String name) throws ClassNotFoundException { 102 String resourceName = name.replace('.', '/') + ".class"; 103 for (ClassPathElement e : classPathElements) { 104 if (e.hasResource(resourceName)) { 105 byte b[] = e.getResourceData(resourceName); 106 107 return b; 108 } 109 } 110 111 throw new ClassNotFoundException(name); 112 } 113 114 protected URL findResource(String name) { 115 for (ClassPathElement e : classPathElements) { 116 if (e.hasResource(name)) { 117 return e.getResourceURL(name); 118 } 119 } 120 return null; 121 } 122 123 protected Enumeration<URL> findResources(String name) throws IOException { 124 ArrayList<URL> l = new ArrayList<URL>(); 125 for (ClassPathElement e : classPathElements) { 126 if (e.hasResource(name)) { 127 l.add(e.getResourceURL(name)); 128 } 129 } 130 return Collections.enumeration(l); 131 } 132 133 private static abstract class ClassPathElement { 134 135 protected abstract boolean hasResource(String name); 136 137 protected abstract URL getResourceURL(String name); 138 139 protected abstract InputStream getResourceStream(String name); 140 141 protected byte[] getResourceData(String name) { 142 assert (hasResource(name)); 143 144 InputStream is = getResourceStream(name); 145 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 146 147 DataInputStream ds = new DataInputStream(is); 148 149 byte b[] = new byte[2048]; 150 int i; 151 try { 152 while((i = ds.read(b)) != -1) { 153 bos.write(b, 0, i); 154 } 155 return bos.toByteArray(); 156 } catch (IOException e) { 157 return null; 158 } finally { 159 try { 160 ds.close(); 161 } catch (IOException e) { 162 } 163 } 164 } 165 166 } 167 168 private static class DirectoryElement extends ClassPathElement { 169 170 private final String dirName; 171 172 DirectoryElement(String dirName) { 173 super(); 174 this.dirName = dirName; 175 } 176 177 protected boolean hasResource(String name) { 178 String fullPath = dirName + File.separatorChar + name; 179 180 File f = new File(fullPath); 181 182 return f.exists() && f.isFile(); 183 } 184 185 protected URL getResourceURL(String name) { 186 assert (hasResource(name)); 187 188 String fullPath = dirName + File.separatorChar + name; 189 190 try { 191 return new URL("file:" + fullPath); 192 } catch (MalformedURLException e) { 193 return null; 194 } 195 } 196 197 protected InputStream getResourceStream(String name) { 198 assert (hasResource(name)); 199 200 try { 201 File f = new File(dirName + File.separatorChar + name); 202 return new FileInputStream(f); 203 } catch (IOException ioe) { 204 return null; 205 } 206 } 207 208 } 209 210 private static class JarElement extends ClassPathElement { 211 212 private final String jarName; 213 214 private final ZipFile jarFile; 215 216 JarElement(String jarName) throws IOException { 217 super(); 218 this.jarName = jarName; 219 jarFile = new ZipFile(jarName); 220 } 221 222 protected boolean hasResource(String name) { 223 ZipEntry entry = jarFile.getEntry(name); 224 225 return entry != null; 226 } 227 228 protected URL getResourceURL(String name) { 229 assert (hasResource(name)); 230 231 try { 232 return new URL("jar:file:" + jarName + "!/" + name); 233 } catch (MalformedURLException e) { 234 return null; 235 } 236 } 237 238 protected InputStream getResourceStream(String name) { 239 assert (hasResource(name)); 240 241 try { 242 ZipEntry entry = jarFile.getEntry(name); 243 return jarFile.getInputStream(entry); 244 } catch (IOException ioe) { 245 return null; 246 } 247 } 248 249 } 250 251 }