Source Code Cross Referenced for WebappLoader.java in  » Web-Server » Rimfaxe-Web-Server » org » apache » catalina » loader » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


0001:        /*
0002:         * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/loader/WebappLoader.java,v 1.28 2002/06/09 01:16:11 remm Exp $
0003:         * $Revision: 1.28 $
0004:         * $Date: 2002/06/09 01:16:11 $
0005:         *
0006:         * ====================================================================
0007:         *
0008:         * The Apache Software License, Version 1.1
0009:         *
0010:         * Copyright (c) 1999 The Apache Software Foundation.  All rights
0011:         * reserved.
0012:         *
0013:         * Redistribution and use in source and binary forms, with or without
0014:         * modification, are permitted provided that the following conditions
0015:         * are met:
0016:         *
0017:         * 1. Redistributions of source code must retain the above copyright
0018:         *    notice, this list of conditions and the following disclaimer.
0019:         *
0020:         * 2. Redistributions in binary form must reproduce the above copyright
0021:         *    notice, this list of conditions and the following disclaimer in
0022:         *    the documentation and/or other materials provided with the
0023:         *    distribution.
0024:         *
0025:         * 3. The end-user documentation included with the redistribution, if
0026:         *    any, must include the following acknowlegement:
0027:         *       "This product includes software developed by the
0028:         *        Apache Software Foundation (http://www.apache.org/)."
0029:         *    Alternately, this acknowlegement may appear in the software itself,
0030:         *    if and wherever such third-party acknowlegements normally appear.
0031:         *
0032:         * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0033:         *    Foundation" must not be used to endorse or promote products derived
0034:         *    from this software without prior written permission. For written
0035:         *    permission, please contact apache@apache.org.
0036:         *
0037:         * 5. Products derived from this software may not be called "Apache"
0038:         *    nor may "Apache" appear in their names without prior written
0039:         *    permission of the Apache Group.
0040:         *
0041:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0042:         * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0043:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0044:         * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0045:         * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0046:         * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0047:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0048:         * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0049:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0050:         * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0051:         * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0052:         * SUCH DAMAGE.
0053:         * ====================================================================
0054:         *
0055:         * This software consists of voluntary contributions made by many
0056:         * individuals on behalf of the Apache Software Foundation.  For more
0057:         * information on the Apache Software Foundation, please see
0058:         * <http://www.apache.org/>.
0059:         *
0060:         * [Additional notices, if required by prior licensing conditions]
0061:         *
0062:         */
0063:
0064:        package org.apache.catalina.loader;
0065:
0066:        import java.beans.PropertyChangeEvent;
0067:        import java.beans.PropertyChangeListener;
0068:        import java.beans.PropertyChangeSupport;
0069:        import java.io.File;
0070:        import java.io.IOException;
0071:        import java.io.InputStream;
0072:        import java.io.FileOutputStream;
0073:        import java.io.FilePermission;
0074:        import java.io.OutputStream;
0075:        import java.lang.reflect.Constructor;
0076:        import java.net.MalformedURLException;
0077:        import java.net.URL;
0078:        import java.net.URLClassLoader;
0079:        import java.net.URLStreamHandlerFactory;
0080:        import java.security.Permission;
0081:        import java.util.jar.JarFile;
0082:        import javax.servlet.ServletContext;
0083:        import javax.naming.NamingException;
0084:        import javax.naming.Binding;
0085:        import javax.naming.NameClassPair;
0086:        import javax.naming.NamingEnumeration;
0087:        import javax.naming.directory.DirContext;
0088:        import org.apache.naming.resources.Resource;
0089:        import org.apache.naming.resources.DirContextURLStreamHandler;
0090:        import org.apache.naming.resources.DirContextURLStreamHandlerFactory;
0091:        import org.apache.catalina.Container;
0092:        import org.apache.catalina.Context;
0093:        import org.apache.catalina.Globals;
0094:        import org.apache.catalina.Lifecycle;
0095:        import org.apache.catalina.LifecycleEvent;
0096:        import org.apache.catalina.LifecycleException;
0097:        import org.apache.catalina.LifecycleListener;
0098:        import org.apache.catalina.Loader;
0099:        import org.apache.catalina.Logger;
0100:        import org.apache.catalina.util.LifecycleSupport;
0101:        import org.apache.catalina.util.StringManager;
0102:
0103:        /**
0104:         * Classloader implementation which is specialized for handling web
0105:         * applications in the most efficient way, while being Catalina aware (all
0106:         * accesses to resources are made through the DirContext interface).
0107:         * This class loader supports detection of modified
0108:         * Java classes, which can be used to implement auto-reload support.
0109:         * <p>
0110:         * This class loader is configured by adding the pathnames of directories,
0111:         * JAR files, and ZIP files with the <code>addRepository()</code> method,
0112:         * prior to calling <code>start()</code>.  When a new class is required,
0113:         * these repositories will be consulted first to locate the class.  If it
0114:         * is not present, the system class loader will be used instead.
0115:         *
0116:         * @author Craig R. McClanahan
0117:         * @author Remy Maucherat
0118:         * @version $Revision: 1.28 $ $Date: 2002/06/09 01:16:11 $
0119:         */
0120:
0121:        public class WebappLoader implements  Lifecycle, Loader,
0122:                PropertyChangeListener, Runnable {
0123:
0124:            // ----------------------------------------------------------- Constructors
0125:
0126:            /**
0127:             * Construct a new WebappLoader with no defined parent class loader
0128:             * (so that the actual parent will be the system class loader).
0129:             */
0130:            public WebappLoader() {
0131:
0132:                this (null);
0133:
0134:            }
0135:
0136:            /**
0137:             * Construct a new WebappLoader with the specified class loader
0138:             * to be defined as the parent of the ClassLoader we ultimately create.
0139:             *
0140:             * @param parent The parent class loader
0141:             */
0142:            public WebappLoader(ClassLoader parent) {
0143:
0144:                super ();
0145:                this .parentClassLoader = parent;
0146:
0147:            }
0148:
0149:            // ----------------------------------------------------- Instance Variables
0150:
0151:            /**
0152:             * The number of seconds between checks for modified classes, if
0153:             * automatic reloading is enabled.
0154:             */
0155:            private int checkInterval = 15;
0156:
0157:            /**
0158:             * The class loader being managed by this Loader component.
0159:             */
0160:            private WebappClassLoader classLoader = null;
0161:
0162:            /**
0163:             * The Container with which this Loader has been associated.
0164:             */
0165:            private Container container = null;
0166:
0167:            /**
0168:             * The debugging detail level for this component.
0169:             */
0170:            private int debug = 0;
0171:
0172:            /**
0173:             * The "follow standard delegation model" flag that will be used to
0174:             * configure our ClassLoader.
0175:             */
0176:            private boolean delegate = false;
0177:
0178:            /**
0179:             * The descriptive information about this Loader implementation.
0180:             */
0181:            private static final String info = "org.apache.catalina.loader.WebappLoader/1.0";
0182:
0183:            /**
0184:             * The lifecycle event support for this component.
0185:             */
0186:            protected LifecycleSupport lifecycle = new LifecycleSupport(this );
0187:
0188:            /**
0189:             * The Java class name of the ClassLoader implementation to be used.
0190:             * This class should extend WebappClassLoader, otherwise, a different 
0191:             * loader implementation must be used.
0192:             */
0193:            private String loaderClass = "org.apache.catalina.loader.WebappClassLoader";
0194:
0195:            /**
0196:             * The parent class loader of the class loader we will create.
0197:             */
0198:            private ClassLoader parentClassLoader = null;
0199:
0200:            /**
0201:             * The reloadable flag for this Loader.
0202:             */
0203:            private boolean reloadable = false;
0204:
0205:            /**
0206:             * The set of repositories associated with this class loader.
0207:             */
0208:            private String repositories[] = new String[0];
0209:
0210:            /**
0211:             * The string manager for this package.
0212:             */
0213:            protected static final StringManager sm = StringManager
0214:                    .getManager(Constants.Package);
0215:
0216:            /**
0217:             * Has this component been started?
0218:             */
0219:            private boolean started = false;
0220:
0221:            /**
0222:             * The property change support for this component.
0223:             */
0224:            protected PropertyChangeSupport support = new PropertyChangeSupport(
0225:                    this );
0226:
0227:            /**
0228:             * The background thread.
0229:             */
0230:            private Thread thread = null;
0231:
0232:            /**
0233:             * The background thread completion semaphore.
0234:             */
0235:            private boolean threadDone = false;
0236:
0237:            /**
0238:             * Name to register for the background thread.
0239:             */
0240:            private String threadName = "WebappLoader";
0241:
0242:            // ------------------------------------------------------------- Properties
0243:
0244:            /**
0245:             * Return the check interval for this Loader.
0246:             */
0247:            public int getCheckInterval() {
0248:
0249:                return (this .checkInterval);
0250:
0251:            }
0252:
0253:            /**
0254:             * Set the check interval for this Loader.
0255:             *
0256:             * @param checkInterval The new check interval
0257:             */
0258:            public void setCheckInterval(int checkInterval) {
0259:
0260:                int oldCheckInterval = this .checkInterval;
0261:                this .checkInterval = checkInterval;
0262:                support.firePropertyChange("checkInterval", new Integer(
0263:                        oldCheckInterval), new Integer(this .checkInterval));
0264:
0265:            }
0266:
0267:            /**
0268:             * Return the Java class loader to be used by this Container.
0269:             */
0270:            public ClassLoader getClassLoader() {
0271:
0272:                return ((ClassLoader) classLoader);
0273:
0274:            }
0275:
0276:            /**
0277:             * Return the Container with which this Logger has been associated.
0278:             */
0279:            public Container getContainer() {
0280:
0281:                return (container);
0282:
0283:            }
0284:
0285:            /**
0286:             * Set the Container with which this Logger has been associated.
0287:             *
0288:             * @param container The associated Container
0289:             */
0290:            public void setContainer(Container container) {
0291:
0292:                // Deregister from the old Container (if any)
0293:                if ((this .container != null)
0294:                        && (this .container instanceof  Context))
0295:                    ((Context) this .container)
0296:                            .removePropertyChangeListener(this );
0297:
0298:                // Process this property change
0299:                Container oldContainer = this .container;
0300:                this .container = container;
0301:                support.firePropertyChange("container", oldContainer,
0302:                        this .container);
0303:
0304:                // Register with the new Container (if any)
0305:                if ((this .container != null)
0306:                        && (this .container instanceof  Context)) {
0307:                    setReloadable(((Context) this .container).getReloadable());
0308:                    ((Context) this .container).addPropertyChangeListener(this );
0309:                }
0310:
0311:            }
0312:
0313:            /**
0314:             * Return the debugging detail level for this component.
0315:             */
0316:            public int getDebug() {
0317:
0318:                return (this .debug);
0319:
0320:            }
0321:
0322:            /**
0323:             * Set the debugging detail level for this component.
0324:             *
0325:             * @param debug The new debugging detail level
0326:             */
0327:            public void setDebug(int debug) {
0328:
0329:                int oldDebug = this .debug;
0330:                this .debug = debug;
0331:                support.firePropertyChange("debug", new Integer(oldDebug),
0332:                        new Integer(this .debug));
0333:
0334:            }
0335:
0336:            /**
0337:             * Return the "follow standard delegation model" flag used to configure
0338:             * our ClassLoader.
0339:             */
0340:            public boolean getDelegate() {
0341:
0342:                return (this .delegate);
0343:
0344:            }
0345:
0346:            /**
0347:             * Set the "follow standard delegation model" flag used to configure
0348:             * our ClassLoader.
0349:             *
0350:             * @param delegate The new flag
0351:             */
0352:            public void setDelegate(boolean delegate) {
0353:
0354:                boolean oldDelegate = this .delegate;
0355:                this .delegate = delegate;
0356:                support.firePropertyChange("delegate",
0357:                        new Boolean(oldDelegate), new Boolean(this .delegate));
0358:
0359:            }
0360:
0361:            /**
0362:             * Return descriptive information about this Loader implementation and
0363:             * the corresponding version number, in the format
0364:             * <code>&lt;description&gt;/&lt;version&gt;</code>.
0365:             */
0366:            public String getInfo() {
0367:
0368:                return (info);
0369:
0370:            }
0371:
0372:            /**
0373:             * Return the ClassLoader class name.
0374:             */
0375:            public String getLoaderClass() {
0376:
0377:                return (this .loaderClass);
0378:
0379:            }
0380:
0381:            /**
0382:             * Set the ClassLoader class name.
0383:             *
0384:             * @param loaderClass The new ClassLoader class name
0385:             */
0386:            public void setLoaderClass(String loaderClass) {
0387:
0388:                this .loaderClass = loaderClass;
0389:
0390:            }
0391:
0392:            /**
0393:             * Return the reloadable flag for this Loader.
0394:             */
0395:            public boolean getReloadable() {
0396:
0397:                return (this .reloadable);
0398:
0399:            }
0400:
0401:            /**
0402:             * Set the reloadable flag for this Loader.
0403:             *
0404:             * @param reloadable The new reloadable flag
0405:             */
0406:            public void setReloadable(boolean reloadable) {
0407:
0408:                // Process this property change
0409:                boolean oldReloadable = this .reloadable;
0410:                this .reloadable = reloadable;
0411:                support.firePropertyChange("reloadable", new Boolean(
0412:                        oldReloadable), new Boolean(this .reloadable));
0413:
0414:                // Start or stop our background thread if required
0415:                if (!started)
0416:                    return;
0417:                if (!oldReloadable && this .reloadable)
0418:                    threadStart();
0419:                else if (oldReloadable && !this .reloadable)
0420:                    threadStop();
0421:
0422:            }
0423:
0424:            // --------------------------------------------------------- Public Methods
0425:
0426:            /**
0427:             * Add a property change listener to this component.
0428:             *
0429:             * @param listener The listener to add
0430:             */
0431:            public void addPropertyChangeListener(
0432:                    PropertyChangeListener listener) {
0433:
0434:                support.addPropertyChangeListener(listener);
0435:
0436:            }
0437:
0438:            /**
0439:             * Add a new repository to the set of repositories for this class loader.
0440:             *
0441:             * @param repository Repository to be added
0442:             */
0443:            public void addRepository(String repository) {
0444:
0445:                if (debug >= 1)
0446:                    log(sm.getString("webappLoader.addRepository", repository));
0447:
0448:                for (int i = 0; i < repositories.length; i++) {
0449:                    if (repository.equals(repositories[i]))
0450:                        return;
0451:                }
0452:                String results[] = new String[repositories.length + 1];
0453:                for (int i = 0; i < repositories.length; i++)
0454:                    results[i] = repositories[i];
0455:                results[repositories.length] = repository;
0456:                repositories = results;
0457:
0458:                if (started && (classLoader != null)) {
0459:                    classLoader.addRepository(repository);
0460:                    setClassPath();
0461:                }
0462:
0463:            }
0464:
0465:            /**
0466:             * Return the set of repositories defined for this class loader.
0467:             * If none are defined, a zero-length array is returned.
0468:             */
0469:            public String[] findRepositories() {
0470:
0471:                return (repositories);
0472:
0473:            }
0474:
0475:            /**
0476:             * Has the internal repository associated with this Loader been modified,
0477:             * such that the loaded classes should be reloaded?
0478:             */
0479:            public boolean modified() {
0480:
0481:                return (classLoader.modified());
0482:
0483:            }
0484:
0485:            /**
0486:             * Remove a property change listener from this component.
0487:             *
0488:             * @param listener The listener to remove
0489:             */
0490:            public void removePropertyChangeListener(
0491:                    PropertyChangeListener listener) {
0492:
0493:                support.removePropertyChangeListener(listener);
0494:
0495:            }
0496:
0497:            /**
0498:             * Return a String representation of this component.
0499:             */
0500:            public String toString() {
0501:
0502:                StringBuffer sb = new StringBuffer("WebappLoader[");
0503:                if (container != null)
0504:                    sb.append(container.getName());
0505:                sb.append("]");
0506:                return (sb.toString());
0507:
0508:            }
0509:
0510:            // ------------------------------------------------------ Lifecycle Methods
0511:
0512:            /**
0513:             * Add a lifecycle event listener to this component.
0514:             *
0515:             * @param listener The listener to add
0516:             */
0517:            public void addLifecycleListener(LifecycleListener listener) {
0518:
0519:                lifecycle.addLifecycleListener(listener);
0520:
0521:            }
0522:
0523:            /**
0524:             * Get the lifecycle listeners associated with this lifecycle. If this 
0525:             * Lifecycle has no listeners registered, a zero-length array is returned.
0526:             */
0527:            public LifecycleListener[] findLifecycleListeners() {
0528:
0529:                return lifecycle.findLifecycleListeners();
0530:
0531:            }
0532:
0533:            /**
0534:             * Remove a lifecycle event listener from this component.
0535:             *
0536:             * @param listener The listener to remove
0537:             */
0538:            public void removeLifecycleListener(LifecycleListener listener) {
0539:
0540:                lifecycle.removeLifecycleListener(listener);
0541:
0542:            }
0543:
0544:            /**
0545:             * Start this component, initializing our associated class loader.
0546:             *
0547:             * @exception LifecycleException if a lifecycle error occurs
0548:             */
0549:            public void start() throws LifecycleException {
0550:
0551:                // Validate and update our current component state
0552:                if (started)
0553:                    throw new LifecycleException(sm
0554:                            .getString("webappLoader.alreadyStarted"));
0555:                if (debug >= 1)
0556:                    log(sm.getString("webappLoader.starting"));
0557:                lifecycle.fireLifecycleEvent(START_EVENT, null);
0558:                started = true;
0559:
0560:                if (container.getResources() == null)
0561:                    return;
0562:
0563:                // Register a stream handler factory for the JNDI protocol
0564:                URLStreamHandlerFactory streamHandlerFactory = new DirContextURLStreamHandlerFactory();
0565:                try {
0566:                    URL.setURLStreamHandlerFactory(streamHandlerFactory);
0567:                } catch (Throwable t) {
0568:                    // Ignore the error here.
0569:                }
0570:
0571:                // Construct a class loader based on our current repositories list
0572:                try {
0573:
0574:                    classLoader = createClassLoader();
0575:                    classLoader.setResources(container.getResources());
0576:                    classLoader.setDebug(this .debug);
0577:                    classLoader.setDelegate(this .delegate);
0578:
0579:                    for (int i = 0; i < repositories.length; i++) {
0580:                        classLoader.addRepository(repositories[i]);
0581:                    }
0582:
0583:                    // Configure our repositories
0584:                    setRepositories();
0585:                    setClassPath();
0586:
0587:                    setPermissions();
0588:
0589:                    if (classLoader instanceof  Lifecycle)
0590:                        ((Lifecycle) classLoader).start();
0591:
0592:                    // Binding the Webapp class loader to the directory context
0593:                    DirContextURLStreamHandler.bind((ClassLoader) classLoader,
0594:                            this .container.getResources());
0595:
0596:                } catch (Throwable t) {
0597:                    throw new LifecycleException("start: ", t);
0598:                }
0599:
0600:                // Validate that all required packages are actually available
0601:                validatePackages();
0602:
0603:                // Start our background thread if we are reloadable
0604:                if (reloadable) {
0605:                    log(sm.getString("webappLoader.reloading"));
0606:                    try {
0607:                        threadStart();
0608:                    } catch (IllegalStateException e) {
0609:                        throw new LifecycleException(e);
0610:                    }
0611:                }
0612:
0613:            }
0614:
0615:            /**
0616:             * Stop this component, finalizing our associated class loader.
0617:             *
0618:             * @exception LifecycleException if a lifecycle error occurs
0619:             */
0620:            public void stop() throws LifecycleException {
0621:
0622:                // Validate and update our current component state
0623:                if (!started)
0624:                    throw new LifecycleException(sm
0625:                            .getString("webappLoader.notStarted"));
0626:                if (debug >= 1)
0627:                    log(sm.getString("webappLoader.stopping"));
0628:                lifecycle.fireLifecycleEvent(STOP_EVENT, null);
0629:                started = false;
0630:
0631:                // Stop our background thread if we are reloadable
0632:                if (reloadable)
0633:                    threadStop();
0634:
0635:                // Remove context attributes as appropriate
0636:                if (container instanceof  Context) {
0637:                    ServletContext servletContext = ((Context) container)
0638:                            .getServletContext();
0639:                    servletContext.removeAttribute(Globals.CLASS_PATH_ATTR);
0640:                }
0641:
0642:                // Throw away our current class loader
0643:                if (classLoader instanceof  Lifecycle)
0644:                    ((Lifecycle) classLoader).stop();
0645:                DirContextURLStreamHandler.unbind((ClassLoader) classLoader);
0646:                classLoader = null;
0647:
0648:            }
0649:
0650:            // ----------------------------------------- PropertyChangeListener Methods
0651:
0652:            /**
0653:             * Process property change events from our associated Context.
0654:             *
0655:             * @param event The property change event that has occurred
0656:             */
0657:            public void propertyChange(PropertyChangeEvent event) {
0658:
0659:                // Validate the source of this event
0660:                if (!(event.getSource() instanceof  Context))
0661:                    return;
0662:                Context context = (Context) event.getSource();
0663:
0664:                // Process a relevant property change
0665:                if (event.getPropertyName().equals("reloadable")) {
0666:                    try {
0667:                        setReloadable(((Boolean) event.getNewValue())
0668:                                .booleanValue());
0669:                    } catch (NumberFormatException e) {
0670:                        log(sm.getString("webappLoader.reloadable", event
0671:                                .getNewValue().toString()));
0672:                    }
0673:                }
0674:
0675:            }
0676:
0677:            // ------------------------------------------------------- Private Methods
0678:
0679:            /**
0680:             * Create associated classLoader.
0681:             */
0682:            private WebappClassLoader createClassLoader() throws Exception {
0683:
0684:                Class clazz = Class.forName(loaderClass);
0685:                WebappClassLoader classLoader = null;
0686:
0687:                if (parentClassLoader == null) {
0688:                    // Will cause a ClassCast is the class does not extend WCL, but
0689:                    // this is on purpose (the exception will be caught and rethrown)
0690:                    classLoader = (WebappClassLoader) clazz.newInstance();
0691:                } else {
0692:                    Class[] argTypes = { ClassLoader.class };
0693:                    Object[] args = { parentClassLoader };
0694:                    Constructor constr = clazz.getConstructor(argTypes);
0695:                    classLoader = (WebappClassLoader) constr.newInstance(args);
0696:                }
0697:
0698:                return classLoader;
0699:
0700:            }
0701:
0702:            /**
0703:             * Log a message on the Logger associated with our Container (if any)
0704:             *
0705:             * @param message Message to be logged
0706:             */
0707:            private void log(String message) {
0708:
0709:                Logger logger = null;
0710:                if (container != null)
0711:                    logger = container.getLogger();
0712:                if (logger != null)
0713:                    logger.log("WebappLoader[" + container.getName() + "]: "
0714:                            + message);
0715:                else {
0716:                    String containerName = null;
0717:                    if (container != null)
0718:                        containerName = container.getName();
0719:                    System.out.println("WebappLoader[" + containerName + "]: "
0720:                            + message);
0721:                }
0722:
0723:            }
0724:
0725:            /**
0726:             * Log a message on the Logger associated with our Container (if any)
0727:             *
0728:             * @param message Message to be logged
0729:             * @param throwable Associated exception
0730:             */
0731:            private void log(String message, Throwable throwable) {
0732:
0733:                Logger logger = null;
0734:                if (container != null)
0735:                    logger = container.getLogger();
0736:                if (logger != null) {
0737:                    logger.log("WebappLoader[" + container.getName() + "] "
0738:                            + message, throwable);
0739:                } else {
0740:                    String containerName = null;
0741:                    if (container != null)
0742:                        containerName = container.getName();
0743:                    System.out.println("WebappLoader[" + containerName + "]: "
0744:                            + message);
0745:                    System.out.println("" + throwable);
0746:                    throwable.printStackTrace(System.out);
0747:                }
0748:
0749:            }
0750:
0751:            /**
0752:             * Notify our Context that a reload is appropriate.
0753:             */
0754:            private void notifyContext() {
0755:
0756:                WebappContextNotifier notifier = new WebappContextNotifier();
0757:                (new Thread(notifier)).start();
0758:
0759:            }
0760:
0761:            /**
0762:             * Configure associated class loader permissions.
0763:             */
0764:            private void setPermissions() {
0765:
0766:                if (System.getSecurityManager() == null)
0767:                    return;
0768:                if (!(container instanceof  Context))
0769:                    return;
0770:
0771:                // Tell the class loader the root of the context
0772:                ServletContext servletContext = ((Context) container)
0773:                        .getServletContext();
0774:
0775:                // Assigning permissions for the work directory
0776:                File workDir = (File) servletContext
0777:                        .getAttribute(Globals.WORK_DIR_ATTR);
0778:                if (workDir != null) {
0779:                    try {
0780:                        String workDirPath = workDir.getCanonicalPath();
0781:                        classLoader.addPermission(new FilePermission(
0782:                                workDirPath, "read,write"));
0783:                        classLoader.addPermission(new FilePermission(
0784:                                workDirPath + File.separator + "-",
0785:                                "read,write,delete"));
0786:                    } catch (IOException e) {
0787:                        // Ignore
0788:                    }
0789:                }
0790:
0791:                try {
0792:
0793:                    URL rootURL = servletContext.getResource("/");
0794:                    classLoader.addPermission(rootURL);
0795:
0796:                    String contextRoot = servletContext.getRealPath("/");
0797:                    if (contextRoot != null) {
0798:                        try {
0799:                            contextRoot = (new File(contextRoot))
0800:                                    .getCanonicalPath()
0801:                                    + File.separator;
0802:                            classLoader.addPermission(contextRoot);
0803:                        } catch (IOException e) {
0804:                            // Ignore
0805:                        }
0806:                    }
0807:
0808:                    URL classesURL = servletContext
0809:                            .getResource("/WEB-INF/classes/");
0810:                    if (classesURL != null)
0811:                        classLoader.addPermission(classesURL);
0812:
0813:                    URL libURL = servletContext.getResource("/WEB-INF/lib/");
0814:                    if (libURL != null) {
0815:                        classLoader.addPermission(libURL);
0816:                    }
0817:
0818:                    if (contextRoot != null) {
0819:
0820:                        if (libURL != null) {
0821:                            File rootDir = new File(contextRoot);
0822:                            File libDir = new File(rootDir, "WEB-INF/lib/");
0823:                            String path = null;
0824:                            try {
0825:                                path = libDir.getCanonicalPath()
0826:                                        + File.separator;
0827:                            } catch (IOException e) {
0828:                            }
0829:                            if (path != null)
0830:                                classLoader.addPermission(path);
0831:                        }
0832:
0833:                    } else {
0834:
0835:                        if (workDir != null) {
0836:                            if (libURL != null) {
0837:                                File libDir = new File(workDir, "WEB-INF/lib/");
0838:                                String path = null;
0839:                                try {
0840:                                    path = libDir.getCanonicalPath()
0841:                                            + File.separator;
0842:                                } catch (IOException e) {
0843:                                }
0844:                                classLoader.addPermission(path);
0845:                            }
0846:                            if (classesURL != null) {
0847:                                File classesDir = new File(workDir,
0848:                                        "WEB-INF/classes/");
0849:                                String path = null;
0850:                                try {
0851:                                    path = classesDir.getCanonicalPath()
0852:                                            + File.separator;
0853:                                } catch (IOException e) {
0854:                                }
0855:                                classLoader.addPermission(path);
0856:                            }
0857:                        }
0858:
0859:                    }
0860:
0861:                } catch (MalformedURLException e) {
0862:                }
0863:
0864:            }
0865:
0866:            /**
0867:             * Configure the repositories for our class loader, based on the
0868:             * associated Context.
0869:             */
0870:            private void setRepositories() {
0871:
0872:        if (!(container instanceof  Context))
0873:            return;
0874:        ServletContext servletContext =
0875:            ((Context) container).getServletContext();
0876:        if (servletContext == null)
0877:            return;
0878:
0879:        // Loading the work directory
0880:        File workDir =
0881:            (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
0882:        if (workDir == null)
0883:            return;
0884:
0885:        log(sm.getString("webappLoader.deploy", workDir.getAbsolutePath()));
0886:
0887:        DirContext resources = container.getResources();
0888:
0889:        // Setting up the class repository (/WEB-INF/classes), if it exists
0890:
0891:        String classesPath = "/WEB-INF/classes";
0892:        DirContext classes = null;
0893:
0894:        try {
0895:            Object object = resources.lookup(classesPath);
0896:            if (object instanceof  DirContext) {
0897:                classes = (DirContext) object;
0898:            }
0899:        } catch(NamingException e) {
0900:            // Silent catch: it's valid that no /WEB-INF/classes collection
0901:            // exists
0902:        }
0903:
0904:        if (classes != null) {
0905:
0906:            File classRepository = null;
0907:
0908:            String absoluteClassesPath =
0909:                servletContext.getRealPath(classesPath);
0910:
0911:            if (absoluteClassesPath != null) {
0912:
0913:                classRepository = new File(absoluteClassesPath);
0914:
0915:            } else {
0916:
0917:                classRepository = new File(workDir, classesPath);
0918:                classRepository.mkdirs();
0919:                copyDir(classes, classRepository);
0920:
0921:            }
0922:
0923:            log(sm.getString("webappLoader.classDeploy", classesPath,
0924:                             classRepository.getAbsolutePath()));
0925:
0926:
0927:            // Adding the repository to the class loader
0928:            classLoader.addRepository(classesPath + "/", classRepository);
0929:
0930:        }
0931:
0932:        // Setting up the JAR repository (/WEB-INF/lib), if it exists
0933:
0934:        String libPath = "/WEB-INF/lib";
0935:
0936:        classLoader.setJarPath(libPath);
0937:
0938:        DirContext libDir = null;
0939:        // Looking up directory /WEB-INF/lib in the context
0940:        try {
0941:            Object object = resources.lookup(libPath);
0942:            if (object instanceof  DirContext)
0943:                libDir = (DirContext) object;
0944:        } catch(NamingException e) {
0945:            // Silent catch: it's valid that no /WEB-INF/lib collection
0946:            // exists
0947:        }
0948:
0949:        if (libDir != null) {
0950:
0951:            boolean copyJars = false;
0952:            String absoluteLibPath = servletContext.getRealPath(libPath);
0953:
0954:            File destDir = null;
0955:
0956:            if (absoluteLibPath != null) {
0957:                destDir = new File(absoluteLibPath);
0958:            } else {
0959:                copyJars = true;
0960:                destDir = new File(workDir, libPath);
0961:                destDir.mkdirs();
0962:            }
0963:
0964:            // Looking up directory /WEB-INF/lib in the context
0965:            try {
0966:                NamingEnumeration enum = resources.listBindings(libPath);
0967:                while (enum.hasMoreElements()) {
0968:
0969:                    Binding binding = (Binding) enum.nextElement();
0970:                    String filename = libPath + "/" + binding.getName();
0971:                    if (!filename.endsWith(".jar"))
0972:                        continue;
0973:
0974:                    // Copy JAR in the work directory, always (the JAR file
0975:                    // would get locked otherwise, which would make it
0976:                    // impossible to update it or remove it at runtime)
0977:                    File destFile = new File(destDir, binding.getName());
0978:
0979:                    log(sm.getString("webappLoader.jarDeploy", filename,
0980:                                     destFile.getAbsolutePath()));
0981:
0982:                    Resource jarResource = (Resource) binding.getObject();
0983:                    if (copyJars) {
0984:                        if (!copy(jarResource.streamContent(),
0985:                                  new FileOutputStream(destFile)))
0986:                            continue;
0987:                    }
0988:
0989:                    JarFile jarFile = new JarFile(destFile);
0990:                    classLoader.addJar(filename, jarFile, destFile);
0991:
0992:                }
0993:            } catch (NamingException e) {
0994:                // Silent catch: it's valid that no /WEB-INF/lib directory
0995:                // exists
0996:            } catch (IOException e) {
0997:                e.printStackTrace();
0998:            }
0999:
1000:        }
1001:
1002:    }
1003:
1004:            /**
1005:             * Set the appropriate context attribute for our class path.  This
1006:             * is required only because Jasper depends on it.
1007:             */
1008:            private void setClassPath() {
1009:
1010:                // Validate our current state information
1011:                if (!(container instanceof  Context))
1012:                    return;
1013:                ServletContext servletContext = ((Context) container)
1014:                        .getServletContext();
1015:                if (servletContext == null)
1016:                    return;
1017:
1018:                StringBuffer classpath = new StringBuffer();
1019:
1020:                // Assemble the class path information from our class loader chain
1021:                ClassLoader loader = getClassLoader();
1022:                int layers = 0;
1023:                int n = 0;
1024:                while ((layers < 3) && (loader != null)) {
1025:                    if (!(loader instanceof  URLClassLoader))
1026:                        break;
1027:                    URL repositories[] = ((URLClassLoader) loader).getURLs();
1028:                    for (int i = 0; i < repositories.length; i++) {
1029:                        String repository = repositories[i].toString();
1030:                        if (repository.startsWith("file://"))
1031:                            repository = repository.substring(7);
1032:                        else if (repository.startsWith("file:"))
1033:                            repository = repository.substring(5);
1034:                        else if (repository.startsWith("jndi:"))
1035:                            repository = servletContext.getRealPath(repository
1036:                                    .substring(5));
1037:                        else
1038:                            continue;
1039:                        if (repository == null)
1040:                            continue;
1041:                        if (n > 0)
1042:                            classpath.append(File.pathSeparator);
1043:                        classpath.append(repository);
1044:                        n++;
1045:                    }
1046:                    loader = loader.getParent();
1047:                    layers++;
1048:                }
1049:
1050:                // Store the assembled class path as a servlet context attribute
1051:                servletContext.setAttribute(Globals.CLASS_PATH_ATTR, classpath
1052:                        .toString());
1053:
1054:            }
1055:
1056:            /**
1057:             * Copy directory.
1058:             */
1059:            private boolean copyDir(DirContext srcDir, File destDir) {
1060:
1061:        try {
1062:
1063:            NamingEnumeration enum = srcDir.list("");
1064:            while (enum.hasMoreElements()) {
1065:                NameClassPair ncPair =
1066:                    (NameClassPair) enum.nextElement();
1067:                String name = ncPair.getName();
1068:                Object object = srcDir.lookup(name);
1069:                File currentFile = new File(destDir, name);
1070:                if (object instanceof  Resource) {
1071:                    InputStream is = ((Resource) object).streamContent();
1072:                    OutputStream os = new FileOutputStream(currentFile);
1073:                    if (!copy(is, os))
1074:                        return false;
1075:                } else if (object instanceof  InputStream) {
1076:                    OutputStream os = new FileOutputStream(currentFile);
1077:                    if (!copy((InputStream) object, os))
1078:                        return false;
1079:                } else if (object instanceof  DirContext) {
1080:                    currentFile.mkdir();
1081:                    copyDir((DirContext) object, currentFile);
1082:                }
1083:            }
1084:
1085:        } catch (NamingException e) {
1086:            return false;
1087:        } catch (IOException e) {
1088:            return false;
1089:        }
1090:
1091:        return true;
1092:
1093:    }
1094:
1095:            /**
1096:             * Copy a file to the specified temp directory. This is required only
1097:             * because Jasper depends on it.
1098:             */
1099:            private boolean copy(InputStream is, OutputStream os) {
1100:
1101:                try {
1102:                    byte[] buf = new byte[4096];
1103:                    while (true) {
1104:                        int len = is.read(buf);
1105:                        if (len < 0)
1106:                            break;
1107:                        os.write(buf, 0, len);
1108:                    }
1109:                    is.close();
1110:                    os.close();
1111:                } catch (IOException e) {
1112:                    return false;
1113:                }
1114:
1115:                return true;
1116:
1117:            }
1118:
1119:            /**
1120:             * Sleep for the duration specified by the <code>checkInterval</code>
1121:             * property.
1122:             */
1123:            private void threadSleep() {
1124:
1125:                try {
1126:                    Thread.sleep(checkInterval * 1000L);
1127:                } catch (InterruptedException e) {
1128:                    ;
1129:                }
1130:
1131:            }
1132:
1133:            /**
1134:             * Start the background thread that will periodically check for
1135:             * session timeouts.
1136:             *
1137:             * @exception IllegalStateException if we should not be starting
1138:             *  a background thread now
1139:             */
1140:            private void threadStart() {
1141:
1142:                // Has the background thread already been started?
1143:                if (thread != null)
1144:                    return;
1145:
1146:                // Validate our current state
1147:                if (!reloadable)
1148:                    throw new IllegalStateException(sm
1149:                            .getString("webappLoader.notReloadable"));
1150:                if (!(container instanceof  Context))
1151:                    throw new IllegalStateException(sm
1152:                            .getString("webappLoader.notContext"));
1153:
1154:                // Start the background thread
1155:                if (debug >= 1)
1156:                    log(" Starting background thread");
1157:                threadDone = false;
1158:                threadName = "WebappLoader[" + container.getName() + "]";
1159:                thread = new Thread(this , threadName);
1160:                thread.setDaemon(true);
1161:                thread.start();
1162:
1163:            }
1164:
1165:            /**
1166:             * Stop the background thread that is periodically checking for
1167:             * modified classes.
1168:             */
1169:            private void threadStop() {
1170:
1171:                if (thread == null)
1172:                    return;
1173:
1174:                if (debug >= 1)
1175:                    log(" Stopping background thread");
1176:                threadDone = true;
1177:                thread.interrupt();
1178:                try {
1179:                    thread.join();
1180:                } catch (InterruptedException e) {
1181:                    ;
1182:                }
1183:
1184:                thread = null;
1185:
1186:            }
1187:
1188:            /**
1189:             * Validate that the required optional packages for this application
1190:             * are actually present.
1191:             *
1192:             * @exception LifecycleException if a required package is not available
1193:             */
1194:            private void validatePackages() throws LifecycleException {
1195:
1196:                ClassLoader classLoader = getClassLoader();
1197:                if (classLoader instanceof  WebappClassLoader) {
1198:
1199:                    Extension available[] = ((WebappClassLoader) classLoader)
1200:                            .findAvailable();
1201:                    Extension required[] = ((WebappClassLoader) classLoader)
1202:                            .findRequired();
1203:                    if (debug >= 1)
1204:                        log("Optional Packages:  available=" + available.length
1205:                                + ", required=" + required.length);
1206:
1207:                    for (int i = 0; i < required.length; i++) {
1208:                        if (debug >= 1)
1209:                            log("Checking for required package " + required[i]);
1210:                        boolean found = false;
1211:                        for (int j = 0; j < available.length; j++) {
1212:                            if (available[j].isCompatibleWith(required[i])) {
1213:                                found = true;
1214:                                break;
1215:                            }
1216:                        }
1217:                        if (!found)
1218:                            throw new LifecycleException(
1219:                                    "Missing optional package " + required[i]);
1220:                    }
1221:
1222:                }
1223:
1224:            }
1225:
1226:            // ------------------------------------------------------ Background Thread
1227:
1228:            /**
1229:             * The background thread that checks for session timeouts and shutdown.
1230:             */
1231:            public void run() {
1232:
1233:                if (debug >= 1)
1234:                    log("BACKGROUND THREAD Starting");
1235:
1236:                // Loop until the termination semaphore is set
1237:                while (!threadDone) {
1238:
1239:                    // Wait for our check interval
1240:                    threadSleep();
1241:
1242:                    if (!started)
1243:                        break;
1244:
1245:                    try {
1246:                        // Perform our modification check
1247:                        if (!classLoader.modified())
1248:                            continue;
1249:                    } catch (Exception e) {
1250:                        log(sm.getString("webappLoader.failModifiedCheck"), e);
1251:                        continue;
1252:                    }
1253:
1254:                    // Handle a need for reloading
1255:                    notifyContext();
1256:                    break;
1257:
1258:                }
1259:
1260:                if (debug >= 1)
1261:                    log("BACKGROUND THREAD Stopping");
1262:
1263:            }
1264:
1265:            // -------------------------------------- WebappContextNotifier Inner Class
1266:
1267:            /**
1268:             * Private thread class to notify our associated Context that we have
1269:             * recognized the need for a reload.
1270:             */
1271:            protected class WebappContextNotifier implements  Runnable {
1272:
1273:                /**
1274:                 * Perform the requested notification.
1275:                 */
1276:                public void run() {
1277:
1278:                    ((Context) container).reload();
1279:
1280:                }
1281:
1282:            }
1283:
1284:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.