Source Code Cross Referenced for AdaptiveClassLoader.java in  » XML-UI » xui32 » com » dawidweiss » util » lang » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » XML UI » xui32 » com.dawidweiss.util.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package com.dawidweiss.util.lang;
002:
003:        /*
004:         * This class slightly modified to allow optional resolving classes from this classloader
005:         * before system/ parent class loader.
006:         */
007:
008:        /*
009:         * Copyright (c) 1997-1999 The Java Apache Project.  All rights reserved.
010:         *
011:         * Redistribution and use in source and binary forms, with or without
012:         * modification, are permitted provided that the following conditions
013:         * are met:
014:         *
015:         * 1. Redistributions of source code must retain the above copyright
016:         *    notice, this list of conditions and the following disclaimer.
017:         *
018:         * 2. Redistributions in binary form must reproduce the above copyright
019:         *    notice, this list of conditions and the following disclaimer in
020:         *    the documentation and/or other materials provided with the
021:         *    distribution.
022:         *
023:         * 3. All advertising materials mentioning features or use of this
024:         *    software must display the following acknowledgment:
025:         *    "This product includes software developed by the Java Apache
026:         *    Project for use in the Apache JServ servlet engine project
027:         *    <http://java.apache.org/>."
028:         *
029:         * 4. The names "Apache JServ", "Apache JServ Servlet Engine" and
030:         *    "Java Apache Project" must not be used to endorse or promote products
031:         *    derived from this software without prior written permission.
032:         *
033:         * 5. Products derived from this software may not be called "Apache JServ"
034:         *    nor may "Apache" nor "Apache JServ" appear in their names without
035:         *    prior written permission of the Java Apache Project.
036:         *
037:         * 6. Redistributions of any form whatsoever must retain the following
038:         *    acknowledgment:
039:         *    "This product includes software developed by the Java Apache
040:         *    Project for use in the Apache JServ servlet engine project
041:         *    <http://java.apache.org/>."
042:         *
043:         * THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
044:         * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
045:         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
046:         * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
047:         * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
048:         * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
049:         * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
050:         * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
051:         * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
052:         * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
053:         * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
054:         * OF THE POSSIBILITY OF SUCH DAMAGE.
055:         *
056:         * This software consists of voluntary contributions made by many
057:         * individuals on behalf of the Java Apache Group. For more information
058:         * on the Java Apache Project and the Apache JServ Servlet Engine project,
059:         * please see <http://java.apache.org/>.
060:         */
061:
062:        import java.util.Hashtable;
063:        import java.util.Vector;
064:        import java.util.Enumeration;
065:        import java.io.*;
066:        import java.net.URL;
067:        import java.util.zip.ZipFile;
068:        import java.util.zip.ZipException;
069:        import java.util.zip.ZipEntry;
070:
071:        /**
072:         * A class loader that loads classes from directories and/or zip-format
073:         * file such as JAR file. It tracks the modification time of the classes
074:         * it loads to permit reloading through re-instantiation.
075:         * <P>
076:         * When the classloader reports its creator that one of the classes it
077:         * has loaded has changed on disk, it should discard the classloader
078:         * and create a new instance using <CODE>reinstantiate</CODE>.
079:         * The classes are then reloaded into the new classloader as required.
080:         *
081:         * <P>The classloader can also load resources, which are a means
082:         * for packaging application data such as images within a jar file
083:         * or directory.
084:         *
085:         * <P>The classloader always first tries to load classes and resources
086:         * from the system, and uses it's own path if that fails. This is also
087:         * done if an empty repository is passed at construction.
088:         *
089:         * <P><B>How autoreload works:</B></P>
090:         *
091:         * <P>The Java VM considers two classes the same if they have the same
092:         * fully-qualified name <B>and</B> if they were loaded from the same
093:         * <CODE>ClassLoader</CODE>.
094:         *
095:         * <P>There is no way for a classloader to 'undefine' a class once it
096:         * has been loaded.  However, the servlet engine can discard a
097:         * classloader and the classes it contains, causing the
098:         *
099:         * <P>The <CODE>JServServletManager</CODE> creates a new instance of
100:         * the classloader each time it detects that any of the loaded classes
101:         * have changed.
102:         *
103:         * <P>Before terminating, all servlets are destroyed.
104:         *
105:         * <P>According to the Java Language Specification (JLS), classes may
106:         * be garbage-collected when there are no longer any instances of that
107:         * class and the <CODE>java.lang.Class</CODE> object is finalizable.
108:         * It is intended that this be the case when a <CODE>JServClassLoader</CODE>
109:         * is discarded.
110:         *
111:         * <P>Many VM releases did not implement class garbage collection
112:         * properly.  In such a VM, the memory usage will continue to grow if
113:         * autoreloading is enable.  Running the VM with
114:         * <CODE>-verbosegc</CODE> (or the corresponding option for
115:         * non-Javasoft VMs) may give some debugging information.
116:         *
117:         * <P>It is important that the <CODE>destroy</CODE> method be
118:         * implemented properly, as servlets may be destroyed and
119:         * reinitialized several times in the life of a VM.
120:         *
121:         * @author Dawid Weiss (modifications)
122:         * @author Francis J. Lacoste
123:         * @author Martin Pool
124:         * @author Jim Heintz
125:         * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
126:         * @see java.lang.ClassLoader
127:         */
128:        public class AdaptiveClassLoader extends ClassLoader {
129:
130:            /**
131:             * Generation counter, incremented for each classloader as they are
132:             * created.
133:             */
134:            static private int generationCounter = 0;
135:
136:            /**
137:             * Generation number of the classloader, used to distinguish between
138:             * different instances.
139:             */
140:            private int generation;
141:
142:            /**
143:             * Cache of the loaded classes. This contains ClassCacheEntry keyed
144:             * by class names.
145:             */
146:            private Hashtable cache;
147:
148:            /**
149:             * Save our class loader for chaining, and speed purposes.
150:             */
151:            private ClassLoader myParentClassLoader;
152:
153:            /**
154:             * The classpath which this classloader searches for class definitions.
155:             * Each element of the vector should be either a directory, a .zip
156:             * file, or a .jar file.
157:             * <p>
158:             * It may be empty when only system classes are controlled.
159:             */
160:            private Vector repository;
161:
162:            /**
163:             * Order of class resolving - if true, parent class loader is checked after
164:             * this class loader attempted to load a class.
165:             */
166:            private boolean parentClassLoaderLast;
167:
168:            /**
169:             * Private class used to maintain information about the classes that
170:             * we loaded.
171:             */
172:            private static class ClassCacheEntry {
173:
174:                /**
175:                 * The actual loaded class
176:                 */
177:                Class loadedClass;
178:
179:                /**
180:                 * The file from which this class was loaded; or null if
181:                 * it was loaded from the system.
182:                 */
183:                File origin;
184:
185:                /**
186:                 * The time at which the class was loaded from the origin
187:                 * file, in ms since the epoch.
188:                 */
189:                long lastModified;
190:
191:                /**
192:                 * Check whether this class was loaded from the system.
193:                 */
194:                public boolean isSystemClass() {
195:                    return origin == null;
196:                }
197:            }
198:
199:            //------------------------------------------------------- Constructors
200:
201:            /**
202:             * Creates a new class loader that will load classes from specified
203:             * class repositories.
204:             *
205:             * @param classRepository An set of File classes indicating
206:             *        directories and/or zip/jar files. It may be empty when
207:             *        only system classes are loaded.
208:             * @param parentClassLoaderLast if set to true, classes are resolved using
209:             *        this classloader before attempting the parent classloader. This
210:             *        feature can be used for dynamic reloading of classes, however
211:             *        it slows down performance and requires additional memory.
212:             * @throws java.lang.IllegalArgumentException if the objects contained
213:             *        in the vector are not a file instance or the file is not
214:             *        a valid directory or a zip/jar file.
215:             */
216:            public AdaptiveClassLoader(Vector classRepository,
217:                    boolean parentClassLoaderLast)
218:                    throws IllegalArgumentException {
219:                this (classRepository, null, parentClassLoaderLast);
220:            }
221:
222:            /**
223:             * Creates a new class loader that will load classes from specified
224:             * class repositories.
225:             *
226:             * @param classRepository An set of File classes indicating
227:             *        directories and/or zip/jar files. It may be empty when
228:             *        only system classes are loaded.
229:             * @param chainedClassLoader A class loader to attempt to load classes
230:             *        as resources thru before falling back on the default system
231:             *        loaders.
232:             * @param parentClassLoaderLast if set to true, classes are resolved using
233:             *        this classloader before attempting the parent classloader. This
234:             *        feature can be used for dynamic reloading of classes, however
235:             *        it slows down performance and requires additional memory.
236:             * @throws java.lang.IllegalArgumentException if the objects contained
237:             *        in the vector are not a file instance or the file is not
238:             *        a valid directory or a zip/jar file.
239:             */
240:            public AdaptiveClassLoader(Vector classRepository,
241:                    ClassLoader chainedClassLoader,
242:                    boolean parentClassLoaderLast)
243:                    throws IllegalArgumentException {
244:                this .parentClassLoaderLast = parentClassLoaderLast;
245:                myParentClassLoader = chainedClassLoader;
246:
247:                // Create the cache of loaded classes
248:                cache = new Hashtable();
249:
250:                // Verify that all the repository are valid.
251:                Enumeration e = classRepository.elements();
252:                while (e.hasMoreElements()) {
253:                    Object o = e.nextElement();
254:                    File file;
255:                    File[] files;
256:                    int i;
257:
258:                    // Check to see if element is a File instance.
259:                    try {
260:                        file = (File) o;
261:                    } catch (ClassCastException objectIsNotFile) {
262:                        throw new IllegalArgumentException("Object " + o
263:                                + "is not a valid \"File\" instance");
264:                    }
265:
266:                    // Check to see if we have proper access.
267:                    if (!file.exists()) {
268:                        throw new IllegalArgumentException("Repository "
269:                                + file.getAbsolutePath() + " doesn't exist!");
270:                    } else if (!file.canRead()) {
271:                        throw new IllegalArgumentException(
272:                                "Do not have read access for file "
273:                                        + file.getAbsolutePath());
274:                    }
275:
276:                    // Check that it is a directory or zip/jar file
277:                    if (!(file.isDirectory() || isZipOrJarArchive(file))) {
278:                        throw new IllegalArgumentException(
279:                                file.getAbsolutePath()
280:                                        + " is not a directory or zip/jar file"
281:                                        + " or if it's a zip/jar file then it is corrupted.");
282:                    }
283:                }
284:
285:                // Store the class repository for use
286:                this .repository = classRepository;
287:
288:                // Increment and store generation counter
289:                this .generation = generationCounter++;
290:            }
291:
292:            //------------------------------------------------------- Methods
293:
294:            /**
295:             * Test if a file is a ZIP or JAR archive.
296:             *
297:             * @param file the file to be tested.
298:             * @return true if the file is a ZIP/JAR archive, false otherwise.
299:             */
300:            private boolean isZipOrJarArchive(File file) {
301:                boolean isArchive = true;
302:                ZipFile zipFile = null;
303:
304:                try {
305:                    zipFile = new ZipFile(file);
306:                } catch (ZipException zipCurrupted) {
307:                    isArchive = false;
308:                } catch (IOException anyIOError) {
309:                    isArchive = false;
310:                } finally {
311:                    if (zipFile != null) {
312:                        try {
313:                            zipFile.close();
314:                        } catch (IOException ignored) {
315:                        }
316:                    }
317:                }
318:
319:                return isArchive;
320:            }
321:
322:            /**
323:             * Check to see if a given class should be reloaded because of a
324:             * modification to the original class.
325:             *
326:             * @param classname The name of the class to check for modification.
327:             */
328:            public synchronized boolean shouldReload(String classname) {
329:
330:                ClassCacheEntry entry = (ClassCacheEntry) cache.get(classname);
331:
332:                if (entry == null) {
333:                    // class wasn't even loaded
334:                    return false;
335:                } else if (entry.isSystemClass()) {
336:                    // System classes cannot be reloaded
337:                    return false;
338:                } else {
339:                    boolean reload = (entry.origin.lastModified() != entry.lastModified);
340:                    return reload;
341:                }
342:            }
343:
344:            /**
345:             * Check whether the classloader should be reinstantiated.
346:             * <P>
347:             * The classloader must be replaced if there is any class whose
348:             * origin file has changed since it was last loaded.
349:             */
350:            public synchronized boolean shouldReload() {
351:
352:                // Check whether any class has changed
353:                Enumeration e = cache.elements();
354:                while (e.hasMoreElements()) {
355:                    ClassCacheEntry entry = (ClassCacheEntry) e.nextElement();
356:
357:                    if (entry.isSystemClass())
358:                        continue;
359:
360:                    // XXX: Because we want the classloader to be an accurate
361:                    // reflection of the contents of the repository, we also
362:                    // reload if a class origin file is now missing.  This
363:                    // probably makes things a bit more fragile, but is OK in
364:                    // a servlet development situation. <mbp@pharos.com.au>
365:
366:                    long msOrigin = entry.origin.lastModified();
367:
368:                    if (msOrigin == 0) {
369:                        // class no longer exists
370:                        return true;
371:                    }
372:
373:                    if (msOrigin != entry.lastModified) {
374:                        // class is modified
375:                        return true;
376:                    }
377:                }
378:
379:                // No changes, no need to reload
380:                return false;
381:            }
382:
383:            /**
384:             * Re-instantiate this class loader.
385:             * <p>
386:             * This method creates a new instance
387:             * of the class loader that will load classes form the same path
388:             * as this one.
389:             */
390:            public AdaptiveClassLoader reinstantiate() {
391:                return new AdaptiveClassLoader(repository, myParentClassLoader,
392:                        parentClassLoaderLast);
393:            }
394:
395:            //------------------------------------ Implementation of Classloader
396:
397:            /*
398:             * XXX: The javadoc for java.lang.ClassLoader says that the
399:             * ClassLoader should cache classes so that it can handle repeated
400:             * requests for the same class.  On the other hand, the JLS seems
401:             * to imply that each classloader is only asked to load each class
402:             * once.  Is this a contradiction?
403:             *
404:             * Perhaps the second call only applies to classes which have been
405:             * garbage-collected?
406:             */
407:
408:            /**
409:             * Resolves the specified name to a Class. The method loadClass()
410:             * is called by the virtual machine.  As an abstract method,
411:             * loadClass() must be defined in a subclass of ClassLoader.
412:             *
413:             * @param      name the name of the desired Class.
414:             * @param      resolve true if the Class needs to be resolved;
415:             *             false if the virtual machine just wants to determine
416:             *             whether the class exists or not
417:             * @return     the resulting Class.
418:             * @exception  ClassNotFoundException  if the class loader cannot
419:             *             find a the requested class.
420:             */
421:            protected synchronized Class loadClass(String name, boolean resolve)
422:                    throws ClassNotFoundException {
423:                // The class object that will be returned.
424:                Class c = null;
425:
426:                // Use the cached value, if this class is already loaded into
427:                // this classloader.
428:                ClassCacheEntry entry = (ClassCacheEntry) cache.get(name);
429:
430:                if (entry != null) {
431:                    // Class found in our cache
432:                    c = entry.loadedClass;
433:                    if (resolve)
434:                        resolveClass(c);
435:                    return c;
436:                }
437:
438:                if (!securityAllowsClass(name)) {
439:                    return loadSystemClass(name, resolve);
440:                }
441:
442:                if (parentClassLoaderLast == false) {
443:                    // Attempt to load the class from the system
444:                    try {
445:                        c = loadSystemClass(name, resolve);
446:                        if (c != null) {
447:                            if (resolve)
448:                                resolveClass(c);
449:                            return c;
450:                        }
451:                    } catch (Exception e) {
452:                        c = null;
453:                    }
454:                }
455:
456:                // Try to load it from each repository
457:                Enumeration repEnum = repository.elements();
458:
459:                // Cache entry.
460:                ClassCacheEntry classCache = new ClassCacheEntry();
461:                while (repEnum.hasMoreElements()) {
462:                    byte[] classData = null;
463:
464:                    File file = (File) repEnum.nextElement();
465:                    try {
466:                        if (file.isDirectory()) {
467:                            classData = loadClassFromDirectory(file, name,
468:                                    classCache);
469:                        } else {
470:                            classData = loadClassFromZipfile(file, name,
471:                                    classCache);
472:                        }
473:                    } catch (IOException ioe) {
474:                        // Error while reading in data, consider it as not found
475:                        classData = null;
476:                    }
477:
478:                    if (classData != null) {
479:                        // Define the class
480:                        c = defineClass(name, classData, 0, classData.length);
481:                        // Cache the result;
482:                        classCache.loadedClass = c;
483:                        // Origin is set by the specific loader
484:                        classCache.lastModified = classCache.origin
485:                                .lastModified();
486:                        cache.put(name, classCache);
487:
488:                        // Resolve it if necessary
489:                        if (resolve)
490:                            resolveClass(c);
491:
492:                        return c;
493:                    }
494:                }
495:
496:                if (parentClassLoaderLast == true) {
497:                    // Attempt to load the class from the system
498:                    try {
499:                        c = loadSystemClass(name, resolve);
500:                        if (c != null) {
501:                            if (resolve)
502:                                resolveClass(c);
503:                            return c;
504:                        }
505:                    } catch (Exception e) {
506:                        c = null;
507:                    }
508:                }
509:
510:                // If not found in any repository
511:                throw new ClassNotFoundException(name);
512:            }
513:
514:            /**
515:             * Load a class using the system classloader.
516:             *
517:             * @exception  ClassNotFoundException  if the class loader cannot
518:             *             find a the requested class.
519:             * @exception  NoClassDefFoundError  if the class loader cannot
520:             *             find a definition for the class.
521:             */
522:            protected Class loadSystemClass(String name, boolean resolve)
523:                    throws NoClassDefFoundError, ClassNotFoundException {
524:                if (myParentClassLoader != null)
525:                    return myParentClassLoader.loadClass(name);
526:                Class c = findSystemClass(name);
527:                // Throws if not found.
528:
529:                // Add cache entry
530:                ClassCacheEntry cacheEntry = new ClassCacheEntry();
531:                cacheEntry.origin = null;
532:                cacheEntry.loadedClass = c;
533:                cacheEntry.lastModified = Long.MAX_VALUE;
534:                cache.put(name, cacheEntry);
535:
536:                if (resolve)
537:                    resolveClass(c);
538:
539:                return c;
540:            }
541:
542:            /**
543:             * Checks whether a classloader is allowed to define a given class,
544:             * within the security manager restrictions.
545:             */
546:            // XXX: Should we perhaps also not allow classes to be dynamically
547:            // loaded from org.apache.jserv.*?  Would it introduce security
548:            // problems if people could override classes here?
549:            // <mbp@humbug.org.au 1998-07-29>
550:            private boolean securityAllowsClass(String className) {
551:                try {
552:                    SecurityManager security = System.getSecurityManager();
553:
554:                    if (security == null) {
555:                        // if there's no security manager then all classes
556:                        // are allowed to be loaded
557:                        return true;
558:                    }
559:
560:                    int lastDot = className.lastIndexOf('.');
561:                    // Check if we are allowed to load the class' package
562:                    security.checkPackageDefinition((lastDot > -1) ? className
563:                            .substring(0, lastDot) : "");
564:                    // Throws if not allowed
565:                    return true;
566:                } catch (SecurityException e) {
567:                    return false;
568:                }
569:            }
570:
571:            /**
572:             * Tries to load the class from a directory.
573:             *
574:             * @param dir The directory that contains classes.
575:             * @param name The classname
576:             * @param cache The cache entry to set the file if successful.
577:             */
578:            private byte[] loadClassFromDirectory(File dir, String name,
579:                    ClassCacheEntry cache) throws IOException {
580:                // Translate class name to file name
581:                String classFileName = name.replace('.', File.separatorChar)
582:                        + ".class";
583:
584:                // Check for garbage input at beginning of file name
585:                // i.e. ../ or similar
586:                if (!Character.isJavaIdentifierStart(classFileName.charAt(0))) {
587:                    // Find real beginning of class name
588:                    int start = 1;
589:                    while (!Character.isJavaIdentifierStart(classFileName
590:                            .charAt(start++)))
591:                        ;
592:                    classFileName = classFileName.substring(start);
593:                }
594:
595:                File classFile = new File(dir, classFileName);
596:
597:                if (classFile.exists()) {
598:                    cache.origin = classFile;
599:                    InputStream in = new FileInputStream(classFile);
600:                    try {
601:                        return loadBytesFromStream(in, (int) classFile.length());
602:                    } finally {
603:                        in.close();
604:                    }
605:                } else {
606:                    // Not found
607:                    return null;
608:                }
609:            }
610:
611:            /**
612:             * Tries to load the class from a zip file.
613:             *
614:             * @param file The zipfile that contains classes.
615:             * @param name The classname
616:             * @param cache The cache entry to set the file if successful.
617:             */
618:            private byte[] loadClassFromZipfile(File file, String name,
619:                    ClassCacheEntry cache) throws IOException {
620:                // Translate class name to file name
621:                String classFileName = name.replace('.', '/') + ".class";
622:
623:                ZipFile zipfile = new ZipFile(file);
624:
625:                try {
626:                    ZipEntry entry = zipfile.getEntry(classFileName);
627:                    if (entry != null) {
628:                        cache.origin = file;
629:                        return loadBytesFromStream(zipfile
630:                                .getInputStream(entry), (int) entry.getSize());
631:                    } else {
632:                        // Not found
633:                        return null;
634:                    }
635:                } finally {
636:                    zipfile.close();
637:                }
638:            }
639:
640:            /**
641:             * Loads all the bytes of an InputStream.
642:             */
643:            private byte[] loadBytesFromStream(InputStream in, int length)
644:                    throws IOException {
645:                byte[] buf = new byte[length];
646:                int nRead, count = 0;
647:
648:                while ((length > 0)
649:                        && ((nRead = in.read(buf, count, length)) != -1)) {
650:                    count += nRead;
651:                    length -= nRead;
652:                }
653:
654:                return buf;
655:            }
656:
657:            /**
658:             * Get an InputStream on a given resource.  Will return null if no
659:             * resource with this name is found.
660:             * <p>
661:             * The JServClassLoader translate the resource's name to a file
662:             * or a zip entry. It looks for the resource in all its repository
663:             * entry.
664:             *
665:             * @see     java.lang.Class#getResourceAsStream(String)
666:             * @param   name    the name of the resource, to be used as is.
667:             * @return  an InputStream on the resource, or null if not found.
668:             */
669:            public InputStream getResourceAsStream(String name) {
670:                // Try to load it from the system class
671:                InputStream s = null;
672:                if (myParentClassLoader != null) {
673:                    s = myParentClassLoader.getResourceAsStream(name);
674:                }
675:                if (s == null) {
676:                    s = getSystemResourceAsStream(name);
677:                }
678:
679:                if (s == null) {
680:                    // Try to find it from every repository
681:                    Enumeration repEnum = repository.elements();
682:                    while (repEnum.hasMoreElements()) {
683:                        File file = (File) repEnum.nextElement();
684:                        if (file.isDirectory()) {
685:                            s = loadResourceFromDirectory(file, name);
686:                        } else if (name.endsWith(".initArgs")) {
687:                            String parentFile = file.getParent();
688:                            if (parentFile != null) {
689:                                File dir = new File(parentFile);
690:                                s = loadResourceFromDirectory(dir, name);
691:                            }
692:                        } else {
693:                            s = loadResourceFromZipfile(file, name);
694:                        }
695:
696:                        if (s != null) {
697:                            break;
698:                        }
699:                    }
700:                }
701:                return s;
702:            }
703:
704:            /**
705:             * Loads resource from a directory.
706:             */
707:            private InputStream loadResourceFromDirectory(File dir, String name) {
708:                // Name of resources are always separated by /
709:                String fileName = name.replace('/', File.separatorChar);
710:                File resFile = new File(dir, fileName);
711:
712:                if (resFile.exists()) {
713:                    try {
714:                        return new FileInputStream(resFile);
715:                    } catch (FileNotFoundException shouldnothappen) {
716:                        return null;
717:                    }
718:                } else {
719:                    return null;
720:                }
721:            }
722:
723:            /**
724:             * Loads resource from a zip file
725:             */
726:            private InputStream loadResourceFromZipfile(File file, String name) {
727:                ZipFile zipfile = null;
728:                InputStream resourceStream = null;
729:                try {
730:                    zipfile = new ZipFile(file);
731:                    ZipEntry entry = zipfile.getEntry(name);
732:
733:                    if (entry != null) {
734:                        long length = entry.getSize();
735:                        resourceStream = zipfile.getInputStream(entry);
736:                        byte[] data = loadBytesFromStream(resourceStream,
737:                                (int) length);
738:                        return new ByteArrayInputStream(data);
739:                    } else {
740:                        return null;
741:                    }
742:                } catch (IOException e) {
743:                    return null;
744:                } finally {
745:                    if (resourceStream != null) {
746:                        try {
747:                            resourceStream.close();
748:                        } catch (IOException ignored) {
749:                        }
750:                    }
751:                    if (zipfile != null) {
752:                        try {
753:                            zipfile.close();
754:                        } catch (IOException ignored) {
755:                        }
756:                    }
757:                }
758:            }
759:
760:            /**
761:             * Find a resource with a given name.  The return is a URL to the
762:             * resource. Doing a getContent() on the URL may return an Image,
763:             * an AudioClip,or an InputStream.
764:             * <p>
765:             * This classloader looks for the resource only in the directory
766:             * repository for this resource.
767:             *
768:             * @param   name    the name of the resource, to be used as is.
769:             * @return  an URL on the resource, or null if not found.
770:             */
771:            public URL getResource(String name) {
772:
773:                if (name == null) {
774:                    return null;
775:                }
776:
777:                // First ask the primordial class loader to fetch it from the classpath
778:
779:                URL u = null;
780:                if (myParentClassLoader != null) {
781:                    u = myParentClassLoader.getResource(name);
782:                }
783:                if (u == null) {
784:                    u = getSystemResource(name);
785:                }
786:                if (u != null) {
787:                    return u;
788:                }
789:
790:                // We got here so we have to look for the resource in our list of repository elements
791:                Enumeration repEnum = repository.elements();
792:                while (repEnum.hasMoreElements()) {
793:                    File file = (File) repEnum.nextElement();
794:                    // Construct a file://-URL if the repository is a directory
795:                    if (file.isDirectory()) {
796:                        String fileName = name.replace('/', File.separatorChar);
797:                        File resFile = new File(file, fileName);
798:                        if (resFile.exists()) {
799:                            // Build a file:// URL form the file name
800:                            try {
801:                                return new URL("file", null, resFile
802:                                        .getAbsolutePath());
803:                            } catch (java.net.MalformedURLException badurl) {
804:                                badurl.printStackTrace();
805:                                return null;
806:                            }
807:                        }
808:                    } else {
809:                        // a jar:-URL *could* change even between minor releases, but
810:                        // didn't between JVM's 1.1.6 and 1.3beta. Tested on JVM's from
811:                        // IBM, Blackdown, Microsoft, Sun @ Windows and Sun @ Solaris
812:                        try {
813:                            ZipFile zf = new ZipFile(file.getAbsolutePath());
814:                            ZipEntry ze = zf.getEntry(name);
815:
816:                            if (ze != null) {
817:                                try {
818:                                    return new URL("jar:file:"
819:                                            + file.getAbsolutePath() + "!/"
820:                                            + name);
821:                                } catch (java.net.MalformedURLException badurl) {
822:                                    badurl.printStackTrace();
823:                                    return null;
824:                                }
825:                            }
826:                        } catch (IOException ioe) {
827:                            ioe.printStackTrace();
828:                            return null;
829:                        }
830:                    }
831:                }
832:
833:                // Not found
834:                return null;
835:            }
836:
837:            /**
838:             * Return the last modified time for a class in the
839:             * ClassCache.
840:             *
841:             * @throws ClassNotFoundException if class is not found
842:             */
843:            public long lastModified(String name) throws ClassNotFoundException {
844:                ClassCacheEntry entry = (ClassCacheEntry) cache.get(name);
845:                if (entry == null) {
846:                    throw new ClassNotFoundException("Could not find class: "
847:                            + name);
848:                } else {
849:                    return entry.lastModified;
850:                }
851:            }
852:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.