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 }