KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > loader > WebappLoader


1 /*
2  * Copyright 1999,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 // Modified by Google
17

18 package org.apache.catalina.loader;
19
20
21 import java.beans.PropertyChangeEvent JavaDoc;
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.beans.PropertyChangeSupport JavaDoc;
24 import java.io.File JavaDoc;
25 import java.io.FileOutputStream JavaDoc;
26 import java.io.FilePermission JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.io.OutputStream JavaDoc;
30 import java.lang.reflect.Constructor JavaDoc;
31 import java.lang.reflect.Method JavaDoc;
32 import java.net.MalformedURLException JavaDoc;
33 import java.net.URL JavaDoc;
34 import java.net.URLClassLoader JavaDoc;
35 import java.net.URLStreamHandlerFactory JavaDoc;
36 import java.util.ArrayList JavaDoc;
37 import java.util.jar.JarFile JavaDoc;
38
39 import javax.management.MBeanRegistration JavaDoc;
40 import javax.management.MBeanServer JavaDoc;
41 import javax.management.ObjectName JavaDoc;
42 import javax.naming.Binding JavaDoc;
43 import javax.naming.NameClassPair JavaDoc;
44 import javax.naming.NamingEnumeration JavaDoc;
45 import javax.naming.NamingException JavaDoc;
46 import javax.naming.directory.DirContext JavaDoc;
47 import javax.servlet.ServletContext JavaDoc;
48
49 import org.apache.catalina.Container;
50 import org.apache.catalina.Context;
51 import org.apache.catalina.DefaultContext;
52 import org.apache.catalina.Engine;
53 import org.apache.catalina.Globals;
54 import org.apache.catalina.Lifecycle;
55 import org.apache.catalina.LifecycleException;
56 import org.apache.catalina.LifecycleListener;
57 import org.apache.catalina.Loader;
58 import org.apache.catalina.Logger;
59 import org.apache.catalina.core.StandardContext;
60 import org.apache.catalina.util.LifecycleSupport;
61 import org.apache.catalina.util.StringManager;
62 import org.apache.commons.modeler.Registry;
63 import org.apache.naming.resources.DirContextURLStreamHandler;
64 import org.apache.naming.resources.DirContextURLStreamHandlerFactory;
65 import org.apache.naming.resources.Resource;
66
67
68 /**
69  * Classloader implementation which is specialized for handling web
70  * applications in the most efficient way, while being Catalina aware (all
71  * accesses to resources are made through the DirContext interface).
72  * This class loader supports detection of modified
73  * Java classes, which can be used to implement auto-reload support.
74  * <p>
75  * This class loader is configured by adding the pathnames of directories,
76  * JAR files, and ZIP files with the <code>addRepository()</code> method,
77  * prior to calling <code>start()</code>. When a new class is required,
78  * these repositories will be consulted first to locate the class. If it
79  * is not present, the system class loader will be used instead.
80  *
81  * @author Craig R. McClanahan
82  * @author Remy Maucherat
83  * @version $Revision: 1.27 $ $Date: 2004/03/02 12:31:57 $
84  */

85
86 public class WebappLoader
87     implements Lifecycle, Loader JavaDoc, PropertyChangeListener JavaDoc, MBeanRegistration JavaDoc {
88
89     // ----------------------------------------------------------- Constructors
90

91
92     /**
93      * Construct a new WebappLoader with no defined parent class loader
94      * (so that the actual parent will be the system class loader).
95      */

96     public WebappLoader() {
97
98         this(null);
99
100     }
101
102
103     /**
104      * Construct a new WebappLoader with the specified class loader
105      * to be defined as the parent of the ClassLoader we ultimately create.
106      *
107      * @param parent The parent class loader
108      */

109     public WebappLoader(ClassLoader JavaDoc parent) {
110         super();
111         this.parentClassLoader = parent;
112     }
113
114
115     // ----------------------------------------------------- Instance Variables
116

117
118     /**
119      * First load of the class.
120      */

121     private static boolean first = true;
122
123
124     /**
125      * The class loader being managed by this Loader component.
126      */

127     private WebappClassLoader classLoader = null;
128
129
130     /**
131      * The Container with which this Loader has been associated.
132      */

133     private Container container = null;
134
135
136     /**
137      * The debugging detail level for this component.
138      */

139     private int debug = 0;
140
141
142     /**
143      * The DefaultContext with which this Loader is associated.
144      */

145     protected DefaultContext defaultContext = null;
146     
147     
148     /**
149      * The "follow standard delegation model" flag that will be used to
150      * configure our ClassLoader.
151      */

152     private boolean delegate = false;
153
154
155     /**
156      * The descriptive information about this Loader implementation.
157      */

158     private static final String JavaDoc info =
159         "org.apache.catalina.loader.WebappLoader/1.0";
160
161
162     /**
163      * The lifecycle event support for this component.
164      */

165     protected LifecycleSupport lifecycle = new LifecycleSupport(this);
166
167
168     /**
169      * The Java class name of the ClassLoader implementation to be used.
170      * This class should extend WebappClassLoader, otherwise, a different
171      * loader implementation must be used.
172      */

173     private String JavaDoc loaderClass =
174         "org.apache.catalina.loader.WebappClassLoader";
175
176
177     /**
178      * The parent class loader of the class loader we will create.
179      */

180     private ClassLoader JavaDoc parentClassLoader = null;
181
182
183     /**
184      * The reloadable flag for this Loader.
185      */

186     private boolean reloadable = false;
187
188
189     /**
190      * The set of repositories associated with this class loader.
191      */

192     private String JavaDoc repositories[] = new String JavaDoc[0];
193
194
195     /**
196      * The string manager for this package.
197      */

198     protected static final StringManager sm =
199         StringManager.getManager(Constants.Package);
200
201
202     /**
203      * Has this component been started?
204      */

205     private boolean started = false;
206
207
208     /**
209      * The property change support for this component.
210      */

211     protected PropertyChangeSupport JavaDoc support = new PropertyChangeSupport JavaDoc(this);
212
213
214     /**
215      * Classpath set in the loader.
216      */

217     private String JavaDoc classpath = null;
218
219
220     /**
221      * Repositories that are set in the loader, for JMX.
222      */

223     private ArrayList JavaDoc loaderRepositories = null;
224
225
226     // ------------------------------------------------------------- Properties
227

228
229     /**
230      * Return the Java class loader to be used by this Container.
231      */

232     public ClassLoader JavaDoc getClassLoader() {
233
234         /*
235          * GOOGLE: When tomcat is embedded (as we are doing), classLoader is
236          * always null. Returning the parentClassLoader seems to do the right
237          * thing.
238          */

239         if (classLoader != null) {
240             return classLoader;
241         } else {
242             return parentClassLoader;
243         }
244
245     }
246
247
248     /**
249      * Return the Container with which this Logger has been associated.
250      */

251     public Container getContainer() {
252
253         return (container);
254
255     }
256
257
258     /**
259      * Set the Container with which this Logger has been associated.
260      *
261      * @param container The associated Container
262      */

263     public void setContainer(Container container) {
264
265         // Deregister from the old Container (if any)
266
if ((this.container != null) && (this.container instanceof Context JavaDoc))
267             ((Context JavaDoc) this.container).removePropertyChangeListener(this);
268
269         // Process this property change
270
Container oldContainer = this.container;
271         this.container = container;
272         support.firePropertyChange("container", oldContainer, this.container);
273
274         // Register with the new Container (if any)
275
if ((this.container != null) && (this.container instanceof Context JavaDoc)) {
276             setReloadable( ((Context JavaDoc) this.container).getReloadable() );
277             ((Context JavaDoc) this.container).addPropertyChangeListener(this);
278         }
279
280     }
281
282
283     /**
284      * Return the DefaultContext with which this Loader is associated.
285      * XXX What is that ???
286      */

287     public DefaultContext getDefaultContext() {
288
289         return (this.defaultContext);
290
291     }
292
293
294     /**
295      * Set the DefaultContext with which this Loader is associated.
296      *
297      * @param defaultContext The newly associated DefaultContext
298      */

299     public void setDefaultContext(DefaultContext defaultContext) {
300
301         DefaultContext oldDefaultContext = this.defaultContext;
302         this.defaultContext = defaultContext;
303         support.firePropertyChange("defaultContext", oldDefaultContext, this.defaultContext);
304
305     }
306
307
308     /**
309      * Return the debugging detail level for this component.
310      */

311     public int getDebug() {
312
313         return (this.debug);
314
315     }
316
317
318     /**
319      * Set the debugging detail level for this component.
320      *
321      * @param debug The new debugging detail level
322      */

323     public void setDebug(int debug) {
324
325         int oldDebug = this.debug;
326         this.debug = debug;
327         support.firePropertyChange("debug", new Integer JavaDoc(oldDebug),
328                                    new Integer JavaDoc(this.debug));
329
330     }
331
332
333     /**
334      * Return the "follow standard delegation model" flag used to configure
335      * our ClassLoader.
336      */

337     public boolean getDelegate() {
338
339         return (this.delegate);
340
341     }
342
343
344     /**
345      * Set the "follow standard delegation model" flag used to configure
346      * our ClassLoader.
347      *
348      * @param delegate The new flag
349      */

350     public void setDelegate(boolean delegate) {
351
352         boolean oldDelegate = this.delegate;
353         this.delegate = delegate;
354         support.firePropertyChange("delegate", new Boolean JavaDoc(oldDelegate),
355                                    new Boolean JavaDoc(this.delegate));
356
357     }
358
359
360     /**
361      * Return descriptive information about this Loader implementation and
362      * the corresponding version number, in the format
363      * <code>&lt;description&gt;/&lt;version&gt;</code>.
364      */

365     public String JavaDoc getInfo() {
366
367         return (info);
368
369     }
370
371
372     /**
373      * Return the ClassLoader class name.
374      */

375     public String JavaDoc getLoaderClass() {
376
377         return (this.loaderClass);
378
379     }
380
381
382     /**
383      * Set the ClassLoader class name.
384      *
385      * @param loaderClass The new ClassLoader class name
386      */

387     public void setLoaderClass(String JavaDoc loaderClass) {
388
389         this.loaderClass = loaderClass;
390
391     }
392
393
394     /**
395      * Return the reloadable flag for this Loader.
396      */

397     public boolean getReloadable() {
398
399         return (this.reloadable);
400
401     }
402
403
404     /**
405      * Set the reloadable flag for this Loader.
406      *
407      * @param reloadable The new reloadable flag
408      */

409     public void setReloadable(boolean reloadable) {
410
411         // Process this property change
412
boolean oldReloadable = this.reloadable;
413         this.reloadable = reloadable;
414         support.firePropertyChange("reloadable",
415                                    new Boolean JavaDoc(oldReloadable),
416                                    new Boolean JavaDoc(this.reloadable));
417
418     }
419
420
421     // --------------------------------------------------------- Public Methods
422

423
424     /**
425      * Add a property change listener to this component.
426      *
427      * @param listener The listener to add
428      */

429     public void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
430
431         support.addPropertyChangeListener(listener);
432
433     }
434
435
436     /**
437      * Add a new repository to the set of repositories for this class loader.
438      *
439      * @param repository Repository to be added
440      */

441     public void addRepository(String JavaDoc repository) {
442
443         if (log.isDebugEnabled())
444             log.debug(sm.getString("webappLoader.addRepository", repository));
445
446         for (int i = 0; i < repositories.length; i++) {
447             if (repository.equals(repositories[i]))
448                 return;
449         }
450         String JavaDoc results[] = new String JavaDoc[repositories.length + 1];
451         for (int i = 0; i < repositories.length; i++)
452             results[i] = repositories[i];
453         results[repositories.length] = repository;
454         repositories = results;
455
456         if (started && (classLoader != null)) {
457             classLoader.addRepository(repository);
458             if( loaderRepositories != null ) loaderRepositories.add(repository);
459             setClassPath();
460         }
461
462     }
463
464
465     /**
466      * Return the set of repositories defined for this class loader.
467      * If none are defined, a zero-length array is returned.
468      * For security reason, returns a clone of the Array (since
469      * String are immutable).
470      */

471     public String JavaDoc[] findRepositories() {
472
473         return ((String JavaDoc[])repositories.clone());
474
475     }
476
477     public String JavaDoc[] getRepositories() {
478         return ((String JavaDoc[])repositories.clone());
479     }
480
481     /** Extra repositories for this loader
482      */

483     public String JavaDoc getRepositoriesString() {
484         StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
485         for( int i=0; i<repositories.length ; i++ ) {
486             sb.append( repositories[i]).append(":");
487         }
488         return sb.toString();
489     }
490
491     public String JavaDoc[] getLoaderRepositories() {
492         if( loaderRepositories==null ) return null;
493         String JavaDoc res[]=new String JavaDoc[ loaderRepositories.size()];
494         loaderRepositories.toArray(res);
495         return res;
496     }
497
498     public String JavaDoc getLoaderRepositoriesString() {
499         String JavaDoc repositories[]=getLoaderRepositories();
500         StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
501         for( int i=0; i<repositories.length ; i++ ) {
502             sb.append( repositories[i]).append(":");
503         }
504         return sb.toString();
505     }
506
507
508     /**
509      * Classpath, as set in org.apache.catalina.jsp_classpath context
510      * property
511      *
512      * @return The classpath
513      */

514     public String JavaDoc getClasspath() {
515         return classpath;
516     }
517
518
519     /**
520      * Has the internal repository associated with this Loader been modified,
521      * such that the loaded classes should be reloaded?
522      */

523     public boolean modified() {
524
525         return (classLoader.modified());
526
527     }
528
529
530     /**
531      * Used to periodically signal to the classloader to release JAR resources.
532      */

533     public void closeJARs(boolean force) {
534         if (classLoader !=null){
535             classLoader.closeJARs(force);
536         }
537     }
538
539
540     /**
541      * Remove a property change listener from this component.
542      *
543      * @param listener The listener to remove
544      */

545     public void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
546
547         support.removePropertyChangeListener(listener);
548
549     }
550
551
552     /**
553      * Return a String representation of this component.
554      */

555     public String JavaDoc toString() {
556
557         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("WebappLoader[");
558         if (container != null)
559             sb.append(container.getName());
560         sb.append("]");
561         return (sb.toString());
562
563     }
564
565
566     // ------------------------------------------------------ Lifecycle Methods
567

568
569     /**
570      * Add a lifecycle event listener to this component.
571      *
572      * @param listener The listener to add
573      */

574     public void addLifecycleListener(LifecycleListener listener) {
575
576         lifecycle.addLifecycleListener(listener);
577
578     }
579
580
581     /**
582      * Get the lifecycle listeners associated with this lifecycle. If this
583      * Lifecycle has no listeners registered, a zero-length array is returned.
584      */

585     public LifecycleListener[] findLifecycleListeners() {
586
587         return lifecycle.findLifecycleListeners();
588
589     }
590
591
592     /**
593      * Remove a lifecycle event listener from this component.
594      *
595      * @param listener The listener to remove
596      */

597     public void removeLifecycleListener(LifecycleListener listener) {
598
599         lifecycle.removeLifecycleListener(listener);
600
601     }
602
603     private boolean initialized=false;
604
605     public void init() {
606         initialized=true;
607
608         if( oname==null ) {
609             // not registered yet - standalone or API
610
if( container instanceof StandardContext) {
611                 // Register ourself. The container must be a webapp
612
try {
613                     StandardContext ctx=(StandardContext)container;
614                     Engine eng=(Engine)ctx.getParent().getParent();
615                     String JavaDoc path = ctx.getPath();
616                     if (path.equals("")) {
617                         path = "/";
618                     }
619                     oname=new ObjectName JavaDoc(ctx.getEngineName() + ":type=Loader,path=" +
620                                 path + ",host=" + ctx.getParent().getName());
621                     Registry.getRegistry(null, null).registerComponent(this, oname, null);
622                     controller=oname;
623                 } catch (Exception JavaDoc e) {
624                     log.error("Error registering loader", e );
625                 }
626             }
627         }
628
629         if( container == null ) {
630             // JMX created the loader
631
// TODO
632

633         }
634     }
635
636     public void destroy() {
637         if( controller==oname ) {
638             // Self-registration, undo it
639
Registry.getRegistry(null, null).unregisterComponent(oname);
640             oname = null;
641         }
642         initialized = false;
643
644     }
645
646     /**
647      * Start this component, initializing our associated class loader.
648      *
649      * @exception LifecycleException if a lifecycle error occurs
650      */

651     public void start() throws LifecycleException {
652         // Validate and update our current component state
653
if( ! initialized ) init();
654         if (started)
655             throw new LifecycleException
656                 (sm.getString("webappLoader.alreadyStarted"));
657         if (log.isDebugEnabled())
658             log.debug(sm.getString("webappLoader.starting"));
659         lifecycle.fireLifecycleEvent(START_EVENT, null);
660         started = true;
661
662         if (container.getResources() == null) {
663             log.info("No resources for " + container);
664             return;
665         }
666         // Register a stream handler factory for the JNDI protocol
667
URLStreamHandlerFactory JavaDoc streamHandlerFactory =
668             new DirContextURLStreamHandlerFactory();
669         if (first) {
670             first = false;
671             try {
672                 URL.setURLStreamHandlerFactory(streamHandlerFactory);
673             } catch (Exception JavaDoc e) {
674                 // Log and continue anyway, this is not critical
675
log.error("Error registering jndi stream handler", e);
676             } catch (Throwable JavaDoc t) {
677                 // This is likely a dual registration
678
log.info("Dual registration of jndi stream handler: "
679                          + t.getMessage());
680             }
681         }
682
683         // Construct a class loader based on our current repositories list
684
try {
685
686             classLoader = createClassLoader();
687             classLoader.setResources(container.getResources());
688             classLoader.setDebug(this.debug);
689             classLoader.setDelegate(this.delegate);
690
691             for (int i = 0; i < repositories.length; i++) {
692                 classLoader.addRepository(repositories[i]);
693             }
694
695             // Configure our repositories
696
setRepositories();
697             setClassPath();
698
699             setPermissions();
700
701             if (classLoader instanceof Lifecycle)
702                 ((Lifecycle) classLoader).start();
703
704             // Binding the Webapp class loader to the directory context
705
DirContextURLStreamHandler.bind
706                 ((ClassLoader JavaDoc) classLoader, this.container.getResources());
707
708             StandardContext ctx=(StandardContext)container;
709             Engine eng=(Engine)ctx.getParent().getParent();
710             String JavaDoc path = ctx.getPath();
711             if (path.equals("")) {
712                 path = "/";
713             }
714             ObjectName JavaDoc cloname = new ObjectName JavaDoc
715                 (ctx.getEngineName() + ":type=WebappClassLoader,path="
716                  + path + ",host=" + ctx.getParent().getName());
717             Registry.getRegistry(null, null)
718                 .registerComponent(classLoader, cloname, null);
719
720         } catch (Throwable JavaDoc t) {
721             log.error( "LifecycleException ", t );
722             throw new LifecycleException("start: ", t);
723         }
724
725     }
726
727
728     /**
729      * Stop this component, finalizing our associated class loader.
730      *
731      * @exception LifecycleException if a lifecycle error occurs
732      */

733     public void stop() throws LifecycleException {
734
735         // Validate and update our current component state
736
if (!started)
737             throw new LifecycleException
738                 (sm.getString("webappLoader.notStarted"));
739         if (log.isDebugEnabled())
740             log.debug(sm.getString("webappLoader.stopping"));
741         lifecycle.fireLifecycleEvent(STOP_EVENT, null);
742         started = false;
743
744         // Remove context attributes as appropriate
745
if (container instanceof Context JavaDoc) {
746             ServletContext JavaDoc servletContext =
747                 ((Context JavaDoc) container).getServletContext();
748             servletContext.removeAttribute(Globals.CLASS_PATH_ATTR);
749         }
750
751         // Throw away our current class loader
752
if (classLoader instanceof Lifecycle)
753             ((Lifecycle) classLoader).stop();
754         DirContextURLStreamHandler.unbind((ClassLoader JavaDoc) classLoader);
755
756         try {
757             StandardContext ctx=(StandardContext)container;
758             Engine eng=(Engine)ctx.getParent().getParent();
759             String JavaDoc path = ctx.getPath();
760             if (path.equals("")) {
761                 path = "/";
762             }
763             ObjectName JavaDoc cloname = new ObjectName JavaDoc
764                 (ctx.getEngineName() + ":type=WebappClassLoader,path="
765                  + path + ",host=" + ctx.getParent().getName());
766             Registry.getRegistry(null, null).unregisterComponent(cloname);
767         } catch (Throwable JavaDoc t) {
768             log.error( "LifecycleException ", t );
769         }
770
771         classLoader = null;
772
773         destroy();
774
775     }
776
777
778     // ----------------------------------------- PropertyChangeListener Methods
779

780
781     /**
782      * Process property change events from our associated Context.
783      *
784      * @param event The property change event that has occurred
785      */

786     public void propertyChange(PropertyChangeEvent JavaDoc event) {
787
788         // Validate the source of this event
789
if (!(event.getSource() instanceof Context JavaDoc))
790             return;
791         Context JavaDoc context = (Context JavaDoc) event.getSource();
792
793         // Process a relevant property change
794
if (event.getPropertyName().equals("reloadable")) {
795             try {
796                 setReloadable
797                     ( ((Boolean JavaDoc) event.getNewValue()).booleanValue() );
798             } catch (NumberFormatException JavaDoc e) {
799                 log.error(sm.getString("webappLoader.reloadable",
800                                  event.getNewValue().toString()));
801             }
802         }
803
804     }
805
806
807     // ------------------------------------------------------- Private Methods
808

809
810     /**
811      * Create associated classLoader.
812      */

813     private WebappClassLoader createClassLoader()
814         throws Exception JavaDoc {
815
816         Class JavaDoc clazz = Class.forName(loaderClass);
817         WebappClassLoader classLoader = null;
818
819         if (parentClassLoader == null) {
820             parentClassLoader = Thread.currentThread().getContextClassLoader();
821         }
822         Class JavaDoc[] argTypes = { ClassLoader JavaDoc.class };
823         Object JavaDoc[] args = { parentClassLoader };
824         Constructor JavaDoc constr = clazz.getConstructor(argTypes);
825         classLoader = (WebappClassLoader) constr.newInstance(args);
826
827         return classLoader;
828
829     }
830
831
832     /**
833      * Log a message on the Logger associated with our Container (if any)
834      *
835      * @param message Message to be logged
836      */

837     private void log(String JavaDoc message) {
838
839         Logger logger = null;
840         if (container != null)
841             logger = container.getLogger();
842         if (logger != null)
843             logger.log("WebappLoader[" + container.getName() + "]: "
844                        + message);
845         else {
846             String JavaDoc containerName = null;
847             if (container != null)
848                 containerName = container.getName();
849             System.out.println("WebappLoader[" + containerName
850                                + "]: " + message);
851         }
852
853     }
854
855
856     /**
857      * Log a message on the Logger associated with our Container (if any)
858      *
859      * @param message Message to be logged
860      * @param throwable Associated exception
861      */

862     private void log(String JavaDoc message, Throwable JavaDoc throwable) {
863
864         Logger logger = null;
865         if (container != null)
866             logger = container.getLogger();
867         if (logger != null) {
868             logger.log("WebappLoader[" + container.getName() + "] "
869                        + message, throwable);
870         } else {
871             String JavaDoc containerName = null;
872             if (container != null)
873                 containerName = container.getName();
874             System.out.println("WebappLoader[" + containerName
875                                + "]: " + message);
876             System.out.println("" + throwable);
877             throwable.printStackTrace(System.out);
878         }
879
880     }
881
882
883     /**
884      * Configure associated class loader permissions.
885      */

886     private void setPermissions() {
887
888         if (System.getSecurityManager() == null)
889             return;
890         if (!(container instanceof Context JavaDoc))
891             return;
892
893         // Tell the class loader the root of the context
894
ServletContext JavaDoc servletContext =
895             ((Context JavaDoc) container).getServletContext();
896
897         // Assigning permissions for the work directory
898
File JavaDoc workDir =
899             (File JavaDoc) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
900         if (workDir != null) {
901             try {
902                 String JavaDoc workDirPath = workDir.getCanonicalPath();
903                 classLoader.addPermission
904                     (new FilePermission JavaDoc(workDirPath, "read,write"));
905                 classLoader.addPermission
906                     (new FilePermission JavaDoc(workDirPath + File.separator + "-",
907                                         "read,write,delete"));
908             } catch (IOException JavaDoc e) {
909                 // Ignore
910
}
911         }
912
913         try {
914
915             URL JavaDoc rootURL = servletContext.getResource("/");
916             classLoader.addPermission(rootURL);
917
918             String JavaDoc contextRoot = servletContext.getRealPath("/");
919             if (contextRoot != null) {
920                 try {
921                     contextRoot = (new File JavaDoc(contextRoot)).getCanonicalPath();
922                     classLoader.addPermission(contextRoot);
923                 } catch (IOException JavaDoc e) {
924                     // Ignore
925
}
926             }
927
928             URL JavaDoc classesURL = servletContext.getResource("/WEB-INF/classes/");
929             classLoader.addPermission(classesURL);
930             URL JavaDoc libURL = servletContext.getResource("/WEB-INF/lib/");
931             classLoader.addPermission(libURL);
932
933             if (contextRoot != null) {
934
935                 if (libURL != null) {
936                     File JavaDoc rootDir = new File JavaDoc(contextRoot);
937                     File JavaDoc libDir = new File JavaDoc(rootDir, "WEB-INF/lib/");
938                     try {
939                         String JavaDoc path = libDir.getCanonicalPath();
940                         classLoader.addPermission(path);
941                     } catch (IOException JavaDoc e) {
942                     }
943                 }
944
945             } else {
946
947                 if (workDir != null) {
948                     if (libURL != null) {
949                         File JavaDoc libDir = new File JavaDoc(workDir, "WEB-INF/lib/");
950                         try {
951                             String JavaDoc path = libDir.getCanonicalPath();
952                             classLoader.addPermission(path);
953                         } catch (IOException JavaDoc e) {
954                         }
955                     }
956                     if (classesURL != null) {
957                         File JavaDoc classesDir = new File JavaDoc(workDir, "WEB-INF/classes/");
958                         try {
959                             String JavaDoc path = classesDir.getCanonicalPath();
960                             classLoader.addPermission(path);
961                         } catch (IOException JavaDoc e) {
962                         }
963                     }
964                 }
965
966             }
967
968         } catch (MalformedURLException JavaDoc e) {
969         }
970
971     }
972
973
974     /**
975      * Configure the repositories for our class loader, based on the
976      * associated Context.
977      */

978     private void setRepositories() {
979
980         if (!(container instanceof Context JavaDoc))
981             return;
982         ServletContext JavaDoc servletContext =
983             ((Context JavaDoc) container).getServletContext();
984         if (servletContext == null)
985             return;
986
987         loaderRepositories=new ArrayList JavaDoc();
988         // Loading the work directory
989
File JavaDoc workDir =
990             (File JavaDoc) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
991         if (workDir == null) {
992             log.info("No work dir for " + servletContext);
993         }
994
995         if( log.isDebugEnabled())
996             log.debug(sm.getString("webappLoader.deploy", workDir.getAbsolutePath()));
997
998         classLoader.setWorkDir(workDir);
999
1000        DirContext JavaDoc resources = container.getResources();
1001
1002        // Setting up the class repository (/WEB-INF/classes), if it exists
1003

1004        String JavaDoc classesPath = "/WEB-INF/classes";
1005        DirContext JavaDoc classes = null;
1006
1007        try {
1008            Object JavaDoc object = resources.lookup(classesPath);
1009            if (object instanceof DirContext JavaDoc) {
1010                classes = (DirContext JavaDoc) object;
1011            }
1012        } catch(NamingException JavaDoc e) {
1013            // Silent catch: it's valid that no /WEB-INF/classes collection
1014
// exists
1015
}
1016
1017        if (classes != null) {
1018
1019            File JavaDoc classRepository = null;
1020
1021            String JavaDoc absoluteClassesPath =
1022                servletContext.getRealPath(classesPath);
1023
1024            if (absoluteClassesPath != null) {
1025
1026                classRepository = new File JavaDoc(absoluteClassesPath);
1027
1028            } else {
1029
1030                classRepository = new File JavaDoc(workDir, classesPath);
1031                classRepository.mkdirs();
1032                copyDir(classes, classRepository);
1033
1034            }
1035
1036            if(log.isDebugEnabled())
1037                log.debug(sm.getString("webappLoader.classDeploy", classesPath,
1038                             classRepository.getAbsolutePath()));
1039
1040
1041            // Adding the repository to the class loader
1042
classLoader.addRepository(classesPath + "/", classRepository);
1043            loaderRepositories.add(classesPath + "/" );
1044
1045        }
1046
1047        // Setting up the JAR repository (/WEB-INF/lib), if it exists
1048

1049        String JavaDoc libPath = "/WEB-INF/lib";
1050
1051        classLoader.setJarPath(libPath);
1052
1053        DirContext JavaDoc libDir = null;
1054        // Looking up directory /WEB-INF/lib in the context
1055
try {
1056            Object JavaDoc object = resources.lookup(libPath);
1057            if (object instanceof DirContext JavaDoc)
1058                libDir = (DirContext JavaDoc) object;
1059        } catch(NamingException JavaDoc e) {
1060            // Silent catch: it's valid that no /WEB-INF/lib collection
1061
// exists
1062
}
1063
1064        if (libDir != null) {
1065
1066            boolean copyJars = false;
1067            String JavaDoc absoluteLibPath = servletContext.getRealPath(libPath);
1068
1069            File JavaDoc destDir = null;
1070
1071            if (absoluteLibPath != null) {
1072                destDir = new File JavaDoc(absoluteLibPath);
1073            } else {
1074                copyJars = true;
1075                destDir = new File JavaDoc(workDir, libPath);
1076                destDir.mkdirs();
1077            }
1078
1079            // Looking up directory /WEB-INF/lib in the context
1080
try {
1081                // GOOGLE: "enum" is a reserved word in JDK 1.5
1082
NamingEnumeration JavaDoc enum_ = resources.listBindings(libPath);
1083                while (enum_.hasMoreElements()) {
1084
1085                    Binding JavaDoc binding = (Binding JavaDoc) enum_.nextElement();
1086                    String JavaDoc filename = libPath + "/" + binding.getName();
1087                    if (!filename.endsWith(".jar"))
1088                        continue;
1089
1090                    // Copy JAR in the work directory, always (the JAR file
1091
// would get locked otherwise, which would make it
1092
// impossible to update it or remove it at runtime)
1093
File JavaDoc destFile = new File JavaDoc(destDir, binding.getName());
1094
1095                    if( log.isDebugEnabled())
1096                    log.debug(sm.getString("webappLoader.jarDeploy", filename,
1097                                     destFile.getAbsolutePath()));
1098
1099                    Resource jarResource = (Resource) binding.getObject();
1100                    if (copyJars) {
1101                        if (!copy(jarResource.streamContent(),
1102                                  new FileOutputStream JavaDoc(destFile)))
1103                            continue;
1104                    }
1105
1106                    try {
1107                        JarFile JavaDoc jarFile = new JarFile JavaDoc(destFile);
1108                        classLoader.addJar(filename, jarFile, destFile);
1109                    } catch (Exception JavaDoc ex) {
1110                        // Catch the exception if there is an empty jar file
1111
// Should ignore and continute loading other jar files
1112
// in the dir
1113
}
1114                    
1115                    loaderRepositories.add( filename );
1116
1117                }
1118            } catch (NamingException JavaDoc e) {
1119                // Silent catch: it's valid that no /WEB-INF/lib directory
1120
// exists
1121
} catch (IOException JavaDoc e) {
1122                e.printStackTrace();
1123            }
1124
1125        }
1126
1127    }
1128
1129
1130    /**
1131     * Set the appropriate context attribute for our class path. This
1132     * is required only because Jasper depends on it.
1133     */

1134    private void setClassPath() {
1135
1136        // Validate our current state information
1137
if (!(container instanceof Context JavaDoc))
1138            return;
1139        ServletContext JavaDoc servletContext =
1140            ((Context JavaDoc) container).getServletContext();
1141        if (servletContext == null)
1142            return;
1143
1144        if (container instanceof StandardContext) {
1145            String JavaDoc baseClasspath =
1146                ((StandardContext) container).getCompilerClasspath();
1147            if (baseClasspath != null) {
1148                servletContext.setAttribute(Globals.CLASS_PATH_ATTR,
1149                                            baseClasspath);
1150                return;
1151            }
1152        }
1153
1154        StringBuffer JavaDoc classpath = new StringBuffer JavaDoc();
1155
1156        // Assemble the class path information from our class loader chain
1157
ClassLoader JavaDoc loader = getClassLoader();
1158        int layers = 0;
1159        int n = 0;
1160        while (loader != null) {
1161            if (!(loader instanceof URLClassLoader JavaDoc)) {
1162                String JavaDoc cp=getClasspath( loader );
1163                if( cp==null ) {
1164                    log.info( "Unknown loader " + loader + " " + loader.getClass());
1165                    break;
1166                } else {
1167                    if (n > 0)
1168                        classpath.append(File.pathSeparator);
1169                    classpath.append(cp);
1170                    n++;
1171                }
1172                break;
1173                //continue;
1174
}
1175            URL JavaDoc repositories[] =
1176                ((URLClassLoader JavaDoc) loader).getURLs();
1177            for (int i = 0; i < repositories.length; i++) {
1178                String JavaDoc repository = repositories[i].toString();
1179                if (repository.startsWith("file://"))
1180                    repository = repository.substring(7);
1181                else if (repository.startsWith("file:"))
1182                    repository = repository.substring(5);
1183                else if (repository.startsWith("jndi:"))
1184                    repository =
1185                        servletContext.getRealPath(repository.substring(5));
1186                else
1187                    continue;
1188                if (repository == null)
1189                    continue;
1190                if (n > 0)
1191                    classpath.append(File.pathSeparator);
1192                classpath.append(repository);
1193                n++;
1194            }
1195            loader = loader.getParent();
1196            layers++;
1197        }
1198
1199        this.classpath=classpath.toString();
1200
1201        // Store the assembled class path as a servlet context attribute
1202
servletContext.setAttribute(Globals.CLASS_PATH_ATTR,
1203                                    classpath.toString());
1204
1205    }
1206
1207    // try to extract the classpath from a loader that is not URLClassLoader
1208
private String JavaDoc getClasspath( ClassLoader JavaDoc loader ) {
1209        try {
1210            Method JavaDoc m=loader.getClass().getMethod("getClasspath", new Class JavaDoc[] {});
1211            if( log.isTraceEnabled())
1212                log.trace("getClasspath " + m );
1213            if( m==null ) return null;
1214            Object JavaDoc o=m.invoke( loader, new Object JavaDoc[] {} );
1215            if( log.isDebugEnabled() )
1216                log.debug("gotClasspath " + o);
1217            if( o instanceof String JavaDoc )
1218                return (String JavaDoc)o;
1219            return null;
1220        } catch( Exception JavaDoc ex ) {
1221            if (log.isDebugEnabled())
1222                log.debug("getClasspath ", ex);
1223        }
1224        return null;
1225    }
1226
1227    /**
1228     * Copy directory.
1229     */

1230    private boolean copyDir(DirContext JavaDoc srcDir, File JavaDoc destDir) {
1231
1232        try {
1233
1234            // GOOGLE: "enum" is a reserved word in JDK 1.5
1235
NamingEnumeration JavaDoc enum_ = srcDir.list("");
1236            while (enum_.hasMoreElements()) {
1237                NameClassPair JavaDoc ncPair =
1238                    (NameClassPair JavaDoc) enum_.nextElement();
1239                String JavaDoc name = ncPair.getName();
1240                Object JavaDoc object = srcDir.lookup(name);
1241                File JavaDoc currentFile = new File JavaDoc(destDir, name);
1242                if (object instanceof Resource) {
1243                    InputStream JavaDoc is = ((Resource) object).streamContent();
1244                    OutputStream JavaDoc os = new FileOutputStream JavaDoc(currentFile);
1245                    if (!copy(is, os))
1246                        return false;
1247                } else if (object instanceof InputStream JavaDoc) {
1248                    OutputStream JavaDoc os = new FileOutputStream JavaDoc(currentFile);
1249                    if (!copy((InputStream JavaDoc) object, os))
1250                        return false;
1251                } else if (object instanceof DirContext JavaDoc) {
1252                    currentFile.mkdir();
1253                    copyDir((DirContext JavaDoc) object, currentFile);
1254                }
1255            }
1256
1257        } catch (NamingException JavaDoc e) {
1258            return false;
1259        } catch (IOException JavaDoc e) {
1260            return false;
1261        }
1262
1263        return true;
1264
1265    }
1266
1267
1268    /**
1269     * Copy a file to the specified temp directory. This is required only
1270     * because Jasper depends on it.
1271     */

1272    private boolean copy(InputStream JavaDoc is, OutputStream JavaDoc os) {
1273
1274        try {
1275            byte[] buf = new byte[4096];
1276            while (true) {
1277                int len = is.read(buf);
1278                if (len < 0)
1279                    break;
1280                os.write(buf, 0, len);
1281            }
1282            is.close();
1283            os.close();
1284        } catch (IOException JavaDoc e) {
1285            return false;
1286        }
1287
1288        return true;
1289
1290    }
1291
1292
1293    private static org.apache.commons.logging.Log log=
1294        org.apache.commons.logging.LogFactory.getLog( WebappLoader.class );
1295
1296    private ObjectName JavaDoc oname;
1297    private MBeanServer JavaDoc mserver;
1298    private String JavaDoc domain;
1299    private ObjectName JavaDoc controller;
1300
1301    public ObjectName JavaDoc preRegister(MBeanServer JavaDoc server,
1302                                  ObjectName JavaDoc name) throws Exception JavaDoc {
1303        oname=name;
1304        mserver=server;
1305        domain=name.getDomain();
1306
1307        return name;
1308    }
1309
1310    public void postRegister(Boolean JavaDoc registrationDone) {
1311    }
1312
1313    public void preDeregister() throws Exception JavaDoc {
1314    }
1315
1316    public void postDeregister() {
1317    }
1318
1319    public ObjectName JavaDoc getController() {
1320        return controller;
1321    }
1322
1323    public void setController(ObjectName JavaDoc controller) {
1324        this.controller = controller;
1325    }
1326
1327}
1328
Popular Tags