Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » core » [javadoc | source]
    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;
   23   import java.beans.PropertyChangeSupport;
   24   import java.io.IOException;
   25   import java.io.Serializable;
   26   import java.security.AccessController;
   27   import java.security.PrivilegedAction;
   28   import java.util.ArrayList;
   29   import java.util.HashMap;
   30   import java.util.Hashtable;
   31   import java.util.Iterator;
   32   
   33   import javax.management.MBeanRegistration;
   34   import javax.management.MBeanServer;
   35   import javax.management.MalformedObjectNameException;
   36   import javax.management.ObjectName;
   37   import javax.naming.directory.DirContext;
   38   import javax.servlet.ServletException;
   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.Globals;
   45   import org.apache.catalina.Lifecycle;
   46   import org.apache.catalina.LifecycleException;
   47   import org.apache.catalina.LifecycleListener;
   48   import org.apache.catalina.Loader;
   49   import org.apache.catalina.Manager;
   50   import org.apache.catalina.Pipeline;
   51   import org.apache.catalina.Realm;
   52   import org.apache.catalina.Valve;
   53   import org.apache.catalina.connector.Request;
   54   import org.apache.catalina.connector.Response;
   55   import org.apache.catalina.util.LifecycleSupport;
   56   import org.apache.catalina.util.StringManager;
   57   import org.apache.juli.logging.Log;
   58   import org.apache.juli.logging.LogFactory;
   59   import org.apache.naming.resources.ProxyDirContext;
   60   import org.apache.tomcat.util.modeler.Registry;
   61   
   62   
   63   /**
   64    * Abstract implementation of the <b>Container</b> interface, providing common
   65    * functionality required by nearly every implementation.  Classes extending
   66    * this base class must implement <code>getInfo()</code>, and may implement
   67    * a replacement for <code>invoke()</code>.
   68    * <p>
   69    * All subclasses of this abstract base class will include support for a
   70    * Pipeline object that defines the processing to be performed for each request
   71    * received by the <code>invoke()</code> method of this class, utilizing the
   72    * "Chain of Responsibility" design pattern.  A subclass should encapsulate its
   73    * own processing functionality as a <code>Valve</code>, and configure this
   74    * Valve into the pipeline by calling <code>setBasic()</code>.
   75    * <p>
   76    * This implementation fires property change events, per the JavaBeans design
   77    * pattern, for changes in singleton properties.  In addition, it fires the
   78    * following <code>ContainerEvent</code> events to listeners who register
   79    * themselves with <code>addContainerListener()</code>:
   80    * <table border=1>
   81    *   <tr>
   82    *     <th>Type</th>
   83    *     <th>Data</th>
   84    *     <th>Description</th>
   85    *   </tr>
   86    *   <tr>
   87    *     <td align=center><code>addChild</code></td>
   88    *     <td align=center><code>Container</code></td>
   89    *     <td>Child container added to this Container.</td>
   90    *   </tr>
   91    *   <tr>
   92    *     <td align=center><code>addValve</code></td>
   93    *     <td align=center><code>Valve</code></td>
   94    *     <td>Valve added to this Container.</td>
   95    *   </tr>
   96    *   <tr>
   97    *     <td align=center><code>removeChild</code></td>
   98    *     <td align=center><code>Container</code></td>
   99    *     <td>Child container removed from this Container.</td>
  100    *   </tr>
  101    *   <tr>
  102    *     <td align=center><code>removeValve</code></td>
  103    *     <td align=center><code>Valve</code></td>
  104    *     <td>Valve removed from this Container.</td>
  105    *   </tr>
  106    *   <tr>
  107    *     <td align=center><code>start</code></td>
  108    *     <td align=center><code>null</code></td>
  109    *     <td>Container was started.</td>
  110    *   </tr>
  111    *   <tr>
  112    *     <td align=center><code>stop</code></td>
  113    *     <td align=center><code>null</code></td>
  114    *     <td>Container was stopped.</td>
  115    *   </tr>
  116    * </table>
  117    * Subclasses that fire additional events should document them in the
  118    * class comments of the implementation class.
  119    *
  120    * @author Craig R. McClanahan
  121    */
  122   
  123   public abstract class ContainerBase
  124       implements Container, Lifecycle, Pipeline, MBeanRegistration, Serializable {
  125   
  126       private static org.apache.juli.logging.Log log=
  127           org.apache.juli.logging.LogFactory.getLog( ContainerBase.class );
  128   
  129       /**
  130        * Perform addChild with the permissions of this class.
  131        * addChild can be called with the XML parser on the stack,
  132        * this allows the XML parser to have fewer privileges than
  133        * Tomcat.
  134        */
  135       protected class PrivilegedAddChild
  136           implements PrivilegedAction {
  137   
  138           private Container child;
  139   
  140           PrivilegedAddChild(Container child) {
  141               this.child = child;
  142           }
  143   
  144           public Object run() {
  145               addChildInternal(child);
  146               return null;
  147           }
  148   
  149       }
  150   
  151   
  152       // ----------------------------------------------------- Instance Variables
  153   
  154   
  155       /**
  156        * The child Containers belonging to this Container, keyed by name.
  157        */
  158       protected HashMap children = new HashMap();
  159   
  160   
  161       /**
  162        * The processor delay for this component.
  163        */
  164       protected int backgroundProcessorDelay = -1;
  165   
  166   
  167       /**
  168        * The lifecycle event support for this component.
  169        */
  170       protected LifecycleSupport lifecycle = new LifecycleSupport(this);
  171   
  172   
  173       /**
  174        * The container event listeners for this Container.
  175        */
  176       protected ArrayList listeners = new ArrayList();
  177   
  178   
  179       /**
  180        * The Loader implementation with which this Container is associated.
  181        */
  182       protected Loader loader = null;
  183   
  184   
  185       /**
  186        * The Logger implementation with which this Container is associated.
  187        */
  188       protected Log logger = null;
  189   
  190   
  191       /**
  192        * Associated logger name.
  193        */
  194       protected String logName = null;
  195       
  196   
  197       /**
  198        * The Manager implementation with which this Container is associated.
  199        */
  200       protected Manager manager = null;
  201   
  202   
  203       /**
  204        * The cluster with which this Container is associated.
  205        */
  206       protected Cluster cluster = null;
  207   
  208       
  209       /**
  210        * The human-readable name of this Container.
  211        */
  212       protected String name = null;
  213   
  214   
  215       /**
  216        * The parent Container to which this Container is a child.
  217        */
  218       protected Container parent = null;
  219   
  220   
  221       /**
  222        * The parent class loader to be configured when we install a Loader.
  223        */
  224       protected ClassLoader parentClassLoader = null;
  225   
  226   
  227       /**
  228        * The Pipeline object with which this Container is associated.
  229        */
  230       protected Pipeline pipeline = new StandardPipeline(this);
  231   
  232   
  233       /**
  234        * The Realm with which this Container is associated.
  235        */
  236       protected Realm realm = null;
  237   
  238   
  239       /**
  240        * The resources DirContext object with which this Container is associated.
  241        */
  242       protected DirContext resources = null;
  243   
  244   
  245       /**
  246        * The string manager for this package.
  247        */
  248       protected static StringManager sm =
  249           StringManager.getManager(Constants.Package);
  250   
  251   
  252       /**
  253        * Has this component been started?
  254        */
  255       protected boolean started = false;
  256   
  257       protected boolean initialized=false;
  258   
  259       /**
  260        * Will children be started automatically when they are added.
  261        */
  262       protected boolean startChildren = true;
  263   
  264       /**
  265        * The property change support for this component.
  266        */
  267       protected PropertyChangeSupport support = new PropertyChangeSupport(this);
  268   
  269   
  270       /**
  271        * The background thread.
  272        */
  273       private Thread thread = null;
  274   
  275   
  276       /**
  277        * The background thread completion semaphore.
  278        */
  279       private boolean threadDone = false;
  280   
  281   
  282       // ------------------------------------------------------------- Properties
  283   
  284   
  285       /**
  286        * Get the delay between the invocation of the backgroundProcess method on
  287        * this container and its children. Child containers will not be invoked
  288        * if their delay value is not negative (which would mean they are using 
  289        * their own thread). Setting this to a positive value will cause 
  290        * a thread to be spawn. After waiting the specified amount of time, 
  291        * the thread will invoke the executePeriodic method on this container 
  292        * and all its children.
  293        */
  294       public int getBackgroundProcessorDelay() {
  295           return backgroundProcessorDelay;
  296       }
  297   
  298   
  299       /**
  300        * Set the delay between the invocation of the execute method on this
  301        * container and its children.
  302        * 
  303        * @param delay The delay in seconds between the invocation of 
  304        *              backgroundProcess methods
  305        */
  306       public void setBackgroundProcessorDelay(int delay) {
  307           backgroundProcessorDelay = delay;
  308       }
  309   
  310   
  311       /**
  312        * Return descriptive information about this Container implementation and
  313        * the corresponding version number, in the format
  314        * <code>&lt;description&gt;/&lt;version&gt;</code>.
  315        */
  316       public String getInfo() {
  317           return this.getClass().getName();
  318       }
  319   
  320   
  321       /**
  322        * Return the Loader with which this Container is associated.  If there is
  323        * no associated Loader, return the Loader associated with our parent
  324        * Container (if any); otherwise, return <code>null</code>.
  325        */
  326       public Loader getLoader() {
  327   
  328           if (loader != null)
  329               return (loader);
  330           if (parent != null)
  331               return (parent.getLoader());
  332           return (null);
  333   
  334       }
  335   
  336   
  337       /**
  338        * Set the Loader with which this Container is associated.
  339        *
  340        * @param loader The newly associated loader
  341        */
  342       public synchronized void setLoader(Loader loader) {
  343   
  344           // Change components if necessary
  345           Loader oldLoader = this.loader;
  346           if (oldLoader == loader)
  347               return;
  348           this.loader = loader;
  349   
  350           // Stop the old component if necessary
  351           if (started && (oldLoader != null) &&
  352               (oldLoader instanceof Lifecycle)) {
  353               try {
  354                   ((Lifecycle) oldLoader).stop();
  355               } catch (LifecycleException e) {
  356                   log.error("ContainerBase.setLoader: stop: ", e);
  357               }
  358           }
  359   
  360           // Start the new component if necessary
  361           if (loader != null)
  362               loader.setContainer(this);
  363           if (started && (loader != null) &&
  364               (loader instanceof Lifecycle)) {
  365               try {
  366                   ((Lifecycle) loader).start();
  367               } catch (LifecycleException e) {
  368                   log.error("ContainerBase.setLoader: start: ", e);
  369               }
  370           }
  371   
  372           // Report this property change to interested listeners
  373           support.firePropertyChange("loader", oldLoader, this.loader);
  374   
  375       }
  376   
  377   
  378       /**
  379        * Return the Logger with which this Container is associated.  If there is
  380        * no associated Logger, return the Logger associated with our parent
  381        * Container (if any); otherwise return <code>null</code>.
  382        */
  383       public Log getLogger() {
  384   
  385           if (logger != null)
  386               return (logger);
  387           logger = LogFactory.getLog(logName());
  388           return (logger);
  389   
  390       }
  391   
  392   
  393       /**
  394        * Return the Manager with which this Container is associated.  If there is
  395        * no associated Manager, return the Manager associated with our parent
  396        * Container (if any); otherwise return <code>null</code>.
  397        */
  398       public Manager getManager() {
  399   
  400           if (manager != null)
  401               return (manager);
  402           if (parent != null)
  403               return (parent.getManager());
  404           return (null);
  405   
  406       }
  407   
  408   
  409       /**
  410        * Set the Manager with which this Container is associated.
  411        *
  412        * @param manager The newly associated Manager
  413        */
  414       public synchronized void setManager(Manager manager) {
  415   
  416           // Change components if necessary
  417           Manager oldManager = this.manager;
  418           if (oldManager == manager)
  419               return;
  420           this.manager = manager;
  421   
  422           // Stop the old component if necessary
  423           if (started && (oldManager != null) &&
  424               (oldManager instanceof Lifecycle)) {
  425               try {
  426                   ((Lifecycle) oldManager).stop();
  427               } catch (LifecycleException e) {
  428                   log.error("ContainerBase.setManager: stop: ", e);
  429               }
  430           }
  431   
  432           // Start the new component if necessary
  433           if (manager != null)
  434               manager.setContainer(this);
  435           if (started && (manager != null) &&
  436               (manager instanceof Lifecycle)) {
  437               try {
  438                   ((Lifecycle) manager).start();
  439               } catch (LifecycleException e) {
  440                   log.error("ContainerBase.setManager: start: ", e);
  441               }
  442           }
  443   
  444           // Report this property change to interested listeners
  445           support.firePropertyChange("manager", oldManager, this.manager);
  446   
  447       }
  448   
  449   
  450       /**
  451        * Return an object which may be utilized for mapping to this component.
  452        */
  453       public Object getMappingObject() {
  454           return this;
  455       }
  456   
  457   
  458       /**
  459        * Return the Cluster with which this Container is associated.  If there is
  460        * no associated Cluster, return the Cluster associated with our parent
  461        * Container (if any); otherwise return <code>null</code>.
  462        */
  463       public Cluster getCluster() {
  464           if (cluster != null)
  465               return (cluster);
  466   
  467           if (parent != null)
  468               return (parent.getCluster());
  469   
  470           return (null);
  471       }
  472   
  473   
  474       /**
  475        * Set the Cluster with which this Container is associated.
  476        *
  477        * @param cluster The newly associated Cluster
  478        */
  479       public synchronized void setCluster(Cluster cluster) {
  480           // Change components if necessary
  481           Cluster oldCluster = this.cluster;
  482           if (oldCluster == cluster)
  483               return;
  484           this.cluster = cluster;
  485   
  486           // Stop the old component if necessary
  487           if (started && (oldCluster != null) &&
  488               (oldCluster instanceof Lifecycle)) {
  489               try {
  490                   ((Lifecycle) oldCluster).stop();
  491               } catch (LifecycleException e) {
  492                   log.error("ContainerBase.setCluster: stop: ", e);
  493               }
  494           }
  495   
  496           // Start the new component if necessary
  497           if (cluster != null)
  498               cluster.setContainer(this);
  499   
  500           if (started && (cluster != null) &&
  501               (cluster instanceof Lifecycle)) {
  502               try {
  503                   ((Lifecycle) cluster).start();
  504               } catch (LifecycleException e) {
  505                   log.error("ContainerBase.setCluster: start: ", e);
  506               }
  507           }
  508   
  509           // Report this property change to interested listeners
  510           support.firePropertyChange("cluster", oldCluster, this.cluster);
  511       }
  512   
  513   
  514       /**
  515        * Return a name string (suitable for use by humans) that describes this
  516        * Container.  Within the set of child containers belonging to a particular
  517        * parent, Container names must be unique.
  518        */
  519       public String getName() {
  520   
  521           return (name);
  522   
  523       }
  524   
  525   
  526       /**
  527        * Set a name string (suitable for use by humans) that describes this
  528        * Container.  Within the set of child containers belonging to a particular
  529        * parent, Container names must be unique.
  530        *
  531        * @param name New name of this container
  532        *
  533        * @exception IllegalStateException if this Container has already been
  534        *  added to the children of a parent Container (after which the name
  535        *  may not be changed)
  536        */
  537       public void setName(String name) {
  538   
  539           String oldName = this.name;
  540           this.name = name;
  541           support.firePropertyChange("name", oldName, this.name);
  542       }
  543   
  544   
  545       /**
  546        * Return if children of this container will be started automatically when
  547        * they are added to this container.
  548        */
  549       public boolean getStartChildren() {
  550   
  551           return (startChildren);
  552   
  553       }
  554   
  555   
  556       /**
  557        * Set if children of this container will be started automatically when
  558        * they are added to this container.
  559        *
  560        * @param startChildren New value of the startChildren flag
  561        */
  562       public void setStartChildren(boolean startChildren) {
  563   
  564           boolean oldStartChildren = this.startChildren;
  565           this.startChildren = startChildren;
  566           support.firePropertyChange("startChildren", oldStartChildren, this.startChildren);
  567       }
  568   
  569   
  570       /**
  571        * Return the Container for which this Container is a child, if there is
  572        * one.  If there is no defined parent, return <code>null</code>.
  573        */
  574       public Container getParent() {
  575   
  576           return (parent);
  577   
  578       }
  579   
  580   
  581       /**
  582        * Set the parent Container to which this Container is being added as a
  583        * child.  This Container may refuse to become attached to the specified
  584        * Container by throwing an exception.
  585        *
  586        * @param container Container to which this Container is being added
  587        *  as a child
  588        *
  589        * @exception IllegalArgumentException if this Container refuses to become
  590        *  attached to the specified Container
  591        */
  592       public void setParent(Container container) {
  593   
  594           Container oldParent = this.parent;
  595           this.parent = container;
  596           support.firePropertyChange("parent", oldParent, this.parent);
  597   
  598       }
  599   
  600   
  601       /**
  602        * Return the parent class loader (if any) for this web application.
  603        * This call is meaningful only <strong>after</strong> a Loader has
  604        * been configured.
  605        */
  606       public ClassLoader getParentClassLoader() {
  607           if (parentClassLoader != null)
  608               return (parentClassLoader);
  609           if (parent != null) {
  610               return (parent.getParentClassLoader());
  611           }
  612           return (ClassLoader.getSystemClassLoader());
  613   
  614       }
  615   
  616   
  617       /**
  618        * Set the parent class loader (if any) for this web application.
  619        * This call is meaningful only <strong>before</strong> a Loader has
  620        * been configured, and the specified value (if non-null) should be
  621        * passed as an argument to the class loader constructor.
  622        *
  623        *
  624        * @param parent The new parent class loader
  625        */
  626       public void setParentClassLoader(ClassLoader parent) {
  627           ClassLoader oldParentClassLoader = this.parentClassLoader;
  628           this.parentClassLoader = parent;
  629           support.firePropertyChange("parentClassLoader", oldParentClassLoader,
  630                                      this.parentClassLoader);
  631   
  632       }
  633   
  634   
  635       /**
  636        * Return the Pipeline object that manages the Valves associated with
  637        * this Container.
  638        */
  639       public Pipeline getPipeline() {
  640   
  641           return (this.pipeline);
  642   
  643       }
  644   
  645   
  646       /**
  647        * Return the Realm with which this Container is associated.  If there is
  648        * no associated Realm, return the Realm associated with our parent
  649        * Container (if any); otherwise return <code>null</code>.
  650        */
  651       public Realm getRealm() {
  652   
  653           if (realm != null)
  654               return (realm);
  655           if (parent != null)
  656               return (parent.getRealm());
  657           return (null);
  658   
  659       }
  660   
  661   
  662       /**
  663        * Set the Realm with which this Container is associated.
  664        *
  665        * @param realm The newly associated Realm
  666        */
  667       public synchronized void setRealm(Realm realm) {
  668   
  669           // Change components if necessary
  670           Realm oldRealm = this.realm;
  671           if (oldRealm == realm)
  672               return;
  673           this.realm = realm;
  674   
  675           // Stop the old component if necessary
  676           if (started && (oldRealm != null) &&
  677               (oldRealm instanceof Lifecycle)) {
  678               try {
  679                   ((Lifecycle) oldRealm).stop();
  680               } catch (LifecycleException e) {
  681                   log.error("ContainerBase.setRealm: stop: ", e);
  682               }
  683           }
  684   
  685           // Start the new component if necessary
  686           if (realm != null)
  687               realm.setContainer(this);
  688           if (started && (realm != null) &&
  689               (realm instanceof Lifecycle)) {
  690               try {
  691                   ((Lifecycle) realm).start();
  692               } catch (LifecycleException e) {
  693                   log.error("ContainerBase.setRealm: start: ", e);
  694               }
  695           }
  696   
  697           // Report this property change to interested listeners
  698           support.firePropertyChange("realm", oldRealm, this.realm);
  699   
  700       }
  701   
  702   
  703       /**
  704         * Return the resources DirContext object with which this Container is
  705         * associated.  If there is no associated resources object, return the
  706         * resources associated with our parent Container (if any); otherwise
  707         * return <code>null</code>.
  708        */
  709       public DirContext getResources() {
  710           if (resources != null)
  711               return (resources);
  712           if (parent != null)
  713               return (parent.getResources());
  714           return (null);
  715   
  716       }
  717   
  718   
  719       /**
  720        * Set the resources DirContext object with which this Container is
  721        * associated.
  722        *
  723        * @param resources The newly associated DirContext
  724        */
  725       public synchronized void setResources(DirContext resources) {
  726           // Called from StandardContext.setResources()
  727           //              <- StandardContext.start() 
  728           //              <- ContainerBase.addChildInternal() 
  729   
  730           // Change components if necessary
  731           DirContext oldResources = this.resources;
  732           if (oldResources == resources)
  733               return;
  734           Hashtable env = new Hashtable();
  735           if (getParent() != null)
  736               env.put(ProxyDirContext.HOST, getParent().getName());
  737           env.put(ProxyDirContext.CONTEXT, getName());
  738           this.resources = new ProxyDirContext(env, resources);
  739           // Report this property change to interested listeners
  740           support.firePropertyChange("resources", oldResources, this.resources);
  741   
  742       }
  743   
  744   
  745       // ------------------------------------------------------ Container Methods
  746   
  747   
  748       /**
  749        * Add a new child Container to those associated with this Container,
  750        * if supported.  Prior to adding this Container to the set of children,
  751        * the child's <code>setParent()</code> method must be called, with this
  752        * Container as an argument.  This method may thrown an
  753        * <code>IllegalArgumentException</code> if this Container chooses not
  754        * to be attached to the specified Container, in which case it is not added
  755        *
  756        * @param child New child Container to be added
  757        *
  758        * @exception IllegalArgumentException if this exception is thrown by
  759        *  the <code>setParent()</code> method of the child Container
  760        * @exception IllegalArgumentException if the new child does not have
  761        *  a name unique from that of existing children of this Container
  762        * @exception IllegalStateException if this Container does not support
  763        *  child Containers
  764        */
  765       public void addChild(Container child) {
  766           if (Globals.IS_SECURITY_ENABLED) {
  767               PrivilegedAction dp =
  768                   new PrivilegedAddChild(child);
  769               AccessController.doPrivileged(dp);
  770           } else {
  771               addChildInternal(child);
  772           }
  773       }
  774   
  775       private void addChildInternal(Container child) {
  776   
  777           if( log.isDebugEnabled() )
  778               log.debug("Add child " + child + " " + this);
  779           synchronized(children) {
  780               if (children.get(child.getName()) != null)
  781                   throw new IllegalArgumentException("addChild:  Child name '" +
  782                                                      child.getName() +
  783                                                      "' is not unique");
  784               child.setParent(this);  // May throw IAE
  785               children.put(child.getName(), child);
  786   
  787               // Start child
  788               if (started && startChildren && (child instanceof Lifecycle)) {
  789                   boolean success = false;
  790                   try {
  791                       ((Lifecycle) child).start();
  792                       success = true;
  793                   } catch (LifecycleException e) {
  794                       log.error("ContainerBase.addChild: start: ", e);
  795                       throw new IllegalStateException
  796                           ("ContainerBase.addChild: start: " + e);
  797                   } finally {
  798                       if (!success) {
  799                           children.remove(child.getName());
  800                       }
  801                   }
  802               }
  803   
  804               fireContainerEvent(ADD_CHILD_EVENT, child);
  805           }
  806   
  807       }
  808   
  809   
  810       /**
  811        * Add a container event listener to this component.
  812        *
  813        * @param listener The listener to add
  814        */
  815       public void addContainerListener(ContainerListener listener) {
  816   
  817           synchronized (listeners) {
  818               listeners.add(listener);
  819           }
  820   
  821       }
  822   
  823   
  824       /**
  825        * Add a property change listener to this component.
  826        *
  827        * @param listener The listener to add
  828        */
  829       public void addPropertyChangeListener(PropertyChangeListener listener) {
  830   
  831           support.addPropertyChangeListener(listener);
  832   
  833       }
  834   
  835   
  836       /**
  837        * Return the child Container, associated with this Container, with
  838        * the specified name (if any); otherwise, return <code>null</code>
  839        *
  840        * @param name Name of the child Container to be retrieved
  841        */
  842       public Container findChild(String name) {
  843   
  844           if (name == null)
  845               return (null);
  846           synchronized (children) {       // Required by post-start changes
  847               return ((Container) children.get(name));
  848           }
  849   
  850       }
  851   
  852   
  853       /**
  854        * Return the set of children Containers associated with this Container.
  855        * If this Container has no children, a zero-length array is returned.
  856        */
  857       public Container[] findChildren() {
  858   
  859           synchronized (children) {
  860               Container results[] = new Container[children.size()];
  861               return ((Container[]) children.values().toArray(results));
  862           }
  863   
  864       }
  865   
  866   
  867       /**
  868        * Return the set of container listeners associated with this Container.
  869        * If this Container has no registered container listeners, a zero-length
  870        * array is returned.
  871        */
  872       public ContainerListener[] findContainerListeners() {
  873   
  874           synchronized (listeners) {
  875               ContainerListener[] results = 
  876                   new ContainerListener[listeners.size()];
  877               return ((ContainerListener[]) listeners.toArray(results));
  878           }
  879   
  880       }
  881   
  882   
  883       /**
  884        * Process the specified Request, to produce the corresponding Response,
  885        * by invoking the first Valve in our pipeline (if any), or the basic
  886        * Valve otherwise.
  887        *
  888        * @param request Request to be processed
  889        * @param response Response to be produced
  890        *
  891        * @exception IllegalStateException if neither a pipeline or a basic
  892        *  Valve have been configured for this Container
  893        * @exception IOException if an input/output error occurred while
  894        *  processing
  895        * @exception ServletException if a ServletException was thrown
  896        *  while processing this request
  897        */
  898       public void invoke(Request request, Response response)
  899           throws IOException, ServletException {
  900   
  901           pipeline.getFirst().invoke(request, response);
  902   
  903       }
  904   
  905   
  906       /**
  907        * Remove an existing child Container from association with this parent
  908        * Container.
  909        *
  910        * @param child Existing child Container to be removed
  911        */
  912       public void removeChild(Container child) {
  913   
  914           synchronized(children) {
  915               if (children.get(child.getName()) == null)
  916                   return;
  917               children.remove(child.getName());
  918           }
  919           
  920           if (started && (child instanceof Lifecycle)) {
  921               try {
  922                   if( child instanceof ContainerBase ) {
  923                       if( ((ContainerBase)child).started ) {
  924                           ((Lifecycle) child).stop();
  925                       }
  926                   } else {
  927                       ((Lifecycle) child).stop();
  928                   }
  929               } catch (LifecycleException e) {
  930                   log.error("ContainerBase.removeChild: stop: ", e);
  931               }
  932           }
  933           
  934           fireContainerEvent(REMOVE_CHILD_EVENT, child);
  935           
  936           // child.setParent(null);
  937   
  938       }
  939   
  940   
  941       /**
  942        * Remove a container event listener from this component.
  943        *
  944        * @param listener The listener to remove
  945        */
  946       public void removeContainerListener(ContainerListener listener) {
  947   
  948           synchronized (listeners) {
  949               listeners.remove(listener);
  950           }
  951   
  952       }
  953   
  954   
  955       /**
  956        * Remove a property change listener from this component.
  957        *
  958        * @param listener The listener to remove
  959        */
  960       public void removePropertyChangeListener(PropertyChangeListener listener) {
  961   
  962           support.removePropertyChangeListener(listener);
  963   
  964       }
  965   
  966   
  967       // ------------------------------------------------------ Lifecycle Methods
  968   
  969   
  970       /**
  971        * Add a lifecycle event listener to this component.
  972        *
  973        * @param listener The listener to add
  974        */
  975       public void addLifecycleListener(LifecycleListener listener) {
  976   
  977           lifecycle.addLifecycleListener(listener);
  978   
  979       }
  980   
  981   
  982       /**
  983        * Get the lifecycle listeners associated with this lifecycle. If this 
  984        * Lifecycle has no listeners registered, a zero-length array is returned.
  985        */
  986       public LifecycleListener[] findLifecycleListeners() {
  987   
  988           return lifecycle.findLifecycleListeners();
  989   
  990       }
  991   
  992   
  993       /**
  994        * Remove a lifecycle event listener from this component.
  995        *
  996        * @param listener The listener to remove
  997        */
  998       public void removeLifecycleListener(LifecycleListener listener) {
  999   
 1000           lifecycle.removeLifecycleListener(listener);
 1001   
 1002       }
 1003   
 1004   
 1005       /**
 1006        * Prepare for active use of the public methods of this Component.
 1007        *
 1008        * @exception LifecycleException if this component detects a fatal error
 1009        *  that prevents it from being started
 1010        */
 1011       public synchronized void start() throws LifecycleException {
 1012   
 1013           // Validate and update our current component state
 1014           if (started) {
 1015               if(log.isInfoEnabled())
 1016                   log.info(sm.getString("containerBase.alreadyStarted", logName()));
 1017               return;
 1018           }
 1019           
 1020           // Notify our interested LifecycleListeners
 1021           lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
 1022   
 1023           started = true;
 1024   
 1025           // Start our subordinate components, if any
 1026           if ((loader != null) && (loader instanceof Lifecycle))
 1027               ((Lifecycle) loader).start();
 1028           logger = null;
 1029           getLogger();
 1030           if ((logger != null) && (logger instanceof Lifecycle))
 1031               ((Lifecycle) logger).start();
 1032           if ((manager != null) && (manager instanceof Lifecycle))
 1033               ((Lifecycle) manager).start();
 1034           if ((cluster != null) && (cluster instanceof Lifecycle))
 1035               ((Lifecycle) cluster).start();
 1036           if ((realm != null) && (realm instanceof Lifecycle))
 1037               ((Lifecycle) realm).start();
 1038           if ((resources != null) && (resources instanceof Lifecycle))
 1039               ((Lifecycle) resources).start();
 1040   
 1041           // Start our child containers, if any
 1042           Container children[] = findChildren();
 1043           for (int i = 0; i < children.length; i++) {
 1044               if (children[i] instanceof Lifecycle)
 1045                   ((Lifecycle) children[i]).start();
 1046           }
 1047   
 1048           // Start the Valves in our pipeline (including the basic), if any
 1049           if (pipeline instanceof Lifecycle)
 1050               ((Lifecycle) pipeline).start();
 1051   
 1052           // Notify our interested LifecycleListeners
 1053           lifecycle.fireLifecycleEvent(START_EVENT, null);
 1054   
 1055           // Start our thread
 1056           threadStart();
 1057   
 1058           // Notify our interested LifecycleListeners
 1059           lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
 1060   
 1061       }
 1062   
 1063   
 1064       /**
 1065        * Gracefully shut down active use of the public methods of this Component.
 1066        *
 1067        * @exception LifecycleException if this component detects a fatal error
 1068        *  that needs to be reported
 1069        */
 1070       public synchronized void stop() throws LifecycleException {
 1071   
 1072           // Validate and update our current component state
 1073           if (!started) {
 1074               if(log.isInfoEnabled())
 1075                   log.info(sm.getString("containerBase.notStarted", logName()));
 1076               return;
 1077           }
 1078   
 1079           // Notify our interested LifecycleListeners
 1080           lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
 1081   
 1082           // Stop our thread
 1083           threadStop();
 1084   
 1085           // Notify our interested LifecycleListeners
 1086           lifecycle.fireLifecycleEvent(STOP_EVENT, null);
 1087           started = false;
 1088   
 1089           // Stop the Valves in our pipeline (including the basic), if any
 1090           if (pipeline instanceof Lifecycle) {
 1091               ((Lifecycle) pipeline).stop();
 1092           }
 1093   
 1094           // Stop our child containers, if any
 1095           Container children[] = findChildren();
 1096           for (int i = 0; i < children.length; i++) {
 1097               if (children[i] instanceof Lifecycle)
 1098                   ((Lifecycle) children[i]).stop();
 1099           }
 1100           // Remove children - so next start can work
 1101           children = findChildren();
 1102           for (int i = 0; i < children.length; i++) {
 1103               removeChild(children[i]);
 1104           }
 1105   
 1106           // Stop our subordinate components, if any
 1107           if ((resources != null) && (resources instanceof Lifecycle)) {
 1108               ((Lifecycle) resources).stop();
 1109           }
 1110           if ((realm != null) && (realm instanceof Lifecycle)) {
 1111               ((Lifecycle) realm).stop();
 1112           }
 1113           if ((cluster != null) && (cluster instanceof Lifecycle)) {
 1114               ((Lifecycle) cluster).stop();
 1115           }
 1116           if ((manager != null) && (manager instanceof Lifecycle)) {
 1117               ((Lifecycle) manager).stop();
 1118           }
 1119           if ((logger != null) && (logger instanceof Lifecycle)) {
 1120               ((Lifecycle) logger).stop();
 1121           }
 1122           if ((loader != null) && (loader instanceof Lifecycle)) {
 1123               ((Lifecycle) loader).stop();
 1124           }
 1125   
 1126           // Notify our interested LifecycleListeners
 1127           lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
 1128   
 1129       }
 1130   
 1131       /** Init method, part of the MBean lifecycle.
 1132        *  If the container was added via JMX, it'll register itself with the 
 1133        * parent, using the ObjectName conventions to locate the parent.
 1134        * 
 1135        *  If the container was added directly and it doesn't have an ObjectName,
 1136        * it'll create a name and register itself with the JMX console. On destroy(), 
 1137        * the object will unregister.
 1138        * 
 1139        * @throws Exception
 1140        */ 
 1141       public void init() throws Exception {
 1142   
 1143           if( this.getParent() == null ) {
 1144               // "Life" update
 1145               ObjectName parentName=getParentName();
 1146   
 1147               //log.info("Register " + parentName );
 1148               if( parentName != null && 
 1149                       mserver.isRegistered(parentName)) 
 1150               {
 1151                   mserver.invoke(parentName, "addChild", new Object[] { this },
 1152                           new String[] {"org.apache.catalina.Container"});
 1153               }
 1154           }
 1155           initialized=true;
 1156       }
 1157       
 1158       public ObjectName getParentName() throws MalformedObjectNameException {
 1159           return null;
 1160       }
 1161       
 1162       public void destroy() throws Exception {
 1163           if( started ) {
 1164               stop();
 1165           }
 1166           initialized=false;
 1167   
 1168           // unregister this component
 1169           if ( oname != null ) {
 1170               try {
 1171                   if( controller == oname ) {
 1172                       Registry.getRegistry(null, null)
 1173                           .unregisterComponent(oname);
 1174                       if(log.isDebugEnabled())
 1175                           log.debug("unregistering " + oname);
 1176                   }
 1177               } catch( Throwable t ) {
 1178                   log.error("Error unregistering ", t );
 1179               }
 1180           }
 1181   
 1182           if (parent != null) {
 1183               parent.removeChild(this);
 1184           }
 1185   
 1186           // Stop our child containers, if any
 1187           Container children[] = findChildren();
 1188           for (int i = 0; i < children.length; i++) {
 1189               removeChild(children[i]);
 1190           }
 1191                   
 1192       }
 1193   
 1194       // ------------------------------------------------------- Pipeline Methods
 1195   
 1196   
 1197       /**
 1198        * Add a new Valve to the end of the pipeline associated with this
 1199        * Container.  Prior to adding the Valve, the Valve's
 1200        * <code>setContainer</code> method must be called, with this Container
 1201        * as an argument.  The method may throw an
 1202        * <code>IllegalArgumentException</code> if this Valve chooses not to
 1203        * be associated with this Container, or <code>IllegalStateException</code>
 1204        * if it is already associated with a different Container.
 1205        *
 1206        * @param valve Valve to be added
 1207        *
 1208        * @exception IllegalArgumentException if this Container refused to
 1209        *  accept the specified Valve
 1210        * @exception IllegalArgumentException if the specifie Valve refuses to be
 1211        *  associated with this Container
 1212        * @exception IllegalStateException if the specified Valve is already
 1213        *  associated with a different Container
 1214        */
 1215       public synchronized void addValve(Valve valve) {
 1216   
 1217           pipeline.addValve(valve);
 1218           fireContainerEvent(ADD_VALVE_EVENT, valve);
 1219       }
 1220   
 1221       public ObjectName[] getValveObjectNames() {
 1222           return ((StandardPipeline)pipeline).getValveObjectNames();
 1223       }
 1224       
 1225       /**
 1226        * <p>Return the Valve instance that has been distinguished as the basic
 1227        * Valve for this Pipeline (if any).
 1228        */
 1229       public Valve getBasic() {
 1230   
 1231           return (pipeline.getBasic());
 1232   
 1233       }
 1234   
 1235   
 1236       /**
 1237        * Return the first valve in the pipeline.
 1238        */
 1239       public Valve getFirst() {
 1240   
 1241           return (pipeline.getFirst());
 1242   
 1243       }
 1244   
 1245   
 1246       /**
 1247        * Return the set of Valves in the pipeline associated with this
 1248        * Container, including the basic Valve (if any).  If there are no
 1249        * such Valves, a zero-length array is returned.
 1250        */
 1251       public Valve[] getValves() {
 1252   
 1253           return (pipeline.getValves());
 1254   
 1255       }
 1256   
 1257   
 1258       /**
 1259        * Remove the specified Valve from the pipeline associated with this
 1260        * Container, if it is found; otherwise, do nothing.
 1261        *
 1262        * @param valve Valve to be removed
 1263        */
 1264       public synchronized void removeValve(Valve valve) {
 1265   
 1266           pipeline.removeValve(valve);
 1267           fireContainerEvent(REMOVE_VALVE_EVENT, valve);
 1268       }
 1269   
 1270   
 1271       /**
 1272        * <p>Set the Valve instance that has been distinguished as the basic
 1273        * Valve for this Pipeline (if any).  Prioer to setting the basic Valve,
 1274        * the Valve's <code>setContainer()</code> will be called, if it
 1275        * implements <code>Contained</code>, with the owning Container as an
 1276        * argument.  The method may throw an <code>IllegalArgumentException</code>
 1277        * if this Valve chooses not to be associated with this Container, or
 1278        * <code>IllegalStateException</code> if it is already associated with
 1279        * a different Container.</p>
 1280        *
 1281        * @param valve Valve to be distinguished as the basic Valve
 1282        */
 1283       public void setBasic(Valve valve) {
 1284   
 1285           pipeline.setBasic(valve);
 1286   
 1287       }
 1288   
 1289   
 1290       /**
 1291        * Execute a periodic task, such as reloading, etc. This method will be
 1292        * invoked inside the classloading context of this container. Unexpected
 1293        * throwables will be caught and logged.
 1294        */
 1295       public void backgroundProcess() {
 1296           
 1297           if (!started)
 1298               return;
 1299   
 1300           if (cluster != null) {
 1301               try {
 1302                   cluster.backgroundProcess();
 1303               } catch (Exception e) {
 1304                   log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e);                
 1305               }
 1306           }
 1307           if (loader != null) {
 1308               try {
 1309                   loader.backgroundProcess();
 1310               } catch (Exception e) {
 1311                   log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e);                
 1312               }
 1313           }
 1314           if (manager != null) {
 1315               try {
 1316                   manager.backgroundProcess();
 1317               } catch (Exception e) {
 1318                   log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e);                
 1319               }
 1320           }
 1321           if (realm != null) {
 1322               try {
 1323                   realm.backgroundProcess();
 1324               } catch (Exception e) {
 1325                   log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);                
 1326               }
 1327           }
 1328           Valve current = pipeline.getFirst();
 1329           while (current != null) {
 1330               try {
 1331                   current.backgroundProcess();
 1332               } catch (Exception e) {
 1333                   log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);                
 1334               }
 1335               current = current.getNext();
 1336           }
 1337           lifecycle.fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
 1338       }
 1339   
 1340   
 1341       // ------------------------------------------------------ Protected Methods
 1342   
 1343   
 1344       /**
 1345        * Notify all container event listeners that a particular event has
 1346        * occurred for this Container.  The default implementation performs
 1347        * this notification synchronously using the calling thread.
 1348        *
 1349        * @param type Event type
 1350        * @param data Event data
 1351        */
 1352       public void fireContainerEvent(String type, Object data) {
 1353   
 1354           if (listeners.size() < 1)
 1355               return;
 1356           ContainerEvent event = new ContainerEvent(this, type, data);
 1357           ContainerListener list[] = new ContainerListener[0];
 1358           synchronized (listeners) {
 1359               list = (ContainerListener[]) listeners.toArray(list);
 1360           }
 1361           for (int i = 0; i < list.length; i++)
 1362               ((ContainerListener) list[i]).containerEvent(event);
 1363   
 1364       }
 1365   
 1366   
 1367       /**
 1368        * Return the abbreviated name of this container for logging messsages
 1369        */
 1370       protected String logName() {
 1371   
 1372           if (logName != null) {
 1373               return logName;
 1374           }
 1375           String loggerName = null;
 1376           Container current = this;
 1377           while (current != null) {
 1378               String name = current.getName();
 1379               if ((name == null) || (name.equals(""))) {
 1380                   name = "/";
 1381               }
 1382               loggerName = "[" + name + "]" 
 1383                   + ((loggerName != null) ? ("." + loggerName) : "");
 1384               current = current.getParent();
 1385           }
 1386           logName = ContainerBase.class.getName() + "." + loggerName;
 1387           return logName;
 1388           
 1389       }
 1390   
 1391       
 1392       // -------------------- JMX and Registration  --------------------
 1393       protected String type;
 1394       protected String domain;
 1395       protected String suffix;
 1396       protected ObjectName oname;
 1397       protected ObjectName controller;
 1398       protected transient MBeanServer mserver;
 1399   
 1400       public ObjectName getJmxName() {
 1401           return oname;
 1402       }
 1403       
 1404       public String getObjectName() {
 1405           if (oname != null) {
 1406               return oname.toString();
 1407           } else return null;
 1408       }
 1409   
 1410       public String getDomain() {
 1411           if( domain==null ) {
 1412               Container parent=this;
 1413               while( parent != null &&
 1414                       !( parent instanceof StandardEngine) ) {
 1415                   parent=parent.getParent();
 1416               }
 1417               if( parent instanceof StandardEngine ) {
 1418                   domain=((StandardEngine)parent).getDomain();
 1419               } 
 1420           }
 1421           return domain;
 1422       }
 1423   
 1424       public void setDomain(String domain) {
 1425           this.domain=domain;
 1426       }
 1427       
 1428       public String getType() {
 1429           return type;
 1430       }
 1431   
 1432       protected String getJSR77Suffix() {
 1433           return suffix;
 1434       }
 1435   
 1436       public ObjectName preRegister(MBeanServer server,
 1437                                     ObjectName name) throws Exception {
 1438           oname=name;
 1439           mserver=server;
 1440           if (name == null ){
 1441               return null;
 1442           }
 1443   
 1444           domain=name.getDomain();
 1445   
 1446           type=name.getKeyProperty("type");
 1447           if( type==null ) {
 1448               type=name.getKeyProperty("j2eeType");
 1449           }
 1450   
 1451           String j2eeApp=name.getKeyProperty("J2EEApplication");
 1452           String j2eeServer=name.getKeyProperty("J2EEServer");
 1453           if( j2eeApp==null ) {
 1454               j2eeApp="none";
 1455           }
 1456           if( j2eeServer==null ) {
 1457               j2eeServer="none";
 1458           }
 1459           suffix=",J2EEApplication=" + j2eeApp + ",J2EEServer=" + j2eeServer;
 1460           return name;
 1461       }
 1462   
 1463       public void postRegister(Boolean registrationDone) {
 1464       }
 1465   
 1466       public void preDeregister() throws Exception {
 1467       }
 1468   
 1469       public void postDeregister() {
 1470       }
 1471   
 1472       public ObjectName[] getChildren() {
 1473           ObjectName result[]=new ObjectName[children.size()];
 1474           Iterator it=children.values().iterator();
 1475           int i=0;
 1476           while( it.hasNext() ) {
 1477               Object next=it.next();
 1478               if( next instanceof ContainerBase ) {
 1479                   result[i++]=((ContainerBase)next).getJmxName();
 1480               }
 1481           }
 1482           return result;
 1483       }
 1484   
 1485       public ObjectName createObjectName(String domain, ObjectName parent)
 1486           throws Exception
 1487       {
 1488           if( log.isDebugEnabled())
 1489               log.debug("Create ObjectName " + domain + " " + parent );
 1490           return null;
 1491       }
 1492   
 1493       public String getContainerSuffix() {
 1494           Container container=this;
 1495           Container context=null;
 1496           Container host=null;
 1497           Container servlet=null;
 1498           
 1499           StringBuffer suffix=new StringBuffer();
 1500           
 1501           if( container instanceof StandardHost ) {
 1502               host=container;
 1503           } else if( container instanceof StandardContext ) {
 1504               host=container.getParent();
 1505               context=container;
 1506           } else if( container instanceof StandardWrapper ) {
 1507               context=container.getParent();
 1508               host=context.getParent();
 1509               servlet=container;
 1510           }
 1511           if( context!=null ) {
 1512               String path=((StandardContext)context).getPath();
 1513               suffix.append(",path=").append((path.equals("")) ? "/" : path);
 1514           } 
 1515           if( host!=null ) suffix.append(",host=").append( host.getName() );
 1516           if( servlet != null ) {
 1517               String name=container.getName();
 1518               suffix.append(",servlet=");
 1519               suffix.append((name=="") ? "/" : name);
 1520           }
 1521           return suffix.toString();
 1522       }
 1523   
 1524   
 1525       /**
 1526        * Start the background thread that will periodically check for
 1527        * session timeouts.
 1528        */
 1529       protected void threadStart() {
 1530   
 1531           if (thread != null)
 1532               return;
 1533           if (backgroundProcessorDelay <= 0)
 1534               return;
 1535   
 1536           threadDone = false;
 1537           String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
 1538           thread = new Thread(new ContainerBackgroundProcessor(), threadName);
 1539           thread.setDaemon(true);
 1540           thread.start();
 1541   
 1542       }
 1543   
 1544   
 1545       /**
 1546        * Stop the background thread that is periodically checking for
 1547        * session timeouts.
 1548        */
 1549       protected void threadStop() {
 1550   
 1551           if (thread == null)
 1552               return;
 1553   
 1554           threadDone = true;
 1555           thread.interrupt();
 1556           try {
 1557               thread.join();
 1558           } catch (InterruptedException e) {
 1559               ;
 1560           }
 1561   
 1562           thread = null;
 1563   
 1564       }
 1565   
 1566   
 1567       // -------------------------------------- ContainerExecuteDelay Inner Class
 1568   
 1569   
 1570       /**
 1571        * Private thread class to invoke the backgroundProcess method 
 1572        * of this container and its children after a fixed delay.
 1573        */
 1574       protected class ContainerBackgroundProcessor implements Runnable {
 1575   
 1576           public void run() {
 1577               while (!threadDone) {
 1578                   try {
 1579                       Thread.sleep(backgroundProcessorDelay * 1000L);
 1580                   } catch (InterruptedException e) {
 1581                       ;
 1582                   }
 1583                   if (!threadDone) {
 1584                       Container parent = (Container) getMappingObject();
 1585                       ClassLoader cl = 
 1586                           Thread.currentThread().getContextClassLoader();
 1587                       if (parent.getLoader() != null) {
 1588                           cl = parent.getLoader().getClassLoader();
 1589                       }
 1590                       processChildren(parent, cl);
 1591                   }
 1592               }
 1593           }
 1594   
 1595           protected void processChildren(Container container, ClassLoader cl) {
 1596               try {
 1597                   if (container.getLoader() != null) {
 1598                       Thread.currentThread().setContextClassLoader
 1599                           (container.getLoader().getClassLoader());
 1600                   }
 1601                   container.backgroundProcess();
 1602               } catch (Throwable t) {
 1603                   log.error("Exception invoking periodic operation: ", t);
 1604               } finally {
 1605                   Thread.currentThread().setContextClassLoader(cl);
 1606               }
 1607               Container[] children = container.findChildren();
 1608               for (int i = 0; i < children.length; i++) {
 1609                   if (children[i].getBackgroundProcessorDelay() <= 0) {
 1610                       processChildren(children[i], cl);
 1611                   }
 1612               }
 1613           }
 1614   
 1615       }
 1616   
 1617   
 1618   }

Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » core » [javadoc | source]