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


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