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   &