Source Code Cross Referenced for MultiClassLoader.java in  » J2EE » Enhydra-Application-Framework » com » lutris » classloader » 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 » J2EE » Enhydra Application Framework » com.lutris.classloader 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Enhydra Java Application Server Project
0003:         *
0004:         * The contents of this file are subject to the Enhydra Public License
0005:         * Version 1.1 (the "License"); you may not use this file except in
0006:         * compliance with the License. You may obtain a copy of the License on
0007:         * the Enhydra web site ( http://www.enhydra.org/ ).
0008:         *
0009:         * Software distributed under the License is distributed on an "AS IS"
0010:         * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
0011:         * the License for the specific terms governing rights and limitations
0012:         * under the License.
0013:         *
0014:         * The Initial Developer of the Enhydra Application Server is Lutris
0015:         * Technologies, Inc. The Enhydra Application Server and portions created
0016:         * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
0017:         * All Rights Reserved.
0018:         *
0019:         * Contributor(s):
0020:         *
0021:         * $Id: MultiClassLoader.java,v 1.3 2007-10-19 10:35:46 sinisa Exp $
0022:         *
0023:         * formatted with JxBeauty (c) johann.langhofer@nextra.at
0024:         */
0025:
0026:        package com.lutris.classloader;
0027:
0028:        import java.io.ByteArrayOutputStream;
0029:        import java.io.File;
0030:        import java.io.FileNotFoundException;
0031:        import java.io.IOException;
0032:        import java.io.InputStream;
0033:        import java.net.MalformedURLException;
0034:        import java.net.URL;
0035:        import java.util.Enumeration;
0036:        import java.util.Hashtable;
0037:        import java.util.StringTokenizer;
0038:        import java.util.Vector;
0039:
0040:        import com.lutris.logging.LogChannel;
0041:
0042:        /**
0043:         * <P><B>Summary:</B>
0044:         * <P>A class loader that can load classes from
0045:         * class files and zip files residing in a specified class path.
0046:         *
0047:         * <P>This class loader can also load resources that reside on the
0048:         * class path and return them as is, as input streams, or as byte arrays.
0049:         *
0050:         * <P><B>Features:</B>
0051:         * <UL>
0052:         * <LI>Loads classes from class files and zip files.
0053:         * <LI>Finds resources and can return them as is, as input streams and as byte arrays.
0054:         * <LI>Loads classes and resources using the specified class path. Class
0055:         *     path entries can be URLs, directories, zip files or jar files.
0056:         * <P> A secondary classloader can be specified which is used to locate
0057:         *     the class if its not found by this classloader.
0058:         * <LI> A filter object can be supplied to determine if the current class
0059:         *      loader should load the class or it should be passed to the parent or
0060:         *      secondary class loader.
0061:         * </UL>
0062:         *
0063:         * <H3>Class Path</H3>
0064:         *
0065:         * <P>If classes are to be loaded from a class path, it must be set by the
0066:         * <CODE>setClassPath</CODE> or <CODE>addClassPath</CODE> methods or by
0067:         * the constructor prior to calling <CODE>loadClass</CODE>. If the class
0068:         * path is not set, the class will be loaded with the system class loader.
0069:         *
0070:         * <P>The class path can consist of directories, files, and/or URLs.
0071:         * <P>Example valid class path entries are:
0072:         * <PRE>
0073:         *     <EM>Files and directories on the local file system</EM>
0074:         *     ../../java/classes
0075:         *     /users/kristen/java/classes
0076:         *     /users/kristen/java/classes/
0077:         *     /users/kristen/java/zipfiles/MyClasses.zip
0078:         *     /users/kristen/java/jarfiles/MyClasses.jar
0079:         *     file:///users/kristen/java/classes
0080:         *     file://localhost/users/kristen/java/classes
0081:         *     <BR>
0082:         *     <EM>Files and directories on a remote file system
0083:         *         (must be in URL format)</EM>
0084:         *     ftp://www.foo.com/pub/java/classes
0085:         *     file://www.foo.com/pub/java/classes/
0086:         *     http://www.foo.com/web/java/classes/
0087:         *     file://www.foo.com:8080/pub/java/zipfiles/MyClasses.zip
0088:         *     http://www.foo.com:8080/web/java/jarfiles/MyClasses.jar
0089:         * </PRE>
0090:         *
0091:         * <P>Note that the location of the entry includes the protocol, the host name,
0092:         * and the port while the file name is everything else.  For example,
0093:         *
0094:         * <PRE>
0095:         *     http://www.foo.com:8080/web/java/jarfiles/MyClasses.jar
0096:         * </PRE>
0097:         * has the form [location][name] or
0098:         * <PRE>
0099:         *     [http://www.foo.com:8080/][/web/java/jarfiles/MyClasses.jar]
0100:         * </PRE>
0101:         * so the location is "http://www.foo.com:8080/" and the name is
0102:         * "/web/java/jarfiles/MyClasses.jar".
0103:         *
0104:         * <P>Note that the two references
0105:         * <PRE>
0106:         *     /users/kristen/java/classes/
0107:         *     file:///users/kristen/java/classes/
0108:         * </PRE>
0109:         * represent the same directory on a Unix machine, and
0110:         * <PRE>
0111:         *     C|/windows/java/classes/
0112:         *     file:///C|/windows/java/classes/
0113:         * </PRE>
0114:         * are equivalent directories on a Windows box.
0115:         *
0116:         * <P>But the two references
0117:         * <PRE>
0118:         *     /users/kristen/java/classes/
0119:         *     file://monet.lutris.com/users/kristen/java/classes/
0120:         * </PRE>
0121:         * are not equivalent even if the directory
0122:         * <EM>/users/kristen/java/classes/</EM> lives
0123:         * on the machine named <EM>monet.lutris.com</EM> and all development
0124:         * is on this machine.  Why?  Because the web (browser?) protocol is different
0125:         * for URLs with host information and those without.  If no host is
0126:         * specified, the file is assumed to be on the local machine and the
0127:         * path is determined from the <EM>ROOT</EM> of the machine.  If the
0128:         * host is specified, then the <EM>ftp protocol</EM> is used and the path
0129:         * is determined from the <EM>ftp ROOT</EM> (e.g. /users/ftp/) rather
0130:         * than the machine's ROOT.  Thus, on a machine that support's anonymous
0131:         * ftp, the following two directories are the same:
0132:         * <PRE>
0133:         *     /users/ftp/pub/classes/
0134:         *     file://picasso.lutris.com/pub/classes/
0135:         * </PRE>
0136:         * assuming the development is being done on <EM>picasso.lutris.com</EM>.
0137:         *
0138:         * <H3>System Class Path</H3>
0139:         *
0140:         * <P>The system class path is the system-dependent path of directories
0141:         * and files (e.g. CLASSPATH on Unix and Windows) used by the system
0142:         * class loader to load classes.  This class path is usually configured
0143:         * prior to executing a Java program but can be dynamically configured
0144:         * during runtime if desired.  If you want to use the system class path
0145:         * for this class loader, the convenience method <CODE>getSystemClassPath</CODE>
0146:         * has been provided.
0147:         *
0148:         * <P>Valid system class path entries are
0149:         * directories and zip files, specified by absolute path or relative path
0150:         * on the system.  Any valid system class path entry is also valid
0151:         * for this class loader.
0152:         *
0153:         * <H3>Example</H3>
0154:         *
0155:         * <P>Here is an example of how to use this class loader:
0156:         * <PRE>
0157:         *     MultiClassLoader loader = new MultiClassLoader();
0158:         *     loader.setClassPath("/web/java/lutris.jar");
0159:         *     loader.addClassPath("/users/kristen/java/");
0160:         *     loader.addClassPath("/usr/local/lib/graphics.zip");
0161:         *     try {
0162:         *         Class c = loader.loadClass("com.lutris.util.MyClass");
0163:         *         System.out.println("My loader is " + c.getClassLoader());
0164:         *         Object o = (Object) c.newInstance();
0165:         *         System.out.println("My class is " + o.getClass());
0166:         *     } catch (ClassNotFoundException e) {
0167:         *         Throwable t = new Throwable();
0168:         *         t.printStackTrace();
0169:         *     }
0170:         * </PRE>
0171:         *
0172:         * <P>
0173:         * <B>Warning:</B>  This class loader is not yet fully compliant with Java 1.2.  It
0174:         * maybe used on 1.2, but not all features are available.  The <em>parent</em> loader,
0175:         * <em>secondary</em> loader, and <em>filter</em> may change in a future release without
0176:         * maintaining compatibility.
0177:         *
0178:         * <!--
0179:         * FIXME:
0180:         * This class needs revisited for JDK 1.2, including adding security
0181:         * managers.  Should implement the find* methods, but probably
0182:         * must have its own loadClass.  Need to have resource loading
0183:         * follow same paradigm as class loading.
0184:         *
0185:         * -->
0186:         *
0187:         * @author Kristen Pol, Lutris Technologies
0188:         * @version $Revision : 1.0 $
0189:         * @see java.lang.ClassLoader
0190:         * @see com.lutris.classloader.Resource
0191:         * @see java.net.URL
0192:         */
0193:        public class MultiClassLoader extends ClassLoader {
0194:
0195:            /**
0196:             * A filter interface, used in deciding if a class should be loaded
0197:             * by this class loader.
0198:             */
0199:            public interface ClassFilter {
0200:                /**
0201:                 * Value returned to indicate that we don't care, other filters
0202:                 * maybe checked.
0203:                 */
0204:                public static final int NORMAL_LOAD = 1;
0205:                /**
0206:                 * Value returned to indicate that the class should not be loaded
0207:                 * by this class loader.  Normal delation/secondary class loader
0208:                 * checks will be done.
0209:                 */
0210:                public static final int DONT_LOAD = 2;
0211:                /**
0212:                 * Value returned to indicate that the class can be loaded
0213:                 * by this class loader.  If it is not loaded, it will be
0214:                 * passed to the secondary class loader.  The delegate
0215:                 * is not check, since it is check before this class loader.
0216:                 */
0217:                public static final int CAN_LOAD = 3;
0218:                /**
0219:                 * Value returned to indicate that the class must loaded
0220:                 * by this class loader.  If it is not loaded, not other
0221:                 * class loader will be checked.
0222:                 */
0223:                public static final int MUST_LOAD = 4;
0224:
0225:                /**
0226:                 * Check if a class should be loaded by this class loader.
0227:                 * @param className the class being loaded.
0228:                 * @return One of NORMAL_LOAD, DONT_LOAD, CAN_LOAD, or MUST_LOAD.
0229:                 */
0230:                public int loadCheck(String className);
0231:            }
0232:
0233:            /**
0234:             * Information kept about a loaded class.
0235:             */
0236:            public static class ClassResource {
0237:
0238:                /**
0239:                 * Class object
0240:                 */
0241:                private Class classObj;
0242:
0243:                /**
0244:                 * Resource were the class was obtained.
0245:                 */
0246:                private Resource resource;
0247:
0248:                /**
0249:                 * Constructor.
0250:                 */
0251:                public ClassResource(Class classObj, Resource resource) {
0252:                    this .classObj = classObj;
0253:                    this .resource = resource;
0254:                }
0255:
0256:                /**
0257:                 * Get the class object.
0258:                 */
0259:                public Class getClassObj() {
0260:                    return classObj;
0261:                }
0262:
0263:                /**
0264:                 * Get the resource.  Maybe null if the class was not loaded by
0265:                 * a MultiClassLoader.
0266:                 */
0267:                public Resource getResource() {
0268:                    return resource;
0269:                }
0270:            }
0271:
0272:            /**
0273:             * The ClassResource objects for classes loaded by this classloader
0274:             * (but not those handled by the parent).
0275:             */
0276:            private Hashtable loadedClasses = new Hashtable();
0277:
0278:            /**
0279:             * The class path to check when loading classes.
0280:             */
0281:            private ClassPath classPath;
0282:
0283:            /**
0284:             * Log level symbolic name
0285:             */
0286:            public static final String LOG_LEVEL = "CLASSLOAD";
0287:
0288:            /**
0289:             * Is logging enabled?
0290:             */
0291:            private boolean loggingEnabled = false;
0292:
0293:            /**
0294:             * Log channel to write messages to; maybe null.
0295:             */
0296:            private LogChannel logChannel;
0297:
0298:            /**
0299:             * Numeric log level number for LOG_LEVEL string
0300:             */
0301:            private int logLevel;
0302:
0303:            /**
0304:             * If any class filters are supplied, this is a non-null list of
0305:             * filters to check.
0306:             */
0307:            private Vector filters = null;
0308:
0309:            /**
0310:             * Parent class loader, or null if there isn't one.
0311:             */
0312:            private ClassLoader parentClassLoader;
0313:
0314:            /**
0315:             * Secondary class loader, or null if there isn't one.
0316:             */
0317:            private ClassLoader secondaryClassLoader;
0318:
0319:            /**
0320:             * Flag which indicates that using of secondary ClassLoader will be forced.
0321:             * If this flag is true the MultiClassLoader is used as utility wrapper class
0322:             * for passed secondary ClassLoader.
0323:             */
0324:            private boolean forceSecondaryLoader = false; //vr 28.06.2004
0325:
0326:            /**
0327:             * Flag which indicates using of MultiClassLoader with AutoReload option.
0328:             */
0329:            private boolean isAutoReload = false; //vr 30.06.2004
0330:
0331:            /**
0332:             * Constructs class loader with no initial class path and a
0333:             * specified parent class loader.
0334:             * @param parent The parent class loader for delegation,
0335:             * or null if no parent is defined.
0336:             * @param secondary The secondary class loader.
0337:             * Use <code>getSysClassLoader</code> to get the system class loader
0338:             * to specify as the secondary.
0339:             * @param loadLogChannel The log channel, maybe null.
0340:             * @see getSysClassLoader
0341:             */
0342:            public MultiClassLoader(ClassLoader parent, ClassLoader secondary,
0343:                    LogChannel loadLogChannel) {
0344:                classPath = new ClassPath(loadLogChannel);
0345:                // v. puskas, 10.03.2003  	native compile changes;
0346:                //    parentClassLoader = parent;
0347:                parentClassLoader = (null != parent) ? parent
0348:                        : getSystemClassLoader();
0349:                secondaryClassLoader = secondary;
0350:                logChannel = loadLogChannel;
0351:                if (logChannel != null) {
0352:                    logLevel = logChannel.getLevel(LOG_LEVEL);
0353:                    loggingEnabled = logChannel.isEnabled(logLevel);
0354:                }
0355:
0356:            }
0357:
0358:            /**
0359:             * Constructs class loader with no initial class path and the
0360:             * system class loader as the secondary.
0361:             * @param loadLogChannel The log channel, maybe null.
0362:             */
0363:            public MultiClassLoader(LogChannel loadLogChannel) {
0364:                this (null, getSystemClassLoader(), loadLogChannel);
0365:            }
0366:
0367:            /**
0368:             * Constructs class loader with specified class path.  The parameter is
0369:             * assumed to be either a directory, URL, or zip file.
0370:             * @param path The class path represented by a String.
0371:             * @param loadLogChannel The log channel, maybe null.
0372:             */
0373:            public MultiClassLoader(String path, LogChannel loadLogChannel) {
0374:                this (new String[] { path }, loadLogChannel);
0375:            }
0376:
0377:            /**
0378:             * Constructs class loader with specified class path.  The parameter is
0379:             * assumed to be an array of directories, URLs, and/or zip files.
0380:             * @param path The class path represented by a String array.
0381:             * @param loadLogChannel The log channel, maybe null.
0382:             */
0383:            public MultiClassLoader(String[] path, LogChannel loadLogChannel) {
0384:                this (loadLogChannel);
0385:                setClassPath(path);
0386:            }
0387:
0388:            /**
0389:             * Constructs class loader with specified class path.  The parameter is
0390:             * assumed to be either a zip file or directory.
0391:             * @param path The class path represented by a File.
0392:             * @param loadLogChannel The log channel, maybe null.
0393:             */
0394:            public MultiClassLoader(File path, LogChannel loadLogChannel) {
0395:                this (new File[] { path }, loadLogChannel);
0396:            }
0397:
0398:            /**
0399:             * Constructs class loader with specified class path.  The parameter is
0400:             * assumed to be an array of zip files and/or directories.
0401:             * @param path The class path represented by a File array.
0402:             * @param loadLogChannel The log channel, maybe null.
0403:             */
0404:            public MultiClassLoader(File[] path, LogChannel loadLogChannel) {
0405:                this (loadLogChannel);
0406:                setClassPath(path);
0407:            }
0408:
0409:            /**
0410:             * Constructs class loader with specified class path.  The parameter is
0411:             * represent a directory or zip file on the local machine or a
0412:             * remote machine.
0413:             * @param path The class path represented by a URL.
0414:             * @param loadLogChannel The log channel, maybe null.
0415:             */
0416:            public MultiClassLoader(URL path, LogChannel loadLogChannel) {
0417:                this (new URL[] { path }, loadLogChannel);
0418:            }
0419:
0420:            /**
0421:             * Constructs class loader with specified class path.  The parameter is
0422:             * represent directories and/or zip files on the local machine and/or
0423:             * on remote machines.
0424:             * @param path The class path represented by a URL array.
0425:             * @param loadLogChannel The log channel, maybe null.
0426:             */
0427:            public MultiClassLoader(URL[] path, LogChannel loadLogChannel) {
0428:                this (loadLogChannel);
0429:                setClassPath(path);
0430:            }
0431:
0432:            /**
0433:             * Sets flag to indicate forsing of Secondary ClassLoader usage or not.
0434:             * @param force true when the MultiClassLoader is used as utility wrapper
0435:             * class for passed secondary ClassLoader. All resource loads will be forced
0436:             * via passed Secondary ClassLoader. If parameter is set to false, then the
0437:             * MultyClassLoader will work in standard maner.
0438:             */
0439:            public void forceSecondaryLoader(boolean force) { //vr 28.06.2004
0440:                this .forceSecondaryLoader = force;
0441:            }
0442:
0443:            /**
0444:             * Sets flag to enable Auto Reloading possibility when Secondary ClassLoader
0445:             * usage is forced (refer to forceSecondaryLoader() method for more help).
0446:             * This flag has no efect when MultiClassLoader is used in standard maner (as
0447:             * realy ClassLoader, not only as wrapper class for external ClassLoader)
0448:             * @param enable true when the AutoReloading should be used.
0449:             */
0450:            public void enableAutoReloadForSecLoader(boolean enable) { //vr 30.06.2004
0451:                this .isAutoReload = enable;
0452:            }
0453:
0454:            /**
0455:             * Removes stored data about already loaded classes
0456:             */
0457:            public void removeLoadedClass() { //vr 28.06.2004
0458:                this .loadedClasses = new Hashtable();
0459:            }
0460:
0461:            /**
0462:             * Sets class loader with specified class path.  The parameter is
0463:             * assumed to be either a directory, URL, or zip file.
0464:             * @param path The class path to be used when loading classes.
0465:             */
0466:            public void setClassPath(String path) {
0467:                setClassPath(new String[] { path });
0468:            }
0469:
0470:            /**
0471:             * Sets class loader with specified class path.  The parameter is
0472:             * assumed to be an array of directories, URLs, and/or zip files.
0473:             * @param path The class path to be used when loading classes.
0474:             */
0475:            public synchronized void setClassPath(String[] path) {
0476:                classPath.set(path);
0477:            }
0478:
0479:            /**
0480:             * Sets class loader with specified class path.  The parameter is
0481:             * assumed to be either a zip file or directory.
0482:             * @param path The class path to be used when loading classes.
0483:             */
0484:            public void setClassPath(File path) {
0485:                setClassPath(new File[] { path });
0486:            }
0487:
0488:            /**
0489:             * Sets class loader with specified class path.  The parameter is
0490:             * assumed to be an array of zip files and/or directories.
0491:             * @param path The class path to be used when loading classes.
0492:             */
0493:            public synchronized void setClassPath(File[] path) {
0494:                classPath.set(path);
0495:            }
0496:
0497:            /**
0498:             * Sets class loader with specified class path.  The parameter is
0499:             * represent a directory or zip file on the local machine or a
0500:             * remote machine.
0501:             * @param path The class path to be used when loading classes.
0502:             */
0503:            public void setClassPath(URL path) {
0504:                setClassPath(new URL[] { path });
0505:            }
0506:
0507:            /**
0508:             * Sets class loader with specified class path.  The parameter is
0509:             * represent directories and/or zip files on the local machine and/or
0510:             * on remote machines.
0511:             * @param path The class path to be used when loading classes.
0512:             */
0513:            public synchronized void setClassPath(URL[] path) {
0514:                classPath.set(path);
0515:            }
0516:
0517:            /**
0518:             * Adds specified class path to beginning of existing path.
0519:             * The parameter is
0520:             * assumed to be either a directory, URL, or zip file.
0521:             * @param path The class path to be added to current class path.
0522:             */
0523:            public void addClassPath(String path) {
0524:                addClassPath(new String[] { path });
0525:            }
0526:
0527:            /**
0528:             * Adds specified class path to beginning of existing path.
0529:             * The parameter is
0530:             * assumed to be an array of directories, URLs, and/or zip files.
0531:             * @param path The class path to be added to current class path.
0532:             */
0533:            public synchronized void addClassPath(String[] path) {
0534:                classPath.add(path);
0535:            }
0536:
0537:            /**
0538:             * Adds specified class path to beginning of existing path.
0539:             * The parameter is assumed to be either a zip file or directory.
0540:             * @param path The class path to be added to current class path.
0541:             */
0542:            public void addClassPath(File path) {
0543:                addClassPath(new File[] { path });
0544:            }
0545:
0546:            /**
0547:             * Adds specified class path to beginning of existing path.
0548:             * The parameter is
0549:             * assumed to be an array of zip files and/or directories.
0550:             * @param path The class path to be added to current class path.
0551:             */
0552:            public synchronized void addClassPath(File[] path) {
0553:                classPath.add(path);
0554:            }
0555:
0556:            /**
0557:             * Adds specified class path to beginning of existing path.
0558:             * The parameter is
0559:             * represent a directory or zip file on the local machine or a
0560:             * remote machine.
0561:             * @param path The class path to be added to current class path.
0562:             */
0563:            public void addClassPath(URL path) {
0564:                addClassPath(new URL[] { path });
0565:            }
0566:
0567:            /**
0568:             * Adds specified class path to beginning of existing path.
0569:             * The parameter is
0570:             * represent directories and/or zip files on the local machine and/or
0571:             * on remote machines.
0572:             * @param path The class path to be added to current class path.
0573:             */
0574:            public synchronized void addClassPath(URL[] path) {
0575:                classPath.add(path);
0576:            }
0577:
0578:            /**
0579:             * Clears class path entries.
0580:             * @see #setClassPath
0581:             */
0582:            public synchronized void clearClassPath() {
0583:                classPath.clear();
0584:            }
0585:
0586:            /**
0587:             * Gets class path for class loader defined previously by constructor and
0588:             * <CODE>setClassPath</CODE>/<CODE>addClassPath</CODE> methods.
0589:             * @return the class path represented by an <CODE>Enumeration</CODE>
0590:             * of URL objects.
0591:             * @see #setClassPath
0592:             * @see #addClassPath
0593:             * <!-- FIXME: should really return a format that can be passed
0594:             *      to another class loader, like an array -->
0595:             */
0596:            public URL[] getClassPath() {
0597:                int len = classPath.getLength();
0598:                URL[] urlPath = new URL[len];
0599:                Enumeration cpeEnum = classPath.getPath();
0600:                for (int i = 0; i < len; i++) {
0601:                    ClassPathEntry cpe = (ClassPathEntry) cpeEnum.nextElement();
0602:                    urlPath[i] = cpe.getURL();
0603:                }
0604:                return urlPath;
0605:            }
0606:
0607:            /**
0608:             * Parse a class-path string using the system path separator.
0609:             */
0610:            public static String[] parseClassPath(String path) {
0611:                String systemSeparator = System.getProperty("path.separator");
0612:                if (systemSeparator == null) {
0613:                    throw new NullPointerException(
0614:                            "path.separator property not defined");
0615:                }
0616:                StringTokenizer tokenizer = new StringTokenizer(path,
0617:                        systemSeparator);
0618:                String[] parsed = new String[tokenizer.countTokens()];
0619:                for (int i = 0; tokenizer.hasMoreTokens(); i++) {
0620:                    parsed[i] = tokenizer.nextToken();
0621:                }
0622:                return parsed;
0623:            }
0624:
0625:            /**
0626:             * Gets class path from system.
0627:             *
0628:             * @return the system class path represented by an
0629:             *         array of URL objects.
0630:             */
0631:            public static URL[] getSystemClassPath() {
0632:                // Parse system class path into its components
0633:                String systemClassPath = System.getProperty("java.class.path");
0634:                if (systemClassPath == null) {
0635:                    systemClassPath = "";
0636:                }
0637:                String[] parsedPath = parseClassPath(systemClassPath);
0638:                // Convert to URLs, dropping invalid entries
0639:                Vector urlVector = new Vector(parsedPath.length);
0640:                for (int i = 0; i < parsedPath.length; i++) {
0641:                    try {
0642:                        urlVector
0643:                                .addElement(new URL("file", "", parsedPath[i]));
0644:                    } catch (MalformedURLException mue) {
0645:                        // Do not add this entry
0646:                    }
0647:                }
0648:                URL[] urlArray = new URL[urlVector.size()];
0649:                urlVector.copyInto(urlArray);
0650:                return urlArray;
0651:            }
0652:
0653:            /**
0654:             * Set the parent class loader for delegation.
0655:             */
0656:            public void setParent(ClassLoader parent) {
0657:                parentClassLoader = parent;
0658:            }
0659:
0660:            /**
0661:             * Get the secondary class loader.
0662:             */
0663:            public ClassLoader getSecondary() {
0664:                return secondaryClassLoader;
0665:            }
0666:
0667:            /**
0668:             * Set the secondary class loader.
0669:             */
0670:            public void setSecondary(ClassLoader secondary) {
0671:                secondaryClassLoader = secondary;
0672:            }
0673:
0674:            /**
0675:             * Get the log channel associated this class loader.
0676:             */
0677:            public LogChannel getLogChannel() {
0678:                return logChannel;
0679:            }
0680:
0681:            /**
0682:             * Add a filter to the list of filters that check if a class maybe
0683:             * loaded by this class loader.
0684:             */
0685:            public synchronized void addClassFilter(ClassFilter filter) {
0686:                if (filters == null) {
0687:                    filters = new Vector();
0688:                }
0689:                filters.addElement(filter);
0690:            }
0691:
0692:            /**
0693:             * Check class filters to determine if a class should be loaded by
0694:             * this class loader.  This also handles check an implicit filter
0695:             * for java.lang.* classes, which must go to the main class loader.
0696:             * @return One of NORMAL_LOAD, DONT_LOAD, CAN_LOAD, or MUST_LOAD.
0697:             */
0698:            private int checkFilters(String className) {
0699:                int restrict = ClassFilter.NORMAL_LOAD;
0700:                if (className.startsWith("java.lang.")) {
0701:                    restrict = ClassFilter.DONT_LOAD;
0702:                } else if (filters != null) {
0703:                    int numFilters = filters.size();
0704:                    for (int idx = 0; idx < numFilters; idx++) {
0705:                        restrict = ((ClassFilter) filters.elementAt(idx))
0706:                                .loadCheck(className);
0707:                        if (restrict != ClassFilter.NORMAL_LOAD) {
0708:                            break;
0709:                        }
0710:                    }
0711:                }
0712:                // Log restriction, if any.
0713:                if ((restrict != ClassFilter.NORMAL_LOAD) && loggingEnabled) {
0714:                    String msg = "";
0715:                    switch (restrict) {
0716:                    case ClassFilter.DONT_LOAD:
0717:                        msg = "Filter disallows loading by this classloader: ";
0718:                        break;
0719:                    case ClassFilter.CAN_LOAD:
0720:                        msg = "Filter allows loading by this classloader: ";
0721:                        break;
0722:                    case ClassFilter.MUST_LOAD:
0723:                        msg = "Filter requires loading by this classloader: ";
0724:                        break;
0725:                    }
0726:                    if (loggingEnabled) {
0727:                        logChannel.write(logLevel, msg + className);
0728:                    }
0729:                }
0730:                return restrict;
0731:            }
0732:
0733:            /**
0734:             * Check the table of loaded classes to determine if a class is already
0735:             * loaded.  Purposely not synchronized, allowing a quick check for a class
0736:             * being loaded.  A second check, which higher level synchronization is
0737:             * required if the class is not found.  This function does logs a message
0738:             * when a class is found.
0739:             * @param className The class to look up.
0740:             * @return The ClassResource object for the class, or null if not found.
0741:             */
0742:            private ClassResource checkForLoadedClass(String className) {
0743:                ClassResource cr = (ClassResource) loadedClasses.get(className);
0744:                if ((cr != null) && loggingEnabled) {
0745:                    logChannel.write(logLevel, "loadClass already loaded: "
0746:                            + className);
0747:                }
0748:                return cr;
0749:            }
0750:
0751:            //FIXME: method with resolve parameter should be protected (see base class).
0752:            /**
0753:             * Loads and, optionally, resolves the specified class. If the class
0754:             * needs to be instantiated, the class must be resolved.  If only the
0755:             * existence of the class needs verification, class resolution is
0756:             * unnecessary.
0757:             *
0758:             * Calling <CODE>loadClass(String className)</CODE> is equivalent to calling
0759:             * this method with <CODE>resolve</CODE> set to <CODE>true</CODE>.
0760:             *
0761:             * Purposely not synchronized. If class is not found in loadedClasses table, then
0762:             * doLoadClass will do the operation in a synchronized manner.
0763:             *
0764:             * @param className The name of the class to be loaded, e.g.
0765:             *        "com.lutris.util.Table".
0766:             * @param resolve Set to <CODE>true</CODE> for class resolution,
0767:             *        <CODE>false</CODE> for no resolution.
0768:             * @return the loaded Class.
0769:             * @exception ClassNotFoundException if the class could not be load.
0770:             * @see #setClassPath
0771:             * @see #addClassPath
0772:             */
0773:            public Class loadClass(String className, boolean resolve)
0774:                    throws ClassNotFoundException {
0775:                return loadClassResource(className, resolve).getClassObj();
0776:            }
0777:
0778:            public Class loadClass(String className)
0779:                    throws ClassNotFoundException {
0780:                if (this .forceSecondaryLoader)
0781:                    return loadClassResource(className, false).getClassObj();
0782:                else
0783:                    return super .loadClass(className);
0784:            }
0785:
0786:            /**
0787:             * Log a class load failer.
0788:             */
0789:            private void logClassLoadFailure(String className, Throwable except) {
0790:                if (loggingEnabled) {
0791:                    logChannel.write(logLevel, "load of class failed: "
0792:                            + className, except);
0793:                }
0794:            }
0795:
0796:            /**
0797:             * Log a resource read failer.
0798:             */
0799:            private void logReadFailure(String name, Throwable except) {
0800:                if (loggingEnabled) {
0801:                    logChannel.write(logLevel, "read of resource failed: "
0802:                            + name, except);
0803:                }
0804:            }
0805:
0806:            /**
0807:             * Loads and, optionally, resolves the specified class, returning the
0808:             * <CODE>ClassResource</CODE> object.
0809:             *
0810:             * @param className The name of the class to load.
0811:             * @param resolve Set to <CODE>true</CODE> for class resolution,
0812:             *        <CODE>false</CODE> for no resolution.
0813:             * @return Object containing class and resource.
0814:             * @exception ClassNotFoundException if this loader and the system loader
0815:             *            can not find or successfully load the class.
0816:             * @see #setClassPath
0817:             * @see #addClassPath
0818:             * @see #loadClass
0819:             */
0820:            private ClassResource loadClassResource(String className,
0821:                    boolean resolve) throws ClassNotFoundException {
0822:                if (loggingEnabled) {
0823:                    logChannel.write(logLevel, "loadClass: " + className);
0824:                }
0825:                try {
0826:                    ClassResource cr = checkForLoadedClass(className);
0827:                    if (cr == null) {
0828:                        cr = doLoadClass(className);
0829:                        if (resolve) {
0830:                            resolveClass(cr.getClassObj());
0831:                        }
0832:                    }
0833:                    return cr;
0834:                } catch (ClassNotFoundException except) {
0835:                    logClassLoadFailure(className, except);
0836:                    throw except;
0837:                } catch (IOException except) {
0838:                    logClassLoadFailure(className, except);
0839:                    throw new ClassNotFoundException(except.getClass()
0840:                            .getName()
0841:                            + ": " + except.getMessage());
0842:                } catch (RuntimeException except) {
0843:                    logClassLoadFailure(className, except);
0844:                    throw except;
0845:                } catch (Error except) {
0846:                    logClassLoadFailure(className, except);
0847:                    throw except;
0848:                }
0849:            }
0850:
0851:            /**
0852:             * Get the resource for a class loaded by this class loader.
0853:             */
0854:            public Resource getClassResource(String className)
0855:                    throws ClassNotFoundException {
0856:                ClassResource cr = checkForLoadedClass(className);
0857:                if (cr == null) {
0858:                    throw new ClassNotFoundException("Class \"" + className
0859:                            + "\" is not loaded by this class loader");
0860:                }
0861:                return cr.getResource();
0862:            }
0863:
0864:            /**
0865:             * Load a class with the parent or secondary class loader.
0866:             * Must already be synchronized
0867:             */
0868:            private ClassResource loadClassOther(String className,
0869:                    ClassLoader loader, String loaderName) {
0870:                ClassResource cr = null;
0871:
0872:                if (loggingEnabled) {
0873:                    logChannel.write(logLevel, "checking " + loaderName
0874:                            + " class loader: " + className);
0875:                }
0876:                try {
0877:                    if (loader instanceof  MultiClassLoader) {
0878:                        cr = ((MultiClassLoader) loader).loadClassResource(
0879:                                className, false);
0880:                    } else {
0881:                        Class c = loader.loadClass(className);
0882:                        cr = new ClassResource(c, null);
0883:                    }
0884:                    if (loggingEnabled) {
0885:                        logChannel.write(logLevel, "class loaded by: "
0886:                                + loaderName);
0887:                    }
0888:                } catch (ClassNotFoundException except) {
0889:                    // Just log and return null
0890:                    if (loggingEnabled) {
0891:                        logChannel.write(logLevel, "class not loaded by "
0892:                                + loaderName + ": "
0893:                                + except.getClass().getName() + ": "
0894:                                + except.getMessage());
0895:                    }
0896:                }
0897:                return cr;
0898:            }
0899:
0900:            /**
0901:             * Load a class with this class loader.  Must already be
0902:             * synchronized
0903:             */
0904:            private ClassResource loadClassHere(String className)
0905:                    throws IOException {
0906:                ClassResource cr = null;
0907:
0908:                if (loggingEnabled) {
0909:                    logChannel.write(logLevel, "checking MultiClassLoader: "
0910:                            + className);
0911:                }
0912:                String fileName = className.replace('.', '/').concat(".class");
0913:                Resource resource = getResourceObject(fileName);
0914:
0915:                if (resource != null) {
0916:
0917:                    Class c = null;
0918:                    try {
0919:                        // AutoReload with secondary loader
0920:                        if (isAutoReload && forceSecondaryLoader) {
0921:                            InputStream is = null;
0922:                            try {
0923:                                is = this .secondaryClassLoader.getResource(
0924:                                        fileName).openConnection()
0925:                                        .getInputStream();
0926:                                c = getClassFromStream(className, is);
0927:                            } catch (Throwable th) {
0928:                                try {
0929:                                    is = this .secondaryClassLoader
0930:                                            .getResourceAsStream(fileName);
0931:                                    c = getClassFromStream(className, is);
0932:                                } catch (Throwable th1) {
0933:                                    c = Class.forName(className, true,
0934:                                            this .secondaryClassLoader);
0935:                                }
0936:                            }
0937:
0938:                        }
0939:                        // loading with secondary loader
0940:                        else if (forceSecondaryLoader) {
0941:                            c = Class.forName(className, true,
0942:                                    this .secondaryClassLoader);
0943:                        }
0944:                        // standard use of MultiClassLoader
0945:                        else
0946:                            c = Class.forName(className);
0947:                    } catch (ClassNotFoundException e) {
0948:                        try {
0949:                            // second try to search the class among Dll-mapped classes
0950:                            // this requires the call Class.forName with system class
0951:                            // loader
0952:                            c = Class.forName(className, true, ClassLoader
0953:                                    .getSystemClassLoader());
0954:                        } catch (ClassNotFoundException e1) {
0955:                            // if there is no precompiled class, try to compile it with JET JIT
0956:                            // NOTE! this will success only if -Djet.jit property is defined
0957:                            byte[] classBytes = resource.getBytes();
0958:                            c = defineClass(className, classBytes, 0,
0959:                                    classBytes.length);
0960:                        }
0961:                    }
0962:
0963:                    cr = new ClassResource(c, resource);
0964:                    loadedClasses.put(className, cr);
0965:
0966:                    if (loggingEnabled) {
0967:                        logChannel.write(logLevel,
0968:                                "class loaded by MultiClassLoader: "
0969:                                        + className);
0970:                    }
0971:                }
0972:                if ((cr == null) && loggingEnabled) {
0973:                    logChannel.write(logLevel,
0974:                            "class not loaded by MultiClassLoader: "
0975:                                    + className);
0976:                }
0977:                return cr;
0978:            }
0979:
0980:            /**
0981:             * Returns Class object for defined class name created by bytes obtained from
0982:             * InputStream. Note that InputStrim will be closed in this method after it
0983:             * is read.
0984:             * @param className full name of class which has to be created
0985:             * @param is InputStream which is used as origin of bytes used for class
0986:             * generation.
0987:             * @return created Class object
0988:             * @throws IOException
0989:             */
0990:            private Class getClassFromStream(String className, InputStream is)
0991:                    throws IOException {
0992:                ByteArrayOutputStream baos = new ByteArrayOutputStream();
0993:                byte[] buf = new byte[1024];
0994:                int i = is.read(buf);
0995:                while (i == 1024) {
0996:                    baos.write(buf);
0997:                    i = is.read(buf);
0998:                }
0999:                if (i != -1)
1000:                    baos.write(buf, 0, i);
1001:
1002:                buf = baos.toByteArray();
1003:                baos.close();
1004:                is.close();
1005:
1006:                return defineClass(className, buf, 0, buf.length);
1007:            }
1008:
1009:            /**
1010:             * Loads specified class.  If possible, the class will loaded from the
1011:             * class path defined previously with <CODE>setClassPath</CODE>,
1012:             * <CODE>addClassPath</CODE>, and/or the constructor.  Otherwise, the
1013:             * class will be passed off to the parent class loader.  Classes from
1014:             * the java.* packages cannot be loaded by this class loader so will
1015:             * be passed off to the parent class loader.
1016:             * @param className The name of the class to be loaded, e.g.
1017:             *        "com.lutris.util.Table".
1018:             * @return Object containing class and resource.
1019:             * @exception ClassNotFoundException if this loader and the system loader
1020:             *            can not find or successfully load the class.
1021:             * @see #setClassPath
1022:             * @see #addClassPath
1023:             */
1024:            private synchronized ClassResource doLoadClass(String className)
1025:                    throws ClassNotFoundException, IOException {
1026:                // Must check loaded class table again, as we are now synchronized.
1027:                ClassResource cr = checkForLoadedClass(className);
1028:                if (cr != null) {
1029:                    return cr;
1030:                }
1031:                // Get filter restriction to use (includes check for java.lang.*).
1032:                int filterRestrict = checkFilters(className);
1033:
1034:                // Delegate if parent exists and filter allows.
1035:                if ((parentClassLoader != null)
1036:                        && (filterRestrict != ClassFilter.CAN_LOAD)
1037:                        && (filterRestrict != ClassFilter.MUST_LOAD)) {
1038:                    cr = loadClassOther(className, parentClassLoader, "parent");
1039:                    if (cr != null) {
1040:                        return cr;
1041:                    }
1042:                }
1043:
1044:                // Try loading with this class loader if filter allows.
1045:                if ((filterRestrict == ClassFilter.NORMAL_LOAD)
1046:                        || (filterRestrict == ClassFilter.CAN_LOAD)
1047:                        || (filterRestrict == ClassFilter.MUST_LOAD)) {
1048:                    cr = loadClassHere(className);
1049:                    if (cr != null) {
1050:                        return cr;
1051:                    }
1052:                }
1053:
1054:                // Try secondary class loader.
1055:                if ((secondaryClassLoader != null)
1056:                        && (filterRestrict != ClassFilter.MUST_LOAD)) {
1057:                    cr = loadClassOther(className, secondaryClassLoader,
1058:                            "secondary");
1059:                    if (cr != null) {
1060:                        return cr;
1061:                    }
1062:                }
1063:                throw new ClassNotFoundException(className);
1064:            }
1065:
1066:            /**
1067:             * Gets specified resource as URL.  Doing a getContent() on the URL may
1068:             * return an Image, an AudioClip, or an InputStream.
1069:             * @param name The name of the resource.
1070:             * @return the resource represented by a URL, or null if not found.
1071:             */
1072:            public URL getResource(String name) {
1073:                Resource resource = getResourceObject(name);
1074:                if (resource != null) {
1075:                    ClassPathEntry location = resource.getLocation();
1076:                    try {
1077:                        return new URL(location.getURL() + resource.getName());
1078:                    } catch (MalformedURLException mue) {
1079:                        if (loggingEnabled) {
1080:                            logChannel.write(logLevel,
1081:                                    "getResource not returned due to exception: "
1082:                                            + name, mue);
1083:                        }
1084:                        return null;
1085:                    }
1086:                }
1087:                return null;
1088:            }
1089:
1090:            /**
1091:             * Gets specified resource object.
1092:             * @param name The name of the resource.
1093:             * @return the resource if found, null if not.
1094:             * @see Resource
1095:             */
1096:            public Resource getResourceObject(String name) {
1097:                Resource resource;
1098:                if (loggingEnabled) {
1099:                    logChannel.write(logLevel, "getResource loading: " + name);
1100:                }
1101:                try {
1102:                    resource = classPath.getResource(name);
1103:                    if (loggingEnabled) {
1104:                        if (resource == null) {
1105:                            logChannel.write(logLevel,
1106:                                    "getResource not found: " + name);
1107:                        } else {
1108:                            logChannel.write(logLevel, "getResource finished: "
1109:                                    + name);
1110:                        }
1111:                    }
1112:                } catch (RuntimeException except) {
1113:                    logReadFailure(name, except);
1114:                    throw except;
1115:                } catch (Error except) {
1116:                    logReadFailure(name, except);
1117:                    throw except;
1118:                }
1119:                return resource;
1120:            }
1121:
1122:            /**
1123:             * Gets specified resource object.
1124:             * @see deprecated Use getResourceObject()
1125:             * @see getResourceObject
1126:             */
1127:            public Resource getResourceAsIs(String name) {
1128:                return getResourceObject(name);
1129:            }
1130:
1131:            /**
1132:             * Gets specified resource as input stream.
1133:             * @param name The name of the resource.
1134:             * @return an input stream representing the specified resource or
1135:             *         null if the resource is not found.
1136:             */
1137:            public InputStream getResourceAsStream(String name) {
1138:                Resource resource = getResourceObject(name);
1139:                if (resource != null) {
1140:                    try {
1141:                        return resource.getInputStream();
1142:                    } catch (IOException except) {
1143:                        logReadFailure(name, except);
1144:                        return null; // This is what getResourceAsStream does..
1145:                    }
1146:                }
1147:                return null;
1148:            }
1149:
1150:            /**
1151:             * Gets specified resource as array of bytes.
1152:             * @param name The name of the resource.
1153:             * @return an array of bytes representing the specified resource or
1154:             *         null if the resource is not found.
1155:             */
1156:            public byte[] getResourceAsByteArray(String name) {
1157:                Resource resource = getResourceObject(name);
1158:                if (resource != null) {
1159:                    try {
1160:                        return resource.getBytes();
1161:                    } catch (IOException except) {
1162:                        logReadFailure(name, except);
1163:                        return null; // This is what getResourceAsStream does..
1164:                    }
1165:                }
1166:                return null;
1167:            }
1168:
1169:            /**
1170:             * Determine if the classes loaded by this class loader have been modified.
1171:             * If any file associated with loaded in the class loader's class path has
1172:             * changed, the classes should be reloaded.  If the classes need to be
1173:             * reloaded, a new instance of this class loader must be created
1174:             * because a particular class loader instance can only load classes
1175:             * once.
1176:             * @return <CODE>true</CODE> if the classes should be reloaded,
1177:             *     <CODE>false</CODE> if not.
1178:             */
1179:            public boolean shouldReload() {
1180:                Enumeration classes = loadedClasses.elements();
1181:                if (loggingEnabled) {
1182:                    logChannel.write(logLevel,
1183:                            "Checking for out-of-date classes");
1184:                }
1185:                while (classes.hasMoreElements()) {
1186:                    boolean isModified;
1187:                    try {
1188:                        isModified = ((ClassResource) classes.nextElement())
1189:                                .getResource().hasBeenModified();
1190:                    } catch (FileNotFoundException except) {
1191:                        if (loggingEnabled) {
1192:                            logChannel
1193:                                    .write(
1194:                                            logLevel,
1195:                                            "File for loaded class can no longer be accessed",
1196:                                            except);
1197:                        }
1198:                        isModified = true;
1199:                    }
1200:                    if (isModified) {
1201:                        if (loggingEnabled) {
1202:                            logChannel.write(logLevel,
1203:                                    "Loaded classes have been modified");
1204:                        }
1205:                        return true;
1206:                    }
1207:                }
1208:                if (loggingEnabled) {
1209:                    logChannel.write(logLevel,
1210:                            "Loaded classes have not been modified");
1211:                }
1212:                return false;
1213:            }
1214:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.