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


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