1
6
7 package main;
8
9
13 import java.io.*;
14 import java.net.*;
15 import java.text.*;
16 import java.util.*;
17 import java.util.zip.*;
18
19 public class AdaptiveClassLoader extends ClassLoader {
20
21
25 static private int generationCounter = 0;
26
27
31 private int generation;
32
33
37 private Hashtable cache;
38
39
46 private Vector repository;
47
48
52 private static class ClassCacheEntry {
53
54
57 Class loadedClass;
58
59
63 File origin;
64
65
69 long lastModified;
70
71
74 public boolean isSystemClass() {
75 return origin == null;
76 }
77 }
78
79
81
92 public AdaptiveClassLoader(Vector classRepository)
93 throws IllegalArgumentException
94 {
95 cache = new Hashtable();
97
98 Enumeration e = classRepository.elements();
100 while(e.hasMoreElements()) {
101 Object o = e.nextElement();
102 File file;
103
104 try {
106 file = (File) o;
107 } catch (ClassCastException objectIsNotFile) {
108 throw new IllegalArgumentException("Object " + o
109 + "is not a valid \"File\" instance");
110 }
111
112 if (!file.exists()) {
114 throw new IllegalArgumentException("Repository "
115 + file.getAbsolutePath() + " doesn't exist!");
116 } else if (!file.canRead()) {
117 throw new IllegalArgumentException(
118 "Don't have read access for file "
119 + file.getAbsolutePath());
120 }
121
122 if (!(file.isDirectory() || isZipOrJarArchive(file))) {
124 throw new IllegalArgumentException(file.getAbsolutePath()
125 + " is not a directory or zip/jar file"
126 + " or if it's a zip/jar file then it is corrupted.");
127 }
128 }
129
130 this.repository = classRepository;
132
133 this.generation = generationCounter++;
135 }
136
137
139
145 private boolean isZipOrJarArchive(File file) {
146 boolean isArchive = true;
147 ZipFile zipFile = null;
148
149 try {
150 zipFile = new ZipFile(file);
151 } catch (ZipException zipCurrupted) {
152 isArchive = false;
153 } catch (IOException anyIOError) {
154 isArchive = false;
155 } finally {
156 if (zipFile != null) {
157 try {
158 zipFile.close();
159 } catch (IOException ignored) {}
160 }
161 }
162
163 return isArchive;
164 }
165
166
172 public synchronized boolean shouldReload(String classname) {
173
174 ClassCacheEntry entry = (ClassCacheEntry) cache.get(classname);
175
176 if (entry == null) {
177 return false;
179 }
180
181 else if (entry.isSystemClass()) {
182 return false;
184 }
185
186 else {
187 boolean reload = (entry.origin.lastModified() != entry.lastModified);
188 return reload;
189 }
190 }
191
192
198 public synchronized boolean shouldReload() {
199
200 Enumeration e = cache.elements();
202 while (e.hasMoreElements()) {
203 ClassCacheEntry entry = (ClassCacheEntry) e.nextElement();
204
205 if (entry.isSystemClass()) continue;
206
207
213 long msOrigin = entry.origin.lastModified();
214
215 if (msOrigin == 0) {
216 return true;
218 }
219
220 if (msOrigin != entry.lastModified) {
221 return true;
223 }
224 }
225
226 return false;
228 }
229
230
237 public AdaptiveClassLoader reinstantiate() {
238 return new AdaptiveClassLoader(repository);
239 }
240
241
243
253
254
268 protected synchronized Class loadClass(File file, boolean resolve) throws ClassNotFoundException
269 {
270 Class c = null;
272
273 String name = file.getName();
276 name=name.substring(0,file.getName().length() - 6);
277
278 ClassCacheEntry entry = (ClassCacheEntry) cache.get(name);
279
280 if (entry != null) {
281 c = entry.loadedClass;
283
284 if (resolve) resolveClass(c);
285 return c;
286 }
287
288 Enumeration repEnum = repository.elements();
290
291 ClassCacheEntry classCache = new ClassCacheEntry();
293
294 byte[] classData=null;
295
296 file = new File((file.getAbsolutePath()).substring(0,(file.getAbsolutePath()).length()-(name.length()+6)));
297
298 try {
299 if (file.isDirectory()) {
300 classData = loadClassFromDirectory(file, name,classCache);
301 }
302
303 }
304
305 catch(IOException ioe) {
306 classData = null;
308 }
309
310 if (classData != null) {
311 c = defineClass(name, classData, 0, classData.length);
313
314 classCache.loadedClass = c;
316
317 classCache.lastModified = classCache.origin.lastModified();
319 cache.put(name, classCache);
320
321 if (resolve) resolveClass(c);
323 return c;
324 }
325
327 return c;
328 }
330
331
339 private Class loadSystemClass(String name, boolean resolve)
340 throws NoClassDefFoundError, ClassNotFoundException
341 {
342 Class c = findSystemClass(name);
343
345 ClassCacheEntry cacheEntry = new ClassCacheEntry();
347 cacheEntry.origin = null;
348 cacheEntry.loadedClass = c;
349 cacheEntry.lastModified = Long.MAX_VALUE;
350 cache.put(name, cacheEntry);
351
352 if (resolve) resolveClass(c);
353
354 return c;
355 }
356
357
361 private boolean securityAllowsClass(String className) {
366 try {
367 SecurityManager security = System.getSecurityManager();
368
369 if (security == null) {
370 return true;
373 }
374
375 int lastDot = className.lastIndexOf('.');
376 security.checkPackageDefinition((lastDot > -1)
378 ? className.substring(0, lastDot) : "");
379 return true;
381 } catch (SecurityException e) {
382 return false;
383 }
384 }
385
386
394 private byte[] loadClassFromDirectory(File dir, String name, ClassCacheEntry cache)
395 throws IOException
396 {
397 String classFileName =
399 name.replace('.', File.separatorChar) + ".class";
400
401 if (!Character.isJavaIdentifierStart(classFileName.charAt(0))) {
404 int start = 1;
406 while (!Character.isJavaIdentifierStart(
407 classFileName.charAt(start++)));
408 classFileName = classFileName.substring(start);
409 }
410
411 File classFile = new File(dir, classFileName);
412
413 if (classFile.exists()) {
414 cache.origin = classFile;
415 InputStream in = new FileInputStream(classFile);
416 try {
417 return loadBytesFromStream(in, (int) classFile.length());
418 } finally {
419 in.close();
420 }
421 } else {
422 return null;
424 }
425
426 }
427
428
435 private byte[] loadClassFromZipfile(File file, String name,
436 ClassCacheEntry cache)
437 throws IOException
438 {
439 String classFileName = name.replace('.', '/') + ".class";
441
442 ZipFile zipfile = new ZipFile(file);
443
444 try {
445 ZipEntry entry = zipfile.getEntry(classFileName);
446 if (entry != null) {
447 cache.origin = file;
448 return loadBytesFromStream(zipfile.getInputStream(entry),
449 (int) entry.getSize());
450 } else {
451 return null;
453 }
454 } finally {
455 zipfile.close();
456 }
457 }
458
459
462 private byte[] loadBytesFromStream(InputStream in, int length)
463 throws IOException
464 {
465 byte[] buf = new byte[length];
466 int nRead, count = 0;
467
468 while ((length > 0) && ((nRead = in.read(buf,count,length)) != -1)) {
469 count += nRead;
470 length -= nRead;
471 }
472
473 return buf;
474 }
475
476
488 public InputStream getResourceAsStream(String name) {
489 InputStream s = getSystemResourceAsStream(name);
491
492 if (s == null) {
493 Enumeration repEnum = repository.elements();
495 while (repEnum.hasMoreElements()) {
496 File file = (File) repEnum.nextElement();
497 if (file.isDirectory()) {
498 s = loadResourceFromDirectory(file, name);
499 } else {
500 s = loadResourceFromZipfile(file, name);
501 }
502
503 if (s != null) {
504 break;
505 }
506 }
507 }
508
509 return s;
510 }
511
512
515 private InputStream loadResourceFromDirectory(File dir, String name) {
516 String fileName = name.replace('/', File.separatorChar);
518 File resFile = new File(dir, fileName);
519
520 if (resFile.exists()) {
521 try {
522 return new FileInputStream(resFile);
523 } catch (FileNotFoundException shouldnothappen) {
524 return null;
525 }
526 } else {
527 return null;
528 }
529 }
530
531
534 private InputStream loadResourceFromZipfile(File file, String name) {
535 try {
536 ZipFile zipfile = new ZipFile(file);
537 ZipEntry entry = zipfile.getEntry(name);
538
539 if (entry != null) {
540 return zipfile.getInputStream(entry);
541 } else {
542 return null;
543 }
544 } catch(IOException e) {
545 return null;
546 }
547 }
548
549
560 public URL getResource(String name) {
561
562 URL u = getSystemResource(name);
563 if (u != null) {
564 return u;
565 }
566
567 Enumeration repEnum = repository.elements();
570 while (repEnum.hasMoreElements()) {
571 File file = (File) repEnum.nextElement();
572 if (file.isDirectory()) {
573 String fileName = name.replace('/', File.separatorChar);
574 File resFile = new File(file, fileName);
575 if (resFile.exists()) {
576 try {
578 return new URL("file://"
579 + resFile.getAbsolutePath());
580 } catch(java.net.MalformedURLException badurl) {
581 badurl.printStackTrace();
582 return null;
583 }
584 }
585 }
586 }
587
588 return null;
590 }
591 }
592