Save This Page
Home » apache-tomcat-6.0.16-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: 615899 $ $Date: 2008-01-28 15:47:11 +0100 (lun., 28 janv. 2008) $
  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   
  207       /**
  208        * The set of instantiated application event listener objects</code>.
  209        */
  210       private transient Object applicationEventListenersObjects[] = 
  211           new Object[0];
  212   
  213   
  214       /**
  215        * The set of instantiated application lifecycle listener objects</code>.
  216        */
  217       private transient Object applicationLifecycleListenersObjects[] = 
  218           new Object[0];
  219   
  220   
  221       /**
  222        * The set of application parameters defined for this application.
  223        */
  224       private ApplicationParameter applicationParameters[] =
  225           new ApplicationParameter[0];
  226   
  227   
  228       /**
  229        * The application available flag for this Context.
  230        */
  231       private boolean available = false;
  232       
  233       /**
  234        * The broadcaster that sends j2ee notifications. 
  235        */
  236       private NotificationBroadcasterSupport broadcaster = null;
  237       
  238       /**
  239        * The Locale to character set mapper for this application.
  240        */
  241       private transient CharsetMapper charsetMapper = null;
  242   
  243   
  244       /**
  245        * The Java class name of the CharsetMapper class to be created.
  246        */
  247       private String charsetMapperClass =
  248         "org.apache.catalina.util.CharsetMapper";
  249   
  250   
  251       /**
  252        * The path to a file to save this Context information.
  253        */
  254       private String configFile = null;
  255   
  256   
  257       /**
  258        * The "correctly configured" flag for this Context.
  259        */
  260       private boolean configured = false;
  261   
  262   
  263       /**
  264        * The security constraints for this web application.
  265        */
  266       private SecurityConstraint constraints[] = new SecurityConstraint[0];
  267   
  268   
  269       /**
  270        * The ServletContext implementation associated with this Context.
  271        */
  272       protected transient ApplicationContext context = null;
  273   
  274   
  275       /**
  276        * Compiler classpath to use.
  277        */
  278       private String compilerClasspath = null;
  279   
  280   
  281       /**
  282        * Should we attempt to use cookies for session id communication?
  283        */
  284       private boolean cookies = true;
  285   
  286   
  287       /**
  288        * Should we allow the <code>ServletContext.getContext()</code> method
  289        * to access the context of other web applications in this server?
  290        */
  291       private boolean crossContext = false;
  292   
  293       
  294       /**
  295        * Encoded path.
  296        */
  297       private String encodedPath = null;
  298       
  299   
  300       /**
  301        * The "follow standard delegation model" flag that will be used to
  302        * configure our ClassLoader.
  303        */
  304       private boolean delegate = false;
  305   
  306   
  307       /**
  308        * The display name of this web application.
  309        */
  310       private String displayName = null;
  311   
  312   
  313       /** 
  314        * Override the default context xml location.
  315        */
  316       private String defaultContextXml;
  317   
  318   
  319       /** 
  320        * Override the default web xml location.
  321        */
  322       private String defaultWebXml;
  323   
  324   
  325       /**
  326        * The distributable flag for this web application.
  327        */
  328       private boolean distributable = false;
  329   
  330   
  331       /**
  332        * The document root for this web application.
  333        */
  334       private String docBase = null;
  335   
  336   
  337       /**
  338        * The exception pages for this web application, keyed by fully qualified
  339        * class name of the Java exception.
  340        */
  341       private HashMap exceptionPages = new HashMap();
  342   
  343   
  344       /**
  345        * The set of filter configurations (and associated filter instances) we
  346        * have initialized, keyed by filter name.
  347        */
  348       private HashMap filterConfigs = new HashMap();
  349   
  350   
  351       /**
  352        * The set of filter definitions for this application, keyed by
  353        * filter name.
  354        */
  355       private HashMap filterDefs = new HashMap();
  356   
  357   
  358       /**
  359        * The set of filter mappings for this application, in the order
  360        * they were defined in the deployment descriptor.
  361        */
  362       private FilterMap filterMaps[] = new FilterMap[0];
  363   
  364   
  365       /**
  366        * Ignore annotations.
  367        */
  368       private boolean ignoreAnnotations = false;
  369   
  370   
  371       /**
  372        * The set of classnames of InstanceListeners that will be added
  373        * to each newly created Wrapper by <code>createWrapper()</code>.
  374        */
  375       private String instanceListeners[] = new String[0];
  376   
  377   
  378       /**
  379        * The login configuration descriptor for this web application.
  380        */
  381       private LoginConfig loginConfig = null;
  382   
  383   
  384       /**
  385        * The mapper associated with this context.
  386        */
  387       private org.apache.tomcat.util.http.mapper.Mapper mapper = 
  388           new org.apache.tomcat.util.http.mapper.Mapper();
  389   
  390   
  391       /**
  392        * The naming context listener for this web application.
  393        */
  394       private transient NamingContextListener namingContextListener = null;
  395   
  396   
  397       /**
  398        * The naming resources for this web application.
  399        */
  400       private NamingResources namingResources = null;
  401   
  402   
  403       /**
  404        * The message destinations for this web application.
  405        */
  406       private HashMap messageDestinations = new HashMap();
  407   
  408   
  409       /**
  410        * The MIME mappings for this web application, keyed by extension.
  411        */
  412       private HashMap mimeMappings = new HashMap();
  413   
  414   
  415        /**
  416         * Special case: error page for status 200.
  417         */
  418        private ErrorPage okErrorPage = null;
  419   
  420   
  421       /**
  422        * The context initialization parameters for this web application,
  423        * keyed by name.
  424        */
  425       private HashMap parameters = new HashMap();
  426   
  427   
  428       /**
  429        * The request processing pause flag (while reloading occurs)
  430        */
  431       private boolean paused = false;
  432   
  433   
  434       /**
  435        * The public identifier of the DTD for the web application deployment
  436        * descriptor version we are currently parsing.  This is used to support
  437        * relaxed validation rules when processing version 2.2 web.xml files.
  438        */
  439       private String publicId = null;
  440   
  441   
  442       /**
  443        * The reloadable flag for this web application.
  444        */
  445       private boolean reloadable = false;
  446   
  447   
  448       /**
  449        * Unpack WAR property.
  450        */
  451       private boolean unpackWAR = true;
  452   
  453   
  454       /**
  455        * The DefaultContext override flag for this web application.
  456        */
  457       private boolean override = false;
  458   
  459   
  460       /**
  461        * The original document root for this web application.
  462        */
  463       private String originalDocBase = null;
  464       
  465       
  466       /**
  467        * The privileged flag for this web application.
  468        */
  469       private boolean privileged = false;
  470   
  471   
  472       /**
  473        * Should the next call to <code>addWelcomeFile()</code> cause replacement
  474        * of any existing welcome files?  This will be set before processing the
  475        * web application's deployment descriptor, so that application specified
  476        * choices <strong>replace</strong>, rather than append to, those defined
  477        * in the global descriptor.
  478        */
  479       private boolean replaceWelcomeFiles = false;
  480   
  481   
  482       /**
  483        * The security role mappings for this application, keyed by role
  484        * name (as used within the application).
  485        */
  486       private HashMap roleMappings = new HashMap();
  487   
  488   
  489       /**
  490        * The security roles for this application, keyed by role name.
  491        */
  492       private String securityRoles[] = new String[0];
  493   
  494   
  495       /**
  496        * The servlet mappings for this web application, keyed by
  497        * matching pattern.
  498        */
  499       private HashMap servletMappings = new HashMap();
  500   
  501   
  502       /**
  503        * The session timeout (in minutes) for this web application.
  504        */
  505       private int sessionTimeout = 30;
  506   
  507       /**
  508        * The notification sequence number.
  509        */
  510       private long sequenceNumber = 0;
  511       
  512       /**
  513        * The status code error pages for this web application, keyed by
  514        * HTTP status code (as an Integer).
  515        */
  516       private HashMap statusPages = new HashMap();
  517   
  518   
  519       /**
  520        * Set flag to true to cause the system.out and system.err to be redirected
  521        * to the logger when executing a servlet.
  522        */
  523       private boolean swallowOutput = false;
  524   
  525   
  526       /**
  527        * The JSP tag libraries for this web application, keyed by URI
  528        */
  529       private HashMap taglibs = new HashMap();
  530   
  531   
  532       /**
  533        * Amount of ms that the container will wait for servlets to unload.
  534        */
  535       private long unloadDelay = 2000;
  536   
  537   
  538       /**
  539        * The watched resources for this application.
  540        */
  541       private String watchedResources[] = new String[0];
  542   
  543   
  544       /**
  545        * The welcome files for this application.
  546        */
  547       private String welcomeFiles[] = new String[0];
  548   
  549   
  550       /**
  551        * The set of classnames of LifecycleListeners that will be added
  552        * to each newly created Wrapper by <code>createWrapper()</code>.
  553        */
  554       private String wrapperLifecycles[] = new String[0];
  555   
  556   
  557       /**
  558        * The set of classnames of ContainerListeners that will be added
  559        * to each newly created Wrapper by <code>createWrapper()</code>.
  560        */
  561       private String wrapperListeners[] = new String[0];
  562   
  563   
  564       /**
  565        * The pathname to the work directory for this context (relative to
  566        * the server's home if not absolute).
  567        */
  568       private String workDir = null;
  569   
  570   
  571       /**
  572        * Java class name of the Wrapper class implementation we use.
  573        */
  574       private String wrapperClassName = StandardWrapper.class.getName();
  575       private Class wrapperClass = null;
  576   
  577   
  578       /**
  579        * JNDI use flag.
  580        */
  581       private boolean useNaming = true;
  582   
  583   
  584       /**
  585        * Filesystem based flag.
  586        */
  587       private boolean filesystemBased = false;
  588   
  589   
  590       /**
  591        * Name of the associated naming context.
  592        */
  593       private String namingContextName = null;
  594   
  595   
  596       /**
  597        * Caching allowed flag.
  598        */
  599       private boolean cachingAllowed = true;
  600   
  601   
  602       /**
  603        * Case sensitivity.
  604        */
  605       protected boolean caseSensitive = true;
  606   
  607   
  608       /**
  609        * Allow linking.
  610        */
  611       protected boolean allowLinking = false;
  612   
  613   
  614       /**
  615        * Cache max size in KB.
  616        */
  617       protected int cacheMaxSize = 10240; // 10 MB
  618   
  619   
  620       /**
  621        * Cache TTL in ms.
  622        */
  623       protected int cacheTTL = 5000;
  624   
  625   
  626       private boolean lazy=true;
  627   
  628       /**
  629        * Non proxied resources.
  630        */
  631       private transient DirContext webappResources = null;
  632   
  633       private long startupTime;
  634       private long startTime;
  635       private long tldScanTime;
  636   
  637       /** 
  638        * Name of the engine. If null, the domain is used.
  639        */ 
  640       private String engineName = null;
  641       private String j2EEApplication="none";
  642       private String j2EEServer="none";
  643   
  644   
  645       /**
  646        * Attribute value used to turn on/off XML validation
  647        */
  648        private boolean webXmlValidation = false;
  649   
  650   
  651       /**
  652        * Attribute value used to turn on/off XML namespace validation
  653        */
  654        private boolean webXmlNamespaceAware = false;
  655   
  656       /**
  657        * Attribute value used to turn on/off TLD processing
  658        */
  659       private boolean processTlds = true;
  660   
  661       /**
  662        * Attribute value used to turn on/off XML validation
  663        */
  664        private boolean tldValidation = false;
  665   
  666   
  667       /**
  668        * Attribute value used to turn on/off TLD XML namespace validation
  669        */
  670        private boolean tldNamespaceAware = false;
  671   
  672   
  673       /**
  674        * Should we save the configuration.
  675        */
  676       private boolean saveConfig = true;
  677   
  678   
  679       // ----------------------------------------------------- Context Properties
  680   
  681   
  682       public AnnotationProcessor getAnnotationProcessor() {
  683          return annotationProcessor;
  684       }
  685   
  686   
  687       public void setAnnotationProcessor(AnnotationProcessor annotationProcessor) {
  688          this.annotationProcessor = annotationProcessor;
  689       }
  690   
  691       
  692       public String getEncodedPath() {
  693           return encodedPath;
  694       }
  695   
  696   
  697       public void setName( String name ) {
  698           super.setName( name );
  699           encodedPath = urlEncoder.encode(name);
  700       }
  701   
  702   
  703       /**
  704        * Is caching allowed ?
  705        */
  706       public boolean isCachingAllowed() {
  707           return cachingAllowed;
  708       }
  709   
  710   
  711       /**
  712        * Set caching allowed flag.
  713        */
  714       public void setCachingAllowed(boolean cachingAllowed) {
  715           this.cachingAllowed = cachingAllowed;
  716       }
  717   
  718   
  719       /**
  720        * Set case sensitivity.
  721        */
  722       public void setCaseSensitive(boolean caseSensitive) {
  723           this.caseSensitive = caseSensitive;
  724       }
  725   
  726   
  727       /**
  728        * Is case sensitive ?
  729        */
  730       public boolean isCaseSensitive() {
  731           return caseSensitive;
  732       }
  733   
  734   
  735       /**
  736        * Set allow linking.
  737        */
  738       public void setAllowLinking(boolean allowLinking) {
  739           this.allowLinking = allowLinking;
  740       }
  741   
  742   
  743       /**
  744        * Is linking allowed.
  745        */
  746       public boolean isAllowLinking() {
  747           return allowLinking;
  748       }
  749   
  750   
  751       /**
  752        * Set cache TTL.
  753        */
  754       public void setCacheTTL(int cacheTTL) {
  755           this.cacheTTL = cacheTTL;
  756       }
  757   
  758   
  759       /**
  760        * Get cache TTL.
  761        */
  762       public int getCacheTTL() {
  763           return cacheTTL;
  764       }
  765   
  766   
  767       /**
  768        * Return the maximum size of the cache in KB.
  769        */
  770       public int getCacheMaxSize() {
  771           return cacheMaxSize;
  772       }
  773   
  774   
  775       /**
  776        * Set the maximum size of the cache in KB.
  777        */
  778       public void setCacheMaxSize(int cacheMaxSize) {
  779           this.cacheMaxSize = cacheMaxSize;
  780       }
  781   
  782   
  783       /**
  784        * Return the "follow standard delegation model" flag used to configure
  785        * our ClassLoader.
  786        */
  787       public boolean getDelegate() {
  788   
  789           return (this.delegate);
  790   
  791       }
  792   
  793   
  794       /**
  795        * Set the "follow standard delegation model" flag used to configure
  796        * our ClassLoader.
  797        *
  798        * @param delegate The new flag
  799        */
  800       public void setDelegate(boolean delegate) {
  801   
  802           boolean oldDelegate = this.delegate;
  803           this.delegate = delegate;
  804           support.firePropertyChange("delegate", new Boolean(oldDelegate),
  805                                      new Boolean(this.delegate));
  806   
  807       }
  808   
  809   
  810       /**
  811        * Returns true if the internal naming support is used.
  812        */
  813       public boolean isUseNaming() {
  814   
  815           return (useNaming);
  816   
  817       }
  818   
  819   
  820       /**
  821        * Enables or disables naming.
  822        */
  823       public void setUseNaming(boolean useNaming) {
  824           this.useNaming = useNaming;
  825       }
  826   
  827   
  828       /**
  829        * Returns true if the resources associated with this context are
  830        * filesystem based.
  831        */
  832       public boolean isFilesystemBased() {
  833   
  834           return (filesystemBased);
  835   
  836       }
  837   
  838   
  839       /**
  840        * Return the set of initialized application event listener objects,
  841        * in the order they were specified in the web application deployment
  842        * descriptor, for this application.
  843        *
  844        * @exception IllegalStateException if this method is called before
  845        *  this application has started, or after it has been stopped
  846        */
  847       public Object[] getApplicationEventListeners() {
  848           return (applicationEventListenersObjects);
  849       }
  850   
  851   
  852       /**
  853        * Store the set of initialized application event listener objects,
  854        * in the order they were specified in the web application deployment
  855        * descriptor, for this application.
  856        *
  857        * @param listeners The set of instantiated listener objects.
  858        */
  859       public void setApplicationEventListeners(Object listeners[]) {
  860           applicationEventListenersObjects = listeners;
  861       }
  862   
  863   
  864       /**
  865        * Return the set of initialized application lifecycle listener objects,
  866        * in the order they were specified in the web application deployment
  867        * descriptor, for this application.
  868        *
  869        * @exception IllegalStateException if this method is called before
  870        *  this application has started, or after it has been stopped
  871        */
  872       public Object[] getApplicationLifecycleListeners() {
  873           return (applicationLifecycleListenersObjects);
  874       }
  875   
  876   
  877       /**
  878        * Store the set of initialized application lifecycle listener objects,
  879        * in the order they were specified in the web application deployment
  880        * descriptor, for this application.
  881        *
  882        * @param listeners The set of instantiated listener objects.
  883        */
  884       public void setApplicationLifecycleListeners(Object listeners[]) {
  885           applicationLifecycleListenersObjects = listeners;
  886       }
  887   
  888   
  889       /**
  890        * Return the antiJARLocking flag for this Context.
  891        */
  892       public boolean getAntiJARLocking() {
  893   
  894           return (this.antiJARLocking);
  895   
  896       }
  897   
  898   
  899       /**
  900        * Return the antiResourceLocking flag for this Context.
  901        */
  902       public boolean getAntiResourceLocking() {
  903   
  904           return (this.antiResourceLocking);
  905   
  906       }
  907   
  908   
  909       /**
  910        * Set the antiJARLocking feature for this Context.
  911        *
  912        * @param antiJARLocking The new flag value
  913        */
  914       public void setAntiJARLocking(boolean antiJARLocking) {
  915   
  916           boolean oldAntiJARLocking = this.antiJARLocking;
  917           this.antiJARLocking = antiJARLocking;
  918           support.firePropertyChange("antiJARLocking",
  919                                      new Boolean(oldAntiJARLocking),
  920                                      new Boolean(this.antiJARLocking));
  921   
  922       }
  923   
  924   
  925       /**
  926        * Set the antiResourceLocking feature for this Context.
  927        *
  928        * @param antiResourceLocking The new flag value
  929        */
  930       public void setAntiResourceLocking(boolean antiResourceLocking) {
  931   
  932           boolean oldAntiResourceLocking = this.antiResourceLocking;
  933           this.antiResourceLocking = antiResourceLocking;
  934           support.firePropertyChange("antiResourceLocking",
  935                                      new Boolean(oldAntiResourceLocking),
  936                                      new Boolean(this.antiResourceLocking));
  937   
  938       }
  939   
  940   
  941       /**
  942        * Return the application available flag for this Context.
  943        */
  944       public boolean getAvailable() {
  945   
  946           return (this.available);
  947   
  948       }
  949   
  950   
  951       /**
  952        * Set the application available flag for this Context.
  953        *
  954        * @param available The new application available flag
  955        */
  956       public void setAvailable(boolean available) {
  957   
  958           boolean oldAvailable = this.available;
  959           this.available = available;
  960           support.firePropertyChange("available",
  961                                      new Boolean(oldAvailable),
  962                                      new Boolean(this.available));
  963   
  964       }
  965   
  966   
  967       /**
  968        * Return the Locale to character set mapper for this Context.
  969        */
  970       public CharsetMapper getCharsetMapper() {
  971   
  972           // Create a mapper the first time it is requested
  973           if (this.charsetMapper == null) {
  974               try {
  975                   Class clazz = Class.forName(charsetMapperClass);
  976                   this.charsetMapper =
  977                     (CharsetMapper) clazz.newInstance();
  978               } catch (Throwable t) {
  979                   this.charsetMapper = new CharsetMapper();
  980               }
  981           }
  982   
  983           return (this.charsetMapper);
  984   
  985       }
  986   
  987   
  988       /**
  989        * Set the Locale to character set mapper for this Context.
  990        *
  991        * @param mapper The new mapper
  992        */
  993       public void setCharsetMapper(CharsetMapper mapper) {
  994   
  995           CharsetMapper oldCharsetMapper = this.charsetMapper;
  996           this.charsetMapper = mapper;
  997           if( mapper != null )
  998               this.charsetMapperClass= mapper.getClass().getName();
  999           support.firePropertyChange("charsetMapper", oldCharsetMapper,
 1000                                      this.charsetMapper);
 1001   
 1002       }
 1003   
 1004       /**
 1005        * Return the path to a file to save this Context information.
 1006        */
 1007       public String getConfigFile() {
 1008   
 1009           return (this.configFile);
 1010   
 1011       }
 1012   
 1013   
 1014       /**
 1015        * Set the path to a file to save this Context information.
 1016        *
 1017        * @param configFile The path to a file to save this Context information.
 1018        */
 1019       public void setConfigFile(String configFile) {
 1020   
 1021           this.configFile = configFile;
 1022       }
 1023   
 1024   
 1025       /**
 1026        * Return the "correctly configured" flag for this Context.
 1027        */
 1028       public boolean getConfigured() {
 1029   
 1030           return (this.configured);
 1031   
 1032       }
 1033   
 1034   
 1035       /**
 1036        * Set the "correctly configured" flag for this Context.  This can be
 1037        * set to false by startup listeners that detect a fatal configuration
 1038        * error to avoid the application from being made available.
 1039        *
 1040        * @param configured The new correctly configured flag
 1041        */
 1042       public void setConfigured(boolean configured) {
 1043   
 1044           boolean oldConfigured = this.configured;
 1045           this.configured = configured;
 1046           support.firePropertyChange("configured",
 1047                                      new Boolean(oldConfigured),
 1048                                      new Boolean(this.configured));
 1049   
 1050       }
 1051   
 1052   
 1053       /**
 1054        * Return the "use cookies for session ids" flag.
 1055        */
 1056       public boolean getCookies() {
 1057   
 1058           return (this.cookies);
 1059   
 1060       }
 1061   
 1062   
 1063       /**
 1064        * Set the "use cookies for session ids" flag.
 1065        *
 1066        * @param cookies The new flag
 1067        */
 1068       public void setCookies(boolean cookies) {
 1069   
 1070           boolean oldCookies = this.cookies;
 1071           this.cookies = cookies;
 1072           support.firePropertyChange("cookies",
 1073                                      new Boolean(oldCookies),
 1074                                      new Boolean(this.cookies));
 1075   
 1076       }
 1077   
 1078   
 1079       /**
 1080        * Return the "allow crossing servlet contexts" flag.
 1081        */
 1082       public boolean getCrossContext() {
 1083   
 1084           return (this.crossContext);
 1085   
 1086       }
 1087   
 1088   
 1089       /**
 1090        * Set the "allow crossing servlet contexts" flag.
 1091        *
 1092        * @param crossContext The new cross contexts flag
 1093        */
 1094       public void setCrossContext(boolean crossContext) {
 1095   
 1096           boolean oldCrossContext = this.crossContext;
 1097           this.crossContext = crossContext;
 1098           support.firePropertyChange("crossContext",
 1099                                      new Boolean(oldCrossContext),
 1100                                      new Boolean(this.crossContext));
 1101   
 1102       }
 1103   
 1104       public String getDefaultContextXml() {
 1105           return defaultContextXml;
 1106       }
 1107   
 1108       /** 
 1109        * Set the location of the default context xml that will be used.
 1110        * If not absolute, it'll be made relative to the engine's base dir
 1111        * ( which defaults to catalina.base system property ).
 1112        *
 1113        * @param defaultContextXml The default web xml 
 1114        */
 1115       public void setDefaultContextXml(String defaultContextXml) {
 1116           this.defaultContextXml = defaultContextXml;
 1117       }
 1118   
 1119       public String getDefaultWebXml() {
 1120           return defaultWebXml;
 1121       }
 1122   
 1123       /** 
 1124        * Set the location of the default web xml that will be used.
 1125        * If not absolute, it'll be made relative to the engine's base dir
 1126        * ( which defaults to catalina.base system property ).
 1127        *
 1128        * @param defaultWebXml The default web xml 
 1129        */
 1130       public void setDefaultWebXml(String defaultWebXml) {
 1131           this.defaultWebXml = defaultWebXml;
 1132       }
 1133   
 1134       /**
 1135        * Gets the time (in milliseconds) it took to start this context.
 1136        *
 1137        * @return Time (in milliseconds) it took to start this context.
 1138        */
 1139       public long getStartupTime() {
 1140           return startupTime;
 1141       }
 1142   
 1143       public void setStartupTime(long startupTime) {
 1144           this.startupTime = startupTime;
 1145       }
 1146   
 1147       public long getTldScanTime() {
 1148           return tldScanTime;
 1149       }
 1150   
 1151       public void setTldScanTime(long tldScanTime) {
 1152           this.tldScanTime = tldScanTime;
 1153       }
 1154   
 1155       /**
 1156        * Return the display name of this web application.
 1157        */
 1158       public String getDisplayName() {
 1159   
 1160           return (this.displayName);
 1161   
 1162       }
 1163   
 1164   
 1165       /**
 1166        * Return the alternate Deployment Descriptor name.
 1167        */
 1168       public String getAltDDName(){
 1169           return altDDName;
 1170       }
 1171   
 1172   
 1173       /**
 1174        * Set an alternate Deployment Descriptor name.
 1175        */
 1176       public void setAltDDName(String altDDName) {
 1177           this.altDDName = altDDName;
 1178           if (context != null) {
 1179               context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
 1180           }
 1181       }
 1182   
 1183   
 1184       /**
 1185        * Return the compiler classpath.
 1186        */
 1187       public String getCompilerClasspath(){
 1188           return compilerClasspath;
 1189       }
 1190   
 1191   
 1192       /**
 1193        * Set the compiler classpath.
 1194        */
 1195       public void setCompilerClasspath(String compilerClasspath) {
 1196           this.compilerClasspath = compilerClasspath;
 1197       }
 1198   
 1199   
 1200       /**
 1201        * Set the display name of this web application.
 1202        *
 1203        * @param displayName The new display name
 1204        */
 1205       public void setDisplayName(String displayName) {
 1206   
 1207           String oldDisplayName = this.displayName;
 1208           this.displayName = displayName;
 1209           support.firePropertyChange("displayName", oldDisplayName,
 1210                                      this.displayName);
 1211       }
 1212   
 1213   
 1214       /**
 1215        * Return the distributable flag for this web application.
 1216        */
 1217       public boolean getDistributable() {
 1218   
 1219           return (this.distributable);
 1220   
 1221       }
 1222   
 1223       /**
 1224        * Set the distributable flag for this web application.
 1225        *
 1226        * @param distributable The new distributable flag
 1227        */
 1228       public void setDistributable(boolean distributable) {
 1229           boolean oldDistributable = this.distributable;
 1230           this.distributable = distributable;
 1231           support.firePropertyChange("distributable",
 1232                                      new Boolean(oldDistributable),
 1233                                      new Boolean(this.distributable));
 1234   
 1235           // Bugzilla 32866
 1236           if(getManager() != null) {
 1237               if(log.isDebugEnabled()) {
 1238                   log.debug("Propagating distributable=" + distributable
 1239                             + " to manager");
 1240               }
 1241               getManager().setDistributable(distributable);
 1242           }
 1243       }
 1244   
 1245   
 1246       /**
 1247        * Return the document root for this Context.  This can be an absolute
 1248        * pathname, a relative pathname, or a URL.
 1249        */
 1250       public String getDocBase() {
 1251   
 1252           return (this.docBase);
 1253   
 1254       }
 1255   
 1256   
 1257       /**
 1258        * Set the document root for this Context.  This can be an absolute
 1259        * pathname, a relative pathname, or a URL.
 1260        *
 1261        * @param docBase The new document root
 1262        */
 1263       public void setDocBase(String docBase) {
 1264   
 1265           this.docBase = docBase;
 1266   
 1267       }
 1268   
 1269       // experimental
 1270       public boolean isLazy() {
 1271           return lazy;
 1272       }
 1273   
 1274       public void setLazy(boolean lazy) {
 1275           this.lazy = lazy;
 1276       }
 1277   
 1278   
 1279       /**
 1280        * Return descriptive information about this Container implementation and
 1281        * the corresponding version number, in the format
 1282        * <code>&lt;description&gt;/&lt;version&gt;</code>.
 1283        */
 1284       public String getInfo() {
 1285   
 1286           return (info);
 1287   
 1288       }
 1289   
 1290       public String getEngineName() {
 1291           if( engineName != null ) return engineName;
 1292           return domain;
 1293       }
 1294   
 1295       public void setEngineName(String engineName) {
 1296           this.engineName = engineName;
 1297       }
 1298   
 1299       public String getJ2EEApplication() {
 1300           return j2EEApplication;
 1301       }
 1302   
 1303       public void setJ2EEApplication(String j2EEApplication) {
 1304           this.j2EEApplication = j2EEApplication;
 1305       }
 1306   
 1307       public String getJ2EEServer() {
 1308           return j2EEServer;
 1309       }
 1310   
 1311       public void setJ2EEServer(String j2EEServer) {
 1312           this.j2EEServer = j2EEServer;
 1313       }
 1314   
 1315   
 1316       /**
 1317        * Set the Loader with which this Context is associated.
 1318        *
 1319        * @param loader The newly associated loader
 1320        */
 1321       public synchronized void setLoader(Loader loader) {
 1322   
 1323           super.setLoader(loader);
 1324   
 1325       }
 1326   
 1327   
 1328       /**
 1329        * Return the boolean on the annotations parsing.
 1330        */
 1331       public boolean getIgnoreAnnotations() {
 1332           return this.ignoreAnnotations;
 1333       }
 1334       
 1335       
 1336       /**
 1337        * Set the boolean on the annotations parsing for this web 
 1338        * application.
 1339        * 
 1340        * @param ignoreAnnotations The boolean on the annotations parsing
 1341        */
 1342       public void setIgnoreAnnotations(boolean ignoreAnnotations) {
 1343           boolean oldIgnoreAnnotations = this.ignoreAnnotations;
 1344           this.ignoreAnnotations = ignoreAnnotations;
 1345           support.firePropertyChange("ignoreAnnotations", Boolean.valueOf(oldIgnoreAnnotations),
 1346                   Boolean.valueOf(this.ignoreAnnotations));
 1347       }
 1348       
 1349       
 1350       /**
 1351        * Return the login configuration descriptor for this web application.
 1352        */
 1353       public LoginConfig getLoginConfig() {
 1354   
 1355           return (this.loginConfig);
 1356   
 1357       }
 1358   
 1359   
 1360       /**
 1361        * Set the login configuration descriptor for this web application.
 1362        *
 1363        * @param config The new login configuration
 1364        */
 1365       public void setLoginConfig(LoginConfig config) {
 1366   
 1367           // Validate the incoming property value
 1368           if (config == null)
 1369               throw new IllegalArgumentException
 1370                   (sm.getString("standardContext.loginConfig.required"));
 1371           String loginPage = config.getLoginPage();
 1372           if ((loginPage != null) && !loginPage.startsWith("/")) {
 1373               if (isServlet22()) {
 1374                   if(log.isDebugEnabled())
 1375                       log.debug(sm.getString("standardContext.loginConfig.loginWarning",
 1376                                    loginPage));
 1377                   config.setLoginPage("/" + loginPage);
 1378               } else {
 1379                   throw new IllegalArgumentException
 1380                       (sm.getString("standardContext.loginConfig.loginPage",
 1381                                     loginPage));
 1382               }
 1383           }
 1384           String errorPage = config.getErrorPage();
 1385           if ((errorPage != null) && !errorPage.startsWith("/")) {
 1386               if (isServlet22()) {
 1387                   if(log.isDebugEnabled())
 1388                       log.debug(sm.getString("standardContext.loginConfig.errorWarning",
 1389                                    errorPage));
 1390                   config.setErrorPage("/" + errorPage);
 1391               } else {
 1392                   throw new IllegalArgumentException
 1393                       (sm.getString("standardContext.loginConfig.errorPage",
 1394                                     errorPage));
 1395               }
 1396           }
 1397   
 1398           // Process the property setting change
 1399           LoginConfig oldLoginConfig = this.loginConfig;
 1400           this.loginConfig = config;
 1401           support.firePropertyChange("loginConfig",
 1402                                      oldLoginConfig, this.loginConfig);
 1403   
 1404       }
 1405   
 1406   
 1407       /**
 1408        * Get the mapper associated with the context.
 1409        */
 1410       public org.apache.tomcat.util.http.mapper.Mapper getMapper() {
 1411           return (mapper);
 1412       }
 1413   
 1414   
 1415       /**
 1416        * Return the naming resources associated with this web application.
 1417        */
 1418       public NamingResources getNamingResources() {
 1419   
 1420           if (namingResources == null) {
 1421               setNamingResources(new NamingResources());
 1422           }
 1423           return (namingResources);
 1424   
 1425       }
 1426   
 1427   
 1428       /**
 1429        * Set the naming resources for this web application.
 1430        *
 1431        * @param namingResources The new naming resources
 1432        */
 1433       public void setNamingResources(NamingResources namingResources) {
 1434   
 1435           // Process the property setting change
 1436           NamingResources oldNamingResources = this.namingResources;
 1437           this.namingResources = namingResources;
 1438           namingResources.setContainer(this);
 1439           support.firePropertyChange("namingResources",
 1440                                      oldNamingResources, this.namingResources);
 1441   
 1442       }
 1443   
 1444   
 1445       /**
 1446        * Return the context path for this Context.
 1447        */
 1448       public String getPath() {
 1449   
 1450           return (getName());
 1451   
 1452       }
 1453   
 1454       
 1455       /**
 1456        * Set the context path for this Context.
 1457        * <p>
 1458        * <b>IMPLEMENTATION NOTE</b>:  The context path is used as the "name" of
 1459        * a Context, because it must be unique.
 1460        *
 1461        * @param path The new context path
 1462        */
 1463       public void setPath(String path) {
 1464           // XXX Use host in name
 1465           setName(RequestUtil.URLDecode(path));
 1466   
 1467       }
 1468   
 1469   
 1470       /**
 1471        * Return the public identifier of the deployment descriptor DTD that is
 1472        * currently being parsed.
 1473        */
 1474       public String getPublicId() {
 1475   
 1476           return (this.publicId);
 1477   
 1478       }
 1479   
 1480   
 1481       /**
 1482        * Set the public identifier of the deployment descriptor DTD that is
 1483        * currently being parsed.
 1484        *
 1485        * @param publicId The public identifier
 1486        */
 1487       public void setPublicId(String publicId) {
 1488   
 1489           if (log.isDebugEnabled())
 1490               log.debug("Setting deployment descriptor public ID to '" +
 1491                   publicId + "'");
 1492   
 1493           String oldPublicId = this.publicId;
 1494           this.publicId = publicId;
 1495           support.firePropertyChange("publicId", oldPublicId, publicId);
 1496   
 1497       }
 1498   
 1499   
 1500       /**
 1501        * Return the reloadable flag for this web application.
 1502        */
 1503       public boolean getReloadable() {
 1504   
 1505           return (this.reloadable);
 1506   
 1507       }
 1508   
 1509   
 1510       /**
 1511        * Return the DefaultContext override flag for this web application.
 1512        */
 1513       public boolean getOverride() {
 1514   
 1515           return (this.override);
 1516   
 1517       }
 1518   
 1519   
 1520       /**
 1521        * Return the original document root for this Context.  This can be an absolute
 1522        * pathname, a relative pathname, or a URL.
 1523        * Is only set as deployment has change docRoot!
 1524        */
 1525       public String getOriginalDocBase() {
 1526   
 1527           return (this.originalDocBase);
 1528   
 1529       }
 1530   
 1531       /**
 1532        * Set the original document root for this Context.  This can be an absolute
 1533        * pathname, a relative pathname, or a URL.
 1534        *
 1535        * @param docBase The orginal document root
 1536        */
 1537       public void setOriginalDocBase(String docBase) {
 1538   
 1539           this.originalDocBase = docBase;
 1540       }
 1541       
 1542   
 1543       /**
 1544        * Return the parent class loader (if any) for this web application.
 1545        * This call is meaningful only <strong>after</strong> a Loader has
 1546        * been configured.
 1547        */
 1548       public ClassLoader getParentClassLoader() {
 1549           if (parentClassLoader != null)
 1550               return (parentClassLoader);
 1551           if (getPrivileged()) {
 1552               return this.getClass().getClassLoader();
 1553           } else if (parent != null) {
 1554               return (parent.getParentClassLoader());
 1555           }
 1556           return (ClassLoader.getSystemClassLoader());
 1557       }
 1558   
 1559       
 1560       /**
 1561        * Return the privileged flag for this web application.
 1562        */
 1563       public boolean getPrivileged() {
 1564   
 1565           return (this.privileged);
 1566   
 1567       }
 1568   
 1569   
 1570       /**
 1571        * Set the privileged flag for this web application.
 1572        *
 1573        * @param privileged The new privileged flag
 1574        */
 1575       public void setPrivileged(boolean privileged) {
 1576   
 1577           boolean oldPrivileged = this.privileged;
 1578           this.privileged = privileged;
 1579           support.firePropertyChange("privileged",
 1580                                      new Boolean(oldPrivileged),
 1581                                      new Boolean(this.privileged));
 1582   
 1583       }
 1584   
 1585   
 1586       /**
 1587        * Set the reloadable flag for this web application.
 1588        *
 1589        * @param reloadable The new reloadable flag
 1590        */
 1591       public void setReloadable(boolean reloadable) {
 1592   
 1593           boolean oldReloadable = this.reloadable;
 1594           this.reloadable = reloadable;
 1595           support.firePropertyChange("reloadable",
 1596                                      new Boolean(oldReloadable),
 1597                                      new Boolean(this.reloadable));
 1598   
 1599       }
 1600   
 1601   
 1602       /**
 1603        * Set the DefaultContext override flag for this web application.
 1604        *
 1605        * @param override The new override flag
 1606        */
 1607       public void setOverride(boolean override) {
 1608   
 1609           boolean oldOverride = this.override;
 1610           this.override = override;
 1611           support.firePropertyChange("override",
 1612                                      new Boolean(oldOverride),
 1613                                      new Boolean(this.override));
 1614   
 1615       }
 1616   
 1617   
 1618       /**
 1619        * Return the "replace welcome files" property.
 1620        */
 1621       public boolean isReplaceWelcomeFiles() {
 1622   
 1623           return (this.replaceWelcomeFiles);
 1624   
 1625       }
 1626   
 1627   
 1628       /**
 1629        * Set the "replace welcome files" property.
 1630        *
 1631        * @param replaceWelcomeFiles The new property value
 1632        */
 1633       public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) {
 1634   
 1635           boolean oldReplaceWelcomeFiles = this.replaceWelcomeFiles;
 1636           this.replaceWelcomeFiles = replaceWelcomeFiles;
 1637           support.firePropertyChange("replaceWelcomeFiles",
 1638                                      new Boolean(oldReplaceWelcomeFiles),
 1639                                      new Boolean(this.replaceWelcomeFiles));
 1640   
 1641       }
 1642   
 1643   
 1644       /**
 1645        * Return the servlet context for which this Context is a facade.
 1646        */
 1647       public ServletContext getServletContext() {
 1648   
 1649           if (context == null) {
 1650               context = new ApplicationContext(getBasePath(), this);
 1651               if (altDDName != null)
 1652                   context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
 1653           }
 1654           return (context.getFacade());
 1655   
 1656       }
 1657   
 1658   
 1659       /**
 1660        * Return the default session timeout (in minutes) for this
 1661        * web application.
 1662        */
 1663       public int getSessionTimeout() {
 1664   
 1665           return (this.sessionTimeout);
 1666   
 1667       }
 1668   
 1669   
 1670       /**
 1671        * Set the default session timeout (in minutes) for this
 1672        * web application.
 1673        *
 1674        * @param timeout The new default session timeout
 1675        */
 1676       public void setSessionTimeout(int timeout) {
 1677   
 1678           int oldSessionTimeout = this.sessionTimeout;
 1679           /*
 1680            * SRV.13.4 ("Deployment Descriptor"):
 1681            * If the timeout is 0 or less, the container ensures the default
 1682            * behaviour of sessions is never to time out.
 1683            */
 1684           this.sessionTimeout = (timeout == 0) ? -1 : timeout;
 1685           support.firePropertyChange("sessionTimeout",
 1686                                      new Integer(oldSessionTimeout),
 1687                                      new Integer(this.sessionTimeout));
 1688   
 1689       }
 1690   
 1691   
 1692       /**
 1693        * Return the value of the swallowOutput flag.
 1694        */
 1695       public boolean getSwallowOutput() {
 1696   
 1697           return (this.swallowOutput);
 1698   
 1699       }
 1700   
 1701   
 1702       /**
 1703        * Set the value of the swallowOutput flag. If set to true, the system.out
 1704        * and system.err will be redirected to the logger during a servlet
 1705        * execution.
 1706        *
 1707        * @param swallowOutput The new value
 1708        */
 1709       public void setSwallowOutput(boolean swallowOutput) {
 1710   
 1711           boolean oldSwallowOutput = this.swallowOutput;
 1712           this.swallowOutput = swallowOutput;
 1713           support.firePropertyChange("swallowOutput",
 1714                                      new Boolean(oldSwallowOutput),
 1715                                      new Boolean(this.swallowOutput));
 1716   
 1717       }
 1718   
 1719   
 1720       /**
 1721        * Return the value of the unloadDelay flag.
 1722        */
 1723       public long getUnloadDelay() {
 1724   
 1725           return (this.unloadDelay);
 1726   
 1727       }
 1728   
 1729   
 1730       /**
 1731        * Set the value of the unloadDelay flag, which represents the amount
 1732        * of ms that the container will wait when unloading servlets.
 1733        * Setting this to a small value may cause more requests to fail 
 1734        * to complete when stopping a web application.
 1735        *
 1736        * @param unloadDelay The new value
 1737        */
 1738       public void setUnloadDelay(long unloadDelay) {
 1739   
 1740           long oldUnloadDelay = this.unloadDelay;
 1741           this.unloadDelay = unloadDelay;
 1742           support.firePropertyChange("unloadDelay",
 1743                                      new Long(oldUnloadDelay),
 1744                                      new Long(this.unloadDelay));
 1745   
 1746       }
 1747   
 1748   
 1749       /**
 1750        * Unpack WAR flag accessor.
 1751        */
 1752       public boolean getUnpackWAR() {
 1753   
 1754           return (unpackWAR);
 1755   
 1756       }
 1757   
 1758   
 1759       /**
 1760        * Unpack WAR flag mutator.
 1761        */
 1762       public void setUnpackWAR(boolean unpackWAR) {
 1763   
 1764           this.unpackWAR = unpackWAR;
 1765   
 1766       }
 1767   
 1768       /**
 1769        * Return the Java class name of the Wrapper implementation used
 1770        * for servlets registered in this Context.
 1771        */
 1772       public String getWrapperClass() {
 1773   
 1774           return (this.wrapperClassName);
 1775   
 1776       }
 1777   
 1778   
 1779       /**
 1780        * Set the Java class name of the Wrapper implementation used
 1781        * for servlets registered in this Context.
 1782        *
 1783        * @param wrapperClassName The new wrapper class name
 1784        *
 1785        * @throws IllegalArgumentException if the specified wrapper class
 1786        * cannot be found or is not a subclass of StandardWrapper
 1787        */
 1788       public void setWrapperClass(String wrapperClassName) {
 1789   
 1790           this.wrapperClassName = wrapperClassName;
 1791   
 1792           try {
 1793               wrapperClass = Class.forName(wrapperClassName);         
 1794               if (!StandardWrapper.class.isAssignableFrom(wrapperClass)) {
 1795                   throw new IllegalArgumentException(
 1796                       sm.getString("standardContext.invalidWrapperClass",
 1797                                    wrapperClassName));
 1798               }
 1799           } catch (ClassNotFoundException cnfe) {
 1800               throw new IllegalArgumentException(cnfe.getMessage());
 1801           }
 1802       }
 1803   
 1804   
 1805       /**
 1806        * Set the resources DirContext object with which this Container is
 1807        * associated.
 1808        *
 1809        * @param resources The newly associated DirContext
 1810        */
 1811       public synchronized void setResources(DirContext resources) {
 1812   
 1813           if (started) {
 1814               throw new IllegalStateException
 1815                   (sm.getString("standardContext.resources.started"));
 1816           }
 1817   
 1818           DirContext oldResources = this.webappResources;
 1819           if (oldResources == resources)
 1820               return;
 1821   
 1822           if (resources instanceof BaseDirContext) {
 1823               ((BaseDirContext) resources).setCached(isCachingAllowed());
 1824               ((BaseDirContext) resources).setCacheTTL(getCacheTTL());
 1825               ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize());
 1826           }
 1827           if (resources instanceof FileDirContext) {
 1828               filesystemBased = true;
 1829               ((FileDirContext) resources).setCaseSensitive(isCaseSensitive());
 1830               ((FileDirContext) resources).setAllowLinking(isAllowLinking());
 1831           }
 1832           this.webappResources = resources;
 1833   
 1834           // The proxied resources will be refreshed on start
 1835           this.resources = null;
 1836   
 1837           support.firePropertyChange("resources", oldResources,
 1838                                      this.webappResources);
 1839   
 1840       }
 1841   
 1842   
 1843       // ------------------------------------------------------ Public Properties
 1844   
 1845   
 1846       /**
 1847        * Return the Locale to character set mapper class for this Context.
 1848        */
 1849       public String getCharsetMapperClass() {
 1850   
 1851           return (this.charsetMapperClass);
 1852   
 1853       }
 1854   
 1855   
 1856       /**
 1857        * Set the Locale to character set mapper class for this Context.
 1858        *
 1859        * @param mapper The new mapper class
 1860        */
 1861       public void setCharsetMapperClass(String mapper) {
 1862   
 1863           String oldCharsetMapperClass = this.charsetMapperClass;
 1864           this.charsetMapperClass = mapper;
 1865           support.firePropertyChange("charsetMapperClass",
 1866                                      oldCharsetMapperClass,
 1867                                      this.charsetMapperClass);
 1868   
 1869       }
 1870   
 1871   
 1872       /** Get the absolute path to the work dir.
 1873        *  To avoid duplication.
 1874        * 
 1875        * @return The work path
 1876        */ 
 1877       public String getWorkPath() {
 1878           if (getWorkDir() == null) {
 1879               return null;
 1880           }
 1881           File workDir = new File(getWorkDir());
 1882           if (!workDir.isAbsolute()) {
 1883               File catalinaHome = engineBase();
 1884               String catalinaHomePath = null;
 1885               try {
 1886                   catalinaHomePath = catalinaHome.getCanonicalPath();
 1887                   workDir = new File(catalinaHomePath,
 1888                           getWorkDir());
 1889               } catch (IOException e) {
 1890                   log.warn("Exception obtaining work path for " + getPath());
 1891               }
 1892           }
 1893           return workDir.getAbsolutePath();
 1894       }
 1895       
 1896       /**
 1897        * Return the work directory for this Context.
 1898        */
 1899       public String getWorkDir() {
 1900   
 1901           return (this.workDir);
 1902   
 1903       }
 1904   
 1905   
 1906       /**
 1907        * Set the work directory for this Context.
 1908        *
 1909        * @param workDir The new work directory
 1910        */
 1911       public void setWorkDir(String workDir) {
 1912   
 1913           this.workDir = workDir;
 1914   
 1915           if (started) {
 1916               postWorkDirectory();
 1917           }
 1918       }
 1919   
 1920   
 1921       /**
 1922        * Save config ?
 1923        */
 1924       public boolean isSaveConfig() {
 1925           return saveConfig;
 1926       }
 1927   
 1928   
 1929       /**
 1930        * Set save config flag.
 1931        */
 1932       public void setSaveConfig(boolean saveConfig) {
 1933           this.saveConfig = saveConfig;
 1934       }
 1935   
 1936   
 1937       // -------------------------------------------------------- Context Methods
 1938   
 1939   
 1940       /**
 1941        * Add a new Listener class name to the set of Listeners
 1942        * configured for this application.
 1943        *
 1944        * @param listener Java class name of a listener class
 1945        */
 1946       public void addApplicationListener(String listener) {
 1947   
 1948           synchronized (applicationListeners) {
 1949               String results[] =new String[applicationListeners.length + 1];
 1950               for (int i = 0; i < applicationListeners.length; i++) {
 1951                   if (listener.equals(applicationListeners[i])) {
 1952                       log.info(sm.getString(
 1953                               "standardContext.duplicateListener",listener));
 1954                       return;
 1955                   }
 1956                   results[i] = applicationListeners[i];
 1957               }
 1958               results[applicationListeners.length] = listener;
 1959               applicationListeners = results;
 1960           }
 1961           fireContainerEvent("addApplicationListener", listener);
 1962   
 1963           // FIXME - add instance if already started?
 1964   
 1965       }
 1966   
 1967   
 1968       /**
 1969        * Add a new application parameter for this application.
 1970        *
 1971        * @param parameter The new application parameter
 1972        */
 1973       public void addApplicationParameter(ApplicationParameter parameter) {
 1974   
 1975           synchronized (applicationParameters) {
 1976               String newName = parameter.getName();
 1977               for (int i = 0; i < applicationParameters.length; i++) {
 1978                   if (newName.equals(applicationParameters[i].getName()) &&
 1979                       !applicationParameters[i].getOverride())
 1980                       return;
 1981               }
 1982               ApplicationParameter results[] =
 1983                   new ApplicationParameter[applicationParameters.length + 1];
 1984               System.arraycopy(applicationParameters, 0, results, 0,
 1985                                applicationParameters.length);
 1986               results[applicationParameters.length] = parameter;
 1987               applicationParameters = results;
 1988           }
 1989           fireContainerEvent("addApplicationParameter", parameter);
 1990   
 1991       }
 1992   
 1993   
 1994       /**
 1995        * Add a child Container, only if the proposed child is an implementation
 1996        * of Wrapper.
 1997        *
 1998        * @param child Child container to be added
 1999        *
 2000        * @exception IllegalArgumentException if the proposed container is
 2001        *  not an implementation of Wrapper
 2002        */
 2003       public void addChild(Container child) {
 2004   
 2005           // Global JspServlet
 2006           Wrapper oldJspServlet = null;
 2007   
 2008           if (!(child instanceof Wrapper)) {
 2009               throw new IllegalArgumentException
 2010                   (sm.getString("standardContext.notWrapper"));
 2011           }
 2012   
 2013           Wrapper wrapper = (Wrapper) child;
 2014           boolean isJspServlet = "jsp".equals(child.getName());
 2015   
 2016           // Allow webapp to override JspServlet inherited from global web.xml.
 2017           if (isJspServlet) {
 2018               oldJspServlet = (Wrapper) findChild("jsp");
 2019               if (oldJspServlet != null) {
 2020                   removeChild(oldJspServlet);
 2021               }
 2022           }
 2023   
 2024           String jspFile = wrapper.getJspFile();
 2025           if ((jspFile != null) && !jspFile.startsWith("/")) {
 2026               if (isServlet22()) {
 2027                   if(log.isDebugEnabled())
 2028                       log.debug(sm.getString("standardContext.wrapper.warning", 
 2029                                          jspFile));
 2030                   wrapper.setJspFile("/" + jspFile);
 2031               } else {
 2032                   throw new IllegalArgumentException
 2033                       (sm.getString("standardContext.wrapper.error", jspFile));
 2034               }
 2035           }
 2036   
 2037           super.addChild(child);
 2038   
 2039           if (isJspServlet && oldJspServlet != null) {
 2040               /*
 2041                * The webapp-specific JspServlet inherits all the mappings
 2042                * specified in the global web.xml, and may add additional ones.
 2043                */
 2044               String[] jspMappings = oldJspServlet.findMappings();
 2045               for (int i=0; jspMappings!=null && i<jspMappings.length; i++) {
 2046                   addServletMapping(jspMappings[i], child.getName());
 2047               }
 2048           }
 2049       }
 2050   
 2051   
 2052       /**
 2053        * Add a security constraint to the set for this web application.
 2054        */
 2055       public void addConstraint(SecurityConstraint constraint) {
 2056   
 2057           // Validate the proposed constraint
 2058           SecurityCollection collections[] = constraint.findCollections();
 2059           for (int i = 0; i < collections.length; i++) {
 2060               String patterns[] = collections[i].findPatterns();
 2061               for (int j = 0; j < patterns.length; j++) {
 2062                   patterns[j] = adjustURLPattern(patterns[j]);
 2063                   if (!validateURLPattern(patterns[j]))
 2064                       throw new IllegalArgumentException
 2065                           (sm.getString
 2066                            ("standardContext.securityConstraint.pattern",
 2067                             patterns[j]));
 2068               }
 2069           }
 2070   
 2071           // Add this constraint to the set for our web application
 2072           synchronized (constraints) {
 2073               SecurityConstraint results[] =
 2074                   new SecurityConstraint[constraints.length + 1];
 2075               for (int i = 0; i < constraints.length; i++)
 2076                   results[i] = constraints[i];
 2077               results[constraints.length] = constraint;
 2078               constraints = results;
 2079           }
 2080   
 2081       }
 2082   
 2083   
 2084   
 2085       /**
 2086        * Add an error page for the specified error or Java exception.
 2087        *
 2088        * @param errorPage The error page definition to be added
 2089        */
 2090       public void addErrorPage(ErrorPage errorPage) {
 2091           // Validate the input parameters
 2092           if (errorPage == null)
 2093               throw new IllegalArgumentException
 2094                   (sm.getString("standardContext.errorPage.required"));
 2095           String location = errorPage.getLocation();
 2096           if ((location != null) && !location.startsWith("/")) {
 2097               if (isServlet22()) {
 2098                   if(log.isDebugEnabled())
 2099                       log.debug(sm.getString("standardContext.errorPage.warning",
 2100                                    location));
 2101                   errorPage.setLocation("/" + location);
 2102               } else {
 2103                   throw new IllegalArgumentException
 2104                       (sm.getString("standardContext.errorPage.error",
 2105                                     location));
 2106               }
 2107           }
 2108   
 2109           // Add the specified error page to our internal collections
 2110           String exceptionType = errorPage.getExceptionType();
 2111           if (exceptionType != null) {
 2112               synchronized (exceptionPages) {
 2113                   exceptionPages.put(exceptionType, errorPage);
 2114               }
 2115           } else {
 2116               synchronized (statusPages) {
 2117                   if (errorPage.getErrorCode() == 200) {
 2118                       this.okErrorPage = errorPage;
 2119                   }
 2120                   statusPages.put(new Integer(errorPage.getErrorCode()),
 2121                                   errorPage);
 2122               }
 2123           }
 2124           fireContainerEvent("addErrorPage", errorPage);
 2125   
 2126       }
 2127   
 2128   
 2129       /**
 2130        * Add a filter definition to this Context.
 2131        *
 2132        * @param filterDef The filter definition to be added
 2133        */
 2134       public void addFilterDef(FilterDef filterDef) {
 2135   
 2136           synchronized (filterDefs) {
 2137               filterDefs.put(filterDef.getFilterName(), filterDef);
 2138           }
 2139           fireContainerEvent("addFilterDef", filterDef);
 2140   
 2141       }
 2142   
 2143   
 2144       /**
 2145        * Add a filter mapping to this Context.
 2146        *
 2147        * @param filterMap The filter mapping to be added
 2148        *
 2149        * @exception IllegalArgumentException if the specified filter name
 2150        *  does not match an existing filter definition, or the filter mapping
 2151        *  is malformed
 2152        */
 2153       public void addFilterMap(FilterMap filterMap) {
 2154   
 2155           // Validate the proposed filter mapping
 2156           String filterName = filterMap.getFilterName();
 2157           String[] servletNames = filterMap.getServletNames();
 2158           String[] urlPatterns = filterMap.getURLPatterns();
 2159           if (findFilterDef(filterName) == null)
 2160               throw new IllegalArgumentException
 2161                   (sm.getString("standardContext.filterMap.name", filterName));
 2162   //      <= Servlet API 2.4
 2163   //      if ((servletNames.length == 0) && (urlPatterns.length == 0))
 2164   //      Servlet API 2.5 (FIX 43338)
 2165   //      SRV 6.2.5 says supporting for '*' as the servlet-name in filter-mapping.
 2166           if (!filterMap.getMatchAllServletNames() && 
 2167               !filterMap.getMatchAllUrlPatterns() && 
 2168               (servletNames.length == 0) && (urlPatterns.length == 0))
 2169               throw new IllegalArgumentException
 2170                   (sm.getString("standardContext.filterMap.either"));
 2171           // FIXME: Older spec revisions may still check this
 2172           /*
 2173           if ((servletNames.length != 0) && (urlPatterns.length != 0))
 2174               throw new IllegalArgumentException
 2175                   (sm.getString("standardContext.filterMap.either"));
 2176           */
 2177           // Because filter-pattern is new in 2.3, no need to adjust
 2178           // for 2.2 backwards compatibility
 2179           for (int i = 0; i < urlPatterns.length; i++) {
 2180               if (!validateURLPattern(urlPatterns[i])) {
 2181                   throw new IllegalArgumentException
 2182                       (sm.getString("standardContext.filterMap.pattern",
 2183                               urlPatterns[i]));
 2184               }
 2185           }
 2186   
 2187           // Add this filter mapping to our registered set
 2188           synchronized (filterMaps) {
 2189               FilterMap results[] =new FilterMap[filterMaps.length + 1];
 2190               System.arraycopy(filterMaps, 0, results, 0, filterMaps.length);
 2191               results[filterMaps.length] = filterMap;
 2192               filterMaps = results;
 2193           }
 2194           fireContainerEvent("addFilterMap", filterMap);
 2195   
 2196       }
 2197   
 2198   
 2199       /**
 2200        * Add the classname of an InstanceListener to be added to each
 2201        * Wrapper appended to this Context.
 2202        *
 2203        * @param listener Java class name of an InstanceListener class
 2204        */
 2205       public void addInstanceListener(String listener) {
 2206   
 2207           synchronized (instanceListeners) {
 2208               String results[] =new String[instanceListeners.length + 1];
 2209               for (int i = 0; i < instanceListeners.length; i++)
 2210                   results[i] = instanceListeners[i];
 2211               results[instanceListeners.length] = listener;
 2212               instanceListeners = results;
 2213           }
 2214           fireContainerEvent("addInstanceListener", listener);
 2215   
 2216       }
 2217   
 2218       /**
 2219        * Add the given URL pattern as a jsp-property-group.  This maps
 2220        * resources that match the given pattern so they will be passed
 2221        * to the JSP container.  Though there are other elements in the
 2222        * property group, we only care about the URL pattern here.  The
 2223        * JSP container will parse the rest.
 2224        *
 2225        * @param pattern URL pattern to be mapped
 2226        */
 2227       public void addJspMapping(String pattern) {
 2228           String servletName = findServletMapping("*.jsp");
 2229           if (servletName == null) {
 2230               servletName = "jsp";
 2231           }
 2232   
 2233           if( findChild(servletName) != null) {
 2234               addServletMapping(pattern, servletName, true);
 2235           } else {
 2236               if(log.isDebugEnabled())
 2237                   log.debug("Skiping " + pattern + " , no servlet " + servletName);
 2238           }
 2239       }
 2240   
 2241   
 2242       /**
 2243        * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4)
 2244        *
 2245        * @param locale locale to map an encoding for
 2246        * @param encoding encoding to be used for a give locale
 2247        */
 2248       public void addLocaleEncodingMappingParameter(String locale, String encoding){
 2249           getCharsetMapper().addCharsetMappingFromDeploymentDescriptor(locale, encoding);
 2250       }
 2251   
 2252   
 2253       /**
 2254        * Add a message destination for this web application.
 2255        *
 2256        * @param md New message destination
 2257        */
 2258       public void addMessageDestination(MessageDestination md) {
 2259   
 2260           synchronized (messageDestinations) {
 2261               messageDestinations.put(md.getName(), md);
 2262           }
 2263           fireContainerEvent("addMessageDestination", md.getName());
 2264   
 2265       }
 2266   
 2267   
 2268       /**
 2269        * Add a message destination reference for this web application.
 2270        *
 2271        * @param mdr New message destination reference
 2272        */
 2273       public void addMessageDestinationRef
 2274           (MessageDestinationRef mdr) {
 2275   
 2276           namingResources.addMessageDestinationRef(mdr);
 2277           fireContainerEvent("addMessageDestinationRef", mdr.getName());
 2278   
 2279       }
 2280   
 2281   
 2282       /**
 2283        * Add a new MIME mapping, replacing any existing mapping for
 2284        * the specified extension.
 2285        *
 2286        * @param extension Filename extension being mapped
 2287        * @param mimeType Corresponding MIME type
 2288        */
 2289       public void addMimeMapping(String extension, String mimeType) {
 2290   
 2291           synchronized (mimeMappings) {
 2292               mimeMappings.put(extension, mimeType);
 2293           }
 2294           fireContainerEvent("addMimeMapping", extension);
 2295   
 2296       }
 2297   
 2298   
 2299       /**
 2300        * Add a new context initialization parameter.
 2301        *
 2302        * @param name Name of the new parameter
 2303        * @param value Value of the new  parameter
 2304        *
 2305        * @exception IllegalArgumentException if the name or value is missing,
 2306        *  or if this context initialization parameter has already been
 2307        *  registered
 2308        */
 2309       public void addParameter(String name, String value) {
 2310           // Validate the proposed context initialization parameter
 2311           if ((name == null) || (value == null))
 2312               throw new IllegalArgumentException
 2313                   (sm.getString("standardContext.parameter.required"));
 2314           if (parameters.get(name) != null)
 2315               throw new IllegalArgumentException
 2316                   (sm.getString("standardContext.parameter.duplicate", name));
 2317   
 2318           // Add this parameter to our defined set
 2319           synchronized (parameters) {
 2320               parameters.put(name, value);
 2321           }
 2322           fireContainerEvent("addParameter", name);
 2323   
 2324       }
 2325   
 2326   
 2327       /**
 2328        * Add a security role reference for this web application.
 2329        *
 2330        * @param role Security role used in the application
 2331        * @param link Actual security role to check for
 2332        */
 2333       public void addRoleMapping(String role, String link) {
 2334   
 2335           synchronized (roleMappings) {
 2336               roleMappings.put(role, link);
 2337           }
 2338           fireContainerEvent("addRoleMapping", role);
 2339   
 2340       }
 2341   
 2342   
 2343       /**
 2344        * Add a new security role for this web application.
 2345        *
 2346        * @param role New security role
 2347        */
 2348       public void addSecurityRole(String role) {
 2349   
 2350           synchronized (securityRoles) {
 2351               String results[] =new String[securityRoles.length + 1];
 2352               for (int i = 0; i < securityRoles.length; i++)
 2353                   results[i] = securityRoles[i];
 2354               results[securityRoles.length] = role;
 2355               securityRoles = results;
 2356           }
 2357           fireContainerEvent("addSecurityRole", role);
 2358   
 2359       }
 2360   
 2361   
 2362       /**
 2363        * Add a new servlet mapping, replacing any existing mapping for
 2364        * the specified pattern.
 2365        *
 2366        * @param pattern URL pattern to be mapped
 2367        * @param name Name of the corresponding servlet to execute
 2368        *
 2369        * @exception IllegalArgumentException if the specified servlet name
 2370        *  is not known to this Context
 2371        */
 2372       public void addServletMapping(String pattern, String name) {
 2373           addServletMapping(pattern, name, false);
 2374       }
 2375   
 2376   
 2377       /**
 2378        * Add a new servlet mapping, replacing any existing mapping for
 2379        * the specified pattern.
 2380        *
 2381        * @param pattern URL pattern to be mapped
 2382        * @param name Name of the corresponding servlet to execute
 2383        * @param jspWildCard true if name identifies the JspServlet
 2384        * and pattern contains a wildcard; false otherwise
 2385        *
 2386        * @exception IllegalArgumentException if the specified servlet name
 2387        *  is not known to this Context
 2388        */
 2389       public void addServletMapping(String pattern, String name,
 2390                                     boolean jspWildCard) {
 2391           // Validate the proposed mapping
 2392           if (findChild(name) == null)
 2393               throw new IllegalArgumentException
 2394                   (sm.getString("standardContext.servletMap.name", name));
 2395           pattern = adjustURLPattern(RequestUtil.URLDecode(pattern));
 2396           if (!validateURLPattern(pattern))
 2397               throw new IllegalArgumentException
 2398                   (sm.getString("standardContext.servletMap.pattern", pattern));
 2399   
 2400           // Add this mapping to our registered set
 2401           synchronized (servletMappings) {
 2402               String name2 = (String) servletMappings.get(pattern);
 2403               if (name2 != null) {
 2404                   // Don't allow more than one servlet on the same pattern
 2405                   Wrapper wrapper = (Wrapper) findChild(name2);
 2406                   wrapper.removeMapping(pattern);
 2407                   mapper.removeWrapper(pattern);
 2408               }
 2409               servletMappings.put(pattern, name);
 2410           }
 2411           Wrapper wrapper = (Wrapper) findChild(name);
 2412           wrapper.addMapping(pattern);
 2413   
 2414           // Update context mapper
 2415           mapper.addWrapper(pattern, wrapper, jspWildCard);
 2416   
 2417           fireContainerEvent("addServletMapping", pattern);
 2418   
 2419       }
 2420   
 2421   
 2422       /**
 2423        * Add a JSP tag library for the specified URI.
 2424        *
 2425        * @param uri URI, relative to the web.xml file, of this tag library
 2426        * @param location Location of the tag library descriptor
 2427        */
 2428       public void addTaglib(String uri, String location) {
 2429   
 2430           synchronized (taglibs) {
 2431               taglibs.put(uri, location);
 2432           }
 2433           fireContainerEvent("addTaglib", uri);
 2434   
 2435       }
 2436   
 2437   
 2438       /**
 2439        * Add a new watched resource to the set recognized by this Context.
 2440        *
 2441        * @param name New watched resource file name
 2442        */
 2443       public void addWatchedResource(String name) {
 2444   
 2445           synchronized (watchedResources) {
 2446               String results[] = new String[watchedResources.length + 1];
 2447               for (int i = 0; i < watchedResources.length; i++)
 2448                   results[i] = watchedResources[i];
 2449               results[watchedResources.length] = name;
 2450               watchedResources = results;
 2451           }
 2452           fireContainerEvent("addWatchedResource", name);
 2453   
 2454       }
 2455   
 2456   
 2457       /**
 2458        * Add a new welcome file to the set recognized by this Context.
 2459        *
 2460        * @param name New welcome file name
 2461        */
 2462       public void addWelcomeFile(String name) {
 2463   
 2464           synchronized (welcomeFiles) {
 2465               // Welcome files from the application deployment descriptor
 2466               // completely replace those from the default conf/web.xml file
 2467               if (replaceWelcomeFiles) {
 2468                   welcomeFiles = new String[0];
 2469                   setReplaceWelcomeFiles(false);
 2470               }
 2471               String results[] =new String[welcomeFiles.length + 1];
 2472               for (int i = 0; i < welcomeFiles.length; i++)
 2473                   results[i] = welcomeFiles[i];
 2474               results[welcomeFiles.length] = name;
 2475               welcomeFiles = results;
 2476           }
 2477           postWelcomeFiles();
 2478           fireContainerEvent("addWelcomeFile", name);
 2479   
 2480       }
 2481   
 2482   
 2483       /**
 2484        * Add the classname of a LifecycleListener to be added to each
 2485        * Wrapper appended to this Context.
 2486        *
 2487        * @param listener Java class name of a LifecycleListener class
 2488        */
 2489       public void addWrapperLifecycle(String listener) {
 2490   
 2491           synchronized (wrapperLifecycles) {
 2492               String results[] =new String[wrapperLifecycles.length + 1];
 2493               for (int i = 0; i < wrapperLifecycles.length; i++)
 2494                   results[i] = wrapperLifecycles[i];
 2495               results[wrapperLifecycles.length] = listener;
 2496               wrapperLifecycles = results;
 2497           }
 2498           fireContainerEvent("addWrapperLifecycle", listener);
 2499   
 2500       }
 2501   
 2502   
 2503       /**
 2504        * Add the classname of a ContainerListener to be added to each
 2505        * Wrapper appended to this Context.
 2506        *
 2507        * @param listener Java class name of a ContainerListener class
 2508        */
 2509       public void addWrapperListener(String listener) {
 2510   
 2511           synchronized (wrapperListeners) {
 2512               String results[] =new String[wrapperListeners.length + 1];
 2513               for (int i = 0; i < wrapperListeners.length; i++)
 2514                   results[i] = wrapperListeners[i];
 2515               results[wrapperListeners.length] = listener;
 2516               wrapperListeners = results;
 2517           }
 2518           fireContainerEvent("addWrapperListener", listener);
 2519   
 2520       }
 2521   
 2522   
 2523       /**
 2524        * Factory method to create and return a new Wrapper instance, of
 2525        * the Java implementation class appropriate for this Context
 2526        * implementation.  The constructor of the instantiated Wrapper
 2527        * will have been called, but no properties will have been set.
 2528        */
 2529       public Wrapper createWrapper() {
 2530   
 2531           Wrapper wrapper = null;
 2532           if (wrapperClass != null) {
 2533               try {
 2534                   wrapper = (Wrapper) wrapperClass.newInstance();
 2535               } catch (Throwable t) {
 2536                   log.error("createWrapper", t);
 2537                   return (null);
 2538               }
 2539           } else {
 2540               wrapper = new StandardWrapper();
 2541           }
 2542   
 2543           synchronized (instanceListeners) {
 2544               for (int i = 0; i < instanceListeners.length; i++) {
 2545                   try {
 2546                       Class clazz = Class.forName(instanceListeners[i]);
 2547                       InstanceListener listener =
 2548                         (InstanceListener) clazz.newInstance();
 2549                       wrapper.addInstanceListener(listener);
 2550                   } catch (Throwable t) {
 2551                       log.error("createWrapper", t);
 2552                       return (null);
 2553                   }
 2554               }
 2555           }
 2556   
 2557           synchronized (wrapperLifecycles) {
 2558               for (int i = 0; i < wrapperLifecycles.length; i++) {
 2559                   try {
 2560                       Class clazz = Class.forName(wrapperLifecycles[i]);
 2561                       LifecycleListener listener =
 2562                         (LifecycleListener) clazz.newInstance();
 2563                       if (wrapper instanceof Lifecycle)
 2564                           ((Lifecycle) wrapper).addLifecycleListener(listener);
 2565                   } catch (Throwable t) {
 2566                       log.error("createWrapper", t);
 2567                       return (null);
 2568                   }
 2569               }
 2570           }
 2571   
 2572           synchronized (wrapperListeners) {
 2573               for (int i = 0; i < wrapperListeners.length; i++) {
 2574                   try {
 2575                       Class clazz = Class.forName(wrapperListeners[i]);
 2576                       ContainerListener listener =
 2577                         (ContainerListener) clazz.newInstance();
 2578                       wrapper.addContainerListener(listener);
 2579                   } catch (Throwable t) {
 2580                       log.error("createWrapper", t);
 2581                       return (null);
 2582                   }
 2583               }
 2584           }
 2585   
 2586           return (wrapper);
 2587   
 2588       }
 2589   
 2590   
 2591       /**
 2592        * Return the set of application listener class names configured
 2593        * for this application.
 2594        */
 2595       public String[] findApplicationListeners() {
 2596   
 2597           return (applicationListeners);
 2598   
 2599       }
 2600   
 2601   
 2602       /**
 2603        * Return the set of application parameters for this application.
 2604        */
 2605       public ApplicationParameter[] findApplicationParameters() {
 2606   
 2607           return (applicationParameters);
 2608   
 2609       }
 2610   
 2611   
 2612       /**
 2613        * Return the security constraints for this web application.
 2614        * If there are none, a zero-length array is returned.
 2615        */
 2616       public SecurityConstraint[] findConstraints() {
 2617   
 2618           return (constraints);
 2619   
 2620       }
 2621   
 2622   
 2623       /**
 2624        * Return the error page entry for the specified HTTP error code,
 2625        * if any; otherwise return <code>null</code>.
 2626        *
 2627        * @param errorCode Error code to look up
 2628        */
 2629       public ErrorPage findErrorPage(int errorCode) {
 2630           if (errorCode == 200) {
 2631               return (okErrorPage);
 2632           } else {
 2633               return ((ErrorPage) statusPages.get(new Integer(errorCode)));
 2634           }
 2635   
 2636       }
 2637   
 2638   
 2639       /**
 2640        * Return the error page entry for the specified Java exception type,
 2641        * if any; otherwise return <code>null</code>.
 2642        *
 2643        * @param exceptionType Exception type to look up
 2644        */
 2645       public ErrorPage findErrorPage(String exceptionType) {
 2646   
 2647           synchronized (exceptionPages) {
 2648               return ((ErrorPage) exceptionPages.get(exceptionType));
 2649           }
 2650   
 2651       }
 2652   
 2653   
 2654       /**
 2655        * Return the set of defined error pages for all specified error codes
 2656        * and exception types.
 2657        */
 2658       public ErrorPage[] findErrorPages() {
 2659   
 2660           synchronized(exceptionPages) {
 2661               synchronized(statusPages) {
 2662                   ErrorPage results1[] = new ErrorPage[exceptionPages.size()];
 2663                   results1 =
 2664                       (ErrorPage[]) exceptionPages.values().toArray(results1);
 2665                   ErrorPage results2[] = new ErrorPage[statusPages.size()];
 2666                   results2 =
 2667                       (ErrorPage[]) statusPages.values().toArray(results2);
 2668                   ErrorPage results[] =
 2669                       new ErrorPage[results1.length + results2.length];
 2670                   for (int i = 0; i < results1.length; i++)
 2671                       results[i] = results1[i];
 2672                   for (int i = results1.length; i < results.length; i++)
 2673                       results[i] = results2[i - results1.length];
 2674                   return (results);
 2675               }
 2676           }
 2677   
 2678       }
 2679   
 2680   
 2681       /**
 2682        * Return the filter definition for the specified filter name, if any;
 2683        * otherwise return <code>null</code>.
 2684        *
 2685        * @param filterName Filter name to look up
 2686        */
 2687       public FilterDef findFilterDef(String filterName) {
 2688   
 2689           synchronized (filterDefs) {
 2690               return ((FilterDef) filterDefs.get(filterName));
 2691           }
 2692   
 2693       }
 2694   
 2695   
 2696       /**
 2697        * Return the set of defined filters for this Context.
 2698        */
 2699       public FilterDef[] findFilterDefs() {
 2700   
 2701           synchronized (filterDefs) {
 2702               FilterDef results[] = new FilterDef[filterDefs.size()];
 2703               return ((FilterDef[]) filterDefs.values().toArray(results));
 2704           }
 2705   
 2706       }
 2707   
 2708   
 2709       /**
 2710        * Return the set of filter mappings for this Context.
 2711        */
 2712       public FilterMap[] findFilterMaps() {
 2713   
 2714           return (filterMaps);
 2715   
 2716       }
 2717   
 2718   
 2719       /**
 2720        * Return the set of InstanceListener classes that will be added to
 2721        * newly created Wrappers automatically.
 2722        */
 2723       public String[] findInstanceListeners() {
 2724   
 2725           return (instanceListeners);
 2726   
 2727       }
 2728   
 2729   
 2730       /**
 2731        * FIXME: Fooling introspection ...
 2732        */
 2733       public Context findMappingObject() {
 2734           return (Context) getMappingObject();
 2735       }
 2736       
 2737       
 2738       /**
 2739        * Return the message destination with the specified name, if any;
 2740        * otherwise, return <code>null</code>.
 2741        *
 2742        * @param name Name of the desired message destination
 2743        */
 2744       public MessageDestination findMessageDestination(String name) {
 2745   
 2746           synchronized (messageDestinations) {
 2747               return ((MessageDestination) messageDestinations.get(name));
 2748           }
 2749   
 2750       }
 2751   
 2752   
 2753       /**
 2754        * Return the set of defined message destinations for this web
 2755        * application.  If none have been defined, a zero-length array
 2756        * is returned.
 2757        */
 2758       public MessageDestination[] findMessageDestinations() {
 2759   
 2760           synchronized (messageDestinations) {
 2761               MessageDestination results[] =
 2762                   new MessageDestination[messageDestinations.size()];
 2763               return ((MessageDestination[])
 2764                       messageDestinations.values().toArray(results));
 2765           }
 2766   
 2767       }
 2768   
 2769   
 2770       /**
 2771        * Return the message destination ref with the specified name, if any;
 2772        * otherwise, return <code>null</code>.
 2773        *
 2774        * @param name Name of the desired message destination ref
 2775        */
 2776       public MessageDestinationRef
 2777           findMessageDestinationRef(String name) {
 2778   
 2779           return namingResources.findMessageDestinationRef(name);
 2780   
 2781       }
 2782   
 2783   
 2784       /**
 2785        * Return the set of defined message destination refs for this web
 2786        * application.  If none have been defined, a zero-length array
 2787        * is returned.
 2788        */
 2789       public MessageDestinationRef[]
 2790           findMessageDestinationRefs() {
 2791   
 2792           return namingResources.findMessageDestinationRefs();
 2793   
 2794       }
 2795   
 2796   
 2797       /**
 2798        * Return the MIME type to which the specified extension is mapped,
 2799        * if any; otherwise return <code>null</code>.
 2800        *
 2801        * @param extension Extension to map to a MIME type
 2802        */
 2803       public String findMimeMapping(String extension) {
 2804   
 2805           return ((String) mimeMappings.get(extension));
 2806   
 2807       }
 2808   
 2809   
 2810       /**
 2811        * Return the extensions for which MIME mappings are defined.  If there
 2812        * are none, a zero-length array is returned.
 2813        */
 2814       public String[] findMimeMappings() {
 2815   
 2816           synchronized (mimeMappings) {
 2817               String results[] = new String[mimeMappings.size()];
 2818               return
 2819                   ((String[]) mimeMappings.keySet().toArray(results));
 2820           }
 2821   
 2822       }
 2823   
 2824   
 2825       /**
 2826        * Return the value for the specified context initialization
 2827        * parameter name, if any; otherwise return <code>null</code>.
 2828        *
 2829        * @param name Name of the parameter to return
 2830        */
 2831       public String findParameter(String name) {
 2832   
 2833           synchronized (parameters) {
 2834               return ((String) parameters.get(name));
 2835           }
 2836   
 2837       }
 2838   
 2839   
 2840       /**
 2841        * Return the names of all defined context initialization par