KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > core > ContainerBase


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

17
18
19 package org.apache.catalina.core;
20
21
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.beans.PropertyChangeSupport JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.Serializable JavaDoc;
26 import java.security.AccessController JavaDoc;
27 import java.security.PrivilegedAction JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Hashtable JavaDoc;
31 import java.util.Iterator JavaDoc;
32
33 import javax.management.MBeanRegistration JavaDoc;
34 import javax.management.MBeanServer JavaDoc;
35 import javax.management.MalformedObjectNameException JavaDoc;
36 import javax.management.ObjectName JavaDoc;
37 import javax.naming.directory.DirContext JavaDoc;
38 import javax.servlet.ServletException JavaDoc;
39
40 import org.apache.catalina.Cluster;
41 import org.apache.catalina.Container;
42 import org.apache.catalina.ContainerEvent;
43 import org.apache.catalina.ContainerListener;
44 import org.apache.catalina.Lifecycle;
45 import org.apache.catalina.LifecycleException;
46 import org.apache.catalina.LifecycleListener;
47 import org.apache.catalina.Loader;
48 import org.apache.catalina.Manager;
49 import org.apache.catalina.Pipeline;
50 import org.apache.catalina.Realm;
51 import org.apache.catalina.Valve;
52 import org.apache.catalina.connector.Request;
53 import org.apache.catalina.connector.Response;
54 import org.apache.catalina.util.LifecycleSupport;
55 import org.apache.catalina.util.StringManager;
56 import org.apache.commons.logging.Log;
57 import org.apache.commons.logging.LogFactory;
58 import org.apache.naming.resources.ProxyDirContext;
59 import org.apache.tomcat.util.modeler.Registry;
60
61
62 /**
63  * Abstract implementation of the <b>Container</b> interface, providing common
64  * functionality required by nearly every implementation. Classes extending
65  * this base class must implement <code>getInfo()</code>, and may implement
66  * a replacement for <code>invoke()</code>.
67  * <p>
68  * All subclasses of this abstract base class will include support for a
69  * Pipeline object that defines the processing to be performed for each request
70  * received by the <code>invoke()</code> method of this class, utilizing the
71  * "Chain of Responsibility" design pattern. A subclass should encapsulate its
72  * own processing functionality as a <code>Valve</code>, and configure this
73  * Valve into the pipeline by calling <code>setBasic()</code>.
74  * <p>
75  * This implementation fires property change events, per the JavaBeans design
76  * pattern, for changes in singleton properties. In addition, it fires the
77  * following <code>ContainerEvent</code> events to listeners who register
78  * themselves with <code>addContainerListener()</code>:
79  * <table border=1>
80  * <tr>
81  * <th>Type</th>
82  * <th>Data</th>
83  * <th>Description</th>
84  * </tr>
85  * <tr>
86  * <td align=center><code>addChild</code></td>
87  * <td align=center><code>Container</code></td>
88  * <td>Child container added to this Container.</td>
89  * </tr>
90  * <tr>
91  * <td align=center><code>addValve</code></td>
92  * <td align=center><code>Valve</code></td>
93  * <td>Valve added to this Container.</td>
94  * </tr>
95  * <tr>
96  * <td align=center><code>removeChild</code></td>
97  * <td align=center><code>Container</code></td>
98  * <td>Child container removed from this Container.</td>
99  * </tr>
100  * <tr>
101  * <td align=center><code>removeValve</code></td>
102  * <td align=center><code>Valve</code></td>
103  * <td>Valve removed from this Container.</td>
104  * </tr>
105  * <tr>
106  * <td align=center><code>start</code></td>
107  * <td align=center><code>null</code></td>
108  * <td>Container was started.</td>
109  * </tr>
110  * <tr>
111  * <td align=center><code>stop</code></td>
112  * <td align=center><code>null</code></td>
113  * <td>Container was stopped.</td>
114  * </tr>
115  * </table>
116  * Subclasses that fire additional events should document them in the
117  * class comments of the implementation class.
118  *
119  * @author Craig R. McClanahan
120  */

121
122 public abstract class ContainerBase
123     implements Container, Lifecycle, Pipeline, MBeanRegistration JavaDoc, Serializable JavaDoc {
124
125     private static org.apache.commons.logging.Log log=
126         org.apache.commons.logging.LogFactory.getLog( ContainerBase.class );
127
128     /**
129      * Perform addChild with the permissions of this class.
130      * addChild can be called with the XML parser on the stack,
131      * this allows the XML parser to have fewer privileges than
132      * Tomcat.
133      */

134     protected class PrivilegedAddChild
135         implements PrivilegedAction JavaDoc {
136
137         private Container child;
138
139         PrivilegedAddChild(Container child) {
140             this.child = child;
141         }
142
143         public Object JavaDoc run() {
144             addChildInternal(child);
145             return null;
146         }
147
148     }
149
150
151     // ----------------------------------------------------- Instance Variables
152

153
154     /**
155      * The child Containers belonging to this Container, keyed by name.
156      */

157     protected HashMap JavaDoc children = new HashMap JavaDoc();
158
159
160     /**
161      * The processor delay for this component.
162      */

163     protected int backgroundProcessorDelay = -1;
164
165
166     /**
167      * The lifecycle event support for this component.
168      */

169     protected LifecycleSupport lifecycle = new LifecycleSupport(this);
170
171
172     /**
173      * The container event listeners for this Container.
174      */

175     protected ArrayList JavaDoc listeners = new ArrayList JavaDoc();
176
177
178     /**
179      * The Loader implementation with which this Container is associated.
180      */

181     protected Loader loader = null;
182
183
184     /**
185      * The Logger implementation with which this Container is associated.
186      */

187     protected Log logger = null;
188
189
190     /**
191      * Associated logger name.
192      */

193     protected String JavaDoc logName = null;
194     
195
196     /**
197      * The Manager implementation with which this Container is associated.
198      */

199     protected Manager manager = null;
200
201
202     /**
203      * The cluster with which this Container is associated.
204      */

205     protected Cluster cluster = null;
206
207     
208     /**
209      * The human-readable name of this Container.
210      */

211     protected String JavaDoc name = null;
212
213
214     /**
215      * The parent Container to which this Container is a child.
216      */

217     protected Container parent = null;
218
219
220     /**
221      * The parent class loader to be configured when we install a Loader.
222      */

223     protected ClassLoader JavaDoc parentClassLoader = null;
224
225
226     /**
227      * The Pipeline object with which this Container is associated.
228      */

229     protected Pipeline pipeline = new StandardPipeline(this);
230
231
232     /**
233      * The Realm with which this Container is associated.
234      */

235     protected Realm realm = null;
236
237
238     /**
239      * The resources DirContext object with which this Container is associated.
240      */

241     protected DirContext JavaDoc resources = null;
242
243
244     /**
245      * The string manager for this package.
246      */

247     protected static StringManager sm =
248         StringManager.getManager(Constants.Package);
249
250
251     /**
252      * Has this component been started?
253      */

254     protected boolean started = false;
255
256     protected boolean initialized=false;
257
258     /**
259      * The property change support for this component.
260      */

261     protected PropertyChangeSupport JavaDoc support = new PropertyChangeSupport JavaDoc(this);
262
263
264     /**
265      * The background thread.
266      */

267     private Thread JavaDoc thread = null;
268
269
270     /**
271      * The background thread completion semaphore.
272      */

273     private boolean threadDone = false;
274
275
276     // ------------------------------------------------------------- Properties
277

278
279     /**
280      * Get the delay between the invocation of the backgroundProcess method on
281      * this container and its children. Child containers will not be invoked
282      * if their delay value is not negative (which would mean they are using
283      * their own thread). Setting this to a positive value will cause
284      * a thread to be spawn. After waiting the specified amount of time,
285      * the thread will invoke the executePeriodic method on this container
286      * and all its children.
287      */

288     public int getBackgroundProcessorDelay() {
289         return backgroundProcessorDelay;
290     }
291
292
293     /**
294      * Set the delay between the invocation of the execute method on this
295      * container and its children.
296      *
297      * @param delay The delay in seconds between the invocation of
298      * backgroundProcess methods
299      */

300     public void setBackgroundProcessorDelay(int delay) {
301         backgroundProcessorDelay = delay;
302     }
303
304
305     /**
306      * Return descriptive information about this Container implementation and
307      * the corresponding version number, in the format
308      * <code>&lt;description&gt;/&lt;version&gt;</code>.
309      */

310     public String JavaDoc getInfo() {
311         return this.getClass().getName();
312     }
313
314
315     /**
316      * Return the Loader with which this Container is associated. If there is
317      * no associated Loader, return the Loader associated with our parent
318      * Container (if any); otherwise, return <code>null</code>.
319      */

320     public Loader getLoader() {
321
322         if (loader != null)
323             return (loader);
324         if (parent != null)
325             return (parent.getLoader());
326         return (null);
327
328     }
329
330
331     /**
332      * Set the Loader with which this Container is associated.
333      *
334      * @param loader The newly associated loader
335      */

336     public synchronized void setLoader(Loader loader) {
337
338         // Change components if necessary
339
Loader oldLoader = this.loader;
340         if (oldLoader == loader)
341             return;
342         this.loader = loader;
343
344         // Stop the old component if necessary
345
if (started && (oldLoader != null) &&
346             (oldLoader instanceof Lifecycle)) {
347             try {
348                 ((Lifecycle) oldLoader).stop();
349             } catch (LifecycleException e) {
350                 log.error("ContainerBase.setLoader: stop: ", e);
351             }
352         }
353
354         // Start the new component if necessary
355
if (loader != null)
356             loader.setContainer(this);
357         if (started && (loader != null) &&
358             (loader instanceof Lifecycle)) {
359             try {
360                 ((Lifecycle) loader).start();
361             } catch (LifecycleException e) {
362                 log.error("ContainerBase.setLoader: start: ", e);
363             }
364         }
365
366         // Report this property change to interested listeners
367
support.firePropertyChange("loader", oldLoader, this.loader);
368
369     }
370
371
372     /**
373      * Return the Logger with which this Container is associated. If there is
374      * no associated Logger, return the Logger associated with our parent
375      * Container (if any); otherwise return <code>null</code>.
376      */

377     public Log getLogger() {
378
379         if (logger != null)
380             return (logger);
381         logger = LogFactory.getLog(logName());
382         return (logger);
383
384     }
385
386
387     /**
388      * Return the Manager with which this Container is associated. If there is
389      * no associated Manager, return the Manager associated with our parent
390      * Container (if any); otherwise return <code>null</code>.
391      */

392     public Manager getManager() {
393
394         if (manager != null)
395             return (manager);
396         if (parent != null)
397             return (parent.getManager());
398         return (null);
399
400     }
401
402
403     /**
404      * Set the Manager with which this Container is associated.
405      *
406      * @param manager The newly associated Manager
407      */

408     public synchronized void setManager(Manager manager) {
409
410         // Change components if necessary
411
Manager oldManager = this.manager;
412         if (oldManager == manager)
413             return;
414         this.manager = manager;
415
416         // Stop the old component if necessary
417
if (started && (oldManager != null) &&
418             (oldManager instanceof Lifecycle)) {
419             try {
420                 ((Lifecycle) oldManager).stop();
421             } catch (LifecycleException e) {
422                 log.error("ContainerBase.setManager: stop: ", e);
423             }
424         }
425
426         // Start the new component if necessary
427
if (manager != null)
428             manager.setContainer(this);
429         if (started && (manager != null) &&
430             (manager instanceof Lifecycle)) {
431             try {
432                 ((Lifecycle) manager).start();
433             } catch (LifecycleException e) {
434                 log.error("ContainerBase.setManager: start: ", e);
435             }
436         }
437
438         // Report this property change to interested listeners
439
support.firePropertyChange("manager", oldManager, this.manager);
440
441     }
442
443
444     /**
445      * Return an object which may be utilized for mapping to this component.
446      */

447     public Object JavaDoc getMappingObject() {
448         return this;
449     }
450
451
452     /**
453      * Return the Cluster with which this Container is associated. If there is
454      * no associated Cluster, return the Cluster associated with our parent
455      * Container (if any); otherwise return <code>null</code>.
456      */

457     public Cluster getCluster() {
458         if (cluster != null)
459             return (cluster);
460
461         if (parent != null)
462             return (parent.getCluster());
463
464         return (null);
465     }
466
467
468     /**
469      * Set the Cluster with which this Container is associated.
470      *
471      * @param cluster The newly associated Cluster
472      */

473     public synchronized void setCluster(Cluster cluster) {
474         // Change components if necessary
475
Cluster oldCluster = this.cluster;
476         if (oldCluster == cluster)
477             return;
478         this.cluster = cluster;
479
480         // Stop the old component if necessary
481
if (started && (oldCluster != null) &&
482             (oldCluster instanceof Lifecycle)) {
483             try {
484                 ((Lifecycle) oldCluster).stop();
485             } catch (LifecycleException e) {
486                 log.error("ContainerBase.setCluster: stop: ", e);
487             }
488         }
489
490         // Start the new component if necessary
491
if (cluster != null)
492             cluster.setContainer(this);
493
494         if (started && (cluster != null) &&
495             (cluster instanceof Lifecycle)) {
496             try {
497                 ((Lifecycle) cluster).start();
498             } catch (LifecycleException e) {
499                 log.error("ContainerBase.setCluster: start: ", e);
500             }
501         }
502
503         // Report this property change to interested listeners
504
support.firePropertyChange("cluster", oldCluster, this.cluster);
505     }
506
507
508     /**
509      * Return a name string (suitable for use by humans) that describes this
510      * Container. Within the set of child containers belonging to a particular
511      * parent, Container names must be unique.
512      */

513     public String JavaDoc getName() {
514
515         return (name);
516
517     }
518
519
520     /**
521      * Set a name string (suitable for use by humans) that describes this
522      * Container. Within the set of child containers belonging to a particular
523      * parent, Container names must be unique.
524      *
525      * @param name New name of this container
526      *
527      * @exception IllegalStateException if this Container has already been
528      * added to the children of a parent Container (after which the name
529      * may not be changed)
530      */

531     public void setName(String JavaDoc name) {
532
533         String JavaDoc oldName = this.name;
534         this.name = name;
535         support.firePropertyChange("name", oldName, this.name);
536     }
537
538
539     /**
540      * Return the Container for which this Container is a child, if there is
541      * one. If there is no defined parent, return <code>null</code>.
542      */

543     public Container getParent() {
544
545         return (parent);
546
547     }
548
549
550     /**
551      * Set the parent Container to which this Container is being added as a
552      * child. This Container may refuse to become attached to the specified
553      * Container by throwing an exception.
554      *
555      * @param container Container to which this Container is being added
556      * as a child
557      *
558      * @exception IllegalArgumentException if this Container refuses to become
559      * attached to the specified Container
560      */

561     public void setParent(Container container) {
562
563         Container oldParent = this.parent;
564         this.parent = container;
565         support.firePropertyChange("parent", oldParent, this.parent);
566
567     }
568
569
570     /**
571      * Return the parent class loader (if any) for this web application.
572      * This call is meaningful only <strong>after</strong> a Loader has
573      * been configured.
574      */

575     public ClassLoader JavaDoc getParentClassLoader() {
576         if (parentClassLoader != null)
577             return (parentClassLoader);
578         if (parent != null) {
579             return (parent.getParentClassLoader());
580         }
581         return (ClassLoader.getSystemClassLoader());
582
583     }
584
585
586     /**
587      * Set the parent class loader (if any) for this web application.
588      * This call is meaningful only <strong>before</strong> a Loader has
589      * been configured, and the specified value (if non-null) should be
590      * passed as an argument to the class loader constructor.
591      *
592      *
593      * @param parent The new parent class loader
594      */

595     public void setParentClassLoader(ClassLoader JavaDoc parent) {
596         ClassLoader JavaDoc oldParentClassLoader = this.parentClassLoader;
597         this.parentClassLoader = parent;
598         support.firePropertyChange("parentClassLoader", oldParentClassLoader,
599                                    this.parentClassLoader);
600
601     }
602
603
604     /**
605      * Return the Pipeline object that manages the Valves associated with
606      * this Container.
607      */

608     public Pipeline getPipeline() {
609
610         return (this.pipeline);
611
612     }
613
614
615     /**
616      * Return the Realm with which this Container is associated. If there is
617      * no associated Realm, return the Realm associated with our parent
618      * Container (if any); otherwise return <code>null</code>.
619      */

620     public Realm getRealm() {
621
622         if (realm != null)
623             return (realm);
624         if (parent != null)
625             return (parent.getRealm());
626         return (null);
627
628     }
629
630
631     /**
632      * Set the Realm with which this Container is associated.
633      *
634      * @param realm The newly associated Realm
635      */

636     public synchronized void setRealm(Realm realm) {
637
638         // Change components if necessary
639
Realm oldRealm = this.realm;
640         if (oldRealm == realm)
641             return;
642         this.realm = realm;
643
644         // Stop the old component if necessary
645
if (started && (oldRealm != null) &&
646             (oldRealm instanceof Lifecycle)) {
647             try {
648                 ((Lifecycle) oldRealm).stop();
649             } catch (LifecycleException e) {
650                 log.error("ContainerBase.setRealm: stop: ", e);
651             }
652         }
653
654         // Start the new component if necessary
655
if (realm != null)
656             realm.setContainer(this);
657         if (started && (realm != null) &&
658             (realm instanceof Lifecycle)) {
659             try {
660                 ((Lifecycle) realm).start();
661             } catch (LifecycleException e) {
662                 log.error("ContainerBase.setRealm: start: ", e);
663             }
664         }
665
666         // Report this property change to interested listeners
667
support.firePropertyChange("realm", oldRealm, this.realm);
668
669     }
670
671
672     /**
673       * Return the resources DirContext object with which this Container is
674       * associated. If there is no associated resources object, return the
675       * resources associated with our parent Container (if any); otherwise
676       * return <code>null</code>.
677      */

678     public DirContext JavaDoc getResources() {
679         if (resources != null)
680             return (resources);
681         if (parent != null)
682             return (parent.getResources());
683         return (null);
684
685     }
686
687
688     /**
689      * Set the resources DirContext object with which this Container is
690      * associated.
691      *
692      * @param resources The newly associated DirContext
693      */

694     public synchronized void setResources(DirContext JavaDoc resources) {
695         // Called from StandardContext.setResources()
696
// <- StandardContext.start()
697
// <- ContainerBase.addChildInternal()
698

699         // Change components if necessary
700
DirContext JavaDoc oldResources = this.resources;
701         if (oldResources == resources)
702             return;
703         Hashtable JavaDoc env = new Hashtable JavaDoc();
704         if (getParent() != null)
705             env.put(ProxyDirContext.HOST, getParent().getName());
706         env.put(ProxyDirContext.CONTEXT, getName());
707         this.resources = new ProxyDirContext(env, resources);
708         // Report this property change to interested listeners
709
support.firePropertyChange("resources", oldResources, this.resources);
710
711     }
712
713
714     // ------------------------------------------------------ Container Methods
715

716
717     /**
718      * Add a new child Container to those associated with this Container,
719      * if supported. Prior to adding this Container to the set of children,
720      * the child's <code>setParent()</code> method must be called, with this
721      * Container as an argument. This method may thrown an
722      * <code>IllegalArgumentException</code> if this Container chooses not
723      * to be attached to the specified Container, in which case it is not added
724      *
725      * @param child New child Container to be added
726      *
727      * @exception IllegalArgumentException if this exception is thrown by
728      * the <code>setParent()</code> method of the child Container
729      * @exception IllegalArgumentException if the new child does not have
730      * a name unique from that of existing children of this Container
731      * @exception IllegalStateException if this Container does not support
732      * child Containers
733      */

734     public void addChild(Container child) {
735         if (System.getSecurityManager() != null) {
736             PrivilegedAction JavaDoc dp =
737                 new PrivilegedAddChild(child);
738             AccessController.doPrivileged(dp);
739         } else {
740             addChildInternal(child);
741         }
742     }
743
744     private void addChildInternal(Container child) {
745
746         if( log.isDebugEnabled() )
747             log.debug("Add child " + child + " " + this);
748         synchronized(children) {
749             if (children.get(child.getName()) != null)
750                 throw new IllegalArgumentException JavaDoc("addChild: Child name '" +
751                                                    child.getName() +
752                                                    "' is not unique");
753             child.setParent(this); // May throw IAE
754
children.put(child.getName(), child);
755
756             // Start child
757
if (started && (child instanceof Lifecycle)) {
758                 boolean success = false;
759                 try {
760                     ((Lifecycle) child).start();
761                     success = true;
762                 } catch (LifecycleException e) {
763                     log.error("ContainerBase.addChild: start: ", e);
764                     throw new IllegalStateException JavaDoc
765                         ("ContainerBase.addChild: start: " + e);
766                 } finally {
767                     if (!success) {
768                         children.remove(child.getName());
769                     }
770                 }
771             }
772
773             fireContainerEvent(ADD_CHILD_EVENT, child);
774         }
775
776     }
777
778
779     /**
780      * Add a container event listener to this component.
781      *
782      * @param listener The listener to add
783      */

784     public void addContainerListener(ContainerListener listener) {
785
786         synchronized (listeners) {
787             listeners.add(listener);
788         }
789
790     }
791
792
793     /**
794      * Add a property change listener to this component.
795      *
796      * @param listener The listener to add
797      */

798     public void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
799
800         support.addPropertyChangeListener(listener);
801
802     }
803
804
805     /**
806      * Return the child Container, associated with this Container, with
807      * the specified name (if any); otherwise, return <code>null</code>
808      *
809      * @param name Name of the child Container to be retrieved
810      */

811     public Container findChild(String JavaDoc name) {
812
813         if (name == null)
814             return (null);
815         synchronized (children) { // Required by post-start changes
816
return ((Container) children.get(name));
817         }
818
819     }
820
821
822     /**
823      * Return the set of children Containers associated with this Container.
824      * If this Container has no children, a zero-length array is returned.
825      */

826     public Container[] findChildren() {
827
828         synchronized (children) {
829             Container results[] = new Container[children.size()];
830             return ((Container[]) children.values().toArray(results));
831         }
832
833     }
834
835
836     /**
837      * Return the set of container listeners associated with this Container.
838      * If this Container has no registered container listeners, a zero-length
839      * array is returned.
840      */

841     public ContainerListener[] findContainerListeners() {
842
843         synchronized (listeners) {
844             ContainerListener[] results =
845                 new ContainerListener[listeners.size()];
846             return ((ContainerListener[]) listeners.toArray(results));
847         }
848
849     }
850
851
852     /**
853      * Process the specified Request, to produce the corresponding Response,
854      * by invoking the first Valve in our pipeline (if any), or the basic
855      * Valve otherwise.
856      *
857      * @param request Request to be processed
858      * @param response Response to be produced
859      *
860      * @exception IllegalStateException if neither a pipeline or a basic
861      * Valve have been configured for this Container
862      * @exception IOException if an input/output error occurred while
863      * processing
864      * @exception ServletException if a ServletException was thrown
865      * while processing this request
866      */

867     public void invoke(Request request, Response response)
868         throws IOException JavaDoc, ServletException JavaDoc {
869
870         pipeline.getFirst().invoke(request, response);
871
872     }
873
874
875     /**
876      * Remove an existing child Container from association with this parent
877      * Container.
878      *
879      * @param child Existing child Container to be removed
880      */

881     public void removeChild(Container child) {
882
883         synchronized(children) {
884             if (children.get(child.getName()) == null)
885                 return;
886             children.remove(child.getName());
887         }
888         
889         if (started && (child instanceof Lifecycle)) {
890             try {
891                 if( child instanceof ContainerBase ) {
892                     if( ((ContainerBase)child).started ) {
893                         ((Lifecycle) child).stop();
894                     }
895                 } else {
896                     ((Lifecycle) child).stop();
897                 }
898             } catch (LifecycleException e) {
899                 log.error("ContainerBase.removeChild: stop: ", e);
900             }
901         }
902         
903         fireContainerEvent(REMOVE_CHILD_EVENT, child);
904         
905         // child.setParent(null);
906

907     }
908
909
910     /**
911      * Remove a container event listener from this component.
912      *
913      * @param listener The listener to remove
914      */

915     public void removeContainerListener(ContainerListener listener) {
916
917         synchronized (listeners) {
918             listeners.remove(listener);
919         }
920
921     }
922
923
924     /**
925      * Remove a property change listener from this component.
926      *
927      * @param listener The listener to remove
928      */

929     public void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
930
931         support.removePropertyChangeListener(listener);
932
933     }
934
935
936     // ------------------------------------------------------ Lifecycle Methods
937

938
939     /**
940      * Add a lifecycle event listener to this component.
941      *
942      * @param listener The listener to add
943      */

944     public void addLifecycleListener(LifecycleListener listener) {
945
946         lifecycle.addLifecycleListener(listener);
947
948     }
949
950
951     /**
952      * Get the lifecycle listeners associated with this lifecycle. If this
953      * Lifecycle has no listeners registered, a zero-length array is returned.
954      */

955     public LifecycleListener[] findLifecycleListeners() {
956
957         return lifecycle.findLifecycleListeners();
958
959     }
960
961
962     /**
963      * Remove a lifecycle event listener from this component.
964      *
965      * @param listener The listener to remove
966      */

967     public void removeLifecycleListener(LifecycleListener listener) {
968
969         lifecycle.removeLifecycleListener(listener);
970
971     }
972
973
974     /**
975      * Prepare for active use of the public methods of this Component.
976      *
977      * @exception LifecycleException if this component detects a fatal error
978      * that prevents it from being started
979      */

980     public synchronized void start() throws LifecycleException {
981
982         // Validate and update our current component state
983
if (started) {
984             if(log.isInfoEnabled())
985                 log.info(sm.getString("containerBase.alreadyStarted", logName()));
986             return;
987         }
988         
989         // Notify our interested LifecycleListeners
990
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
991
992         started = true;
993
994         // Start our subordinate components, if any
995
if ((loader != null) && (loader instanceof Lifecycle))
996             ((Lifecycle) loader).start();
997         logger = null;
998         getLogger();
999         if ((logger != null) && (logger instanceof Lifecycle))
1000            ((Lifecycle) logger).start();
1001        if ((manager != null) && (manager instanceof Lifecycle))
1002            ((Lifecycle) manager).start();
1003        if ((cluster != null) && (cluster instanceof Lifecycle))
1004            ((Lifecycle) cluster).start();
1005        if ((realm != null) && (realm instanceof Lifecycle))
1006            ((Lifecycle) realm).start();
1007        if ((resources != null) && (resources instanceof Lifecycle))
1008            ((Lifecycle) resources).start();
1009
1010        // Start our child containers, if any
1011
Container children[] = findChildren();
1012        for (int i = 0; i < children.length; i++) {
1013            if (children[i] instanceof Lifecycle)
1014                ((Lifecycle) children[i]).start();
1015        }
1016
1017        // Start the Valves in our pipeline (including the basic), if any
1018
if (pipeline instanceof Lifecycle)
1019            ((Lifecycle) pipeline).start();
1020
1021        // Notify our interested LifecycleListeners
1022
lifecycle.fireLifecycleEvent(START_EVENT, null);
1023
1024        // Start our thread
1025
threadStart();
1026
1027        // Notify our interested LifecycleListeners
1028
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
1029
1030    }
1031
1032
1033    /**
1034     * Gracefully shut down active use of the public methods of this Component.
1035     *
1036     * @exception LifecycleException if this component detects a fatal error
1037     * that needs to be reported
1038     */

1039    public synchronized void stop() throws LifecycleException {
1040
1041        // Validate and update our current component state
1042
if (!started) {
1043            if(log.isInfoEnabled())
1044                log.info(sm.getString("containerBase.notStarted", logName()));
1045            return;
1046        }
1047
1048        // Notify our interested LifecycleListeners
1049
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
1050
1051        // Stop our thread
1052
threadStop();
1053
1054        // Notify our interested LifecycleListeners
1055
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
1056        started = false;
1057
1058        // Stop the Valves in our pipeline (including the basic), if any
1059
if (pipeline instanceof Lifecycle) {
1060            ((Lifecycle) pipeline).stop();
1061        }
1062
1063        // Stop our child containers, if any
1064
Container children[] = findChildren();
1065        for (int i = 0; i < children.length; i++) {
1066            if (children[i] instanceof Lifecycle)
1067                ((Lifecycle) children[i]).stop();
1068        }
1069        // Remove children - so next start can work
1070
children = findChildren();
1071        for (int i = 0; i < children.length; i++) {
1072            removeChild(children[i]);
1073        }
1074
1075        // Stop our subordinate components, if any
1076
if ((resources != null) && (resources instanceof Lifecycle)) {
1077            ((Lifecycle) resources).stop();
1078        }
1079        if ((realm != null) && (realm instanceof Lifecycle)) {
1080            ((Lifecycle) realm).stop();
1081        }
1082        if ((cluster != null) && (cluster instanceof Lifecycle)) {
1083            ((Lifecycle) cluster).stop();
1084        }
1085        if ((manager != null) && (manager instanceof Lifecycle)) {
1086            ((Lifecycle) manager).stop();
1087        }
1088        if ((logger != null) && (logger instanceof Lifecycle)) {
1089            ((Lifecycle) logger).stop();
1090        }
1091        if ((loader != null) && (loader instanceof Lifecycle)) {
1092            ((Lifecycle) loader).stop();
1093        }
1094
1095        // Notify our interested LifecycleListeners
1096
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
1097
1098    }
1099
1100    /** Init method, part of the MBean lifecycle.
1101     * If the container was added via JMX, it'll register itself with the
1102     * parent, using the ObjectName conventions to locate the parent.
1103     *
1104     * If the container was added directly and it doesn't have an ObjectName,
1105     * it'll create a name and register itself with the JMX console. On destroy(),
1106     * the object will unregister.
1107     *
1108     * @throws Exception
1109     */

1110    public void init() throws Exception JavaDoc {
1111
1112        if( this.getParent() == null ) {
1113            // "Life" update
1114
ObjectName JavaDoc parentName=getParentName();
1115
1116            //log.info("Register " + parentName );
1117
if( parentName != null &&
1118                    mserver.isRegistered(parentName))
1119            {
1120                mserver.invoke(parentName, "addChild", new Object JavaDoc[] { this },
1121                        new String JavaDoc[] {"org.apache.catalina.Container"});
1122            }
1123        }
1124        initialized=true;
1125    }
1126    
1127    public ObjectName JavaDoc getParentName() throws MalformedObjectNameException JavaDoc {
1128        return null;
1129    }
1130    
1131    public void destroy() throws Exception JavaDoc {
1132        if( started ) {
1133            stop();
1134        }
1135        initialized=false;
1136
1137        // unregister this component
1138
if ( oname != null ) {
1139            try {
1140                if( controller == oname ) {
1141                    Registry.getRegistry(null, null)
1142                        .unregisterComponent(oname);
1143                    if(log.isDebugEnabled())
1144                        log.debug("unregistering " + oname);
1145                }
1146            } catch( Throwable JavaDoc t ) {
1147                log.error("Error unregistering ", t );
1148            }
1149        }
1150
1151        if (parent != null) {
1152            parent.removeChild(this);
1153        }
1154
1155        // Stop our child containers, if any
1156
Container children[] = findChildren();
1157        for (int i = 0; i < children.length; i++) {
1158            removeChild(children[i]);
1159        }
1160                
1161    }
1162
1163    // ------------------------------------------------------- Pipeline Methods
1164

1165
1166    /**
1167     * Add a new Valve to the end of the pipeline associated with this
1168     * Container. Prior to adding the Valve, the Valve's
1169     * <code>setContainer</code> method must be called, with this Container
1170     * as an argument. The method may throw an
1171     * <code>IllegalArgumentException</code> if this Valve chooses not to
1172     * be associated with this Container, or <code>IllegalStateException</code>
1173     * if it is already associated with a different Container.
1174     *
1175     * @param valve Valve to be added
1176     *
1177     * @exception IllegalArgumentException if this Container refused to
1178     * accept the specified Valve
1179     * @exception IllegalArgumentException if the specifie Valve refuses to be
1180     * associated with this Container
1181     * @exception IllegalStateException if the specified Valve is already
1182     * associated with a different Container
1183     */

1184    public synchronized void addValve(Valve valve) {
1185
1186        pipeline.addValve(valve);
1187        fireContainerEvent(ADD_VALVE_EVENT, valve);
1188    }
1189
1190    public ObjectName JavaDoc[] getValveObjectNames() {
1191        return ((StandardPipeline)pipeline).getValveObjectNames();
1192    }
1193    
1194    /**
1195     * <p>Return the Valve instance that has been distinguished as the basic
1196     * Valve for this Pipeline (if any).
1197     */

1198    public Valve getBasic() {
1199
1200        return (pipeline.getBasic());
1201
1202    }
1203
1204
1205    /**
1206     * Return the first valve in the pipeline.
1207     */

1208    public Valve getFirst() {
1209
1210        return (pipeline.getFirst());
1211
1212    }
1213
1214
1215    /**
1216     * Return the set of Valves in the pipeline associated with this
1217     * Container, including the basic Valve (if any). If there are no
1218     * such Valves, a zero-length array is returned.
1219     */

1220    public Valve[] getValves() {
1221
1222        return (pipeline.getValves());
1223
1224    }
1225
1226
1227    /**
1228     * Remove the specified Valve from the pipeline associated with this
1229     * Container, if it is found; otherwise, do nothing.
1230     *
1231     * @param valve Valve to be removed
1232     */

1233    public synchronized void removeValve(Valve valve) {
1234
1235        pipeline.removeValve(valve);
1236        fireContainerEvent(REMOVE_VALVE_EVENT, valve);
1237    }
1238
1239
1240    /**
1241     * <p>Set the Valve instance that has been distinguished as the basic
1242     * Valve for this Pipeline (if any). Prioer to setting the basic Valve,
1243     * the Valve's <code>setContainer()</code> will be called, if it
1244     * implements <code>Contained</code>, with the owning Container as an
1245     * argument. The method may throw an <code>IllegalArgumentException</code>
1246     * if this Valve chooses not to be associated with this Container, or
1247     * <code>IllegalStateException</code> if it is already associated with
1248     * a different Container.</p>
1249     *
1250     * @param valve Valve to be distinguished as the basic Valve
1251     */

1252    public void setBasic(Valve valve) {
1253
1254        pipeline.setBasic(valve);
1255
1256    }
1257
1258
1259    /**
1260     * Execute a periodic task, such as reloading, etc. This method will be
1261     * invoked inside the classloading context of this container. Unexpected
1262     * throwables will be caught and logged.
1263     */

1264    public void backgroundProcess() {
1265        
1266        if (!started)
1267            return;
1268
1269        if (cluster != null) {
1270            try {
1271                cluster.backgroundProcess();
1272            } catch (Exception JavaDoc e) {
1273                log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e);
1274            }
1275        }
1276        if (loader != null) {
1277            try {
1278                loader.backgroundProcess();
1279            } catch (Exception JavaDoc e) {
1280                log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e);
1281            }
1282        }
1283        if (manager != null) {
1284            try {
1285                manager.backgroundProcess();
1286            } catch (Exception JavaDoc e) {
1287                log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e);
1288            }
1289        }
1290        if (realm != null) {
1291            try {
1292                realm.backgroundProcess();
1293            } catch (Exception JavaDoc e) {
1294                log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);
1295            }
1296        }
1297        Valve current = pipeline.getFirst();
1298        while (current != null) {
1299            try {
1300                current.backgroundProcess();
1301            } catch (Exception JavaDoc e) {
1302                log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);
1303            }
1304            current = current.getNext();
1305        }
1306        lifecycle.fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
1307    }
1308
1309
1310    // ------------------------------------------------------ Protected Methods
1311

1312
1313    /**
1314     * Notify all container event listeners that a particular event has
1315     * occurred for this Container. The default implementation performs
1316     * this notification synchronously using the calling thread.
1317     *
1318     * @param type Event type
1319     * @param data Event data
1320     */

1321    public void fireContainerEvent(String JavaDoc type, Object JavaDoc data) {
1322
1323        if (listeners.size() < 1)
1324            return;
1325        ContainerEvent event = new ContainerEvent(this, type, data);
1326        ContainerListener list[] = new ContainerListener[0];
1327        synchronized (listeners) {
1328            list = (ContainerListener[]) listeners.toArray(list);
1329        }
1330        for (int i = 0; i < list.length; i++)
1331            ((ContainerListener) list[i]).containerEvent(event);
1332
1333    }
1334
1335
1336    /**
1337     * Return the abbreviated name of this container for logging messsages
1338     */

1339    protected String JavaDoc logName() {
1340
1341        if (logName != null) {
1342            return logName;
1343        }
1344        String JavaDoc loggerName = null;
1345        Container current = this;
1346        while (current != null) {
1347            String JavaDoc name = current.getName();
1348            if ((name == null) || (name.equals(""))) {
1349                name = "/";
1350            }
1351            loggerName = "[" + name + "]"
1352                + ((loggerName != null) ? ("." + loggerName) : "");
1353            current = current.getParent();
1354        }
1355        logName = ContainerBase.class.getName() + "." + loggerName;
1356        return logName;
1357        
1358    }
1359
1360    
1361    // -------------------- JMX and Registration --------------------
1362
protected String JavaDoc type;
1363    protected String JavaDoc domain;
1364    protected String JavaDoc suffix;
1365    protected ObjectName JavaDoc oname;
1366    protected ObjectName JavaDoc controller;
1367    protected transient MBeanServer JavaDoc mserver;
1368
1369    public ObjectName JavaDoc getJmxName() {
1370        return oname;
1371    }
1372    
1373    public String JavaDoc getObjectName() {
1374        if (oname != null) {
1375            return oname.toString();
1376        } else return null;
1377    }
1378
1379    public String JavaDoc getDomain() {
1380        if( domain==null ) {
1381            Container parent=this;
1382            while( parent != null &&
1383                    !( parent instanceof StandardEngine) ) {
1384                parent=parent.getParent();
1385            }
1386            if( parent instanceof StandardEngine ) {
1387                domain=((StandardEngine)parent).getDomain();
1388            }
1389        }
1390        return domain;
1391    }
1392
1393    public void setDomain(String JavaDoc domain) {
1394        this.domain=domain;
1395    }
1396    
1397    public String JavaDoc getType() {
1398        return type;
1399    }
1400
1401    protected String JavaDoc getJSR77Suffix() {
1402        return suffix;
1403    }
1404
1405    public ObjectName JavaDoc preRegister(MBeanServer JavaDoc server,
1406                                  ObjectName JavaDoc name) throws Exception JavaDoc {
1407        oname=name;
1408        mserver=server;
1409        if (name == null ){
1410            return null;
1411        }
1412
1413        domain=name.getDomain();
1414
1415        type=name.getKeyProperty("type");
1416        if( type==null ) {
1417            type=name.getKeyProperty("j2eeType");
1418        }
1419
1420        String JavaDoc j2eeApp=name.getKeyProperty("J2EEApplication");
1421        String JavaDoc j2eeServer=name.getKeyProperty("J2EEServer");
1422        if( j2eeApp==null ) {
1423            j2eeApp="none";
1424        }
1425        if( j2eeServer==null ) {
1426            j2eeServer="none";
1427        }
1428        suffix=",J2EEApplication=" + j2eeApp + ",J2EEServer=" + j2eeServer;
1429        return name;
1430    }
1431
1432    public void postRegister(Boolean JavaDoc registrationDone) {
1433    }
1434
1435    public void preDeregister() throws Exception JavaDoc {
1436    }
1437
1438    public void postDeregister() {
1439    }
1440
1441    public ObjectName JavaDoc[] getChildren() {
1442        ObjectName JavaDoc result[]=new ObjectName JavaDoc[children.size()];
1443        Iterator JavaDoc it=children.values().iterator();
1444        int i=0;
1445        while( it.hasNext() ) {
1446            Object JavaDoc next=it.next();
1447            if( next instanceof ContainerBase ) {
1448                result[i++]=((ContainerBase)next).getJmxName();
1449            }
1450        }
1451        return result;
1452    }
1453
1454    public ObjectName JavaDoc createObjectName(String JavaDoc domain, ObjectName JavaDoc parent)
1455        throws Exception JavaDoc
1456    {
1457        if( log.isDebugEnabled())
1458            log.debug("Create ObjectName " + domain + " " + parent );
1459        return null;
1460    }
1461
1462    public String JavaDoc getContainerSuffix() {
1463        Container container=this;
1464        Container context=null;
1465        Container host=null;
1466        Container servlet=null;
1467        
1468        StringBuffer JavaDoc suffix=new StringBuffer JavaDoc();
1469        
1470        if( container instanceof StandardHost ) {
1471            host=container;
1472        } else if( container instanceof StandardContext ) {
1473            host=container.getParent();
1474            context=container;
1475        } else if( container instanceof StandardWrapper ) {
1476            context=container.getParent();
1477            host=context.getParent();
1478            servlet=container;
1479        }
1480        if( context!=null ) {
1481            String JavaDoc path=((StandardContext)context).getPath();
1482            suffix.append(",path=").append((path.equals("")) ? "/" : path);
1483        }
1484        if( host!=null ) suffix.append(",host=").append( host.getName() );
1485        if( servlet != null ) {
1486            String JavaDoc name=container.getName();
1487            suffix.append(",servlet=");
1488            suffix.append((name=="") ? "/" : name);
1489        }
1490        return suffix.toString();
1491    }
1492
1493
1494    /**
1495     * Start the background thread that will periodically check for
1496     * session timeouts.
1497     */

1498    protected void threadStart() {
1499
1500        if (thread != null)
1501            return;
1502        if (backgroundProcessorDelay <= 0)
1503            return;
1504
1505        threadDone = false;
1506        String JavaDoc threadName = "ContainerBackgroundProcessor[" + toString() + "]";
1507        thread = new Thread JavaDoc(new ContainerBackgroundProcessor(), threadName);
1508        thread.setDaemon(true);
1509        thread.start();
1510
1511    }
1512
1513
1514    /**
1515     * Stop the background thread that is periodically checking for
1516     * session timeouts.
1517     */

1518    protected void threadStop() {
1519
1520        if (thread == null)
1521            return;
1522
1523        threadDone = true;
1524        thread.interrupt();
1525        try {
1526            thread.join();
1527        } catch (InterruptedException JavaDoc e) {
1528            ;
1529        }
1530
1531        thread = null;
1532
1533    }
1534
1535
1536    // -------------------------------------- ContainerExecuteDelay Inner Class
1537

1538
1539    /**
1540     * Private thread class to invoke the backgroundProcess method
1541     * of this container and its children after a fixed delay.
1542     */

1543    protected class ContainerBackgroundProcessor implements Runnable JavaDoc {
1544
1545        public void run() {
1546            while (!threadDone) {
1547                try {
1548                    Thread.sleep(backgroundProcessorDelay * 1000L);
1549                } catch (InterruptedException JavaDoc e) {
1550                    ;
1551                }
1552                if (!threadDone) {
1553                    Container parent = (Container) getMappingObject();
1554                    ClassLoader JavaDoc cl =
1555                        Thread.currentThread().getContextClassLoader();
1556                    if (parent.getLoader() != null) {
1557                        cl = parent.getLoader().getClassLoader();
1558                    }
1559                    processChildren(parent, cl);
1560                }
1561            }
1562        }
1563
1564        protected void processChildren(Container container, ClassLoader JavaDoc cl) {
1565            try {
1566                if (container.getLoader() != null) {
1567                    Thread.currentThread().setContextClassLoader
1568                        (container.getLoader().getClassLoader());
1569                }
1570                container.backgroundProcess();
1571            } catch (Throwable JavaDoc t) {
1572                log.error("Exception invoking periodic operation: ", t);
1573            } finally {
1574                Thread.currentThread().setContextClassLoader(cl);
1575            }
1576            Container[] children = container.findChildren();
1577            for (int i = 0; i < children.length; i++) {
1578                if (children[i].getBackgroundProcessorDelay() <= 0) {
1579                    processChildren(children[i], cl);
1580                }
1581            }
1582        }
1583
1584    }
1585
1586
1587}
1588
Popular Tags