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    }