KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > polyglot > types > reflect > ClassFileLoader


1 package polyglot.types.reflect;
2
3 import polyglot.main.Report;
4 import polyglot.util.InternalCompilerError;
5
6 import java.io.*;
7 import java.util.*;
8 import java.util.zip.*;
9 import java.util.jar.*;
10
11 /**
12  * We implement our own class loader. All this pain is so
13  * we can define the classpath on the command line.
14  */

15 public class ClassFileLoader
16 {
17     /**
18      * Keep a cache of the zips and jars so we don't have to keep
19      * opening them from the file system.
20      */

21     Map zipCache;
22
23     /**
24      * A cache of directories found in zip files.
25      */

26     Set packageCache;
27
28     /**
29      * Directory contents cache. Cache the first level of the directory
30      * so that we get less FileNotFoundExceptions
31      */

32     Map dirContentsCache;
33
34     final static Object JavaDoc not_found = new Object JavaDoc();
35
36     public ClassFileLoader() {
37         this.zipCache = new HashMap();
38         this.dirContentsCache = new HashMap();
39     this.packageCache = new HashSet();
40     }
41
42     /**
43      * Return true if the package name exists under the directory or file
44      * <code>dir</code>.
45      */

46     public boolean packageExists(File dir, String JavaDoc name) {
47         if (Report.should_report(verbose, 3)) {
48         Report.report(3, "looking in " + dir + " for " +
49                              name.replace('.', File.separatorChar));
50         }
51
52         try {
53             if (dir.getName().endsWith(".jar") ||
54                 dir.getName().endsWith(".zip")) {
55
56                 String JavaDoc entryName = name.replace('.', '/');
57         
58         if (packageCache.contains(entryName)) {
59             return true;
60         }
61
62         // load the zip file, forcing the package cache to be initialized
63
// with its contents.
64
loadZip(dir);
65             
66         return packageCache.contains(entryName);
67         }
68             else {
69                 String JavaDoc entryName = name.replace('.', File.separatorChar);
70                 File f = new File(dir, entryName);
71                 return f.exists() && f.isDirectory();
72             }
73         }
74         catch (FileNotFoundException e) {
75             // ignore the exception.
76
}
77         catch (IOException e) {
78             throw new InternalCompilerError(e);
79         }
80
81         return false;
82     }
83
84     /**
85      * Try to find the class <code>name</code> in the directory or jar or zip
86      * file <code>dir</code>.
87      * If the class does not exist in the specified file/directory, then
88      * <code>null</code> is returned.
89      */

90     public ClassFile loadClass(File dir, String JavaDoc name)
91     {
92         if (Report.should_report(verbose, 3)) {
93         Report.report(3, "looking in " + dir + " for " +
94                              name.replace('.', File.separatorChar) + ".class");
95         }
96     
97         try {
98             if (dir.getName().endsWith(".jar") ||
99                 dir.getName().endsWith(".zip")) {
100
101                 ZipFile zip = loadZip(dir);
102                 String JavaDoc entryName = name.replace('.', '/') + ".class";
103                 return loadFromZip(dir, zip, entryName);
104             }
105             else {
106                 return loadFromFile(name, dir);
107             }
108         }
109         catch (FileNotFoundException e) {
110             // ignore the exception.
111
}
112         catch (IOException e) {
113             throw new InternalCompilerError(e);
114         }
115
116         return null;
117     }
118
119     ZipFile loadZip(File dir) throws IOException {
120         Object JavaDoc o = zipCache.get(dir);
121         if (o != not_found) {
122             ZipFile zip = (ZipFile) o;
123             if (zip != null) {
124                 return zip;
125             }
126             else {
127                 // the zip is not in the cache.
128
// try to get it.
129
if (!dir.exists()) {
130                     // record that the file does not exist,
131
zipCache.put(dir, not_found);
132                 }
133                 else {
134                     // get the zip and put it in the cache.
135
if (Report.should_report(verbose, 2))
136                         Report.report(2, "Opening zip " + dir);
137             if (dir.getName().endsWith(".jar")) {
138             zip = new JarFile(dir);
139             }
140             else {
141             zip = new ZipFile(dir);
142             }
143             zipCache.put(dir, zip);
144             
145             // Load the package cache.
146
for (Enumeration i = zip.entries(); i.hasMoreElements(); ) {
147             ZipEntry ei = (ZipEntry) i.nextElement();
148             String JavaDoc n = ei.getName();
149             
150             int index = n.indexOf('/');
151             while (index >= 0) {
152                 packageCache.add(n.substring(0, index));
153                 index = n.indexOf('/', index+1);
154             }
155             }
156             
157                     return zip;
158                 }
159             }
160         }
161         throw new FileNotFoundException(dir.getAbsolutePath());
162     }
163
164     ClassFile loadFromZip(File source, ZipFile zip, String JavaDoc entryName) throws IOException {
165         if (Report.should_report(verbose, 2))
166             Report.report(2, "Looking for " + entryName + " in " + zip.getName());
167         if (zip != null) {
168             ZipEntry entry = zip.getEntry(entryName);
169             if (entry != null) {
170                 if (Report.should_report(verbose, 3))
171                     Report.report(3, "found zip entry " + entry);
172                 InputStream in = zip.getInputStream(entry);
173                 ClassFile c = loadFromStream(source, in, entryName);
174                 in.close();
175                 return c;
176             }
177         }
178         return null;
179     }
180
181     ClassFile loadFromFile(String JavaDoc name, File dir) throws IOException {
182         Set dirContents = (Set)dirContentsCache.get(dir);
183         if (dirContents == null) {
184             dirContents = new HashSet();
185             dirContentsCache.put(dir, dirContents);
186             if (dir.exists() && dir.isDirectory()) {
187                 String JavaDoc[] contents = dir.list();
188                 for (int j = 0; j < contents.length; j++) {
189                     dirContents.add(contents[j]);
190                 }
191             }
192         }
193
194
195         StringBuffer JavaDoc filenameSB = new StringBuffer JavaDoc(name.length() + 8);
196         int firstSeparator = -1;
197         filenameSB.append(name);
198         // our own replace, to save a suprising amount of memory
199
for (int i = 0; i < filenameSB.length(); i++) {
200             if (filenameSB.charAt(i) == '.') {
201                 filenameSB.setCharAt(i, File.separatorChar);
202                 if (firstSeparator == -1)
203                     firstSeparator = i;
204             }
205         }
206         filenameSB.append(".class");
207
208         String JavaDoc filename = filenameSB.toString();
209         String JavaDoc firstPart = (firstSeparator==-1) ? filename
210                                                 : filename.substring(0, firstSeparator);
211
212         // check to see if the directory has the first part of the filename,
213
// to avoid trying to open the file if it doesn't
214
if (!dirContents.contains(firstPart)) {
215             return null;
216         }
217
218         // otherwise, try and open the thing.
219
File file = new File(dir, filename);
220
221         FileInputStream in = new FileInputStream(file);
222         if (Report.should_report(verbose, 3))
223             Report.report(3, "found " + file);
224         ClassFile c = loadFromStream(file, in, name);
225         in.close();
226         return c;
227     }
228
229     /**
230      * Load a class from an input stream.
231      */

232     ClassFile loadFromStream(File source, InputStream in, String JavaDoc name) throws IOException {
233         ByteArrayOutputStream out = new ByteArrayOutputStream();
234
235         byte[] buf = new byte[4096];
236         int n = 0;
237
238         do {
239             n = in.read(buf);
240             if (n >= 0) out.write(buf, 0, n);
241         } while (n >= 0);
242
243         byte[] bytecode = out.toByteArray();
244
245         try {
246             if (Report.should_report(verbose, 3))
247         Report.report(3, "defining class " + name);
248             return new ClassFile(source, bytecode);
249         }
250         catch (ClassFormatError JavaDoc e) {
251             throw new IOException(e.getMessage());
252         }
253     }
254
255     static Collection verbose;
256
257     static {
258         verbose = new HashSet();
259         verbose.add("loader");
260     }
261 }
262
Popular Tags