Source Code Cross Referenced for WebappClassLoader.java in  » Web-Server » Rimfaxe-Web-Server » org » apache » catalina » loader » 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 » Web Server » Rimfaxe Web Server » org.apache.catalina.loader 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java,v 1.45 2002/08/09 10:01:48 remm Exp $
0003:         * $Revision: 1.45 $
0004:         * $Date: 2002/08/09 10:01:48 $
0005:         *
0006:         * ====================================================================
0007:         *
0008:         * The Apache Software License, Version 1.1
0009:         *
0010:         * Copyright (c) 1999 The Apache Software Foundation.  All rights
0011:         * reserved.
0012:         *
0013:         * Redistribution and use in source and binary forms, with or without
0014:         * modification, are permitted provided that the following conditions
0015:         * are met:
0016:         *
0017:         * 1. Redistributions of source code must retain the above copyright
0018:         *    notice, this list of conditions and the following disclaimer.
0019:         *
0020:         * 2. Redistributions in binary form must reproduce the above copyright
0021:         *    notice, this list of conditions and the following disclaimer in
0022:         *    the documentation and/or other materials provided with the
0023:         *    distribution.
0024:         *
0025:         * 3. The end-user documentation included with the redistribution, if
0026:         *    any, must include the following acknowlegement:
0027:         *       "This product includes software developed by the
0028:         *        Apache Software Foundation (http://www.apache.org/)."
0029:         *    Alternately, this acknowlegement may appear in the software itself,
0030:         *    if and wherever such third-party acknowlegements normally appear.
0031:         *
0032:         * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0033:         *    Foundation" must not be used to endorse or promote products derived
0034:         *    from this software without prior written permission. For written
0035:         *    permission, please contact apache@apache.org.
0036:         *
0037:         * 5. Products derived from this software may not be called "Apache"
0038:         *    nor may "Apache" appear in their names without prior written
0039:         *    permission of the Apache Group.
0040:         *
0041:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0042:         * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0043:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0044:         * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0045:         * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0046:         * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0047:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0048:         * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0049:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0050:         * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0051:         * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0052:         * SUCH DAMAGE.
0053:         * ====================================================================
0054:         *
0055:         * This software consists of voluntary contributions made by many
0056:         * individuals on behalf of the Apache Software Foundation.  For more
0057:         * information on the Apache Software Foundation, please see
0058:         * <http://www.apache.org/>.
0059:         *
0060:         * [Additional notices, if required by prior licensing conditions]
0061:         *
0062:         */
0063:
0064:        package org.apache.catalina.loader;
0065:
0066:        import java.io.File;
0067:        import java.io.FilePermission;
0068:        import java.io.InputStream;
0069:        import java.io.ByteArrayInputStream;
0070:        import java.io.IOException;
0071:        import java.net.JarURLConnection;
0072:        import java.net.MalformedURLException;
0073:        import java.net.URL;
0074:        import java.net.URLClassLoader;
0075:        import java.net.URLConnection;
0076:        import java.net.URLStreamHandlerFactory;
0077:        import java.net.URLStreamHandler;
0078:        import java.security.AccessControlException;
0079:        import java.security.AccessController;
0080:        import java.security.CodeSource;
0081:        import java.security.Permission;
0082:        import java.security.PermissionCollection;
0083:        import java.security.Policy;
0084:        import java.security.PrivilegedAction;
0085:        import java.security.cert.Certificate;
0086:        import java.util.ArrayList;
0087:        import java.util.Enumeration;
0088:        import java.util.HashMap;
0089:        import java.util.Iterator;
0090:        import java.util.Vector;
0091:        import java.util.jar.JarFile;
0092:        import java.util.jar.JarEntry;
0093:        import java.util.jar.JarInputStream;
0094:        import java.util.jar.Manifest;
0095:        import java.util.jar.Attributes;
0096:        import java.util.jar.Attributes.Name;
0097:
0098:        import javax.naming.directory.DirContext;
0099:        import javax.naming.NamingException;
0100:        import javax.naming.NamingEnumeration;
0101:        import javax.naming.NameClassPair;
0102:
0103:        import org.apache.catalina.Lifecycle;
0104:        import org.apache.catalina.LifecycleEvent;
0105:        import org.apache.catalina.LifecycleException;
0106:        import org.apache.catalina.LifecycleListener;
0107:
0108:        import org.apache.naming.JndiPermission;
0109:        import org.apache.naming.resources.ResourceAttributes;
0110:        import org.apache.naming.resources.Resource;
0111:
0112:        /**
0113:         * Specialized web application class loader.
0114:         * <p>
0115:         * This class loader is a full reimplementation of the 
0116:         * <code>URLClassLoader</code> from the JDK. It is desinged to be fully
0117:         * compatible with a normal <code>URLClassLoader</code>, although its internal
0118:         * behavior may be completely different.
0119:         * <p>
0120:         * <strong>IMPLEMENTATION NOTE</strong> - This class loader faithfully follows 
0121:         * the delegation model recommended in the specification. The system class 
0122:         * loader will be queried first, then the local repositories, and only then 
0123:         * delegation to the parent class loader will occur. This allows the web 
0124:         * application to override any shared class except the classes from J2SE.
0125:         * Special handling is provided from the JAXP XML parser interfaces, the JNDI
0126:         * interfaces, and the classes from the servlet API, which are never loaded 
0127:         * from the webapp repository.
0128:         * <p>
0129:         * <strong>IMPLEMENTATION NOTE</strong> - Due to limitations in Jasper 
0130:         * compilation technology, any repository which contains classes from 
0131:         * the servlet API will be ignored by the class loader.
0132:         * <p>
0133:         * <strong>IMPLEMENTATION NOTE</strong> - The class loader generates source
0134:         * URLs which include the full JAR URL when a class is loaded from a JAR file,
0135:         * which allows setting security permission at the class level, even when a
0136:         * class is contained inside a JAR.
0137:         * <p>
0138:         * <strong>IMPLEMENTATION NOTE</strong> - Local repositories are searched in
0139:         * the order they are added via the initial constructor and/or any subsequent
0140:         * calls to <code>addRepository()</code> or <code>addJar()</code>.
0141:         * <p>
0142:         * <strong>IMPLEMENTATION NOTE</strong> - No check for sealing violations or
0143:         * security is made unless a security manager is present.
0144:         *
0145:         * @author Remy Maucherat
0146:         * @author Craig R. McClanahan
0147:         * @version $Revision: 1.45 $ $Date: 2002/08/09 10:01:48 $
0148:         */
0149:        public class WebappClassLoader extends URLClassLoader implements 
0150:                Reloader, Lifecycle {
0151:
0152:            protected class PrivilegedFindResource implements  PrivilegedAction {
0153:
0154:                private String name;
0155:                private String path;
0156:
0157:                PrivilegedFindResource(String name, String path) {
0158:                    this .name = name;
0159:                    this .path = path;
0160:                }
0161:
0162:                public Object run() {
0163:                    return findResourceInternal(name, path);
0164:                }
0165:
0166:            }
0167:
0168:            // ------------------------------------------------------- Static Variables
0169:
0170:            /**
0171:             * The set of trigger classes that will cause a proposed repository not
0172:             * to be added if this class is visible to the class loader that loaded
0173:             * this factory class.  Typically, trigger classes will be listed for
0174:             * components that have been integrated into the JDK for later versions,
0175:             * but where the corresponding JAR files are required to run on
0176:             * earlier versions.
0177:             */
0178:            private static final String[] triggers = { "javax.servlet.Servlet" // Servlet API
0179:            };
0180:
0181:            /**
0182:             * Set of package names which are not allowed to be loaded from a webapp
0183:             * class loader without delegating first.
0184:             */
0185:            private static final String[] packageTriggers = { "javax", // Java extensions
0186:                    "org.xml.sax", // SAX 1 & 2
0187:                    "org.w3c.dom", // DOM 1 & 2
0188:                    "org.apache.xerces", // Xerces 1 & 2
0189:                    "org.apache.xalan" // Xalan
0190:            };
0191:
0192:            // ----------------------------------------------------------- Constructors
0193:
0194:            /**
0195:             * Construct a new ClassLoader with no defined repositories and no
0196:             * parent ClassLoader.
0197:             */
0198:            public WebappClassLoader() {
0199:
0200:                super (new URL[0]);
0201:                this .parent = getParent();
0202:                system = getSystemClassLoader();
0203:                securityManager = System.getSecurityManager();
0204:
0205:                if (securityManager != null) {
0206:                    refreshPolicy();
0207:                }
0208:
0209:            }
0210:
0211:            /**
0212:             * Construct a new ClassLoader with no defined repositories and no
0213:             * parent ClassLoader.
0214:             */
0215:            public WebappClassLoader(ClassLoader parent) {
0216:
0217:                super (new URL[0], parent);
0218:                this .parent = getParent();
0219:                system = getSystemClassLoader();
0220:                securityManager = System.getSecurityManager();
0221:
0222:                if (securityManager != null) {
0223:                    refreshPolicy();
0224:                }
0225:
0226:            }
0227:
0228:            // ----------------------------------------------------- Instance Variables
0229:
0230:            /**
0231:             * Associated directory context giving access to the resources in this
0232:             * webapp.
0233:             */
0234:            protected DirContext resources = null;
0235:
0236:            /**
0237:             * The set of optional packages (formerly standard extensions) that
0238:             * are available in the repositories associated with this class loader.
0239:             * Each object in this list is of type
0240:             * <code>org.apache.catalina.loader.Extension</code>.
0241:             */
0242:            protected ArrayList available = new ArrayList();
0243:
0244:            /**
0245:             * The cache of ResourceEntry for classes and resources we have loaded,
0246:             * keyed by resource name.
0247:             */
0248:            protected HashMap resourceEntries = new HashMap();
0249:
0250:            /**
0251:             * The list of not found resources.
0252:             */
0253:            protected HashMap notFoundResources = new HashMap();
0254:
0255:            /**
0256:             * The debugging detail level of this component.
0257:             */
0258:            protected int debug = 0;
0259:
0260:            /**
0261:             * Should this class loader delegate to the parent class loader
0262:             * <strong>before</strong> searching its own repositories (i.e. the
0263:             * usual Java2 delegation model)?  If set to <code>false</code>,
0264:             * this class loader will search its own repositories first, and
0265:             * delegate to the parent only if the class or resource is not
0266:             * found locally.
0267:             */
0268:            protected boolean delegate = false;
0269:
0270:            /**
0271:             * The list of local repositories, in the order they should be searched
0272:             * for locally loaded classes or resources.
0273:             */
0274:            protected String[] repositories = new String[0];
0275:
0276:            /**
0277:             * Repositories translated as path in the work directory (for Jasper
0278:             * originally), but which is used to generate fake URLs should getURLs be
0279:             * called.
0280:             */
0281:            protected File[] files = new File[0];
0282:
0283:            /**
0284:             * The list of JARs, in the order they should be searched
0285:             * for locally loaded classes or resources.
0286:             */
0287:            protected JarFile[] jarFiles = new JarFile[0];
0288:
0289:            /**
0290:             * The list of JARs, in the order they should be searched
0291:             * for locally loaded classes or resources.
0292:             */
0293:            protected File[] jarRealFiles = new File[0];
0294:
0295:            /**
0296:             * The path which will be monitored for added Jar files.
0297:             */
0298:            protected String jarPath = null;
0299:
0300:            /**
0301:             * The list of JARs, in the order they should be searched
0302:             * for locally loaded classes or resources.
0303:             */
0304:            protected String[] jarNames = new String[0];
0305:
0306:            /**
0307:             * The list of JARs last modified dates, in the order they should be
0308:             * searched for locally loaded classes or resources.
0309:             */
0310:            protected long[] lastModifiedDates = new long[0];
0311:
0312:            /**
0313:             * The list of resources which should be checked when checking for
0314:             * modifications.
0315:             */
0316:            protected String[] paths = new String[0];
0317:
0318:            /**
0319:             * The set of optional packages (formerly standard extensions) that
0320:             * are required in the repositories associated with this class loader.
0321:             * Each object in this list is of type
0322:             * <code>org.apache.catalina.loader.Extension</code>.
0323:             */
0324:            protected ArrayList required = new ArrayList();
0325:
0326:            /**
0327:             * A list of read File and Jndi Permission's required if this loader
0328:             * is for a web application context.
0329:             */
0330:            private ArrayList permissionList = new ArrayList();
0331:
0332:            /**
0333:             * The PermissionCollection for each CodeSource for a web
0334:             * application context.
0335:             */
0336:            private HashMap loaderPC = new HashMap();
0337:
0338:            /**
0339:             * Instance of the SecurityManager installed.
0340:             */
0341:            private SecurityManager securityManager = null;
0342:
0343:            /**
0344:             * The parent class loader.
0345:             */
0346:            private ClassLoader parent = null;
0347:
0348:            /**
0349:             * The system class loader.
0350:             */
0351:            private ClassLoader system = null;
0352:
0353:            /**
0354:             * Has this component been started?
0355:             */
0356:            protected boolean started = false;
0357:
0358:            /**
0359:             * Has external repositories.
0360:             */
0361:            protected boolean hasExternalRepositories = false;
0362:
0363:            /**
0364:             * All permission.
0365:             */
0366:            private Permission allPermission = new java.security.AllPermission();
0367:
0368:            // ------------------------------------------------------------- Properties
0369:
0370:            /**
0371:             * Get associated resources.
0372:             */
0373:            public DirContext getResources() {
0374:
0375:                return this .resources;
0376:
0377:            }
0378:
0379:            /**
0380:             * Set associated resources.
0381:             */
0382:            public void setResources(DirContext resources) {
0383:
0384:                this .resources = resources;
0385:
0386:            }
0387:
0388:            /**
0389:             * Return the debugging detail level for this component.
0390:             */
0391:            public int getDebug() {
0392:
0393:                return (this .debug);
0394:
0395:            }
0396:
0397:            /**
0398:             * Set the debugging detail level for this component.
0399:             *
0400:             * @param debug The new debugging detail level
0401:             */
0402:            public void setDebug(int debug) {
0403:
0404:                this .debug = debug;
0405:
0406:            }
0407:
0408:            /**
0409:             * Return the "delegate first" flag for this class loader.
0410:             */
0411:            public boolean getDelegate() {
0412:
0413:                return (this .delegate);
0414:
0415:            }
0416:
0417:            /**
0418:             * Set the "delegate first" flag for this class loader.
0419:             *
0420:             * @param delegate The new "delegate first" flag
0421:             */
0422:            public void setDelegate(boolean delegate) {
0423:
0424:                this .delegate = delegate;
0425:
0426:            }
0427:
0428:            /**
0429:             * If there is a Java SecurityManager create a read FilePermission
0430:             * or JndiPermission for the file directory path.
0431:             *
0432:             * @param path file directory path
0433:             */
0434:            public void addPermission(String path) {
0435:                if (securityManager != null) {
0436:                    Permission permission = null;
0437:                    if (path.startsWith("jndi:")
0438:                            || path.startsWith("jar:jndi:")) {
0439:                        permission = new JndiPermission(path + "*");
0440:                    } else {
0441:                        permission = new FilePermission(path + "-", "read");
0442:                    }
0443:                    addPermission(permission);
0444:                }
0445:            }
0446:
0447:            /**
0448:             * If there is a Java SecurityManager create a read FilePermission
0449:             * or JndiPermission for URL.
0450:             *
0451:             * @param url URL for a file or directory on local system
0452:             */
0453:            public void addPermission(URL url) {
0454:                addPermission(url.toString());
0455:            }
0456:
0457:            /**
0458:             * If there is a Java SecurityManager create a Permission.
0459:             *
0460:             * @param url URL for a file or directory on local system
0461:             */
0462:            public void addPermission(Permission permission) {
0463:                if ((securityManager != null) && (permission != null)) {
0464:                    permissionList.add(permission);
0465:                }
0466:            }
0467:
0468:            /**
0469:             * Return the JAR path.
0470:             */
0471:            public String getJarPath() {
0472:
0473:                return this .jarPath;
0474:
0475:            }
0476:
0477:            /**
0478:             * Change the Jar path.
0479:             */
0480:            public void setJarPath(String jarPath) {
0481:
0482:                this .jarPath = jarPath;
0483:
0484:            }
0485:
0486:            // ------------------------------------------------------- Reloader Methods
0487:
0488:            /**
0489:             * Add a new repository to the set of places this ClassLoader can look for
0490:             * classes to be loaded.
0491:             *
0492:             * @param repository Name of a source of classes to be loaded, such as a
0493:             *  directory pathname, a JAR file pathname, or a ZIP file pathname
0494:             *
0495:             * @exception IllegalArgumentException if the specified repository is
0496:             *  invalid or does not exist
0497:             */
0498:            public void addRepository(String repository) {
0499:
0500:                // Ignore any of the standard repositories, as they are set up using
0501:                // either addJar or addRepository
0502:                if (repository.startsWith("/WEB-INF/lib")
0503:                        || repository.startsWith("/WEB-INF/classes"))
0504:                    return;
0505:
0506:                // Add this repository to our underlying class loader
0507:                try {
0508:                    URL url = new URL(repository);
0509:                    super .addURL(url);
0510:                    hasExternalRepositories = true;
0511:                } catch (MalformedURLException e) {
0512:                    throw new IllegalArgumentException(e.toString());
0513:                }
0514:
0515:            }
0516:
0517:            /**
0518:             * Add a new repository to the set of places this ClassLoader can look for
0519:             * classes to be loaded.
0520:             *
0521:             * @param repository Name of a source of classes to be loaded, such as a
0522:             *  directory pathname, a JAR file pathname, or a ZIP file pathname
0523:             *
0524:             * @exception IllegalArgumentException if the specified repository is
0525:             *  invalid or does not exist
0526:             */
0527:            synchronized void addRepository(String repository, File file) {
0528:
0529:                // Note : There should be only one (of course), but I think we should
0530:                // keep this a bit generic
0531:
0532:                if (repository == null)
0533:                    return;
0534:
0535:                if (debug >= 1)
0536:                    log("addRepository(" + repository + ")");
0537:
0538:                int i;
0539:
0540:                // Add this repository to our internal list
0541:                String[] result = new String[repositories.length + 1];
0542:                for (i = 0; i < repositories.length; i++) {
0543:                    result[i] = repositories[i];
0544:                }
0545:                result[repositories.length] = repository;
0546:                repositories = result;
0547:
0548:                // Add the file to the list
0549:                File[] result2 = new File[files.length + 1];
0550:                for (i = 0; i < files.length; i++) {
0551:                    result2[i] = files[i];
0552:                }
0553:                result2[files.length] = file;
0554:                files = result2;
0555:
0556:            }
0557:
0558:            synchronized void addJar(String jar, JarFile jarFile, File file)
0559:                    throws IOException {
0560:
0561:                if (jar == null)
0562:                    return;
0563:                if (jarFile == null)
0564:                    return;
0565:                if (file == null)
0566:                    return;
0567:
0568:                if (debug >= 1)
0569:                    log("addJar(" + jar + ")");
0570:
0571:                int i;
0572:
0573:                if ((jarPath != null) && (jar.startsWith(jarPath))) {
0574:
0575:                    String jarName = jar.substring(jarPath.length());
0576:                    while (jarName.startsWith("/"))
0577:                        jarName = jarName.substring(1);
0578:
0579:                    String[] result = new String[jarNames.length + 1];
0580:                    for (i = 0; i < jarNames.length; i++) {
0581:                        result[i] = jarNames[i];
0582:                    }
0583:                    result[jarNames.length] = jarName;
0584:                    jarNames = result;
0585:
0586:                }
0587:
0588:                try {
0589:
0590:                    // Register the JAR for tracking
0591:
0592:                    long lastModified = ((ResourceAttributes) resources
0593:                            .getAttributes(jar)).getLastModified();
0594:
0595:                    String[] result = new String[paths.length + 1];
0596:                    for (i = 0; i < paths.length; i++) {
0597:                        result[i] = paths[i];
0598:                    }
0599:                    result[paths.length] = jar;
0600:                    paths = result;
0601:
0602:                    long[] result3 = new long[lastModifiedDates.length + 1];
0603:                    for (i = 0; i < lastModifiedDates.length; i++) {
0604:                        result3[i] = lastModifiedDates[i];
0605:                    }
0606:                    result3[lastModifiedDates.length] = lastModified;
0607:                    lastModifiedDates = result3;
0608:
0609:                } catch (NamingException e) {
0610:                    // Ignore
0611:                }
0612:
0613:                // If the JAR currently contains invalid classes, don't actually use it
0614:                // for classloading
0615:                if (!validateJarFile(file))
0616:                    return;
0617:
0618:                JarFile[] result2 = new JarFile[jarFiles.length + 1];
0619:                for (i = 0; i < jarFiles.length; i++) {
0620:                    result2[i] = jarFiles[i];
0621:                }
0622:                result2[jarFiles.length] = jarFile;
0623:                jarFiles = result2;
0624:
0625:                // Add the file to the list
0626:                File[] result4 = new File[jarRealFiles.length + 1];
0627:                for (i = 0; i < jarRealFiles.length; i++) {
0628:                    result4[i] = jarRealFiles[i];
0629:                }
0630:                result4[jarRealFiles.length] = file;
0631:                jarRealFiles = result4;
0632:
0633:                // Load manifest
0634:                Manifest manifest = jarFile.getManifest();
0635:                if (manifest != null) {
0636:                    Iterator extensions = Extension.getAvailable(manifest)
0637:                            .iterator();
0638:                    while (extensions.hasNext()) {
0639:                        available.add(extensions.next());
0640:                    }
0641:                    extensions = Extension.getRequired(manifest).iterator();
0642:                    while (extensions.hasNext()) {
0643:                        required.add(extensions.next());
0644:                    }
0645:                }
0646:
0647:            }
0648:
0649:            /**
0650:             * Return a list of "optional packages" (formerly "standard extensions")
0651:             * that have been declared to be available in the repositories associated
0652:             * with this class loader, plus any parent class loader implemented with
0653:             * the same class.
0654:             */
0655:            public Extension[] findAvailable() {
0656:
0657:                // Initialize the results with our local available extensions
0658:                ArrayList results = new ArrayList();
0659:                Iterator available = this .available.iterator();
0660:                while (available.hasNext())
0661:                    results.add(available.next());
0662:
0663:                // Trace our parentage tree and add declared extensions when possible
0664:                ClassLoader loader = this ;
0665:                while (true) {
0666:                    loader = loader.getParent();
0667:                    if (loader == null)
0668:                        break;
0669:                    if (!(loader instanceof  WebappClassLoader))
0670:                        continue;
0671:                    Extension extensions[] = ((WebappClassLoader) loader)
0672:                            .findAvailable();
0673:                    for (int i = 0; i < extensions.length; i++)
0674:                        results.add(extensions[i]);
0675:                }
0676:
0677:                // Return the results as an array
0678:                Extension extensions[] = new Extension[results.size()];
0679:                return ((Extension[]) results.toArray(extensions));
0680:
0681:            }
0682:
0683:            /**
0684:             * Return a String array of the current repositories for this class
0685:             * loader.  If there are no repositories, a zero-length array is
0686:             * returned.
0687:             */
0688:            public String[] findRepositories() {
0689:
0690:                return (repositories);
0691:
0692:            }
0693:
0694:            /**
0695:             * Return a list of "optional packages" (formerly "standard extensions")
0696:             * that have been declared to be required in the repositories associated
0697:             * with this class loader, plus any parent class loader implemented with
0698:             * the same class.
0699:             */
0700:            public Extension[] findRequired() {
0701:
0702:                // Initialize the results with our local required extensions
0703:                ArrayList results = new ArrayList();
0704:                Iterator required = this .required.iterator();
0705:                while (required.hasNext())
0706:                    results.add(required.next());
0707:
0708:                // Trace our parentage tree and add declared extensions when possible
0709:                ClassLoader loader = this ;
0710:                while (true) {
0711:                    loader = loader.getParent();
0712:                    if (loader == null)
0713:                        break;
0714:                    if (!(loader instanceof  WebappClassLoader))
0715:                        continue;
0716:                    Extension extensions[] = ((WebappClassLoader) loader)
0717:                            .findRequired();
0718:                    for (int i = 0; i < extensions.length; i++)
0719:                        results.add(extensions[i]);
0720:                }
0721:
0722:                // Return the results as an array
0723:                Extension extensions[] = new Extension[results.size()];
0724:                return ((Extension[]) results.toArray(extensions));
0725:
0726:            }
0727:
0728:            /**
0729:             * Have one or more classes or resources been modified so that a reload
0730:             * is appropriate?
0731:             */
0732:            public boolean modified() {
0733:
0734:        if (debug >= 2)
0735:            log("modified()");
0736:
0737:        // Checking for modified loaded resources
0738:        int length = paths.length;
0739:
0740:        // A rare race condition can occur in the updates of the two arrays
0741:        // It's totally ok if the latest class added is not checked (it will
0742:        // be checked the next time
0743:        int length2 = lastModifiedDates.length;
0744:        if (length > length2)
0745:            length = length2;
0746:
0747:        for (int i = 0; i < length; i++) {
0748:            try {
0749:                long lastModified =
0750:                    ((ResourceAttributes) resources.getAttributes(paths[i]))
0751:                    .getLastModified();
0752:                if (lastModified != lastModifiedDates[i]) {
0753:                    log("  Resource '" + paths[i]
0754:                        + "' was modified; Date is now: "
0755:                        + new java.util.Date(lastModified) + " Was: "
0756:                        + new java.util.Date(lastModifiedDates[i]));
0757:                    return (true);
0758:                }
0759:            } catch (NamingException e) {
0760:                log("    Resource '" + paths[i] + "' is missing");
0761:                return (true);
0762:            }
0763:        }
0764:
0765:        length = jarNames.length;
0766:
0767:        // Check if JARs have been added or removed
0768:        if (getJarPath() != null) {
0769:
0770:            try {
0771:                NamingEnumeration enum = resources.listBindings(getJarPath());
0772:                int i = 0;
0773:                while (enum.hasMoreElements() && (i < length)) {
0774:                    NameClassPair ncPair = (NameClassPair) enum.nextElement();
0775:                    String name = ncPair.getName();
0776:                    // Ignore non JARs present in the lib folder
0777:                    if (!name.endsWith(".jar"))
0778:                        continue;
0779:                    if (!name.equals(jarNames[i])) {
0780:                        // Missing JAR
0781:                        log("    Additional JARs have been added : '" 
0782:                            + name + "'");
0783:                        return (true);
0784:                    }
0785:                    i++;
0786:                }
0787:                if (enum.hasMoreElements()) {
0788:                    while (enum.hasMoreElements()) {
0789:                        NameClassPair ncPair = 
0790:                            (NameClassPair) enum.nextElement();
0791:                        String name = ncPair.getName();
0792:                        // Additional non-JAR files are allowed
0793:                        if (name.endsWith(".jar")) {
0794:                            // There was more JARs
0795:                            log("    Additional JARs have been added");
0796:                            return (true);
0797:                        }
0798:                    }
0799:                } else if (i < jarNames.length) {
0800:                    // There was less JARs
0801:                    log("    Additional JARs have been added");
0802:                    return (true);
0803:                }
0804:            } catch (NamingException e) {
0805:                if (debug > 2)
0806:                    log("    Failed tracking modifications of '"
0807:                        + getJarPath() + "'");
0808:            } catch (ClassCastException e) {
0809:                log("    Failed tracking modifications of '"
0810:                    + getJarPath() + "' : " + e.getMessage());
0811:            }
0812:
0813:        }
0814:
0815:        // No classes have been modified
0816:        return (false);
0817:
0818:    }
0819:
0820:            /**
0821:             * Render a String representation of this object.
0822:             */
0823:            public String toString() {
0824:
0825:                StringBuffer sb = new StringBuffer("WebappClassLoader\r\n");
0826:                sb.append("  available:\r\n");
0827:                Iterator available = this .available.iterator();
0828:                while (available.hasNext()) {
0829:                    sb.append("    ");
0830:                    sb.append(available.next().toString());
0831:                    sb.append("\r\n");
0832:                }
0833:                sb.append("  delegate: ");
0834:                sb.append(delegate);
0835:                sb.append("\r\n");
0836:                sb.append("  repositories:\r\n");
0837:                for (int i = 0; i < repositories.length; i++) {
0838:                    sb.append("    ");
0839:                    sb.append(repositories[i]);
0840:                    sb.append("\r\n");
0841:                }
0842:                sb.append("  required:\r\n");
0843:                Iterator required = this .required.iterator();
0844:                while (required.hasNext()) {
0845:                    sb.append("    ");
0846:                    sb.append(required.next().toString());
0847:                    sb.append("\r\n");
0848:                }
0849:                if (this .parent != null) {
0850:                    sb.append("----------> Parent Classloader:\r\n");
0851:                    sb.append(this .parent.toString());
0852:                    sb.append("\r\n");
0853:                }
0854:                return (sb.toString());
0855:
0856:            }
0857:
0858:            // ---------------------------------------------------- ClassLoader Methods
0859:
0860:            /**
0861:             * Find the specified class in our local repositories, if possible.  If
0862:             * not found, throw <code>ClassNotFoundException</code>.
0863:             *
0864:             * @param name Name of the class to be loaded
0865:             *
0866:             * @exception ClassNotFoundException if the class was not found
0867:             */
0868:            public Class findClass(String name) throws ClassNotFoundException {
0869:
0870:                if (debug >= 3)
0871:                    log("    findClass(" + name + ")");
0872:
0873:                // (1) Permission to define this class when using a SecurityManager
0874:                if (securityManager != null) {
0875:                    int i = name.lastIndexOf('.');
0876:                    if (i >= 0) {
0877:                        try {
0878:                            if (debug >= 4)
0879:                                log("      securityManager.checkPackageDefinition");
0880:                            securityManager.checkPackageDefinition(name
0881:                                    .substring(0, i));
0882:                        } catch (Exception se) {
0883:                            if (debug >= 4)
0884:                                log(
0885:                                        "      -->Exception-->ClassNotFoundException",
0886:                                        se);
0887:                            throw new ClassNotFoundException(name);
0888:                        }
0889:                    }
0890:                }
0891:
0892:                // Ask our superclass to locate this class, if possible
0893:                // (throws ClassNotFoundException if it is not found)
0894:                Class clazz = null;
0895:                try {
0896:                    if (debug >= 4)
0897:                        log("      findClassInternal(" + name + ")");
0898:                    try {
0899:                        clazz = findClassInternal(name);
0900:                    } catch (AccessControlException ace) {
0901:                        ace.printStackTrace();
0902:                        throw new ClassNotFoundException(name);
0903:                    } catch (RuntimeException e) {
0904:                        if (debug >= 4)
0905:                            log("      -->RuntimeException Rethrown", e);
0906:                        throw e;
0907:                    }
0908:                    if ((clazz == null) && hasExternalRepositories) {
0909:                        try {
0910:                            clazz = super .findClass(name);
0911:                        } catch (AccessControlException ace) {
0912:                            throw new ClassNotFoundException(name);
0913:                        } catch (RuntimeException e) {
0914:                            if (debug >= 4)
0915:                                log("      -->RuntimeException Rethrown", e);
0916:                            throw e;
0917:                        }
0918:                    }
0919:                    if (clazz == null) {
0920:                        if (debug >= 3)
0921:                            log("    --> Returning ClassNotFoundException");
0922:                        throw new ClassNotFoundException(name);
0923:                    }
0924:                } catch (ClassNotFoundException e) {
0925:                    if (debug >= 3)
0926:                        log("    --> Passing on ClassNotFoundException", e);
0927:                    throw e;
0928:                }
0929:
0930:                // Return the class we have located
0931:                if (debug >= 4)
0932:                    log("      Returning class " + clazz);
0933:                if ((debug >= 4) && (clazz != null))
0934:                    log("      Loaded by " + clazz.getClassLoader());
0935:                return (clazz);
0936:
0937:            }
0938:
0939:            /**
0940:             * Find the specified resource in our local repository, and return a
0941:             * <code>URL</code> refering to it, or <code>null</code> if this resource
0942:             * cannot be found.
0943:             *
0944:             * @param name Name of the resource to be found
0945:             */
0946:            public URL findResource(final String name) {
0947:
0948:                if (debug >= 3)
0949:                    log("    findResource(" + name + ")");
0950:
0951:                URL url = null;
0952:
0953:                ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
0954:                if (entry == null) {
0955:                    if (securityManager != null) {
0956:                        PrivilegedAction dp = new PrivilegedFindResource(name,
0957:                                name);
0958:                        entry = (ResourceEntry) AccessController
0959:                                .doPrivileged(dp);
0960:                    } else {
0961:                        entry = findResourceInternal(name, name);
0962:                    }
0963:                }
0964:                if (entry != null) {
0965:                    url = entry.source;
0966:                }
0967:
0968:                if ((url == null) && hasExternalRepositories)
0969:                    url = super .findResource(name);
0970:
0971:                if (debug >= 3) {
0972:                    if (url != null)
0973:                        log("    --> Returning '" + url.toString() + "'");
0974:                    else
0975:                        log("    --> Resource not found, returning null");
0976:                }
0977:                return (url);
0978:
0979:            }
0980:
0981:            /**
0982:             * Return an enumeration of <code>URLs</code> representing all of the
0983:             * resources with the given name.  If no resources with this name are
0984:             * found, return an empty enumeration.
0985:             *
0986:             * @param name Name of the resources to be found
0987:             *
0988:             * @exception IOException if an input/output error occurs
0989:             */
0990:            public Enumeration findResources(String name) throws IOException {
0991:
0992:                if (debug >= 3)
0993:                    log("    findResources(" + name + ")");
0994:
0995:                Vector result = new Vector();
0996:
0997:                int jarFilesLength = jarFiles.length;
0998:                int repositoriesLength = repositories.length;
0999:
1000:                int i;
1001:
1002:                // Looking at the repositories
1003:                for (i = 0; i < repositoriesLength; i++) {
1004:                    try {
1005:                        String fullPath = repositories[i] + name;
1006:                        resources.lookup(fullPath);
1007:                        // Note : Not getting an exception here means the resource was
1008:                        // found
1009:                        try {
1010:                            result.addElement(getURL(new File(files[i], name)));
1011:                        } catch (MalformedURLException e) {
1012:                            // Ignore
1013:                        }
1014:                    } catch (NamingException e) {
1015:                    }
1016:                }
1017:
1018:                // Looking at the JAR files
1019:                for (i = 0; i < jarFilesLength; i++) {
1020:                    JarEntry jarEntry = jarFiles[i].getJarEntry(name);
1021:                    if (jarEntry != null) {
1022:                        try {
1023:                            String jarFakeUrl = getURL(jarRealFiles[i])
1024:                                    .toString();
1025:                            jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name;
1026:                            result.addElement(new URL(jarFakeUrl));
1027:                        } catch (MalformedURLException e) {
1028:                            // Ignore
1029:                        }
1030:                    }
1031:                }
1032:
1033:                // Adding the results of a call to the superclass
1034:                if (hasExternalRepositories) {
1035:
1036:                    Enumeration otherResourcePaths = super .findResources(name);
1037:
1038:                    while (otherResourcePaths.hasMoreElements()) {
1039:                        result.addElement(otherResourcePaths.nextElement());
1040:                    }
1041:
1042:                }
1043:
1044:                return result.elements();
1045:
1046:            }
1047:
1048:            /**
1049:             * Find the resource with the given name.  A resource is some data
1050:             * (images, audio, text, etc.) that can be accessed by class code in a
1051:             * way that is independent of the location of the code.  The name of a
1052:             * resource is a "/"-separated path name that identifies the resource.
1053:             * If the resource cannot be found, return <code>null</code>.
1054:             * <p>
1055:             * This method searches according to the following algorithm, returning
1056:             * as soon as it finds the appropriate URL.  If the resource cannot be
1057:             * found, returns <code>null</code>.
1058:             * <ul>
1059:             * <li>If the <code>delegate</code> property is set to <code>true</code>,
1060:             *     call the <code>getResource()</code> method of the parent class
1061:             *     loader, if any.</li>
1062:             * <li>Call <code>findResource()</code> to find this resource in our
1063:             *     locally defined repositories.</li>
1064:             * <li>Call the <code>getResource()</code> method of the parent class
1065:             *     loader, if any.</li>
1066:             * </ul>
1067:             *
1068:             * @param name Name of the resource to return a URL for
1069:             */
1070:            public URL getResource(String name) {
1071:
1072:                if (debug >= 2)
1073:                    log("getResource(" + name + ")");
1074:                URL url = null;
1075:
1076:                // (1) Delegate to parent if requested
1077:                if (delegate) {
1078:                    if (debug >= 3)
1079:                        log("  Delegating to parent classloader");
1080:                    ClassLoader loader = parent;
1081:                    if (loader == null)
1082:                        loader = system;
1083:                    url = loader.getResource(name);
1084:                    if (url != null) {
1085:                        if (debug >= 2)
1086:                            log("  --> Returning '" + url.toString() + "'");
1087:                        return (url);
1088:                    }
1089:                }
1090:
1091:                // (2) Search local repositories
1092:                if (debug >= 3)
1093:                    log("  Searching local repositories");
1094:                url = findResource(name);
1095:                if (url != null) {
1096:                    if (debug >= 2)
1097:                        log("  --> Returning '" + url.toString() + "'");
1098:                    return (url);
1099:                }
1100:
1101:                // (3) Delegate to parent unconditionally if not already attempted
1102:                if (!delegate) {
1103:                    ClassLoader loader = parent;
1104:                    if (loader == null)
1105:                        loader = system;
1106:                    url = loader.getResource(name);
1107:                    if (url != null) {
1108:                        if (debug >= 2)
1109:                            log("  --> Returning '" + url.toString() + "'");
1110:                        return (url);
1111:                    }
1112:                }
1113:
1114:                // (4) Resource was not found
1115:                if (debug >= 2)
1116:                    log("  --> Resource not found, returning null");
1117:                return (null);
1118:
1119:            }
1120:
1121:            /**
1122:             * Find the resource with the given name, and return an input stream
1123:             * that can be used for reading it.  The search order is as described
1124:             * for <code>getResource()</code>, after checking to see if the resource
1125:             * data has been previously cached.  If the resource cannot be found,
1126:             * return <code>null</code>.
1127:             *
1128:             * @param name Name of the resource to return an input stream for
1129:             */
1130:            public InputStream getResourceAsStream(String name) {
1131:
1132:                if (debug >= 2)
1133:                    log("getResourceAsStream(" + name + ")");
1134:                InputStream stream = null;
1135:
1136:                // (0) Check for a cached copy of this resource
1137:                stream = findLoadedResource(name);
1138:                if (stream != null) {
1139:                    if (debug >= 2)
1140:                        log("  --> Returning stream from cache");
1141:                    return (stream);
1142:                }
1143:
1144:                // (1) Delegate to parent if requested
1145:                if (delegate) {
1146:                    if (debug >= 3)
1147:                        log("  Delegating to parent classloader");
1148:                    ClassLoader loader = parent;
1149:                    if (loader == null)
1150:                        loader = system;
1151:                    stream = loader.getResourceAsStream(name);
1152:                    if (stream != null) {
1153:                        // FIXME - cache???
1154:                        if (debug >= 2)
1155:                            log("  --> Returning stream from parent");
1156:                        return (stream);
1157:                    }
1158:                }
1159:
1160:                // (2) Search local repositories
1161:                if (debug >= 3)
1162:                    log("  Searching local repositories");
1163:                URL url = findResource(name);
1164:                if (url != null) {
1165:                    // FIXME - cache???
1166:                    if (debug >= 2)
1167:                        log("  --> Returning stream from local");
1168:                    stream = findLoadedResource(name);
1169:                    try {
1170:                        if (hasExternalRepositories && (stream == null))
1171:                            stream = url.openStream();
1172:                    } catch (IOException e) {
1173:                        ; // Ignore
1174:                    }
1175:                    if (stream != null)
1176:                        return (stream);
1177:                }
1178:
1179:                // (3) Delegate to parent unconditionally
1180:                if (!delegate) {
1181:                    if (debug >= 3)
1182:                        log("  Delegating to parent classloader");
1183:                    ClassLoader loader = parent;
1184:                    if (loader == null)
1185:                        loader = system;
1186:                    stream = loader.getResourceAsStream(name);
1187:                    if (stream != null) {
1188:                        // FIXME - cache???
1189:                        if (debug >= 2)
1190:                            log("  --> Returning stream from parent");
1191:                        return (stream);
1192:                    }
1193:                }
1194:
1195:                // (4) Resource was not found
1196:                if (debug >= 2)
1197:                    log("  --> Resource not found, returning null");
1198:                return (null);
1199:
1200:            }
1201:
1202:            /**
1203:             * Load the class with the specified name.  This method searches for
1204:             * classes in the same manner as <code>loadClass(String, boolean)</code>
1205:             * with <code>false</code> as the second argument.
1206:             *
1207:             * @param name Name of the class to be loaded
1208:             *
1209:             * @exception ClassNotFoundException if the class was not found
1210:             */
1211:            public Class loadClass(String name) throws ClassNotFoundException {
1212:
1213:                return (loadClass(name, false));
1214:
1215:            }
1216:
1217:            /**
1218:             * Load the class with the specified name, searching using the following
1219:             * algorithm until it finds and returns the class.  If the class cannot
1220:             * be found, returns <code>ClassNotFoundException</code>.
1221:             * <ul>
1222:             * <li>Call <code>findLoadedClass(String)</code> to check if the
1223:             *     class has already been loaded.  If it has, the same
1224:             *     <code>Class</code> object is returned.</li>
1225:             * <li>If the <code>delegate</code> property is set to <code>true</code>,
1226:             *     call the <code>loadClass()</code> method of the parent class
1227:             *     loader, if any.</li>
1228:             * <li>Call <code>findClass()</code> to find this class in our locally
1229:             *     defined repositories.</li>
1230:             * <li>Call the <code>loadClass()</code> method of our parent
1231:             *     class loader, if any.</li>
1232:             * </ul>
1233:             * If the class was found using the above steps, and the
1234:             * <code>resolve</code> flag is <code>true</code>, this method will then
1235:             * call <code>resolveClass(Class)</code> on the resulting Class object.
1236:             *
1237:             * @param name Name of the class to be loaded
1238:             * @param resolve If <code>true</code> then resolve the class
1239:             *
1240:             * @exception ClassNotFoundException if the class was not found
1241:             */
1242:            public Class loadClass(String name, boolean resolve)
1243:                    throws ClassNotFoundException {
1244:
1245:                if (debug >= 2)
1246:                    log("loadClass(" + name + ", " + resolve + ")");
1247:                Class clazz = null;
1248:
1249:                // Don't load classes if class loader is stopped
1250:                if (!started) {
1251:                    log("Lifecycle error : CL stopped");
1252:                    throw new ClassNotFoundException(name);
1253:                }
1254:
1255:                // (0) Check our previously loaded local class cache
1256:                clazz = findLoadedClass0(name);
1257:                if (clazz != null) {
1258:                    if (debug >= 3)
1259:                        log("  Returning class from cache");
1260:                    if (resolve)
1261:                        resolveClass(clazz);
1262:                    return (clazz);
1263:                }
1264:
1265:                // (0.1) Check our previously loaded class cache
1266:                clazz = findLoadedClass(name);
1267:                if (clazz != null) {
1268:                    if (debug >= 3)
1269:                        log("  Returning class from cache");
1270:                    if (resolve)
1271:                        resolveClass(clazz);
1272:                    return (clazz);
1273:                }
1274:
1275:                // (0.2) Try loading the class with the system class loader, to prevent
1276:                //       the webapp from overriding J2SE classes
1277:                try {
1278:                    clazz = system.loadClass(name);
1279:                    if (clazz != null) {
1280:                        if (resolve)
1281:                            resolveClass(clazz);
1282:                        return (clazz);
1283:                    }
1284:                } catch (ClassNotFoundException e) {
1285:                    // Ignore
1286:                }
1287:
1288:                // (0.5) Permission to access this class when using a SecurityManager
1289:                if (securityManager != null) {
1290:                    int i = name.lastIndexOf('.');
1291:                    if (i >= 0) {
1292:                        try {
1293:                            securityManager.checkPackageAccess(name.substring(
1294:                                    0, i));
1295:                        } catch (SecurityException se) {
1296:                            String error = "Security Violation, attempt to use "
1297:                                    + "Restricted Class: " + name;
1298:                            System.out.println(error);
1299:                            se.printStackTrace();
1300:                            log(error);
1301:                            throw new ClassNotFoundException(error);
1302:                        }
1303:                    }
1304:                }
1305:
1306:                boolean delegateLoad = delegate || filter(name);
1307:
1308:                // (1) Delegate to our parent if requested
1309:                if (delegateLoad) {
1310:                    if (debug >= 3)
1311:                        log("  Delegating to parent classloader");
1312:                    ClassLoader loader = parent;
1313:                    if (loader == null)
1314:                        loader = system;
1315:                    try {
1316:                        clazz = loader.loadClass(name);
1317:                        if (clazz != null) {
1318:                            if (debug >= 3)
1319:                                log("  Loading class from parent");
1320:                            if (resolve)
1321:                                resolveClass(clazz);
1322:                            return (clazz);
1323:                        }
1324:                    } catch (ClassNotFoundException e) {
1325:                        ;
1326:                    }
1327:                }
1328:
1329:                // (2) Search local repositories
1330:                if (debug >= 3)
1331:                    log("  Searching local repositories");
1332:                try {
1333:                    clazz = findClass(name);
1334:                    if (clazz != null) {
1335:                        if (debug >= 3)
1336:                            log("  Loading class from local repository");
1337:                        if (resolve)
1338:                            resolveClass(clazz);
1339:                        return (clazz);
1340:                    }
1341:                } catch (ClassNotFoundException e) {
1342:                    ;
1343:                }
1344:
1345:                // (3) Delegate to parent unconditionally
1346:                if (!delegateLoad) {
1347:                    if (debug >= 3)
1348:                        log("  Delegating to parent classloader");
1349:                    ClassLoader loader = parent;
1350:                    if (loader == null)
1351:                        loader = system;
1352:                    try {
1353:                        clazz = loader.loadClass(name);
1354:                        if (clazz != null) {
1355:                            if (debug >= 3)
1356:                                log("  Loading class from parent");
1357:                            if (resolve)
1358:                                resolveClass(clazz);
1359:                            return (clazz);
1360:                        }
1361:                    } catch (ClassNotFoundException e) {
1362:                        ;
1363:                    }
1364:                }
1365:
1366:                // This class was not found
1367:                throw new ClassNotFoundException(name);
1368:
1369:            }
1370:
1371:            /**
1372:             * Get the Permissions for a CodeSource.  If this instance
1373:             * of WebappClassLoader is for a web application context,
1374:             * add read FilePermission or JndiPermissions for the base
1375:             * directory (if unpacked),
1376:             * the context URL, and jar file resources.
1377:             *
1378:             * @param CodeSource where the code was loaded from
1379:             * @return PermissionCollection for CodeSource
1380:             */
1381:            protected PermissionCollection getPermissions(CodeSource codeSource) {
1382:
1383:                String codeUrl = codeSource.getLocation().toString();
1384:                PermissionCollection pc;
1385:                if ((pc = (PermissionCollection) loaderPC.get(codeUrl)) == null) {
1386:                    pc = super .getPermissions(codeSource);
1387:                    if (pc != null) {
1388:                        Iterator perms = permissionList.iterator();
1389:                        while (perms.hasNext()) {
1390:                            Permission p = (Permission) perms.next();
1391:                            pc.add(p);
1392:                        }
1393:                        loaderPC.put(codeUrl, pc);
1394:                    }
1395:                }
1396:                return (pc);
1397:
1398:            }
1399:
1400:            /**
1401:             * Returns the search path of URLs for loading classes and resources.
1402:             * This includes the original list of URLs specified to the constructor,
1403:             * along with any URLs subsequently appended by the addURL() method.
1404:             * @return the search path of URLs for loading classes and resources.
1405:             */
1406:            public URL[] getURLs() {
1407:
1408:                URL[] external = super .getURLs();
1409:
1410:                int filesLength = files.length;
1411:                int jarFilesLength = jarRealFiles.length;
1412:                int length = filesLength + jarFilesLength + external.length;
1413:                int i;
1414:
1415:                try {
1416:
1417:                    URL[] urls = new URL[length];
1418:                    for (i = 0; i < length; i++) {
1419:                        if (i < filesLength) {
1420:                            urls[i] = getURL(files[i]);
1421:                        } else if (i < filesLength + jarFilesLength) {
1422:                            urls[i] = getURL(jarRealFiles[i - filesLength]);
1423:                        } else {
1424:                            urls[i] = external[i - filesLength - jarFilesLength];
1425:                        }
1426:                    }
1427:
1428:                    return urls;
1429:
1430:                } catch (MalformedURLException e) {
1431:                    return (new URL[0]);
1432:                }
1433:
1434:            }
1435:
1436:            // ------------------------------------------------------ Lifecycle Methods
1437:
1438:            /**
1439:             * Add a lifecycle event listener to this component.
1440:             *
1441:             * @param listener The listener to add
1442:             */
1443:            public void addLifecycleListener(LifecycleListener listener) {
1444:            }
1445:
1446:            /**
1447:             * Get the lifecycle listeners associated with this lifecycle. If this 
1448:             * Lifecycle has no listeners registered, a zero-length array is returned.
1449:             */
1450:            public LifecycleListener[] findLifecycleListeners() {
1451:                return new LifecycleListener[0];
1452:            }
1453:
1454:            /**
1455:             * Remove a lifecycle event listener from this component.
1456:             *
1457:             * @param listener The listener to remove
1458:             */
1459:            public void removeLifecycleListener(LifecycleListener listener) {
1460:            }
1461:
1462:            /**
1463:             * Start the class loader.
1464:             *
1465:             * @exception LifecycleException if a lifecycle error occurs
1466:             */
1467:            public void start() throws LifecycleException {
1468:
1469:                started = true;
1470:
1471:            }
1472:
1473:            /**
1474:             * Stop the class loader.
1475:             *
1476:             * @exception LifecycleException if a lifecycle error occurs
1477:             */
1478:            public void stop() throws LifecycleException {
1479:
1480:                started = false;
1481:
1482:                int length = jarFiles.length;
1483:                for (int i = 0; i < length; i++) {
1484:                    try {
1485:                        jarFiles[i].close();
1486:                        jarFiles[i] = null;
1487:                    } catch (IOException e) {
1488:                        // Ignore
1489:                    }
1490:                }
1491:
1492:                notFoundResources.clear();
1493:                resourceEntries.clear();
1494:                repositories = new String[0];
1495:                files = new File[0];
1496:                jarFiles = new JarFile[0];
1497:                jarRealFiles = new File[0];
1498:                jarPath = null;
1499:                jarNames = new String[0];
1500:                lastModifiedDates = new long[0];
1501:                paths = new String[0];
1502:                hasExternalRepositories = false;
1503:
1504:                required.clear();
1505:                permissionList.clear();
1506:                loaderPC.clear();
1507:
1508:            }
1509:
1510:            // ------------------------------------------------------ Protected Methods
1511:
1512:            /**
1513:             * Find specified class in local repositories.
1514:             *
1515:             * @return the loaded class, or null if the class isn't found
1516:             */
1517:            protected Class findClassInternal(String name)
1518:                    throws ClassNotFoundException {
1519:
1520:                if (!validate(name))
1521:                    throw new ClassNotFoundException(name);
1522:
1523:                String tempPath = name.replace('.', '/');
1524:                String classPath = tempPath + ".class";
1525:
1526:                ResourceEntry entry = null;
1527:
1528:                if (securityManager != null) {
1529:                    PrivilegedAction dp = new PrivilegedFindResource(name,
1530:                            classPath);
1531:                    entry = (ResourceEntry) AccessController.doPrivileged(dp);
1532:                } else {
1533:                    entry = findResourceInternal(name, classPath);
1534:                }
1535:
1536:                if ((entry == null) || (entry.binaryContent == null))
1537:                    throw new ClassNotFoundException(name);
1538:
1539:                Class clazz = entry.loadedClass;
1540:                if (clazz != null)
1541:                    return clazz;
1542:
1543:                // Looking up the package
1544:                String packageName = null;
1545:                int pos = name.lastIndexOf('.');
1546:                if (pos != -1)
1547:                    packageName = name.substring(0, pos);
1548:
1549:                Package pkg = null;
1550:
1551:                if (packageName != null) {
1552:
1553:                    pkg = getPackage(packageName);
1554:
1555:                    // Define the package (if null)
1556:                    if (pkg == null) {
1557:                        if (entry.manifest == null) {
1558:                            definePackage(packageName, null, null, null, null,
1559:                                    null, null, null);
1560:                        } else {
1561:                            definePackage(packageName, entry.manifest,
1562:                                    entry.codeBase);
1563:                        }
1564:                    }
1565:
1566:                }
1567:
1568:                // Create the code source object
1569:                CodeSource codeSource = new CodeSource(entry.codeBase,
1570:                        entry.certificates);
1571:
1572:                if (securityManager != null) {
1573:
1574:                    // Checking sealing
1575:                    if (pkg != null) {
1576:                        boolean sealCheck = true;
1577:                        if (pkg.isSealed()) {
1578:                            sealCheck = pkg.isSealed(entry.codeBase);
1579:                        } else {
1580:                            sealCheck = (entry.manifest == null)
1581:                                    || !isPackageSealed(packageName,
1582:                                            entry.manifest);
1583:                        }
1584:                        if (!sealCheck)
1585:                            throw new SecurityException(
1586:                                    "Sealing violation loading " + name
1587:                                            + " : Package " + packageName
1588:                                            + " is sealed.");
1589:                    }
1590:
1591:                }
1592:
1593:                if (entry.loadedClass == null) {
1594:                    synchronized (this ) {
1595:                        if (entry.loadedClass == null) {
1596:                            clazz = defineClass(name, entry.binaryContent, 0,
1597:                                    entry.binaryContent.length, codeSource);
1598:                            entry.loadedClass = clazz;
1599:                        } else {
1600:                            clazz = entry.loadedClass;
1601:                        }
1602:                    }
1603:                } else {
1604:                    clazz = entry.loadedClass;
1605:                }
1606:
1607:                return clazz;
1608:
1609:            }
1610:
1611:            /**
1612:             * Find specified resource in local repositories.
1613:             *
1614:             * @return the loaded resource, or null if the resource isn't found
1615:             */
1616:            protected ResourceEntry findResourceInternal(String name,
1617:                    String path) {
1618:
1619:                if (!started) {
1620:                    log("Lifecycle error : CL stopped");
1621:                    return null;
1622:                }
1623:
1624:                if ((name == null) || (path == null))
1625:                    return null;
1626:
1627:                ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
1628:                if (entry != null)
1629:                    return entry;
1630:
1631:                int contentLength = -1;
1632:                InputStream binaryStream = null;
1633:
1634:                int jarFilesLength = jarFiles.length;
1635:                int repositoriesLength = repositories.length;
1636:
1637:                int i;
1638:
1639:                Resource resource = null;
1640:
1641:                for (i = 0; (entry == null) && (i < repositoriesLength); i++) {
1642:                    try {
1643:
1644:                        String fullPath = repositories[i] + path;
1645:
1646:                        Object lookupResult = resources.lookup(fullPath);
1647:                        if (lookupResult instanceof  Resource) {
1648:                            resource = (Resource) lookupResult;
1649:                        }
1650:
1651:                        // Note : Not getting an exception here means the resource was
1652:                        // found
1653:
1654:                        entry = new ResourceEntry();
1655:                        try {
1656:                            entry.source = getURL(new File(files[i], path));
1657:                            entry.codeBase = entry.source;
1658:                        } catch (MalformedURLException e) {
1659:                            return null;
1660:                        }
1661:                        ResourceAttributes attributes = (ResourceAttributes) resources
1662:                                .getAttributes(fullPath);
1663:                        contentLength = (int) attributes.getContentLength();
1664:                        entry.lastModified = attributes.getLastModified();
1665:
1666:                        if (resource != null) {
1667:
1668:                            try {
1669:                                binaryStream = resource.streamContent();
1670:                            } catch (IOException e) {
1671:                                return null;
1672:                            }
1673:
1674:                            // Register the full path for modification checking
1675:                            // Note: Only syncing on a 'constant' object is needed
1676:                            synchronized (allPermission) {
1677:
1678:                                int j;
1679:
1680:                                long[] result2 = new long[lastModifiedDates.length + 1];
1681:                                for (j = 0; j < lastModifiedDates.length; j++) {
1682:                                    result2[j] = lastModifiedDates[j];
1683:                                }
1684:                                result2[lastModifiedDates.length] = entry.lastModified;
1685:                                lastModifiedDates = result2;
1686:
1687:                                String[] result = new String[paths.length + 1];
1688:                                for (j = 0; j < paths.length; j++) {
1689:                                    result[j] = paths[j];
1690:                                }
1691:                                result[paths.length] = fullPath;
1692:                                paths = result;
1693:
1694:                            }
1695:
1696:                        }
1697:
1698:                    } catch (NamingException e) {
1699:                    }
1700:                }
1701:
1702:                if ((entry == null) && (notFoundResources.containsKey(name)))
1703:                    return null;
1704:
1705:                JarEntry jarEntry = null;
1706:
1707:                for (i = 0; (entry == null) && (i < jarFilesLength); i++) {
1708:
1709:                    jarEntry = jarFiles[i].getJarEntry(path);
1710:
1711:                    if (jarEntry != null) {
1712:
1713:                        entry = new ResourceEntry();
1714:                        try {
1715:                            entry.codeBase = getURL(jarRealFiles[i]);
1716:                            String jarFakeUrl = entry.codeBase.toString();
1717:                            jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path;
1718:                            entry.source = new URL(jarFakeUrl);
1719:                        } catch (MalformedURLException e) {
1720:                            return null;
1721:                        }
1722:                        contentLength = (int) jarEntry.getSize();
1723:                        try {
1724:                            entry.manifest = jarFiles[i].getManifest();
1725:                            binaryStream = jarFiles[i].getInputStream(jarEntry);
1726:                        } catch (IOException e) {
1727:                            return null;
1728:                        }
1729:                    }
1730:
1731:                }
1732:
1733:                if (entry == null) {
1734:                    synchronized (notFoundResources) {
1735:                        notFoundResources.put(name, name);
1736:                    }
1737:                    return null;
1738:                }
1739:
1740:                if (binaryStream != null) {
1741:
1742:                    byte[] binaryContent = new byte[contentLength];
1743:
1744:                    try {
1745:                        int pos = 0;
1746:                        while (true) {
1747:                            int n = binaryStream.read(binaryContent, pos,
1748:                                    binaryContent.length - pos);
1749:                            if (n <= 0)
1750:                                break;
1751:                            pos += n;
1752:                        }
1753:                        binaryStream.close();
1754:                    } catch (IOException e) {
1755:                        e.printStackTrace();
1756:                        return null;
1757:                    } catch (Exception e) {
1758:                        e.printStackTrace();
1759:                        return null;
1760:                    }
1761:
1762:                    entry.binaryContent = binaryContent;
1763:
1764:                    // The certificates are only available after the JarEntry 
1765:                    // associated input stream has been fully read
1766:                    if (jarEntry != null) {
1767:                        entry.certificates = jarEntry.getCertificates();
1768:                    }
1769:
1770:                }
1771:
1772:                // Add the entry in the local resource repository
1773:                synchronized (resourceEntries) {
1774:                    // Ensures that all the threads which may be in a race to load
1775:                    // a particular class all end up with the same ResourceEntry
1776:                    // instance
1777:                    ResourceEntry entry2 = (ResourceEntry) resourceEntries
1778:                            .get(name);
1779:                    if (entry2 == null) {
1780:                        resourceEntries.put(name, entry);
1781:                    } else {
1782:                        entry = entry2;
1783:                    }
1784:                }
1785:
1786:                return entry;
1787:
1788:            }
1789:
1790:            /**
1791:             * Returns true if the specified package name is sealed according to the
1792:             * given manifest.
1793:             */
1794:            protected boolean isPackageSealed(String name, Manifest man) {
1795:
1796:                String path = name + "/";
1797:                Attributes attr = man.getAttributes(path);
1798:                String sealed = null;
1799:                if (attr != null) {
1800:                    sealed = attr.getValue(Name.SEALED);
1801:                }
1802:                if (sealed == null) {
1803:                    if ((attr = man.getMainAttributes()) != null) {
1804:                        sealed = attr.getValue(Name.SEALED);
1805:                    }
1806:                }
1807:                return "true".equalsIgnoreCase(sealed);
1808:
1809:            }
1810:
1811:            /**
1812:             * Finds the resource with the given name if it has previously been
1813:             * loaded and cached by this class loader, and return an input stream
1814:             * to the resource data.  If this resource has not been cached, return
1815:             * <code>null</code>.
1816:             *
1817:             * @param name Name of the resource to return
1818:             */
1819:            protected InputStream findLoadedResource(String name) {
1820:
1821:                ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
1822:                if (entry != null) {
1823:                    if (entry.binaryContent != null)
1824:                        return new ByteArrayInputStream(entry.binaryContent);
1825:                }
1826:                return (null);
1827:
1828:            }
1829:
1830:            /**
1831:             * Finds the class with the given name if it has previously been
1832:             * loaded and cached by this class loader, and return the Class object.
1833:             * If this class has not been cached, return <code>null</code>.
1834:             *
1835:             * @param name Name of the resource to return
1836:             */
1837:            protected Class findLoadedClass0(String name) {
1838:
1839:                ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
1840:                if (entry != null) {
1841:                    return entry.loadedClass;
1842:                }
1843:                return (null); // FIXME - findLoadedResource()
1844:
1845:            }
1846:
1847:            /**
1848:             * Refresh the system policy file, to pick up eventual changes.
1849:             */
1850:            protected void refreshPolicy() {
1851:
1852:                try {
1853:                    // The policy file may have been modified to adjust 
1854:                    // permissions, so we're reloading it when loading or 
1855:                    // reloading a Context
1856:                    Policy policy = Policy.getPolicy();
1857:                    policy.refresh();
1858:                } catch (AccessControlException e) {
1859:                    // Some policy files may restrict this, even for the core,
1860:                    // so this exception is ignored
1861:                }
1862:
1863:            }
1864:
1865:            /**
1866:             * Filter classes.
1867:             * 
1868:             * @param name class name
1869:             * @return true if the class should be filtered
1870:             */
1871:            protected boolean filter(String name) {
1872:
1873:                if (name == null)
1874:                    return false;
1875:
1876:                // Looking up the package
1877:                String packageName = null;
1878:                int pos = name.lastIndexOf('.');
1879:                if (pos != -1)
1880:                    packageName = name.substring(0, pos);
1881:                else
1882:                    return false;
1883:
1884:                for (int i = 0; i < packageTriggers.length; i++) {
1885:                    if (packageName.startsWith(packageTriggers[i]))
1886:                        return true;
1887:                }
1888:
1889:                return false;
1890:
1891:            }
1892:
1893:            /**
1894:             * Validate a classname. As per SRV.9.7.2, we must restict loading of 
1895:             * classes from J2SE (java.*) and classes of the servlet API 
1896:             * (javax.servlet.*). That should enhance robustness and prevent a number
1897:             * of user error (where an older version of servlet.jar would be present
1898:             * in /WEB-INF/lib).
1899:             * 
1900:             * @param name class name
1901:             * @return true if the name is valid
1902:             */
1903:            protected boolean validate(String name) {
1904:
1905:                if (name == null)
1906:                    return false;
1907:                if (name.startsWith("java."))
1908:                    return false;
1909:
1910:                return true;
1911:
1912:            }
1913:
1914:            /**
1915:             * Check the specified JAR file, and return <code>true</code> if it does
1916:             * not contain any of the trigger classes.
1917:             *
1918:             * @param jarFile The JAR file to be checked
1919:             *
1920:             * @exception IOException if an input/output error occurs
1921:             */
1922:            private boolean validateJarFile(File jarfile) throws IOException {
1923:
1924:                if (triggers == null)
1925:                    return (true);
1926:                JarFile jarFile = new JarFile(jarfile);
1927:                for (int i = 0; i < triggers.length; i++) {
1928:                    Class clazz = null;
1929:                    try {
1930:                        if (parent != null) {
1931:                            clazz = parent.loadClass(triggers[i]);
1932:                        } else {
1933:                            clazz = Class.forName(triggers[i]);
1934:                        }
1935:                    } catch (Throwable t) {
1936:                        clazz = null;
1937:                    }
1938:                    if (clazz == null)
1939:                        continue;
1940:                    String name = triggers[i].replace('.', '/') + ".class";
1941:                    if (debug >= 2)
1942:                        log(" Checking for " + name);
1943:                    JarEntry jarEntry = jarFile.getJarEntry(name);
1944:                    if (jarEntry != null) {
1945:                        log("validateJarFile(" + jarfile
1946:                                + ") - jar not loaded. See Servlet Spec 2.3, "
1947:                                + "section 9.7.2. Offending class: " + name);
1948:                        jarFile.close();
1949:                        return (false);
1950:                    }
1951:                }
1952:                jarFile.close();
1953:                return (true);
1954:
1955:            }
1956:
1957:            /**
1958:             * Get URL.
1959:             */
1960:            protected URL getURL(File file) throws MalformedURLException {
1961:
1962:                File realFile = file;
1963:                try {
1964:                    realFile = realFile.getCanonicalFile();
1965:                } catch (IOException e) {
1966:                    // Ignore
1967:                }
1968:                return new URL("file:" + realFile.getPath());
1969:
1970:            }
1971:
1972:            /**
1973:             * Log a debugging output message.
1974:             *
1975:             * @param message Message to be logged
1976:             */
1977:            private void log(String message) {
1978:
1979:                System.out.println("WebappClassLoader: " + message);
1980:
1981:            }
1982:
1983:            /**
1984:             * Log a debugging output message with an exception.
1985:             *
1986:             * @param message Message to be logged
1987:             * @param throwable Exception to be logged
1988:             */
1989:            private void log(String message, Throwable throwable) {
1990:
1991:                System.out.println("WebappClassLoader: " + message);
1992:                throwable.printStackTrace(System.out);
1993:
1994:            }
1995:
1996:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.