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   import java.io.BufferedReader;
   22   import java.io.File;
   23   import java.io.FileInputStream;
   24   import java.io.FileOutputStream;
   25   import java.io.IOException;
   26   import java.io.InputStream;
   27   import java.io.InputStreamReader;
   28   import java.io.ObjectOutputStream;
   29   import java.io.Serializable;
   30   import java.util.ArrayList;
   31   import java.util.HashMap;
   32   import java.util.Hashtable;
   33   import java.util.Iterator;
   34   import java.util.Stack;
   35   import java.util.TreeMap;
   36   
   37   import javax.management.AttributeNotFoundException;
   38   import javax.management.ListenerNotFoundException;
   39   import javax.management.MBeanNotificationInfo;
   40   import javax.management.MBeanRegistrationException;
   41   import javax.management.MBeanServer;
   42   import javax.management.MalformedObjectNameException;
   43   import javax.management.Notification;
   44   import javax.management.NotificationBroadcasterSupport;
   45   import javax.management.NotificationEmitter;
   46   import javax.management.NotificationFilter;
   47   import javax.management.NotificationListener;
   48   import javax.management.ObjectName;
   49   import javax.naming.NamingException;
   50   import javax.naming.directory.DirContext;
   51   import javax.servlet.FilterConfig;
   52   import javax.servlet.ServletContext;
   53   import javax.servlet.ServletContextAttributeListener;
   54   import javax.servlet.ServletContextEvent;
   55   import javax.servlet.ServletContextListener;
   56   import javax.servlet.ServletException;
   57   import javax.servlet.ServletRequestAttributeListener;
   58   import javax.servlet.ServletRequestListener;
   59   import javax.servlet.http.HttpSessionAttributeListener;
   60   import javax.servlet.http.HttpSessionListener;
   61   
   62   import org.apache.AnnotationProcessor;
   63   import org.apache.catalina.Container;
   64   import org.apache.catalina.ContainerListener;
   65   import org.apache.catalina.Context;
   66   import org.apache.catalina.Engine;
   67   import org.apache.catalina.Globals;
   68   import org.apache.catalina.Host;
   69   import org.apache.catalina.InstanceListener;
   70   import org.apache.catalina.Lifecycle;
   71   import org.apache.catalina.LifecycleException;
   72   import org.apache.catalina.LifecycleListener;
   73   import org.apache.catalina.Loader;
   74   import org.apache.catalina.Manager;
   75   import org.apache.catalina.Wrapper;
   76   import org.apache.catalina.deploy.ApplicationParameter;
   77   import org.apache.catalina.deploy.ErrorPage;
   78   import org.apache.catalina.deploy.FilterDef;
   79   import org.apache.catalina.deploy.FilterMap;
   80   import org.apache.catalina.deploy.LoginConfig;
   81   import org.apache.catalina.deploy.MessageDestination;
   82   import org.apache.catalina.deploy.MessageDestinationRef;
   83   import org.apache.catalina.deploy.NamingResources;
   84   import org.apache.catalina.deploy.SecurityCollection;
   85   import org.apache.catalina.deploy.SecurityConstraint;
   86   import org.apache.catalina.loader.WebappLoader;
   87   import org.apache.catalina.session.StandardManager;
   88   import org.apache.catalina.startup.ContextConfig;
   89   import org.apache.catalina.startup.TldConfig;
   90   import org.apache.catalina.util.CharsetMapper;
   91   import org.apache.catalina.util.DefaultAnnotationProcessor;
   92   import org.apache.catalina.util.ExtensionValidator;
   93   import org.apache.catalina.util.RequestUtil;
   94   import org.apache.catalina.util.URLEncoder;
   95   import org.apache.juli.logging.Log;
   96   import org.apache.juli.logging.LogFactory;
   97   import org.apache.naming.ContextBindings;
   98   import org.apache.naming.resources.BaseDirContext;
   99   import org.apache.naming.resources.DirContextURLStreamHandler;
  100   import org.apache.naming.resources.FileDirContext;
  101   import org.apache.naming.resources.ProxyDirContext;
  102   import org.apache.naming.resources.WARDirContext;
  103   import org.apache.tomcat.util.modeler.Registry;
  104   
  105   /**
  106    * Standard implementation of the <b>Context</b> interface.  Each
  107    * child container must be a Wrapper implementation to process the
  108    * requests directed to a particular servlet.
  109    *
  110    * @author Craig R. McClanahan
  111    * @author Remy Maucherat
  112    * @version $Revision: 893564 $ $Date: 2009-12-23 17:31:31 +0100 (Wed, 23 Dec 2009) $
  113    */
  114   
  115   public class StandardContext
  116       extends ContainerBase
  117       implements Context, Serializable, NotificationEmitter
  118   {
  119       private static transient Log log = LogFactory.getLog(StandardContext.class);
  120   
  121   
  122       // ----------------------------------------------------------- Constructors
  123   
  124   
  125       /**
  126        * Create a new StandardContext component with the default basic Valve.
  127        */
  128       public StandardContext() {
  129   
  130           super();
  131           pipeline.setBasic(new StandardContextValve());
  132           broadcaster = new NotificationBroadcasterSupport();
  133   
  134       }
  135   
  136   
  137       // ----------------------------------------------------- Class Variables
  138   
  139   
  140       /**
  141        * The descriptive information string for this implementation.
  142        */
  143       private static final String info =
  144           "org.apache.catalina.core.StandardContext/1.0";
  145   
  146   
  147       /**
  148        * Array containing the safe characters set.
  149        */
  150       protected static URLEncoder urlEncoder;
  151   
  152   
  153       /**
  154        * GMT timezone - all HTTP dates are on GMT
  155        */
  156       static {
  157           urlEncoder = new URLEncoder();
  158           urlEncoder.addSafeCharacter('~');
  159           urlEncoder.addSafeCharacter('-');
  160           urlEncoder.addSafeCharacter('_');
  161           urlEncoder.addSafeCharacter('.');
  162           urlEncoder.addSafeCharacter('*');
  163           urlEncoder.addSafeCharacter('/');
  164       }
  165   
  166   
  167       // ----------------------------------------------------- Instance Variables
  168   
  169   
  170       /**
  171        * The alternate deployment descriptor name.
  172        */
  173       private String altDDName = null;
  174   
  175   
  176       /**
  177        * Annotation processor.
  178        */
  179       private AnnotationProcessor annotationProcessor = null;
  180   
  181   
  182      /**
  183        * Associated host name.
  184        */
  185       private String hostName;
  186   
  187   
  188       /**
  189        * The antiJARLocking flag for this Context.
  190        */
  191       private boolean antiJARLocking = false;
  192   
  193       
  194       /**
  195        * The antiResourceLocking flag for this Context.
  196        */
  197       private boolean antiResourceLocking = false;
  198   
  199       
  200       /**
  201        * The set of application listener class names configured for this
  202        * application, in the order they were encountered in the web.xml file.
  203        */
  204       private String applicationListeners[] = new String[0];
  205       
  206       private final Object applicationListenersLock = new Object();
  207   
  208   
  209       /**
  210        * The set of instantiated application event listener objects</code>.
  211        */
  212       private transient Object applicationEventListenersObjects[] = 
  213           new Object[0];
  214   
  215   
  216       /**
  217        * The set of instantiated application lifecycle listener objects</code>.
  218        */
  219       private transient Object applicationLifecycleListenersObjects[] = 
  220           new Object[0];
  221   
  222   
  223       /**
  224        * The set of application parameters defined for this application.
  225        */
  226       private ApplicationParameter applicationParameters[] =
  227           new ApplicationParameter[0];
  228   
  229       private final Object applicationParametersLock = new Object();
  230       
  231   
  232       /**
  233        * The application available flag for this Context.
  234        */
  235       private boolean available = false;
  236       
  237       /**
  238        * The broadcaster that sends j2ee notifications. 
  239        */
  240       private NotificationBroadcasterSupport broadcaster = null;
  241       
  242       /**
  243        * The Locale to character set mapper for this application.
  244        */
  245       private transient CharsetMapper charsetMapper = null;
  246   
  247   
  248       /**
  249        * The Java class name of the CharsetMapper class to be created.
  250        */
  251       private String charsetMapperClass =
  252         "org.apache.catalina.util.CharsetMapper";
  253   
  254   
  255       /**
  256        * The path to a file to save this Context information.
  257        */
  258       private String configFile = null;
  259   
  260   
  261       /**
  262        * The "correctly configured" flag for this Context.
  263        */
  264       private boolean configured = false;
  265   
  266   
  267       /**
  268        * The security constraints for this web application.
  269        */
  270       private SecurityConstraint constraints[] = new SecurityConstraint[0];
  271       
  272       private final Object constraintsLock = new Object();
  273   
  274   
  275       /**
  276        * The ServletContext implementation associated with this Context.
  277        */
  278       protected transient ApplicationContext context = null;
  279   
  280   
  281       /**
  282        * Compiler classpath to use.
  283        */
  284       private String compilerClasspath = null;
  285   
  286   
  287       /**
  288        * Should we attempt to use cookies for session id communication?
  289        */
  290       private boolean cookies = true;
  291   
  292   
  293       /**
  294        * Should we allow the <code>ServletContext.getContext()</code> method
  295        * to access the context of other web applications in this server?
  296        */
  297       private boolean crossContext = false;
  298   
  299       
  300       /**
  301        * Encoded path.
  302        */
  303       private String encodedPath = null;
  304       
  305   
  306       /**
  307        * The "follow standard delegation model" flag that will be used to
  308        * configure our ClassLoader.
  309        */
  310       private boolean delegate = false;
  311   
  312   
  313       /**
  314        * The display name of this web application.
  315        */
  316       private String displayName = null;
  317   
  318   
  319       /** 
  320        * Override the default context xml location.
  321        */
  322       private String defaultContextXml;
  323   
  324   
  325       /** 
  326        * Override the default web xml location.
  327        */
  328       private String defaultWebXml;
  329   
  330   
  331       /**
  332        * The distributable flag for this web application.
  333        */
  334       private boolean distributable = false;
  335   
  336   
  337       /**
  338        * The document root for this web application.
  339        */
  340       private String docBase = null;
  341   
  342   
  343       /**
  344        * The exception pages for this web application, keyed by fully qualified
  345        * class name of the Java exception.
  346        */
  347       private HashMap exceptionPages = new HashMap();
  348   
  349   
  350       /**
  351        * The set of filter configurations (and associated filter instances) we
  352        * have initialized, keyed by filter name.
  353        */
  354       private HashMap filterConfigs = new HashMap();
  355   
  356   
  357       /**
  358        * The set of filter definitions for this application, keyed by
  359        * filter name.
  360        */
  361       private HashMap filterDefs = new HashMap();
  362   
  363   
  364       /**
  365        * The set of filter mappings for this application, in the order
  366        * they were defined in the deployment descriptor.
  367        */
  368       private FilterMap filterMaps[] = new FilterMap[0];
  369       
  370       private final Object filterMapsLock = new Object();
  371   
  372   
  373       /**
  374        * Ignore annotations.
  375        */
  376       private boolean ignoreAnnotations = false;
  377   
  378   
  379       /**
  380        * The set of classnames of InstanceListeners that will be added
  381        * to each newly created Wrapper by <code>createWrapper()</code>.
  382        */
  383       private String instanceListeners[] = new String[0];
  384   
  385       private final Object instanceListenersLock = new Object();
  386   
  387   
  388       /**
  389        * The login configuration descriptor for this web application.
  390        */
  391       private LoginConfig loginConfig = null;
  392   
  393   
  394       /**
  395        * The mapper associated with this context.
  396        */
  397       private org.apache.tomcat.util.http.mapper.Mapper mapper = 
  398           new org.apache.tomcat.util.http.mapper.Mapper();
  399   
  400   
  401       /**
  402        * The naming context listener for this web application.
  403        */
  404       private transient NamingContextListener namingContextListener = null;
  405   
  406   
  407       /**
  408        * The naming resources for this web application.
  409        */
  410       private NamingResources namingResources = null;
  411   
  412   
  413       /**
  414        * The message destinations for this web application.
  415        */
  416       private HashMap messageDestinations = new HashMap();
  417   
  418   
  419       /**
  420        * The MIME mappings for this web application, keyed by extension.
  421        */
  422       private HashMap mimeMappings = new HashMap();
  423   
  424   
  425        /**
  426         * Special case: error page for status 200.
  427         */
  428        private ErrorPage okErrorPage = null;
  429   
  430   
  431       /**
  432        * The context initialization parameters for this web application,
  433        * keyed by name.
  434        */
  435       private HashMap parameters = new HashMap();
  436   
  437   
  438       /**
  439        * The request processing pause flag (while reloading occurs)
  440        */
  441       private boolean paused = false;
  442   
  443   
  444       /**
  445        * The public identifier of the DTD for the web application deployment
  446        * descriptor version we are currently parsing.  This is used to support
  447        * relaxed validation rules when processing version 2.2 web.xml files.
  448        */
  449       private String publicId = null;
  450   
  451   
  452       /**
  453        * The reloadable flag for this web application.
  454        */
  455       private boolean reloadable = false;
  456   
  457   
  458       /**
  459        * Unpack WAR property.
  460        */
  461       private boolean unpackWAR = true;
  462   
  463   
  464       /**
  465        * The DefaultContext override flag for this web application.
  466        */
  467       private boolean override = false;
  468   
  469   
  470       /**
  471        * The original document root for this web application.
  472        */
  473       private String originalDocBase = null;
  474       
  475       
  476       /**
  477        * The privileged flag for this web application.
  478        */
  479       private boolean privileged = false;
  480   
  481   
  482       /**
  483        * Should the next call to <code>addWelcomeFile()</code> cause replacement
  484        * of any existing welcome files?  This will be set before processing the
  485        * web application's deployment descriptor, so that application specified
  486        * choices <strong>replace</strong>, rather than append to, those defined
  487        * in the global descriptor.
  488        */
  489       private boolean replaceWelcomeFiles = false;
  490   
  491   
  492       /**
  493        * The security role mappings for this application, keyed by role
  494        * name (as used within the application).
  495        */
  496       private HashMap roleMappings = new HashMap();
  497   
  498   
  499       /**
  500        * The security roles for this application, keyed by role name.
  501        */
  502       private String securityRoles[] = new String[0];
  503   
  504       private final Object securityRolesLock = new Object();
  505   
  506   
  507       /**
  508        * The servlet mappings for this web application, keyed by
  509        * matching pattern.
  510        */
  511       private HashMap servletMappings = new HashMap();
  512       
  513       private final Object servletMappingsLock = new Object();
  514   
  515   
  516       /**
  517        * The session timeout (in minutes) for this web application.
  518        */
  519       private int sessionTimeout = 30;
  520   
  521       /**
  522        * The notification sequence number.
  523        */
  524       private long sequenceNumber = 0;
  525       
  526       /**
  527        * The status code error pages for this web application, keyed by
  528        * HTTP status code (as an Integer).
  529        */
  530       private HashMap statusPages = new HashMap();
  531   
  532   
  533       /**
  534        * Set flag to true to cause the system.out and system.err to be redirected
  535        * to the logger when executing a servlet.
  536        */
  537       private boolean swallowOutput = false;
  538   
  539   
  540       /**
  541        * The JSP tag libraries for this web application, keyed by URI
  542        */
  543       private HashMap taglibs = new HashMap();
  544   
  545   
  546       /**
  547        * Amount of ms that the container will wait for servlets to unload.
  548        */
  549       private long unloadDelay = 2000;
  550   
  551   
  552       /**
  553        * The watched resources for this application.
  554        */
  555       private String watchedResources[] = new String[0];
  556   
  557       private final Object watchedResourcesLock = new Object();
  558   
  559   
  560       /**
  561        * The welcome files for this application.
  562        */
  563       private String welcomeFiles[] = new String[0];
  564   
  565       private final Object welcomeFilesLock = new Object();
  566   
  567   
  568       /**
  569        * The set of classnames of LifecycleListeners that will be added
  570        * to each newly created Wrapper by <code>createWrapper()</code>.
  571        */
  572       private String wrapperLifecycles[] = new String[0];
  573   
  574       private final Object wrapperLifecyclesLock = new Object();
  575   
  576   
  577       /**
  578        * The set of classnames of ContainerListeners that will be added
  579        * to each newly created Wrapper by <code>createWrapper()</code>.
  580        */
  581       private String wrapperListeners[] = new String[0];
  582   
  583       private final Object wrapperListenersLock = new Object();
  584   
  585   
  586       /**
  587        * The pathname to the work directory for this context (relative to
  588        * the server's home if not absolute).
  589        */
  590       private String workDir = null;
  591   
  592   
  593       /**
  594        * Java class name of the Wrapper class implementation we use.
  595        */
  596       private String wrapperClassName = StandardWrapper.class.getName();
  597       private Class wrapperClass = null;
  598   
  599   
  600       /**
  601        * JNDI use flag.
  602        */
  603       private boolean useNaming = true;
  604   
  605   
  606       /**
  607        * Filesystem based flag.
  608        */
  609       private boolean filesystemBased = false;
  610   
  611   
  612       /**
  613        * Name of the associated naming context.
  614        */
  615       private String namingContextName = null;
  616   
  617   
  618       /**
  619        * Caching allowed flag.
  620        */
  621       private boolean cachingAllowed = true;
  622   
  623   
  624       /**
  625        * Case sensitivity.
  626        */
  627       protected boolean caseSensitive = true;
  628   
  629   
  630       /**
  631        * Allow linking.
  632        */
  633       protected boolean allowLinking = false;
  634   
  635   
  636       /**
  637        * Cache max size in KB.
  638        */
  639       protected int cacheMaxSize = 10240; // 10 MB
  640   
  641   
  642       /**
  643        * Cache object max size in KB.
  644        */
  645       protected int cacheObjectMaxSize = 512; // 512K
  646   
  647   
  648       /**
  649        * Cache TTL in ms.
  650        */
  651       protected int cacheTTL = 5000;
  652   
  653   
  654       private boolean lazy=true;
  655   
  656       /**
  657        * Non proxied resources.
  658        */
  659       private transient DirContext webappResources = null;
  660   
  661       private long startupTime;
  662       private long startTime;
  663       private long tldScanTime;
  664   
  665       /** 
  666        * Name of the engine. If null, the domain is used.
  667        */ 
  668       private String engineName = null;
  669       private String j2EEApplication="none";
  670       private String j2EEServer="none";
  671   
  672   
  673       /**
  674        * Attribute value used to turn on/off XML validation
  675        */
  676        private boolean webXmlValidation = false;
  677   
  678   
  679       /**
  680        * Attribute value used to turn on/off XML namespace validation
  681        */
  682        private boolean webXmlNamespaceAware = false;
  683   
  684       /**
  685        * Attribute value used to turn on/off TLD processing
  686        */
  687       private boolean processTlds = true;
  688   
  689       /**
  690        * Attribute value used to turn on/off XML validation
  691        */
  692        private boolean tldValidation = false;
  693   
  694   
  695       /**
  696        * Attribute value used to turn on/off TLD XML namespace validation
  697        */
  698        private boolean tldNamespaceAware = false;
  699   
  700   
  701       /**
  702        * Should we save the configuration.
  703        */
  704       private boolean saveConfig = true;
  705   
  706       /**
  707        * The flag that indicates that session cookies should use HttpOnly
  708        */
  709       private boolean useHttpOnly = false;
  710   
  711       /**
  712        * Should Tomcat attempt to terminate threads that have been started by the
  713        * web application? Stopping threads is performed via the deprecated (for
  714        * good reason) <code>Thread.stop()</code> method and is likely to result in
  715        * instability. As such, enabling this should be viewed as an option of last
  716        * resort in a development environment and is not recommended in a
  717        * production environment. If not specified, the default value of
  718        * <code>false</code> will be used. 
  719        */
  720       private boolean clearReferencesStopThreads = false;
  721   
  722       // ----------------------------------------------------- Context Properties
  723   
  724   
  725       public AnnotationProcessor getAnnotationProcessor() {
  726          return annotationProcessor;
  727       }
  728   
  729   
  730       public void setAnnotationProcessor(AnnotationProcessor annotationProcessor) {
  731          this.annotationProcessor = annotationProcessor;
  732       }
  733   
  734       
  735       public String getEncodedPath() {
  736           return encodedPath;
  737       }
  738   
  739   
  740       public void setName( String name ) {
  741           super.setName( name );
  742           encodedPath = urlEncoder.encode(name);
  743       }
  744   
  745   
  746       /**
  747        * Is caching allowed ?
  748        */
  749       public boolean isCachingAllowed() {
  750           return cachingAllowed;
  751       }
  752   
  753   
  754       /**
  755        * Set caching allowed flag.
  756        */
  757       public void setCachingAllowed(boolean cachingAllowed) {
  758           this.cachingAllowed = cachingAllowed;
  759       }
  760   
  761   
  762       /**
  763        * Set case sensitivity.
  764        */
  765       public void setCaseSensitive(boolean caseSensitive) {
  766           this.caseSensitive = caseSensitive;
  767       }
  768   
  769   
  770       /**
  771        * Is case sensitive ?
  772        */
  773       public boolean isCaseSensitive() {
  774           return caseSensitive;
  775       }
  776   
  777   
  778       /**
  779        * Set allow linking.
  780        */
  781       public void setAllowLinking(boolean allowLinking) {
  782           this.allowLinking = allowLinking;
  783       }
  784   
  785   
  786       /**
  787        * Is linking allowed.
  788        */
  789       public boolean isAllowLinking() {
  790           return allowLinking;
  791       }
  792   
  793   
  794       /**
  795        * Set cache TTL.
  796        */
  797       public void setCacheTTL(int cacheTTL) {
  798           this.cacheTTL = cacheTTL;
  799       }
  800   
  801   
  802       /**
  803        * Get cache TTL.
  804        */
  805       public int getCacheTTL() {
  806           return cacheTTL;
  807       }
  808   
  809   
  810       /**
  811        * Return the maximum size of the cache in KB.
  812        */
  813       public int getCacheMaxSize() {
  814           return cacheMaxSize;
  815       }
  816   
  817   
  818       /**
  819        * Set the maximum size of the cache in KB.
  820        */
  821       public void setCacheMaxSize(int cacheMaxSize) {
  822           this.cacheMaxSize = cacheMaxSize;
  823       }
  824   
  825   
  826       /**
  827        * Return the maximum size of objects to be cached in KB.
  828        */
  829       public int getCacheObjectMaxSize() {
  830           return cacheObjectMaxSize;
  831       }
  832   
  833   
  834       /**
  835        * Set the maximum size of objects to be placed the cache in KB.
  836        */
  837       public void setCacheObjectMaxSize(int cacheObjectMaxSize) {
  838           this.cacheObjectMaxSize = cacheObjectMaxSize;
  839       }
  840   
  841   
  842       /**
  843        * Return the "follow standard delegation model" flag used to configure
  844        * our ClassLoader.
  845        */
  846       public boolean getDelegate() {
  847   
  848           return (this.delegate);
  849   
  850       }
  851   
  852   
  853       /**
  854        * Set the "follow standard delegation model" flag used to configure
  855        * our ClassLoader.
  856        *
  857        * @param delegate The new flag
  858        */
  859       public void setDelegate(boolean delegate) {
  860   
  861           boolean oldDelegate = this.delegate;
  862           this.delegate = delegate;
  863           support.firePropertyChange("delegate", oldDelegate,
  864                                      this.delegate);
  865   
  866       }
  867   
  868   
  869       /**
  870        * Returns true if the internal naming support is used.
  871        */
  872       public boolean isUseNaming() {
  873   
  874           return (useNaming);
  875   
  876       }
  877   
  878   
  879       /**
  880        * Enables or disables naming.
  881        */
  882       public void setUseNaming(boolean useNaming) {
  883           this.useNaming = useNaming;
  884       }
  885   
  886   
  887       /**
  888        * Returns true if the resources associated with this context are
  889        * filesystem based.
  890        */
  891       public boolean isFilesystemBased() {
  892   
  893           return (filesystemBased);
  894   
  895       }
  896   
  897   
  898       /**
  899        * Return the set of initialized application event listener objects,
  900        * in the order they were specified in the web application deployment
  901        * descriptor, for this application.
  902        *
  903        * @exception IllegalStateException if this method is called before
  904        *  this application has started, or after it has been stopped
  905        */
  906       public Object[] getApplicationEventListeners() {
  907           return (applicationEventListenersObjects);
  908       }
  909   
  910   
  911       /**
  912        * Store the set of initialized application event listener objects,
  913        * in the order they were specified in the web application deployment
  914        * descriptor, for this application.
  915        *
  916        * @param listeners The set of instantiated listener objects.
  917        */
  918       public void setApplicationEventListeners(Object listeners[]) {
  919           applicationEventListenersObjects = listeners;
  920       }
  921   
  922   
  923       /**
  924        * Return the set of initialized application lifecycle listener objects,
  925        * in the order they were specified in the web application deployment
  926        * descriptor, for this application.
  927        *
  928        * @exception IllegalStateException if this method is called before
  929        *  this application has started, or after it has been stopped
  930        */
  931       public Object[] getApplicationLifecycleListeners() {
  932           return (applicationLifecycleListenersObjects);
  933       }
  934   
  935   
  936       /**
  937        * Store the set of initialized application lifecycle listener objects,
  938        * in the order they were specified in the web application deployment
  939        * descriptor, for this application.
  940        *
  941        * @param listeners The set of instantiated listener objects.
  942        */
  943       public void setApplicationLifecycleListeners(Object listeners[]) {
  944           applicationLifecycleListenersObjects = listeners;
  945       }
  946   
  947   
  948       /**
  949        * Return the antiJARLocking flag for this Context.
  950        */
  951       public boolean getAntiJARLocking() {
  952   
  953           return (this.antiJARLocking);
  954   
  955       }
  956   
  957   
  958       /**
  959        * Return the antiResourceLocking flag for this Context.
  960        */
  961       public boolean getAntiResourceLocking() {
  962   
  963           return (this.antiResourceLocking);
  964   
  965       }
  966   
  967   
  968       /**
  969        * Set the antiJARLocking feature for this Context.
  970        *
  971        * @param antiJARLocking The new flag value
  972        */
  973       public void setAntiJARLocking(boolean antiJARLocking) {
  974   
  975           boolean oldAntiJARLocking = this.antiJARLocking;
  976           this.antiJARLocking = antiJARLocking;
  977           support.firePropertyChange("antiJARLocking",
  978                                      oldAntiJARLocking,
  979                                      this.antiJARLocking);
  980   
  981       }
  982   
  983   
  984       /**
  985        * Set the antiResourceLocking feature for this Context.
  986        *
  987        * @param antiResourceLocking The new flag value
  988        */
  989       public void setAntiResourceLocking(boolean antiResourceLocking) {
  990   
  991           boolean oldAntiResourceLocking = this.antiResourceLocking;
  992           this.antiResourceLocking = antiResourceLocking;
  993           support.firePropertyChange("antiResourceLocking",
  994                                      oldAntiResourceLocking,
  995                                      this.antiResourceLocking);
  996   
  997       }
  998   
  999   
 1000       /**
 1001        * Return the application available flag for this Context.
 1002        */
 1003       public boolean getAvailable() {
 1004   
 1005           return (this.available);
 1006   
 1007       }
 1008   
 1009   
 1010       /**
 1011        * Set the application available flag for this Context.
 1012        *
 1013        * @param available The new application available flag
 1014        */
 1015       public void setAvailable(boolean available) {
 1016   
 1017           boolean oldAvailable = this.available;
 1018           this.available = available;
 1019           support.firePropertyChange("available",
 1020                                      oldAvailable,
 1021                                      this.available);
 1022   
 1023       }
 1024   
 1025   
 1026       /**
 1027        * Return the Locale to character set mapper for this Context.
 1028        */
 1029       public CharsetMapper getCharsetMapper() {
 1030   
 1031           // Create a mapper the first time it is requested
 1032           if (this.charsetMapper == null) {
 1033               try {
 1034                   Class clazz = Class.forName(charsetMapperClass);
 1035                   this.charsetMapper =
 1036                     (CharsetMapper) clazz.newInstance();
 1037               } catch (Throwable t) {
 1038                   this.charsetMapper = new CharsetMapper();
 1039               }
 1040           }
 1041   
 1042           return (this.charsetMapper);
 1043   
 1044       }
 1045   
 1046   
 1047       /**
 1048        * Set the Locale to character set mapper for this Context.
 1049        *
 1050        * @param mapper The new mapper
 1051        */
 1052       public void setCharsetMapper(CharsetMapper mapper) {
 1053   
 1054           CharsetMapper oldCharsetMapper = this.charsetMapper;
 1055           this.charsetMapper = mapper;
 1056           if( mapper != null )
 1057               this.charsetMapperClass= mapper.getClass().getName();
 1058           support.firePropertyChange("charsetMapper", oldCharsetMapper,
 1059                                      this.charsetMapper);
 1060   
 1061       }
 1062   
 1063       /**
 1064        * Return the path to a file to save this Context information.
 1065        */
 1066       public String getConfigFile() {
 1067   
 1068           return (this.configFile);
 1069   
 1070       }
 1071   
 1072   
 1073       /**
 1074        * Set the path to a file to save this Context information.
 1075        *
 1076        * @param configFile The path to a file to save this Context information.
 1077        */
 1078       public void setConfigFile(String configFile) {
 1079   
 1080           this.configFile = configFile;
 1081       }
 1082   
 1083   
 1084       /**
 1085        * Return the "correctly configured" flag for this Context.
 1086        */
 1087       public boolean getConfigured() {
 1088   
 1089           return (this.configured);
 1090   
 1091       }
 1092   
 1093   
 1094       /**
 1095        * Set the "correctly configured" flag for this Context.  This can be
 1096        * set to false by startup listeners that detect a fatal configuration
 1097        * error to avoid the application from being made available.
 1098        *
 1099        * @param configured The new correctly configured flag
 1100        */
 1101       public void setConfigured(boolean configured) {
 1102   
 1103           boolean oldConfigured = this.configured;
 1104           this.configured = configured;
 1105           support.firePropertyChange("configured",
 1106                                      oldConfigured,
 1107                                      this.configured);
 1108   
 1109       }
 1110   
 1111   
 1112       /**
 1113        * Return the "use cookies for session ids" flag.
 1114        */
 1115       public boolean getCookies() {
 1116   
 1117           return (this.cookies);
 1118   
 1119       }
 1120   
 1121   
 1122       /**
 1123        * Set the "use cookies for session ids" flag.
 1124        *
 1125        * @param cookies The new flag
 1126        */
 1127       public void setCookies(boolean cookies) {
 1128   
 1129           boolean oldCookies = this.cookies;
 1130           this.cookies = cookies;
 1131           support.firePropertyChange("cookies",
 1132                                      oldCookies,
 1133                                      this.cookies);
 1134   
 1135       }
 1136       
 1137       /**
 1138        * Gets the value of the use HttpOnly cookies for session cookies flag.
 1139        * 
 1140        * @return <code>true</code> if the HttpOnly flag should be set on session
 1141        *         cookies
 1142        */
 1143       public boolean getUseHttpOnly() {
 1144           return useHttpOnly;
 1145       }
 1146   
 1147   
 1148       /**
 1149        * Sets the use HttpOnly cookies for session cookies flag.
 1150        * 
 1151        * @param useHttpOnly   Set to <code>true</code> to use HttpOnly cookies
 1152        *                          for session cookies
 1153        */
 1154       public void setUseHttpOnly(boolean useHttpOnly) {
 1155           boolean oldUseHttpOnly = this.useHttpOnly;
 1156           this.useHttpOnly = useHttpOnly;
 1157           support.firePropertyChange("useHttpOnly",
 1158                   oldUseHttpOnly,
 1159                   this.useHttpOnly);
 1160       }
 1161       
 1162       
 1163   
 1164   
 1165       /**
 1166        * Return the "allow crossing servlet contexts" flag.
 1167        */
 1168       public boolean getCrossContext() {
 1169   
 1170           return (this.crossContext);
 1171   
 1172       }
 1173   
 1174   
 1175       /**
 1176        * Set the "allow crossing servlet contexts" flag.
 1177        *
 1178        * @param crossContext The new cross contexts flag
 1179        */
 1180       public void setCrossContext(boolean crossContext) {
 1181   
 1182           boolean oldCrossContext = this.crossContext;
 1183           this.crossContext = crossContext;
 1184           support.firePropertyChange("crossContext",
 1185                                      oldCrossContext,
 1186                                      this.crossContext);
 1187   
 1188       }
 1189   
 1190       public String getDefaultContextXml() {
 1191           return defaultContextXml;
 1192       }
 1193   
 1194       /** 
 1195        * Set the location of the default context xml that will be used.
 1196        * If not absolute, it'll be made relative to the engine's base dir
 1197        * ( which defaults to catalina.base system property ).
 1198        *
 1199        * @param defaultContextXml The default web xml 
 1200        */
 1201       public void setDefaultContextXml(String defaultContextXml) {
 1202           this.defaultContextXml = defaultContextXml;
 1203       }
 1204   
 1205       public String getDefaultWebXml() {
 1206           return defaultWebXml;
 1207       }
 1208   
 1209       /** 
 1210        * Set the location of the default web xml that will be used.
 1211        * If not absolute, it'll be made relative to the engine's base dir
 1212        * ( which defaults to catalina.base system property ).
 1213        *
 1214        * @param defaultWebXml The default web xml 
 1215        */
 1216       public void setDefaultWebXml(String defaultWebXml) {
 1217           this.defaultWebXml = defaultWebXml;
 1218       }
 1219   
 1220       /**
 1221        * Gets the time (in milliseconds) it took to start this context.
 1222        *
 1223        * @return Time (in milliseconds) it took to start this context.
 1224        */
 1225       public long getStartupTime() {
 1226           return startupTime;
 1227       }
 1228   
 1229       public void setStartupTime(long startupTime) {
 1230           this.startupTime = startupTime;
 1231       }
 1232   
 1233       public long getTldScanTime() {
 1234           return tldScanTime;
 1235       }
 1236   
 1237       public void setTldScanTime(long tldScanTime) {
 1238           this.tldScanTime = tldScanTime;
 1239       }
 1240   
 1241       /**
 1242        * Return the display name of this web application.
 1243        */
 1244       public String getDisplayName() {
 1245   
 1246           return (this.displayName);
 1247   
 1248       }
 1249   
 1250   
 1251       /**
 1252        * Return the alternate Deployment Descriptor name.
 1253        */
 1254       public String getAltDDName(){
 1255           return altDDName;
 1256       }
 1257   
 1258   
 1259       /**
 1260        * Set an alternate Deployment Descriptor name.
 1261        */
 1262       public void setAltDDName(String altDDName) {
 1263           this.altDDName = altDDName;
 1264           if (context != null) {
 1265               context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
 1266           }
 1267       }
 1268   
 1269   
 1270       /**
 1271        * Return the compiler classpath.
 1272        */
 1273       public String getCompilerClasspath(){
 1274           return compilerClasspath;
 1275       }
 1276   
 1277   
 1278       /**
 1279        * Set the compiler classpath.
 1280        */
 1281       public void setCompilerClasspath(String compilerClasspath) {
 1282           this.compilerClasspath = compilerClasspath;
 1283       }
 1284   
 1285   
 1286       /**
 1287        * Set the display name of this web application.
 1288        *
 1289        * @param displayName The new display name
 1290        */
 1291       public void setDisplayName(String displayName) {
 1292   
 1293           String oldDisplayName = this.displayName;
 1294           this.displayName = displayName;
 1295           support.firePropertyChange("displayName", oldDisplayName,
 1296                                      this.displayName);
 1297       }
 1298   
 1299   
 1300       /**
 1301        * Return the distributable flag for this web application.
 1302        */
 1303       public boolean getDistributable() {
 1304   
 1305           return (this.distributable);
 1306   
 1307       }
 1308   
 1309       /**
 1310        * Set the distributable flag for this web application.
 1311        *
 1312        * @param distributable The new distributable flag
 1313        */
 1314       public void setDistributable(boolean distributable) {
 1315           boolean oldDistributable = this.distributable;
 1316           this.distributable = distributable;
 1317           support.firePropertyChange("distributable",
 1318                                      oldDistributable,
 1319                                      this.distributable);
 1320   
 1321           // Bugzilla 32866
 1322           if(getManager() != null) {
 1323               if(log.isDebugEnabled()) {
 1324                   log.debug("Propagating distributable=" + distributable
 1325                             + " to manager");
 1326               }
 1327               getManager().setDistributable(distributable);
 1328           }
 1329       }
 1330   
 1331   
 1332       /**
 1333        * Return the document root for this Context.  This can be an absolute
 1334        * pathname, a relative pathname, or a URL.
 1335        */
 1336       public String getDocBase() {
 1337   
 1338           return (this.docBase);
 1339   
 1340       }
 1341   
 1342   
 1343       /**
 1344        * Set the document root for this Context.  This can be an absolute
 1345        * pathname, a relative pathname, or a URL.
 1346        *
 1347        * @param docBase The new document root
 1348        */
 1349       public void setDocBase(String docBase) {
 1350   
 1351           this.docBase = docBase;
 1352   
 1353       }
 1354   
 1355       // experimental
 1356       public boolean isLazy() {
 1357           return lazy;
 1358       }
 1359   
 1360       public void setLazy(boolean lazy) {
 1361           this.lazy = lazy;
 1362       }
 1363   
 1364   
 1365       /**
 1366        * Return descriptive information about this Container implementation and
 1367        * the corresponding version number, in the format
 1368        * <code>&lt;description&gt;/&lt;version&gt;</code>.
 1369        */
 1370       public String getInfo() {
 1371   
 1372           return (info);
 1373   
 1374       }
 1375   
 1376       public String getEngineName() {
 1377           if( engineName != null ) return engineName;
 1378           return domain;
 1379       }
 1380   
 1381       public void setEngineName(String engineName) {
 1382           this.engineName = engineName;
 1383       }
 1384   
 1385       public String getJ2EEApplication() {
 1386           return j2EEApplication;
 1387       }
 1388   
 1389       public void setJ2EEApplication(String j2EEApplication) {
 1390           this.j2EEApplication = j2EEApplication;
 1391       }
 1392   
 1393       public String getJ2EEServer() {
 1394           return j2EEServer;
 1395       }
 1396   
 1397       public void setJ2EEServer(String j2EEServer) {
 1398           this.j2EEServer = j2EEServer;
 1399       }
 1400   
 1401   
 1402       /**
 1403        * Set the Loader with which this Context is associated.
 1404        *
 1405        * @param loader The newly associated loader
 1406        */
 1407       public synchronized void setLoader(Loader loader) {
 1408   
 1409           super.setLoader(loader);
 1410   
 1411       }
 1412   
 1413   
 1414       /**
 1415        * Return the boolean on the annotations parsing.
 1416        */
 1417       public boolean getIgnoreAnnotations() {
 1418           return this.ignoreAnnotations;
 1419       }
 1420       
 1421       
 1422       /**
 1423        * Set the boolean on the annotations parsing for this web 
 1424        * application.
 1425        * 
 1426        * @param ignoreAnnotations The boolean on the annotations parsing
 1427        */
 1428       public void setIgnoreAnnotations(boolean ignoreAnnotations) {
 1429           boolean oldIgnoreAnnotations = this.ignoreAnnotations;
 1430           this.ignoreAnnotations = ignoreAnnotations;
 1431           support.firePropertyChange("ignoreAnnotations", oldIgnoreAnnotations,
 1432                   this.ignoreAnnotations);
 1433       }
 1434       
 1435       
 1436       /**
 1437        * Return the login configuration descriptor for this web application.
 1438        */
 1439       public LoginConfig getLoginConfig() {
 1440   
 1441           return (this.loginConfig);
 1442   
 1443       }
 1444   
 1445   
 1446       /**
 1447        * Set the login configuration descriptor for this web application.
 1448        *
 1449        * @param config The new login configuration
 1450        */
 1451       public void setLoginConfig(LoginConfig config) {
 1452   
 1453           // Validate the incoming property value
 1454           if (config == null)
 1455               throw new IllegalArgumentException
 1456                   (sm.getString("standardContext.loginConfig.required"));
 1457           String loginPage = config.getLoginPage();
 1458           if ((loginPage != null) && !loginPage.startsWith("/")) {
 1459               if (isServlet22()) {
 1460                   if(log.isDebugEnabled())
 1461                       log.debug(sm.getString("standardContext.loginConfig.loginWarning",
 1462                                    loginPage));
 1463                   config.setLoginPage("/" + loginPage);
 1464               } else {
 1465                   throw new IllegalArgumentException
 1466                       (sm.getString("standardContext.loginConfig.loginPage",
 1467                                     loginPage));
 1468               }
 1469           }
 1470           String errorPage = config.getErrorPage();
 1471           if ((errorPage != null) && !errorPage.startsWith("/")) {
 1472               if (isServlet22()) {
 1473                   if(log.isDebugEnabled())
 1474                       log.debug(sm.getString("standardContext.loginConfig.errorWarning",
 1475                                    errorPage));
 1476                   config.setErrorPage("/" + errorPage);
 1477               } else {
 1478                   throw new IllegalArgumentException
 1479                       (sm.getString("standardContext.loginConfig.errorPage",
 1480                                     errorPage));
 1481               }
 1482           }
 1483   
 1484           // Process the property setting change
 1485           LoginConfig oldLoginConfig = this.loginConfig;
 1486           this.loginConfig = config;
 1487           support.firePropertyChange("loginConfig",
 1488                                      oldLoginConfig, this.loginConfig);
 1489   
 1490       }
 1491   
 1492   
 1493       /**
 1494        * Get the mapper associated with the context.
 1495        */
 1496       public org.apache.tomcat.util.http.mapper.Mapper getMapper() {
 1497           return (mapper);
 1498       }
 1499   
 1500   
 1501       /**
 1502        * Return the naming resources associated with this web application.
 1503        */
 1504       public NamingResources getNamingResources() {
 1505   
 1506           if (namingResources == null) {
 1507               setNamingResources(new NamingResources());
 1508           }
 1509           return (namingResources);
 1510   
 1511       }
 1512   
 1513   
 1514       /**
 1515        * Set the naming resources for this web application.
 1516        *
 1517        * @param namingResources The new naming resources
 1518        */
 1519       public void setNamingResources(NamingResources namingResources) {
 1520   
 1521           // Process the property setting change
 1522           NamingResources oldNamingResources = this.namingResources;
 1523           this.namingResources = namingResources;
 1524           namingResources.setContainer(this);
 1525           support.firePropertyChange("namingResources",
 1526                                      oldNamingResources, this.namingResources);
 1527   
 1528       }
 1529   
 1530   
 1531       /**
 1532        * Return the context path for this Context.
 1533        */
 1534       public String getPath() {
 1535   
 1536           return (getName());
 1537   
 1538       }
 1539   
 1540       
 1541       /**
 1542        * Set the context path for this Context.
 1543        * <p>
 1544        * <b>IMPLEMENTATION NOTE</b>:  The context path is used as the "name" of
 1545        * a Context, because it must be unique.
 1546        *
 1547        * @param path The new context path
 1548        */
 1549       public void setPath(String path) {
 1550           // XXX Use host in name
 1551           setName(path);
 1552   
 1553       }
 1554   
 1555   
 1556       /**
 1557        * Return the public identifier of the deployment descriptor DTD that is
 1558        * currently being parsed.
 1559        */
 1560       public String getPublicId() {
 1561   
 1562           return (this.publicId);
 1563   
 1564       }
 1565   
 1566   
 1567       /**
 1568        * Set the public identifier of the deployment descriptor DTD that is
 1569        * currently being parsed.
 1570        *
 1571        * @param publicId The public identifier
 1572        */
 1573       public void setPublicId(String publicId) {
 1574   
 1575           if (log.isDebugEnabled())
 1576               log.debug("Setting deployment descriptor public ID to '" +
 1577                   publicId + "'");
 1578   
 1579           String oldPublicId = this.publicId;
 1580           this.publicId = publicId;
 1581           support.firePropertyChange("publicId", oldPublicId, publicId);
 1582   
 1583       }
 1584   
 1585   
 1586       /**
 1587        * Return the reloadable flag for this web application.
 1588        */
 1589       public boolean getReloadable() {
 1590   
 1591           return (this.reloadable);
 1592   
 1593       }
 1594   
 1595   
 1596       /**
 1597        * Return the DefaultContext override flag for this web application.
 1598        */
 1599       public boolean getOverride() {
 1600   
 1601           return (this.override);
 1602   
 1603       }
 1604   
 1605   
 1606       /**
 1607        * Return the original document root for this Context.  This can be an absolute
 1608        * pathname, a relative pathname, or a URL.
 1609        * Is only set as deployment has change docRoot!
 1610        */
 1611       public String getOriginalDocBase() {
 1612   
 1613           return (this.originalDocBase);
 1614   
 1615       }
 1616   
 1617       /**
 1618        * Set the original document root for this Context.  This can be an absolute
 1619        * pathname, a relative pathname, or a URL.
 1620        *
 1621        * @param docBase The orginal document root
 1622        */
 1623       public void setOriginalDocBase(String docBase) {
 1624   
 1625           this.originalDocBase = docBase;
 1626       }
 1627       
 1628   
 1629       /**
 1630        * Return the parent class loader (if any) for this web application.
 1631        * This call is meaningful only <strong>after</strong> a Loader has
 1632        * been configured.
 1633        */
 1634       public ClassLoader getParentClassLoader() {
 1635           if (parentClassLoader != null)
 1636               return (parentClassLoader);
 1637           if (getPrivileged()) {
 1638               return this.getClass().getClassLoader();
 1639           } else if (parent != null) {
 1640               return (parent.getParentClassLoader());
 1641           }
 1642           return (ClassLoader.getSystemClassLoader());
 1643       }
 1644   
 1645       
 1646       /**
 1647        * Return the privileged flag for this web application.
 1648        */
 1649       public boolean getPrivileged() {
 1650   
 1651           return (this.privileged);
 1652   
 1653       }
 1654   
 1655   
 1656       /**
 1657        * Set the privileged flag for this web application.
 1658        *
 1659        * @param privileged The new privileged flag
 1660        */
 1661       public void setPrivileged(boolean privileged) {
 1662   
 1663           boolean oldPrivileged = this.privileged;
 1664           this.privileged = privileged;
 1665           support.firePropertyChange("privileged",
 1666                                      oldPrivileged,
 1667                                      this.privileged);
 1668   
 1669       }
 1670   
 1671   
 1672       /**
 1673        * Set the reloadable flag for this web application.
 1674        *
 1675        * @param reloadable The new reloadable flag
 1676        */
 1677       public void setReloadable(boolean reloadable) {
 1678   
 1679           boolean oldReloadable = this.reloadable;
 1680           this.reloadable = reloadable;
 1681           support.firePropertyChange("reloadable",
 1682                                      oldReloadable,
 1683                                      this.reloadable);
 1684   
 1685       }
 1686   
 1687   
 1688       /**
 1689        * Set the DefaultContext override flag for this web application.
 1690        *
 1691        * @param override The new override flag
 1692        */
 1693       public void setOverride(boolean override) {
 1694   
 1695           boolean oldOverride = this.override;
 1696           this.override = override;
 1697           support.firePropertyChange("override",
 1698                                      oldOverride,
 1699                                      this.override);
 1700   
 1701       }
 1702   
 1703   
 1704       /**
 1705        * Return the "replace welcome files" property.
 1706        */
 1707       public boolean isReplaceWelcomeFiles() {
 1708   
 1709           return (this.replaceWelcomeFiles);
 1710   
 1711       }
 1712   
 1713   
 1714       /**
 1715        * Set the "replace welcome files" property.
 1716        *
 1717        * @param replaceWelcomeFiles The new property value
 1718        */
 1719       public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) {
 1720   
 1721           boolean oldReplaceWelcomeFiles = this.replaceWelcomeFiles;
 1722           this.replaceWelcomeFiles = replaceWelcomeFiles;
 1723           support.firePropertyChange("replaceWelcomeFiles",
 1724                                      oldReplaceWelcomeFiles,
 1725                                      this.replaceWelcomeFiles);
 1726   
 1727       }
 1728   
 1729   
 1730       /**
 1731        * Return the servlet context for which this Context is a facade.
 1732        */
 1733       public ServletContext getServletContext() {
 1734   
 1735           if (context == null) {
 1736               context = new ApplicationContext(getBasePath(), this);
 1737               if (altDDName != null)
 1738                   context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
 1739           }
 1740           return (context.getFacade());
 1741   
 1742       }
 1743   
 1744   
 1745       /**
 1746        * Return the default session timeout (in minutes) for this
 1747        * web application.
 1748        */
 1749       public int getSessionTimeout() {
 1750   
 1751           return (this.sessionTimeout);
 1752   
 1753       }
 1754   
 1755   
 1756       /**
 1757        * Set the default session timeout (in minutes) for this
 1758        * web application.
 1759        *
 1760        * @param timeout The new default session timeout
 1761        */
 1762       public void setSessionTimeout(int timeout) {
 1763   
 1764           int oldSessionTimeout = this.sessionTimeout;
 1765           /*
 1766            * SRV.13.4 ("Deployment Descriptor"):
 1767            * If the timeout is 0 or less, the container ensures the default
 1768            * behaviour of sessions is never to time out.
 1769            */
 1770           this.sessionTimeout = (timeout == 0) ? -1 : timeout;
 1771           support.firePropertyChange("sessionTimeout",
 1772                                      oldSessionTimeout,
 1773                                      this.sessionTimeout);
 1774   
 1775       }
 1776   
 1777   
 1778       /**
 1779        * Return the value of the swallowOutput flag.
 1780        */
 1781       public boolean getSwallowOutput() {
 1782   
 1783           return (this.swallowOutput);
 1784   
 1785       }
 1786   
 1787   
 1788       /**
 1789        * Set the value of the swallowOutput flag. If set to true, the system.out
 1790        * and system.err will be redirected to the logger during a servlet
 1791        * execution.
 1792        *
 1793        * @param swallowOutput The new value
 1794        */
 1795       public void setSwallowOutput(boolean swallowOutput) {
 1796   
 1797           boolean oldSwallowOutput = this.swallowOutput;
 1798           this.swallowOutput = swallowOutput;
 1799           support.firePropertyChange("swallowOutput",
 1800                                      oldSwallowOutput,
 1801                                      this.swallowOutput);
 1802   
 1803       }
 1804   
 1805   
 1806       /**
 1807        * Return the value of the unloadDelay flag.
 1808        */
 1809       public long getUnloadDelay() {
 1810   
 1811           return (this.unloadDelay);
 1812   
 1813       }
 1814   
 1815   
 1816       /**
 1817        * Set the value of the unloadDelay flag, which represents the amount
 1818        * of ms that the container will wait when unloading servlets.
 1819        * Setting this to a small value may cause more requests to fail 
 1820        * to complete when stopping a web application.
 1821        *
 1822        * @param unloadDelay The new value
 1823        */
 1824       public void setUnloadDelay(long unloadDelay) {
 1825   
 1826           long oldUnloadDelay = this.unloadDelay;
 1827           this.unloadDelay = unloadDelay;
 1828           support.firePropertyChange("unloadDelay",
 1829                                      Long.valueOf(oldUnloadDelay),
 1830                                      Long.valueOf(this.unloadDelay));
 1831   
 1832       }
 1833   
 1834   
 1835       /**
 1836        * Unpack WAR flag accessor.
 1837        */
 1838       public boolean getUnpackWAR() {
 1839   
 1840           return (unpackWAR);
 1841   
 1842       }
 1843   
 1844   
 1845       /**
 1846        * Unpack WAR flag mutator.
 1847        */
 1848       public void setUnpackWAR(boolean unpackWAR) {
 1849   
 1850           this.unpackWAR = unpackWAR;
 1851   
 1852       }
 1853   
 1854       /**
 1855        * Return the Java class name of the Wrapper implementation used
 1856        * for servlets registered in this Context.
 1857        */
 1858       public String getWrapperClass() {
 1859   
 1860           return (this.wrapperClassName);
 1861   
 1862       }
 1863   
 1864   
 1865       /**
 1866        * Set the Java class name of the Wrapper implementation used
 1867        * for servlets registered in this Context.
 1868        *
 1869        * @param wrapperClassName The new wrapper class name
 1870        *
 1871        * @throws IllegalArgumentException if the specified wrapper class
 1872        * cannot be found or is not a subclass of StandardWrapper
 1873        */
 1874       public void setWrapperClass(String wrapperClassName) {
 1875   
 1876           this.wrapperClassName = wrapperClassName;
 1877   
 1878           try {
 1879               wrapperClass = Class.forName(wrapperClassName);         
 1880               if (!StandardWrapper.class.isAssignableFrom(wrapperClass)) {
 1881                   throw new IllegalArgumentException(
 1882                       sm.getString("standardContext.invalidWrapperClass",
 1883                                    wrapperClassName));
 1884               }
 1885           } catch (ClassNotFoundException cnfe) {
 1886               throw new IllegalArgumentException(cnfe.getMessage());
 1887           }
 1888       }
 1889   
 1890   
 1891       /**
 1892        * Set the resources DirContext object with which this Container is
 1893        * associated.
 1894        *
 1895        * @param resources The newly associated DirContext
 1896        */
 1897       public synchronized void setResources(DirContext resources) {
 1898   
 1899           if (started) {
 1900               throw new IllegalStateException
 1901                   (sm.getString("standardContext.resources.started"));
 1902           }
 1903   
 1904           DirContext oldResources = this.webappResources;
 1905           if (oldResources == resources)
 1906               return;
 1907   
 1908           if (resources instanceof BaseDirContext) {
 1909               ((BaseDirContext) resources).setCached(isCachingAllowed());
 1910               ((BaseDirContext) resources).setCacheTTL(getCacheTTL());
 1911               ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize());
 1912               ((BaseDirContext) resources).setCacheObjectMaxSize(
 1913                       getCacheObjectMaxSize());
 1914           }
 1915           if (resources instanceof FileDirContext) {
 1916               filesystemBased = true;
 1917               ((FileDirContext) resources).setCaseSensitive(isCaseSensitive());
 1918               ((FileDirContext) resources).setAllowLinking(isAllowLinking());
 1919           }
 1920           this.webappResources = resources;
 1921   
 1922           // The proxied resources will be refreshed on start
 1923           this.resources = null;
 1924   
 1925           support.firePropertyChange("resources", oldResources,
 1926                                      this.webappResources);
 1927   
 1928       }
 1929   
 1930   
 1931       // ------------------------------------------------------ Public Properties
 1932   
 1933   
 1934       /**
 1935        * Return the Locale to character set mapper class for this Context.
 1936        */
 1937       public String getCharsetMapperClass() {
 1938   
 1939           return (this.charsetMapperClass);
 1940   
 1941       }
 1942   
 1943   
 1944       /**
 1945        * Set the Locale to character set mapper class for this Context.
 1946        *
 1947        * @param mapper The new mapper class
 1948        */
 1949       public void setCharsetMapperClass(String mapper) {
 1950   
 1951           String oldCharsetMapperClass = this.charsetMapperClass;
 1952           this.charsetMapperClass = mapper;
 1953           support.firePropertyChange("charsetMapperClass",
 1954                                      oldCharsetMapperClass,
 1955                                      this.charsetMapperClass);
 1956   
 1957       }
 1958   
 1959   
 1960       /** Get the absolute path to the work dir.
 1961        *  To avoid duplication.
 1962        * 
 1963        * @return The work path
 1964        */ 
 1965       public String getWorkPath() {
 1966           if (getWorkDir() == null) {
 1967               return null;
 1968           }
 1969           File workDir = new File(getWorkDir());
 1970           if (!workDir.isAbsolute()) {
 1971               File catalinaHome = engineBase();
 1972               String catalinaHomePath = null;
 1973               try {
 1974                   catalinaHomePath = catalinaHome.getCanonicalPath();
 1975                   workDir = new File(catalinaHomePath,
 1976                           getWorkDir());
 1977               } catch (IOException e) {
 1978                   log.warn("Exception obtaining work path for " + getPath());
 1979               }
 1980           }
 1981           return workDir.getAbsolutePath();
 1982       }
 1983       
 1984       /**
 1985        * Return the work directory for this Context.
 1986        */
 1987       public String getWorkDir() {
 1988   
 1989           return (this.workDir);
 1990   
 1991       }
 1992   
 1993   
 1994       /**
 1995        * Set the work directory for this Context.
 1996        *
 1997        * @param workDir The new work directory
 1998        */
 1999       public void setWorkDir(String workDir) {
 2000   
 2001           this.workDir = workDir;
 2002   
 2003           if (started) {
 2004               postWorkDirectory();
 2005           }
 2006       }
 2007   
 2008   
 2009       /**
 2010        * Save config ?
 2011        */
 2012       public boolean isSaveConfig() {
 2013           return saveConfig;
 2014       }
 2015   
 2016   
 2017       /**
 2018        * Set save config flag.
 2019        */
 2020       public void setSaveConfig(boolean saveConfig) {
 2021           this.saveConfig = saveConfig;
 2022       }
 2023   
 2024   
 2025       /**
 2026        * Return the clearReferencesStopThreads flag for this Context.
 2027        */
 2028       public boolean getClearReferencesStopThreads() {
 2029   
 2030           return (this.clearReferencesStopThreads);
 2031   
 2032       }
 2033   
 2034   
 2035       /**
 2036        * Set the clearReferencesStopThreads feature for this Context.
 2037        *
 2038        * @param clearReferencesStopThreads The new flag value
 2039        */
 2040       public void setClearReferencesStopThreads(
 2041               boolean clearReferencesStopThreads) {
 2042   
 2043           boolean oldClearReferencesStopThreads = this.clearReferencesStopThreads;
 2044           this.clearReferencesStopThreads = clearReferencesStopThreads;
 2045           support.firePropertyChange("clearReferencesStopThreads",
 2046                                      oldClearReferencesStopThreads,
 2047                                      this.clearReferencesStopThreads);
 2048   
 2049       }
 2050   
 2051   
 2052       // -------------------------------------------------------- Context Methods
 2053   
 2054   
 2055       /**
 2056        * Add a new Listener class name to the set of Listeners
 2057        * configured for this application.
 2058        *
 2059        * @param listener Java class name of a listener class
 2060        */
 2061       public void addApplicationListener(String listener) {
 2062   
 2063           synchronized (applicationListenersLock) {
 2064               String results[] =new String[applicationListeners.length + 1];
 2065               for (int i = 0; i < applicationListeners.length; i++) {
 2066                   if (listener.equals(applicationListeners[i])) {
 2067                       log.info(sm.getString(
 2068                               "standardContext.duplicateListener",listener));
 2069                       return;
 2070                   }
 2071                   results[i] = applicationListeners[i];
 2072               }
 2073               results[applicationListeners.length] = listener;
 2074               applicationListeners = results;
 2075           }
 2076           fireContainerEvent("addApplicationListener", listener);
 2077   
 2078           // FIXME - add instance if already started?
 2079   
 2080       }
 2081   
 2082   
 2083       /**
 2084        * Add a new application parameter for this application.
 2085        *
 2086        * @param parameter The new application parameter
 2087        */
 2088       public void addApplicationParameter(ApplicationParameter parameter) {
 2089   
 2090           synchronized (applicationParametersLock) {
 2091               String newName = parameter.getName();
 2092               for (int i = 0; i < applicationParameters.length; i++) {
 2093                   if (newName.equals(applicationParameters[i].getName()) &&
 2094                       !applicationParameters[i].getOverride())
 2095                       return;
 2096               }
 2097               ApplicationParameter results[] =
 2098                   new ApplicationParameter[applicationParameters.length + 1];
 2099               System.arraycopy(applicationParameters, 0, results, 0,
 2100                                applicationParameters.length);
 2101               results[applicationParameters.length] = parameter;
 2102               applicationParameters = results;
 2103           }
 2104           fireContainerEvent("addApplicationParameter", parameter);
 2105   
 2106       }
 2107   
 2108   
 2109       /**
 2110        * Add a child Container, only if the proposed child is an implementation
 2111        * of Wrapper.
 2112        *
 2113        * @param child Child container to be added
 2114        *
 2115        * @exception IllegalArgumentException if the proposed container is
 2116        *  not an implementation of Wrapper
 2117        */
 2118       public void addChild(Container child) {
 2119   
 2120           // Global JspServlet
 2121           Wrapper oldJspServlet = null;
 2122   
 2123           if (!(child instanceof Wrapper)) {
 2124               throw new IllegalArgumentException
 2125                   (sm.getString("standardContext.notWrapper"));
 2126           }
 2127   
 2128           Wrapper wrapper = (Wrapper) child;
 2129           boolean isJspServlet = "jsp".equals(child.getName());
 2130   
 2131           // Allow webapp to override JspServlet inherited from global web.xml.
 2132           if (isJspServlet) {
 2133               oldJspServlet = (Wrapper) findChild("jsp");
 2134               if (oldJspServlet != null) {
 2135                   removeChild(oldJspServlet);
 2136               }
 2137           }
 2138   
 2139           String jspFile = wrapper.getJspFile();
 2140           if ((jspFile != null) && !jspFile.startsWith("/")) {
 2141               if (isServlet22()) {
 2142                   if(log.isDebugEnabled())
 2143                       log.debug(sm.getString("standardContext.wrapper.warning", 
 2144                                          jspFile));
 2145                   wrapper.setJspFile("/" + jspFile);
 2146               } else {
 2147                   throw new IllegalArgumentException
 2148                       (sm.getString("standardContext.wrapper.error", jspFile));
 2149               }
 2150           }
 2151   
 2152           super.addChild(child);
 2153   
 2154           if (isJspServlet && oldJspServlet != null) {
 2155               /*
 2156                * The webapp-specific JspServlet inherits all the mappings
 2157                * specified in the global web.xml, and may add additional ones.
 2158                */
 2159               String[] jspMappings = oldJspServlet.findMappings();
 2160               for (int i=0; jspMappings!=null && i<jspMappings.length; i++) {
 2161                   addServletMapping(jspMappings[i], child.getName());
 2162               }
 2163           }
 2164       }
 2165   
 2166   
 2167       /**
 2168        * Add a security constraint to the set for this web application.
 2169        */
 2170       public void addConstraint(SecurityConstraint constraint) {
 2171   
 2172           // Validate the proposed constraint
 2173           SecurityCollection collections[] = constraint.findCollections();
 2174           for (int i = 0; i < collections.length; i++) {
 2175               String patterns[] = collections[i].findPatterns();
 2176               for (int j = 0; j < patterns.length; j++) {
 2177                   patterns[j] = adjustURLPattern(patterns[j]);
 2178                   if (!validateURLPattern(patterns[j]))
 2179                       throw new IllegalArgumentException
 2180                           (sm.getString
 2181                            ("standardContext.securityConstraint.pattern",
 2182                             patterns[j]));
 2183               }
 2184           }
 2185   
 2186           // Add this constraint to the set for our web application
 2187           synchronized (constraintsLock) {
 2188               SecurityConstraint results[] =
 2189                   new SecurityConstraint[constraints.length + 1];
 2190               for (int i = 0; i < constraints.length; i++)
 2191                   results[i] = constraints[i];
 2192               results[constraints.length] = constraint;
 2193               constraints = results;
 2194           }
 2195   
 2196       }
 2197   
 2198   
 2199   
 2200       /**
 2201        * Add an error page for the specified error or Java exception.
 2202        *
 2203        * @param errorPage The error page definition to be added
 2204        */
 2205       public void addErrorPage(ErrorPage errorPage) {
 2206           // Validate the input parameters
 2207           if (errorPage == null)
 2208               throw new IllegalArgumentException
 2209                   (sm.getString("standardContext.errorPage.required"));
 2210           String location = errorPage.getLocation();
 2211           if ((location != null) && !location.startsWith("/")) {
 2212               if (isServlet22()) {
 2213                   if(log.isDebugEnabled())
 2214                       log.debug(sm.getString("standardContext.errorPage.warning",
 2215                                    location));
 2216                   errorPage.setLocation("/" + location);
 2217               } else {
 2218                   throw new IllegalArgumentException
 2219                       (sm.getString("standardContext.errorPage.error",
 2220                                     location));
 2221               }
 2222           }
 2223   
 2224           // Add the specified error page to our internal collections
 2225           String exceptionType = errorPage.getExceptionType();
 2226           if (exceptionType != null) {
 2227               synchronized (exceptionPages) {
 2228                   exceptionPages.put(exceptionType, errorPage);
 2229               }
 2230           } else {
 2231               synchronized (statusPages) {
 2232                   if (errorPage.getErrorCode() == 200) {
 2233                       this.okErrorPage = errorPage;
 2234                   }
 2235                   statusPages.put(Integer.valueOf(errorPage.getErrorCode()),
 2236                                   errorPage);
 2237               }
 2238           }
 2239           fireContainerEvent("addErrorPage", errorPage);
 2240   
 2241       }
 2242   
 2243   
 2244       /**
 2245        * Add a filter definition to this Context.
 2246        *
 2247        * @param filterDef The filter definition to be added
 2248        */
 2249       public void addFilterDef(FilterDef filterDef) {
 2250   
 2251           synchronized (filterDefs) {
 2252               filterDefs.put(filterDef.getFilterName(), filterDef);
 2253           }
 2254           fireContainerEvent("addFilterDef", filterDef);
 2255   
 2256       }
 2257   
 2258   
 2259       /**
 2260        * Add a filter mapping to this Context.
 2261        *
 2262        * @param filterMap The filter mapping to be added
 2263        *
 2264        * @exception IllegalArgumentException if the specified filter name
 2265        *  does not match an existing filter definition, or the filter mapping
 2266        *  is malformed
 2267        */
 2268       public void addFilterMap(FilterMap filterMap) {
 2269   
 2270           // Validate the proposed filter mapping
 2271           String filterName = filterMap.getFilterName();
 2272           String[] servletNames = filterMap.getServletNames();
 2273           String[] urlPatterns = filterMap.getURLPatterns();
 2274           if (findFilterDef(filterName) == null)
 2275               throw new IllegalArgumentException
 2276                   (sm.getString("standardContext.filterMap.name", filterName));
 2277   //      <= Servlet API 2.4
 2278   //      if ((servletNames.length == 0) && (urlPatterns.length == 0))
 2279   //      Servlet API 2.5 (FIX 43338)
 2280   //      SRV 6.2.5 says supporting for '*' as the servlet-name in filter-mapping.
 2281           if (!filterMap.getMatchAllServletNames() && 
 2282               !filterMap.getMatchAllUrlPatterns() && 
 2283               (servletNames.length == 0) && (urlPatterns.length == 0))
 2284               throw new IllegalArgumentException
 2285                   (sm.getString("standardContext.filterMap.either"));
 2286           // FIXME: Older spec revisions may still check this
 2287           /*
 2288           if ((servletNames.length != 0) && (urlPatterns.length != 0))
 2289               throw new IllegalArgumentException
 2290                   (sm.getString("standardContext.filterMap.either"));
 2291           */
 2292           // Because filter-pattern is new in 2.3, no need to adjust
 2293           // for 2.2 backwards compatibility
 2294           for (int i = 0; i < urlPatterns.length; i++) {
 2295               if (!validateURLPattern(urlPatterns[i])) {
 2296                   throw new IllegalArgumentException
 2297                       (sm.getString("standardContext.filterMap.pattern",
 2298                               urlPatterns[i]));
 2299               }
 2300           }
 2301   
 2302           // Add this filter mapping to our registered set
 2303           synchronized (filterMaps) {
 2304               FilterMap results[] =new FilterMap[filterMaps.length + 1];
 2305               System.arraycopy(filterMaps, 0, results, 0, filterMaps.length);
 2306               results[filterMaps.length] = filterMap;
 2307               filterMaps = results;
 2308           }
 2309           fireContainerEvent("addFilterMap", filterMap);
 2310   
 2311       }
 2312   
 2313   
 2314       /**
 2315        * Add the classname of an InstanceListener to be added to each
 2316        * Wrapper appended to this Context.
 2317        *
 2318        * @param listener Java class name of an InstanceListener class
 2319        */
 2320       public void addInstanceListener(String listener) {
 2321   
 2322           synchronized (instanceListenersLock) {
 2323               String results[] =new String[instanceListeners.length + 1];
 2324               for (int i = 0; i < instanceListeners.length; i++)
 2325                   results[i] = instanceListeners[i];
 2326               results[instanceListeners.length] = listener;
 2327               instanceListeners = results;
 2328           }
 2329           fireContainerEvent("addInstanceListener", listener);
 2330   
 2331       }
 2332   
 2333       /**
 2334        * Add the given URL pattern as a jsp-property-group.  This maps
 2335        * resources that match the given pattern so they will be passed
 2336        * to the JSP container.  Though there are other elements in the
 2337        * property group, we only care about the URL pattern here.  The
 2338        * JSP container will parse the rest.
 2339        *
 2340        * @param pattern URL pattern to be mapped
 2341        */
 2342       public void addJspMapping(String pattern) {
 2343           String servletName = findServletMapping("*.jsp");
 2344           if (servletName == null) {
 2345               servletName = "jsp";
 2346           }
 2347   
 2348           if( findChild(servletName) != null) {
 2349               addServletMapping(pattern, servletName, true);
 2350           } else {
 2351               if(log.isDebugEnabled())
 2352                   log.debug("Skiping " + pattern + " , no servlet " + servletName);
 2353           }
 2354       }
 2355   
 2356   
 2357       /**
 2358        * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4)
 2359        *
 2360        * @param locale locale to map an encoding for
 2361        * @param encoding encoding to be used for a give locale
 2362        */
 2363       public void addLocaleEncodingMappingParameter(String locale, String encoding){
 2364           getCharsetMapper().addCharsetMappingFromDeploymentDescriptor(locale, encoding);
 2365       }
 2366   
 2367   
 2368       /**
 2369        * Add a message destination for this web application.
 2370        *
 2371        * @param md New message destination
 2372        */
 2373       public void addMessageDestination(MessageDestination md) {
 2374   
 2375           synchronized (messageDestinations) {
 2376               messageDestinations.put(md.getName(), md);
 2377           }
 2378           fireContainerEvent("addMessageDestination", md.getName());
 2379   
 2380       }
 2381   
 2382   
 2383       /**
 2384        * Add a message destination reference for this web application.
 2385        *
 2386        * @param mdr New message destination reference
 2387        */
 2388       public void addMessageDestinationRef
 2389           (MessageDestinationRef mdr) {
 2390   
 2391           namingResources.addMessageDestinationRef(mdr);
 2392           fireContainerEvent("addMessageDestinationRef", mdr.getName());
 2393   
 2394       }
 2395   
 2396   
 2397       /**
 2398        * Add a new MIME mapping, replacing any existing mapping for
 2399        * the specified extension.
 2400        *
 2401        * @param extension Filename extension being mapped
 2402        * @param mimeType Corresponding MIME type
 2403        */
 2404       public void addMimeMapping(String extension, String mimeType) {
 2405   
 2406           synchronized (mimeMappings) {
 2407               mimeMappings.put(extension, mimeType);
 2408           }
 2409           fireContainerEvent("addMimeMapping", extension);
 2410   
 2411       }
 2412   
 2413   
 2414       /**
 2415        * Add a new context initialization parameter.
 2416        *
 2417        * @param name Name of the new parameter
 2418        * @param value Value of the new  parameter
 2419        *
 2420        * @exception IllegalArgumentException if the name or value is missing,
 2421        *  or if this context initialization parameter has already been
 2422        *  registered
 2423        */
 2424       public void addParameter(String name, String value) {
 2425           // Validate the proposed context initialization parameter
 2426           if ((name == null) || (value == null))
 2427               throw new IllegalArgumentException
 2428                   (sm.getString("standardContext.parameter.required"));
 2429           if (parameters.get(name) != null)
 2430               throw new IllegalArgumentException
 2431                   (sm.getString("standardContext.parameter.duplicate", name));
 2432   
 2433           // Add this parameter to our defined set
 2434           synchronized (parameters) {
 2435               parameters.put(name, value);
 2436           }
 2437           fireContainerEvent("addParameter", name);
 2438   
 2439       }
 2440   
 2441   
 2442       /**
 2443        * Add a security role reference for this web application.
 2444        *
 2445        * @param role Security role used in the application
 2446        * @param link Actual security role to check for
 2447        */
 2448       public void addRoleMapping(String role, String link) {
 2449   
 2450           synchronized (roleMappings) {
 2451               roleMappings.put(role, link);
 2452           }
 2453           fireContainerEvent("addRoleMapping", role);
 2454   
 2455       }
 2456   
 2457   
 2458       /**
 2459        * Add a new security role for this web application.
 2460        *
 2461        * @param role New security role
 2462        */
 2463       public void addSecurityRole(String role) {
 2464   
 2465           synchronized (securityRolesLock) {
 2466               String results[] =new String[securityRoles.length + 1];
 2467               for (int i = 0; i < securityRoles.length; i++)
 2468                   results[i] = securityRoles[i];
 2469               results[securityRoles.length] = role;
 2470               securityRoles = results;
 2471           }
 2472           fireContainerEvent("addSecurityRole", role);
 2473   
 2474       }
 2475   
 2476   
 2477       /**
 2478        * Add a new servlet mapping, replacing any existing mapping for
 2479        * the specified pattern.
 2480        *
 2481        * @param pattern URL pattern to be mapped
 2482        * @param name Name of the corresponding servlet to execute
 2483        *
 2484        * @exception IllegalArgumentException if the specified servlet name
 2485        *  is not known to this Context
 2486        */
 2487       public void addServletMapping(String pattern, String name) {
 2488           addServletMapping(pattern, name, false);
 2489       }
 2490   
 2491   
 2492       /**
 2493        * Add a new servlet mapping, replacing any existing mapping for
 2494        * the specified pattern.
 2495        *
 2496        * @param pattern URL pattern to be mapped
 2497        * @param name Name of the corresponding servlet to execute
 2498        * @param jspWildCard true if name identifies the JspServlet
 2499        * and pattern contains a wildcard; false otherwise
 2500        *
 2501        * @exception IllegalArgumentException if the specified servlet name
 2502        *  is not known to this Context
 2503        */
 2504       public void addServletMapping(String pattern, String name,
 2505                                     boolean jspWildCard) {
 2506           // Validate the proposed mapping
 2507           if (findChild(name) == null)
 2508               throw new IllegalArgumentException
 2509                   (sm.getString("standardContext.servletMap.name", name));
 2510           pattern = adjustURLPattern(RequestUtil.URLDecode(pattern));
 2511           if (!validateURLPattern(pattern))
 2512               throw new IllegalArgumentException
 2513                   (sm.getString("standardContext.servletMap.pattern", pattern));
 2514   
 2515           // Add this mapping to our registered set
 2516           synchronized (servletMappingsLock) {
 2517               String name2 = (String) servletMappings.get(pattern);
 2518               if (name2 != null) {
 2519                   // Don't allow more than one servlet on the same pattern
 2520                   Wrapper wrapper = (Wrapper) findChild(name2);
 2521                   wrapper.removeMapping(pattern);
 2522                   mapper.removeWrapper(pattern);
 2523               }
 2524               servletMappings.put(pattern, name);
 2525           }
 2526           Wrapper wrapper = (Wrapper) findChild(name);
 2527           wrapper.addMapping(pattern);
 2528   
 2529           // Update context mapper
 2530           mapper.addWrapper(pattern, wrapper, jspWildCard);
 2531   
 2532           fireContainerEvent("addServletMapping", pattern);
 2533   
 2534       }
 2535   
 2536   
 2537       /**
 2538        * Add a JSP tag library for the specified URI.
 2539        *
 2540        * @param uri URI, relative to the web.xml file, of this tag library
 2541        * @param location Location of the tag library descriptor
 2542        */
 2543       public void addTaglib(String uri, String location) {
 2544   
 2545           synchronized (taglibs) {
 2546               taglibs.put(uri, location);
 2547           }
 2548           fireContainerEvent("addTaglib", uri);
 2549   
 2550       }
 2551   
 2552   
 2553       /**
 2554        * Add a new watched resource to the set recognized by this Context.
 2555        *
 2556        * @param name New watched resource file name
 2557        */
 2558       public void addWatchedResource(String name) {
 2559   
 2560           synchronized (watchedResourcesLock) {
 2561               String results[] = new String[watchedResources.length + 1];
 2562               for (int i = 0; i < watchedResources.length; i++)
 2563                   results[i] = watchedResources[i];
 2564               results[watchedResources.length] = name;
 2565               watchedResources = results;
 2566           }
 2567           fireContainerEvent("addWatchedResource", name);
 2568   
 2569       }
 2570   
 2571   
 2572       /**
 2573        * Add a new welcome file to the set recognized by this Context.
 2574        *
 2575        * @param name New welcome file name
 2576        */
 2577       public void addWelcomeFile(String name) {
 2578   
 2579           synchronized (welcomeFilesLock) {
 2580               // Welcome files from the application deployment descriptor
 2581               // completely replace those from the default conf/web.xml file
 2582               if (replaceWelcomeFiles) {
 2583                   welcomeFiles = new String[0];
 2584                   setReplaceWelcomeFiles(false);
 2585               }
 2586               String results[] =new String[welcomeFiles.length + 1];
 2587               for (int i = 0; i < welcomeFiles.length; i++)
 2588                   results[i] = welcomeFiles[i];
 2589               results[welcomeFiles.length] = name;
 2590               welcomeFiles = results;
 2591           }
 2592           postWelcomeFiles();
 2593           fireContainerEvent("addWelcomeFile", name);
 2594   
 2595       }
 2596   
 2597   
 2598       /**
 2599        * Add the classname of a LifecycleListener to be added to each
 2600        * Wrapper appended to this Context.
 2601        *
 2602        * @param listener Java class name of a LifecycleListener class
 2603        */
 2604       public void addWrapperLifecycle(String listener) {
 2605   
 2606           synchronized (wrapperLifecyclesLock) {
 2607               String results[] =new String[wrapperLifecycles.length + 1];
 2608               for (int i = 0; i < wrapperLifecycles.length; i++)
 2609                   results[i] = wrapperLifecycles[i];
 2610               results[wrapperLifecycles.length] = listener;
 2611               wrapperLifecycles = results;
 2612           }
 2613           fireContainerEvent("addWrapperLifecycle", listener);
 2614   
 2615       }
 2616   
 2617   
 2618       /**
 2619        * Add the classname of a ContainerListener to be added to each
 2620        * Wrapper appended to this Context.
 2621        *
 2622        * @param listener Java class name of a ContainerListener class
 2623        */
 2624       public void addWrapperListener(String listener) {
 2625   
 2626           synchronized (wrapperListenersLock) {
 2627               String results[] =new String[wrapperListeners.length + 1];
 2628               for (int i = 0; i < wrapperListeners.length; i++)
 2629                   results[i] = wrapperListeners[i];
 2630               results[wrapperListeners.length] = listener;
 2631               wrapperListeners = results;
 2632           }
 2633           fireContainerEvent("addWrapperListener", listener);
 2634   
 2635       }
 2636   
 2637   
 2638       /**
 2639        * Factory method to create and return a new Wrapper instance, of
 2640        * the Java implementation class appropriate for this Context
 2641        * implementation.  The constructor of the instantiated Wrapper
 2642        * will have been called, but no properties will have been set.
 2643        */
 2644       public Wrapper createWrapper() {
 2645   
 2646           Wrapper wrapper = null;
 2647           if (wrapperClass != null) {
 2648               try {
 2649                   wrapper = (Wrapper) wrapperClass.newInstance();
 2650               } catch (Throwable t) {
 2651                   log.error("createWrapper", t);
 2652                   return (null);
 2653               }
 2654           } else {
 2655               wrapper = new StandardWrapper();
 2656           }
 2657   
 2658           synchronized (instanceListenersLock) {
 2659               for (int i = 0; i < instanceListeners.length; i++) {
 2660                   try {
 2661                       Class clazz = Class.forName(instanceListeners[i]);
 2662                       InstanceListener listener =
 2663                         (InstanceListener) clazz.newInstance();
 2664                       wrapper.addInstanceListener(listener);
 2665                   } catch (Throwable t) {
 2666                       log.error("createWrapper", t);
 2667                       return (null);
 2668                   }
 2669               }
 2670           }
 2671   
 2672           synchronized (wrapperLifecyclesLock) {
 2673               for (int i = 0; i < wrapperLifecycles.length; i++) {
 2674                   try {
 2675                       Class clazz = Class.forName(wrapperLifecycles[i]);
 2676                       LifecycleListener listener =
 2677                         (LifecycleListener) clazz.newInstance();
 2678                       if (wrapper instanceof Lifecycle)
 2679                           ((Lifecycle) wrapper).addLifecycleListener(listener);
 2680                   } catch (Throwable t) {
 2681                       log.error("createWrapper", t);
 2682                       return (null);
 2683                   }
 2684               }
 2685           }
 2686   
 2687           synchronized (wrapperListenersLock) {
 2688               for (int i = 0; i < wrapperListeners.length; i++) {
 2689                   try {
 2690                       Class clazz = Class.forName(wrapperListeners[i]);
 2691                       ContainerListener listener =
 2692                         (ContainerListener) clazz.newInstance();
 2693                       wrapper.addContainerListener(listener);
 2694                   } catch (Throwable t) {
 2695                       log.error("createWrapper", t);
 2696                       return (null);
 2697                   }
 2698               }
 2699           }
 2700   
 2701           return (wrapper);
 2702   
 2703       }
 2704   
 2705   
 2706       /**
 2707        * Return the set of application listener class names configured
 2708        * for this application.
 2709        */
 2710       public String[] findApplicationListeners() {
 2711   
 2712           return (applicationListeners);
 2713   
 2714       }
 2715   
 2716   
 2717       /**
 2718        * Return the set of application parameters for this application.
 2719        */
 2720       public ApplicationParameter[] findApplicationParameters() {
 2721   
 2722           synchronized (applicationParametersLock) {
 2723               return (applicationParameters);
 2724           }
 2725   
 2726       }
 2727   
 2728   
 2729       /**
 2730        * Return the security constraints for this web application.
 2731        * If there are none, a zero-length array is returned.
 2732        */
 2733       public SecurityConstraint[] findConstraints() {
 2734   
 2735           return (constraints);
 2736   
 2737       }
 2738   
 2739   
 2740       /**
 2741        * Return the error page entry for the specified HTTP error code,
 2742        * if any; otherwise return <code>null</code>.
 2743        *
 2744        * @param errorCode Error code to look up
 2745        */
 2746       public ErrorPage findErrorPage(int errorCode) {
 2747           if (errorCode == 200) {
 2748               return (okErrorPage);
 2749           } else {
 2750               return ((ErrorPage) statusPages.get(new Integer(errorCode)));
 2751           }
 2752   
 2753       }
 2754   
 2755   
 2756       /**
 2757        * Return the error page entry for the specified Java exception type,
 2758        * if any; otherwise return <code>null</code>.
 2759        *
 2760        * @param exceptionType Exception type to look up
 2761        */
 2762       public ErrorPage findErrorPage(String exceptionType) {
 2763   
 2764           synchronized (exceptionPages) {
 2765               return ((ErrorPage) exceptionPages.get(exceptionType));
 2766           }
 2767   
 2768       }
 2769   
 2770   
 2771       /**
 2772        * Return the set of defined error pages for all specified error codes
 2773        * and exception types.
 2774        */
 2775       public ErrorPage[] findErrorPages() {
 2776   
 2777           synchronized(exceptionPages) {
 2778               synchronized(statusPages) {
 2779                   ErrorPage results1[] = new ErrorPage[exceptionPages.size()];
 2780                   results1 =
 2781                       (ErrorPage[]) exceptionPages.values().toArray(results1);
 2782                   ErrorPage results2[] = new ErrorPage[statusPages.size()];
 2783                   results2 =
 2784                       (ErrorPage[]) statusPages.values().toArray(results2);
 2785                   ErrorPage results[] =
 2786                       new ErrorPage[results1.length + results2.length];
 2787                   for (int i = 0; i < results1.length; i++)
 2788                       results[i] = results1[i];
 2789                   for (int i = results1.length; i < results.length; i++)
 2790                       results[i] = results2[i - results1.length];
 2791                   return (results);
 2792               }
 2793           }
 2794   
 2795       }
 2796   
 2797   
 2798       /**
 2799        * Return the filter definition for the specified filter name, if any;
 2800        * otherwise return <code>null</code>.
 2801        *
 2802        * @param filterName Filter name to look up
 2803        */
 2804       public FilterDef findFilterDef(String filterName) {
 2805   
 2806           synchronized (filterDefs) {
 2807               return ((FilterDef) filterDefs.get(filterName));
 2808           }
 2809   
 2810       }
 2811   
 2812   
 2813       /**
 2814        * Return the set of defined filters for this Context.
 2815        */
 2816       public FilterDef[] findFilterDefs() {
 2817   
 2818           synchronized (filterDefs) {
 2819               FilterDef results[] = new FilterDef[filterDefs.size()];
 2820               return ((FilterDef[]) filterDefs.values().toArray(results));
 2821           }
 2822   
 2823       }
 2824   
 2825   
 2826       /**
 2827        * Return the set of filter mappings for this Context.
 2828        */
 2829       public FilterMap[] findFilterMaps() {
 2830   
 2831           return (filterMaps);
 2832   
 2833       }
 2834   
 2835   
 2836       /**
 2837        * Return the set of InstanceListener classes that will be added to
 2838        * newly created Wrappers automatically.
 2839        */
 2840       public String[] findInstanceListeners() {
 2841   
 2842           synchronized (instanceListenersLock) {
 2843               return (instanceListeners);
 2844           }
 2845   
 2846       }
 2847   
 2848   
 2849       /**
 2850        * FIXME: Fooling introspection ...
 2851        */
 2852       public Context findMappingObject() {
 2853           return (Context) getMappingObject();
 2854       }
 2855       
 2856       
 2857       /**
 2858        * Return the message destination with the specified name, if any;
 2859        * otherwise, return <code>null</code>.
 2860        *
 2861        * @param name Name of the desired message destination
 2862        */
 2863       public MessageDestination findMessageDestination(String name) {
 2864   
 2865           synchronized (messageDestinations) {
 2866               return ((MessageDestination) messageDestinations.get(name));
 2867           }
 2868   
 2869       }
 2870   
 2871   
 2872       /**
 2873        * Return the set of defined message destinations for this web
 2874        * application.  If none have been defined, a zero-length array
 2875        * is returned.
 2876        */
 2877       public MessageDestination[] findMessageDestinations() {
 2878   
 2879           synchronized (messageDestinations) {
 2880               MessageDestination results[] =
 2881                   new MessageDestination[messageDestinations.size()];
 2882               return ((MessageDestination[])
 2883                       messageDestinations.values().toArray(results));
 2884           }
 2885   
 2886       }
 2887   
 2888   
 2889       /**
 2890        * Return the message destination ref with the specified name, if any;
 2891        * otherwise, return <code>null</code>.
 2892        *
 2893        * @param name Name of the desired message destination ref
 2894        */
 2895       public MessageDestinationRef
 2896           findMessageDestinationRef(String name) {
 2897   
 2898           return namingResources.findMessageDestinationRef(name);
 2899   
 2900       }
 2901   
 2902   
 2903       /**
 2904        * Return the set of defined message destination refs for this web
 2905        * application.  If none have been defined, a zero-length array
 2906        * is returned.
 2907        */
 2908       public MessageDestinationRef[]
 2909           findMessageDestinationRefs() {
 2910   
 2911           return namingResources.findMessageDestinationRefs();
 2912   
 2913       }
 2914   
 2915   
 2916       /**
 2917        * Return the MIME type to which the specified extension is mapped,
 2918        * if any; otherwise return <code>null</code>.
 2919        *
 2920        * @param extension Extension to map to a MIME type
 2921        */
 2922       public String findMimeMapping(String extension) {
 2923   
 2924           return ((String) mimeMappings.get(extension));
 2925   
 2926       }
 2927   
 2928   
 2929       /**
 2930        * Return the extensions for which MIME mappings are defined.  If there
 2931        * are none, a zero-length array is returned.
 2932        */
 2933       public String[] findMimeMappings() {
 2934   
 2935           synchronized (mimeMappings) {
 2936               String results[] = new String[mimeMappings.size()];
 2937               return
 2938                   ((String[]) mimeMappings.keySet().toArray(results));
 2939           }
 2940   
 2941       }
 2942   
 2943   
 2944       /**
 2945        * Return the value for the specified context initialization
 2946        * parameter name, if any; otherwise return <code>null</code>.
 2947        *
 2948        * @param name Name of the parameter to return
 2949        */
 2950       public String findParameter(String name) {
 2951   
 2952           synchronized (parameters) {
 2953               return ((String) parameters.get(name));
 2954           }
 2955   
 2956       }
 2957   
 2958   
 2959       /**
 2960        * Return the names of all defined context initialization parameters
 2961        * for this Context.  If no parameters are defined, a zero-length
 2962        * array is returned.
 2963        */
 2964       public String[] findParameters() {
 2965   
 2966           synchronized (parameters) {
 2967               String results[] = new String[parameters.size()];
 2968               return ((String[]) parameters.keySet().toArray(results));
 2969           }
 2970   
 2971       }
 2972   
 2973   
 2974       /**
 2975        * For the given security role (as used by an application), return the
 2976        * corresponding role name (as defined by the underlying Realm) if there
 2977        * is one.  Otherwise, return the specified role unchanged.
 2978        *
 2979        * @param role Security role to map
 2980        */
 2981       public String findRoleMapping(String role) {
 2982   
 2983           String realRole = null;
 2984           synchronized (roleMappings) {
 2985               realRole = (String) roleMappings.get(role);
 2986           }
 2987           if (realRole != null)
 2988               return (realRole);
 2989           else
 2990               return (role);
 2991   
 2992       }
 2993   
 2994   
 2995       /**
 2996        * Return <code>true</code> if the specified security role is defined
 2997        * for this application; otherwise return <code>false</code>.
 2998        *
 2999        * @param role Security role to verify
 3000        */
 3001       public boolean findSecurityRole(String role) {
 3002   
 3003           synchronized (securityRolesLock) {
 3004               for (int i = 0; i < securityRoles.length; i++) {
 3005                   if (role.equals(securityRoles[i]))
 3006                       return (true);
 3007               }
 3008           }
 3009           return (false);
 3010   
 3011       }
 3012   
 3013   
 3014       /**
 3015        * Return the security roles defined for this application.  If none
 3016        * have been defined, a zero-length array is returned.
 3017        */
 3018       public String[] findSecurityRoles() {
 3019   
 3020           synchronized (securityRolesLock) {
 3021               return (securityRoles);
 3022           }
 3023   
 3024       }
 3025   
 3026   
 3027       /**
 3028        * Return the servlet name mapped by the specified pattern (if any);
 3029        * otherwise return <code>null</code>.
 3030        *
 3031        * @param pattern Pattern for which a mapping is requested
 3032        */
 3033       public String findServletMapping(String pattern) {
 3034   
 3035           synchronized (servletMappingsLock) {
 3036               return ((String) servletMappings.get(pattern));
 3037           }
 3038   
 3039       }
 3040   
 3041   
 3042       /**
 3043        * Return the patterns of all defined servlet mappings for this
 3044        * Context.  If no mappings are defined, a zero-length array is returned.
 3045        */
 3046       public String[] findServletMappings() {
 3047   
 3048           synchronized (servletMappingsLock) {
 3049               String results[] = new String[servletMappings.size()];
 3050               return
 3051                  ((String[]) servletMappings.keySet().toArray(results));
 3052           }
 3053   
 3054       }
 3055   
 3056   
 3057       /**
 3058        * Return the context-relative URI of the error page for the specified
 3059        * HTTP status code, if any; otherwise return <code>null</code>.
 3060        *
 3061        * @param status HTTP status code to look up
 3062        */
 3063       public String findStatusPage(int status) {
 3064   
 3065           ErrorPage errorPage = (ErrorPage)statusPages.get(new Integer(status));
 3066           if (errorPage!=null) {
 3067               return errorPage.getLocation();
 3068           }
 3069           return null;
 3070   
 3071       }
 3072   
 3073   
 3074       /**
 3075        * Return the set of HTTP status codes for which error pages have
 3076        * been specified.  If none are specified, a zero-length array
 3077        * is returned.
 3078        */
 3079       public int[] findStatusPages() {
 3080   
 3081           synchronized (statusPages) {
 3082               int results[] = new int[statusPages.size()];
 3083               Iterator elements = statusPages.keySet().iterator();
 3084               int i = 0;
 3085               while (elements.hasNext())
 3086                   results[i++] = ((Integer) elements.next()).intValue();
 3087               return (results);
 3088           }
 3089   
 3090       }
 3091   
 3092   
 3093       /**
 3094        * Return the tag library descriptor location for the specified taglib
 3095        * URI, if any; otherwise, return <code>null</code>.
 3096        *
 3097        * @param uri URI, relative to the web.xml file
 3098        */
 3099       public String findTaglib(String uri) {
 3100   
 3101           synchronized (taglibs) {
 3102               return ((String) taglibs.get(uri));
 3103           }
 3104   
 3105       }
 3106   
 3107   
 3108       /**
 3109        * Return the URIs of all tag libraries for which a tag library
 3110        * descriptor location has been specified.  If none are specified,
 3111        * a zero-length array is returned.
 3112        */
 3113       public String[] findTaglibs() {
 3114   
 3115           synchronized (taglibs) {
 3116               String results[] = new String[taglibs.size()];
 3117               return ((String[]) taglibs.keySet().toArray(results));
 3118           }
 3119   
 3120       }
 3121   
 3122   
 3123       /**
 3124        * Return <code>true</code> if the specified welcome file is defined
 3125        * for this Context; otherwise return <code>false</code>.
 3126        *
 3127        * @param name Welcome file to verify
 3128        */
 3129       public boolean findWelcomeFile(String name) {
 3130   
 3131           synchronized (welcomeFilesLock) {
 3132               for (int i = 0; i < welcomeFiles.length; i++) {
 3133                   if (name.equals(welcomeFiles[i]))
 3134                       return (true);
 3135               }
 3136           }
 3137           return (false);
 3138   
 3139       }
 3140   
 3141   
 3142       /**
 3143        * Return the set of watched resources for this Context. If none are 
 3144        * defined, a zero length array will be returned.
 3145        */
 3146       public String[] findWatchedResources() {
 3147           synchronized (watchedResourcesLock) {
 3148               return watchedResources;
 3149           }
 3150       }
 3151       
 3152       
 3153       /**
 3154        * Return the set of welcome files defined for this Context.  If none are
 3155        * defined, a zero-length array is returned.
 3156        */
 3157       public String[] findWelcomeFiles() {
 3158   
 3159           synchronized (welcomeFilesLock) {
 3160               return (welcomeFiles);
 3161           }
 3162   
 3163       }
 3164   
 3165   
 3166       /**
 3167        * Return the set of LifecycleListener classes that will be added to
 3168        * newly created Wrappers automatically.
 3169        */
 3170       public String[] findWrapperLifecycles() {
 3171   
 3172           synchronized (wrapperLifecyclesLock) {
 3173               return (wrapperLifecycles);
 3174           }
 3175   
 3176       }
 3177   
 3178   
 3179       /**
 3180        * Return the set of ContainerListener classes that will be added to
 3181        * newly created Wrappers automatically.
 3182        */
 3183       public String[] findWrapperListeners() {
 3184   
 3185           synchronized (wrapperListenersLock) {
 3186               return (wrapperListeners);
 3187           }
 3188   
 3189       }
 3190   
 3191   
 3192       /**
 3193        * Reload this web application, if reloading is supported.
 3194        * <p>
 3195        * <b>IMPLEMENTATION NOTE</b>:  This method is designed to deal with
 3196        * reloads required by changes to classes in the underlying repositories
 3197        * of our class loader.  It does not handle changes to the web application
 3198        * deployment descriptor.  If that has occurred, you should stop this
 3199        * Context and create (and start) a new Context instance instead.
 3200        *
 3201        * @exception IllegalStateException if the <code>reloadable</code>
 3202        *  property is set to <code>false</code>.
 3203        */
 3204       public synchronized void reload() {
 3205   
 3206           // Validate our current component state
 3207           if (!started)
 3208               throw new IllegalStateException
 3209                   (sm.getString("containerBase.notStarted", logName()));
 3210   
 3211           // Make sure reloading is enabled
 3212           //      if (!reloadable)
 3213           //          throw new IllegalStateException
 3214           //              (sm.getString("standardContext.notReloadable"));
 3215           if(log.isInfoEnabled())
 3216               log.info(sm.getString("standardContext.reloadingStarted"));
 3217   
 3218           // Stop accepting requests temporarily
 3219           setPaused(true);
 3220   
 3221           try {
 3222               stop();
 3223           } catch (LifecycleException e) {
 3224               log.error(sm.getString("standardContext.stoppingContext"), e);
 3225           }
 3226   
 3227           try {
 3228               start();
 3229           } catch (LifecycleException e) {
 3230               log.error(sm.getString("standardContext.startingContext"), e);
 3231           }
 3232   
 3233           setPaused(false);
 3234   
 3235       }
 3236   
 3237   
 3238       /**
 3239        * Remove the specified application listener class from the set of
 3240        * listeners for this application.
 3241        *
 3242        * @param listener Java class name of the listener to be removed
 3243        */
 3244       public void removeApplicationListener(String listener) {
 3245   
 3246           synchronized (applicationListenersLock) {
 3247   
 3248               // Make sure this welcome file is currently present
 3249               int n = -1;
 3250               for (int i = 0; i < applicationListeners.length; i++) {
 3251                   if (applicationListeners[i].equals(listener)) {
 3252                       n = i;
 3253                       break;
 3254                   }
 3255               }
 3256               if (n < 0)
 3257                   return;
 3258   
 3259               // Remove the specified constraint
 3260               int j = 0;
 3261               String results[] = new String[applicationListeners.length - 1];
 3262               for (int i = 0; i < applicationListeners.length; i++) {
 3263                   if (i != n)
 3264                       results[j++] = applicationListeners[i];
 3265               }
 3266               applicationListeners = results;
 3267   
 3268           }
 3269   
 3270           // Inform interested listeners
 3271           fireContainerEvent("removeApplicationListener", listener);
 3272   
 3273           // FIXME - behavior if already started?
 3274   
 3275       }
 3276   
 3277   
 3278       /**
 3279        * Remove the application parameter with the specified name from
 3280        * the set for this application.
 3281        *
 3282        * @param name Name of the application parameter to remove
 3283        */
 3284       public void removeApplicationParameter(String name) {
 3285   
 3286           synchronized (applicationParametersLock) {
 3287   
 3288               // Make sure this parameter is currently present
 3289               int n = -1;
 3290               for (int i = 0; i < applicationParameters.length; i++) {
 3291                   if (name.equals(applicationParameters[i].getName())) {
 3292                       n = i;
 3293                       break;
 3294                   }
 3295               }
 3296               if (n < 0)
 3297                   return;
 3298   
 3299               // Remove the specified parameter
 3300               int j = 0;
 3301               ApplicationParameter results[] =
 3302                   new ApplicationParameter[applicationParameters.length - 1];
 3303               for (int i = 0; i < applicationParameters.length; i++) {
 3304                   if (i != n)
 3305                       results[j++] = applicationParameters[i];
 3306               }
 3307               applicationParameters = results;
 3308   
 3309           }
 3310   
 3311           // Inform interested listeners
 3312           fireContainerEvent("removeApplicationParameter", name);
 3313   
 3314       }
 3315   
 3316   
 3317       /**
 3318        * Add a child Container, only if the proposed child is an implementation
 3319        * of Wrapper.
 3320        *
 3321        * @param child Child container to be added
 3322        *
 3323        * @exception IllegalArgumentException if the proposed container is
 3324        *  not an implementation of Wrapper
 3325        */
 3326       public void removeChild(Container child) {
 3327   
 3328           if (!(child instanceof Wrapper)) {
 3329               throw new IllegalArgumentException
 3330                   (sm.getString("standardContext.notWrapper"));
 3331           }
 3332   
 3333           super.removeChild(child);
 3334   
 3335       }
 3336   
 3337   
 3338       /**
 3339        * Remove the specified security constraint from this web application.
 3340        *
 3341        * @param constraint Constraint to be removed
 3342        */
 3343       public void removeConstraint(SecurityConstraint constraint) {
 3344   
 3345           synchronized (constraintsLock) {
 3346   
 3347               // Make sure this constraint is currently present
 3348               int n = -1;
 3349               for (int i = 0; i < constraints.length; i++) {
 3350                   if (constraints[i].equals(constraint)) {
 3351                       n = i;
 3352                       break;
 3353                   }
 3354               }
 3355               if (n < 0)
 3356                   return;
 3357   
 3358               // Remove the specified constraint
 3359               int j = 0;
 3360               SecurityConstraint results[] =
 3361                   new SecurityConstraint[constraints.length - 1];
 3362               for (int i = 0; i < constraints.length; i++) {
 3363                   if (i != n)
 3364                       results[j++] = constraints[i];
 3365               }
 3366               constraints = results;
 3367   
 3368           }
 3369   
 3370           // Inform interested listeners
 3371           fireContainerEvent("removeConstraint", constraint);
 3372   
 3373       }
 3374   
 3375   
 3376       /**
 3377        * Remove the error page for the specified error code or
 3378        * Java language exception, if it exists; otherwise, no action is taken.
 3379        *
 3380        * @param errorPage The error page definition to be removed
 3381        */
 3382       public void removeErrorPage(ErrorPage errorPage) {
 3383   
 3384           String exceptionType = errorPage.getExceptionType();
 3385           if (exceptionType != null) {
 3386               synchronized (exceptionPages) {
 3387                   exceptionPages.remove(exceptionType);
 3388               }
 3389           } else {
 3390               synchronized (statusPages) {
 3391                   if (errorPage.getErrorCode() == 200) {
 3392                       this.okErrorPage = null;
 3393                   }
 3394                   statusPages.remove(Integer.valueOf(errorPage.getErrorCode()));
 3395               }
 3396           }
 3397           fireContainerEvent("removeErrorPage", errorPage);
 3398   
 3399       }
 3400   
 3401   
 3402       /**
 3403        * Remove the specified filter definition from this Context, if it exists;
 3404        * otherwise, no action is taken.
 3405        *
 3406        * @param filterDef Filter definition to be removed
 3407        */
 3408       public void removeFilterDef(FilterDef filterDef) {
 3409   
 3410           synchronized (filterDefs) {
 3411               filterDefs.remove(filterDef.getFilterName());
 3412           }
 3413           fireContainerEvent("removeFilterDef", filterDef);
 3414   
 3415       }
 3416   
 3417   
 3418       /**
 3419        * Remove a filter mapping from this Context.
 3420        *
 3421        * @param filterMap The filter mapping to be removed
 3422        */
 3423       public void removeFilterMap(FilterMap filterMap) {
 3424   
 3425           synchronized (filterMapsLock) {
 3426   
 3427               // Make sure this filter mapping is currently present
 3428               int n = -1;
 3429               for (int i = 0; i < filterMaps.length; i++) {
 3430                   if (filterMaps[i] == filterMap) {
 3431                       n = i;
 3432                       break;
 3433                   }
 3434               }
 3435               if (n < 0)
 3436                   return;
 3437   
 3438               // Remove the specified filter mapping
 3439               FilterMap results[] = new FilterMap[filterMaps.length - 1];
 3440               System.arraycopy(filterMaps, 0, results, 0, n);
 3441               System.arraycopy(filterMaps, n + 1, results, n,
 3442                                (filterMaps.length - 1) - n);
 3443               filterMaps = results;
 3444   
 3445           }
 3446   
 3447           // Inform interested listeners
 3448           fireContainerEvent("removeFilterMap", filterMap);
 3449   
 3450       }
 3451   
 3452   
 3453       /**
 3454        * Remove a class name from the set of InstanceListener classes that
 3455        * will be added to newly created Wrappers.
 3456        *
 3457        * @param listener Class name of an InstanceListener class to be removed
 3458        */
 3459       public void removeInstanceListener(String listener) {
 3460   
 3461           synchronized (instanceListenersLock) {
 3462   
 3463               // Make sure this welcome file is currently present
 3464               int n = -1;
 3465               for (int i = 0; i < instanceListeners.length; i++) {
 3466                   if (instanceListeners[i].equals(listener)) {
 3467                       n = i;
 3468                       break;
 3469                   }
 3470               }
 3471               if (n < 0)
 3472                   return;
 3473   
 3474               // Remove the specified constraint
 3475               int j = 0;
 3476               String results[] = new String[instanceListeners.length - 1];
 3477               for (int i = 0; i < instanceListeners.length; i++) {
 3478                   if (i != n)
 3479                       results[j++] = instanceListeners[i];
 3480               }
 3481               instanceListeners = results;
 3482   
 3483           }
 3484   
 3485           // Inform interested listeners
 3486           fireContainerEvent("removeInstanceListener", listener);
 3487   
 3488       }
 3489   
 3490   
 3491       /**
 3492        * Remove any message destination with the specified name.
 3493        *
 3494        * @param name Name of the message destination to remove
 3495        */
 3496       public void removeMessageDestination(String name) {
 3497   
 3498           synchronized (messageDestinations) {
 3499               messageDestinations.remove(name);
 3500           }
 3501           fireContainerEvent("removeMessageDestination", name);
 3502   
 3503       }
 3504   
 3505   
 3506       /**
 3507        * Remove any message destination ref with the specified name.
 3508        *
 3509        * @param name Name of the message destination ref to remove
 3510        */
 3511       public void removeMessageDestinationRef(String name) {
 3512   
 3513           namingResources.removeMessageDestinationRef(name);
 3514           fireContainerEvent("removeMessageDestinationRef", name);
 3515   
 3516       }
 3517   
 3518   
 3519       /**
 3520        * Remove the MIME mapping for the specified extension, if it exists;
 3521        * otherwise, no action is taken.
 3522        *
 3523        * @param extension Extension to remove the mapping for
 3524        */
 3525       public void removeMimeMapping(String extension) {
 3526   
 3527           synchronized (mimeMappings) {
 3528               mimeMappings.remove(extension);
 3529           }
 3530           fireContainerEvent("removeMimeMapping", extension);
 3531   
 3532       }
 3533   
 3534   
 3535       /**
 3536        * Remove the context initialization parameter with the specified
 3537        * name, if it exists; otherwise, no action is taken.
 3538        *
 3539        * @param name Name of the parameter to remove
 3540        */
 3541       public void removeParameter(String name) {
 3542   
 3543           synchronized (parameters) {
 3544               parameters.remove(name);
 3545           }
 3546           fireContainerEvent("removeParameter", name);
 3547   
 3548       }
 3549   
 3550   
 3551       /**
 3552        * Remove any security role reference for the specified name
 3553        *
 3554        * @param role Security role (as used in the application) to remove
 3555        */
 3556       public void removeRoleMapping(String role) {
 3557   
 3558           synchronized (roleMappings) {
 3559               roleMappings.remove(role);
 3560           }
 3561           fireContainerEvent("removeRoleMapping", role);
 3562   
 3563       }
 3564   
 3565   
 3566       /**
 3567        * Remove any security role with the specified name.
 3568        *
 3569        * @param role Security role to remove
 3570        */
 3571       public void removeSecurityRole(String role) {
 3572   
 3573           synchronized (securityRolesLock) {
 3574   
 3575               // Make sure this security role is currently present
 3576               int n = -1;
 3577               for (int i = 0; i < securityRoles.length; i++) {
 3578                   if (role.equals(securityRoles[i])) {
 3579                       n = i;
 3580                       break;
 3581                   }
 3582               }
 3583               if (n < 0)
 3584                   return;
 3585   
 3586               // Remove the specified security role
 3587               int j = 0;
 3588               String results[] = new String[securityRoles.length - 1];
 3589               for (int i = 0; i < securityRoles.length; i++) {
 3590                   if (i != n)
 3591                       results[j++] = securityRoles[i];
 3592               }
 3593               securityRoles = results;
 3594   
 3595           }
 3596   
 3597           // Inform interested listeners
 3598           fireContainerEvent("removeSecurityRole", role);
 3599   
 3600       }
 3601   
 3602   
 3603       /**
 3604        * Remove any servlet mapping for the specified pattern, if it exists;
 3605        * otherwise, no action is taken.
 3606        *
 3607        * @param pattern URL pattern of the mapping to remove
 3608        */
 3609       public void removeServletMapping(String pattern) {
 3610   
 3611           String name = null;
 3612           synchronized (servletMappingsLock) {
 3613               name = (String) servletMappings.remove(pattern);
 3614           }
 3615           Wrapper wrapper = (Wrapper) findChild(name);
 3616           if( wrapper != null ) {
 3617               wrapper.removeMapping(pattern);
 3618           }
 3619           mapper.removeWrapper(pattern);
 3620           fireContainerEvent("removeServletMapping", pattern);
 3621   
 3622       }
 3623   
 3624   
 3625       /**
 3626        * Remove the tag library location forthe specified tag library URI.
 3627        *
 3628        * @param uri URI, relative to the web.xml file
 3629        */
 3630       public void removeTaglib(String uri) {
 3631   
 3632           synchronized (taglibs) {
 3633               taglibs.remove(uri);
 3634           }
 3635           fireContainerEvent("removeTaglib", uri);
 3636       }
 3637   
 3638   
 3639       /**
 3640        * Remove the specified watched resource name from the list associated
 3641        * with this Context.
 3642        * 
 3643        * @param name Name of the watched resource to be removed
 3644        */
 3645       public void removeWatchedResource(String name) {
 3646           
 3647           synchronized (watchedResourcesLock) {
 3648   
 3649               // Make sure this watched resource is currently present
 3650               int n = -1;
 3651               for (int i = 0; i < watchedResources.length; i++) {
 3652                   if (watchedResources[i].equals(name)) {
 3653                       n = i;
 3654                       break;
 3655                   }
 3656               }
 3657               if (n < 0)
 3658                   return;
 3659   
 3660               // Remove the specified watched resource
 3661               int j = 0;
 3662               String results[] = new String[watchedResources.length - 1];
 3663               for (int i = 0; i < watchedResources.length; i++) {
 3664                   if (i != n)
 3665                       results[j++] = watchedResources[i];
 3666               }
 3667               watchedResources = results;
 3668   
 3669           }
 3670   
 3671           fireContainerEvent("removeWatchedResource", name);
 3672   
 3673       }
 3674       
 3675       
 3676       /**
 3677        * Remove the specified welcome file name from the list recognized
 3678        * by this Context.
 3679        *
 3680        * @param name Name of the welcome file to be removed
 3681        */
 3682       public void removeWelcomeFile(String name) {
 3683   
 3684           synchronized (welcomeFilesLock) {
 3685   
 3686               // Make sure this welcome file is currently present
 3687               int n = -1;
 3688               for (int i = 0; i < welcomeFiles.length; i++) {
 3689                   if (welcomeFiles[i].equals(name)) {
 3690                       n = i;
 3691                       break;
 3692                   }
 3693               }
 3694               if (n < 0)
 3695                   return;
 3696   
 3697               // Remove the specified constraint
 3698               int j = 0;
 3699               String results[] = new String[welcomeFiles.length - 1];
 3700               for (int i = 0; i < welcomeFiles.length; i++) {
 3701                   if (i != n)
 3702                       results[j++] = welcomeFiles[i];
 3703               }
 3704               welcomeFiles = results;
 3705   
 3706           }
 3707   
 3708           // Inform interested listeners
 3709           postWelcomeFiles();
 3710           fireContainerEvent("removeWelcomeFile", name);
 3711   
 3712       }
 3713   
 3714   
 3715       /**
 3716        * Remove a class name from the set of LifecycleListener classes that
 3717        * will be added to newly created Wrappers.
 3718        *
 3719        * @param listener Class name of a LifecycleListener class to be removed
 3720        */
 3721       public void removeWrapperLifecycle(String listener) {
 3722   
 3723   
 3724           synchronized (wrapperLifecyclesLock) {
 3725   
 3726               // Make sure this welcome file is currently present
 3727               int n = -1;
 3728               for (int i = 0; i < wrapperLifecycles.length; i++) {
 3729                   if (wrapperLifecycles[i].equals(listener)) {
 3730                       n = i;
 3731                       break;
 3732                   }
 3733               }
 3734               if (n < 0)
 3735                   return;
 3736   
 3737               // Remove the specified constraint
 3738               int j = 0;
 3739               String results[] = new String[wrapperLifecycles.length - 1];
 3740               for (int i = 0; i < wrapperLifecycles.length; i++) {
 3741                   if (i != n)
 3742                       results[j++] = wrapperLifecycles[i];
 3743               }
 3744               wrapperLifecycles = results;
 3745   
 3746           }
 3747   
 3748           // Inform interested listeners
 3749           fireContainerEvent("removeWrapperLifecycle", listener);
 3750   
 3751       }
 3752   
 3753   
 3754       /**
 3755        * Remove a class name from the set of ContainerListener classes that
 3756        * will be added to newly created Wrappers.
 3757        *
 3758        * @param listener Class name of a ContainerListener class to be removed
 3759        */
 3760       public void removeWrapperListener(String listener) {
 3761   
 3762   
 3763           synchronized (wrapperListenersLock) {
 3764   
 3765               // Make sure this welcome file is currently present
 3766               int n = -1;
 3767               for (int i = 0; i < wrapperListeners.length; i++) {
 3768                   if (wrapperListeners[i].equals(listener)) {
 3769                       n = i;
 3770                       break;
 3771                   }
 3772               }
 3773               if (n < 0)
 3774                   return;
 3775   
 3776               // Remove the specified constraint
 3777               int j = 0;
 3778               String results[] = new String[wrapperListeners.length - 1];
 3779               for (int i = 0; i < wrapperListeners.length; i++) {
 3780                   if (i != n)
 3781                       results[j++] = wrapperListeners[i];
 3782               }
 3783               wrapperListeners = results;
 3784   
 3785           }
 3786   
 3787           // Inform interested listeners
 3788           fireContainerEvent("removeWrapperListener", listener);
 3789   
 3790       }
 3791   
 3792   
 3793       /**
 3794        * Gets the cumulative processing times of all servlets in this
 3795        * StandardContext.
 3796        *
 3797        * @return Cumulative processing times of all servlets in this
 3798        * StandardContext
 3799        */
 3800       public long getProcessingTime() {
 3801           
 3802           long result = 0;
 3803   
 3804           Container[] children = findChildren();
 3805           if (children != null) {
 3806               for( int i=0; i< children.length; i++ ) {
 3807                   result += ((StandardWrapper)children[i]).getProcessingTime();
 3808               }
 3809           }
 3810   
 3811           return result;
 3812       }
 3813   
 3814   
 3815       // --------------------------------------------------------- Public Methods
 3816   
 3817   
 3818       /**
 3819        * Configure and initialize the set of filters for this Context.
 3820        * Return <code>true</code> if all filter initialization completed
 3821        * successfully, or <code>false</code> otherwise.
 3822        */
 3823       public boolean filterStart() {
 3824   
 3825           if (getLogger().isDebugEnabled())
 3826               getLogger().debug("Starting filters");
 3827           // Instantiate and record a FilterConfig for each defined filter
 3828           boolean ok = true;
 3829           synchronized (filterConfigs) {
 3830               filterConfigs.clear();
 3831               Iterator names = filterDefs.keySet().iterator();
 3832               while (names.hasNext()) {
 3833                   String name = (String) names.next();
 3834                   if (getLogger().isDebugEnabled())
 3835                       getLogger().debug(" Starting filter '" + name + "'");
 3836                   ApplicationFilterConfig filterConfig = null;
 3837                   try {
 3838                       filterConfig = new ApplicationFilterConfig
 3839                         (this, (FilterDef) filterDefs.get(name));
 3840                       filterConfigs.put(name, filterConfig);
 3841                   } catch (Throwable t) {
 3842                       getLogger().error
 3843                           (sm.getString("standardContext.filterStart", name), t);
 3844                       ok = false;
 3845                   }
 3846               }
 3847           }
 3848   
 3849           return (ok);
 3850   
 3851       }
 3852   
 3853   
 3854       /**
 3855        * Finalize and release the set of filters for this Context.
 3856        * Return <code>true</code> if all filter finalization completed
 3857        * successfully, or <code>false</code> otherwise.
 3858        */
 3859       public boolean filterStop() {
 3860   
 3861           if (getLogger().isDebugEnabled())
 3862               getLogger().debug("Stopping filters");
 3863   
 3864           // Release all Filter and FilterConfig instances
 3865           synchronized (filterConfigs) {
 3866               Iterator names = filterConfigs.keySet().iterator();
 3867               while (names.hasNext()) {
 3868                   String name = (String) names.next();
 3869                   if (getLogger().isDebugEnabled())
 3870                       getLogger().debug(" Stopping filter '" + name + "'");
 3871                   ApplicationFilterConfig filterConfig =
 3872                     (ApplicationFilterConfig) filterConfigs.get(name);
 3873                   filterConfig.release();
 3874               }
 3875               filterConfigs.clear();
 3876           }
 3877           return (true);
 3878   
 3879       }
 3880   
 3881   
 3882       /**
 3883        * Find and return the initialized <code>FilterConfig</code> for the
 3884        * specified filter name, if any; otherwise return <code>null</code>.
 3885        *
 3886        * @param name Name of the desired filter
 3887        */
 3888       public FilterConfig findFilterConfig(String name) {
 3889   
 3890           return ((FilterConfig) filterConfigs.get(name));
 3891   
 3892       }
 3893   
 3894   
 3895       /**
 3896        * Configure the set of instantiated application event listeners
 3897        * for this Context.  Return <code>true</code> if all listeners wre
 3898        * initialized successfully, or <code>false</code> otherwise.
 3899        */
 3900       public boolean listenerStart() {
 3901   
 3902           if (log.isDebugEnabled())
 3903               log.debug("Configuring application event listeners");
 3904   
 3905           // Instantiate the required listeners
 3906           ClassLoader loader = getLoader().getClassLoader();
 3907           String listeners[] = findApplicationListeners();
 3908           Object results[] = new Object[listeners.length];
 3909           boolean ok = true;
 3910           for (int i = 0; i < results.length; i++) {
 3911               if (getLogger().isDebugEnabled())
 3912                   getLogger().debug(" Configuring event listener class '" +
 3913                       listeners[i] + "'");
 3914               try {
 3915                   Class clazz = loader.loadClass(listeners[i]);
 3916                   results[i] = clazz.newInstance();
 3917                   // Annotation processing
 3918                   if (!getIgnoreAnnotations()) {
 3919                       getAnnotationProcessor().processAnnotations(results[i]);
 3920                       getAnnotationProcessor().postConstruct(results[i]);
 3921                   }
 3922               } catch (Throwable t) {
 3923                   getLogger().error
 3924                       (sm.getString("standardContext.applicationListener",
 3925                                     listeners[i]), t);
 3926                   ok = false;
 3927               }
 3928           }
 3929           if (!ok) {
 3930               getLogger().error(sm.getString("standardContext.applicationSkipped"));
 3931               return (false);
 3932           }
 3933   
 3934           // Sort listeners in two arrays
 3935           ArrayList eventListeners = new ArrayList();
 3936           ArrayList lifecycleListeners = new ArrayList();
 3937           for (int i = 0; i < results.length; i++) {
 3938               if ((results[i] instanceof ServletContextAttributeListener)
 3939                   || (results[i] instanceof ServletRequestAttributeListener)
 3940                   || (results[i] instanceof ServletRequestListener)
 3941                   || (results[i] instanceof HttpSessionAttributeListener)) {
 3942                   eventListeners.add(results[i]);
 3943               }
 3944               if ((results[i] instanceof ServletContextListener)
 3945                   || (results[i] instanceof HttpSessionListener)) {
 3946                   lifecycleListeners.add(results[i]);
 3947               }
 3948           }
 3949   
 3950           setApplicationEventListeners(eventListeners.toArray());
 3951           setApplicationLifecycleListeners(lifecycleListeners.toArray());
 3952   
 3953           // Send application start events
 3954   
 3955           if (getLogger().isDebugEnabled())
 3956               getLogger().debug("Sending application start events");
 3957   
 3958           Object instances[] = getApplicationLifecycleListeners();
 3959           if (instances == null)
 3960               return (ok);
 3961           ServletContextEvent event =
 3962             new ServletContextEvent(getServletContext());
 3963           for (int i = 0; i < instances.length; i++) {
 3964               if (instances[i] == null)
 3965                   continue;
 3966               if (!(instances[i] instanceof ServletContextListener))
 3967                   continue;
 3968               ServletContextListener listener =
 3969                   (ServletContextListener) instances[i];
 3970               try {
 3971                   fireContainerEvent("beforeContextInitialized", listener);
 3972                   listener.contextInitialized(event);
 3973                   fireContainerEvent("afterContextInitialized", listener);
 3974               } catch (Throwable t) {
 3975                   fireContainerEvent("afterContextInitialized", listener);
 3976                   getLogger().error
 3977                       (sm.getString("standardContext.listenerStart",
 3978                                     instances[i].getClass().getName()), t);
 3979                   ok = false;
 3980               }
 3981           }
 3982           return (ok);
 3983   
 3984       }
 3985   
 3986   
 3987       /**
 3988        * Send an application stop event to all interested listeners.
 3989        * Return <code>true</code> if all events were sent successfully,
 3990        * or <code>false</code> otherwise.
 3991        */
 3992       public boolean listenerStop() {
 3993   
 3994           if (log.isDebugEnabled())
 3995               log.debug("Sending application stop events");
 3996   
 3997           boolean ok = true;
 3998           Object listeners[] = getApplicationLifecycleListeners();
 3999           if (listeners != null) {
 4000               ServletContextEvent event =
 4001                   new ServletContextEvent(getServletContext());
 4002               for (int i = 0; i < listeners.length; i++) {
 4003                   int j = (listeners.length - 1) - i;
 4004                   if (listeners[j] == null)
 4005                       continue;
 4006                   if (listeners[j] instanceof ServletContextListener) {
 4007                       ServletContextListener listener =
 4008                           (ServletContextListener) listeners[j];
 4009                       try {
 4010                           fireContainerEvent("beforeContextDestroyed", listener);
 4011                           listener.contextDestroyed(event);
 4012                           fireContainerEvent("afterContextDestroyed", listener);
 4013                       } catch (Throwable t) {
 4014                           fireContainerEvent("afterContextDestroyed", listener);
 4015                           getLogger().error
 4016                               (sm.getString("standardContext.listenerStop",
 4017                                   listeners[j].getClass().getName()), t);
 4018                           ok = false;
 4019                       }
 4020                   }
 4021                   // Annotation processing
 4022                   if (!getIgnoreAnnotations()) {
 4023                       try {
 4024                           getAnnotationProcessor().preDestroy(listeners[j]);
 4025                       } catch (Throwable t) {
 4026                           getLogger().error
 4027                               (sm.getString("standardContext.listenerStop",
 4028                                   listeners[j].getClass().getName()), t);
 4029                           ok = false;
 4030                       }
 4031                   }
 4032               }
 4033           }
 4034   
 4035           // Annotation processing
 4036           listeners = getApplicationEventListeners();
 4037           if (!getIgnoreAnnotations() && listeners != null) {
 4038               for (int i = 0; i < listeners.length; i++) {
 4039                   int j = (listeners.length - 1) - i;
 4040                   if (listeners[j] == null)
 4041                       continue;
 4042                   try {
 4043                       getAnnotationProcessor().preDestroy(listeners[j]);
 4044                   } catch (Throwable t) {
 4045                       getLogger().error
 4046                           (sm.getString("standardContext.listenerStop",
 4047                               listeners[j].getClass().getName()), t);
 4048                       ok = false;
 4049                   }
 4050               }
 4051           }
 4052           
 4053           setApplicationEventListeners(null);
 4054           setApplicationLifecycleListeners(null);
 4055   
 4056           return (ok);
 4057   
 4058       }
 4059   
 4060   
 4061       /**
 4062        * Allocate resources, including proxy.
 4063        * Return <code>true</code> if initialization was successfull,
 4064        * or <code>false</code> otherwise.
 4065        */
 4066       public boolean resourcesStart() {
 4067   
 4068           boolean ok = true;
 4069   
 4070           Hashtable env = new Hashtable();
 4071           if (getParent() != null)
 4072               env.put(ProxyDirContext.HOST, getParent().getName());
 4073           env.put(ProxyDirContext.CONTEXT, getName());
 4074   
 4075           try {
 4076               ProxyDirContext proxyDirContext =
 4077                   new ProxyDirContext(env, webappResources);
 4078               if (webappResources instanceof FileDirContext) {
 4079                   filesystemBased = true;
 4080                   ((FileDirContext) webappResources).setCaseSensitive
 4081                       (isCaseSensitive());
 4082                   ((FileDirContext) webappResources).setAllowLinking
 4083                       (isAllowLinking());
 4084               }
 4085               if (webappResources instanceof BaseDirContext) {
 4086                   ((BaseDirContext) webappResources).setDocBase(getBasePath());
 4087                   ((BaseDirContext) webappResources).setCached
 4088                       (isCachingAllowed());
 4089                   ((BaseDirContext) webappResources).setCacheTTL(getCacheTTL());
 4090                   ((BaseDirContext) webappResources).setCacheMaxSize
 4091                       (getCacheMaxSize());
 4092                   ((BaseDirContext) webappResources).allocate();
 4093               }
 4094               // Register the cache in JMX
 4095               if (isCachingAllowed()) {
 4096                   ObjectName resourcesName = 
 4097                       new ObjectName(this.getDomain() + ":type=Cache,host=" 
 4098                                      + getHostname() + ",path=" 
 4099                                      + (("".equals(getPath()))?"/":getPath()));
 4100                   Registry.getRegistry(null, null).registerComponent
 4101                       (proxyDirContext.getCache(), resourcesName, null);
 4102               }
 4103               this.resources = proxyDirContext;
 4104           } catch (Throwable t) {
 4105               log.error(sm.getString("standardContext.resourcesStart"), t);
 4106               ok = false;
 4107           }
 4108   
 4109           return (ok);
 4110   
 4111       }
 4112   
 4113   
 4114       /**
 4115        * Deallocate resources and destroy proxy.
 4116        */
 4117       public boolean resourcesStop() {
 4118   
 4119           boolean ok = true;
 4120   
 4121           try {
 4122               if (resources != null) {
 4123                   if (resources instanceof Lifecycle) {
 4124                       ((Lifecycle) resources).stop();
 4125                   }
 4126                   if (webappResources instanceof BaseDirContext) {
 4127                       ((BaseDirContext) webappResources).release();
 4128                   }
 4129                   // Unregister the cache in JMX
 4130                   if (isCachingAllowed()) {
 4131                       ObjectName resourcesName = 
 4132                           new ObjectName(this.getDomain()
 4133                                          + ":type=Cache,host=" 
 4134                                          + getHostname() + ",path=" 
 4135                                          + (("".equals(getPath()))?"/"
 4136                                             :getPath()));
 4137                       Registry.getRegistry(null, null)
 4138                           .unregisterComponent(resourcesName);
 4139                   }
 4140               }
 4141           } catch (Throwable t) {
 4142               log.error(sm.getString("standardContext.resourcesStop"), t);
 4143               ok = false;
 4144           }
 4145   
 4146           this.resources = null;
 4147   
 4148           return (ok);
 4149   
 4150       }
 4151   
 4152   
 4153       /**
 4154        * Load and initialize all servlets marked "load on startup" in the
 4155        * web application deployment descriptor.
 4156        *
 4157        * @param children Array of wrappers for all currently defined
 4158        *  servlets (including those not declared load on startup)
 4159        */
 4160       public void loadOnStartup(Container children[]) {
 4161   
 4162           // Collect "load on startup" servlets that need to be initialized
 4163           TreeMap map = new TreeMap();
 4164           for (int i = 0; i < children.length; i++) {
 4165               Wrapper wrapper = (Wrapper) children[i];
 4166               int loadOnStartup = wrapper.getLoadOnStartup();
 4167               if (loadOnStartup < 0)
 4168                   continue;
 4169               Integer key = Integer.valueOf(loadOnStartup);
 4170               ArrayList list = (ArrayList) map.get(key);
 4171               if (list == null) {
 4172                   list = new ArrayList();
 4173                   map.put(key, list);
 4174               }
 4175               list.add(wrapper);
 4176           }
 4177   
 4178           // Load the collected "load on startup" servlets
 4179           Iterator keys = map.keySet().iterator();
 4180           while (keys.hasNext()) {
 4181               Integer key = (Integer) keys.next();
 4182               ArrayList list = (ArrayList) map.get(key);
 4183               Iterator wrappers = list.iterator();
 4184               while (wrappers.hasNext()) {
 4185                   Wrapper wrapper = (Wrapper) wrappers.next();
 4186                   try {
 4187                       wrapper.load();
 4188                   } catch (ServletException e) {
 4189                       getLogger().error(sm.getString("standardWrapper.loadException",
 4190                                         getName()), StandardWrapper.getRootCause(e));
 4191                       // NOTE: load errors (including a servlet that throws
 4192                       // UnavailableException from tht init() method) are NOT
 4193                       // fatal to application startup
 4194                   }
 4195               }
 4196           }
 4197   
 4198       }
 4199   
 4200   
 4201       /**
 4202        * Start this Context component.
 4203        *
 4204        * @exception LifecycleException if a startup error occurs
 4205        */
 4206       public synchronized void start() throws LifecycleException {
 4207           //if (lazy ) return;
 4208           if (started) {
 4209               if(log.isInfoEnabled())
 4210                   log.info(sm.getString("containerBase.alreadyStarted", logName()));
 4211               return;
 4212           }
 4213           if( !initialized ) { 
 4214               try {
 4215                   init();
 4216               } catch( Exception ex ) {
 4217                   throw new LifecycleException("Error initializaing ", ex);
 4218               }
 4219           }
 4220           if(log.isDebugEnabled())
 4221               log.debug("Starting " + ("".equals(getName()) ? "ROOT" : getName()));
 4222   
 4223           // Set JMX object name for proper pipeline registration
 4224           preRegisterJMX();
 4225   
 4226           if ((oname != null) && 
 4227               (Registry.getRegistry(null, null).getMBeanServer().isRegistered(oname))) {
 4228               // As things depend on the JMX registration, the context
 4229               // must be reregistered again once properly initialized
 4230               Registry.getRegistry(null, null).unregisterComponent(oname);
 4231           }
 4232   
 4233           // Notify our interested LifecycleListeners
 4234           lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
 4235   
 4236           setAvailable(false);
 4237           setConfigured(false);
 4238           boolean ok = true;
 4239   
 4240           // Add missing components as necessary
 4241           if (webappResources == null) {   // (1) Required by Loader
 4242               if (log.isDebugEnabled())
 4243                   log.debug("Configuring default Resources");
 4244               try {
 4245                   if ((docBase != null) && (docBase.endsWith(".war")) && (!(new File(getBasePath())).isDirectory()))
 4246                       setResources(new WARDirContext());
 4247                   else
 4248                       setResources(new FileDirContext());
 4249               } catch (IllegalArgumentException e) {
 4250                   log.error("Error initializing resources: " + e.getMessage());
 4251                   ok = false;
 4252               }
 4253           }
 4254           if (ok) {
 4255               if (!resourcesStart()) {
 4256                   log.error( "Error in resourceStart()");
 4257                   ok = false;
 4258               }
 4259           }
 4260   
 4261           // Look for a realm - that may have been configured earlier. 
 4262           // If the realm is added after context - it'll set itself.
 4263           // TODO: what is the use case for this ? 
 4264           if( realm == null && mserver != null ) {
 4265               ObjectName realmName=null;
 4266               try {
 4267                   realmName=new ObjectName( getEngineName() + ":type=Realm,host=" + 
 4268                           getHostname() + ",path=" + getPath());
 4269                   if( mserver.isRegistered(realmName ) ) {
 4270                       mserver.invoke(realmName, "init", 
 4271                               new Object[] {},
 4272                               new String[] {}
 4273                       );            
 4274                   }
 4275               } catch( Throwable t ) {
 4276                   if(log.isDebugEnabled())
 4277                       log.debug("No realm for this host " + realmName);
 4278               }
 4279           }
 4280           
 4281           if (getLoader() == null) {
 4282               WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
 4283               webappLoader.setDelegate(getDelegate());
 4284               setLoader(webappLoader);
 4285           }
 4286   
 4287           // Initialize character set mapper
 4288           getCharsetMapper();
 4289   
 4290           // Post work directory
 4291           postWorkDirectory();
 4292   
 4293           // Validate required extensions
 4294           boolean dependencyCheck = true;
 4295           try {
 4296               dependencyCheck = ExtensionValidator.validateApplication
 4297                   (getResources(), this);
 4298           } catch (IOException ioe) {
 4299               log.error("Error in dependencyCheck", ioe);
 4300               dependencyCheck = false;
 4301           }
 4302   
 4303           if (!dependencyCheck) {
 4304               // do not make application available if depency check fails
 4305               ok = false;
 4306           }
 4307   
 4308           // Reading the "catalina.useNaming" environment variable
 4309           String useNamingProperty = System.getProperty("catalina.useNaming");
 4310           if ((useNamingProperty != null)
 4311               && (useNamingProperty.equals("false"))) {
 4312               useNaming = false;
 4313           }
 4314   
 4315           if (ok && isUseNaming()) {
 4316               if (namingContextListener == null) {
 4317                   namingContextListener = new NamingContextListener();
 4318                   namingContextListener.setName(getNamingContextName());
 4319                   addLifecycleListener(namingContextListener);
 4320               }
 4321           }
 4322           
 4323           // Standard container startup
 4324           if (log.isDebugEnabled())
 4325               log.debug("Processing standard container startup");
 4326   
 4327           
 4328           // Binding thread
 4329           ClassLoader oldCCL = bindThread();
 4330   
 4331           boolean mainOk = false;
 4332   
 4333           try {
 4334   
 4335               if (ok) {
 4336                   
 4337                   started = true;
 4338   
 4339                   // Start our subordinate components, if any
 4340                   if ((loader != null) && (loader instanceof Lifecycle))
 4341                       ((Lifecycle) loader).start();
 4342   
 4343                   // Unbinding thread
 4344                   unbindThread(oldCCL);
 4345   
 4346                   // Binding thread
 4347                   oldCCL = bindThread();
 4348   
 4349                   // Initialize logger again. Other components might have used it too early, 
 4350                   // so it should be reset.
 4351                   logger = null;
 4352                   getLogger();
 4353                   if ((logger != null) && (logger instanceof Lifecycle))
 4354                       ((Lifecycle) logger).start();
 4355                   
 4356                   if ((cluster != null) && (cluster instanceof Lifecycle))
 4357                       ((Lifecycle) cluster).start();
 4358                   if ((realm != null) && (realm instanceof Lifecycle))
 4359                       ((Lifecycle) realm).start();
 4360                   if ((resources != null) && (resources instanceof Lifecycle))
 4361                       ((Lifecycle) resources).start();
 4362   
 4363                   // Start our child containers, if any
 4364                   Container children[] = findChildren();
 4365                   for (int i = 0; i < children.length; i++) {
 4366                       if (children[i] instanceof Lifecycle)
 4367                           ((Lifecycle) children[i]).start();
 4368                   }
 4369   
 4370                   // Start the Valves in our pipeline (including the basic),
 4371                   // if any
 4372                   if (pipeline instanceof Lifecycle) {
 4373                       ((Lifecycle) pipeline).start();
 4374                   }
 4375                   
 4376                   // Notify our interested LifecycleListeners
 4377                   lifecycle.fireLifecycleEvent(START_EVENT, null);
 4378                   
 4379                   // Acquire clustered manager
 4380                   Manager contextManager = null;
 4381                   if (manager == null) {
 4382                       if ( (getCluster() != null) && distributable) {
 4383                           try {
 4384                               contextManager = getCluster().createManager(getName());
 4385                           } catch (Exception ex) {
 4386                               log.error("standardContext.clusterFail", ex);
 4387                               ok = false;
 4388                           }
 4389                       } else {
 4390                           contextManager = new StandardManager();
 4391                       }
 4392                   } 
 4393                   
 4394                   // Configure default manager if none was specified
 4395                   if (contextManager != null) {
 4396                       setManager(contextManager);
 4397                   }
 4398   
 4399                   if (manager!=null && (getCluster() != null) && distributable) {
 4400                       //let the cluster know that there is a context that is distributable
 4401                       //and that it has its own manager
 4402                       getCluster().registerManager(manager);
 4403                   }
 4404   
 4405                   
 4406                   mainOk = true;
 4407   
 4408               }
 4409   
 4410           } finally {
 4411               // Unbinding thread
 4412               unbindThread(oldCCL);
 4413               if (!mainOk) {
 4414                   // An exception occurred
 4415                   // Register with JMX anyway, to allow management
 4416                   registerJMX();
 4417               }
 4418           }
 4419   
 4420           if (!getConfigured()) {
 4421               log.error( "Error getConfigured");
 4422               ok = false;
 4423           }
 4424   
 4425           // We put the resources into the servlet context
 4426           if (ok)
 4427               getServletContext().setAttribute
 4428                   (Globals.RESOURCES_ATTR, getResources());
 4429   
 4430           // Initialize associated mapper
 4431           mapper.setContext(getPath(), welcomeFiles, resources);
 4432   
 4433           // Binding thread
 4434           oldCCL = bindThread();
 4435   
 4436           // Set annotation processing parameter for Jasper (unfortunately, since
 4437           // this can be configured in many places and not just in /WEB-INF/web.xml,
 4438           // there are not many solutions)
 4439           // Initialize annotation processor
 4440           if (ok && !getIgnoreAnnotations()) {
 4441               if (annotationProcessor == null) {
 4442                   if (isUseNaming() && namingContextListener != null) {
 4443                       annotationProcessor = 
 4444                           new DefaultAnnotationProcessor(namingContextListener.getEnvContext());
 4445                   } else {
 4446                       annotationProcessor = new DefaultAnnotationProcessor(null);
 4447                   }
 4448               }
 4449               getServletContext().setAttribute
 4450                   (AnnotationProcessor.class.getName(), annotationProcessor);
 4451           }
 4452   
 4453           try {
 4454               
 4455               // Create context attributes that will be required
 4456               if (ok) {
 4457                   postWelcomeFiles();
 4458               }
 4459               
 4460               if (ok) {
 4461                   // Notify our interested LifecycleListeners
 4462                   lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
 4463               }
 4464               
 4465               // Configure and call application event listeners
 4466               if (ok) {
 4467                   if (!listenerStart()) {
 4468                       log.error( "Error listenerStart");
 4469                       ok = false;
 4470                   }
 4471               }
 4472               
 4473               try {
 4474                   // Start manager
 4475                   if ((manager != null) && (manager instanceof Lifecycle)) {
 4476                       ((Lifecycle) getManager()).start();
 4477                   }
 4478       
 4479                   // Start ContainerBackgroundProcessor thread
 4480                   super.threadStart();
 4481               } catch(Exception e) {
 4482                   log.error("Error manager.start()", e);
 4483                   ok = false;
 4484               }
 4485   
 4486               // Configure and call application filters
 4487               if (ok) {
 4488                   if (!filterStart()) {
 4489                       log.error( "Error filterStart");
 4490                       ok = false;
 4491                   }
 4492               }
 4493               
 4494               // Load and initialize all "load on startup" servlets
 4495               if (ok) {
 4496                   loadOnStartup(findChildren());
 4497               }
 4498               
 4499           } finally {
 4500               // Unbinding thread
 4501               unbindThread(oldCCL);
 4502           }
 4503   
 4504           // Set available status depending upon startup success
 4505           if (ok) {
 4506               if (log.isDebugEnabled())
 4507                   log.debug("Starting completed");
 4508               setAvailable(true);
 4509           } else {
 4510               log.error(sm.getString("standardContext.startFailed", getName()));
 4511               try {
 4512                   stop();
 4513               } catch (Throwable t) {
 4514                   log.error(sm.getString("standardContext.startCleanup"), t);
 4515               }
 4516               setAvailable(false);
 4517           }
 4518   
 4519           // JMX registration
 4520           registerJMX();
 4521   
 4522           startTime=System.currentTimeMillis();
 4523           
 4524           // Send j2ee.state.running notification 
 4525           if (ok && (this.getObjectName() != null)) {
 4526               Notification notification = 
 4527                   new Notification("j2ee.state.running", this.getObjectName(), 
 4528                                   sequenceNumber++);
 4529               broadcaster.sendNotification(notification);
 4530           }
 4531   
 4532           // Close all JARs right away to avoid always opening a peak number 
 4533           // of files on startup
 4534           if (getLoader() instanceof WebappLoader) {
 4535               ((WebappLoader) getLoader()).closeJARs(true);
 4536           }
 4537   
 4538           // Reinitializing if something went wrong
 4539           if (!ok && started) {
 4540               stop();
 4541           }
 4542   
 4543           //cacheContext();
 4544       }
 4545   
 4546       
 4547       private void cacheContext() {
 4548           try {
 4549               File workDir=new File( getWorkPath() );
 4550               
 4551               File ctxSer=new File( workDir, "_tomcat_context.ser");
 4552               FileOutputStream fos=new FileOutputStream( ctxSer );
 4553               ObjectOutputStream oos=new ObjectOutputStream( fos );
 4554               oos.writeObject(this);
 4555               oos.close();
 4556               fos.close();
 4557           } catch( Throwable t ) {
 4558               if(log.isInfoEnabled())
 4559                   log.info("Error saving context.ser ", t);
 4560           }
 4561       }
 4562   
 4563       
 4564       /**
 4565        * Stop this Context component.
 4566        *
 4567        * @exception LifecycleException if a shutdown error occurs
 4568        */
 4569       public synchronized void stop() throws LifecycleException {
 4570   
 4571           // Validate and update our current component state
 4572           if (!started) {
 4573               if(log.isInfoEnabled())
 4574                   log.info(sm.getString("containerBase.notStarted", logName()));
 4575               return;
 4576           }
 4577   
 4578           // Notify our interested LifecycleListeners
 4579           lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
 4580           
 4581           // Send j2ee.state.stopping notification 
 4582           if (this.getObjectName() != null) {
 4583               Notification notification = 
 4584                   new Notification("j2ee.state.stopping", this.getObjectName(), 
 4585                                   sequenceNumber++);
 4586               broadcaster.sendNotification(notification);
 4587           }
 4588           
 4589           // Mark this application as unavailable while we shut down
 4590           setAvailable(false);
 4591   
 4592           // Binding thread
 4593           ClassLoader oldCCL = bindThread();
 4594   
 4595           try {
 4596   
 4597               // Stop our child containers, if any
 4598               Container[] children = findChildren();
 4599               for (int i = 0; i < children.length; i++) {
 4600                   if (children[i] instanceof Lifecycle)
 4601                       ((Lifecycle) children[i]).stop();
 4602               }
 4603   
 4604               // Stop our filters
 4605               filterStop();
 4606   
 4607               // Stop ContainerBackgroundProcessor thread
 4608               super.threadStop();
 4609   
 4610               if ((manager != null) && (manager instanceof Lifecycle)) {
 4611                   ((Lifecycle) manager).stop();
 4612               }
 4613   
 4614               // Stop our application listeners
 4615               listenerStop();
 4616   
 4617               // Finalize our character set mapper
 4618               setCharsetMapper(null);
 4619   
 4620               // Normal container shutdown processing
 4621               if (log.isDebugEnabled())
 4622                   log.debug("Processing standard container shutdown");
 4623               // Notify our interested LifecycleListeners
 4624               lifecycle.fireLifecycleEvent(STOP_EVENT, null);
 4625               started = false;
 4626   
 4627               // Stop the Valves in our pipeline (including the basic), if any
 4628               if (pipeline instanceof Lifecycle) {
 4629                   ((Lifecycle) pipeline).stop();
 4630               }
 4631   
 4632               // Clear all application-originated servlet context attributes
 4633               if (context != null)
 4634                   context.clearAttributes();
 4635   
 4636               // Stop resources
 4637               resourcesStop();
 4638   
 4639               if ((realm != null) && (realm instanceof Lifecycle)) {
 4640                   ((Lifecycle) realm).stop();
 4641               }
 4642               if ((cluster != null) && (cluster instanceof Lifecycle)) {
 4643                   ((Lifecycle) cluster).stop();
 4644               }
 4645               if ((logger != null) && (logger instanceof Lifecycle)) {
 4646                   ((Lifecycle) logger).stop();
 4647               }
 4648               if ((loader != null) && (loader instanceof Lifecycle)) {
 4649                   ((Lifecycle) loader).stop();
 4650               }
 4651   
 4652           } finally {
 4653   
 4654               // Unbinding thread
 4655               unbindThread(oldCCL);
 4656   
 4657           }
 4658   
 4659           // Send j2ee.state.stopped notification 
 4660           if (this.getObjectName() != null) {
 4661               Notification notification = 
 4662                   new Notification("j2ee.state.stopped", this.getObjectName(), 
 4663                                   sequenceNumber++);
 4664               broadcaster.sendNotification(notification);
 4665           }
 4666           
 4667           // Reset application context
 4668           context = null;
 4669   
 4670           // This object will no longer be visible or used. 
 4671           try {
 4672               resetContext();
 4673           } catch( Exception ex ) {
 4674               log.error( "Error reseting context " + this + " " + ex, ex );
 4675           }
 4676           
 4677           // Notify our interested LifecycleListeners
 4678           lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
 4679   
 4680           if (log.isDebugEnabled())
 4681               log.debug("Stopping complete");
 4682   
 4683       }
 4684   
 4685       /** Destroy needs to clean up the context completely.
 4686        * 
 4687        * The problem is that undoing all the config in start() and restoring 
 4688        * a 'fresh' state is impossible. After stop()/destroy()/init()/start()
 4689        * we should have the same state as if a fresh start was done - i.e
 4690        * read modified web.xml, etc. This can only be done by completely 
 4691        * removing the context object and remapping a new one, or by cleaning
 4692        * up everything.
 4693        * 
 4694        * XXX Should this be done in stop() ?
 4695        * 
 4696        */ 
 4697       public void destroy() throws Exception {
 4698           if( oname != null ) { 
 4699               // Send j2ee.object.deleted notification 
 4700               Notification notification = 
 4701                   new Notification("j2ee.object.deleted", this.getObjectName(), 
 4702                                   sequenceNumber++);
 4703               broadcaster.sendNotification(notification);
 4704           } 
 4705           super.destroy();
 4706   
 4707           // Notify our interested LifecycleListeners
 4708           lifecycle.fireLifecycleEvent(DESTROY_EVENT, null);
 4709   
 4710           synchronized (instanceListenersLock) {
 4711               instanceListeners = new String[0];
 4712           }
 4713   
 4714       }
 4715       
 4716       private void resetContext() throws Exception, MBeanRegistrationException {
 4717           // Restore the original state ( pre reading web.xml in start )
 4718           // If you extend this - override this method and make sure to clean up
 4719           children=new HashMap();
 4720           startupTime = 0;
 4721           startTime = 0;
 4722           tldScanTime = 0;
 4723   
 4724           // Bugzilla 32867
 4725           distributable = false;
 4726   
 4727           applicationListeners = new String[0];
 4728           applicationEventListenersObjects = new Object[0];
 4729           applicationLifecycleListenersObjects = new Object[0];
 4730           taglibs = new HashMap<String, String>();
 4731           
 4732           annotationProcessor = null;
 4733   
 4734           if(log.isDebugEnabled())
 4735               log.debug("resetContext " + oname);
 4736       }
 4737   
 4738       /**
 4739        * Return a String representation of this component.
 4740        */
 4741       public String toString() {
 4742   
 4743           StringBuffer sb = new StringBuffer();
 4744           if (getParent() != null) {
 4745               sb.append(getParent().toString());
 4746               sb.append(".");
 4747           }
 4748           sb.append("StandardContext[");
 4749           sb.append(getName());
 4750           sb.append("]");
 4751           return (sb.toString());
 4752   
 4753       }
 4754   
 4755   
 4756       // ------------------------------------------------------ Protected Methods
 4757   
 4758   
 4759       /**
 4760        * Adjust the URL pattern to begin with a leading slash, if appropriate
 4761        * (i.e. we are running a servlet 2.2 application).  Otherwise, return
 4762        * the specified URL pattern unchanged.
 4763        *
 4764        * @param urlPattern The URL pattern to be adjusted (if needed)
 4765        *  and returned
 4766        */
 4767       protected String adjustURLPattern(String urlPattern) {
 4768   
 4769           if (urlPattern == null)
 4770               return (urlPattern);
 4771           if (urlPattern.startsWith("/") || urlPattern.startsWith("*."))
 4772               return (urlPattern);
 4773           if (!isServlet22())
 4774               return (urlPattern);
 4775           if(log.isDebugEnabled())
 4776               log.debug(sm.getString("standardContext.urlPattern.patternWarning",
 4777                            urlPattern));
 4778           return ("/" + urlPattern);
 4779   
 4780       }
 4781   
 4782   
 4783       /**
 4784        * Are we processing a version 2.2 deployment descriptor?
 4785        */
 4786       protected boolean isServlet22() {
 4787   
 4788           if (this.publicId == null)
 4789               return (false);
 4790           if (this.publicId.equals
 4791               (org.apache.catalina.startup.Constants.WebDtdPublicId_22))
 4792               return (true);
 4793           else
 4794               return (false);
 4795   
 4796       }
 4797   
 4798   
 4799       /**
 4800        * Return a File object representing the base directory for the
 4801        * entire servlet container (i.e. the Engine container if present).
 4802        */
 4803       protected File engineBase() {
 4804           String base=System.getProperty("catalina.base");
 4805           if( base == null ) {
 4806               StandardEngine eng=(StandardEngine)this.getParent().getParent();
 4807               base=eng.getBaseDir();
 4808           }
 4809           return (new File(base));
 4810       }
 4811   
 4812   
 4813       // -------------------------------------------------------- Private Methods
 4814   
 4815   
 4816       /**
 4817        * Bind current thread, both for CL purposes and for JNDI ENC support
 4818        * during : startup, shutdown and realoading of the context.
 4819        *
 4820        * @return the previous context class loader
 4821        */
 4822       private ClassLoader bindThread() {
 4823   
 4824           ClassLoader oldContextClassLoader =
 4825               Thread.currentThread().getContextClassLoader();
 4826   
 4827           if (getResources() == null)
 4828               return oldContextClassLoader;
 4829   
 4830           if (getLoader().getClassLoader() != null) {
 4831               Thread.currentThread().setContextClassLoader
 4832                   (getLoader().getClassLoader());
 4833           }
 4834   
 4835           DirContextURLStreamHandler.bind(getResources());
 4836   
 4837           if (isUseNaming()) {
 4838               try {
 4839                   ContextBindings.bindThread(this, this);
 4840               } catch (NamingException e) {
 4841                   // Silent catch, as this is a normal case during the early
 4842                   // startup stages
 4843               }
 4844           }
 4845   
 4846           return oldContextClassLoader;
 4847   
 4848       }
 4849   
 4850   
 4851       /**
 4852        * Unbind thread.
 4853        */
 4854       private void unbindThread(ClassLoader oldContextClassLoader) {
 4855   
 4856           Thread.currentThread().setContextClassLoader(oldContextClassLoader);
 4857   
 4858           oldContextClassLoader = null;
 4859   
 4860           if (isUseNaming()) {
 4861               ContextBindings.unbindThread(this, this);
 4862           }
 4863   
 4864           DirContextURLStreamHandler.unbind();
 4865   
 4866       }
 4867   
 4868   
 4869   
 4870       /**
 4871        * Get base path.
 4872        */
 4873       protected String getBasePath() {
 4874           String docBase = null;
 4875           Container container = this;
 4876           while (container != null) {
 4877               if (container instanceof Host)
 4878                   break;
 4879               container = container.getParent();
 4880           }
 4881           File file = new File(getDocBase());
 4882           if (!file.isAbsolute()) {
 4883               if (container == null) {
 4884                   docBase = (new File(engineBase(), getDocBase())).getPath();
 4885               } else {
 4886                   // Use the "appBase" property of this container
 4887                   String appBase = ((Host) container).getAppBase();
 4888                   file = new File(appBase);
 4889                   if (!file.isAbsolute())
 4890                       file = new File(engineBase(), appBase);
 4891                   docBase = (new File(file, getDocBase())).getPath();
 4892               }
 4893           } else {
 4894               docBase = file.getPath();
 4895           }
 4896           return docBase;
 4897       }
 4898   
 4899   
 4900       /**
 4901        * Get app base.
 4902        */
 4903       protected String getAppBase() {
 4904           String appBase = null;
 4905           Container container = this;
 4906           while (container != null) {
 4907               if (container instanceof Host)
 4908                   break;
 4909               container = container.getParent();
 4910           }
 4911           if (container != null) {
 4912               appBase = ((Host) container).getAppBase();
 4913           }
 4914           return appBase;
 4915       }
 4916   
 4917   
 4918       /**
 4919        * Get config base.
 4920        */
 4921       public File getConfigBase() {
 4922           File configBase = 
 4923               new File(System.getProperty("catalina.base"), "conf");
 4924           if (!configBase.exists()) {
 4925               return null;
 4926           }
 4927           Container container = this;
 4928           Container host = null;
 4929           Container engine = null;
 4930           while (container != null) {
 4931               if (container instanceof Host)
 4932                   host = container;
 4933               if (container instanceof Engine)
 4934                   engine = container;
 4935               container = container.getParent();
 4936           }
 4937           if (engine != null) {
 4938               configBase = new File(configBase, engine.getName());
 4939           }
 4940           if (host != null) {
 4941               configBase = new File(configBase, host.getName());
 4942           }
 4943           if (saveConfig) {
 4944               configBase.mkdirs();
 4945           }
 4946           return configBase;
 4947       }
 4948   
 4949   
 4950       /**
 4951        * Given a context path, get the config file name.
 4952        */
 4953       protected String getDefaultConfigFile() {
 4954           String basename = null;
 4955           String path = getPath();
 4956           if (path.equals("")) {
 4957               basename = "ROOT";
 4958           } else {
 4959               basename = path.substring(1).replace('/', '#');
 4960           }
 4961           return (basename + ".xml");
 4962       }
 4963   
 4964   
 4965       /**
 4966        * Copy a file.
 4967        */
 4968       private boolean copy(File src, File dest) {
 4969           FileInputStream is = null;
 4970           FileOutputStream os = null;
 4971           try {
 4972               is = new FileInputStream(src);
 4973               os = new FileOutputStream(dest);
 4974               byte[] buf = new byte[4096];
 4975               while (true) {
 4976                   int len = is.read(buf);
 4977                   if (len < 0)
 4978                       break;
 4979                   os.write(buf, 0, len);
 4980               }
 4981               is.close();
 4982               os.close();
 4983           } catch (IOException e) {
 4984               return false;
 4985           } finally {
 4986               try {
 4987                   if (is != null) {
 4988                       is.close();
 4989                   }
 4990               } catch (Exception e) {
 4991                   // Ignore
 4992               }
 4993               try {
 4994                   if (os != null) {
 4995                       os.close();
 4996                   }
 4997               } catch (Exception e) {
 4998                   // Ignore
 4999               }
 5000           }
 5001           return true;
 5002       }
 5003   
 5004   
 5005       /**
 5006        * Get naming context full name.
 5007        */
 5008       private String getNamingContextName() {
 5009       if (namingContextName == null) {
 5010           Container parent = getParent();
 5011           if (parent == null) {
 5012           namingContextName = getName();
 5013           } else {
 5014           Stack stk = new Stack();
 5015           StringBuffer buff = new StringBuffer();
 5016           while (parent != null) {
 5017               stk.push(parent.getName());
 5018               parent = parent.getParent();
 5019           }
 5020           while (!stk.empty()) {
 5021               buff.append("/" + stk.pop());
 5022           }
 5023           buff.append(getName());
 5024           namingContextName = buff.toString();
 5025           }
 5026       }
 5027       return namingContextName;
 5028       }
 5029   
 5030       
 5031       /**
 5032        * Naming context listener accessor.
 5033        */
 5034       public NamingContextListener getNamingContextListener() {
 5035           return namingContextListener;
 5036       }
 5037       
 5038   
 5039       /**
 5040        * Naming context listener setter.
 5041        */
 5042       public void setNamingContextListener(NamingContextListener namingContextListener) {
 5043           this.namingContextListener = namingContextListener;
 5044       }
 5045       
 5046   
 5047       /**
 5048        * Return the request processing paused flag for this Context.
 5049        */
 5050       public boolean getPaused() {
 5051   
 5052           return (this.paused);
 5053   
 5054       }
 5055   
 5056   
 5057       /**
 5058        * Post a copy of our web application resources as a servlet context
 5059        * attribute.
 5060        */
 5061       private void postResources() {
 5062   
 5063           getServletContext().setAttribute
 5064               (Globals.RESOURCES_ATTR, getResources());
 5065   
 5066       }
 5067   
 5068   
 5069       /**
 5070        * Post a copy of our current list of welcome files as a servlet context
 5071        * attribute, so that the default servlet can find them.
 5072        */
 5073       private void postWelcomeFiles() {
 5074   
 5075           getServletContext().setAttribute("org.apache.catalina.WELCOME_FILES",
 5076                                            welcomeFiles);
 5077   
 5078       }
 5079   
 5080       public String getHostname() {
 5081           Container parentHost = getParent();
 5082           if (parentHost != null) {
 5083               hostName = parentHost.getName();
 5084           }
 5085           if ((hostName == null) || (hostName.length() < 1))
 5086               hostName = "_";
 5087           return hostName;
 5088       }
 5089   
 5090       /**
 5091        * Set the appropriate context attribute for our work directory.
 5092        */
 5093       private void postWorkDirectory() {
 5094   
 5095           // Acquire (or calculate) the work directory path
 5096           String workDir = getWorkDir();
 5097           if (workDir == null || workDir.length() == 0) {
 5098   
 5099               // Retrieve our parent (normally a host) name
 5100               String hostName = null;
 5101               String engineName = null;
 5102               String hostWorkDir = null;
 5103               Container parentHost = getParent();
 5104               if (parentHost != null) {
 5105                   hostName = parentHost.getName();
 5106                   if (parentHost instanceof StandardHost) {
 5107                       hostWorkDir = ((StandardHost)parentHost).getWorkDir();
 5108                   }
 5109                   Container parentEngine = parentHost.getParent();
 5110                   if (parentEngine != null) {
 5111                      engineName = parentEngine.getName();
 5112                   }
 5113               }
 5114               if ((hostName == null) || (hostName.length() < 1))
 5115                   hostName = "_";
 5116               if ((engineName == null) || (engineName.length() < 1))
 5117                   engineName = "_";
 5118   
 5119               String temp = getPath();
 5120               if (temp.startsWith("/"))
 5121                   temp = temp.substring(1);
 5122               temp = temp.replace('/', '_');
 5123               temp = temp.replace('\\', '_');
 5124               if (temp.length() < 1)
 5125                   temp = "_";
 5126               if (hostWorkDir != null ) {
 5127                   workDir = hostWorkDir + File.separator + temp;
 5128               } else {
 5129                   workDir = "work" + File.separator + engineName +
 5130                       File.separator + hostName + File.separator + temp;
 5131               }
 5132               setWorkDir(workDir);
 5133           }
 5134   
 5135           // Create this directory if necessary
 5136           File dir = new File(workDir);
 5137           if (!dir.isAbsolute()) {
 5138               File catalinaHome = engineBase();
 5139               String catalinaHomePath = null;
 5140               try {
 5141                   catalinaHomePath = catalinaHome.getCanonicalPath();
 5142                   dir = new File(catalinaHomePath, workDir);
 5143               } catch (IOException e) {
 5144               }
 5145           }
 5146           dir.mkdirs();
 5147   
 5148           // Set the appropriate servlet context attribute
 5149           getServletContext().setAttribute(Globals.WORK_DIR_ATTR, dir);
 5150           if (getServletContext() instanceof ApplicationContext)
 5151               ((ApplicationContext) getServletContext()).setAttributeReadOnly
 5152                   (Globals.WORK_DIR_ATTR);
 5153   
 5154       }
 5155   
 5156   
 5157       /**
 5158        * Set the request processing paused flag for this Context.
 5159        *
 5160        * @param paused The new request processing paused flag
 5161        */
 5162       private void setPaused(boolean paused) {
 5163   
 5164           this.paused = paused;
 5165   
 5166       }
 5167   
 5168   
 5169       /**
 5170        * Validate the syntax of a proposed <code>&lt;url-pattern&gt;</code>
 5171        * for conformance with specification requirements.
 5172        *
 5173        * @param urlPattern URL pattern to be validated
 5174        */
 5175       private boolean validateURLPattern(String urlPattern) {
 5176   
 5177           if (urlPattern == null)
 5178               return (false);
 5179           if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) {
 5180               return (false);
 5181           }
 5182           if (urlPattern.startsWith("*.")) {
 5183               if (urlPattern.indexOf('/') < 0) {
 5184                   checkUnusualURLPattern(urlPattern);
 5185                   return (true);
 5186               } else
 5187                   return (false);
 5188           }
 5189           if ( (urlPattern.startsWith("/")) &&
 5190                   (urlPattern.indexOf("*.") < 0)) {
 5191               checkUnusualURLPattern(urlPattern);
 5192               return (true);
 5193           } else
 5194               return (false);
 5195   
 5196       }
 5197   
 5198   
 5199       /**
 5200        * Check for unusual but valid <code>&lt;url-pattern&gt;</code>s.
 5201        * See Bugzilla 34805, 43079 & 43080
 5202        */
 5203       private void checkUnusualURLPattern(String urlPattern) {
 5204           if (log.isInfoEnabled()) {
 5205               if(urlPattern.endsWith("*") && (urlPattern.length() < 2 ||
 5206                       urlPattern.charAt(urlPattern.length()-2) != '/')) {
 5207                   log.info("Suspicious url pattern: \"" + urlPattern + "\"" +
 5208                           " in context [" + getName() + "] - see" +
 5209                           " section SRV.11.2 of the Servlet specification" );
 5210               }
 5211           }
 5212       }
 5213   
 5214   
 5215       // ------------------------------------------------------------- Operations
 5216   
 5217   
 5218       /**
 5219        * JSR77 deploymentDescriptor attribute
 5220        *
 5221        * @return string deployment descriptor 
 5222        */
 5223       public String getDeploymentDescriptor() {
 5224       
 5225           InputStream stream = null;
 5226           ServletContext servletContext = getServletContext();
 5227           if (servletContext != null) {
 5228               stream = servletContext.getResourceAsStream(
 5229                   org.apache.catalina.startup.Constants.ApplicationWebXml);
 5230           }
 5231           if (stream == null) {
 5232               return "";
 5233           }
 5234           BufferedReader br = new BufferedReader(
 5235                                   new InputStreamReader(stream));
 5236           StringBuffer sb = new StringBuffer();
 5237           String strRead = "";
 5238           try {
 5239               while (strRead != null) {
 5240                   sb.append(strRead);
 5241                   strRead = br.readLine();
 5242               }
 5243           } catch (IOException e) {
 5244               return "";
 5245           }
 5246   
 5247           return sb.toString(); 
 5248       
 5249       }
 5250       
 5251       
 5252       /**
 5253        * JSR77 servlets attribute
 5254        *
 5255        * @return list of all servlets ( we know about )
 5256        */
 5257       public String[] getServlets() {
 5258           
 5259           String[] result = null;
 5260   
 5261           Container[] children = findChildren();
 5262           if (children != null) {
 5263               result = new String[children.length];
 5264               for( int i=0; i< children.length; i++ ) {
 5265                   result[i] = ((StandardWrapper)children[i]).getObjectName();
 5266               }
 5267           }
 5268   
 5269           return result;
 5270       }
 5271       
 5272   
 5273       public ObjectName createObjectName(String hostDomain, ObjectName parentName)
 5274               throws MalformedObjectNameException
 5275       {
 5276           String onameStr;
 5277           StandardHost hst=(StandardHost)getParent();
 5278           
 5279           String pathName=getName();
 5280           String hostName=getParent().getName();
 5281           String name= "//" + ((hostName==null)? "DEFAULT" : hostName) +
 5282                   (("".equals(pathName))?"/":pathName );
 5283   
 5284           String suffix=",J2EEApplication=" +
 5285                   getJ2EEApplication() + ",J2EEServer=" +
 5286                   getJ2EEServer();
 5287   
 5288           onameStr="j2eeType=WebModule,name=" + name + suffix;
 5289           if( log.isDebugEnabled())
 5290               log.debug("Registering " + onameStr + " for " + oname);
 5291           
 5292           // default case - no domain explictely set.
 5293           if( getDomain() == null ) domain=hst.getDomain();
 5294   
 5295           ObjectName oname=new ObjectName(getDomain() + ":" + onameStr);
 5296           return oname;        
 5297       }    
 5298       
 5299       private void preRegisterJMX() {
 5300           try {
 5301               StandardHost host = (StandardHost) getParent();
 5302               if ((oname == null) 
 5303                   || (oname.getKeyProperty("j2eeType") == null)) {
 5304                   oname = createObjectName(host.getDomain(), host.getJmxName());
 5305                   controller = oname;
 5306               }
 5307           } catch(Exception ex) {
 5308               if(log.isInfoEnabled())
 5309                   log.info("Error registering ctx with jmx " + this + " " +
 5310                        oname + " " + ex.toString(), ex );
 5311           }
 5312       }
 5313   
 5314       private void registerJMX() {
 5315           try {
 5316               if (log.isDebugEnabled()) {
 5317                   log.debug("Checking for " + oname );
 5318               }
 5319               if(! Registry.getRegistry(null, null)
 5320                   .getMBeanServer().isRegistered(oname)) {
 5321                   controller = oname;
 5322                   Registry.getRegistry(null, null)
 5323                       .registerComponent(this, oname, null);
 5324                   
 5325                   // Send j2ee.object.created notification 
 5326                   if (this.getObjectName() != null) {
 5327                       Notification notification = new Notification(
 5328                                                           "j2ee.object.created", 
 5329                                                           this.getObjectName(), 
 5330                                                           sequenceNumber++);
 5331                       broadcaster.sendNotification(notification);
 5332                   }
 5333               }
 5334               Container children[] = findChildren();
 5335               for (int i=0; children!=null && i<children.length; i++) {
 5336                   ((StandardWrapper)children[i]).registerJMX( this );
 5337               }
 5338           } catch (Exception ex) {
 5339               if(log.isInfoEnabled())
 5340                   log.info("Error registering wrapper with jmx " + this + " " +
 5341                       oname + " " + ex.toString(), ex );
 5342           }
 5343       }
 5344   
 5345       /** There are 2 cases:
 5346        *   1.The context is created and registered by internal APIS
 5347        *   2. The context is created by JMX, and it'll self-register.
 5348        *
 5349        * @param server The server
 5350        * @param name The object name
 5351        * @return ObjectName The name of the object
 5352        * @throws Exception If an error occurs
 5353        */
 5354       public ObjectName preRegister(MBeanServer server,
 5355                                     ObjectName name)
 5356               throws Exception
 5357       {
 5358           if( oname != null ) {
 5359               //log.info( "Already registered " + oname + " " + name);
 5360               // Temporary - /admin uses the old names
 5361               return name;
 5362           }
 5363           ObjectName result=super.preRegister(server,name);
 5364           return name;
 5365       }
 5366   
 5367       public void preDeregister() throws Exception {
 5368           if( started ) {
 5369               try {
 5370                   stop();
 5371               } catch( Exception ex ) {
 5372                   log.error( "error stopping ", ex);
 5373               }
 5374           }
 5375       }
 5376   
 5377       public void init() throws Exception {
 5378   
 5379           if( this.getParent() == null ) {
 5380               ObjectName parentName=getParentName();
 5381               
 5382               if( ! mserver.isRegistered(parentName)) {
 5383                   if(log.isDebugEnabled())
 5384                       log.debug("No host, creating one " + parentName);
 5385                   StandardHost host=new StandardHost();
 5386                   host.setName(hostName);
 5387                   host.setAutoDeploy(false);
 5388                   Registry.getRegistry(null, null)
 5389                       .registerComponent(host, parentName, null);
 5390                   // We could do it the hard way...
 5391                   //mserver.invoke(parentName, "init", new Object[] {}, new String[] {} );
 5392                   // or same thing easier:
 5393                   host.init();
 5394               }
 5395               
 5396               // Add the main configuration listener
 5397               LifecycleListener config = null;
 5398               try {
 5399                   String configClassName = null;
 5400                   try {
 5401                       configClassName = String.valueOf(mserver.getAttribute(parentName, "configClass"));
 5402                   } catch (AttributeNotFoundException e) {
 5403                       // Ignore, it's normal a host may not have this optional attribute
 5404                   }
 5405                   if (configClassName != null) {
 5406                       Class clazz = Class.forName(configClassName);
 5407                       config = (LifecycleListener) clazz.newInstance();
 5408                   } else {
 5409                       config = new ContextConfig();
 5410                   }
 5411               } catch (Exception e) {
 5412                   log.warn("Error creating ContextConfig for " + parentName, e);
 5413                   throw e;
 5414               }
 5415               this.addLifecycleListener(config);
 5416   
 5417               if (log.isDebugEnabled()) {
 5418                   log.debug("AddChild " + parentName + " " + this);
 5419               }
 5420               try {
 5421                   mserver.invoke(parentName, "addChild", new Object[] { this },
 5422                           new String[] {"org.apache.catalina.Container"});
 5423               } catch (Exception e) {
 5424                   destroy();
 5425                   throw e;
 5426               }
 5427               // It's possible that addChild may have started us
 5428               if( initialized ) {
 5429                   return;
 5430               }
 5431           }
 5432           if (processTlds) {
 5433               this.addLifecycleListener(new TldConfig());
 5434           }
 5435   
 5436           super.init();
 5437           
 5438           // Notify our interested LifecycleListeners
 5439           lifecycle.fireLifecycleEvent(INIT_EVENT, null);
 5440   
 5441           // Send j2ee.state.starting notification 
 5442           if (this.getObjectName() != null) {
 5443               Notification notification = new Notification("j2ee.state.starting", 
 5444                                                           this.getObjectName(), 
 5445                                                           sequenceNumber++);
 5446               broadcaster.sendNotification(notification);
 5447           }
 5448           
 5449       }
 5450   
 5451       public ObjectName getParentName() throws MalformedObjectNameException {
 5452           // "Life" update
 5453           String path=oname.getKeyProperty("name");
 5454           if( path == null ) {
 5455               log.error( "No name attribute " +name );
 5456               return null;
 5457           }
 5458           if( ! path.startsWith( "//")) {
 5459               log.error("Invalid name " + name);
 5460           }
 5461           path=path.substring(2);
 5462           int delim=path.indexOf( "/" );
 5463           hostName="localhost"; // Should be default...
 5464           if( delim > 0 ) {
 5465               hostName=path.substring(0, delim);
 5466               path = path.substring(delim);
 5467               if (path.equals("/")) {
 5468                   this.setName("");
 5469               } else {
 5470                   this.setName(path);
 5471               }
 5472           } else {
 5473               if(log.isDebugEnabled())
 5474                   log.debug("Setting path " +  path );
 5475               this.setName( path );
 5476           }
 5477           // XXX The service and domain should be the same.
 5478           String parentDomain=getEngineName();
 5479           if( parentDomain == null ) parentDomain=domain;
 5480           ObjectName parentName=new ObjectName( parentDomain + ":" +
 5481                   "type=Host,host=" + hostName);
 5482           return parentName;
 5483       }
 5484       
 5485       public void create() throws Exception{
 5486           init();
 5487       }
 5488   
 5489       /* Remove a JMX notficationListener 
 5490        * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
 5491        */
 5492       public void removeNotificationListener(NotificationListener listener, 
 5493               NotificationFilter filter, Object object) throws ListenerNotFoundException {
 5494       	broadcaster.removeNotificationListener(listener,filter,object);
 5495       	
 5496       }
 5497       
 5498       private MBeanNotificationInfo[] notificationInfo;
 5499       
 5500       /* Get JMX Broadcaster Info
 5501        * @TODO use StringManager for international support!
 5502        * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed!
 5503        * @see javax.management.NotificationBroadcaster#getNotificationInfo()
 5504        */
 5505       public MBeanNotificationInfo[] getNotificationInfo() {
 5506       	// FIXME: i18n
 5507       	if(notificationInfo == null) {
 5508       		notificationInfo = new MBeanNotificationInfo[]{
 5509       				new MBeanNotificationInfo(new String[] {
 5510       				"j2ee.object.created"},
 5511   					Notification.class.getName(),
 5512   					"web application is created"
 5513       				), 
 5514   					new MBeanNotificationInfo(new String[] {
 5515   					"j2ee.state.starting"},
 5516   					Notification.class.getName(),
 5517   					"change web application is starting"
 5518   					),
 5519   					new MBeanNotificationInfo(new String[] {
 5520   					"j2ee.state.running"},
 5521   					Notification.class.getName(),
 5522   					"web application is running"
 5523   					),
 5524   					new MBeanNotificationInfo(new String[] {
 5525   					"j2ee.state.stopped"},
 5526   					Notification.class.getName(),
 5527   					"web application start to stopped"
 5528   					),
 5529   					new MBeanNotificationInfo(new String[] {
 5530   					"j2ee.object.stopped"},
 5531   					Notification.class.getName(),
 5532   					"web application is stopped"
 5533   					),
 5534   					new MBeanNotificationInfo(new String[] {
 5535   					"j2ee.object.deleted"},
 5536   					Notification.class.getName(),
 5537   					"web application is deleted"
 5538   					)
 5539       		};
 5540       		
 5541       	}
 5542       	
 5543       	return notificationInfo;
 5544       }
 5545       
 5546       
 5547       /* Add a JMX-NotificationListener
 5548        * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
 5549        */
 5550       public void addNotificationListener(NotificationListener listener, 
 5551               NotificationFilter filter, Object object) throws IllegalArgumentException {
 5552       	broadcaster.addNotificationListener(listener,filter,object);
 5553       	
 5554       }
 5555       
 5556       
 5557       /**
 5558        * Remove a JMX-NotificationListener 
 5559        * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener)
 5560        */
 5561       public void removeNotificationListener(NotificationListener listener) 
 5562       throws ListenerNotFoundException {
 5563       	broadcaster.removeNotificationListener(listener);
 5564       	
 5565       }
 5566       
 5567       
 5568       // ------------------------------------------------------------- Attributes
 5569   
 5570   
 5571       /**
 5572        * Return the naming resources associated with this web application.
 5573        */
 5574       public javax.naming.directory.DirContext getStaticResources() {
 5575   
 5576           return getResources();
 5577   
 5578       }
 5579   
 5580   
 5581       /**
 5582        * Return the naming resources associated with this web application.
 5583        * FIXME: Fooling introspection ... 
 5584        */
 5585       public javax.naming.directory.DirContext findStaticResources() {
 5586   
 5587           return getResources();
 5588   
 5589       }
 5590   
 5591   
 5592       /**
 5593        * Return the naming resources associated with this web application.
 5594        */
 5595       public String[] getWelcomeFiles() {
 5596   
 5597           return findWelcomeFiles();
 5598   
 5599       }
 5600   
 5601        /**
 5602        * Set the validation feature of the XML parser used when
 5603        * parsing xml instances.
 5604        * @param webXmlValidation true to enable xml instance validation
 5605        */
 5606       public void setXmlValidation(boolean webXmlValidation){
 5607           
 5608           this.webXmlValidation = webXmlValidation;
 5609   
 5610       }
 5611   
 5612       /**
 5613        * Get the server.xml <context> attribute's xmlValidation.
 5614        * @return true if validation is enabled.
 5615        *
 5616        */
 5617       public boolean getXmlValidation(){
 5618           return webXmlValidation;
 5619       }
 5620   
 5621   
 5622       /**
 5623        * Get the server.xml <context> attribute's xmlNamespaceAware.
 5624        * @return true if namespace awarenes is enabled.
 5625        */
 5626       public boolean getXmlNamespaceAware(){
 5627           return webXmlNamespaceAware;
 5628       }
 5629   
 5630   
 5631       /**
 5632        * Set the namespace aware feature of the XML parser used when
 5633        * parsing xml instances.
 5634        * @param webXmlNamespaceAware true to enable namespace awareness
 5635        */
 5636       public void setXmlNamespaceAware(boolean webXmlNamespaceAware){
 5637           this.webXmlNamespaceAware= webXmlNamespaceAware;
 5638       }    
 5639   
 5640   
 5641       /**
 5642        * Set the validation feature of the XML parser used when
 5643        * parsing tlds files. 
 5644        * @param tldValidation true to enable xml instance validation
 5645        */
 5646       public void setTldValidation(boolean tldValidation){
 5647           
 5648           this.tldValidation = tldValidation;
 5649   
 5650       }
 5651   
 5652       /**
 5653        * Get the server.xml <context> attribute's webXmlValidation.
 5654        * @return true if validation is enabled.
 5655        *
 5656        */
 5657       public boolean getTldValidation(){
 5658           return tldValidation;
 5659       }
 5660   
 5661       /**
 5662        * Sets the process TLDs attribute.
 5663        *
 5664        * @param newProcessTlds The new value
 5665        */
 5666       public void setProcessTlds(boolean newProcessTlds) {
 5667   	processTlds = newProcessTlds;
 5668       }
 5669   
 5670       /**
 5671        * Returns the processTlds attribute value.
 5672        */
 5673       public boolean getProcessTlds() {
 5674   	return processTlds;
 5675       }
 5676   
 5677       /**
 5678        * Get the server.xml &lt;host&gt; attribute's xmlNamespaceAware.
 5679        * @return true if namespace awarenes is enabled.
 5680        */
 5681       public boolean getTldNamespaceAware(){
 5682           return tldNamespaceAware;
 5683       }
 5684   
 5685   
 5686       /**
 5687        * Set the namespace aware feature of the XML parser used when
 5688        * parsing xml instances.
 5689        * @param tldNamespaceAware true to enable namespace awareness
 5690        */
 5691       public void setTldNamespaceAware(boolean tldNamespaceAware){
 5692           this.tldNamespaceAware= tldNamespaceAware;
 5693       }    
 5694   
 5695   
 5696       /** 
 5697        * Support for "stateManageable" JSR77 
 5698        */
 5699       public boolean isStateManageable() {
 5700           return true;
 5701       }
 5702       
 5703       public void startRecursive() throws LifecycleException {
 5704           // nothing to start recursive, the servlets will be started by load-on-startup
 5705           start();
 5706       }
 5707       
 5708       public int getState() {
 5709           if( started ) {
 5710               return 1; // RUNNING
 5711           }
 5712           if( initialized ) {
 5713               return 0; // starting ? 
 5714           }
 5715           if( ! available ) { 
 5716               return 4; //FAILED
 5717           }
 5718           // 2 - STOPPING
 5719           return 3; // STOPPED
 5720       }
 5721       
 5722       /**
 5723        * The J2EE Server ObjectName this module is deployed on.
 5724        */     
 5725       private String server = null;
 5726       
 5727       /**
 5728        * The Java virtual machines on which this module is running.
 5729        */       
 5730       private String[] javaVMs = null;
 5731       
 5732       public String getServer() {
 5733           return server;
 5734       }
 5735           
 5736       public String setServer(String server) {
 5737           return this.server=server;
 5738       }
 5739           
 5740       public String[] getJavaVMs() {
 5741           return javaVMs;
 5742       }
 5743           
 5744       public String[] setJavaVMs(String[] javaVMs) {
 5745           return this.javaVMs = javaVMs;
 5746       }
 5747       
 5748       /**
 5749        * Gets the time this context was started.
 5750        *
 5751        * @return Time (in milliseconds since January 1, 1970, 00:00:00) when this
 5752        * context was started 
 5753        */
 5754       public long getStartTime() {
 5755           return startTime;
 5756       }
 5757       
 5758       public boolean isEventProvider() {
 5759           return false;
 5760       }
 5761       
 5762       public boolean isStatisticsProvider() {
 5763           return false;
 5764       }
 5765       
 5766   }

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