Package org.apache.catalina.core

Source Code of org.apache.catalina.core.StandardContext

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.catalina.core;

import com.sun.grizzly.util.buf.CharChunk;
import com.sun.grizzly.util.buf.MessageBytes;
import com.sun.grizzly.util.http.mapper.AlternateDocBase;
import com.sun.grizzly.util.http.mapper.Mapper;
import com.sun.grizzly.util.http.mapper.MappingData;
import org.apache.catalina.*;
import org.apache.catalina.deploy.*;
import org.apache.catalina.loader.WebappLoader;
import org.apache.catalina.mbeans.MBeanUtils;
import org.apache.catalina.session.ManagerBase;
import org.apache.catalina.session.PersistentManagerBase;
import org.apache.catalina.session.StandardManager;
import org.apache.catalina.servlets.DefaultServlet;
import org.apache.catalina.startup.ContextConfig;
import org.apache.catalina.util.*;
import org.apache.naming.ContextBindings;
import org.apache.naming.resources.BaseDirContext;
import org.apache.naming.resources.DirContextURLStreamHandler;
import org.apache.naming.resources.FileDirContext;
import org.apache.naming.resources.ProxyDirContext;
import org.apache.naming.resources.Resource;
import org.apache.naming.resources.WARDirContext;
import org.apache.tomcat.util.modeler.ManagedBean;
import org.apache.tomcat.util.modeler.Registry;
import org.glassfish.hk2.classmodel.reflect.Types;
import org.glassfish.web.loader.WebappClassLoader;
import org.glassfish.web.loader.ServletContainerInitializerUtil;
import org.glassfish.web.valve.GlassFishValve;

import javax.management.*;
import javax.naming.Binding;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.servlet.*;
import javax.servlet.descriptor.JspConfigDescriptor;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionListener;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URLDecoder;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Standard implementation of the <b>Context</b> interface.  Each
* child container must be a Wrapper implementation to process the
* requests directed to a particular servlet.
*
* @author Craig R. McClanahan
* @author Remy Maucherat
* @version $Revision: 1.48 $ $Date: 2007/07/25 00:52:04 $
*/

public class StandardContext
    extends ContainerBase
    implements Context, ServletContext
{
    private static final transient Logger log = Logger.getLogger(
        StandardContext.class.getName());

    private static final ClassLoader standardContextClassLoader =
        StandardContext.class.getClassLoader();

    private static final Set<SessionTrackingMode> DEFAULT_SESSION_TRACKING_MODES =
        EnumSet.of(SessionTrackingMode.COOKIE);

    /**
     * Array containing the safe characters set.
     */
    protected static final URLEncoder urlEncoder;

    /**
     * The descriptive information string for this implementation.
     */
    private static final String info =
        "org.apache.catalina.core.StandardContext/1.0";

    private static final RuntimePermission GET_CLASSLOADER_PERMISSION =
        new RuntimePermission("getClassLoader");

    /**
     * GMT timezone - all HTTP dates are on GMT
     */
    static {
        urlEncoder = new URLEncoder();
        urlEncoder.addSafeCharacter('~');
        urlEncoder.addSafeCharacter('-');
        urlEncoder.addSafeCharacter('_');
        urlEncoder.addSafeCharacter('.');
        urlEncoder.addSafeCharacter('*');
        urlEncoder.addSafeCharacter('/');
    }


    // ----------------------------------------------------------- Constructors

    /**
     * Create a new StandardContext component with the default basic Valve.
     */
    public StandardContext() {
        pipeline.setBasic(new StandardContextValve());
        namingResources.setContainer(this);
        broadcaster = new NotificationBroadcasterSupport();
        if (Globals.IS_SECURITY_ENABLED) {
            mySecurityManager = AccessController.doPrivileged(
                    new PrivilegedCreateSecurityManager());
        }
       
        //START PWC 6403328
        this.logPrefix = sm.getString("standardContext.logPrefix", logName());
        //END PWC 6403328
    }

    // ----------------------------------------------------- Instance Variables

    /**
     * The alternate deployment descriptor name.
     */
    private String altDDName = null;

    /**
     * Associated host name.
     */
    private String hostName;
   
    /**
     * The list of instantiated application event listeners
     */
    private transient List<EventListener> eventListeners =
        new ArrayList<EventListener>();

    /**
     * The list of ServletContextListeners
     */
    protected transient ArrayList<ServletContextListener> contextListeners =
        new ArrayList<ServletContextListener>();

    /**
     * The list of HttpSessionListeners
     */
    private transient List<HttpSessionListener> sessionListeners =
        new ArrayList<HttpSessionListener>();

    /**
     * The set of application parameters defined for this application.
     */
    private List<ApplicationParameter> applicationParameters =
        new ArrayList<ApplicationParameter>();

    /**
     * The application available flag for this Context.
     */
    private boolean available = false;

    /**
     * The broadcaster that sends j2ee notifications.
     */
    private transient NotificationBroadcasterSupport broadcaster = null;

    /**
     * The Locale to character set mapper for this application.
     */
    private transient CharsetMapper charsetMapper = null;

    /**
     * The Java class name of the CharsetMapper class to be created.
     */
    private String charsetMapperClass = CharsetMapper.class.getName();

    /**
     * The path to a file to save this Context information.
     */
    private String configFile = null;

    /**
     * The "correctly configured" flag for this Context.
     */
    private boolean configured = false;

    /**
     * The security constraints for this web application.
     */
    private List<SecurityConstraint> constraints =
        new ArrayList<SecurityConstraint>();

    /**
     * The ServletContext implementation associated with this Context.
     */
    // START RIMOD 4894300
    /*
    private transient ApplicationContext context = null;
    */
    protected transient ApplicationContext context = null;
    // END RIMOD 4894300

    /**
     *  Is the context initialized.
     */
    private boolean isContextInitializedCalled = false;

    /**
     * Compiler classpath to use.
     */
    private String compilerClasspath = null;

    /**
     * Should we attempt to use cookies for session id communication?
     */
    private boolean cookies = true;

    /**
     * true if the rewriting of URLs with the jsessionids of HTTP
     * sessions belonging to this context is enabled, false otherwise
     */
    private boolean enableURLRewriting = true;

    /**
     * Should we allow the <code>ServletContext.getContext()</code> method
     * to access the context of other web applications in this server?
     */
    private boolean crossContext = false;

    /**
     * The "follow standard delegation model" flag that will be used to
     * configure our ClassLoader.
     */
    private boolean delegate = false;

    /**
     * The display name of this web application.
     */
    private String displayName = null;

    /**
     * Override the default web xml location. ContextConfig is not configurable
     * so the setter is not used.
     */
    private String defaultWebXml;

    /**
     * The distributable flag for this web application.
     */
    private boolean distributable = false;
   
    /**
     * Thread local data used during request dispatch.
     */
    private transient ThreadLocal<DispatchData> dispatchData =
        new ThreadLocal<DispatchData>();
       
    /**
     * The document root for this web application.
     */
    private String docBase = null;

    /**
     * The exception pages for this web application, keyed by fully qualified
     * class name of the Java exception.
     */
    private Map<String, ErrorPage> exceptionPages =
        new HashMap<String, ErrorPage>();

    /**
     * The default error page (error page that was declared
     * without any exception-type and error-code).
     */
    private ErrorPage defaultErrorPage;

    /**
     * The set of filter configurations (and associated filter instances) we
     * have initialized, keyed by filter name.
     */
    private Map<String, FilterConfig> filterConfigs =
        new HashMap<String, FilterConfig>();

    /**
     * The set of filter definitions for this application, keyed by
     * filter name.
     */
    private Map<String, FilterDef> filterDefs = new HashMap<String, FilterDef>();

    /**
     * The list of filter mappings for this application, in the order
     * they were defined in the deployment descriptor.
     */
    private List<FilterMap> filterMaps = new ArrayList<FilterMap>();

    /**
     * The list of classnames of InstanceListeners that will be added
     * to each newly created Wrapper by <code>createWrapper()</code>.
     */
    private ArrayList<String> instanceListeners = new ArrayList<String>();

    /**
     * The set of already instantiated InstanceListeners that will be added
     * to each newly created Wrapper by <code>createWrapper()</code>.
     */
    private List<InstanceListener> instanceListenerInstances = new ArrayList<InstanceListener>();

    /**
     * The login configuration descriptor for this web application.
     */
    private LoginConfig loginConfig = null;
   
    // START PWC 6403328
    /**
     * Log prefix string
     */
    private String logPrefix = null;
    // END PWC 6403328
   
    /**
     * The mapper associated with this context.
     */
    private transient Mapper mapper = new Mapper();

    /**
     * The naming context listener for this web application.
     */
    private transient NamingContextListener namingContextListener = null;

    /**
     * The naming resources for this web application.
     */
    private NamingResources namingResources = new NamingResources();

    /**
     * The message destinations for this web application.
     */
    private Map<String, MessageDestination> messageDestinations = new HashMap<String, MessageDestination>();

    /**
     * The MIME mappings for this web application, keyed by extension.
     */
    private HashMap<String,String> mimeMappings = new HashMap<String,String>();

    /**
     * The context initialization parameters for this web application,
     * keyed by name.
     */
    private HashMap<String, String> parameters = new HashMap<String, String>();

    /**
     * The request processing pause flag (while reloading occurs)
     */
    private boolean paused = false;

    /**
     * The public identifier of the DTD for the web application deployment
     * descriptor version we are currently parsing.  This is used to support
     * relaxed validation rules when processing version 2.2 web.xml files.
     */
    private String publicId = null;

    /**
     * The reloadable flag for this web application.
     */
    private boolean reloadable = false;

    /**
     * Unpack WAR property.
     */
    private boolean unpackWAR = true;

    /**
     * The DefaultContext override flag for this web application.
     */
    private boolean override = false;
      
    /**
     * The original document root for this web application.
     */
    private String originalDocBase = null;

    /**
     * The privileged flag for this web application.
     */
    private boolean privileged = false;

    /**
     * Should the next call to <code>addWelcomeFile()</code> cause replacement
     * of any existing welcome files?  This will be set before processing the
     * web application's deployment descriptor, so that application specified
     * choices <strong>replace</strong>, rather than append to, those defined
     * in the global descriptor.
     */
    private boolean replaceWelcomeFiles = false;

    /**
     * With proxy caching disabled, setting this flag to true adds
     * Pragma and Cache-Control headers with "No-cache" as value.
     * Setting this flag to false does not add any Pragma header,
     * but sets the Cache-Control header to "private".
     */
    private boolean securePagesWithPragma = true;

    /**
     * The security role mappings for this application, keyed by role
     * name (as used within the application).
     */
    private Map<String, String> roleMappings = new HashMap<String, String>();

    /**
     * The security roles for this application
     */
    private List<String> securityRoles = new ArrayList<String>();

    /**
     * The servlet mappings for this web application, keyed by
     * matching pattern.
     */
    private final Map<String, String> servletMappings = new HashMap<String, String>();

    /**
     * The session timeout (in minutes) for this web application.
     */
    private int sessionTimeout = 30;

    /**
     * Has the session timeout (in minutes) for this web application
     * been over-ridden by web-xml
     * HERCULES:add
     */
    private boolean sessionTimeoutOveridden = false;

    /**
     * The notification sequence number.
     */
    private long sequenceNumber = 0;

    /**
     * The status code error pages for this web application, keyed by
     * HTTP status code (as an Integer).
     */
    private final Map<Integer, ErrorPage> statusPages =
        new HashMap<Integer, ErrorPage>();

    /**
     * The watched resources for this application.
     */
    private List<String> watchedResources =
            Collections.synchronizedList(new ArrayList<String>());

    /**
     * The welcome files for this application.
     */
    private String[] welcomeFiles = new String[0];

    /**
     * The list of classnames of LifecycleListeners that will be added
     * to each newly created Wrapper by <code>createWrapper()</code>.
     */
    private ArrayList<String> wrapperLifecycles = new ArrayList<String>();

    /**
     * The list of classnames of ContainerListeners that will be added
     * to each newly created Wrapper by <code>createWrapper()</code>.
     */
    private List<String> wrapperListeners = new ArrayList<String>();

    /**
     * The pathname to the work directory for this context (relative to
     * the server's home if not absolute).
     */
    private String workDir = null;

    /**
     * JNDI use flag.
     */
    private boolean useNaming = true;

    /**
     * Filesystem based flag.
     */
    private boolean filesystemBased = false;

    /**
     * Name of the associated naming context.
     */
    private String namingContextName = null;

    /**
     * Frequency of the session expiration, and related manager operations.
     * Manager operations will be done once for the specified amount of
     * backgrondProcess calls (ie, the lower the amount, the most often the
     * checks will occur).
     */
    private int managerChecksFrequency = 6;

    /**
     * Iteration count for background processing.
     */
    private int count = 0;

    /**
     * Caching allowed flag.
     */
    private boolean cachingAllowed = true;

    /**
     * Case sensitivity.
     */
    protected boolean caseSensitive = true;

    /**
     * Allow linking.
     */
    protected boolean allowLinking = false;

    /**
     * Cache max size in KB.
     */
    protected int cacheMaxSize = 10240; // 10 MB

    /**
     * Cache TTL in ms.
     */
    protected int cacheTTL = 5000;

    /**
     * Non proxied resources.
     */
    private transient DirContext webappResources = null;

    /*
     * Time (in milliseconds) it took to start this context
     */
    private long startupTime;

    /*
     * Time (in milliseconds since January 1, 1970, 00:00:00) when this
     * context was started
     */
    private long startTimeMillis;

    private long tldScanTime;

    // START SJSWS 6324431
    // Should the filter and security mapping be done
    // in a case sensitive manner
    protected boolean caseSensitiveMapping = true;
    // END SJSWS 6324431

    // START S1AS8PE 4817642
    /**
     * The flag that specifies whether to reuse the session id (if any) from
     * the request for newly created sessions
     */
    private boolean reuseSessionID = false;
    // END S1AS8PE 4817642

    // START RIMOD 4642650
    /**
     * The flag that specifies whether this context allows sendRedirect() to
     * redirect to a relative URL.
     */
    private boolean allowRelativeRedirect = false;

    // END RIMOD 4642650

    /** Name of the engine. If null, the domain is used.
     */
    private String engineName = null;
    /* SJSAS 6340499
    private String j2EEApplication="none";
     */
    // START SJSAS 6340499
    private String j2EEApplication="null";
    // END SJSAS 6340499
    private String j2EEServer="none";

    // START IASRI 4823322
    /**
     * List of configured Auditors for this context.
     */
    private transient Auditor[] auditors = null;
    // END IASRI 4823322

    // START RIMOD 4868393
    /**
     * used to create unique id for each app instance.
     */
    private static int instanceIDCounter = 1;
    // END RIMOD 4868393

    /**
     * Attribute value used to turn on/off XML validation
     */
    private boolean webXmlValidation = false;

    private String jvmRoute;

    /**
     * Attribute value used to turn on/off XML namespace validation
     */
    private boolean webXmlNamespaceAware = false;

    /**
     * Attribute value used to turn on/off XML validation
     */
    private boolean tldValidation = false;

    /**
     * Attribute value used to turn on/off TLD XML namespace validation
     */
    private boolean tldNamespaceAware = false;

    /**
     * Is the context contains the JSF servlet.
     */
    protected boolean isJsfApplication = false;

    // START S1AS8PE 4965017
    private boolean isReload = false;
    // END S1AS8PE 4965017

    /**
     * Alternate doc base resources
     */
    private ArrayList<AlternateDocBase> alternateDocBases = null;

    private boolean useMyFaces;

    private Set<SessionTrackingMode> sessionTrackingModes;

    /**
     * Encoded path.
     */
    private String encodedPath = null;

    /**
     * Session cookie config
     */
    private SessionCookieConfig sessionCookieConfig;

    /**
     * The name of the session tracking cookies created by this context
     * Cache the name here as the getSessionCookieConfig() is synchronized.
     */
    private String sessionCookieName = Globals.SESSION_COOKIE_NAME;

    private boolean sessionCookieNameInitialized = false;

    protected ConcurrentHashMap<String, ServletRegistrationImpl> servletRegisMap =
        new ConcurrentHashMap<String, ServletRegistrationImpl>();

    protected ConcurrentHashMap<String, FilterRegistrationImpl> filterRegisMap =
        new ConcurrentHashMap<String, FilterRegistrationImpl>();

    /**
     * The list of ordered libs, which is used as the value of the
     * ServletContext attribute with name javax.servlet.context.orderedLibs
     */
    private List<String> orderedLibs;

    // <jsp-config> related info aggregated from web.xml and web-fragment.xml
    private JspConfigDescriptor jspConfigDesc;

    // ServletContextListeners may be registered (via
    // ServletContext#addListener) only within the scope of
    // ServletContainerInitializer#onStartup
    private boolean isProgrammaticServletContextListenerRegistrationAllowed = false;

    /*
     * Security manager responsible for enforcing permission check on
     * ServletContext#getClassLoader
     */
    private transient MySecurityManager mySecurityManager;

    // Iterable over all ServletContainerInitializers that were discovered
    private Iterable<ServletContainerInitializer> servletContainerInitializers = null;

    // The major Servlet spec version of the web.xml
    private int effectiveMajorVersion = 0;

    // The minor Servlet spec version of the web.xml
    private int effectiveMinorVersion = 0;

    // Created via embedded API
    private boolean isEmbedded = false;

    // ----------------------------------------------------- Context Properties

    public String getEncodedPath() {
        return encodedPath;
    }

    @Override
    public void setName( String name ) {
        super.setName( name );
        encodedPath = urlEncoder.encode(name);
    }

    /**
     * Is caching allowed ?
     */
    public boolean isCachingAllowed() {
        return cachingAllowed;
    }

    /**
     * Set caching allowed flag.
     */
    public void setCachingAllowed(boolean cachingAllowed) {
        this.cachingAllowed = cachingAllowed;
    }

    /**
     * Set case sensitivity.
     */
    public void setCaseSensitive(boolean caseSensitive) {
        this.caseSensitive = caseSensitive;
    }

    /**
     * Is case sensitive ?
     */
    public boolean isCaseSensitive() {
        return caseSensitive;
    }

    // START SJSWS 6324431
    /**
     * Set case sensitivity for filter and security constraint mappings.
     */
    public void setCaseSensitiveMapping(boolean caseSensitiveMap) {
        caseSensitiveMapping = caseSensitiveMap;
    }

    /**
     * Are filters and security constraints mapped in a case sensitive manner?
     */
    public boolean isCaseSensitiveMapping() {
        return caseSensitiveMapping;
    }
    // END SJSWS 6324431

    /**
     * Set allow linking.
     */
    public void setAllowLinking(boolean allowLinking) {
        this.allowLinking = allowLinking;
    }

    /**
     * Is linking allowed.
     */
    public boolean isAllowLinking() {
        return allowLinking;
    }

    /**
     * Set cache TTL.
     */
    public void setCacheTTL(int cacheTTL) {
        this.cacheTTL = cacheTTL;
    }

    /**
     * Get cache TTL.
     */
    public int getCacheTTL() {
        return cacheTTL;
    }

    /**
     * Return the maximum size of the cache in KB.
     */
    public int getCacheMaxSize() {
        return cacheMaxSize;
    }

    /**
     * Set the maximum size of the cache in KB.
     */
    public void setCacheMaxSize(int cacheMaxSize) {
        this.cacheMaxSize = cacheMaxSize;
    }

    /**
     * Return the "follow standard delegation model" flag used to configure
     * our ClassLoader.
     */
    public boolean getDelegate() {
        return delegate;
    }

    /**
     * Set the "follow standard delegation model" flag used to configure
     * our ClassLoader.
     *
     * @param delegate The new flag
     */
    public void setDelegate(boolean delegate) {
        boolean oldDelegate = this.delegate;
        this.delegate = delegate;
        support.firePropertyChange("delegate", Boolean.valueOf(oldDelegate),
                                   Boolean.valueOf(this.delegate));
    }

    /**
     * Returns true if the internal naming support is used.
     */
    public boolean isUseNaming() {
        return useNaming;
    }

    /**
     * Enables or disables naming.
     */
    public void setUseNaming(boolean useNaming) {
        this.useNaming = useNaming;
    }

    /**
     * @return true if the resources associated with this context are
     * filesystem based, false otherwise
     */
    public boolean isFilesystemBased() {
        return filesystemBased;
    }

    /**
     * @return the list of initialized application event listeners
     * of this application, in the order in which they have been specified
     * in the deployment descriptor
     */
    public List<EventListener> getApplicationEventListeners() {
        return eventListeners;
    }
   
    public List<HttpSessionListener> getSessionListeners() {
        return sessionListeners;
    }
   
    /**
     * Return the application available flag for this Context.
     */
    public boolean getAvailable() {
        return available;
    }

    /**
     * Set the application available flag for this Context.
     *
     * @param available The new application available flag
     */
    public void setAvailable(boolean available) {
        boolean oldAvailable = this.available;
        this.available = available;
        support.firePropertyChange("available", Boolean.valueOf(oldAvailable),
            Boolean.valueOf(this.available));
    }

    /**
     * Return the Locale to character set mapper for this Context.
     */
    public CharsetMapper getCharsetMapper() {

        // Create a mapper the first time it is requested
        if (this.charsetMapper == null) {
            try {
                Class clazz = Class.forName(charsetMapperClass);
                this.charsetMapper =
                  (CharsetMapper) clazz.newInstance();
            } catch (Throwable t) {
                this.charsetMapper = new CharsetMapper();
            }
        }

        return (this.charsetMapper);
    }

    /**
     * Set the Locale to character set mapper for this Context.
     *
     * @param mapper The new mapper
     */
    public void setCharsetMapper(CharsetMapper mapper) {
        CharsetMapper oldCharsetMapper = this.charsetMapper;
        this.charsetMapper = mapper;
        if( mapper != null )
            this.charsetMapperClass= mapper.getClass().getName();
        support.firePropertyChange("charsetMapper", oldCharsetMapper,
                                   this.charsetMapper);
    }

    /**
     * @return the path to a file to save this Context information
     */
    public String getConfigFile() {
        return configFile;
    }

    /**
     * Set the path to a file to save this Context information.
     *
     * @param configFile The path to a file to save this Context information
     */
    public void setConfigFile(String configFile) {
        this.configFile = configFile;
    }

    /**
     * @return the "correctly configured" flag for this Context
     */
    public boolean getConfigured() {
        return configured;
    }

    /**
     * Sets the "correctly configured" flag for this Context.  This can be
     * set to false by startup listeners that detect a fatal configuration
     * error to avoid the application from being made available.
     *
     * @param configured The new correctly configured flag
     */
    public void setConfigured(boolean configured) {
        boolean oldConfigured = this.configured;
        this.configured = configured;
        support.firePropertyChange("configured",
            Boolean.valueOf(oldConfigured), Boolean.valueOf(this.configured));
    }

    /**
     * @return the "use cookies for session ids" flag
     */
    public boolean getCookies() {
        return cookies;
    }

    /**
     * Set the "use cookies for session ids" flag.
     *
     * @param cookies The new flag
     */
    public void setCookies(boolean cookies) {
        boolean oldCookies = this.cookies;
        this.cookies = cookies;
        support.firePropertyChange("cookies",
                                   Boolean.valueOf(oldCookies),
                                   Boolean.valueOf(this.cookies));
    }

    /**
     * Checks whether the rewriting of URLs with the jsessionids of
     * HTTP sessions belonging to this context is enabled or not.
     *
     * @return true if the rewriting of URLs with the jsessionids of HTTP
     * sessions belonging to this context is enabled, false otherwise
     */
    public boolean isEnableURLRewriting() {
        return enableURLRewriting;
    }

    /**
     * Enables or disables the rewriting of URLs with the jsessionids of
     * HTTP sessions belonging to this context.
     *
     * @param enableURLRewriting true if the rewriting of URLs with the
     * jsessionids of HTTP sessions belonging to this context should be
     * enabled, false otherwise
     */
    public void setEnableURLRewriting(boolean enableURLRewriting) {
        boolean oldEnableURLRewriting = this.enableURLRewriting;
        this.enableURLRewriting = enableURLRewriting;
        support.firePropertyChange("enableURLRewriting",
                                   Boolean.valueOf(oldEnableURLRewriting),
                                   Boolean.valueOf(this.enableURLRewriting));
    }


    /**
     * @return the "allow crossing servlet contexts" flag
     */
    public boolean getCrossContext() {
        return (this.crossContext);
    }

    /**
     * Sets the "allow crossing servlet contexts" flag.
     *
     * @param crossContext The new cross contexts flag
     */
    public void setCrossContext(boolean crossContext) {

        boolean oldCrossContext = this.crossContext;
        this.crossContext = crossContext;
        support.firePropertyChange("crossContext",
                                   Boolean.valueOf(oldCrossContext),
                                   Boolean.valueOf(this.crossContext));
    }

    public String getDefaultWebXml() {
        return defaultWebXml;
    }

    /** Set the location of the default web xml that will be used.
     * If not absolute, it'll be made relative to the engine's base dir
     * ( which defaults to catalina.base system property ).
     *
     * XXX  If a file is not found - we can attempt a getResource()
     *
     * @param defaultWebXml
     */
    public void setDefaultWebXml(String defaultWebXml) {
        this.defaultWebXml = defaultWebXml;
    }

    /**
     * Gets the time (in milliseconds) it took to start this context.
     *
     * @return Time (in milliseconds) it took to start this context.
     */
    public long getStartupTime() {
        return startupTime;
    }

    public void setStartupTime(long startupTime) {
        this.startupTime = startupTime;
    }

    public long getTldScanTime() {
        return tldScanTime;
    }

    public void setTldScanTime(long tldScanTime) {
        this.tldScanTime = tldScanTime;
    }

    /**
     * Return the display name of this web application.
     */
    public String getDisplayName() {

        return (this.displayName);

    }

    /**
     * Return the alternate Deployment Descriptor name.
     */
    public String getAltDDName(){
        return altDDName;
    }

    /**
     * Set an alternate Deployment Descriptor name.
     */
    public void setAltDDName(String altDDName) {
        this.altDDName = altDDName;
        if (context != null) {
            context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
            context.setAttributeReadOnly(Globals.ALT_DD_ATTR);
        }
    }

    /**
     * Return the compiler classpath.
     */
    public String getCompilerClasspath(){
        return compilerClasspath;
    }

    /**
     * Set the compiler classpath.
     */
    public void setCompilerClasspath(String compilerClasspath) {
        this.compilerClasspath = compilerClasspath;
    }

    /**
     * Set the display name of this web application.
     *
     * @param displayName The new display name
     */
    public void setDisplayName(String displayName) {
        String oldDisplayName = this.displayName;
        this.displayName = displayName;
        support.firePropertyChange("displayName", oldDisplayName,
                                   this.displayName);
    }

    /**
     * Return the distributable flag for this web application.
     */
    public boolean getDistributable() {
        return distributable;
    }

    /**
     * Set the distributable flag for this web application.
     *
     * @param distributable The new distributable flag
     */
    public void setDistributable(boolean distributable) {
        boolean oldDistributable = this.distributable;
        this.distributable = distributable;
        support.firePropertyChange("distributable",
                                   Boolean.valueOf(oldDistributable),
                                   Boolean.valueOf(this.distributable));

        // Bugzilla 32866
        if(getManager() != null) {
            if(log.isLoggable(Level.FINE)) {
                log.fine("Propagating distributable=" + distributable
                         + " to manager");
            }
            getManager().setDistributable(distributable);
        }
    }

    /**
     * Return the document root for this Context.  This can be an absolute
     * pathname, a relative pathname, or a URL.
     */
    public String getDocBase() {
        return docBase;
    }

    /**
     * Set the document root for this Context.  This can be an absolute
     * pathname, a relative pathname, or a URL.
     *
     * @param docBase The new document root
     */
    public void setDocBase(String docBase) {
        this.docBase = docBase;
    }

    /**
     * Configures this context's alternate doc base mappings.
     *
     * @param urlPattern
     * @param docBase
     */
    public void addAlternateDocBase(String urlPattern, String docBase) {

        if (urlPattern == null || docBase == null) {
            throw new IllegalArgumentException(
                sm.getString(
                    "standardContext.alternateDocBase.missingPathOrUrlPattern"));
        }

        AlternateDocBase alternateDocBase = new AlternateDocBase();
        alternateDocBase.setUrlPattern(urlPattern);
        alternateDocBase.setDocBase(docBase);
        alternateDocBase.setBasePath(getBasePath(docBase));

        if (alternateDocBases == null) {
            alternateDocBases = new ArrayList<AlternateDocBase>();
        }
        alternateDocBases.add(alternateDocBase);
    }

    /**
     * Gets this context's configured alternate doc bases.
     *
     * @return This context's configured alternate doc bases
     */
    public ArrayList<AlternateDocBase> getAlternateDocBases() {
        return alternateDocBases;
    }

    /**
     * Return the frequency of manager checks.
     */
    public int getManagerChecksFrequency() {
        return managerChecksFrequency;
    }

    /**
     * Set the manager checks frequency.
     *
     * @param managerChecksFrequency the new manager checks frequency
     */
    public void setManagerChecksFrequency(int managerChecksFrequency) {

        if (managerChecksFrequency <= 0) {
            return;
        }

        int oldManagerChecksFrequency = this.managerChecksFrequency;
        this.managerChecksFrequency = managerChecksFrequency;
        support.firePropertyChange("managerChecksFrequency",
            Integer.valueOf(oldManagerChecksFrequency),
            Integer.valueOf(this.managerChecksFrequency));
    }

    /**
     * Return descriptive information about this Container implementation and
     * the corresponding version number, in the format
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
     */
    @Override
    public String getInfo() {
        return (info);
    }

    public void setJvmRoute(String jvmRoute) {
        this.jvmRoute = jvmRoute;
    }

    public String getJvmRoute() {
        return jvmRoute;
    }

    public String getEngineName() {
        if( engineName != null ) return engineName;
        return domain;
    }

    public void setEngineName(String engineName) {
        this.engineName = engineName;
    }

    public String getJ2EEApplication() {
        return j2EEApplication;
    }

    public void setJ2EEApplication(String j2EEApplication) {
        this.j2EEApplication = j2EEApplication;
    }

    public String getJ2EEServer() {
        return j2EEServer;
    }

    public void setJ2EEServer(String j2EEServer) {
        this.j2EEServer = j2EEServer;
    }

    /**
     * Return the login configuration descriptor for this web application.
     */
    public LoginConfig getLoginConfig() {
        return (this.loginConfig);
    }

    /**
     * Set the login configuration descriptor for this web application.
     *
     * @param config The new login configuration
     */
    public void setLoginConfig(LoginConfig config) {

        // Validate the incoming property value
        if (config == null)
            throw new IllegalArgumentException
                (sm.getString("standardContext.loginConfig.required"));
        String loginPage = config.getLoginPage();
        if ((loginPage != null) && !loginPage.startsWith("/")) {
            if (isServlet22()) {
                if (log.isLoggable(Level.FINE)) {
                    log.fine(sm.getString(
                        "standardContext.loginConfig.loginWarning",
                        loginPage));
                }
                config.setLoginPage("/" + loginPage);
            } else {
                throw new IllegalArgumentException
                    (sm.getString("standardContext.loginConfig.loginPage",
                                  loginPage));
            }
        }
        String errorPage = config.getErrorPage();
        if ((errorPage != null) && !errorPage.startsWith("/")) {
            if (isServlet22()) {
                if (log.isLoggable(Level.FINE)) {
                    log.fine(sm.getString(
                        "standardContext.loginConfig.errorWarning",
                        errorPage));
                }
                config.setErrorPage("/" + errorPage);
            } else {
                throw new IllegalArgumentException
                    (sm.getString("standardContext.loginConfig.errorPage",
                                  errorPage));
            }
        }

        // Process the property setting change
        LoginConfig oldLoginConfig = this.loginConfig;
        this.loginConfig = config;
        support.firePropertyChange("loginConfig",
                                   oldLoginConfig, this.loginConfig);
    }

    /**
     * Get the mapper associated with the context.
     */
    public Mapper getMapper() {
        return mapper;
    }

    /**
     * Sets a new pipeline
     */
    public void restrictedSetPipeline(Pipeline pl) {
        pl.setBasic(new StandardContextValve());
        pipeline = pl;
        hasCustomPipeline = true;
    }

    /**
     * Return the naming resources associated with this web application.
     */
    public NamingResources getNamingResources() {
        return namingResources;
    }

    /**
     * Set the naming resources for this web application.
     *
     * @param namingResources The new naming resources
     */
    public void setNamingResources(NamingResources namingResources) {

        // Process the property setting change
        NamingResources oldNamingResources = this.namingResources;
        this.namingResources = namingResources;
        support.firePropertyChange("namingResources",
                                   oldNamingResources, this.namingResources);
    }

    /**
     * Return the context path for this Context.
     */
    public String getPath() {
        return (getName());
    }

    /**
     * Set the context path for this Context.
     * <p>
     * <b>IMPLEMENTATION NOTE</b>:  The context path is used as the "name" of
     * a Context, because it must be unique.
     *
     * @param path The new context path
     */
    public void setPath(String path) {
        // XXX  Use host in name
        /* GlassFish Issue 2339
        setName(RequestUtil.URLDecode(path));
         */
        // START GlassFish Issue 2339
        setName(RequestUtil.urlDecode(path, "UTF-8"));
        // END GlassFish Issue 2339
    }

    /**
     * Return the public identifier of the deployment descriptor DTD that is
     * currently being parsed.
     */
    public String getPublicId() {
        return publicId;
    }

    /**
     * Set the public identifier of the deployment descriptor DTD that is
     * currently being parsed.
     *
     * @param publicId The public identifier
     */
    public void setPublicId(String publicId) {
        if (log.isLoggable(Level.FINEST))
            log.finest("Setting deployment descriptor public ID to '" +
                       publicId + "'");

        String oldPublicId = this.publicId;
        this.publicId = publicId;
        support.firePropertyChange("publicId", oldPublicId, publicId);
    }

    /**
     * Return the reloadable flag for this web application.
     */
    public boolean getReloadable() {
        return reloadable;
    }

    /**
     * Return the DefaultContext override flag for this web application.
     */
    public boolean getOverride() {
        return override;
    }

    /**
     * Gets the original document root for this Context, which can be an
     * absolute pathname, a relative pathname, or a URL.
     *
     * Is only set as deployment has change docRoot!
     */
    public String getOriginalDocBase() {
        return (this.originalDocBase);
    }
   
    /**
     * Set the original document root for this Context, which can be an
     * absolute pathname, a relative pathname, or a URL.
     *
     * @param docBase The original document root
     */
    public void setOriginalDocBase(String docBase) {
        this.originalDocBase = docBase;
    }
   
    /**
     * Return the privileged flag for this web application.
     */
    public boolean getPrivileged() {
        return (this.privileged);
    }

    /**
     * Set the privileged flag for this web application.
     *
     * @param privileged The new privileged flag
     */
    public void setPrivileged(boolean privileged) {
        boolean oldPrivileged = this.privileged;
        this.privileged = privileged;
        support.firePropertyChange("privileged",
                                   Boolean.valueOf(oldPrivileged),
                                   Boolean.valueOf(this.privileged));
    }

    /**
     * Set the reloadable flag for this web application.
     *
     * @param reloadable The new reloadable flag
     */
    public void setReloadable(boolean reloadable) {
        boolean oldReloadable = this.reloadable;
        this.reloadable = reloadable;
        support.firePropertyChange("reloadable",
                                   Boolean.valueOf(oldReloadable),
                                   Boolean.valueOf(this.reloadable));
    }

    /**
     * Set the DefaultContext override flag for this web application.
     *
     * @param override The new override flag
     */
    public void setOverride(boolean override) {
        boolean oldOverride = this.override;
        this.override = override;
        support.firePropertyChange("override",
                                   Boolean.valueOf(oldOverride),
                                   Boolean.valueOf(this.override));
    }

    // START SJSAS 8.1 5049111
    /**
     * Scan the parent when searching for TLD listeners.
     */
    public boolean isJsfApplication(){
        return isJsfApplication;
    }
    // END SJSAS 8.1 5049111


    // START SJSAS 6253524
    /**
     * Indicates whether this web module contains any ad-hoc paths.
     *
     * An ad-hoc path is a servlet path that is mapped to a servlet
     * not declared in the web module's deployment descriptor.
     *
     * A web module all of whose mappings are for ad-hoc paths is called an
     * ad-hoc web module.
     *
     * @return true if this web module contains any ad-hoc paths, false
     * otherwise
     */
    public boolean hasAdHocPaths() {
        return false;
    }

    /**
     * Returns the name of the ad-hoc servlet responsible for servicing the
     * given path.
     *
     * @param path The path to service
     *
     * @return The name of the ad-hoc servlet responsible for servicing the
     * given path, or null if the given path is not an ad-hoc path
     */
    public String getAdHocServletName(String path) {
        return null;
    }
    // END SJSAS 6253524

    /**
     * Return the "replace welcome files" property.
     */
    public boolean isReplaceWelcomeFiles() {
        return replaceWelcomeFiles;
    }

    /**
     * Set the "replace welcome files" property.
     *
     * @param replaceWelcomeFiles The new property value
     */
    public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) {

        boolean oldReplaceWelcomeFiles = this.replaceWelcomeFiles;
        this.replaceWelcomeFiles = replaceWelcomeFiles;
        support.firePropertyChange("replaceWelcomeFiles",
                                   Boolean.valueOf(oldReplaceWelcomeFiles),
                                   Boolean.valueOf(this.replaceWelcomeFiles));
    }

    /**
     * Returns the value of the securePagesWithPragma property.
     */
    public boolean isSecurePagesWithPragma() {
        return securePagesWithPragma;
    }

    /**
     * Sets the securePagesWithPragma property of this Context.
     *
     * Setting this property to true will result in Pragma and Cache-Control
     * headers with a value of "No-cache" if proxy caching has been disabled.
     *
     * Setting this property to false will not add any Pragma header,
     * but will set the Cache-Control header to "private".
     *
     * @param securePagesWithPragma true if Pragma and Cache-Control headers
     * are to be set to "No-cache" if proxy caching has been disabled, false
     * otherwise
     */
    public void setSecurePagesWithPragma(boolean securePagesWithPragma) {

        boolean oldSecurePagesWithPragma = this.securePagesWithPragma;
        this.securePagesWithPragma = securePagesWithPragma;
        support.firePropertyChange("securePagesWithPragma",
                                   Boolean.valueOf(oldSecurePagesWithPragma),
                                   Boolean.valueOf(this.securePagesWithPragma));
    }

    public void setUseMyFaces(boolean useMyFaces) {
        this.useMyFaces = useMyFaces;
    }

    public boolean isUseMyFaces() {
        return useMyFaces;
    }

    /**
     * Return the servlet context for which this Context is a facade.
     */
    public ServletContext getServletContext() {
        if (context == null) {
            context = new ApplicationContext(this);
            if (altDDName != null
                    && context.getAttribute(Globals.ALT_DD_ATTR) == null){
                context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
                context.setAttributeReadOnly(Globals.ALT_DD_ATTR);
            }
        }

        return context.getFacade();
    }

    /**
     * Return the default session timeout (in minutes) for this
     * web application.
     */
    public int getSessionTimeout() {
        return sessionTimeout;
    }

    /**
     * Is the session timeout (in minutes) for this
     * web application over-ridden from the default
     * HERCULES:add
     */
    public boolean isSessionTimeoutOveridden() {
        return sessionTimeoutOveridden;
    }

    /**
     * Set the default session timeout (in minutes) for this
     * web application.
     *
     * @param timeout The new default session timeout
     */
    public void setSessionTimeout(int timeout) {

        int oldSessionTimeout = this.sessionTimeout;

        /*
         * SRV.13.4 ("Deployment Descriptor"):
         * If the timeout is 0 or less, the container ensures the default
         * behaviour of sessions is never to time out.
         */
        this.sessionTimeout = (timeout == 0) ? -1 : timeout;
        support.firePropertyChange("sessionTimeout",
                                   Integer.valueOf(oldSessionTimeout),
                                   Integer.valueOf(this.sessionTimeout));
        //HERCULES:add
        sessionTimeoutOveridden = true;
        //end HERCULES:add
    }

    /**
     * Unpack WAR flag accessor.
     */
    public boolean getUnpackWAR() {
        return unpackWAR;
    }

    /**
     * Unpack WAR flag mutator.
     */
    public void setUnpackWAR(boolean unpackWAR) {
        this.unpackWAR = unpackWAR;
    }

    /**
     * Set the resources DirContext object with which this Container is
     * associated.
     *
     * @param resources The newly associated DirContext
     */
    @Override
    public synchronized void setResources(DirContext resources) {

        if (started) {
            throw new IllegalStateException
                (sm.getString("standardContext.resources.started"));
        }

        DirContext oldResources = this.webappResources;
        if (oldResources == resources)
            return;

        if (resources instanceof BaseDirContext) {
            BaseDirContext baseDirContext = (BaseDirContext)resources;
            baseDirContext.setCached(isCachingAllowed());
            baseDirContext.setCacheTTL(getCacheTTL());
            baseDirContext.setCacheMaxSize(getCacheMaxSize());
        }
        if (resources instanceof FileDirContext) {
            filesystemBased = true;
            FileDirContext fileDirContext = (FileDirContext)resources;
            fileDirContext.setCaseSensitive(isCaseSensitive());
            fileDirContext.setAllowLinking(isAllowLinking());
        }
        this.webappResources = resources;

        // The proxied resources will be refreshed on start
        this.resources = null;

        support.firePropertyChange("resources", oldResources,
                                   this.webappResources);

    }

    private synchronized void setAlternateResources(
                            AlternateDocBase alternateDocBase,
                            DirContext resources) {

        if (started) {
            throw new IllegalStateException
                (sm.getString("standardContext.resources.started"));
        }

        DirContext oldResources = alternateDocBase.getWebappResources();
        if (oldResources == resources)
            return;

        if (resources instanceof BaseDirContext) {
            ((BaseDirContext) resources).setCached(isCachingAllowed());
            ((BaseDirContext) resources).setCacheTTL(getCacheTTL());
            ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize());
        }
        if (resources instanceof FileDirContext) {
            filesystemBased = true;
            ((FileDirContext) resources).setCaseSensitive(isCaseSensitive());
            ((FileDirContext) resources).setAllowLinking(isAllowLinking());
        }
        alternateDocBase.setWebappResources(resources);
        // The proxied resources will be refreshed on start
        alternateDocBase.setResources(null);
    }

    // START S1AS8PE 4817642
    /**
     * Return the "reuse session IDs when creating sessions" flag
     */
    public boolean getReuseSessionID() {
        return reuseSessionID;
    }

    /**
     * Set the "reuse session IDs when creating sessions" flag
     *
     * @param reuse The new value for the flag
     */
    public void setReuseSessionID(boolean reuse) {
        reuseSessionID = reuse;
    }
    // END S1AS8PE 4817642



    // START RIMOD 4642650
    /**
     * Return whether this context allows sendRedirect() to redirect
     * to a relative URL.
     *
     * The default value for this property is 'false'.
     */
    public boolean getAllowRelativeRedirect() {

        return allowRelativeRedirect;

    }


    /**
     * Set whether this context allows sendRedirect() to redirect
     * to a relative URL.
     *
     * @param allowRelativeURLs The new value for this property.
     *                          The default value for this property is
     *                          'false'.
     */
    public void setAllowRelativeRedirect(boolean allowRelativeURLs) {

        allowRelativeRedirect = allowRelativeURLs;

    }


    // END RIMOD 4642650

    // START IASRI 4823322
    /**
     * Get Auditors associated with this context, if any.
     *
     * @return array of Auditor objects, or null
     *
     */
    public Auditor[] getAuditors() {
        return auditors;
    }


    /**
     * Set the Auditors associated with this context.
     *
     * @param auditor array of Auditor objects
     *
     */
    public void setAuditors(Auditor[] auditor) {
        this.auditors=auditor;
    }
    // END IASRI 4823322


    // START S1AS8PE 4965017
    public void setReload(boolean isReload) {
        this.isReload = isReload;
    }

    public boolean isReload() {
        return isReload;
    }
    // END S1AS8PE 4965017

    public void setEmbedded(boolean isEmbedded) {
        this.isEmbedded = isEmbedded;
    }

    public boolean isEmbedded() {
        return isEmbedded;
    }

    /**
     * Should we generate directory listings?
     */
    protected boolean directoryListing = false;

    /**
     * Enables or disables directory listings on this <tt>Context</tt>.
     */
    public void setDirectoryListing(boolean directoryListing) {
        this.directoryListing = directoryListing;
        Wrapper wrapper = (Wrapper) findChild(
                org.apache.catalina.core.Constants.DEFAULT_SERVLET_NAME);
        if (wrapper !=null) {
            Servlet servlet = ((StandardWrapper)wrapper).getServlet();
            if (servlet instanceof DefaultServlet) {
                ((DefaultServlet)servlet).setListings(directoryListing);
            }
        }
    }

    /**
     * Checks whether directory listings are enabled or disabled on this
     * <tt>Context</tt>.
     */
    public boolean isDirectoryListing() {
        return directoryListing;
    }

    // ------------------------------------------------------ Public Properties


    /**
     * Return the Locale to character set mapper class for this Context.
     */
    public String getCharsetMapperClass() {

        return (this.charsetMapperClass);

    }


    /**
     * Set the Locale to character set mapper class for this Context.
     *
     * @param mapper The new mapper class
     */
    public void setCharsetMapperClass(String mapper) {

        String oldCharsetMapperClass = this.charsetMapperClass;
        this.charsetMapperClass = mapper;
        support.firePropertyChange("charsetMapperClass",
                                   oldCharsetMapperClass,
                                   this.charsetMapperClass);

    }


    /**
     * Get the absolute path to the work dir.
     *
     * @return the absolute path to the work dir
     */
    public String getWorkPath() {
        if (getWorkDir() == null) {
            return null;
        }
        File workDir = new File(getWorkDir());
        if (!workDir.isAbsolute()) {
            File catalinaHome = engineBase();
            String catalinaHomePath = null;
            try {
                catalinaHomePath = catalinaHome.getCanonicalPath();
                workDir = new File(catalinaHomePath,
                        getWorkDir());
            } catch (IOException e) {
            }
        }
              return workDir.getAbsolutePath();
    }

    /**
     * Return the work directory for this Context.
     */
    public String getWorkDir() {

        return (this.workDir);

    }


    /**
     * Set the work directory for this Context.
     *
     * @param workDir The new work directory
     */
    public void setWorkDir(String workDir) {
        this.workDir = workDir;
        if (started) {
            postWorkDirectory();
        }
    }


    // -------------------------------------------------------- Context Methods


    /**
     * Adds the Listener with the given class name that is declared in the
     * deployment descriptor to the set of Listeners configured for this
     * application.
     *
     * @param listener the fully qualified class name of the Listener
     */
    public void addApplicationListener(String listener) {
        addListener(listener, false);
    }

    /**
     * Add a new application parameter for this application.
     *
     * @param parameter The new application parameter
     */
    public void addApplicationParameter(ApplicationParameter parameter) {
        String newName = parameter.getName();
        Iterator<ApplicationParameter> i =
            applicationParameters.iterator();
        while (i.hasNext()) {
            ApplicationParameter applicationParameter = i.next();
            if (newName.equals(applicationParameter.getName())) {
                if (applicationParameter.getOverride()) {
                    applicationParameter.setValue(parameter.getValue());
                }
                return;
            }
        }

        applicationParameters.add(parameter);

        if (notifyContainerListeners) {
            fireContainerEvent("addApplicationParameter", parameter);
        }
    }

    /**
     * Adds the given child Container to this context.
     *
     * @param child the child Container to add
     *
     * @exception IllegalArgumentException if the given child Container is
     * not an instance of Wrapper
     */
    @Override
    public void addChild(Container child) {
        addChild(child, false, true);
    }

    /**
     * Adds the given child (Servlet) to this context.
     *
     * @param child the child (Servlet) to add
     * @param isProgrammatic true if the given child (Servlet) is being
     * added via one of the programmatic interfaces, and false if it is
     * declared in the deployment descriptor
     * @param createRegistration true if a ServletRegistration needs to be
     * created for the given child, and false if a (preliminary)
     * ServletRegistration had already been created (which would be the
     * case if the Servlet had been declared in the deployment descriptor
     * without any servlet-class, and the servlet-class was later provided
     * via ServletContext#addServlet)
     *
     * @exception IllegalArgumentException if the given child Container is
     * not an instance of Wrapper
     */
    protected void addChild(Container child, boolean isProgrammatic,
            boolean createRegistration) {

        if (!(child instanceof Wrapper)) {
            throw new IllegalArgumentException
                (sm.getString("standardContext.notWrapper"));
        }

        Wrapper wrapper = (Wrapper) child;
        String wrapperName = child.getName();

        if (createRegistration) {
            ServletRegistrationImpl regis = null;
            if (isProgrammatic ||
                    (null == wrapper.getServletClassName() &&
                        null == wrapper.getJspFile())) {
                regis = createDynamicServletRegistrationImpl(
                    (StandardWrapper) wrapper);
            } else {
                regis = createServletRegistrationImpl(
                    (StandardWrapper) wrapper);
            }
            servletRegisMap.put(wrapperName, regis);
            if (null == wrapper.getServletClassName() &&
                    null == wrapper.getJspFile()) {
                /*
                 * Preliminary registration for Servlet that was declared
                 * without any servlet-class. Once the registration is
                 * completed via ServletContext#addServlet, addChild will
                 * be called again, and 'wrapper' will have been configured
                 * with a proper class name at that time
                 */
                return;
            }
        }

        if ("javax.faces.webapp.FacesServlet".equals(
                wrapper.getServletClassName())) {
            isJsfApplication = true;
        }

        // Global JspServlet
        Wrapper oldJspServlet = null;

        // Allow webapp to override JspServlet inherited from global web.xml.
        boolean isJspServlet = "jsp".equals(wrapperName);
        if (isJspServlet) {
            oldJspServlet = (Wrapper) findChild("jsp");
            if (oldJspServlet != null) {
                removeChild(oldJspServlet);
            }
        }

        String jspFile = wrapper.getJspFile();
        if ((jspFile != null) && !jspFile.startsWith("/")) {
            if (isServlet22()) {
                if (log.isLoggable(Level.FINE)) {
                    log.fine(sm.getString("standardContext.wrapper.warning",
                                          jspFile));
                }
                wrapper.setJspFile("/" + jspFile);
            } else {
                throw new IllegalArgumentException
                    (sm.getString("standardContext.wrapper.error", jspFile));
            }
        }

        super.addChild(child);

        // START SJSAS 6342808
        /* SJSWS 6362207
        if (started) {
        */
        // START SJSWS 6362207
        if (getAvailable()) {
        // END SJSWS 6362207
            /*
             * If this StandardContext has already been started, we need to
             * register the newly added child with JMX. Any children that were
             * added before this StandardContext was started have already been
             * registered with JMX (as part of StandardContext.start()).
             */
            if (wrapper instanceof StandardWrapper) {
                ((StandardWrapper) wrapper).registerJMX( this );
            }
        }
        // END SJSAS 6342808

        if (isJspServlet && oldJspServlet != null) {
            /*
             * The webapp-specific JspServlet inherits all the mappings
             * specified in the global web.xml, and may add additional ones.
             */
            String[] jspMappings = oldJspServlet.findMappings();
            for (int i=0; jspMappings!=null && i<jspMappings.length; i++) {
                addServletMapping(jspMappings[i], wrapperName);
            }
        }
    }

    protected ServletRegistrationImpl createServletRegistrationImpl(
            StandardWrapper wrapper) {
        return new ServletRegistrationImpl(wrapper, this);
    }

    protected ServletRegistrationImpl createDynamicServletRegistrationImpl(
            StandardWrapper wrapper) {
        return new DynamicServletRegistrationImpl(wrapper, this);
    }

    /**
     * Add a security constraint to the set for this web application.
     */
    public void addConstraint(SecurityConstraint constraint) {

        // Validate the proposed constraint
        SecurityCollection collections[] = constraint.findCollections();
        for(SecurityCollection collection : collections) {
            String patterns[] = collection.findPatterns();
            for(int j = 0; j < patterns.length; j++) {
                patterns[j] = adjustURLPattern(patterns[j]);
                if(!validateURLPattern(patterns[j])) {
                    throw new IllegalArgumentException
                        (sm.getString
                            ("standardContext.securityConstraint.pattern",
                                patterns[j]));
                }
            }
        }

        // Add this constraint to the set for our web application
        constraints.add(constraint);
    }

    /**
     * Add an EJB resource reference for this web application.
     *
     * @param ejb New EJB resource reference
     */
    public void addEjb(ContextEjb ejb) {
        namingResources.addEjb(ejb);
        if (notifyContainerListeners) {
           fireContainerEvent("addEjb", ejb.getName());
        }
    }

    /**
     * Add an environment entry for this web application.
     *
     * @param environment New environment entry
     */
    public void addEnvironment(ContextEnvironment environment) {

        ContextEnvironment env = findEnvironment(environment.getName());
        if ((env != null) && !env.getOverride())
            return;
        namingResources.addEnvironment(environment);

        if (notifyContainerListeners) {
            fireContainerEvent("addEnvironment", environment.getName());
        }
    }


    /**
     * Add resource parameters for this web application.
     *
     * @param resourceParameters New resource parameters
     */
    public void addResourceParams(ResourceParams resourceParameters) {
        namingResources.addResourceParams(resourceParameters);
        if (notifyContainerListeners) {
            fireContainerEvent("addResourceParams",
                               resourceParameters.getName());
        }
    }

    /**
     * Add an error page for the specified error or Java exception.
     *
     * @param errorPage The error page definition to be added
     */
    public void addErrorPage(ErrorPage errorPage) {
        // Validate the input parameters
        if (errorPage == null)
            throw new IllegalArgumentException
                (sm.getString("standardContext.errorPage.required"));
        String location = errorPage.getLocation();
        if ((location != null) && !location.startsWith("/")) {
            if (isServlet22()) {
                if (log.isLoggable(Level.FINE)) {
                    log.fine(sm.getString("standardContext.errorPage.warning",
                                          location));
                }
                errorPage.setLocation("/" + location);
            } else {
                throw new IllegalArgumentException
                    (sm.getString("standardContext.errorPage.error",
                                  location));
            }
        }

        // Add the specified error page to our internal collections
        String exceptionType = errorPage.getExceptionType();
        if (exceptionType != null) {
            synchronized (exceptionPages) {
                exceptionPages.put(exceptionType, errorPage);
            }
        } else if (errorPage.getErrorCode() > 0) {
            synchronized (statusPages) {
                int errorCode = errorPage.getErrorCode();
                if ((errorCode >= 400) && (errorCode < 600)) {
                    statusPages.put(errorCode, errorPage);
                } else {
                    log.severe(sm.getString(
                        "standardContext.invalidErrorPageCode", errorCode));
                }
            }
        } else {
            defaultErrorPage = errorPage;
        }

        if (notifyContainerListeners) {
            fireContainerEvent("addErrorPage", errorPage);
        }
    }

    /**
     * Add a filter definition to this Context.
     *
     * @param filterDef The filter definition to be added
     */
    public void addFilterDef(FilterDef filterDef) {
        addFilterDef(filterDef, false, true);
    }

    public void addFilterDef(FilterDef filterDef, boolean isProgrammatic,
            boolean createRegistration) {
        if (createRegistration) {
            FilterRegistrationImpl regis = null;
            if (isProgrammatic || null == filterDef.getFilterClassName()) {
                regis = new DynamicFilterRegistrationImpl(filterDef, this);
            } else {
                regis = new FilterRegistrationImpl(filterDef, this);
            }
            filterRegisMap.put(filterDef.getFilterName(), regis);
            if (null == filterDef.getFilterClassName()) {
                /*
                 * Preliminary registration for Filter that was declared
                 * without any filter-class. Once the registration is
                 * completed via ServletContext#addFilter, addFilterDef will
                 * be called again, and 'filterDef' will have been configured
                 * with a proper class name at that time
                 */
                return;
            }
        }

        synchronized (filterDefs) {
            filterDefs.put(filterDef.getFilterName(), filterDef);
        }

        if (notifyContainerListeners) {
            fireContainerEvent("addFilterDef", filterDef);
        }
    }

    /**
     * Add multiple filter mappings to this Context.
     *
     * @param filterMaps The filter mappings to be added
     *
     * @exception IllegalArgumentException if the specified filter name
     *  does not match an existing filter definition, or the filter mapping
     *  is malformed
     */
    public void addFilterMaps(FilterMaps filterMaps) {
        String[] servletNames = filterMaps.getServletNames();
        String[] urlPatterns = filterMaps.getURLPatterns();
        for (String servletName : servletNames) {
            FilterMap fmap = new FilterMap();
            fmap.setFilterName(filterMaps.getFilterName());
            fmap.setServletName(servletName);
            fmap.setDispatcherTypes(filterMaps.getDispatcherTypes());
            addFilterMap(fmap);
        }
        for (String urlPattern : urlPatterns) {
            FilterMap fmap = new FilterMap();
            fmap.setFilterName(filterMaps.getFilterName());
            fmap.setURLPattern(urlPattern);
            fmap.setDispatcherTypes(filterMaps.getDispatcherTypes());
            addFilterMap(fmap);
        }
    }

    /**
     * Add a filter mapping to this Context.
     *
     * @param filterMap The filter mapping to be added
     *
     * @exception IllegalArgumentException if the specified filter name
     *  does not match an existing filter definition, or the filter mapping
     *  is malformed
     */
    public void addFilterMap(FilterMap filterMap) {
        addFilterMap(filterMap, true);
    }


    /**
     * Add a filter mapping to this Context.
     *
     * @param filterMap The filter mapping to be added
     *
     * @param isMatchAfter true if the given filter mapping should be matched
     * against requests after any declared filter mappings of this servlet
     * context, and false if it is supposed to be matched before any declared
     * filter mappings of this servlet context
     *
     * @exception IllegalArgumentException if the specified filter name
     *  does not match an existing filter definition, or the filter mapping
     *  is malformed
     *
     */
    public void addFilterMap(FilterMap filterMap, boolean isMatchAfter) {

        // Validate the proposed filter mapping
        String filterName = filterMap.getFilterName();
        String servletName = filterMap.getServletName();
        String urlPattern = filterMap.getURLPattern();
        if (null == filterRegisMap.get(filterName)) {
            throw new IllegalArgumentException
                (sm.getString("standardContext.filterMap.name", filterName));
        }
        if ((servletName == null) && (urlPattern == null)) {
            throw new IllegalArgumentException
                (sm.getString("standardContext.filterMap.either"));
        }
        if ((servletName != null) && (urlPattern != null)) {
            throw new IllegalArgumentException
                (sm.getString("standardContext.filterMap.either"));
        }
        // Because filter-pattern is new in 2.3, no need to adjust
        // for 2.2 backwards compatibility
        if ((urlPattern != null) && !validateURLPattern(urlPattern)) {
            throw new IllegalArgumentException
                (sm.getString("standardContext.filterMap.pattern",
                              urlPattern));
        }

        // Add this filter mapping to our registered set
        if (isMatchAfter) {
            filterMaps.add(filterMap);
        } else {
            filterMaps.add(0, filterMap);
        }

        if (notifyContainerListeners) {
            fireContainerEvent("addFilterMap", filterMap);
        }
    }

    /**
     * Gets the current servlet name mappings of the Filter with
     * the given name.
     */
    public Collection<String> getServletNameFilterMappings(String filterName) {
        HashSet<String> mappings = new HashSet<String>();
        synchronized (filterMaps) {
            for (FilterMap fm : filterMaps) {
                if (filterName.equals(fm.getFilterName()) &&
                        fm.getServletName() != null) {
                    mappings.add(fm.getServletName());
                }
            }
        }
        return mappings;
    }

    /**
     * Gets the current URL pattern mappings of the Filter with the given
     * name.
     */
    public Collection<String> getUrlPatternFilterMappings(String filterName) {
        HashSet<String> mappings = new HashSet<String>();
        synchronized (filterMaps) {
            for (FilterMap fm : filterMaps) {
                if (filterName.equals(fm.getFilterName()) &&
                        fm.getURLPattern() != null) {
                    mappings.add(fm.getURLPattern());
                }
            }
        }
        return mappings;
    }

    /**
     * Adds the filter with the given name and class name to this servlet
     * context.
     */
    public FilterRegistration.Dynamic addFilter(
            String filterName, String className) {

        if (isContextInitializedCalled) {
            throw new IllegalStateException(
                sm.getString("applicationContext.alreadyInitialized",
                             "addFilter", getName()));
        }

        synchronized (filterDefs) {
            // Make sure filter name is unique for this context
            if (findFilterDef(filterName) != null) {
                return null;
            }

            DynamicFilterRegistrationImpl regis =
                (DynamicFilterRegistrationImpl) filterRegisMap.get(
                    filterName);
            FilterDef filterDef = null;
            if (null == regis) {
                filterDef = new FilterDef();
            } else {
                // Complete preliminary filter registration
                filterDef = regis.getFilterDefinition();
            }

            filterDef.setFilterName(filterName);
            filterDef.setFilterClassName(className);

            addFilterDef(filterDef, true, (regis == null));
            if (null == regis) {
                regis = (DynamicFilterRegistrationImpl)
                    filterRegisMap.get(filterName);
            }

            return regis;
        }
    }

    /*
     * Registers the given filter instance with this ServletContext
     * under the given <tt>filterName</tt>.
     */
    public FilterRegistration.Dynamic addFilter(
            String filterName, Filter filter) {

        if (isContextInitializedCalled) {
            throw new IllegalStateException(
                sm.getString("applicationContext.alreadyInitialized",
                             "addFilter", getName()));
        }

        if (filterName == null || filter == null) {
            throw new NullPointerException("Null filter instance or name");
        }

        /*
         * Make sure the given Filter instance is unique across all deployed
         * contexts
         */
        Container host = getParent();
        if (host != null) {
            for (Container child : host.findChildren()) {
                if (child == this) {
                    // Our own context will be checked further down
                    continue;
                }
                if (((StandardContext) child).hasFilter(filter)) {
                    return null;
                }
            }
        }

        /*
         * Make sure the given Filter name and instance are unique within
         * this context
         */
        synchronized (filterDefs) {
            for (Map.Entry<String, FilterDef> e : filterDefs.entrySet()) {
                if (filterName.equals(e.getKey()) ||
                        filter == e.getValue().getFilter()) {
                    return null;
                }
            }

            DynamicFilterRegistrationImpl regis =
                (DynamicFilterRegistrationImpl) filterRegisMap.get(
                    filterName);
            FilterDef filterDef = null;
            if (null == regis) {
                filterDef = new FilterDef();
            } else {
                // Complete preliminary filter registration
                filterDef = regis.getFilterDefinition();
            }

            filterDef.setFilterName(filterName);
            filterDef.setFilter(filter);

            addFilterDef(filterDef, true, (regis == null));
            if (null == regis) {
                regis = (DynamicFilterRegistrationImpl)
                    filterRegisMap.get(filterName);
            }

            return regis;
        }
    }

    /**
     * Checks whether this context contains the given Filter instance
     */
    public boolean hasFilter(Filter filter) {
        for (Map.Entry<String, FilterDef> e : filterDefs.entrySet()) {
            if (filter == e.getValue().getFilter()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Adds the filter with the given name and class type to this servlet
     * context.
     */
    public FilterRegistration.Dynamic addFilter(String filterName,
            Class <? extends Filter> filterClass) {

        if (isContextInitializedCalled) {
            throw new IllegalStateException(
                sm.getString("applicationContext.alreadyInitialized",
                             "addFilter", getName()));
        }

        synchronized (filterDefs) {
            if (findFilterDef(filterName) != null) {
                return null;
            }

            DynamicFilterRegistrationImpl regis =
                (DynamicFilterRegistrationImpl) filterRegisMap.get(
                    filterName);
            FilterDef filterDef = null;
            if (null == regis) {
                filterDef = new FilterDef();
            } else {
                // Complete preliminary filter registration
                filterDef = regis.getFilterDefinition();
            }

            filterDef.setFilterName(filterName);
            filterDef.setFilterClass(filterClass);

            addFilterDef(filterDef, true, (regis == null));
            if (null == regis) {
                regis = (DynamicFilterRegistrationImpl)
                    filterRegisMap.get(filterName);
            }

            return regis;
        }
    }

    /**
     * Instantiates the given Filter class and performs any required
     * resource injection into the new Filter instance before returning
     * it.
     */
    public <T extends Filter> T createFilter(Class<T> clazz)
            throws ServletException {
        try {
            return createFilterInstance(clazz);
        } catch (Throwable t) {
            throw new ServletException("Unable to create Filter from " +
                                       "class " + clazz.getName(), t);
        }
    }

    /**
     * Gets the FilterRegistration corresponding to the filter with the
     * given <tt>filterName</tt>.
     */
    public FilterRegistration getFilterRegistration(String filterName) {
        return filterRegisMap.get(filterName);
    }

    /**
     * Gets a Map of the FilterRegistration objects corresponding to all
     * currently registered filters.
     */
    public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
        return Collections.unmodifiableMap(filterRegisMap);
    }

    /**
     * Gets the session tracking cookie configuration of this
     * <tt>ServletContext</tt>.
     */
    public synchronized SessionCookieConfig getSessionCookieConfig() {
        if (sessionCookieConfig == null) {
            sessionCookieConfig = new SessionCookieConfigImpl(this);
        }
        return sessionCookieConfig;
    }

    /**
     * Sets the name that will be assigned to any session tracking
     * cookies created on behalf of this context
     */
    void setSessionCookieName(String sessionCookieName) {
        this.sessionCookieName = sessionCookieName;
        sessionCookieNameInitialized = true;
    }

    /**
     * Gets the name that will be assigned to any session tracking
     * cookies created on behalf of this context
     */
    public String getSessionCookieName() {
        return sessionCookieName;
    }

    /**
     * @return the name that will be assigned to any session tracking
     * parameter created on behalf of this context
     */
    public String getSessionParameterName() {
        if (sessionCookieNameInitialized) {
            if (sessionCookieName != null && (!sessionCookieName.isEmpty())) {
               return sessionCookieName;
            }
        }
       
        return Globals.SESSION_PARAMETER_NAME;
    }

    /**
     * Sets the session tracking modes that are to become effective for this
     * <tt>ServletContext</tt>.
     */
    public void setSessionTrackingModes(
            Set<SessionTrackingMode> sessionTrackingModes) {

        if (sessionTrackingModes.contains(SessionTrackingMode.SSL)) {
            throw new IllegalArgumentException(
                sm.getString(
                    "applicationContext.sessionTrackingModes.iae.unsupported",
                    SessionTrackingMode.SSL, getName()));
        }

        if (isContextInitializedCalled) {
            throw new IllegalStateException(
                sm.getString("applicationContext.alreadyInitialized",
                             "setSessionTrackingModes", getName()));
        }

        this.sessionTrackingModes =
            Collections.unmodifiableSet(sessionTrackingModes);

        if (sessionTrackingModes.contains(SessionTrackingMode.COOKIE)) {
            setCookies(true);
        } else {
            setCookies(false);
        }

        if (sessionTrackingModes.contains(SessionTrackingMode.URL)) {
            setEnableURLRewriting(true);
        } else {
            setEnableURLRewriting(false);
        }
    }

    /**
     * Gets the session tracking modes that are supported by default for this
     * <tt>ServletContext</tt>.
     *
     * @return set of the session tracking modes supported by default for
     * this <tt>ServletContext</tt>
     */
    public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
        return DEFAULT_SESSION_TRACKING_MODES;
    }

    /**
     * Gets the session tracking modes that are in effect for this
     * <tt>ServletContext</tt>.
     *
     * @return set of the session tracking modes in effect for this
     * <tt>ServletContext</tt>
     */
    public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
        return (sessionTrackingModes != null ? sessionTrackingModes :
            DEFAULT_SESSION_TRACKING_MODES);
    }

    /**
     * Adds the listener with the given class name to this ServletContext.
     *
     * @param className the fully qualified class name of the listener
     */
    public void addListener(String className) {
        addListener(className, true);
    }


    /**
     * Adds the listener with the given class name to this ServletContext.
     *
     * @param className the fully qualified class name of the listener
     * @param isProgrammatic true if the listener is being added
     * programmatically, and false if it has been declared in the deployment
     * descriptor
     */
    private void addListener(String className, boolean isProgrammatic) {
        try {
            addListener(loadListener(getClassLoader(), className),
                        isProgrammatic);
        } catch (Throwable t) {
            throw new IllegalArgumentException(t);
        }
    }

    /**
     * Adds the given listener instance to this ServletContext.
     *
     * @param t the listener to be added
     */
    public <T extends EventListener> void addListener(T t) {
        addListener(t, true);
    }

    /**
     * Adds the given listener instance to this ServletContext.
     *
     * @param t the listener to be added
     * @param isProgrammatic true if the listener is being added
     * programmatically, and false if it has been declared in the deployment
     * descriptor
     */
    private <T extends EventListener> void addListener(T t,
            boolean isProgrammatic) {
        if (isContextInitializedCalled) {
            throw new IllegalStateException(
                sm.getString("applicationContext.alreadyInitialized",
                             "addListener", getName()));
        }

        if ((t instanceof ServletContextListener) && isProgrammatic &&
                !isProgrammaticServletContextListenerRegistrationAllowed) {
            throw new IllegalArgumentException("Not allowed to register " +
                "ServletContextListener programmatically");
        }

        boolean added = false;

        if (t instanceof ServletContextAttributeListener ||
                t instanceof ServletRequestAttributeListener ||
                t instanceof ServletRequestListener ||
                t instanceof HttpSessionAttributeListener) {
            eventListeners.add(t);
            added = true;
        }

        if (t instanceof HttpSessionListener) {
            sessionListeners.add((HttpSessionListener) t);
            if (!added) {
                added = true;
            }
        }

        if (t instanceof ServletContextListener) {
            ServletContextListener proxy = (ServletContextListener) t;
            if (isProgrammatic) {
                proxy = new RestrictedServletContextListener(
                    (ServletContextListener) t);
            }
            // Always add the JSF listener as the first element,
            // see GlassFish Issue 2563 for details
            boolean isFirst =
                "com.sun.faces.config.ConfigureListener".equals(
                    t.getClass().getName());
            if (isFirst) {
                contextListeners.add(0, proxy);
            } else {
                contextListeners.add(proxy);
            }
            if (!added) {
                added = true;
            }
        }

        if (!added) {
            throw new IllegalArgumentException("Invalid listener type " +
                t.getClass().getName());
        }
    }

    /**
     * Adds a listener of the given class type to this ServletContext.
     */
    public void addListener(Class <? extends EventListener> listenerClass) {
        try {
            addListener(createListenerInstance(listenerClass));
        } catch (Throwable t) {
            throw new IllegalArgumentException(t);
        }
    }

    /**
     * Instantiates the given EventListener class and performs any
     * required resource injection into the new EventListener instance
     * before returning it.
     */
    public <T extends EventListener> T createListener(Class<T> clazz)
            throws ServletException {
        if (!ServletContextListener.class.isAssignableFrom(clazz) &&
                !ServletContextAttributeListener.class.isAssignableFrom(clazz) &&
                !ServletRequestListener.class.isAssignableFrom(clazz) &&
                !ServletRequestAttributeListener.class.isAssignableFrom(clazz) &&
                !HttpSessionListener.class.isAssignableFrom(clazz) &&
                !HttpSessionAttributeListener.class.isAssignableFrom(clazz)) {
            throw new IllegalArgumentException(sm.getString(
                    "standardContext.invalidListenerType", clazz.getName()));
        }

        try {
            return createListenerInstance(clazz);
        } catch (Throwable t) {
            throw new ServletException(t);
        }
    }

    public void setJspConfigDescriptor(JspConfigDescriptor jspConfigDesc) {
        this.jspConfigDesc = jspConfigDesc;
    }

    /**
     * Gets the <code>&lt;jsp-config&gt;</code> related configuration
     * that was aggregated over the <code>web.xml</code> and
     * <code>web-fragment.xml</code> resources of the web application
     * represented by this ServletContext.
     */
    public JspConfigDescriptor getJspConfigDescriptor() {
        return jspConfigDesc;
    }

    /**
     * Gets the class loader of the web application represented by this
     * ServletContext.
     */
    public ClassLoader getClassLoader() {
        ClassLoader webappLoader = (getLoader() != null) ?
            getLoader().getClassLoader() : null;
        if (webappLoader == null) {
            return null;
        }
        if (mySecurityManager != null) {
            mySecurityManager.checkGetClassLoaderPermission(webappLoader);
        }
        return webappLoader;
    }

    public void declareRoles(String... roleNames) {
        if (isContextInitializedCalled) {
            throw new IllegalStateException(
                sm.getString("applicationContext.alreadyInitialized",
                             "declareRoles", getName()));
        }

        for (String roleName : roleNames) {
            addSecurityRole(roleName);
        }
    }

    public void setEffectiveMajorVersion(int effectiveMajorVersion) {
        this.effectiveMajorVersion = effectiveMajorVersion;
    }

    public int getEffectiveMajorVersion() {
        return effectiveMajorVersion;
    }

    public void setEffectiveMinorVersion(int effectiveMinorVersion) {
        this.effectiveMinorVersion = effectiveMinorVersion;
    }
   
    public int getEffectiveMinorVersion() {
        return effectiveMinorVersion;
    }

    /**
     * Add the classname of an InstanceListener to be added to each
     * Wrapper appended to this Context.
     *
     * @param listener Java class name of an InstanceListener class
     */
    public void addInstanceListener(String listener) {
        instanceListeners.add(listener);
        if (notifyContainerListeners) {
            fireContainerEvent("addInstanceListener", listener);
        }
    }

    public void addInstanceListener(InstanceListener listener) {
        instanceListenerInstances.add(listener);
        if (notifyContainerListeners) {
            fireContainerEvent("addInstanceListener", listener);
        }
    }

    /**
     * Add the given URL pattern as a jsp-property-group.  This maps
     * resources that match the given pattern so they will be passed
     * to the JSP container.  Though there are other elements in the
     * property group, we only care about the URL pattern here.  The
     * JSP container will parse the rest.
     *
     * @param pattern URL pattern to be mapped
     */
    public void addJspMapping(String pattern) {
        String servletName = findServletMapping("*.jsp");
        if (servletName == null) {
            servletName = "jsp";
        }

        if( findChild(servletName) != null) {
            addServletMapping(pattern, servletName, true);
        } else {
            if (log.isLoggable(Level.FINE)) {
                log.fine("Skipping " + pattern + " , no servlet "
                         + servletName);
            }
        }
    }

    /**
     * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4)
     *
     * @param locale locale to map an encoding for
     * @param encoding encoding to be used for a give locale
     */
    public void addLocaleEncodingMappingParameter(String locale, String encoding){
        getCharsetMapper().addCharsetMappingFromDeploymentDescriptor(locale, encoding);
    }

    /**
     * Add a local EJB resource reference for this web application.
     *
     * @param ejb New EJB resource reference
     */
    public void addLocalEjb(ContextLocalEjb ejb) {
        namingResources.addLocalEjb(ejb);
        if (notifyContainerListeners) {
            fireContainerEvent("addLocalEjb", ejb.getName());
        }
    }

    /**
     * Add a message destination for this web application.
     *
     * @param md New message destination
     */
    public void addMessageDestination(MessageDestination md) {
        synchronized (messageDestinations) {
            messageDestinations.put(md.getName(), md);
        }
        if (notifyContainerListeners) {
            fireContainerEvent("addMessageDestination", md.getName());
        }
    }

    /**
     * Add a message destination reference for this web application.
     *
     * @param mdr New message destination reference
     */
    public void addMessageDestinationRef(MessageDestinationRef mdr) {
        namingResources.addMessageDestinationRef(mdr);
        if (notifyContainerListeners) {
            fireContainerEvent("addMessageDestinationRef", mdr.getName());
        }
    }

    /**
     * Add a new MIME mapping, replacing any existing mapping for
     * the specified extension.
     *
     * @param extension Filename extension being mapped
     * @param mimeType Corresponding MIME type
     */
    public void addMimeMapping(String extension, String mimeType) {
        synchronized (mimeMappings) {
            mimeMappings.put(extension, mimeType);
        }
        if (notifyContainerListeners) {
            fireContainerEvent("addMimeMapping", extension);
        }
    }

    /**
     * Add a new context initialization parameter.
     *
     * @param name Name of the new parameter
     * @param value Value of the new  parameter
     *
     * @exception IllegalArgumentException if the name or value is missing,
     *  or if this context initialization parameter has already been
     *  registered
     */
    public void addParameter(String name, String value) {
        // Validate the proposed context initialization parameter
        if ((name == null) || (value == null))
            throw new IllegalArgumentException
                (sm.getString("standardContext.parameter.required"));
        if (parameters.get(name) != null)
            throw new IllegalArgumentException
                (sm.getString("standardContext.parameter.duplicate", name));

        // Add this parameter to our defined set
        synchronized (parameters) {
            parameters.put(name, value);
        }

        if (notifyContainerListeners) {
            fireContainerEvent("addParameter", name);
        }
    }


    /**
     * Add a resource reference for this web application.
     *
     * @param resource New resource reference
     */
    public void addResource(ContextResource resource) {
        namingResources.addResource(resource);
        if (notifyContainerListeners) {
            fireContainerEvent("addResource", resource.getName());
        }
    }


    /**
     * Add a resource environment reference for this web application.
     *
     * @param name The resource environment reference name
     * @param type The resource environment reference type
     */
    public void addResourceEnvRef(String name, String type) {
        namingResources.addResourceEnvRef(name, type);
        if (notifyContainerListeners) {
            fireContainerEvent("addResourceEnvRef", name);
        }
    }

    /**
     * Add a resource link for this web application.
     *
     * @param resourceLink New resource link
     */
    public void addResourceLink(ContextResourceLink resourceLink) {
        namingResources.addResourceLink(resourceLink);
        if (notifyContainerListeners) {
            fireContainerEvent("addResourceLink", resourceLink.getName());
        }
    }


    /**
     * Add a security role reference for this web application.
     *
     * @param role Security role used in the application
     * @param link Actual security role to check for
     */
    public void addRoleMapping(String role, String link) {
        synchronized (roleMappings) {
            roleMappings.put(role, link);
        }
        if (notifyContainerListeners) {
            fireContainerEvent("addRoleMapping", role);
        }
    }

    /**
     * Add a new security role for this web application.
     *
     * @param role New security role
     */
    public void addSecurityRole(String role) {
        securityRoles.add(role);
        if (notifyContainerListeners) {
            fireContainerEvent("addSecurityRole", role);
        }
    }

    /**
     * Adds the given servlet mappings to this Context.
     *
     * <p>If any of the specified URL patterns are already mapped to a
     * different Servlet, no updates will be performed.
     *
     * @param servletMap the Servlet mappings containing the Servlet name
     * and URL patterns
     *
     * @return the (possibly empty) Set of URL patterns that are already
     * mapped to a different Servlet
     *
     * @exception IllegalArgumentException if the specified servlet name
     * is not known to this Context
     */
     public Set<String> addServletMapping(ServletMap servletMap) {
         return addServletMapping(servletMap.getServletName(),
                                  servletMap.getUrlPatterns());
     }

    /**
     * Adds the given servlet mappings to this Context.
     *
     * <p>If any of the specified URL patterns are already mapped to a
     * different Servlet, no updates will be performed.
     *
     * @param name the Servlet name
     * @param urlPatterns the URL patterns
     *
     * @return the (possibly empty) Set of URL patterns that are already
     * mapped to a different Servlet
     *
     * @exception IllegalArgumentException if the specified servlet name
     * is not known to this Context
     */
    public Set<String> addServletMapping(String name,
                                         String[] urlPatterns) {
        Set<String> conflicts = null;

        synchronized (servletMappings) {
            for (String pattern : urlPatterns) {
                pattern = adjustURLPattern(RequestUtil.urlDecode(pattern));
                if (!validateURLPattern(pattern)) {
                    throw new IllegalArgumentException(sm.getString(
                        "standardContext.servletMap.pattern", pattern));
                }

                // Ignore any conflicts with the container provided
                // Default- and JspServlet
                String existing = servletMappings.get(pattern);
                if (existing != null &&
                        !existing.equals(Constants.DEFAULT_SERVLET_NAME) &&
                        !existing.equals(Constants.JSP_SERVLET_NAME) &&
                        !name.equals(Constants.DEFAULT_SERVLET_NAME) &&
                        !name.equals(Constants.JSP_SERVLET_NAME)) {
                    if (conflicts == null) {
                        conflicts = new HashSet<String>();
                    }
                    conflicts.add(pattern);
                }
            }

            if (conflicts == null) {
                for (String urlPattern : urlPatterns) {
                    addServletMapping(urlPattern, name, false);
                }
                return Collections.emptySet();
            } else {
                return conflicts;  
            }
        }
    }

    /**
     * Adds the given servlet mapping to this Context, overriding any
     * existing mapping for the specified pattern.
     *
     * @param pattern URL pattern to be mapped
     * @param name Name of the corresponding servlet to execute
     *
     * @exception IllegalArgumentException if the specified servlet name
     *  is not known to this Context
     */
    public void addServletMapping(String pattern, String name) {
        addServletMapping(pattern, name, false);
    }

    /**
     * Adds the given servlet mapping to this Context, overriding any
     * existing mapping for the specified pattern.
     *
     * @param pattern URL pattern to be mapped
     * @param name Name of the corresponding servlet to execute
     * @param jspWildCard true if name identifies the JspServlet
     * and pattern contains a wildcard; false otherwise
     *
     * @exception IllegalArgumentException if the specified servlet name
     * is not known to this Context
     */
    public void addServletMapping(String pattern, String name,
                                  boolean jspWildCard) {
        // Validate the proposed mapping
        ServletRegistrationImpl regis = servletRegisMap.get(name);
        if (null == regis) {
            throw new IllegalArgumentException
                (sm.getString("standardContext.servletMap.name", name));
        }

        pattern = adjustURLPattern(RequestUtil.urlDecode(pattern));
        if (!validateURLPattern(pattern)) {
            throw new IllegalArgumentException
                (sm.getString("standardContext.servletMap.pattern", pattern));
        }

        /*
         * Add this mapping to our registered set. Make sure that it is
         * possible to override the mappings of the container provided
         * Default- and JspServlet, and that these servlets are prevented
         * from overriding any user-defined mappings (depending on the order
         * in which the contents of the default-web.xml are merged with those
         * of the app's deployment descriptor).
         * This is to prevent the DefaultServlet from hijacking '/', and the
         * JspServlet from hijacking *.jsp(x).
         */
        synchronized (servletMappings) {
            String existing = servletMappings.get(pattern);
            if (existing != null) {
                if (!existing.equals(Constants.DEFAULT_SERVLET_NAME) &&
                        !existing.equals(Constants.JSP_SERVLET_NAME) &&
                        !name.equals(Constants.DEFAULT_SERVLET_NAME) &&
                        !name.equals(Constants.JSP_SERVLET_NAME)) {
                    throw new IllegalArgumentException(sm.getString(
                        "standardContext.duplicateServletMapping",
                        name, pattern, existing));
                }
                if (existing.equals(Constants.DEFAULT_SERVLET_NAME) ||
                        existing.equals(Constants.JSP_SERVLET_NAME)) {
                    // Override the mapping of the container provided
                    // Default- or JspServlet
                    Wrapper wrapper = (Wrapper) findChild(existing);
                    removePatternFromServlet(wrapper, pattern);
                    mapper.removeWrapper(pattern);
                    servletMappings.put(pattern, name);
                }
            } else {
                servletMappings.put(pattern, name);
            }
        }

        Wrapper wrapper = regis.getWrapper();
        wrapper.addMapping(pattern);

        // Update context mapper
        mapper.addWrapper(pattern, wrapper, jspWildCard, true);

        if (notifyContainerListeners) {
            fireContainerEvent("addServletMapping", pattern);
        }
    }

    /*
     * Adds the servlet with the given name and class name to this servlet
     * context.
     */
    public ServletRegistration.Dynamic addServlet(
            String servletName, String className) {

        if (isContextInitializedCalled) {
            throw new IllegalStateException(
                sm.getString("applicationContext.alreadyInitialized",
                             "addServlet", getName()));
        }
        synchronized (children) {
            if (findChild(servletName) == null) {
                DynamicServletRegistrationImpl regis =
                    (DynamicServletRegistrationImpl)
                        servletRegisMap.get(servletName);
                Wrapper wrapper = null;
                if (regis == null) {
                    wrapper = createWrapper();
                    wrapper.setServletClassName(className);
                } else {
                    // Complete preliminary servlet registration
                    wrapper = regis.getWrapper();
                    regis.setServletClassName(className);
                }
                wrapper.setName(servletName);
                addChild(wrapper, true, (null == regis));
                if (null == regis) {
                    regis = (DynamicServletRegistrationImpl)
                        servletRegisMap.get(servletName);
                }
                return regis;
            } else {
                return null;
            }
        }
    }

    /*
     * Registers the given servlet instance with this ServletContext
     * under the given <tt>servletName</tt>.
     */
    public ServletRegistration.Dynamic addServlet(
            String servletName, Servlet servlet) {
        return addServlet(servletName, servlet, null, null);
    }

    /*
     * Adds the servlet with the given name and class type to this servlet
     * context.
     */
    public ServletRegistration.Dynamic addServlet(String servletName,
            Class <? extends Servlet> servletClass) {

        if (isContextInitializedCalled) {
            throw new IllegalStateException(
                sm.getString("applicationContext.alreadyInitialized",
                             "addServlet", getName()));
        }
        // Make sure servlet name is unique for this context
        synchronized (children) {
            if (findChild(servletName) == null) {
                DynamicServletRegistrationImpl regis =
                    (DynamicServletRegistrationImpl)
                        servletRegisMap.get(servletName);
                Wrapper wrapper = null;
                if (regis == null) {
                    wrapper = createWrapper();
                    wrapper.setServletClass(servletClass);
                } else {
                    // Complete preliminary servlet registration
                    wrapper = regis.getWrapper();
                    regis.setServletClass(servletClass);
                }
                wrapper.setName(servletName);
                addChild(wrapper, true, (null == regis));
                if (null == regis) {
                    regis = (DynamicServletRegistrationImpl)
                        servletRegisMap.get(servletName);
                }
                return regis;
            } else {
                return null;
            }
        }
    }

    /**
     * Adds the given servlet instance with the given name to this servlet
     * context and initializes it.
     *
     * <p>In order to add any URL patterns that will be mapped to the
     * given servlet, addServletMappings must be used. If this context
     * has already been started, the URL patterns must be passed to
     * addServlet instead.
     *
     * @param servletName the servlet name
     * @param instance the servlet instance
     * @param initParams Map containing the initialization parameters for
     * the servlet
     *
     * @throws ServletException if the servlet fails to be initialized
     */
    public ServletRegistration.Dynamic addServlet(String servletName,
            Servlet instance, Map<String, String> initParams) {
        return addServlet(servletName, instance, initParams, null);
    }

    /**
     * Adds the given servlet instance with the given name and URL patterns
     * to this servlet context, and initializes it.
     *
     * @param servletName the servlet name
     * @param servlet the servlet instance
     * @param initParams Map containing the initialization parameters for
     * the servlet
     * @param urlPatterns the URL patterns that will be mapped to the servlet
     *
     * @return the ServletRegistration through which the servlet may be
     * further configured
     */
    public ServletRegistration.Dynamic addServlet(String servletName,
            Servlet servlet, Map<String, String> initParams,
            String... urlPatterns) {

        if (isContextInitializedCalled) {
            throw new IllegalStateException(
                sm.getString("applicationContext.alreadyInitialized",
                             "addServlet", getName()));
        }

        if (servletName == null || servlet == null) {
            throw new NullPointerException("Null servlet instance or name");
        }

        if (servlet instanceof SingleThreadModel) {
            throw new IllegalArgumentException("Servlet implements " +
                SingleThreadModel.class.getName());
        }

        /*
         * Make sure the given Servlet instance is unique across all deployed
         * contexts
         */
        Container host = getParent();
        if (host != null) {
            for (Container child : host.findChildren()) {
                if (child == this) {
                    // Our own context will be checked further down
                    continue;
                }
                if (((StandardContext) child).hasServlet(servlet)) {
                    return null;
                }
            }
        }
     
        /*
         * Make sure the given Servlet name and instance are unique within
         * this context
         */
        synchronized (children) {
            for (Map.Entry<String, Container> e : children.entrySet()) {
                if (servletName.equals(e.getKey()) ||
                        servlet == ((StandardWrapper)e.getValue()).getServlet()) {
                    return null;
                }
            }

            DynamicServletRegistrationImpl regis =
                (DynamicServletRegistrationImpl)
                    servletRegisMap.get(servletName);
            StandardWrapper wrapper = null;
            if (regis == null) {
                wrapper = (StandardWrapper) createWrapper();
            } else {
                // Complete preliminary servlet registration
                wrapper = regis.getWrapper();
            }
                        
            wrapper.setName(servletName);
            wrapper.setServlet(servlet);
            if (initParams != null) {
                for (Map.Entry<String, String> e : initParams.entrySet()) {
                    wrapper.addInitParameter(e.getKey(), e.getValue());
                }
            }

            addChild(wrapper, true, (null == regis));
            if (null == regis) {
                regis = (DynamicServletRegistrationImpl)
                    servletRegisMap.get(servletName);
            }

            if (urlPatterns != null) {
                for (String urlPattern : urlPatterns) {
                    addServletMapping(urlPattern, servletName, false);
                }
            }

            return regis;
        }
    }

    /**
     * This method is overridden in web-glue to also remove the given
     * mapping from the deployment backend's WebBundleDescriptor.
     */
    protected void removePatternFromServlet(Wrapper wrapper, String pattern) {
        wrapper.removeMapping(pattern);
    }

    /**
     * Checks whether this context contains the given Servlet instance
     */
    public boolean hasServlet(Servlet servlet) {
        for (Map.Entry<String, Container> e : children.entrySet()) {
            if (servlet == ((StandardWrapper)e.getValue()).getServlet()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Instantiates the given Servlet class and performs any required
     * resource injection into the new Servlet instance before returning
     * it.
     */
    public <T extends Servlet> T createServlet(Class<T> clazz)
            throws ServletException {
        try {
            return createServletInstance(clazz);
        } catch (Throwable t) {
            throw new ServletException("Unable to create Servlet from " +
                                       "class " + clazz.getName(), t);
        }
    }

    /**
     * Gets the ServletRegistration corresponding to the servlet with the
     * given <tt>servletName</tt>.
     */
    public ServletRegistration getServletRegistration(String servletName) {
        return servletRegisMap.get(servletName);
    }

    /**
     * Gets a Map of the ServletRegistration objects corresponding to all
     * currently registered servlets.
     */
    public Map<String, ? extends ServletRegistration> getServletRegistrations() {
        return Collections.unmodifiableMap(servletRegisMap);
    }

    /**
     * Add a new watched resource to the set recognized by this Context.
     *
     * @param name New watched resource file name
     */
    public void addWatchedResource(String name) {
        watchedResources.add(name);
        fireContainerEvent("addWatchedResource", name);
    }

    /**
     * Add a new welcome file to the set recognized by this Context.
     *
     * @param name New welcome file name
     */
    public void addWelcomeFile(String name) {

        // Welcome files from the application deployment descriptor
        // completely replace those from the default conf/web.xml file
        if (replaceWelcomeFiles) {
            welcomeFiles = new String[0];
            setReplaceWelcomeFiles(false);
        }
        String results[] = new String[welcomeFiles.length + 1];
        for (int i = 0; i < welcomeFiles.length; i++)
            results[i] = welcomeFiles[i];
        results[welcomeFiles.length] = name;
        welcomeFiles = results;

        if (notifyContainerListeners) {
            fireContainerEvent("addWelcomeFile", name);
        }
    }

    /**
     * Add the classname of a LifecycleListener to be added to each
     * Wrapper appended to this Context.
     *
     * @param listener Java class name of a LifecycleListener class
     */
    public void addWrapperLifecycle(String listener) {
        wrapperLifecycles.add(listener);
        if (notifyContainerListeners) {
            fireContainerEvent("addWrapperLifecycle", listener);
        }
    }

    /**
     * Add the classname of a ContainerListener to be added to each
     * Wrapper appended to this Context.
     *
     * @param listener Java class name of a ContainerListener class
     */
    public void addWrapperListener(String listener) {
        wrapperListeners.add(listener);
        if (notifyContainerListeners) {
            fireContainerEvent("addWrapperListener", listener);
        }
    }

    /**
     * Factory method to create and return a new Wrapper instance, of
     * the Java implementation class appropriate for this Context
     * implementation.  The constructor of the instantiated Wrapper
     * will have been called, but no properties will have been set.
     */
    public Wrapper createWrapper() {
        Wrapper wrapper = new StandardWrapper();

        synchronized (instanceListeners) {
            for (String instanceListener : instanceListeners) {
                try {
                    Class clazz = Class.forName(instanceListener);
                    wrapper.addInstanceListener((InstanceListener)clazz.newInstance());
                } catch(Throwable t) {
                    log.log(Level.SEVERE,
                        sm.getString("standardContext.instanceListener",
                            instanceListener),
                        t);
                    return (null);
                }
            }
        }

        synchronized (instanceListenerInstances) {
            for(InstanceListener instanceListenerInstance : instanceListenerInstances) {
                wrapper.addInstanceListener(instanceListenerInstance);
            }
        }

        Iterator<String> i = wrapperLifecycles.iterator();
        while (i.hasNext()) {
            String wrapperLifecycle = i.next();
            try {
                Class clazz = Class.forName(wrapperLifecycle);
                if(wrapper instanceof Lifecycle) {
                    ((Lifecycle)wrapper).addLifecycleListener(
                        (LifecycleListener)clazz.newInstance());
                }
            } catch(Throwable t) {
                log.log(Level.SEVERE,
                    sm.getString("standardContext.lifecycleListener",
                                 wrapperLifecycle),
                    t);
                return (null);
            }
        }

        i = wrapperListeners.iterator();
        while (i.hasNext()) {
            String wrapperListener = i.next();
            try {
                Class clazz = Class.forName(wrapperListener);
                wrapper.addContainerListener((ContainerListener)
                    clazz.newInstance());
            } catch(Throwable t) {
                log.log(Level.SEVERE,
                    sm.getString("standardContext.containerListener",
                                 wrapperListener),
                    t);
                return (null);
            }
        }

        return (wrapper);
    }

    /**
     * Return the set of application parameters for this application.
     */
    public List<ApplicationParameter> findApplicationParameters() {
        return applicationParameters;
    }

    /**
     * Gets the security constraints defined for this web application.
     */
    public List<SecurityConstraint> getConstraints() {
        return constraints;
    }

    /**
     * Checks whether this web application has any security constraints
     * defined.
     */
    public boolean hasConstraints() {
        return !constraints.isEmpty();
    }

    /**
     * Return the EJB resource reference with the specified name, if any;
     * otherwise, return <code>null</code>.
     *
     * @param name Name of the desired EJB resource reference
     */
    public ContextEjb findEjb(String name) {
        return namingResources.findEjb(name);
    }

    /**
     * Return the defined EJB resource references for this application.
     * If there are none, a zero-length array is returned.
     */
    public ContextEjb[] findEjbs() {
        return namingResources.findEjbs();
    }

    /**
     * Return the environment entry with the specified name, if any;
     * otherwise, return <code>null</code>.
     *
     * @param name Name of the desired environment entry
     */
    public ContextEnvironment findEnvironment(String name) {
        return namingResources.findEnvironment(name);
    }

    /**
     * Return the set of defined environment entries for this web
     * application.  If none have been defined, a zero-length array
     * is returned.
     */
    public ContextEnvironment[] findEnvironments() {
        return namingResources.findEnvironments();
    }

    /**
     * Return the error page entry for the specified HTTP error code,
     * if any; otherwise return <code>null</code>.
     *
     * @param errorCode Error code to look up
     */
    public ErrorPage findErrorPage(int errorCode) {
        if ((errorCode >= 400) && (errorCode < 600)) {
            return statusPages.get(errorCode);
        }

        return null;
    }

    /**
     * Return the error page entry for the specified Java exception type,
     * if any; otherwise return <code>null</code>.
     *
     * @param exceptionType Exception type to look up
     */
    public ErrorPage findErrorPage(String exceptionType) {
        synchronized (exceptionPages) {
            return exceptionPages.get(exceptionType);
        }
    }

    /**
     * Gets the default error page of this context.
     *
     * <p>A default error page is an error page that was declared without
     * any exception-type and error-code.
     *
     * @return the default error page of this context, or null if this
     * context does not have any default error page
     */
    public ErrorPage getDefaultErrorPage() {
        return defaultErrorPage;
    }

    /**
     * Return the filter definition for the specified filter name, if any;
     * otherwise return <code>null</code>.
     *
     * @param filterName Filter name to look up
     */
    public FilterDef findFilterDef(String filterName) {
        synchronized (filterDefs) {
            return filterDefs.get(filterName);
        }
    }

    /**
     * Return the set of defined filters for this Context.
     */
    public FilterDef[] findFilterDefs() {
        synchronized (filterDefs) {
            FilterDef results[] = new FilterDef[filterDefs.size()];
            return filterDefs.values().toArray(results);
        }
    }

    /**
     * Return the list of filter mappings for this Context.
     */
    public List<FilterMap> findFilterMaps() {
        return filterMaps;
    }

    /**
     * Return the list of InstanceListener classes that will be added to
     * newly created Wrappers automatically.
     */
    public List<String> findInstanceListeners() {
        return instanceListeners;
    }

    /**
     * Return the local EJB resource reference with the specified name, if any;
     * otherwise, return <code>null</code>.
     *
     * @param name Name of the desired EJB resource reference
     */
    public ContextLocalEjb findLocalEjb(String name) {
        return namingResources.findLocalEjb(name);
    }

    /**
     * Return the defined local EJB resource references for this application.
     * If there are none, a zero-length array is returned.
     */
    public ContextLocalEjb[] findLocalEjbs() {
        return namingResources.findLocalEjbs();
    }

    /**
     * FIXME: Fooling introspection ...
     */
    public Context findMappingObject() {
        return (Context) getMappingObject();
    }

    /**
     * Return the message destination with the specified name, if any;
     * otherwise, return <code>null</code>.
     *
     * @param name Name of the desired message destination
     */
    public MessageDestination findMessageDestination(String name) {
        synchronized (messageDestinations) {
            return messageDestinations.get(name);
        }
    }

    /**
     * Return the set of defined message destinations for this web
     * application.  If none have been defined, a zero-length array
     * is returned.
     */
    public MessageDestination[] findMessageDestinations() {
        synchronized (messageDestinations) {
            return messageDestinations.values().toArray(
                new MessageDestination[messageDestinations.size()]);
        }
    }

    /**
     * Return the message destination ref with the specified name, if any;
     * otherwise, return <code>null</code>.
     *
     * @param name Name of the desired message destination ref
     */
    public MessageDestinationRef findMessageDestinationRef(String name) {
        return namingResources.findMessageDestinationRef(name);
    }

    /**
     * Return the set of defined message destination refs for this web
     * application.  If none have been defined, a zero-length array
     * is returned.
     */
    public MessageDestinationRef[] findMessageDestinationRefs() {
        return namingResources.findMessageDestinationRefs();
    }

    /**
     * Return the MIME type to which the specified extension is mapped,
     * if any; otherwise return <code>null</code>.
     *
     * @param extension Extension to map to a MIME type
     */
    public String findMimeMapping(String extension) {

        String mimeType = mimeMappings.get(extension);
        if (mimeType == null) {
            // No mapping found, try case-insensitive match
            synchronized (mimeMappings) {
                for(String ext : mimeMappings.keySet()) {
                    if(ext.equalsIgnoreCase(extension)) {
                        // Case-insensitive extension match found
                        mimeType = mimeMappings.get(ext);
                        // Add given extension to the map, in order to make
                        // subsequent lookups faster
                        mimeMappings.put(extension, mimeType);
                        break;
                    }
                }
            }
        }

        return mimeType;
    }

    /**
     * Return the extensions for which MIME mappings are defined.  If there
     * are none, a zero-length array is returned.
     */
    public String[] findMimeMappings() {
        synchronized (mimeMappings) {
            return mimeMappings.keySet().toArray(
                new String[mimeMappings.size()]);
        }
    }

    /**
     * Return the value for the specified context initialization
     * parameter name, if any; otherwise return <code>null</code>.
     *
     * @param name Name of the parameter to return
     */
    public String findParameter(String name) {
        synchronized (parameters) {
            return parameters.get(name);
        }
    }

    /**
     * Return the names of all defined context initialization parameters
     * for this Context.  If no parameters are defined, a zero-length
     * array is returned.
     */
    public String[] findParameters() {
        synchronized (parameters) {
            return parameters.keySet().toArray(new String[parameters.size()]);
        }
    }

    /**
     * Return the resource reference with the specified name, if any;
     * otherwise return <code>null</code>.
     *
     * @param name Name of the desired resource reference
     */
    public ContextResource findResource(String name) {
        return namingResources.findResource(name);
    }

    /**
     * Return the resource environment reference type for the specified
     * name, if any; otherwise return <code>null</code>.
     *
     * @param name Name of the desired resource environment reference
     */
    public String findResourceEnvRef(String name) {
        return namingResources.findResourceEnvRef(name);
    }

    /**
     * Return the set of resource environment reference names for this
     * web application.  If none have been specified, a zero-length
     * array is returned.
     */
    public String[] findResourceEnvRefs() {
        return namingResources.findResourceEnvRefs();
    }

    /**
     * Return the resource link with the specified name, if any;
     * otherwise return <code>null</code>.
     *
     * @param name Name of the desired resource link
     */
    public ContextResourceLink findResourceLink(String name) {
        return namingResources.findResourceLink(name);
    }

    /**
     * Return the defined resource links for this application.  If
     * none have been defined, a zero-length array is returned.
     */
    public ContextResourceLink[] findResourceLinks() {
        return namingResources.findResourceLinks();
    }

    /**
     * Return the defined resource references for this application.  If
     * none have been defined, a zero-length array is returned.
     */
    public ContextResource[] findResources() {
        return namingResources.findResources();
    }

    /**
     * For the given security role (as used by an application), return the
     * corresponding role name (as defined by the underlying Realm) if there
     * is one.  Otherwise, return the specified role unchanged.
     *
     * @param role Security role to map
     */
    public String findRoleMapping(String role) {

        String realRole = null;
        synchronized (roleMappings) {
            realRole = roleMappings.get(role);
        }
        if (realRole != null)
            return (realRole);
        else
            return (role);
    }

    /**
     * Checks if the given security role is defined for this application.
     *
     * @param role Security role to check for
     *
     * @return true if the specified security role is defined
     * for this application, false otherwise
     */
    public boolean hasSecurityRole(String role) {
        return securityRoles.contains(role);
    }

    /**
     * Removes any security roles defined for this application.
     */
    public void removeSecurityRoles() {
        // Inform interested listeners
        if (notifyContainerListeners) {
            Iterator<String> i = securityRoles.iterator();
            while (i.hasNext()) {
                fireContainerEvent("removeSecurityRole", i.next());
            }
        }
        securityRoles.clear();
    }

    /**
     * Return the servlet name mapped by the specified pattern (if any);
     * otherwise return <code>null</code>.
     *
     * @param pattern Pattern for which a mapping is requested
     */
    public String findServletMapping(String pattern) {
        synchronized (servletMappings) {
            return servletMappings.get(pattern);
        }
    }

    /**
     * Return the patterns of all defined servlet mappings for this
     * Context.  If no mappings are defined, a zero-length array is returned.
     */
    public String[] findServletMappings() {
        synchronized (servletMappings) {
            String results[] = new String[servletMappings.size()];
            return
                servletMappings.keySet().toArray(results);
        }
    }

    /**
     * Return the context-relative URI of the error page for the specified
     * HTTP status code, if any; otherwise return <code>null</code>.
     *
     * @param status HTTP status code to look up
     */
    public ErrorPage findStatusPage(int status) {
        return statusPages.get(status);
    }

    /**
     * Return the set of HTTP status codes for which error pages have
     * been specified.  If none are specified, a zero-length array
     * is returned.
     */
    public int[] findStatusPages() {
        synchronized (statusPages) {
            int results[] = new int[statusPages.size()];
            Iterator<Integer> elements = statusPages.keySet().iterator();
            int i = 0;
            while (elements.hasNext())
                results[i++] = elements.next();
            return results;
        }
    }

    /**
     * Return <code>true</code> if the specified welcome file is defined
     * for this Context; otherwise return <code>false</code>.
     *
     * @param name Welcome file to verify
     */
    public boolean findWelcomeFile(String name) {
        synchronized (welcomeFiles) {
            for(String welcomeFile : welcomeFiles) {
                if(name.equals(welcomeFile)) {
                    return true;
                }
            }
        }
        return (false);
    }

    /**
     * Gets the watched resources defined for this web application.
     */
    public List<String> getWatchedResources() {
        return watchedResources;
    }

    /**
     * Return the set of welcome files defined for this Context.  If none are
     * defined, a zero-length array is returned.
     */
    public String[] findWelcomeFiles() {
        return (welcomeFiles);
    }

    /**
     * Return the list of LifecycleListener classes that will be added to
     * newly created Wrappers automatically.
     */
    public List<String> findWrapperLifecycles() {
        return wrapperLifecycles;
    }

    /**
     * Return the list of ContainerListener classes that will be added to
     * newly created Wrappers automatically.
     */
    public List<String> findWrapperListeners() {
        return wrapperListeners;
    }

    /**
     * Gets the Authenticator of this Context.
     *
     * @return the Authenticator of this Context
     */
    public Authenticator getAuthenticator() {
        Pipeline p = getPipeline();
        if (p != null) {
            for (GlassFishValve valve : p.getValves()) {
                if (valve instanceof Authenticator) {
                    return (Authenticator) valve;
                }
            }
        }
        return null;
    }

    /**
     * Reload this web application, if reloading is supported.
     * <p>
     * <b>IMPLEMENTATION NOTE</b>:  This method is designed to deal with
     * reloads required by changes to classes in the underlying repositories
     * of our class loader.  It does not handle changes to the web application
     * deployment descriptor.  If that has occurred, you should stop this
     * Context and create (and start) a new Context instance instead.
     *
     * @exception IllegalStateException if the <code>reloadable</code>
     *  property is set to <code>false</code>.
     */
    public synchronized void reload() {

        // Validate our current component state
        if (!started)
            throw new IllegalStateException
                (sm.getString("containerBase.notStarted", logName()));

        // Make sure reloading is enabled
        //      if (!reloadable)
        //          throw new IllegalStateException
        //              (sm.getString("standardContext.notReloadable"));
        if (log.isLoggable(Level.INFO)) {
            log.info(sm.getString("standardContext.reloadingStarted"));
        }

        // Stop accepting requests temporarily
        setPaused(true);

        try {
            stop();
        } catch (LifecycleException e) {
            log.log(Level.SEVERE,
                    sm.getString("standardContext.stoppingContext", this),
                    e);
        }

        try {
            start();
        } catch (LifecycleException e) {
            log.log(Level.SEVERE,
                    sm.getString("standardContext.startingContext", this),
                    e);
        }

        setPaused(false);

    }

    /**
     * Remove the application parameter with the specified name from
     * the set for this application.
     *
     * @param name Name of the application parameter to remove
     */
    public void removeApplicationParameter(String name) {
        ApplicationParameter match = null;
        Iterator<ApplicationParameter> i =
            applicationParameters.iterator();
        while (i.hasNext()) {
            ApplicationParameter applicationParameter = i.next();
            // Make sure this parameter is currently present
            if (name.equals(applicationParameter.getName())) {
                match = applicationParameter;
                break;
            }
        }
        if (match != null) {
            applicationParameters.remove(match);
            // Inform interested listeners
            if (notifyContainerListeners) {
                fireContainerEvent("removeApplicationParameter", name);
            }
        }
    }

    /**
     * Removes the given child container.
     *
     * @param child the child container to be removed
     *
     * @exception IllegalArgumentException if the given child container is
     * not an implementation of Wrapper
     */
    @Override
    public void removeChild(Container child) {

        if (!(child instanceof Wrapper))
            throw new IllegalArgumentException
                (sm.getString("standardContext.notWrapper"));

        super.removeChild(child);
    }

    /**
     * Removes any security constraints from this web application.
     */
    public void removeConstraints() {
        // Inform interested listeners
        if (notifyContainerListeners) {
            Iterator<SecurityConstraint> i = constraints.iterator();
            while (i.hasNext()) {
                fireContainerEvent("removeConstraint", i.next());
            }
        }
        constraints.clear();
    }

    /**
     * Remove any EJB resource reference with the specified name.
     *
     * @param name Name of the EJB resource reference to remove
     */
    public void removeEjb(String name) {

        namingResources.removeEjb(name);

        if (notifyContainerListeners) {
            fireContainerEvent("removeEjb", name);
        }
    }

    /**
     * Remove any environment entry with the specified name.
     *
     * @param name Name of the environment entry to remove
     */
    public void removeEnvironment(String name) {
        if (namingResources == null) {
            return;
        }
        ContextEnvironment env = namingResources.findEnvironment(name);
        if (env == null) {
            throw new IllegalArgumentException
                ("Invalid environment name '" + name + "'");
        }

        namingResources.removeEnvironment(name);

        if (notifyContainerListeners) {
            fireContainerEvent("removeEnvironment", name);
        }
    }

    /**
     * Removes any error page declarations.
     */
    public void removeErrorPages() {
        synchronized (exceptionPages) {
            if (notifyContainerListeners) {
                for (ErrorPage errorPage : exceptionPages.values()) {
                    fireContainerEvent("removeErrorPage", errorPage);
                }
            }
            exceptionPages.clear();
        }
        synchronized (statusPages) {
            if (notifyContainerListeners) {
                for (ErrorPage statusPage : statusPages.values()) {
                    fireContainerEvent("removeErrorPage", statusPage);
                }
            }
            statusPages.clear();
        }
    }

    /**
     * Remove the specified filter definition from this Context, if it exists;
     * otherwise, no action is taken.
     *
     * @param filterDef Filter definition to be removed
     */
    public void removeFilterDef(FilterDef filterDef) {

        synchronized (filterDefs) {
            filterDefs.remove(filterDef.getFilterName());
        }

        if (notifyContainerListeners) {
            fireContainerEvent("removeFilterDef", filterDef);
        }
    }

    /**
     * Removes any filter mappings from this Context.
     */
    public void removeFilterMaps() {
        // Inform interested listeners
        if (notifyContainerListeners) {
            Iterator<FilterMap> i = filterMaps.iterator();
            while (i.hasNext()) {
                fireContainerEvent("removeFilterMap", i.next());
            }
        }
        filterMaps.clear();
    }

    /**
     * Remove a class name from the list of InstanceListener classes that
     * will be added to newly created Wrappers.
     *
     * @param listener Class name of an InstanceListener class to be removed
     */
    public void removeInstanceListener(String listener) {
        instanceListeners.remove(listener);
        // Inform interested listeners
        if (notifyContainerListeners) {
            fireContainerEvent("removeInstanceListener", listener);
        }
    }

    /**
     * Remove any local EJB resource reference with the specified name.
     *
     * @param name Name of the EJB resource reference to remove
     */
    public void removeLocalEjb(String name) {

        namingResources.removeLocalEjb(name);

        if (notifyContainerListeners) {
            fireContainerEvent("removeLocalEjb", name);
        }
    }

    /**
     * Remove any message destination with the specified name.
     *
     * @param name Name of the message destination to remove
     */
    public void removeMessageDestination(String name) {

        synchronized (messageDestinations) {
            messageDestinations.remove(name);
        }

        if (notifyContainerListeners) {
            fireContainerEvent("removeMessageDestination", name);
        }
    }

    /**
     * Remove any message destination ref with the specified name.
     *
     * @param name Name of the message destination ref to remove
     */
    public void removeMessageDestinationRef(String name) {

        namingResources.removeMessageDestinationRef(name);

        if (notifyContainerListeners) {
            fireContainerEvent("removeMessageDestinationRef", name);
        }
    }

    /**
     * Remove the MIME mapping for the specified extension, if it exists;
     * otherwise, no action is taken.
     *
     * @param extension Extension to remove the mapping for
     */
    public void removeMimeMapping(String extension) {

        synchronized (mimeMappings) {
            mimeMappings.remove(extension);
        }

        if (notifyContainerListeners) {
            fireContainerEvent("removeMimeMapping", extension);
        }
    }

    /**
     * Remove the context initialization parameter with the specified
     * name, if it exists; otherwise, no action is taken.
     *
     * @param name Name of the parameter to remove
     */
    public void removeParameter(String name) {

        synchronized (parameters) {
            parameters.remove(name);
        }

        if (notifyContainerListeners) {
            fireContainerEvent("removeParameter", name);
        }
    }

    /**
     * Remove any resource reference with the specified name.
     *
     * @param resourceName Name of the resource reference to remove
     */
    public void removeResource(String resourceName) {
        String decoded = URLDecoder.decode(resourceName);
        if (namingResources == null) {
            return;
        }
        ContextResource resource = namingResources.findResource(decoded);
        if (resource == null) {
            throw new IllegalArgumentException
                ("Invalid resource name '" + decoded + "'");
        }

        namingResources.removeResource(decoded);

        if (notifyContainerListeners) {
            fireContainerEvent("removeResource", decoded);
        }
    }

    /**
     * Remove any resource environment reference with the specified name.
     *
     * @param name Name of the resource environment reference to remove
     */
    public void removeResourceEnvRef(String name) {

        namingResources.removeResourceEnvRef(name);

        if (notifyContainerListeners) {
            fireContainerEvent("removeResourceEnvRef", name);
        }
    }

    /**
     * Remove any resource link with the specified name.
     *
     * @param link Name of the resource link to remove
     */
    public void removeResourceLink(String link) {
        String decoded = URLDecoder.decode(link);
        if (namingResources == null) {
            return;
        }
        ContextResourceLink resource = namingResources.findResourceLink(decoded);
        if (resource == null) {
            throw new IllegalArgumentException
                ("Invalid resource name '" + decoded + "'");
        }

        namingResources.removeResourceLink(decoded);

        if (notifyContainerListeners) {
            fireContainerEvent("removeResourceLink", decoded);
        }
    }

    /**
     * Remove any security role reference for the specified name
     *
     * @param role Security role (as used in the application) to remove
     */
    public void removeRoleMapping(String role) {
        synchronized (roleMappings) {
            roleMappings.remove(role);
        }

        if (notifyContainerListeners) {
            fireContainerEvent("removeRoleMapping", role);
        }
    }

    /**
     * Remove any servlet mapping for the specified pattern, if it exists;
     * otherwise, no action is taken.
     *
     * @param pattern URL pattern of the mapping to remove
     */
    public void removeServletMapping(String pattern) {

        String name = null;
        synchronized (servletMappings) {
            name = servletMappings.remove(pattern);
        }
        Wrapper wrapper = (Wrapper) findChild(name);
        if( wrapper != null ) {
            wrapper.removeMapping(pattern);
        }
        mapper.removeWrapper(pattern);

        if (notifyContainerListeners) {
            fireContainerEvent("removeServletMapping", pattern);
        }
    }

    /**
     * Checks whether this web application has any watched resources
     * defined.
     */
    @Override
    public boolean hasWatchedResources() {
        return !watchedResources.isEmpty();
    }

    /**
     * Clears any watched resources defined for this web application.
     */
    @Override
    public void removeWatchedResources() {
        synchronized (watchedResources) {
            // Inform interested listeners
            if (notifyContainerListeners) {
                Iterator<String> i = watchedResources.iterator();
                while (i.hasNext()) {
                    fireContainerEvent("removeWatchedResource", i.next());
                }
            }
            watchedResources.clear();
        }
    }
        
    @Override
    public void removeWelcomeFiles() {
        if (notifyContainerListeners) {
            for (String welcomeFile : welcomeFiles) {
                fireContainerEvent("removeWelcomeFile", welcomeFile);
            }
        }
        welcomeFiles = new String[0];
    }

    @Override
    public void removeWrapperLifecycles() {
        // Inform interested listeners
        if (notifyContainerListeners) {
            Iterator<String> i = wrapperLifecycles.iterator();
            while (i.hasNext()) {
                fireContainerEvent("removeWrapperLifecycle", i.next());
            }
        }
        wrapperLifecycles.clear();
    }

    @Override
    public void removeWrapperListeners() {
        // Inform interested listeners
        if (notifyContainerListeners) {
            Iterator<String> i = wrapperListeners.iterator();
            while (i.hasNext()) {
                fireContainerEvent("removeWrapperListener", i.next());
            }
        }
        wrapperListeners.clear();
    }

    @Override
    public void fireRequestInitializedEvent(ServletRequest request) {
        List<EventListener> listeners = getApplicationEventListeners();
        ServletRequestEvent event = null;
        if (!listeners.isEmpty()) {
            event = new ServletRequestEvent(getServletContext(), request);
            // create pre-service event
            Iterator<EventListener> iter = listeners.iterator();
            while (iter.hasNext()) {
                EventListener eventListener = iter.next();
                if (!(eventListener instanceof ServletRequestListener)) {
                    continue;
                }
                ServletRequestListener listener =
                    (ServletRequestListener) eventListener;
                // START SJSAS 6329662
                fireContainerEvent(ContainerEvent.BEFORE_REQUEST_INITIALIZED,
                    listener);
                // END SJSAS 6329662
                try {
                    listener.requestInitialized(event);
                } catch (Throwable t) {
                    log(sm.getString(
                        "standardContextValve.requestListener.requestInit",
                        listener.getClass().getName()),
                        t);
                    request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
                // START SJSAS 6329662
                } finally {
                    fireContainerEvent(ContainerEvent.AFTER_REQUEST_INITIALIZED,
                        listener);
                // END SJSAS 6329662
                }
            }
        }
    }

    @Override
    public void fireRequestDestroyedEvent(ServletRequest request) {
        List<EventListener> listeners = getApplicationEventListeners();
        if (!listeners.isEmpty()) {
            // create post-service event
            ServletRequestEvent event = new ServletRequestEvent(getServletContext(),
                request);
            int len = listeners.size();
            for (int i = 0; i < len; i++) {
                EventListener eventListener = listeners.get((len - 1) - i);
                if (!(eventListener instanceof ServletRequestListener)) {
                    continue;
                }
                ServletRequestListener listener =
                    (ServletRequestListener) eventListener;
                // START SJSAS 6329662
                fireContainerEvent(ContainerEvent.BEFORE_REQUEST_DESTROYED,
                    listener);
                // END SJSAS 6329662
                try {
                    listener.requestDestroyed(event);
                } catch (Throwable t) {
                    log(sm.getString(
                        "standardContextValve.requestListener.requestDestroyed",
                        listener.getClass().getName()),
                        t);
                    request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
                // START SJSAS 6329662
                } finally {
                    fireContainerEvent(ContainerEvent.AFTER_REQUEST_DESTROYED,
                        listener);
                // END SJSAS 6329662
                }
            }
        }
    }

    // --------------------------------------------------------- Public Methods

    /**
     * Configure and initialize the set of filters for this Context.
     * Return <code>true</code> if all filter initialization completed
     * successfully, or <code>false</code> otherwise.
     */
    public boolean filterStart() {

        if (log.isLoggable(Level.FINE))
            log.fine("Starting filters");
        // Instantiate and record a FilterConfig for each defined filter
        boolean ok = true;
        synchronized (filterConfigs) {
            filterConfigs.clear();
            for (String name : filterDefs.keySet()) {
                if(log.isLoggable(Level.FINE)) {
                    log.fine(" Starting filter '" + name + "'");
                }
                try {
                    filterConfigs.put(name,
                        new ApplicationFilterConfig(this,
                                                    filterDefs.get(name)));
                } catch(Throwable t) {
                    getServletContext().log
                        (sm.getString("standardContext.filterStart", name), t);
                    ok = false;
                }
            }
        }

        return (ok);

    }

    /**
     * Finalize and release the set of filters for this Context.
     * Return <code>true</code> if all filter finalization completed
     * successfully, or <code>false</code> otherwise.
     */
    public boolean filterStop() {

        if (log.isLoggable(Level.FINE))
            log.fine("Stopping filters");

        // Release all Filter and FilterConfig instances
        synchronized (filterConfigs) {
            for (String filterName : filterConfigs.keySet()) {
                if(log.isLoggable(Level.FINE)) {
                    log.fine(" Stopping filter '" + filterName + "'");
                }
                ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)filterConfigs.get(filterName);
                filterConfig.release();
            }
            filterConfigs.clear();
        }
        return (true);
    }

    /**
     * Find and return the initialized <code>FilterConfig</code> for the
     * specified filter name, if any; otherwise return <code>null</code>.
     *
     * @param name Name of the desired filter
     */
    public FilterConfig findFilterConfig(String name) {
        return filterConfigs.get(name);
    }

    /**
     * Notifies all ServletContextListeners at their contextInitialized
     * method.
     */
    protected void contextListenerStart() {
        ServletContextEvent event = new ServletContextEvent(
            getServletContext());
        for (ServletContextListener listener : contextListeners) {
            if (listener instanceof RestrictedServletContextListener) {
                listener = ((RestrictedServletContextListener) listener).
                    getNestedListener();
                context.setRestricted(true);
            }
            try {
                fireContainerEvent(ContainerEvent.BEFORE_CONTEXT_INITIALIZED,
                                   listener);
                listener.contextInitialized(event);
            } finally {
                context.setRestricted(false);
                fireContainerEvent(ContainerEvent.AFTER_CONTEXT_INITIALIZED,
                                   listener);
            }
        }

        /*
         * Make sure there are no preliminary servlet or filter
         * registrations left after all listeners have been notified
         */
        Collection<ServletRegistrationImpl> servletRegistrations =
            servletRegisMap.values();
        for (ServletRegistrationImpl regis : servletRegistrations) {
            if (null == regis.getClassName() && null == regis.getJspFile()) {
                throw new IllegalStateException(
                    sm.getString(
                        "standardContext.servletWithoutAnyClassOrJspFile",
                        regis.getName()));
            }
        }
        Collection<FilterRegistrationImpl> filterRegistrations =
            filterRegisMap.values();
        for (FilterRegistrationImpl regis : filterRegistrations) {
            if (null == regis.getClassName()) {
                throw new IllegalStateException(
                    sm.getString(
                        "standardContext.filterWithoutAnyClass",
                        regis.getName()));
            }
        }
       
        isContextInitializedCalled = true;
    }


    /**
     * Loads and instantiates the listener with the specified classname.
     *
     * @param loader the classloader to use
     * @param listenerClassName the fully qualified classname to instantiate
     *
     * @return the instantiated listener
     *
     * @throws Exception if the specified classname fails to be loaded or
     * instantiated
     */
    @SuppressWarnings("unchecked")
    protected EventListener loadListener(ClassLoader loader,
                                         String listenerClassName)
            throws Exception {
        if (log.isLoggable(Level.FINE)) {
            log.fine("Configuring event listener class '" +
                     listenerClassName + "'");
        }
        return createListener((Class<EventListener>)
            loader.loadClass(listenerClassName));
    }

    /**
     * Notifies all ServletContextListeners at their contextDestroyed
     * method.
     *
     * @return <code>true</code> if the event was processed successfully,
     * <code>false</code> otherwise.
     */
    private boolean contextListenerStop() {

        boolean ok = true;

        if (contextListeners.isEmpty()) {
            return ok;
        }

        ServletContextEvent event = new ServletContextEvent(
            getServletContext());
        int len = contextListeners.size();
        for (int i = 0; i < len; i++) {
            // Invoke in reverse order of declaration
            ServletContextListener listener =
                contextListeners.get((len - 1) - i);
            if (listener instanceof RestrictedServletContextListener) {
                listener = ((RestrictedServletContextListener) listener).
                    getNestedListener();
                context.setRestricted(true);
            }
            try {
                fireContainerEvent(ContainerEvent.BEFORE_CONTEXT_DESTROYED,
                                   listener);
                listener.contextDestroyed(event);
                fireContainerEvent(ContainerEvent.AFTER_CONTEXT_DESTROYED,
                                   listener);
            } catch (Throwable t) {
                context.setRestricted(false);
                fireContainerEvent(ContainerEvent.AFTER_CONTEXT_DESTROYED,
                                   listener);
                getServletContext().log(sm.getString(
                        "standardContext.listenerStop",
                        listener.getClass().getName()), t);
                ok = false;
            }
        }

        contextListeners.clear();

        return ok;
    }

    private void sessionListenerStop() {
        for (HttpSessionListener listener : sessionListeners) {
            // ServletContextListeners already had their PreDestroy called
            if (!(listener instanceof ServletContextListener)) {
                fireContainerEvent(ContainerEvent.PRE_DESTROY, listener);
            }
        }
        sessionListeners.clear();
    }

    private boolean eventListenerStop() {
        if (eventListeners.isEmpty()) {
            return true;
        }

        Iterator<EventListener> iter = eventListeners.iterator();
        while (iter.hasNext()) {
            EventListener listener = iter.next();
            // ServletContextListeners and HttpSessionListeners
            // already had their PreDestroy called
            if (listener instanceof ServletContextListener ||
                    listener instanceof HttpSessionListener) {
                continue;
            }
            fireContainerEvent(ContainerEvent.PRE_DESTROY, listener);
        }
       
        eventListeners.clear();

        return true;
    }

    /**
     * Allocate resources, including proxy.
     * Return <code>true</code> if initialization was successfull,
     * or <code>false</code> otherwise.
     */
    public boolean resourcesStart() {

        boolean ok = true;

        Hashtable<String, String> env = new Hashtable<String, String>();
        if(getParent() != null) {
            env.put(ProxyDirContext.HOST, getParent().getName());
        }
        env.put(ProxyDirContext.CONTEXT, getName());
        try {
            ProxyDirContext proxyDirContext = new ProxyDirContext(env, webappResources);
            if(webappResources instanceof BaseDirContext) {
                ((BaseDirContext)webappResources).setDocBase(getBasePath(getDocBase()));
                ((BaseDirContext)webappResources).allocate();
            }
            // Register the cache in JMX
            if(isCachingAllowed()) {
                ObjectName resourcesName = new ObjectName(
                    this.getDomain() + ":type=Cache,host="
                        + getHostname() + ",path="
                    + (("".equals(encodedPath)) ? "/" : encodedPath));
                Registry.getRegistry(null, null).registerComponent
                    (proxyDirContext.getCache(), resourcesName, null);
            }
            this.resources = proxyDirContext;
        } catch(Throwable t) {
            if(log.isLoggable(Level.FINE)) {
                log.log(Level.SEVERE,
                    sm.getString("standardContext.resourcesStart",
                        getName()),
                    t);
            } else {
                log.log(Level.SEVERE,
                    sm.getString("standardContext.resourcesStart",
                        getName()) +
                        ": " + t.getMessage());
            }
            ok = false;
        }

        return ok;
    }

    /**
     * Starts this context's alternate doc base resources.
     */
    public void alternateResourcesStart() throws LifecycleException {

        if (alternateDocBases == null || alternateDocBases.isEmpty()) {
            return;
        }

        Hashtable<String, String> env = new Hashtable<String, String>();
        if (getParent() != null) {
            env.put(ProxyDirContext.HOST, getParent().getName());
        }
        env.put(ProxyDirContext.CONTEXT, getName());
        for(AlternateDocBase alternateDocBase : alternateDocBases) {
            String basePath = alternateDocBase.getBasePath();
            DirContext alternateWebappResources = alternateDocBase.getWebappResources();
            try {
                ProxyDirContext proxyDirContext = new ProxyDirContext(env, alternateWebappResources);
                if(alternateWebappResources instanceof BaseDirContext) {
                    ((BaseDirContext)alternateWebappResources).setDocBase(basePath);
                    ((BaseDirContext)alternateWebappResources).allocate();
                }
                alternateDocBase.setResources(proxyDirContext);
            } catch(Throwable t) {
                if(log.isLoggable(Level.FINE)) {
                    throw new LifecycleException(
                        sm.getString("standardContext.resourcesStart",
                            getName()),
                        t);
                } else {
                    throw new LifecycleException(
                        sm.getString("standardContext.resourcesStart",
                            getName()) +
                            ": " + t.getMessage());
                }
            }
        }
    }

    /**
     * Deallocate resources and destroy proxy.
     */
    public boolean resourcesStop() {

        boolean ok = true;

        try {
            if (resources != null) {
                if (resources instanceof Lifecycle) {
                    ((Lifecycle) resources).stop();
                }
                if (webappResources instanceof BaseDirContext) {
                    ((BaseDirContext) webappResources).release();
                }
                // Unregister the cache in JMX
                if (isCachingAllowed()) {
                    ObjectName resourcesName =
                        new ObjectName(this.getDomain()
                                       + ":type=Cache,host="
                                       + getHostname() + ",path="
                                       + (("".equals(getPath()))?"/"
                                          :getPath()));
                    Registry.getRegistry(null, null).unregisterComponent(resourcesName);
                }
            }
        } catch (Throwable t) {
            log.log(Level.SEVERE,
                    sm.getString("standardContext.resourcesStop"), t);
            ok = false;
        }

        this.resources = null;

        return (ok);

    }

    /**
     * Stops this context's alternate doc base resources.
     */
    public boolean alternateResourcesStop() {

        boolean ok = true;

        if (alternateDocBases == null || alternateDocBases.isEmpty()) {
            return ok;
        }
        for(AlternateDocBase alternateDocBase : alternateDocBases) {
            DirContext alternateResources = alternateDocBase.getResources();
            if(alternateResources instanceof Lifecycle) {
                try {
                    ((Lifecycle)alternateResources).stop();
                } catch(Throwable t) {
                    log.log(Level.SEVERE,
                        sm.getString("standardContext.resourcesStop"),
                        t);
                    ok = false;
                }
            }
            DirContext alternateWebappResources =
                alternateDocBase.getWebappResources();
            if(alternateWebappResources instanceof BaseDirContext) {
                try {
                    ((BaseDirContext)alternateWebappResources).release();
                } catch(Throwable t) {
                    log.log(Level.SEVERE,
                        sm.getString("standardContext.resourcesStop"),
                        t);
                    ok = false;
                }
            }
        }

        this.alternateDocBases = null;

        return (ok);
    }

    /**
     * Load and initialize all servlets marked "load on startup" in the
     * web application deployment descriptor.
     *
     * @param children Array of wrappers for all currently defined
     *  servlets (including those not declared load on startup)
     */
    /* SJSAS 6377790
    public void loadOnStartup(Container children[]){
    */
    // START SJSAS 6377790
    public void loadOnStartup(Container children[]) throws LifecycleException {
    // END SJSAS 6377790
        // Collect "load on startup" servlets that need to be initialized
        Map<Integer, List<Wrapper>> map =
            new TreeMap<Integer, List<Wrapper>>();
        for (Container aChildren : children) {
            Wrapper wrapper = (Wrapper)aChildren;
            int loadOnStartup = wrapper.getLoadOnStartup();
            if(loadOnStartup < 0) {
                continue;
            }
            Integer key = loadOnStartup;
            List<Wrapper> list = map.get(key);
            if(list == null) {
                list = new ArrayList<Wrapper>();
                map.put(key, list);
            }
            list.add(wrapper);
        }

        // Load the collected "load on startup" servlets
        for (List<Wrapper> list : map.values()) {
            for(Wrapper wrapper : list) {
                try {
                    wrapper.load();
                } catch(ServletException e) {
                    getServletContext().log
                        (sm.getString("standardWrapper.loadException",
                            getName()),
                            StandardWrapper.getRootCause(e));
                    // NOTE: load errors (including a servlet that throws
                    // UnavailableException from the init() method) are NOT
                    // fatal to application startup
                    // START SJSAS 6377790
                    throw new LifecycleException(
                        StandardWrapper.getRootCause(e));
                    // END SJSAS 6377790
                }
            }
        }
    }

    /**
     * Starts the session manager of this Context.
     */
    protected void managerStart() throws LifecycleException {
        if ((manager != null) && (manager instanceof Lifecycle)) {
            ((Lifecycle) getManager()).start();
        }
    }


    /**
     * Stops the session manager of this Context.
     */
    protected void managerStop() throws LifecycleException {
        if ((manager != null) && (manager instanceof Lifecycle)) {
            ((Lifecycle) manager).stop();
        }
    }

    /**
     * Start this Context component.
     *
     * @exception LifecycleException if a startup error occurs
     */
    @Override
    public synchronized void start() throws LifecycleException {

        if (started) {
            if (log.isLoggable(Level.INFO)) {
                log.info(sm.getString("containerBase.alreadyStarted",
                                      logName()));
            }
            return;
        }

        long startupTimeStart = System.currentTimeMillis();

        if(!initialized) {
            try {
                init();
            } catch( Exception ex ) {
                throw new LifecycleException("Error initializaing ", ex);
            }
        }
        if (log.isLoggable(Level.FINE)) {
            log.fine("Starting " +
                ("".equals(getName()) ? "ROOT" : getName()));
        }

        // Set JMX object name for proper pipeline registration
        preRegisterJMX();

        if ((oname != null) &&
            (Registry.getRegistry(null, null).getMBeanServer().isRegistered(oname))) {
            // As things depend on the JMX registration, the context
            // must be reregistered again once properly initialized
            Registry.getRegistry(null, null).unregisterComponent(oname);
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

        setAvailable(false);
        setConfigured(false);

        // Install DefaultContext configuration
        if (!getOverride()) {
            Container host = getParent();
            if (host instanceof StandardHost) {
                ((StandardHost)host).installDefaultContext(this);
                Container engine = host.getParent();
                if( engine instanceof StandardEngine ) {
                    ((StandardEngine)engine).installDefaultContext(this);
                }
            }
        }

        // Add missing components as necessary
        if (webappResources == null) {   // (1) Required by Loader
            if (log.isLoggable(Level.FINE)) {
                log.fine("Configuring default Resources");
            }
            try {
                if ((docBase != null) && (docBase.endsWith(".war")) &&
                        (!(new File(docBase).isDirectory())))
                    setResources(new WARDirContext());
                else
                    setResources(new FileDirContext());
            } catch (IllegalArgumentException e) {
                throw new LifecycleException(
                    sm.getString("standardContext.resourcesInit"), e);
            }
        }

        resourcesStart();

        // Add alternate resources
        if (alternateDocBases != null && !alternateDocBases.isEmpty()) {
            for(AlternateDocBase alternateDocBase : alternateDocBases) {
                String docBase = alternateDocBase.getDocBase();
                if(log.isLoggable(Level.FINE)) {
                    log.fine("Configuring alternate resources");
                }
                try {
                    if(docBase != null && docBase.endsWith(".war") &&
                        (!(new File(docBase).isDirectory()))) {
                        setAlternateResources(alternateDocBase,
                            new WARDirContext());
                    } else {
                        setAlternateResources(alternateDocBase,
                            new FileDirContext());
                    }
                } catch(IllegalArgumentException e) {
                    throw new LifecycleException(
                        sm.getString("standardContext.resourcesInit"), e);
                }
            }

            alternateResourcesStart();
        }

        // Look for a realm - that may have been configured earlier.
        // If the realm is added after context - it'll set itself.
        if (realm == null) {
            ObjectName realmName=null;
            try {
                realmName=new ObjectName( getEngineName() + ":type=Realm,host="
                                        + getHostname() + ",path=" + getPath());
                if( mserver.isRegistered(realmName ) ) {
                    mserver.invoke(realmName, "init",
                            new Object[] {},
                            new String[] {}
                    );
                }
            } catch( Throwable t ) {
                if (log.isLoggable(Level.FINE)) {
                    log.fine("No realm for this host " + realmName);
                }
            }
        }

        if (getLoader() == null) {
            createLoader();
        }

        // Initialize character set mapper
        getCharsetMapper();

        // Post work directory
        postWorkDirectory();

        // Validate required extensions
        try {
            ExtensionValidator.validateApplication(getResources(), this);
        } catch (IOException ioe) {
            throw new LifecycleException(
                sm.getString("standardContext.dependencyCheck", this),
                ioe);
        }

        // Reading the "catalina.useNaming" environment variable
        String useNamingProperty = System.getProperty("catalina.useNaming");
        if ((useNamingProperty != null) &&
                ("false".equals(useNamingProperty))) {
            useNaming = false;
        }

        if (isUseNaming()) {
            if (namingContextListener == null) {
                namingContextListener = new NamingContextListener();
                namingContextListener.setDebug(getDebug());
                namingContextListener.setName(getNamingContextName());
                addLifecycleListener(namingContextListener);
            }
        }

        // Binding thread
        // START OF SJSAS 8.1 6174179
        //ClassLoader oldCCL = bindThread();
        ClassLoader oldCCL = null;
        // END OF SJSAS 8.1 6174179

        try {
            started = true;

            // Start our subordinate components, if any
            if ((loader != null) && (loader instanceof Lifecycle))
                ((Lifecycle) loader).start();
            if ((logger != null) && (logger instanceof Lifecycle))
                ((Lifecycle) logger).start();

            // Unbinding thread
            // START OF SJSAS 8.1 6174179
            //unbindThread(oldCCL);
            // END OF SJSAS 8.1 6174179

            // Binding thread
            oldCCL = bindThread();

            if ((realm != null) && (realm instanceof Lifecycle))
                ((Lifecycle) realm).start();
            if ((resources != null) && (resources instanceof Lifecycle))
                ((Lifecycle) resources).start();

            // Start our child containers, if any
            for (Container child : findChildren()) {
                if(child instanceof Lifecycle) {
                    ((Lifecycle)child).start();
                }
            }

            // Start the Valves in our pipeline (including the basic),
            // if any
            if (pipeline instanceof Lifecycle)
                ((Lifecycle) pipeline).start();

            // START SJSAS 8.1 5049111
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(START_EVENT, null);
            // END SJSAS 8.1 5049111
        } catch (Throwable t) {
            throw new LifecycleException(t);
        } finally {
            // Unbinding thread
            unbindThread(oldCCL);
        }

        if (!getConfigured()) {
            throw new LifecycleException(
                sm.getString("standardContext.startFailed", getName()));
        }

        // Store some required info as ServletContext attributes
        postResources();
        if (orderedLibs != null && !orderedLibs.isEmpty()) {
            getServletContext().setAttribute(ServletContext.ORDERED_LIBS,
                orderedLibs);
            context.setAttributeReadOnly(ServletContext.ORDERED_LIBS);
        }

        // Initialize associated mapper
        mapper.setContext(getPath(), welcomeFiles, resources);

        // Binding thread
        oldCCL = bindThread();

        try {
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

            // Support for pluggability : this has to be done before
            // listener events are fired
            callServletContainerInitializers();

            // Configure and call application event listeners
            contextListenerStart();

            // Start manager
            if ((manager != null) && (manager instanceof Lifecycle)) {
                ((Lifecycle) getManager()).start();
            }

            // Start ContainerBackgroundProcessor thread
            super.threadStart();

            // Configure and call application filters
            filterStart();

            // Load and initialize all "load on startup" servlets
            loadOnStartup(findChildren());
        } catch (Throwable t) {
            log.severe(sm.getString("standardContext.startFailed", getName()));
            try {
                stop();
            } catch (Throwable tt) {
                log.log(Level.SEVERE,
                        sm.getString("standardContext.startCleanup"), tt);
            }
            throw new LifecycleException(t);
        } finally {
            // Unbinding thread
            unbindThread(oldCCL);
        }

        // Set available status depending upon startup success
        if (log.isLoggable(Level.FINEST)) {
            log.finest("Startup successfully completed");
        }

        setAvailable(true);

        // JMX registration
        registerJMX();

        startTimeMillis = System.currentTimeMillis();
        startupTime = startTimeMillis - startupTimeStart;

        // Send j2ee.state.running notification
        if (getObjectName() != null) {
            Notification notification =
                new Notification("j2ee.state.running", this.getObjectName(),
                                 sequenceNumber++);
            broadcaster.sendNotification(notification);
        }

        // Close all JARs right away to avoid always opening a peak number
        // of files on startup
        if (getLoader() instanceof WebappLoader) {
            ((WebappLoader) getLoader()).closeJARs(true);
        }
    }

    protected Types getTypes() {
        return null;
    }

    protected void callServletContainerInitializers()
            throws LifecycleException {

        // Get the list of ServletContainerInitializers and the classes
        // they are interested in
        Map<Class<?>, List<Class<? extends ServletContainerInitializer>>> interestList =
            ServletContainerInitializerUtil.getInterestList(
                servletContainerInitializers);
        Map<Class<? extends ServletContainerInitializer>, Set<Class<?>>> initializerList =
            ServletContainerInitializerUtil.getInitializerList(
                servletContainerInitializers, interestList,
                getTypes(),
                getClassLoader());
        if (initializerList == null) {
            return;
        }

        // Allow programmatic registration of ServletContextListeners, but
        // only within the scope of ServletContainerInitializer#onStartup
        isProgrammaticServletContextListenerRegistrationAllowed = true;

        // We have the list of initializers and the classes that satisfy
        // the condition. Time to call the initializers
        ServletContext ctxt = this.getServletContext();
        try {
            for (Map.Entry<Class<? extends ServletContainerInitializer>, Set<Class<?>>> e :
                    initializerList.entrySet()) {
                Class<? extends ServletContainerInitializer> initializer = e.getKey();
                // See IT 11333
                if (isUseMyFaces() &&
                        Globals.FACES_INITIALIZER.equals(initializer.getName())) {
                    continue;
                }
                try {
                    if (log.isLoggable(Level.FINE)) {
                        log.fine("Calling ServletContainerInitializer [" + initializer + "] onStartup with classes " +
                                e.getValue());
                    }
                    ServletContainerInitializer iniInstance =
                        initializer.newInstance();
                    iniInstance.onStartup(
                        initializerList.get(initializer), ctxt);
                } catch (Throwable t) {
                    log.log(Level.SEVERE,
                        sm.getString(
                            "standardContext.servletContainerInitializer.error",
                            initializer.getCanonicalName()),
                        t);
                    throw new LifecycleException(t);
                }
            }
        } finally {
            isProgrammaticServletContextListenerRegistrationAllowed = false;
        }
    }

    public void setServletContainerInitializerInterestList(
            Iterable<ServletContainerInitializer> initializers)
{
        servletContainerInitializers = initializers;
    }

    /**
     * Creates a classloader for this context.
     */
    public void createLoader() {
        ClassLoader parent = null;
        if (getPrivileged()) {
            if (log.isLoggable(Level.FINE)) {
                log.fine("Configuring privileged default Loader");
            }
            parent = this.getClass().getClassLoader();
        } else {
            if (log.isLoggable(Level.FINE)) {
                log.fine("Configuring non-privileged default Loader");
            }
            parent = getParentClassLoader();
        }
        WebappLoader webappLoader = new WebappLoader(parent);
        webappLoader.setDelegate(getDelegate());
        webappLoader.setUseMyFaces(useMyFaces);
        setLoader(webappLoader);
    }

    /**
     * Stop this Context component.
     *
     * @exception LifecycleException if a shutdown error occurs
     */
    @Override
    public synchronized void stop() throws LifecycleException {
        stop(false);
    }

    /**
     * Stop this Context component.
     *
     * @param isShutdown true if this Context is being stopped as part
     * of a domain shutdown (as opposed to an undeployment), and false otherwise
     * @exception LifecycleException if a shutdown error occurs
     */
    public synchronized void stop(boolean isShutdown)
            throws LifecycleException {

        // Validate and update our current component state
        if (!started) {
            if(log.isLoggable(Level.INFO))
                log.info(sm.getString("containerBase.notStarted", logName()));
            return;
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);

        // Send j2ee.state.stopping notification
        if (this.getObjectName() != null) {
            Notification notification =
                new Notification("j2ee.state.stopping", this.getObjectName(),
                                sequenceNumber++);
            broadcaster.sendNotification(notification);
        }

        // Mark this application as unavailable while we shut down
        setAvailable(false);

        // Binding thread
        ClassLoader oldCCL = bindThread();

        try {
            // Stop our child containers, if any
            for (Container child : findChildren()) {
                if(child instanceof Lifecycle) {
                    ((Lifecycle)child).stop();
                }
            }

            // Stop our filters
            filterStop();

            // Stop ContainerBackgroundProcessor thread
            super.threadStop();

            if ((manager != null) && (manager instanceof Lifecycle)) {
                if(manager instanceof StandardManager) {
                    ((StandardManager)manager).stop(isShutdown);
                } else {
                    ((Lifecycle)manager).stop();
                }
            }

            /*
             * Stop all ServletContextListeners. It is important that they
             * are passed a ServletContext to their contextDestroyed() method
             * that still has all its attributes set. In other words, it is
             * important that we invoke these listeners before calling
             * context.clearAttributes()
             */
            contextListenerStop();

            sessionListenerStop();

            // Clear all application-originated servlet context attributes
            if (context != null) {
                context.clearAttributes();
            }

            /*
             * Stop all event listeners, including those of type
             * ServletContextAttributeListener. For the latter, it is
             * important that we invoke them after calling
             * context.clearAttributes, so that they receive the corresponding
             * attribute removal events
             */
            eventListenerStop();

            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(STOP_EVENT, null);
            started = false;

            // Stop the Valves in our pipeline (including the basic), if any
            if (pipeline instanceof Lifecycle) {
                ((Lifecycle) pipeline).stop();
            }

            // Finalize our character set mapper
            setCharsetMapper(null);

            // Stop resources
            resourcesStop();
            alternateResourcesStop();

            if ((realm != null) && (realm instanceof Lifecycle)) {
                ((Lifecycle) realm).stop();
            }
            if ((logger != null) && (logger instanceof Lifecycle)) {
                ((Lifecycle) logger).stop();
            }
            /* SJSAS 6347606
            if ((loader != null) && (loader instanceof Lifecycle)) {
                ((Lifecycle) loader).stop();
            }
            */
        } catch(Throwable t) {
            // started was "true" when it first enters the try block.
            // Note that it is set to false after STOP_EVENT is fired.
            // One need to fire STOP_EVENT to clean up naming information
            // if START_EVENT is processed successfully.
            if (started) {
                lifecycle.fireLifecycleEvent(STOP_EVENT, null);
            }

            if (t instanceof RuntimeException) {
                throw (RuntimeException)t;
            } else if (t instanceof LifecycleException) {
                throw (LifecycleException)t;
            } else {
                throw new LifecycleException(t);
            }
        } finally {

            // Unbinding thread
            unbindThread(oldCCL);

            // START SJSAS 6347606
            /*
             * Delay the stopping of the webapp classloader until this point,
             * because unbindThread() calls the security-checked
             * Thread.setContextClassLoader(), which may ask the current thread
             * context classloader (i.e., the webapp classloader) to load
             * Principal classes specified in the security policy file
             */
            if ((loader != null) && (loader instanceof Lifecycle)) {
                ((Lifecycle) loader).stop();
            }
            // END SJSAS 6347606
        }

        // Send j2ee.state.stopped notification
        if (this.getObjectName() != null) {
            Notification notification =
                new Notification("j2ee.state.stopped", this.getObjectName(),
                                sequenceNumber++);
            broadcaster.sendNotification(notification);
        }

        // Reset application context
        context = null;

        // This object will no longer be visible or used.
        try {
            resetContext();
        } catch( Exception ex ) {
            log.log(Level.SEVERE, sm.getString("standardContext.reset", this),
                    ex);
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);

        if (log.isLoggable(Level.FINE))
            log.fine("Stopping complete");

    }

    /**
     * Destroys this context by cleaning it up completely.
     *
     * The problem is that undoing all the config in start() and restoring
     * a 'fresh' state is impossible. After stop()/destroy()/init()/start()
     * we should have the same state as if a fresh start was done - i.e
     * read modified web.xml, etc. This can only be done by completely
     * removing the context object and remapping a new one, or by cleaning
     * up everything.
     *
     * XXX  Should this be done in stop() ?
     */
    @Override
    public void destroy() throws Exception {
        if(oname != null) {
            // Send j2ee.object.deleted notification
            Notification notification =
                new Notification("j2ee.object.deleted", this.getObjectName(),
                                sequenceNumber++);
            broadcaster.sendNotification(notification);
        }
        super.destroy();

        // START SJASAS 6359401
        // super.destroy() will stop session manager and cause it to unload
        // all its active sessions into a file. Delete this file, because this
        // context is being destroyed and must not leave any traces.
        if (getManager() instanceof ManagerBase) {
            ((ManagerBase)getManager()).release();
        }
        // END SJSAS 6359401

        instanceListeners.clear();
        instanceListenerInstances.clear();
    }

    private void resetContext() throws Exception, MBeanRegistrationException {
        // Restore the original state ( pre reading web.xml in start )
        // If you extend this - override this method and make sure to clean up
        children=new HashMap<String, Container>();
        startupTime = 0;
        startTimeMillis = 0;
        tldScanTime = 0;

        // Bugzilla 32867
        distributable = false;

        eventListeners.clear();
        contextListeners.clear();
        sessionListeners.clear();

        if (log.isLoggable(Level.FINE)) {
            log.fine("resetContext " + oname + " " + mserver);
        }
    }

    /**
     * Return a String representation of this component.
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        if (getParent() != null) {
            sb.append(getParent().toString());
            sb.append(".");
        }
        sb.append("StandardContext[");
        sb.append(getName());
        sb.append("]");
        return (sb.toString());

    }

    /**
     * Execute a periodic task, such as reloading, etc. This method will be
     * invoked inside the classloading context of this container. Unexpected
     * throwables will be caught and logged.
     */
    @Override
    public void backgroundProcess() {

        if (!started)
            return;

        count = (count + 1) % managerChecksFrequency;

        if ((getManager() != null) && (count == 0)) {
            if (getManager() instanceof StandardManager) {
                ((StandardManager) getManager()).processExpires();
            } else if (getManager() instanceof PersistentManagerBase) {
                PersistentManagerBase pManager =
                    (PersistentManagerBase) getManager();
                pManager.backgroundProcess();
            }
        }

        // START S1AS8PE 4965017
        if (isReload()) {
            if (getLoader() != null) {
                if (reloadable && (getLoader().modified())) {
                    try {
                        Thread.currentThread().setContextClassLoader
                            (standardContextClassLoader);
                        reload();
                    } finally {
                        if (getLoader() != null) {
                            Thread.currentThread().setContextClassLoader
                                (getClassLoader());
                        }
                    }
                }
                if (getLoader() instanceof WebappLoader) {
                    ((WebappLoader) getLoader()).closeJARs(false);
                }
            }
        }
        // END S1AS8PE 4965017
    }


    // ------------------------------------------------------ Protected Methods

    /**
     * Adjust the URL pattern to begin with a leading slash, if appropriate
     * (i.e. we are running a servlet 2.2 application).  Otherwise, return
     * the specified URL pattern unchanged.
     *
     * @param urlPattern The URL pattern to be adjusted (if needed)
     *  and returned
     */
    protected String adjustURLPattern(String urlPattern) {

        if (urlPattern == null)
            return (urlPattern);
        if (urlPattern.startsWith("/") || urlPattern.startsWith("*."))
            return (urlPattern);
        if (!isServlet22())
            return (urlPattern);
        if (log.isLoggable(Level.FINE)) {
            log.fine(sm.getString("standardContext.urlPattern.patternWarning",
                                  urlPattern));
        }
        return ("/" + urlPattern);

    }

    /**
     * Are we processing a version 2.2 deployment descriptor?
     */
    protected boolean isServlet22() {
        return publicId != null && publicId.equals(
            org.apache.catalina.startup.Constants.WebDtdPublicId_22);
    }

    /**
     * Return a File object representing the base directory for the
     * entire servlet container (i.e. the Engine container if present).
     */
    protected File engineBase() {
        String base=System.getProperty("catalina.base");
        if( base == null ) {
            StandardEngine eng=(StandardEngine)this.getParent().getParent();
            base=eng.getBaseDir();
        }
        return (new File(base));
    }


    // -------------------------------------------------------- Private Methods


    /**
     * Bind current thread, both for CL purposes and for JNDI ENC support
     * during : startup, shutdown and realoading of the context.
     *
     * @return the previous context class loader
     */
    private ClassLoader bindThread() {
        ClassLoader oldContextClassLoader =
            Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(getClassLoader());
        if (isUseNaming()) {
            try {
                ContextBindings.bindThread(this, this);
            } catch (Throwable e) {
                log.log(Level.WARNING, "Error during bindThread", e);
            }
        }

        return oldContextClassLoader;

    }

    /**
     * Unbind thread.
     */
    private void unbindThread(ClassLoader oldContextClassLoader) {
        Thread.currentThread().setContextClassLoader(oldContextClassLoader);
        if (isUseNaming()) {
            ContextBindings.unbindThread(this, this);
        }
    }

    /**
     * Get base path.
     */
    private String getBasePath(String docBase) {
        String basePath = null;
        Container container = this;
        while (container != null) {
            if (container instanceof Host)
                break;
            container = container.getParent();
        }
        File file = new File(docBase);
        if (!file.isAbsolute()) {
            if (container == null) {
                basePath = (new File(engineBase(), docBase)).getPath();
            } else {
                // Use the "appBase" property of this container
                String appBase = ((Host) container).getAppBase();
                file = new File(appBase);
                if (!file.isAbsolute())
                    file = new File(engineBase(), appBase);
                basePath = (new File(file, docBase)).getPath();
            }
        } else {
            basePath = file.getPath();
        }
        return basePath;
    }

    /**
     * Get app base.
     */
    private String getAppBase() {
        String appBase = null;
        Container container = this;
        while (container != null) {
            if (container instanceof Host)
                break;
            container = container.getParent();
        }
        if (container != null) {
            appBase = ((Host) container).getAppBase();
        }
        return appBase;
    }

    /**
     * Get config base.
     */
    private File getConfigBase() {
        File configBase =
            new File(System.getProperty("catalina.base"), "conf");
        if (!configBase.exists()) {
            return null;
        }
        Container container = this;
        Container host = null;
        Container engine = null;
        while (container != null) {
            if (container instanceof Host)
                host = container;
            if (container instanceof Engine)
                engine = container;
            container = container.getParent();
        }
        if (engine != null) {
            configBase = new File(configBase, engine.getName());
        }
        if (host != null) {
            configBase = new File(configBase, host.getName());
        }
        configBase.mkdirs();
        return configBase;
    }

    /**
     * Given a context path, get the config file name.
     */
    protected String getDefaultConfigFile() {
        String basename = null;
        String path = getPath();
        if ("".equals(path)) {
            basename = "ROOT";
        } else {
            basename = path.substring(1).replace('/', '_');
        }
        return (basename + ".xml");
    }

    /**
     * Copy a file.
     */
    private boolean copy(File src, File dest) {
        FileInputStream is = null;
        FileOutputStream os = null;
        try {
            is = new FileInputStream(src);
            os = new FileOutputStream(dest);
            byte[] buf = new byte[4096];
            while (true) {
                int len = is.read(buf);
                if (len < 0)
                    break;
                os.write(buf, 0, len);
            }
            is.close();
            os.close();
        } catch (IOException e) {
            return false;
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (Exception e) {
                // Ignore
            }
            try {
                if (os != null) {
                    os.close();
                }
            } catch (Exception e) {
                // Ignore
            }
        }
        return true;
    }


    /**
     * Get naming context full name.
     */
    public String getNamingContextName() {
        if (namingContextName == null) {
            Container parent = getParent();
            if (parent == null) {
                namingContextName = getName();
            } else {
                Stack<String> stk = new Stack<String>();
                StringBuilder buff = new StringBuilder();
                while (parent != null) {
                    stk.push(parent.getName());
                    parent = parent.getParent();
                }
                while (!stk.empty()) {
                    buff.append("/").append(stk.pop());
                }
                buff.append(getName());
                namingContextName = buff.toString();
            }
            // START RIMOD 4868393
            // append an id to make the name unique to the instance.
            namingContextName += instanceIDCounter++;
            // END RIMOD 4868393
        }
        return namingContextName;
    }

    /**
     * @return the request processing paused flag for this Context
     */
    public boolean getPaused() {
        return paused;
    }

    /**
     * Stores the resources of this application as ServletContext
     * attributes.
     */
    private void postResources() {
        getServletContext().setAttribute(
            Globals.RESOURCES_ATTR, getResources());
        context.setAttributeReadOnly(Globals.RESOURCES_ATTR);
        getServletContext().setAttribute(
            Globals.ALTERNATE_RESOURCES_ATTR, getAlternateDocBases());
        context.setAttributeReadOnly(Globals.ALTERNATE_RESOURCES_ATTR);
    }

    public String getHostname() {
        Container parentHost = getParent();
        if (parentHost != null) {
            hostName = parentHost.getName();
        }
        if ((hostName == null) || (hostName.length() < 1))
            hostName = "_";
        return hostName;
    }

    /**
     * Set the appropriate context attribute for our work directory.
     */
    private void postWorkDirectory() {

        // Acquire (or calculate) the work directory path
        String workDir = getWorkDir();
        if (workDir == null || workDir.length() == 0) {

            // Retrieve our parent (normally a host) name
            String hostName = null;
            String engineName = null;
            String hostWorkDir = null;
            Container parentHost = getParent();
            if (parentHost != null) {
                hostName = parentHost.getName();
                if (parentHost instanceof StandardHost) {
                    hostWorkDir = ((StandardHost)parentHost).getWorkDir();
                }
                Container parentEngine = parentHost.getParent();
                if (parentEngine != null) {
                   engineName = parentEngine.getName();
                }
            }
            if ((hostName == null) || (hostName.length() < 1))
                hostName = "_";
            if ((engineName == null) || (engineName.length() < 1))
                engineName = "_";

            String temp = getPath();
            if (temp.startsWith("/"))
                temp = temp.substring(1);
            temp = temp.replace('/', '_');
            temp = temp.replace('\\', '_');
            if (temp.length() < 1)
                temp = "_";
            if (hostWorkDir != null ) {
                workDir = hostWorkDir + File.separator + temp;
            } else {
                workDir = "work" + File.separator + engineName +
                    File.separator + hostName + File.separator + temp;
            }
            setWorkDir(workDir);
        }

        // Create this directory if necessary
        File dir = new File(workDir);
        if (!dir.isAbsolute()) {
            File catalinaHome = engineBase();
            String catalinaHomePath = null;
            try {
                catalinaHomePath = catalinaHome.getCanonicalPath();
                dir = new File(catalinaHomePath, workDir);
            } catch (IOException e) {
            }
        }
        dir.mkdirs();

        // Set the appropriate servlet context attribute
        getServletContext().setAttribute(ServletContext.TEMPDIR, dir);
        context.setAttributeReadOnly(ServletContext.TEMPDIR);

    }

    /**
     * Set the request processing paused flag for this Context.
     *
     * @param paused The new request processing paused flag
     */
    private void setPaused(boolean paused) {
        this.paused = paused;
    }

    /**
     * Validate the syntax of a proposed <code>&lt;url-pattern&gt;</code>
     * for conformance with specification requirements.
     *
     * @param urlPattern URL pattern to be validated
     */
    protected boolean validateURLPattern(String urlPattern) {
        if (urlPattern == null) {
            return false;
        }
        if (urlPattern.isEmpty()) {
            return true;
        }
        if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) {
            log.warning(sm.getString("standardContext.crlfinurl", urlPattern));
            return false;
        }
        if (urlPattern.startsWith("*.")) {
            if (urlPattern.indexOf('/') < 0) {
                checkUnusualURLPattern(urlPattern);
                return true;
            } else
                return false;
        }
        if ( (urlPattern.startsWith("/")) &&
                (!urlPattern.contains("*."))) {
            checkUnusualURLPattern(urlPattern);
            return true;
        } else
            return false;

    }


    /**
     * Check for unusual but valid <code>&lt;url-pattern&gt;</code>s.
     * See Bugzilla 34805, 43079 &amp; 43080
     */
    private void checkUnusualURLPattern(String urlPattern) {
        if (log.isLoggable(Level.INFO)) {
            if(urlPattern.endsWith("*") && (urlPattern.length() < 2 ||
                    urlPattern.charAt(urlPattern.length()-2) != '/')) {
                log.info("Suspicious url pattern: \"" + urlPattern + "\"" +
                        " in context [" + getName() + "] - see" +
                        " section SRV.11.2 of the Servlet specification" );
            }
        }
    }


    // -------------------- JMX methods  --------------------

    /**
     * Return the MBean Names of the set of defined environment entries for
     * this web application
     */
    public String[] getEnvironments() {
        ContextEnvironment[] envs = getNamingResources().findEnvironments();
        List<String> results = new ArrayList<String>();
        for(ContextEnvironment env : envs) {
            try {
                ObjectName oname =
                    MBeanUtils.createObjectName(this.getEngineName(), env);
                results.add(oname.toString());
            } catch(MalformedObjectNameException e) {
                IllegalArgumentException iae = new IllegalArgumentException
                    ("Cannot create object name for environment " + env);
                iae.initCause(e);
                throw iae;
            }
        }
        return results.toArray(new String[results.size()]);

    }


    /**
     * Return the MBean Names of all the defined resource references for this
     * application.
     */
    public String[] getResourceNames() {

        ContextResource[] resources = getNamingResources().findResources();
        List<String> results = new ArrayList<String>();
        for(ContextResource resource : resources) {
            try {
                ObjectName oname =
                    MBeanUtils.createObjectName(this.getEngineName(), resource);
                results.add(oname.toString());
            } catch(MalformedObjectNameException e) {
                IllegalArgumentException iae = new IllegalArgumentException
                    ("Cannot create object name for resource " + resource);
                iae.initCause(e);
                throw iae;
            }
        }
        return results.toArray(new String[results.size()]);

    }

    /**
     * Return the MBean Names of all the defined resource links for this
     * application
     */
    public String[] getResourceLinks() {

        ContextResourceLink[] links = getNamingResources().findResourceLinks();
        List<String> results = new ArrayList<String>();
        for(ContextResourceLink link : links) {
            try {
                ObjectName oname =
                    MBeanUtils.createObjectName(this.getEngineName(), link);
                results.add(oname.toString());
            } catch(MalformedObjectNameException e) {
                IllegalArgumentException iae = new IllegalArgumentException
                    ("Cannot create object name for resource " + link);
                iae.initCause(e);
                throw iae;
            }
        }
        return results.toArray(new String[results.size()]);

    }

    // ------------------------------------------------------------- Operations


    /**
     * Add an environment entry for this web application.
     *
     * @param envName New environment entry name
     */
    public String addEnvironment(String envName, String type)
        throws MalformedObjectNameException {

        NamingResources nresources = getNamingResources();
        if (nresources == null) {
            return null;
        }
        ContextEnvironment env = nresources.findEnvironment(envName);
        if (env != null) {
            throw new IllegalArgumentException
                ("Invalid environment name - already exists '" + envName + "'");
        }
        env = new ContextEnvironment();
        env.setName(envName);
        env.setType(type);
        nresources.addEnvironment(env);

        // Return the corresponding MBean name
        ManagedBean managed = Registry.getRegistry(null, null).findManagedBean("ContextEnvironment");
        ObjectName oname =
            MBeanUtils.createObjectName(managed.getDomain(), env);
        return (oname.toString());

    }


    /**
     * Add a resource reference for this web application.
     *
     * @param resourceName New resource reference name
     */
    public String addResource(String resourceName, String type)
        throws MalformedObjectNameException {

        NamingResources nresources = getNamingResources();
        if (nresources == null) {
            return null;
        }
        ContextResource resource = nresources.findResource(resourceName);
        if (resource != null) {
            throw new IllegalArgumentException
                ("Invalid resource name - already exists'" + resourceName + "'");
        }
        resource = new ContextResource();
        resource.setName(resourceName);
        resource.setType(type);
        nresources.addResource(resource);

        // Return the corresponding MBean name
        ManagedBean managed = Registry.getRegistry(null, null).findManagedBean("ContextResource");
        ObjectName oname =
            MBeanUtils.createObjectName(managed.getDomain(), resource);
        return (oname.toString());
    }

    /**
     * Add a resource link for this web application.
     *
     * @param resourceLinkName New resource link name
     */
    public String addResourceLink(String resourceLinkName, String global,
                String name, String type) throws MalformedObjectNameException {

        NamingResources nresources = getNamingResources();
        if (nresources == null) {
            return null;
        }
        ContextResourceLink resourceLink =
                                nresources.findResourceLink(resourceLinkName);
        if (resourceLink != null) {
            throw new IllegalArgumentException
                ("Invalid resource link name - already exists'" +
                                                        resourceLinkName + "'");
        }
        resourceLink = new ContextResourceLink();
        resourceLink.setGlobal(global);
        resourceLink.setName(resourceLinkName);
        resourceLink.setType(type);
        nresources.addResourceLink(resourceLink);

        // Return the corresponding MBean name
        ManagedBean managed = Registry.getRegistry(null, null).findManagedBean("ContextResourceLink");
        ObjectName oname =
            MBeanUtils.createObjectName(managed.getDomain(), resourceLink);
        return (oname.toString());
    }

    @Override
    public ObjectName createObjectName(String hostDomain, ObjectName parentName)
            throws MalformedObjectNameException
    {
        String onameStr;
        StandardHost hst=(StandardHost)getParent();

        String hostName=getParent().getName();
        String name= "//" + ((hostName==null)? "DEFAULT" : hostName) +
                (("".equals(encodedPath)) ? "/" : encodedPath);

        String suffix=",J2EEApplication=" +
                getJ2EEApplication() + ",J2EEServer=" +
                getJ2EEServer();

        onameStr="j2eeType=WebModule,name=" + name + suffix;
        if( log.isLoggable(Level.FINE))
            log.fine("Registering " + onameStr + " for " + oname);

        // default case - no domain explictely set.
        if( getDomain() == null ) domain=hst.getDomain();
        return new ObjectName(getDomain() + ":" + onameStr);
    }

    public void updateObjectName() {
        try {
            StandardHost host = (StandardHost) getParent();
            oname = createObjectName(host.getDomain(), host.getJmxName());
            controller = oname;
            for (Container wrapper : findChildren()) {
                ((StandardWrapper)wrapper).registerJMX(this);
            }
        } catch(Exception ex) {
            if (log.isLoggable(Level.INFO)) {
                log.log(Level.INFO,
                        "Error updating ctx with jmx " + this + " " +
                        oname + " " + ex.toString(),
                        ex );
            }
        }
    }

    private void preRegisterJMX() {
        try {
            StandardHost host = (StandardHost) getParent();
            if ((oname == null)
                    || (oname.getKeyProperty("j2eeType") == null)) {
                oname = createObjectName(host.getDomain(), host.getJmxName());
                controller = oname;
            }
        } catch(Exception ex) {
            if (log.isLoggable(Level.INFO)) {
                log.log(Level.INFO,
                        "Error registering ctx with jmx " + this + " " +
                        oname + " " + ex.toString(),
                        ex );
            }
        }
    }

    private void registerJMX() {
        try {
            if (log.isLoggable(Level.FINE)) {
                log.fine("Checking for " + oname );
            }
            if(! Registry.getRegistry(null, null).getMBeanServer().isRegistered(oname)) {
                controller = oname;
                Registry.getRegistry(null, null).registerComponent(
                    this, oname, null);

                // Send j2ee.object.created notification
                if (this.getObjectName() != null) {
                    Notification notification = new Notification(
                        "j2ee.object.created", this.getObjectName(),
                        sequenceNumber++);
                    broadcaster.sendNotification(notification);
                }
            }
            for (Container child : findChildren()) {
                ((StandardWrapper)child).registerJMX( this );
            }
        } catch (Exception ex) {
            log.log(Level.INFO,
                    "Error registering wrapper with jmx " + this + " " +
                    oname + " " + ex.toString(),
                    ex );
        }
    }

    /**
     * There are 2 cases:
     *
     *   1. The context is created and registered by internal APIs
     *   2. The context is created by JMX, and it'll self-register.
     *
     * @param server
     * @param name
     *
     * @return the ObjectName that was used for registration
     *
     * @throws Exception
     */
    @Override
    public ObjectName preRegister(MBeanServer server,
                                  ObjectName name)
            throws Exception
    {
        if( oname != null ) {
            //log.info( "Already registered " + oname + " " + name);
            // Temporary - /admin uses the old names
            return name;
        }
        ObjectName result=super.preRegister(server,name);
        return name;
    }

    @Override
    public void preDeregister() throws Exception {
        if( started ) {
            try {
                stop();
            } catch( Exception ex ) {
                log.log(Level.SEVERE,
                        sm.getString("standardContext.stoppingContext", this),
                        ex);
            }
        }
    }

    @Override
    public void init() throws Exception {

        if( this.getParent() == null ) {
            ObjectName parentName=getParentName();

            if( ! mserver.isRegistered(parentName)) {
                if (log.isLoggable(Level.FINE)) {
                    log.fine("No host, creating one " + parentName);
                }
                StandardHost host=new StandardHost();
                host.setName(hostName);
                Registry.getRegistry(null, null).registerComponent(
                    host, parentName, null);
                mserver.invoke(parentName, "init", new Object[] {}, new String[] {} );
            }
            ContextConfig config = new ContextConfig();
            this.addLifecycleListener(config);

            if (log.isLoggable(Level.FINE)) {
                log.fine( "AddChild " + parentName + " " + this);
            }
            try {
                mserver.invoke(parentName, "addChild", new Object[] { this },
                               new String[] {"org.apache.catalina.Container"});
            } catch (Exception e) {
                destroy();
                throw e;
            }
        }

        // It's possible that addChild may have started us
        if( initialized ) {
            return;
        }

        super.init();

        // START GlassFish 2439
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(INIT_EVENT, null);
        // END GlassFish 2439

        // Send j2ee.state.starting notification
        if (this.getObjectName() != null) {
            Notification notification = new Notification("j2ee.state.starting",
                this.getObjectName(), sequenceNumber++);
            broadcaster.sendNotification(notification);
        }

    }

    @Override
    public ObjectName getParentName() throws MalformedObjectNameException {
        // "Life" update
        String path=oname.getKeyProperty("name");
        if( path == null ) {
            log.severe(sm.getString(
                "standardContext.missingNameAttributeInName", getName()));
            return null;
        }
        if( ! path.startsWith( "//")) {
            log.severe(sm.getString("standardContext.malformedName",
                                    getName()));
        }
        path=path.substring(2);
        int delim=path.indexOf( "/" );
        hostName="localhost"; // Should be default...
        if( delim > 0 ) {
            hostName=path.substring(0, delim);
            path = path.substring(delim);
            if ("/".equals(path)) {
                this.setName("");
            } else {
                this.setName(path);
            }
        } else {
            if (log.isLoggable(Level.FINE)) {
                log.fine("Setting path " +  path );
            }
            this.setName( path );
        }
        // XXX  The service and domain should be the same.
        String parentDomain=getEngineName();
        if( parentDomain == null ) parentDomain=domain;
        return new ObjectName( parentDomain + ":" +
                "type=Host,host=" + hostName);
    }

    public void create() throws Exception{
        init();
    }
   
    // ------------------------------------------------- ServletContext Methods
           
    /**
     * Return the value of the specified context attribute, if any;
     * otherwise return <code>null</code>.
     */
    public Object getAttribute(String name) {
        return context.getAttribute(name);
    }
   
    /**
     * Return an enumeration of the names of the context attributes
     * associated with this context.
     */
    public Enumeration<String> getAttributeNames() {
        return context.getAttributeNames();
    }     
       
    /**
     * Returns the context path of the web application.
     */
    public String getContextPath() {
        return getPath();
    }

    /**
     * Return a <code>ServletContext</code> object that corresponds to a
     * specified URI on the server. 
     */
    public ServletContext getContext(String uri) {      
       
        // Validate the format of the specified argument
        if ((uri == null) || (!uri.startsWith("/"))) {
            return (null);
        }

        Context child = null;
        try {
            Host host = (Host) getParent();
            String mapuri = uri;
            while (true) {
                child = (Context) host.findChild(mapuri);
                if (child != null)
                    break;
                int slash = mapuri.lastIndexOf('/');
                if (slash < 0)
                    break;
                mapuri = mapuri.substring(0, slash);
            }
        } catch (Throwable t) {
            return (null);
        }

        if (child == null) {
            return (null);
        }

        if (getCrossContext()) {
            // If crossContext is enabled, can always return the context
            return child.getServletContext();
        } else if (child == this) {
            // Can still return the current context
            return getServletContext();
        } else {
            // Nothing to return
            return (null);
        }
    }
   
    /**
     * Return the value of the specified initialization parameter, or
     * <code>null</code> if this parameter does not exist.
     */
    public String getInitParameter(final String name) {
        return context.getInitParameter(name);
    }

    /**
     * Return the names of the context's initialization parameters, or an
     * empty enumeration if the context has no initialization parameters.
     */
    public Enumeration<String> getInitParameterNames() {
        return context.getInitParameterNames();
    }
   
    /**
     * @return true if the context initialization parameter with the given
     * name and value was set successfully on this ServletContext, and false
     * if it was not set because this ServletContext already contains a
     * context initialization parameter with a matching name
     */
    public boolean setInitParameter(String name, String value) {
        if (isContextInitializedCalled) {
            throw new IllegalStateException(
                sm.getString("applicationContext.alreadyInitialized",
                             "setInitParameter", getName()));
        }
        return context.setInitParameter(name, value);
    }   
       
    /**
     * Return the major version of the Java Servlet API that we implement.
     */
    public int getMajorVersion() {
        return context.getMajorVersion();
    }

    /**
     * Return the minor version of the Java Servlet API that we implement.
     */
    public int getMinorVersion() {
        return context.getMinorVersion();
    }
       
    /**
     * Return the MIME type of the specified file, or <code>null</code> if
     * the MIME type cannot be determined.
     */
    public String getMimeType(String file) {
       
        if (file == null)
            return (null);
        int period = file.lastIndexOf(".");
        if (period < 0)
            return (null);
        String extension = file.substring(period + 1);
        if (extension.length() < 1)
            return (null);
        return (findMimeMapping(extension));
       
    }
       
    /**
     * Return a <code>RequestDispatcher</code> object that acts as a
     * wrapper for the named servlet.
     */
    public RequestDispatcher getNamedDispatcher(String name) {
       
        // Validate the name argument
        if (name == null)
            return (null);

        // Create and return a corresponding request dispatcher
        Wrapper wrapper = (Wrapper) findChild(name);
        if (wrapper == null)
            return (null);
       
        return new ApplicationDispatcher(wrapper, null, null, null, null, name);
       
    }
   
    /**
     * Return the display name of this web application.
     */
    public String getServletContextName() {
        return getDisplayName();
    }
       
    /**
     * Remove the context attribute with the specified name, if any.
     */
    public void removeAttribute(String name) {
        context.removeAttribute(name);
    }
           
    /**
     * Bind the specified value with the specified context attribute name,
     * replacing any existing value for that name.
     */
    public void setAttribute(String name, Object value) {
        context.setAttribute(name, value);
    }
       
    /**
     * Return the name and version of the servlet container.
     */
    public String getServerInfo() {
        return context.getServerInfo();
    }
       
    /**
     * Return the real path corresponding to the given virtual path, or
     * <code>null</code> if the container was unable to perform the
     * translation
     */
    public String getRealPath(String path) {
        if (!isFilesystemBased())
            return null;

        if (path == null) {
            return null;
        }

        File file = null;
        if (alternateDocBases == null
                || alternateDocBases.size() == 0) {
            file = new File(getBasePath(getDocBase()), path);
        } else {
            AlternateDocBase match = AlternateDocBase.findMatch(
                                                path, alternateDocBases);
            if (match != null) {
                file = new File(match.getBasePath(), path);
            } else {
                // None of the url patterns for alternate doc bases matched
                file = new File(getBasePath(getDocBase()), path);
            }
        }

        if (!file.exists()) {
            try {
                // Try looking up resource in
                // WEB-INF/lib/[*.jar]/META-INF/resources
                URL u = getMetaInfResource(path);
                return (u != null ? u.getPath() : file.getAbsolutePath());
            } catch (Exception e) {
                return null;
            }
        } else {
            return file.getAbsolutePath();
        }
    }   
   
    /**
     * Writes the specified message to a servlet log file.
     */
    public void log(String message) {
        org.apache.catalina.Logger logger = getLogger();
        if (logger != null) {
            /* PWC 6403328
            logger.log(context.logName() + message, Logger.INFORMATION);
            */
            //START PWC 6403328
            logger.log(logPrefix + message, org.apache.catalina.Logger.INFORMATION);
            //END PWC 6403328
        }
    }
   
    /**
     * Writes the specified exception and message to a servlet log file.
     */
    public void log(Exception exception, String message) {    
        org.apache.catalina.Logger logger = getLogger();
        if (logger != null)
            logger.log(exception, logName() + message);
    }      
       
    /**
     * Writes the specified message and exception to a servlet log file.
     */
    public void log(String message, Throwable throwable) {
        org.apache.catalina.Logger logger = getLogger();
        if (logger != null)
            logger.log(logName() + message, throwable);
    }
       
    public Servlet getServlet(String name) {
        return context.getServlet(name);
    }
   
    public Enumeration<String> getServletNames() {
        return context.getServletNames();
    }           
       
    public Enumeration<Servlet> getServlets() {
        return context.getServlets();
    }
       
    /**
     * Return the requested resource as an <code>InputStream</code>.  The
     * path must be specified according to the rules described under
     * <code>getResource</code>.  If no such resource can be identified,
     * return <code>null</code>.
     */
    public InputStream getResourceAsStream(String path) {

        if (path == null || !path.startsWith("/"))
            return (null);

        path = RequestUtil.normalize(path);
        if (path == null)
            return (null);

        DirContext resources = null;

        if (alternateDocBases == null
                || alternateDocBases.size() == 0) {
            resources = getResources();
        } else {
            AlternateDocBase match = AlternateDocBase.findMatch(
                                path, alternateDocBases);
            if (match != null) {
                resources = match.getResources();
            } else {
                // None of the url patterns for alternate doc bases matched
                resources = getResources();
            }
        }

        if (resources != null) {
            try {
                Object resource = resources.lookup(path);
                if (resource instanceof Resource)
                    return (((Resource) resource).streamContent());
            } catch (Exception e) {
                try {
                    // Try looking up resource in
                    // WEB-INF/lib/[*.jar]/META-INF/resources
                    URL u = getMetaInfResource(path);
                    return (u != null ? u.openStream() : null);
                } catch (Exception ee) {
                    // do nothing
                }
            }
        }
        return (null);
    }
       
    /**
     * Return the URL to the resource that is mapped to a specified path.
     * The path must begin with a "/" and is interpreted as relative to the
     * current context root.
     */
    public java.net.URL getResource(String path)
        throws MalformedURLException {

        if (path == null || !path.startsWith("/")) {
            throw new MalformedURLException(
                sm.getString("applicationContext.resourcePaths.iae",
                             path));
        }
       
        path = RequestUtil.normalize(path);
        if (path == null)
            return (null);

        String libPath = "/WEB-INF/lib/";
        if ((path.startsWith(libPath)) && (path.endsWith(".jar"))) {
            File jarFile = null;
            if (isFilesystemBased()) {
                jarFile = new File(getBasePath(docBase), path);
            } else {
                jarFile = new File(getWorkPath(), path);
            }
            if (jarFile.exists()) {
                return jarFile.toURL();
            } else {
                return null;
            }

        } else {

            DirContext resources = null;
            if (alternateDocBases == null
                    || alternateDocBases.size() == 0) {
                resources = context.getResources();
            } else {
                AlternateDocBase match = AlternateDocBase.findMatch(
                                                path, alternateDocBases);
                if (match != null) {
                    resources = match.getResources();
                } else {
                    // None of the url patterns for alternate doc bases matched
                    resources = getResources();
                }
            }

            if (resources != null) {
                String fullPath = getName() + path;
                String hostName = getParent().getName();
                try {
                    resources.lookup(path);
                    return new java.net.URL
                        /* SJSAS 6318494
                        ("jndi", null, 0, getJNDIUri(hostName, fullPath),
                         */
                        // START SJAS 6318494
                        ("jndi", "", 0, getJNDIUri(hostName, fullPath),
                        // END SJSAS 6318494
             new DirContextURLStreamHandler(resources));
                } catch (Exception e) {
                    try {
                        // Try looking up resource in
                        // WEB-INF/lib/[*.jar]/META-INF/resources
                        return getMetaInfResource(path);
                    } catch (Exception ee) {
                        // do nothing
                    }
                }
            }
        }

        return (null);
    }
       
    /**
     * Return a Set containing the resource paths of resources member of the
     * specified collection. Each path will be a String starting with
     * a "/" character. The returned set is immutable.
     */
    public Set<String> getResourcePaths(String path) {
        // Validate the path argument
        if (path == null) {
            return null;
        }
        if (!path.startsWith("/")) {
            throw new IllegalArgumentException
                (sm.getString("applicationContext.resourcePaths.iae", path));
        }

        path = RequestUtil.normalize(path);
        if (path == null)
            return (null);

        DirContext resources = null;

        if (alternateDocBases == null
                || alternateDocBases.size() == 0) {
            resources = getResources();
        } else {
            AlternateDocBase match = AlternateDocBase.findMatch(
                                path, alternateDocBases);
            if (match != null) {
                resources = match.getResources();
            } else {
                // None of the url patterns for alternate doc bases matched
                resources = getResources();
            }
        }

        if (resources != null) {
            return (getResourcePathsInternal(resources, path));
        }

        return (null);
    }   
   
    /**
     * Internal implementation of getResourcesPath() logic.
     *
     * @param resources Directory context to search
     * @param path Collection path
     */
    private Set<String> getResourcePathsInternal(DirContext resources,
                                                 String path) {
        HashSet<String> set = new HashSet<String>();
        try {
            listCollectionPaths(set, resources, path);
        } catch (NamingException e) {
            // Ignore, need to check for resource paths underneath
            // WEB-INF/lib/[*.jar]/META-INF/resources, see next
        }
        try {
            // Trigger expansion of bundled JAR files
            File file = getExtractedMetaInfResourcePath(path);
            if (file != null) {
                File[] children = file.listFiles();
                StringBuilder sb = null;
                for (File child : children) {
                    sb = new StringBuilder(path);
                    if (!path.endsWith("/")) {
                        sb.append("/");
                    }
                    sb.append(child.getName());
                    if (child.isDirectory()) {
                        sb.append("/");
                    }
                    set.add(sb.toString());
                }
            }
        } catch (Exception e) {
            // ignore
        }
        return Collections.unmodifiableSet(set);
    }
        
    /**
     * Return a <code>RequestDispatcher</code> instance that acts as a
     * wrapper for the resource at the given path.  The path must begin
     * with a "/" and is interpreted as relative to the current context root.
     */
    public RequestDispatcher getRequestDispatcher(String path) {
       
        // Validate the path argument
        if (path == null) {
            return null;
        }

        if (!path.startsWith("/") && !path.isEmpty()) {
            throw new IllegalArgumentException(
                sm.getString("applicationContext.requestDispatcher.iae",
                             path));
        }

        // Get query string
        String queryString = null;
        int pos = path.indexOf('?');
        if (pos >= 0) {
            queryString = path.substring(pos + 1);
            path = path.substring(0, pos);
        }

        path = RequestUtil.normalize(path);
        if (path == null)
            return (null);

        pos = path.length();

        // Use the thread local URI and mapping data
        DispatchData dd = dispatchData.get();
        if (dd == null) {
            dd = new DispatchData();
            dispatchData.set(dd);
        }

        MessageBytes uriMB = dd.uriMB;
        uriMB.recycle();

        // Retrieve the thread local mapping data
        MappingData mappingData = dd.mappingData;

        // Map the URI
        CharChunk uriCC = uriMB.getCharChunk();
        try {
            uriCC.append(getPath(), 0, getPath().length());
            /*
             * Ignore any trailing path params (separated by ';') for mapping
             * purposes
             */
            int semicolon = path.indexOf(';');
            if (pos >= 0 && semicolon > pos) {
                semicolon = -1;
            }
            uriCC.append(path, 0, semicolon > 0 ? semicolon : pos);
            getMapper().map(uriMB, mappingData);
            if (mappingData.wrapper == null) {
                return (null);
            }
            /*
             * Append any trailing path params (separated by ';') that were
             * ignored for mapping purposes, so that they're reflected in the
             * RequestDispatcher's requestURI
             */
            if (semicolon > 0) {
                uriCC.append(path, semicolon, pos - semicolon);
            }
        } catch (Exception e) {
            // Should never happen
            log(sm.getString("applicationContext.mapping.error"), e);
            return (null);
        }

        Wrapper wrapper = (Wrapper) mappingData.wrapper;
        String wrapperPath = mappingData.wrapperPath.toString();
        String pathInfo = mappingData.pathInfo.toString();

        mappingData.recycle();
       
        // Construct a RequestDispatcher to process this request
        return new ApplicationDispatcher
            (wrapper, uriCC.toString(), wrapperPath, pathInfo,
             queryString, null);
    }
   
       
    // ------------------------------------------------------------- Attributes


    /**
     * Return the naming resources associated with this web application.
     */
    public DirContext getStaticResources() {
        return getResources();
    }

    /**
     * Return the naming resources associated with this web application.
     * FIXME: Fooling introspection ...
     */
    public DirContext findStaticResources() {
        return getResources();
    }

    /**
     * Return the naming resources associated with this web application.
     */
    public String[] getWelcomeFiles() {
        return findWelcomeFiles();
    }

    /**
     * Set the validation feature of the XML parser used when
     * parsing xml instances.
     * @param webXmlValidation true to enable xml instance validation
     */
    public void setXmlValidation(boolean webXmlValidation){
        this.webXmlValidation = webXmlValidation;
    }

    /**
     * Get the server.xml <context> attribute's xmlValidation.
     * @return true if validation is enabled.
     *
     */
    public boolean getXmlValidation(){
        return webXmlValidation;
    }

    /**
     * Get the server.xml <context> attribute's xmlNamespaceAware.
     * @return true if namespace awarenes is enabled.
     */
    public boolean getXmlNamespaceAware(){
        return webXmlNamespaceAware;
    }

    /**
     * Set the namespace aware feature of the XML parser used when
     * parsing xml instances.
     * @param webXmlNamespaceAware true to enable namespace awareness
     */
    public void setXmlNamespaceAware(boolean webXmlNamespaceAware){
        this.webXmlNamespaceAware= webXmlNamespaceAware;
    }

    /**
     * Set the validation feature of the XML parser used when
     * parsing tlds files.
     * @param tldValidation true to enable xml instance validation
     */
    public void setTldValidation(boolean tldValidation){
        this.tldValidation = tldValidation;
    }

    /**
     * Get the server.xml <context> attribute's webXmlValidation.
     * @return true if validation is enabled.
     *
     */
    public boolean getTldValidation(){
        return tldValidation;
    }

    /**
     * Get the server.xml <host> attribute's xmlNamespaceAware.
     * @return true if namespace awarenes is enabled.
     */
    public boolean getTldNamespaceAware(){
        return tldNamespaceAware;
    }

    /**
     * Set the namespace aware feature of the XML parser used when
     * parsing xml instances.
     * @param tldNamespaceAware true to enable namespace awareness
     */
    public void setTldNamespaceAware(boolean tldNamespaceAware){
        this.tldNamespaceAware= tldNamespaceAware;
    }   
   
    /**
     * Sets the list of ordered libs, which will be used as the value of the
     * ServletContext attribute with name javax.servlet.context.orderedLibs
     */
    public void setOrderedLibs(List<String> orderedLibs) {
        this.orderedLibs = orderedLibs;
    }

    public void startRecursive() throws LifecycleException {
        // nothing to start recursively, the servlets will be started by
        // load-on-startup
        start();
    }

    public int getState() {
        if( started ) {
            return 1; // RUNNING
        }
        if( initialized ) {
            return 0; // starting ?
        }
        if( ! available ) {
            return 4; //FAILED
        }
        // 2 - STOPPING
        return 3; // STOPPED
    }

    boolean isContextInitializedCalled() {
        return isContextInitializedCalled;
    }

    /**
     * Creates an ObjectInputStream that provides special deserialization
     * logic for classes that are normally not serializable (such as
     * javax.naming.Context).
     */
    public ObjectInputStream createObjectInputStream(InputStream is)
            throws IOException {

        ObjectInputStream ois = null;

        Loader loader = getLoader();
        if (loader != null) {
            ClassLoader classLoader = loader.getClassLoader();
            if (classLoader != null) {
                try {
                    ois = new CustomObjectInputStream(is, classLoader);
                } catch (IOException ioe) {
                    log.log(Level.SEVERE,
                            "Unable to create custom ObjectInputStream",
                            ioe);
                }
            }
        }

        if (ois == null) {
            ois = new ObjectInputStream(is);
        }

        return ois;
    }

    /**
     * Creates an ObjectOutputStream that provides special serialization
     * logic for classes that are normally not serializable (such as
     * javax.naming.Context).
     */
    public ObjectOutputStream createObjectOutputStream(OutputStream os)
            throws IOException {
        return new ObjectOutputStream(os);
    }

    /**
     * Gets the time this context was started.
     *
     * @return Time (in milliseconds since January 1, 1970, 00:00:00) when this
     * context was started
     */
    public long getStartTimeMillis() {
        return startTimeMillis;
    }
   
    public boolean isEventProvider() {
        return false;
    }
   
    public boolean isStatisticsProvider() {
        return false;
    }

    /*
     * HTTP session related monitoring events
     */
    public void sessionCreatedEvent(HttpSession session) {
        // Deliberate noop
    }

    public void sessionDestroyedEvent(HttpSession session) {
        // Deliberate noop
    }

    public void sessionRejectedEvent(int maxSessions) {
        // Deliberate noop
    }

    public void sessionExpiredEvent(HttpSession session) {
        // Deliberate noop
    }

    public void sessionPersistedStartEvent(HttpSession session) {
        // Deliberate noop
    }

    public void sessionPersistedEndEvent(HttpSession session) {
        // Deliberate noop
    }

    public void sessionActivatedStartEvent(HttpSession session) {
        // Deliberate noop
    }

    public void sessionActivatedEndEvent(HttpSession session) {
        // Deliberate noop
    }

    public void sessionPassivatedStartEvent(HttpSession session) {
        // Deliberate noop
    }

    public void sessionPassivatedEndEvent(HttpSession session) {
        // Deliberate noop
    }
   
    public static class RestrictedServletContextListener
            implements ServletContextListener {

        /*
         * The ServletContextListener to which to delegate
         */
        private ServletContextListener delegate;

        /**
         * Constructor
         */
        public RestrictedServletContextListener(
                ServletContextListener delegate) {
            this.delegate = delegate;
        }
       
        public void contextInitialized(ServletContextEvent sce) {
            delegate.contextInitialized(sce);
        }

        public void contextDestroyed(ServletContextEvent sce) {
            delegate.contextDestroyed(sce);
        }

        public ServletContextListener getNestedListener() {
            return delegate;
        }
    }

    /**
     * Instantiates the given Servlet class.
     *
     * @return the new Servlet instance
     */
    protected <T extends Servlet> T createServletInstance(Class<T> clazz)
            throws Exception{
        return clazz.newInstance();
    }

    /**
     * Instantiates the given Filter class.
     *
     * @return the new Filter instance
     */
    protected <T extends Filter> T createFilterInstance(Class<T> clazz)
            throws Exception{
        return clazz.newInstance();
    }

    /**
     * Instantiates the given EventListener class.
     *
     * @return the new EventListener instance
     */
    public <T extends EventListener> T createListenerInstance(
                Class<T> clazz) throws Exception{
        return clazz.newInstance();
    }

    /**
     * Custom security manager responsible for enforcing permission
     * check on ServletContext#getClassLoader if necessary.
     */
    private static class MySecurityManager extends SecurityManager {

        /*
         * @return true if the specified class loader <code>cl</code>
         * can be found in the class loader delegation chain of the
         * <code>start</code> class loader, false otherwise
         */
        boolean isAncestor(ClassLoader start, ClassLoader cl) {
            ClassLoader acl = start;
            do {
          acl = acl.getParent();
                if (cl == acl) {
                    return true;
                }
            } while (acl != null);
            return false;
        }

        /*
         * Checks whether access to the webapp class loader associated
         * with this Context should be granted to the caller of
         * ServletContext#getClassLoader.
         *
         * If no security manager exists, this method returns immediately.
         *
         * Otherwise, it calls the security manager's checkPermission
         * method with the getClassLoader permission if the class loader
         * of the caller of ServletContext#getClassLoader is not the same as,
         * or an ancestor of the webapp class loader associated with this
         * Context.
         */
        void checkGetClassLoaderPermission(ClassLoader webappLoader) {
            SecurityManager sm = System.getSecurityManager();
            if (sm == null) {
                return;
            }

            // Get the current execution stack as an array of classes
            Class[] classContext = getClassContext();

            /*
             * Determine the caller of ServletContext#getClassLoader:
             *
             * classContext[0]:
             *   org.apache.catalina.core.StandardContext$MySecurityManager
             * classContext[1]:
             *   org.apache.catalina.core.StandardContext
             * classContext[2]:
             *   org.apache.catalina.core.StandardContext
             * classContext[3]:
             *   org.apache.catalina.core.ApplicationContext
             * classContext[4]:
             *  org.apache.catalina.core.ApplicationContextFacade
             * classContext[5]:
             *  Caller whose classloader to check
             *
             * NOTE: INDEX MUST BE ADJUSTED WHENEVER EXECUTION STACK
             * CHANGES, E.G., DUE TO CODE BEING REORGANIZED
             */
            ClassLoader ccl = classContext[5].getClassLoader();
            if (ccl != null && ccl != webappLoader &&
                    !isAncestor(webappLoader, ccl)) {
                sm.checkPermission(GET_CLASSLOADER_PERMISSION);
            }
        }
    }

    private static class PrivilegedCreateSecurityManager
            implements PrivilegedAction<MySecurityManager> {

        public MySecurityManager run() {
            return new MySecurityManager();
        }
    }

    /**
     * List resource paths (recursively), and store all of them in the given
     * Set.
     */
    private static void listCollectionPaths
        (Set<String> set, DirContext resources, String path)
        throws NamingException {

        Enumeration<Binding> childPaths = resources.listBindings(path);
        while (childPaths.hasMoreElements()) {
            Binding binding = childPaths.nextElement();
            String name = binding.getName();
            StringBuilder childPath = new StringBuilder(path);
            if (!"/".equals(path) && !path.endsWith("/"))
                childPath.append("/");
            childPath.append(name);
            Object object = binding.getObject();
            if (object instanceof DirContext) {
                childPath.append("/");
            }
            set.add(childPath.toString());
        }
    }
   
    /**
     * Get full path, based on the host name and the context path.
     */
    private static String getJNDIUri(String hostName, String path) {
        if (!path.startsWith("/"))
            return "/" + hostName + "/" + path;
        else
            return "/" + hostName + path;
    }
   
    /**
     * Internal class used as thread-local storage when doing path
     * mapping during dispatch.
     */
    private static final class DispatchData {
        public MessageBytes uriMB;
        public MappingData mappingData;

        public DispatchData() {
            uriMB = MessageBytes.newInstance();
            CharChunk uriCC = uriMB.getCharChunk();
            uriCC.setLimit(-1);
            mappingData = new MappingData();
        }
    }

    /**
     * Get resource from META-INF/resources/ in jars.
     */
    private URL getMetaInfResource(String path) {

        path = Globals.META_INF_RESOURCES + path;

        ClassLoader cl = getLoader().getClassLoader();
        if (cl instanceof WebappClassLoader) {
            return ((WebappClassLoader)cl).getResourceFromJars(path);
        }

        // This probably won't happen
        return cl.getResource(path);
    }

    /**
     * Get resource from META-INF/resources/ in jars.
     */
    private File getExtractedMetaInfResourcePath(String path) {
        path = Globals.META_INF_RESOURCES + path;

        ClassLoader cl = getLoader().getClassLoader();
        if (cl instanceof WebappClassLoader) {
            return ((WebappClassLoader)cl).getExtractedResourcePath(path);
        }
       
        return null;
    }
}
TOP

Related Classes of org.apache.catalina.core.StandardContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.