Package com.sun.enterprise.web

Source Code of com.sun.enterprise.web.WebContainer

/*
* 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.
*/

package com.sun.enterprise.web;

import com.sun.appserv.server.util.Version;
import com.sun.common.util.logging.LoggingConfigImpl;
import com.sun.enterprise.config.serverbeans.*;
import com.sun.enterprise.config.serverbeans.Server;
import com.sun.enterprise.config.serverbeans.SessionProperties;
import com.sun.enterprise.container.common.spi.JCDIService;
import com.sun.enterprise.container.common.spi.util.ComponentEnvManager;
import com.sun.enterprise.container.common.spi.util.InjectionManager;
import com.sun.enterprise.container.common.spi.util.JavaEEIOUtils;
import com.sun.enterprise.deployment.WebBundleDescriptor;
import com.sun.enterprise.deployment.WebComponentDescriptor;
import com.sun.enterprise.deployment.archivist.WebArchivist;
import com.sun.enterprise.deployment.runtime.web.ManagerProperties;
import com.sun.enterprise.deployment.runtime.web.SessionManager;
import com.sun.enterprise.deployment.runtime.web.StoreProperties;
import com.sun.enterprise.deployment.runtime.web.*;
import com.sun.enterprise.deployment.util.WebValidatorWithoutCL;
import com.sun.enterprise.security.integration.RealmInitializer;
import com.sun.enterprise.util.Result;
import com.sun.enterprise.util.StringUtils;
import com.sun.enterprise.util.io.FileUtils;
import com.sun.enterprise.v3.services.impl.ContainerMapper;
import com.sun.enterprise.v3.services.impl.GrizzlyService;
import com.sun.enterprise.web.connector.coyote.PECoyoteConnector;
import com.sun.enterprise.web.logger.FileLoggerHandlerFactory;
import com.sun.enterprise.web.logger.IASLogger;
import com.sun.enterprise.web.pluggable.WebContainerFeatureFactory;
import com.sun.enterprise.web.reconfig.WebConfigListener;
import com.sun.grizzly.config.ContextRootInfo;
import com.sun.grizzly.config.dom.NetworkConfig;
import com.sun.grizzly.config.dom.NetworkListener;
import com.sun.grizzly.config.dom.NetworkListeners;
import com.sun.grizzly.util.buf.MessageBytes;
import com.sun.grizzly.util.http.mapper.Mapper;
import com.sun.grizzly.util.http.mapper.MappingData;
import com.sun.hk2.component.ConstructorCreator;
import com.sun.logging.LogDomains;
import org.apache.catalina.*;
import org.apache.catalina.Engine;
import org.apache.catalina.connector.Request;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.ServerInfo;
import org.apache.jasper.runtime.JspFactoryImpl;
import org.apache.jasper.xmlparser.ParserUtils;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.event.EventListener;
import org.glassfish.api.event.EventTypes;
import org.glassfish.api.event.Events;
import org.glassfish.api.invocation.InvocationManager;
import org.glassfish.api.web.TldProvider;
import org.glassfish.embeddable.CommandRunner;
import org.glassfish.internal.api.ClassLoaderHierarchy;
import org.glassfish.internal.api.ServerContext;
import org.glassfish.internal.data.ApplicationRegistry;
import org.glassfish.internal.deployment.Deployment;
import org.glassfish.internal.grizzly.ContextMapper;
import org.glassfish.web.admin.monitor.*;
import org.glassfish.web.valve.GlassFishValve;
import org.jvnet.hk2.annotations.Inject;
import org.jvnet.hk2.annotations.Scoped;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.component.Habitat;
import org.jvnet.hk2.component.PostConstruct;
import org.jvnet.hk2.component.PreDestroy;
import org.jvnet.hk2.component.Singleton;
import org.jvnet.hk2.config.ConfigSupport;
import org.jvnet.hk2.config.ObservableBean;
import org.jvnet.hk2.config.Transactions;
import org.jvnet.hk2.config.types.Property;
import org.xml.sax.EntityResolver;

import javax.imageio.ImageIO;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import javax.servlet.jsp.JspFactory;
import javax.servlet.jsp.tagext.JspTag;
import java.io.File;
import java.io.IOException;
import java.lang.ClassLoader;
import java.net.BindException;
import java.net.MalformedURLException;
import java.text.MessageFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Web container service
*
* @author jluehe
* @author amyroh
* @author swchan2
*/
@SuppressWarnings({"StringContatenationInLoop"})
@Service(name = "com.sun.enterprise.web.WebContainer")
@Scoped(Singleton.class)
public class WebContainer implements org.glassfish.api.container.Container, PostConstruct, PreDestroy, EventListener {

    // -------------------------------------------------- Constants

    public static final String DISPATCHER_MAX_DEPTH = "dispatcher-max-depth";

    static final int DEFAULT_REAP_INTERVAL = 60;   // 1 minute

    public static final String JWS_APPCLIENT_EAR_NAME = "__JWSappclients";
    public static final String JWS_APPCLIENT_WAR_NAME = "sys";
    private static final String JWS_APPCLIENT_MODULE_NAME = JWS_APPCLIENT_EAR_NAME + ":" + JWS_APPCLIENT_WAR_NAME + ".war";

    private static final String DOL_DEPLOYMENT =
            "com.sun.enterprise.web.deployment.backend";

    private static final String MONITORING_NODE_SEPARATOR = "/";
    /**
     * The logger to use for logging ALL web container related messages.
     */
    protected static final Logger _logger = LogDomains.getLogger(
            WebContainer.class, LogDomains.WEB_LOGGER);

    protected static final ResourceBundle rb = _logger.getResourceBundle();

    /**
     * The current <code>WebContainer</code> instance used (single).
     */
    protected static WebContainer webContainer;

    /**
     * Are we using Tomcat deployment backend or DOL?
     */
    protected static boolean useDOLforDeployment = true;

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

    @Inject
    private Domain domain;

    @Inject
    private Habitat habitat;

    @Inject
    ServerContext _serverContext;

    @Inject
    private ApplicationRegistry appRegistry;

    @Inject
    private ComponentEnvManager componentEnvManager;

    @Inject
    Configs configs;

    @Inject(name = ServerEnvironment.DEFAULT_INSTANCE_NAME)
    private Config serverConfig;

    @Inject
    private Transactions transactions;

    @Inject(optional = true)
    private DasConfig dasConfig;

    @Inject
    private Events events;

    @Inject
    private ClassLoaderHierarchy clh;

    @Inject
    private GrizzlyService grizzlyService;

    @Inject
    private LoggingConfigImpl logConfig;

    //@Inject
    //MonitoringService monitoringService;

    @Inject
    private FileLoggerHandlerFactory fileLoggerHandlerFactory;

    @Inject
    private JavaEEIOUtils javaEEIOUtils;

    @Inject(optional = true)
    private JCDIService jcdiService;

    @Inject
    private CommandRunner runner;

    private HashMap<String, WebConnector> connectorMap = new HashMap<String, WebConnector>();

    private EmbeddedWebContainer _embedded;
    private Engine engine;
    private String instanceName;

    private String logLevel = "INFO";


    private WebConnector jkConnector;

    /**
     * Allow disabling accessLog mechanism
     */
    protected boolean globalAccessLoggingEnabled = true;

    /**
     * AccessLog buffer size for storing logs.
     */
    protected String globalAccessLogBufferSize = null;

    /**
     * AccessLog interval before the valve flush its buffer to the disk.
     */
    protected String globalAccessLogWriteInterval = null;

    /**
     * The default-redirect port
     */
    protected int defaultRedirectPort = -1;

    /**
     * <tt>false</tt> when the Grizzly File Cache is enabled. When disabled
     * the Servlet Container temporary Naming cache is used when loading the
     * resources.
     */
    protected boolean catalinaCachingAllowed = true;

    @Inject
    protected ServerEnvironment instance = null;

    // TODO
    //protected WebModulesManager webModulesManager = null;
    //protected AppsManager appsManager = null;

    /**
     * The schema2beans object that represents the root node of server.xml.
     */
    private Server _serverBean = null;

    /**
     * Controls the verbosity of the web container subsystem's debug messages.
     * <p/>
     * This value is non-zero only when the iAS level is one of FINE, FINER
     * or FINEST.
     */
    protected int _debug = 0;

    /**
     * Top-level directory for files generated (compiled JSPs) by
     * standalone web modules.
     */
    private String _modulesWorkRoot = null;

    /**
     * Absolute path for location where all the deployed
     * standalone modules are stored for this Server Instance.
     */
    protected File _modulesRoot = null;

    /**
     * Top-level directory for files generated by application web modules.
     */
    private String _appsWorkRoot = null;

    // START S1AS 6178005
    /**
     * Top-level directory where ejb stubs for applications are stored.
     */
    private String appsStubRoot = null;
    // END S1AS 6178005

    /**
     * Indicates whether dynamic reloading is enabled (as specified by
     * the dynamic-reload-enabled attribute of <applications> in server.xml)
     */
    private boolean _reloadingEnabled = false;

    /**
     * The number of seconds between checks for modified classes (if
     * dynamic reloading is enabled).
     * <p/>
     * This value is specified by the reload-poll-interval attribute of
     * <applications> in server.xml.
     */
    private int _pollInterval = 2;

    /**
     * Has this component been started yet?
     */
    protected boolean _started = false;

    /**
     * The global (at the http-service level) ssoEnabled property.
     */
    protected boolean globalSSOEnabled = true;

    protected volatile WebContainerFeatureFactory webContainerFeatureFactory;

    /**
     * The value of the instance-level session property named "enableCookies"
     */
    boolean instanceEnableCookies = true;

    @Inject
    ServerConfigLookup serverConfigLookup;

    protected JspProbeProvider jspProbeProvider = null;
    protected RequestProbeProvider requestProbeProvider = null;
    protected ServletProbeProvider servletProbeProvider = null;
    protected SessionProbeProvider sessionProbeProvider = null;
    protected WebModuleProbeProvider webModuleProbeProvider = null;

    protected WebConfigListener configListener = null;

    // Indicates whether we are being shut down
    private boolean isShutdown = false;

    private final Object mapperUpdateSync = new Object();

    private SecurityService securityService = null;

    private WebStatsProviderBootstrap webStatsProviderBootstrap = null;

    private InjectionManager injectionMgr;

    private InvocationManager invocationMgr;

    private Collection<TldProvider> tldProviders;

    private String logServiceFile = null;

    /**
     * Static initialization
     */
    static {
        if (System.getProperty(DOL_DEPLOYMENT) != null) {
            useDOLforDeployment = Boolean.valueOf(System.getProperty(DOL_DEPLOYMENT));
        }
    }

    public void postConstruct() {

        createProbeProviders();

        injectionMgr = habitat.getByContract(InjectionManager.class);
        invocationMgr = habitat.getByContract(InvocationManager.class);
        tldProviders = habitat.getAllByContract(TldProvider.class);

        //createMonitoringConfig();
        createStatsProviders();

        setJspFactory();

        _appsWorkRoot =
                instance.getApplicationCompileJspPath().getAbsolutePath();
        _modulesRoot = instance.getApplicationRepositoryPath();

        // START S1AS 6178005
        appsStubRoot = instance.getApplicationStubPath().getAbsolutePath();
        // END S1AS 6178005

        // TODO: ParserUtils should become a @Service and it should initialize itself.
        // TODO: there should be only one EntityResolver for both DigesterFactory
        // and ParserUtils
        File root = _serverContext.getInstallRoot();
        File libRoot = new File(root, "lib");
        File schemas = new File(libRoot, "schemas");
        File dtds = new File(libRoot, "dtds");

        try {
            ParserUtils.setSchemaResourcePrefix(schemas.toURI().toURL().toString());
            ParserUtils.setDtdResourcePrefix(dtds.toURI().toURL().toString());
            ParserUtils.setEntityResolver(habitat.getComponent(EntityResolver.class, "web"));
        } catch (MalformedURLException e) {
            _logger.log(Level.SEVERE, "webContainer.exceptionSetSchemasDtdsLocation", e);
        }

        instanceName = _serverContext.getInstanceName();

        webContainerFeatureFactory = getWebContainerFeatureFactory();

        configureDynamicReloadingSettings();
        setDebugLevel();

        String maxDepth = null;
        if (serverConfig.getWebContainer() != null)
            maxDepth = serverConfig.getWebContainer().getPropertyValue(DISPATCHER_MAX_DEPTH);
        if (maxDepth != null) {
            int depth = -1;
            try {
                depth = Integer.parseInt(maxDepth);
            } catch (NumberFormatException e) {
            }

            if (depth > 0) {
                Request.setMaxDispatchDepth(depth);
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("Maximum depth for nested request "
                            + "dispatches set to "
                            + maxDepth);
                }
            }
        }

        logServiceFile = null;
        Map<String, String> logProps = null;
        try {
            logProps = logConfig.getLoggingProperties();
            if (logProps != null) {
                logServiceFile = logProps.get("com.sun.enterprise.server.logging.GFFileHandler.file");

                if (logServiceFile.contains("${com.sun.aas.instanceRoot}")) {
                    String instanceRoot = System.getProperty("com.sun.aas.instanceRoot");
                    String f = logServiceFile.replace("${com.sun.aas.instanceRoot}", instanceRoot);
                    logServiceFile = f;
                }

                logLevel = logProps.get("org.apache.catalina.level");
            }
        } catch (IOException ioe) {
            _logger.log(Level.SEVERE, "webContainer.unableDetermineServerLogLocation", ioe);
        }

        _embedded = habitat.getByType(EmbeddedWebContainer.class);
        _embedded.setWebContainer(this);
        _embedded.setLogServiceFile(logServiceFile);
        _embedded.setLogLevel(logLevel);
        _embedded.setFileLoggerHandlerFactory(fileLoggerHandlerFactory);
        _embedded.setWebContainerFeatureFactory(webContainerFeatureFactory);

        _embedded.setCatalinaHome(instance.getDomainRoot().getAbsolutePath());
        _embedded.setCatalinaBase(instance.getDomainRoot().getAbsolutePath());
        _embedded.setUseNaming(false);
        if (_debug > 1)
            _embedded.setDebug(_debug);
        _embedded.setLogger(new IASLogger(_logger));

        engine = _embedded.createEngine();
        engine.setParentClassLoader(EmbeddedWebContainer.class.getClassLoader());
        _embedded.addEngine(engine);
        ((StandardEngine) engine).setDomain(_serverContext.getDefaultDomainName());
        engine.setName(_serverContext.getDefaultDomainName());

        /*
        * Set the server info.
        * By default, the server info is taken from Version#getVersion.
        * However, customers may override it via the product.name system
        * property.
        * Some customers prefer not to disclose the server info
        * for security reasons, in which case they would set the value of the
        * product.name system property to the empty string. In this case,
        * the server name will not be publicly disclosed via the "Server"
        * HTTP response header (which will be suppressed) or any container
        * generated error pages. However, it will still appear in the
        * server logs (see IT 6900).
        */
        String serverInfo = System.getProperty("product.name");
        if (serverInfo == null) {
            ServerInfo.setServerInfo(Version.getVersion());
            ServerInfo.setPublicServerInfo(Version.getVersion());
        } else if (serverInfo.isEmpty()) {
            ServerInfo.setServerInfo(Version.getVersion());
            ServerInfo.setPublicServerInfo(serverInfo);
        } else {
            ServerInfo.setServerInfo(serverInfo);
            ServerInfo.setPublicServerInfo(serverInfo);
        }

        initInstanceSessionProperties();

        ConstructorCreator<WebConfigListener> womb =
                new ConstructorCreator<WebConfigListener>(
                        WebConfigListener.class,
                        habitat,
                        null);
        configListener = womb.get(null);

        ObservableBean bean = (ObservableBean) ConfigSupport.getImpl(
                serverConfig.getHttpService());
        bean.addListener(configListener);

        bean = (ObservableBean) ConfigSupport.getImpl(
                serverConfig.getNetworkConfig().getNetworkListeners());
        bean.addListener(configListener);

        if (serverConfig.getAvailabilityService() != null) {
            bean = (ObservableBean) ConfigSupport.getImpl(
                    serverConfig.getAvailabilityService());
            bean.addListener(configListener);
        }

        transactions.addListenerForType(SystemProperty.class, configListener);

        configListener.setNetworkConfig(serverConfig.getNetworkConfig());

        // embedded mode does not have manager-propertie in domain.xml
        if (configListener.managerProperties != null) {
            ObservableBean managerBean = (ObservableBean) ConfigSupport.getImpl(
                    configListener.managerProperties);
            managerBean.addListener(configListener);
        }

        configListener.setContainer(this);
        configListener.setLogger(_logger);

        events.register(this);

        grizzlyService.addMapperUpdateListener(configListener);

        HttpService httpService = serverConfig.getHttpService();
        NetworkConfig networkConfig = serverConfig.getNetworkConfig();
        if (networkConfig != null) {
            //continue;
            securityService = serverConfig.getSecurityService();

            // Configure HTTP listeners
            NetworkListeners networkListeners = networkConfig.getNetworkListeners();
            if (networkListeners != null) {
                List<NetworkListener> listeners = networkListeners.getNetworkListener();
                for (NetworkListener listener : listeners) {
                    if (ConfigBeansUtilities.toBoolean(listener.getJkEnabled())) {
                        createJKConnector(listener, httpService);
                    } else {
                        createHttpListener(listener, httpService);
                    }
                }
            }
            createJKConnector(null, httpService);

            setDefaultRedirectPort(defaultRedirectPort);

            // Configure virtual servers
            createHosts(httpService, securityService);
        }

        loadSystemDefaultWebModules();

        //_lifecycle.fireLifecycleEvent(START_EVENT, null);
        _started = true;

        /*
         * Start the embedded container.
         * Make sure to set the thread's context classloader to the
         * classloader of this class (see IT 8866 for details)
         */
        ClassLoader current = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(
                getClass().getClassLoader());
        try {
            /*
             * Trigger a call to sun.awt.AppContext.getAppContext().
             * This will pin the classloader of this class in memory
             * and fix a memory leak affecting instances of WebappClassLoader
             * that was caused by a JRE implementation change in 1.6.0_15
             * onwards. See IT 11110
             */
            ImageIO.getCacheDirectory();
            _embedded.start();
        } catch (LifecycleException le) {
            _logger.log(Level.SEVERE,
                    "webcontainer.exceptionDuringEmbeddedStart", le);
            return;
        } finally {
            // Restore original context classloader
            Thread.currentThread().setContextClassLoader(current);
        }
    }

    public void event(Event event) {
        if (event.is(Deployment.ALL_APPLICATIONS_PROCESSED)) {
            // configure default web modules for virtual servers after all
            // applications are processed
            loadDefaultWebModulesAfterAllAppsProcessed();
        } else if (event.is(EventTypes.PREPARE_SHUTDOWN)) {
            isShutdown = true;
        }
    }

    /**
     * Notifies any interested listeners that all ServletContextListeners
     * of the web module represented by the given WebBundleDescriptor
     * have been invoked at their contextInitialized method
     */
    void afterServletContextInitializedEvent(WebBundleDescriptor wbd) {
        events.send(new Event<WebBundleDescriptor>(
                WebBundleDescriptor.AFTER_SERVLET_CONTEXT_INITIALIZED_EVENT, wbd),
                false);
    }

    public void preDestroy() {
        try {
            _embedded.stop();
        } catch (LifecycleException le) {
            _logger.log(Level.SEVERE,
                    "webcontainer.exceptionDuringEmbeddedStop", le);
            return;
        }
    }

    JavaEEIOUtils getJavaEEIOUtils() {
        return javaEEIOUtils;
    }

    public boolean isShutdown() {
        return isShutdown;
    }

    Collection<TldProvider> getTldProviders() {
        return tldProviders;
    }

    /**
     * Gets the probe provider for servlet related events.
     */
    public ServletProbeProvider getServletProbeProvider() {
        return servletProbeProvider;
    }


    /**
     * Gets the probe provider for jsp related events.
     */
    public JspProbeProvider getJspProbeProvider() {
        return jspProbeProvider;
    }


    /**
     * Gets the probe provider for session related events.
     */
    public SessionProbeProvider getSessionProbeProvider() {
        return sessionProbeProvider;
    }


    /**
     * Gets the probe provider for request/response related events.
     */
    public RequestProbeProvider getRequestProbeProvider() {
        return requestProbeProvider;
    }

    /**
     * Gets the probe provider for web module related events.
     */
    public WebModuleProbeProvider getWebModuleProbeProvider() {
        return webModuleProbeProvider;
    }

    public String getName() {
        return "Web";
    }

    public Class<? extends WebDeployer> getDeployer() {
        return WebDeployer.class;
    }

    InvocationManager getInvocationManager() {
        return invocationMgr;
    }

    public WebConnector getJkConnector() {
        return jkConnector;
    }

    HashMap<String, WebConnector> getConnectorMap() {
        return connectorMap;
    }

    /**
     * Instantiates and injects the given Servlet class for the given
     * WebModule
     */
    <T extends Servlet> T createServletInstance(WebModule module,
                                                Class<T> clazz) throws Exception {
        validateJSR299Scope(clazz);
        WebComponentInvocation inv = new WebComponentInvocation(module);
        try {
            invocationMgr.preInvoke(inv);
            return injectionMgr.createManagedObject(clazz);
        } finally {
            invocationMgr.postInvoke(inv);
        }
    }

    /**
     * Instantiates and injects the given Filter class for the given
     * WebModule
     */
    <T extends Filter> T createFilterInstance(WebModule module,
                                              Class<T> clazz) throws Exception {
        validateJSR299Scope(clazz);
        WebComponentInvocation inv = new WebComponentInvocation(module);
        try {
            invocationMgr.preInvoke(inv);
            return injectionMgr.createManagedObject(clazz);
        } finally {
            invocationMgr.postInvoke(inv);
        }
    }

    /**
     * Instantiates and injects the given EventListener class for the
     * given WebModule
     */
    <T extends java.util.EventListener> T createListenerInstance(
            WebModule module, Class<T> clazz) throws Exception {
        validateJSR299Scope(clazz);
        WebComponentInvocation inv = new WebComponentInvocation(module);
        try {
            invocationMgr.preInvoke(inv);
            return injectionMgr.createManagedObject(clazz);
        } finally {
            invocationMgr.postInvoke(inv);
        }
    }

    /**
     * Instantiates and injects the given tag handler class for the given
     * WebModule
     */
    public <T extends JspTag> T createTagHandlerInstance(WebModule module,
                                                         Class<T> clazz) throws Exception {
        WebComponentInvocation inv = new WebComponentInvocation(module);
        try {
            invocationMgr.preInvoke(inv);
            return injectionMgr.createManagedObject(clazz);
        } finally {
            invocationMgr.postInvoke(inv);
        }
    }

    /**
     * Use an network-listener subelements and creates a corresponding
     * Tomcat Connector for each.
     *
     * @param httpService The http-service element
     * @param listener    the configuration element.
     */
    protected WebConnector createHttpListener(NetworkListener listener,
                                              HttpService httpService) {
        return createHttpListener(listener, httpService, null);
    }


    protected WebConnector createHttpListener(NetworkListener listener,
                                              HttpService httpService,
                                              Mapper mapper) {

        if (!Boolean.valueOf(listener.getEnabled())) {
            return null;
        }

        int port = 8080;
        WebConnector connector;

        checkHostnameUniqueness(listener.getName(), httpService);

        try {
            port = Integer.parseInt(listener.getPort());
        } catch (NumberFormatException nfe) {
            String msg = rb.getString("pewebcontainer.http_listener.invalid_port");
            msg = MessageFormat.format(msg, listener.getPort(),
                    listener.getName());
            throw new IllegalArgumentException(msg);
        }

        if (mapper == null) {
            for (Mapper m : habitat.getAllByContract(Mapper.class)) {
                if (m.getPort() == port && m instanceof ContextMapper) {
                    ContextMapper cm = (ContextMapper) m;
                    if (listener.getName().equals(cm.getId())) {
                        mapper = m;
                        break;
                    }
                }
            }
        }

        String defaultVS = listener.findHttpProtocol().getHttp().getDefaultVirtualServer();
        if (!defaultVS.equals(org.glassfish.api.web.Constants.ADMIN_VS)) {
            // Before we start a WebConnector, let's makes sure there is
            // not another Container already listening on that port
            MessageBytes host = MessageBytes.newInstance();
            char[] c = defaultVS.toCharArray();
            host.setChars(c, 0, c.length);

            MessageBytes mb = MessageBytes.newInstance();
            mb.setChars(new char[]{'/'}, 0, 1);

            MappingData md = new MappingData();
            try {
                mapper.map(host, mb, md);
            } catch (Exception e) {
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.log(Level.FINE, "", e);
                }
            }

            if (md.context != null && md.context instanceof ContextRootInfo) {
                ContextRootInfo r = (ContextRootInfo) md.context;
                if (!(r.getAdapter() instanceof ContainerMapper)) {
                    new BindException("Port " + port + " is already used by Container: "
                            + r.getAdapter() +
                            " and will not get started.").printStackTrace();
                    return null;
                }
            }
        }

        /*
         * Create Connector. Connector is SSL-enabled if
         * 'security-enabled' attribute in <http-listener>
         * element is set to TRUE.
         */
        boolean isSecure = Boolean.valueOf(listener.findHttpProtocol().getSecurityEnabled());
        if (isSecure && defaultRedirectPort == -1) {
            defaultRedirectPort = port;
        }
        String address = listener.getAddress();
        if ("any".equals(address) || "ANY".equals(address)
                || "INADDR_ANY".equals(address)) {
            address = null;
            /*
             * Setting 'address' to NULL will cause Tomcat to pass a
             * NULL InetAddress argument to the java.net.ServerSocket
             * constructor, meaning that the server socket will accept
             * connections on any/all local addresses.
             */
        }

        connector = (WebConnector) _embedded.createConnector(
                address, port, isSecure);

        connector.setMapper(mapper);

        if (_logger.isLoggable(Level.INFO)) {
            _logger.log(Level.INFO, "webContainer.HTTP.listenerAndPort", new Object[]{listener.getName(), listener.getAddress(), listener.getPort()});
        }

        connector.setDefaultHost(listener.findHttpProtocol().getHttp().getDefaultVirtualServer());
        connector.setName(listener.getName());
        connector.setInstanceName(instanceName);
        connector.configure(listener, isSecure, httpService);

        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "create.listenerport",
                    new Object[]{port, connector});
        }

        _embedded.addConnector(connector);

        connectorMap.put(listener.getName(), connector);

        // If we already know the redirect port, then set it now
        // This situation will occurs when dynamic reconfiguration occurs
        String redirectPort = listener.findHttpProtocol().getHttp().getRedirectPort();
        if (redirectPort != null) {
            connector.setRedirectPort(Integer.parseInt(redirectPort));
        } else if (defaultRedirectPort != -1) {
            connector.setRedirectPort(defaultRedirectPort);
        }

        ObservableBean httpListenerBean = (ObservableBean) ConfigSupport.getImpl(
                listener);
        httpListenerBean.addListener(configListener);

        return connector;
    }

    /**
     * Starts the AJP connector that will listen to call from Apache using
     * mod_jk, mod_jk2 or mod_ajp.
     */
    protected WebConnector createJKConnector(NetworkListener listener,
                                             HttpService httpService) {

        int port = 8009;
        boolean isSecure = false;
        String address = null;

        if (listener == null) {
            String portString =
                    System.getProperty("com.sun.enterprise.web.connector.enableJK");
            if (portString == null) {
                // do not create JK Connector if property is not set
                return null;
            } else {
                try {
                    port = Integer.parseInt(portString);
                } catch (NumberFormatException ex) {
                    // use default port 8009
                    port = 8009;
                }
            }
        } else {
            port = Integer.parseInt(listener.getPort());
            isSecure = Boolean.valueOf(listener.findHttpProtocol().getSecurityEnabled());
            address = listener.getAddress();
        }

        if (isSecure && defaultRedirectPort == -1) {
            defaultRedirectPort = port;
        }

        if ("any".equals(address) || "ANY".equals(address)
                || "INADDR_ANY".equals(address)) {
            address = null;
            /*
             * Setting 'address' to NULL will cause Tomcat to pass a
             * NULL InetAddress argument to the java.net.ServerSocket
             * constructor, meaning that the server socket will accept
             * connections on any/all local addresses.
             */
        }

        jkConnector = (WebConnector) _embedded.createConnector(address,
                port, "ajp");
        jkConnector.configureJKProperties(listener);

        String defaultHost = "server";
        String jkConnectorName = "jk-connector";
        if (listener != null) {
            defaultHost = listener.findHttpProtocol().getHttp().getDefaultVirtualServer();
            jkConnectorName = listener.getName();
        }
        jkConnector.setDefaultHost(defaultHost);
        jkConnector.setName(jkConnectorName);
        jkConnector.setDomain(_serverContext.getDefaultDomainName());
        jkConnector.setInstanceName(instanceName);
        if (listener != null) {
            jkConnector.configure(listener, isSecure, httpService);
            connectorMap.put(listener.getName(), jkConnector);
        }

        if (_logger.isLoggable(Level.INFO)) {
            _logger.log(Level.INFO, "webContainer.virtualServer.hostAndPort", new Object[]{defaultHost, port});
        }


        for (Mapper m : habitat.getAllByContract(Mapper.class)) {
            if (m.getPort() == port && m instanceof ContextMapper) {
                ContextMapper cm = (ContextMapper) m;
                if (listener.getName().equals(cm.getId())) {
                    jkConnector.setMapper(m);
                    break;
                }
            }
        }

        _embedded.addConnector(jkConnector);

        ObservableBean httpListenerBean = (ObservableBean) ConfigSupport.getImpl(
                listener);
        httpListenerBean.addListener(configListener);

        return jkConnector;

    }

    /**
     * Assigns the given redirect port to each Connector whose corresponding
     * http-listener element in domain.xml does not specify its own
     * redirect-port attribute.
     * <p/>
     * The given defaultRedirectPort corresponds to the port number of the
     * first security-enabled http-listener in domain.xml.
     * <p/>
     * This method does nothing if none of the http-listener elements is
     * security-enabled, in which case Tomcat's default redirect port (443)
     * will be used.
     *
     * @param defaultRedirectPort The redirect port to be assigned to any
     *                            Connector object that doesn't specify its own
     */
    private void setDefaultRedirectPort(int defaultRedirectPort) {
        if (defaultRedirectPort != -1) {
            Connector[] connectors = _embedded.getConnectors();
            for (Connector connector : connectors) {
                if (connector.getRedirectPort() == -1) {
                    connector.setRedirectPort(defaultRedirectPort);
                }
            }
        }
    }

    /**
     * Configure http-service properties.
     *
     * @deprecated most of these properties are handled elsewhere.  validate and remove outdated properties checks
     */
    public void configureHttpServiceProperties(HttpService httpService,
                                               PECoyoteConnector connector) {
        // Configure Connector with <http-service> properties
        List<Property> httpServiceProps = httpService.getProperty();

        // Set default ProxyHandler impl, may be overriden by
        // proxyHandler property
        connector.setProxyHandler(new ProxyHandlerImpl());

        globalSSOEnabled = ConfigBeansUtilities.toBoolean(httpService.getSsoEnabled());
        globalAccessLoggingEnabled = ConfigBeansUtilities.toBoolean(httpService.getAccessLoggingEnabled());
        globalAccessLogWriteInterval = httpService.getAccessLog().getWriteIntervalSeconds();
        globalAccessLogBufferSize = httpService.getAccessLog().getBufferSizeBytes();
        if (httpServiceProps != null) {
            for (Property httpServiceProp : httpServiceProps) {
                String propName = httpServiceProp.getName();
                String propValue = httpServiceProp.getValue();

                if (connector.configureHttpListenerProperty(propName, propValue)) {
                    continue;
                }

                if ("connectionTimeout".equals(propName)) {
                    connector.setConnectionTimeout(Integer.parseInt(propValue));
                } else if ("tcpNoDelay".equals(propName)) {
                    connector.setTcpNoDelay(ConfigBeansUtilities.toBoolean(propValue));
                } else if ("traceEnabled".equals(propName)) {
                    connector.setAllowTrace(ConfigBeansUtilities.toBoolean(propValue));
                } else if ("ssl-session-timeout".equals(propName)) {
                    connector.setSslSessionTimeout(propValue);
                } else if ("ssl3-session-timeout".equals(propName)) {
                    connector.setSsl3SessionTimeout(propValue);
                } else if ("ssl-cache-entries".equals(propName)) {
                    connector.setSslSessionCacheSize(propValue);
                } else if ("proxyHandler".equals(propName)) {
                    connector.setProxyHandler(propValue);
                } else {
                    String msg = rb.getString("pewebcontainer.invalid_http_service_property");
                    _logger.log(Level.WARNING,
                            MessageFormat.format(msg, httpServiceProp.getName()));
                }
            }
        }
    }

    /*
     * Ensures that the host names of all virtual servers associated with the
     * HTTP listener with the given listener id are unique.
     *
     * @param listenerId The id of the HTTP listener whose associated virtual
     * servers are checked for uniqueness of host names
     * @param httpService The http-service element whose virtual servers are
     * checked
     */

    private void checkHostnameUniqueness(String listenerId,
                                         HttpService httpService) {

        List<com.sun.enterprise.config.serverbeans.VirtualServer> listenerVses = null;

        // Determine all the virtual servers associated with the given listener
        for (com.sun.enterprise.config.serverbeans.VirtualServer vse : httpService.getVirtualServer()) {
            List<String> vsListeners = StringUtils.parseStringList(vse.getNetworkListeners(), ",");
            for (int j = 0; vsListeners != null && j < vsListeners.size(); j++) {
                if (listenerId.equals(vsListeners.get(j))) {
                    if (listenerVses == null) {
                        listenerVses = new ArrayList<com.sun.enterprise.config.serverbeans.VirtualServer>();
                    }
                    listenerVses.add(vse);
                    break;
                }
            }
        }
        if (listenerVses == null) {
            return;
        }

        for (int i = 0; i < listenerVses.size(); i++) {
            com.sun.enterprise.config.serverbeans.VirtualServer vs
                    = listenerVses.get(i);
            List hosts = StringUtils.parseStringList(vs.getHosts(), ",");
            for (int j = 0; hosts != null && j < hosts.size(); j++) {
                String host = (String) hosts.get(j);
                for (int k = 0; k < listenerVses.size(); k++) {
                    if (k <= i) {
                        continue;
                    }
                    com.sun.enterprise.config.serverbeans.VirtualServer otherVs
                            = listenerVses.get(k);
                    List otherHosts = StringUtils.parseStringList(otherVs.getHosts(), ",");
                    for (int l = 0; otherHosts != null && l < otherHosts.size(); l++) {
                        if (host.equals(otherHosts.get(l))) {
                            _logger.log(Level.SEVERE,
                                    "pewebcontainer.duplicate_host_name",
                                    new Object[]{host, vs.getId(),
                                            otherVs.getId(),
                                            listenerId});
                        }
                    }
                }
            }
        }
    }


    /**
     * Enumerates the virtual-server subelements of the given http-service
     * element, and creates a corresponding Host for each.
     *
     * @param httpService     The http-service element
     * @param securityService The security-service element
     */
    protected void createHosts(HttpService httpService, SecurityService securityService) {

        List<com.sun.enterprise.config.serverbeans.VirtualServer> virtualServers = httpService.getVirtualServer();
        for (com.sun.enterprise.config.serverbeans.VirtualServer vs : virtualServers) {
            createHost(vs, httpService, securityService);
            if (_logger.isLoggable(Level.INFO)) {
                _logger.log(Level.INFO, "webContainer.virtualServer.created", vs.getId());
            }

        }
    }


    /**
     * Creates a Host from a virtual-server config bean.
     *
     * @param vsBean          The virtual-server configuration bean
     * @param httpService     The http-service element.
     * @param securityService The security-service element
     */
    public VirtualServer createHost(
            com.sun.enterprise.config.serverbeans.VirtualServer vsBean,
            HttpService httpService,
            SecurityService securityService) {

        MimeMap mm = null;
        String vs_id = vsBean.getId();

        String docroot = vsBean.getPropertyValue("docroot");
        if (docroot == null) {
            docroot = vsBean.getDocroot();
        }

        validateDocroot(docroot,
                vs_id,
                vsBean.getDefaultWebModule());

        VirtualServer vs = createHost(vs_id, vsBean, docroot, mm
        );

        // cache control
        Property cacheProp = vsBean.getProperty("setCacheControl");
        if (cacheProp != null) {
            vs.configureCacheControl(cacheProp.getValue());
        }

        PEAccessLogValve accessLogValve = vs.getAccessLogValve();
        boolean startAccessLog = accessLogValve.configure(
                vs_id, vsBean, httpService, domain,
                habitat, webContainerFeatureFactory,
                globalAccessLogBufferSize, globalAccessLogWriteInterval);
        if (startAccessLog
                && vs.isAccessLoggingEnabled(globalAccessLoggingEnabled)) {
            vs.addValve((GlassFishValve) accessLogValve);
            vs.setErrorHandler(serverConfig, grizzlyService, false);
        }

        if (_logger.isLoggable(Level.FINEST)) {
            _logger.log(Level.FINEST, "Created virtual server " + vs_id);
        }

        /*
         * We must configure the Host with its associated port numbers and
         * alias names before adding it as an engine child and thereby
         * starting it, because a MapperListener, which is associated with
         * an HTTP listener and receives notifications about Host
         * registrations, relies on these Host properties in order to determine
         * whether a new Host needs to be added to the HTTP listener's Mapper.
         */
        configureHost(vs, securityService);
        vs.setServerEnvironment(instance);
        vs.setDomain(domain);
        vs.setCommandRunner(runner);
        vs.setHabitat(habitat);
        vs.setClassLoaderHierarchy(clh);

        // Add Host to Engine
        engine.addChild(vs);

        ObservableBean virtualServerBean = (ObservableBean) ConfigSupport.getImpl(vsBean);
        virtualServerBean.addListener(configListener);

        return vs;
    }


    /**
     * Validate the docroot properties of a virtual-server.
     */
    protected void validateDocroot(String docroot, String vs_id,
                                   String defaultWebModule) {
        if (docroot == null) {
            return;
        }

        boolean isValid = new File(docroot).exists();
        if (!isValid) {
            String msg = rb.getString(
                    "pewebcontainer.virtual_server.invalid_docroot");
            msg = MessageFormat.format(msg, vs_id, docroot);
            throw new IllegalArgumentException(msg);
        }
    }


    /**
     * Configures the given virtual server.
     *
     * @param vs              The virtual server to be configured
     * @param securityService The security-service element
     */
    protected void configureHost(VirtualServer vs, SecurityService securityService) {

        com.sun.enterprise.config.serverbeans.VirtualServer vsBean = vs.getBean();

        vs.configureAliases();

        // Set the ports with which this virtual server is associated
        List<String> listeners = StringUtils.parseStringList(
                vsBean.getNetworkListeners(), ",");
        if (listeners == null) {
            return;
        }

        HashSet<NetworkListener> httpListeners = new HashSet<NetworkListener>();
        for (String listener : listeners) {
            boolean found = false;
            for (NetworkListener httpListener :
                    serverConfig.getNetworkConfig().getNetworkListeners().getNetworkListener()) {
                if (httpListener.getName().equals(listener)) {
                    httpListeners.add(httpListener);
                    found = true;
                    break;
                }
            }
            if (!found) {
                String msg = rb.getString(
                        "webcontainer.listenerReferencedByHostNotExist");
                msg = MessageFormat.format(msg, listener, vs.getName());
                _logger.log(Level.SEVERE, msg);
            }
        }

        configureHostPortNumbers(vs, httpListeners);
        vs.configureCatalinaProperties();
        vs.configureAuthRealm(securityService);
    }


    /**
     * Configures the given virtual server with the port numbers of its
     * associated http listeners.
     *
     * @param vs        The virtual server to configure
     * @param listeners The http listeners with which the given virtual
     *                  server is associated
     */
    protected void configureHostPortNumbers(VirtualServer vs,
                                            HashSet<NetworkListener> listeners) {

        boolean addJkListenerName = jkConnector != null &&
                !vs.getName().equalsIgnoreCase(
                        org.glassfish.api.web.Constants.ADMIN_VS);

        List<String> listenerNames = new ArrayList<String>();
        for (NetworkListener listener : listeners) {
            if (Boolean.valueOf(listener.getEnabled())) {
                listenerNames.add(listener.getName());
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("Virtual Server " + vs.getID() +
                            " set listener name " + listener.getName());
                }
            } else {
                if (vs.getName().equalsIgnoreCase(
                        org.glassfish.api.web.Constants.ADMIN_VS)) {
                    String msg = rb.getString(
                            "pewebcontainer.httpListener.mustNotDisable");
                    msg = MessageFormat.format(msg, listener.getName(),
                            vs.getName());
                    throw new IllegalArgumentException(msg);
                }
            }
        }

        if (addJkListenerName && (!listenerNames.contains(jkConnector.getName()))) {
            listenerNames.add(jkConnector.getName());
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("Virtual Server " + vs.getID() +
                        " set jk listener name " + jkConnector.getName());
            }
        }

        vs.setNetworkListenerNames(
                listenerNames.toArray(new String[listenerNames.size()]));
    }


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

    /**
     * Create a virtual server/host.
     */
    public VirtualServer createHost(String vsID,
                                    com.sun.enterprise.config.serverbeans.VirtualServer vsBean,
                                    String docroot, MimeMap mimeMap) {

        // Initialize the docroot
        VirtualServer vs = (VirtualServer) _embedded.createHost(vsID,
                vsBean, docroot, vsBean.getLogFile(), mimeMap);
        vs.configureState();
        vs.configureRemoteAddressFilterValve();
        vs.configureRemoteHostFilterValve();
        vs.configureSingleSignOn(globalSSOEnabled, webContainerFeatureFactory, isSsoFailoverEnabled());
        vs.configureRedirect();
        vs.configureErrorPage();
        vs.configureErrorReportValve();
        vs.setServerContext(getServerContext());
        vs.setServerConfig(serverConfig);
        vs.setGrizzlyService(grizzlyService);
        vs.setWebContainer(this);

        return vs;
    }


    /**
     * Gracefully terminate the active use of the public methods of this
     * component.  This method should be the last one called on a given
     * instance of this component.
     *
     * @throws IllegalStateException if this component has not been started
     * @throws LifecycleException    if this component detects a fatal error
     *                               that needs to be reported
     */
    public void stop() throws LifecycleException {
        // Validate and update our current component state
        if (!_started) {
            String msg = rb.getString("webcontainer.notStarted");
            throw new LifecycleException(msg);
        }

        _started = false;

        // stop the embedded container
        try {
            _embedded.stop();
        } catch (LifecycleException ex) {
            if (!ex.getMessage().contains("has not been started")) {
                throw ex;
            }
        }
    }


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


    /**
     * Configures a default web module for each virtual server based on the
     * virtual server's docroot if a virtual server does not specify
     * any default-web-module, and none of its web modules are loaded at "/"
     * <p/>
     * Needed in postConstruct before Deployment.ALL_APPLICATIONS_PROCESSED
     * for "jsp from docroot before web container start" scenario
     */

    public void loadSystemDefaultWebModules() {

        WebModuleConfig wmInfo = null;
        String defaultPath = null;

        Container[] vsArray = getEngine().findChildren();
        for (Container aVsArray : vsArray) {
            if (aVsArray instanceof VirtualServer) {
                VirtualServer vs = (VirtualServer) aVsArray;
                /*
                * Let AdminConsoleAdapter handle any requests for
                * the root context of the '__asadmin' virtual-server, see
                * https://glassfish.dev.java.net/issues/show_bug.cgi?id=5664
                */
                if (org.glassfish.api.web.Constants.ADMIN_VS.equals(
                        vs.getName())) {
                    continue;
                }

                // Create default web module off of virtual
                // server's docroot if necessary                  
                wmInfo = vs.createSystemDefaultWebModuleIfNecessary(
                        habitat.getComponent(
                                WebArchivist.class));
                if (wmInfo != null) {
                    defaultPath = wmInfo.getContextPath();
                    loadStandaloneWebModule(vs, wmInfo);
                }
                if (_logger.isLoggable(Level.INFO)) {
                    _logger.log(Level.INFO,
                            "webContainer.virtualServer.loadedDefaultWebModule",
                            new Object[]{vs.getName(), defaultPath});
                }

            }
        }

    }


    /**
     * Configures a default web module for each virtual server
     * if default-web-module is defined.
     */
    public void loadDefaultWebModulesAfterAllAppsProcessed() {

        String defaultPath = null;

        Container[] vsArray = getEngine().findChildren();
        for (Container aVsArray : vsArray) {
            if (aVsArray instanceof VirtualServer) {
                VirtualServer vs = (VirtualServer) aVsArray;
                /*
                * Let AdminConsoleAdapter handle any requests for
                * the root context of the '__asadmin' virtual-server, see
                * https://glassfish.dev.java.net/issues/show_bug.cgi?id=5664
                */
                if (org.glassfish.api.web.Constants.ADMIN_VS.equals(
                        vs.getName())) {
                    continue;
                }
                WebModuleConfig wmInfo = vs.getDefaultWebModule(domain,
                        habitat.getComponent(
                                WebArchivist.class),
                        appRegistry);
                if (wmInfo != null) {
                    defaultPath = wmInfo.getContextPath();
                    // Virtual server declares default-web-module
                    try {
                        updateDefaultWebModule(vs, vs.getNetworkListenerNames(), wmInfo);
                    } catch (LifecycleException le) {
                        String msg = rb.getString(
                                "webcontainer.defaultWebModuleError");
                        msg = MessageFormat.format(msg, defaultPath,
                                vs.getName());
                        _logger.log(Level.SEVERE, msg, le);
                    }
                    if (_logger.isLoggable(Level.INFO)) {
                        _logger.log(Level.INFO, "webContainer.virtual-server.loadedDefaultWebModule",
                                new Object[]{vs.getName(), defaultPath});
                    }

                } else {
                    // No need to create default web module off of virtual
                    // server's docroot since system web modules are already
                    // created in WebContainer.postConstruct
                }
            }
        }
    }


    /**
     * Load a default-web-module on the specified virtual server.
     */
    public void loadDefaultWebModule(
            com.sun.enterprise.config.serverbeans.VirtualServer vsBean) {

        VirtualServer virtualServer = (VirtualServer)
                getEngine().findChild(vsBean.getId());

        if (virtualServer != null) {
            loadDefaultWebModule(virtualServer);
        }
    }


    /**
     * Load a default-web-module on the specified virtual server.
     */
    public void loadDefaultWebModule(VirtualServer vs) {

        String defaultPath = null;
        WebModuleConfig wmInfo = vs.getDefaultWebModule(domain,
                habitat.getComponent(
                        WebArchivist.class),
                appRegistry);
        if (wmInfo != null) {
            defaultPath = wmInfo.getContextPath();
            // Virtual server declares default-web-module
            try {
                updateDefaultWebModule(vs, vs.getNetworkListenerNames(), wmInfo);
            } catch (LifecycleException le) {
                String msg = rb.getString("webcontainer.defaultWebModuleError");
                msg = MessageFormat.format(msg, defaultPath, vs.getName());
                _logger.log(Level.SEVERE, msg, le);
            }

        } else {
            // Create default web module off of virtual
            // server's docroot if necessary                  
            wmInfo = vs.createSystemDefaultWebModuleIfNecessary(
                    habitat.getComponent(
                            WebArchivist.class));
            if (wmInfo != null) {
                defaultPath = wmInfo.getContextPath();
                loadStandaloneWebModule(vs, wmInfo);
            }
        }

        if (_logger.isLoggable(Level.INFO)) {
            _logger.log(Level.INFO, "webContainer.virtual-server.loadedDefaultWebModule",
                    new Object[]{vs.getName(), defaultPath});
        }
    }


    /**
     * Load the specified web module as a standalone module on the specified
     * virtual server.
     */
    protected void loadStandaloneWebModule(VirtualServer vs,
                                           WebModuleConfig wmInfo) {
        try {
            loadWebModule(vs, wmInfo, "null", null);
        } catch (Throwable t) {
            String msg = rb.getString("webContainer.loadWebModuleError");
            msg = MessageFormat.format(msg, wmInfo.getName());
            _logger.log(Level.SEVERE, msg, t);
        }
    }


    /**
     * Whether or not a component (either an application or a module) should be
     * enabled is defined by the "enable" attribute on both the
     * application/module element and the application-ref element.
     *
     * @param moduleName The name of the component (application or module)
     * @return boolean
     */
    protected boolean isEnabled(String moduleName) {
        // TODO dochez : optimize
        /*
        Domain domain = habitat.getComponent(Domain.class);
        applications = domain.getApplications().getLifecycleModuleOrJ2EeApplicationOrEjbModuleOrWebModuleOrConnectorModuleOrAppclientModuleOrMbeanOrExtensionModule();
        com.sun.enterprise.config.serverbeans.WebModule webModule = null;
        for (Object module : applications) {
            if (module instanceof WebModule) {
                if (moduleName.equals(((com.sun.enterprise.config.serverbeans.WebModule) module).getName())) {
                    webModule = (com.sun.enterprise.config.serverbeans.WebModule) module;
                }
            }
        }    em
        ServerContext env = habitat.getComponent(ServerContext.class);
        List<Server> servers = domain.getServers().getServer();
        Server thisServer = null;
        for (Server server : servers) {
            if (env.getInstanceName().equals(server.getName())) {
                thisServer = server;
            }
        }
        List<ApplicationRef> appRefs = thisServer.getApplicationRef();
        ApplicationRef appRef = null;
        for (ApplicationRef ar : appRefs) {
            if (ar.getRef().equals(moduleName)) {
                appRef = ar;
            }
        }

        return ((webModule != null && Boolean.valueOf(webModule.getEnabled())) &&
                (appRef != null && Boolean.valueOf(appRef.getEnabled())));
         */
        return true;
    }

    /**
     * Creates and configures a web module for each virtual server
     * that the web module is hosted under.
     * <p/>
     * If no virtual servers have been specified, then the web module will
     * not be loaded.
     */
    public List<Result<WebModule>> loadWebModule(
            WebModuleConfig wmInfo, String j2eeApplication,
            Properties deploymentProperties) {
        List<Result<WebModule>> results = new ArrayList<Result<WebModule>>();
        String vsIDs = wmInfo.getVirtualServers();
        List<String> vsList = StringUtils.parseStringList(vsIDs, " ,");
        if (vsList == null || vsList.isEmpty()) {
            if (_logger.isLoggable(Level.INFO)) {
                _logger.log(Level.INFO,
                        "webcontainer.webModuleNotLoadedNoVirtualServers",
                        wmInfo.getName());
            }
            return results;
        }

        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "About to load web module " +
                    wmInfo.getName() + " to virtual servers " + vsIDs);
        }

        List<String> nonProcessedVSList = new ArrayList<String>(vsList);
        Container[] vsArray = getEngine().findChildren();
        for (Container aVsArray : vsArray) {
            if (aVsArray instanceof VirtualServer) {
                VirtualServer vs = (VirtualServer) aVsArray;
                boolean eqVS = vsList.contains(vs.getID());
                if (eqVS) {
                    nonProcessedVSList.remove(vs.getID());
                }
                Set<String> matchedAliases = matchAlias(vsList, vs);
                boolean hasMatchedAlias = (matchedAliases.size() > 0);
                if (hasMatchedAlias) {
                    nonProcessedVSList.removeAll(matchedAliases);
                }
                if (eqVS || hasMatchedAlias) {
                    WebModule ctx = null;
                    try {
                        ctx = loadWebModule(vs, wmInfo, j2eeApplication,
                                deploymentProperties);
                        results.add(new Result<WebModule>(ctx));
                    } catch (Throwable t) {
                        if (ctx != null) {
                            ctx.setAvailable(false);
                        }
                        results.add(new Result<WebModule>(t));
                    }
                }
            }
        }

        if (nonProcessedVSList.size() > 0) {
            StringBuilder sb = new StringBuilder();
            boolean follow = false;
            for (String alias : nonProcessedVSList) {
                 if (follow) {
                     sb.append(",");
                 }
                 sb.append(alias);
                 follow = true;
            }
            Object[] params = {wmInfo.getName(), sb.toString()};
            _logger.log(Level.SEVERE, "webcontainer.moduleNotLoadedToVS",
                            params);
        }
        return results;
    }


    /**
     * Deploy on aliases as well as host.
     */
    private boolean verifyAlias(List<String> vsList, VirtualServer vs) {
        for (int i = 0; i < vs.getAliases().length; i++) {
            if (vsList.contains(vs.getAliases()[i])) {
                return true;
            }
        }
        return false;
    }

    /**
     * Find all matched aliases.
     * This is more expensive than verifyAlias.
     */
    private Set<String> matchAlias(List<String> vsList, VirtualServer vs) {
        Set<String> matched = new HashSet<String>();
        for (String alias : vs.getAliases()) {
            if (vsList.contains(alias)) {
                matched.add(alias);
            }
        }

        return matched;
    }


    /**
     * Creates and configures a web module and adds it to the specified
     * virtual server.
     */
    private WebModule loadWebModule(
            VirtualServer vs,
            WebModuleConfig wmInfo,
            String j2eeApplication,
            Properties deploymentProperties)
            throws Exception {

        String wmName = wmInfo.getName();
        String wmContextPath = wmInfo.getContextPath();

        if (wmContextPath.indexOf('%') != -1) {
            try {
                RequestUtil.urlDecode(wmContextPath, "UTF-8");
            } catch (Exception e) {
                String msg = rb.getString(
                        "webcontainer.invalidEncodedContextRoot");
                msg = MessageFormat.format(msg, wmName, wmContextPath);
                throw new Exception(msg);
            }
        }

        if (wmContextPath.length() == 0 &&
                vs.getDefaultWebModuleID() != null) {
            String msg = rb.getString("webcontainer.defaultWebModuleConflict");
            msg = MessageFormat.format(msg,
                    new Object[]{wmName, vs.getID()});
            throw new Exception(msg);
        }

        wmInfo.setWorkDirBase(_appsWorkRoot);
        // START S1AS 6178005
        wmInfo.setStubBaseDir(appsStubRoot);
        // END S1AS 6178005

        String displayContextPath = null;
        if (wmContextPath.length() == 0)
            displayContextPath = "/";
        else
            displayContextPath = wmContextPath;

        Map<String, AdHocServletInfo> adHocPaths = null;
        Map<String, AdHocServletInfo> adHocSubtrees = null;
        WebModule ctx = (WebModule) vs.findChild(wmContextPath);
        if (ctx != null) {
            if (ctx instanceof AdHocWebModule) {
                /*
                 * Found ad-hoc web module which has been created by web
                 * container in order to store mappings for ad-hoc paths
                 * and subtrees.
                 * All these mappings must be propagated to the context
                 * that is being deployed.
                 */
                if (ctx.hasAdHocPaths()) {
                    adHocPaths = ctx.getAdHocPaths();
                }
                if (ctx.hasAdHocSubtrees()) {
                    adHocSubtrees = ctx.getAdHocSubtrees();
                }
                vs.removeChild(ctx);
            } else if (Constants.DEFAULT_WEB_MODULE_NAME
                    .equals(ctx.getModuleName())) {
                /*
                 * Dummy context that was created just off of a docroot,
                 * (see
                 * VirtualServer.createSystemDefaultWebModuleIfNecessary()).
                 * Unload it so it can be replaced with the web module to be
                 * loaded
                 */
                unloadWebModule(wmContextPath,
                        ctx.getJ2EEApplication(),
                        vs.getName(),
                        true,
                        null);
            } else if (!ctx.getAvailable()) {
                /*
                 * Context has been marked unavailable by a previous
                 * call to disableWebModule. Mark the context as available and
                 * return
                 */
                ctx.setAvailable(true);
                return ctx;
            } else {
                String msg = rb.getString("webcontainer.duplicateContextRoot");
                throw new Exception(MessageFormat.format(msg, vs.getID(),
                        ctx.getModuleName(), displayContextPath, wmName));
            }
        }

        if (_logger.isLoggable(Level.FINEST)) {
            Object[] params = {wmName, vs.getID(), displayContextPath};
            _logger.log(Level.FINEST, "webcontainer.loadModule", params);
        }

        File docBase = null;
        if (JWS_APPCLIENT_MODULE_NAME.equals(wmName)) {
            docBase = new File(System.getProperty("com.sun.aas.installRoot"));
        } else {
            docBase = wmInfo.getLocation();
        }

        ctx = (WebModule) _embedded.createContext(
                wmName,
                wmContextPath,
                docBase,
                vs.getDefaultContextXmlLocation(),
                vs.getDefaultWebXmlLocation(),
                useDOLforDeployment,
                wmInfo);

        // for now disable JNDI
        ctx.setUseNaming(false);

        // Set JSR 77 object name and attributes
        Engine engine = (Engine) vs.getParent();
        if (engine != null) {
            ctx.setEngineName(engine.getName());
            ctx.setJvmRoute(engine.getJvmRoute());
        }
        String j2eeServer = _serverContext.getInstanceName();
        String domain = _serverContext.getDefaultDomainName();
        // String[] javaVMs = J2EEModuleUtil.getjavaVMs();
        ctx.setDomain(domain);

        ctx.setJ2EEServer(j2eeServer);
        ctx.setJ2EEApplication(j2eeApplication);
        ctx.setCachingAllowed(false);
        ctx.setCacheControls(vs.getCacheControls());
        ctx.setBean(wmInfo.getBean());

        if (adHocPaths != null) {
            ctx.addAdHocPaths(adHocPaths);
        }
        if (adHocSubtrees != null) {
            ctx.addAdHocSubtrees(adHocSubtrees);
        }

        // Object containing web.xml information
        WebBundleDescriptor wbd = wmInfo.getDescriptor();

        // Set the context root
        if (wbd != null) {
            ctx.setContextRoot(wbd.getContextRoot());
        } else {
            // Should never happen.
            _logger.log(Level.WARNING, "webContainer.unableSetContextRoot", wmInfo);
        }

        //
        // Ensure that the generated directory for JSPs in the document root
        // (i.e. those that are serviced by a system default-web-module)
        // is different for each virtual server.
        String wmInfoWorkDir = wmInfo.getWorkDir();
        if (wmInfoWorkDir != null) {
            StringBuilder workDir = new StringBuilder(wmInfo.getWorkDir());
            if (wmName.equals(Constants.DEFAULT_WEB_MODULE_NAME)) {
                workDir.append("-");
                workDir.append(FileUtils.makeFriendlyFilename(vs.getID()));
            }
            ctx.setWorkDir(workDir.toString());
        }

        ClassLoader parentLoader = wmInfo.getParentLoader();
        if (parentLoader == null) {
            // Use the shared classloader as the parent for all
            // standalone web-modules
            parentLoader = _serverContext.getSharedClassLoader();
        }
        ctx.setParentClassLoader(parentLoader);


        if (wbd != null) {
            // Determine if an alternate DD is set for this web-module in
            // the application
            ctx.configureAlternateDD(wbd);
            ctx.configureWebServices(wbd);
        }

        // Object containing sun-web.xml information
        SunWebApp iasBean = null;

        // The default context is the only case when wbd == null
        if (wbd != null) {
            iasBean = wbd.getSunDescriptor();
        }

        // set the sun-web config bean
        ctx.setIasWebAppConfigBean(iasBean);

        // Configure SingleThreadedServletPools, work/tmp directory etc
        ctx.configureMiscSettings(iasBean, vs, displayContextPath);

        // Configure alternate docroots if dummy web module
        if (ctx.getID().startsWith(Constants.DEFAULT_WEB_MODULE_NAME)) {
            ctx.setAlternateDocBases(vs.getProperties());
        }

        // Configure the class loader delegation model, classpath etc
        Loader loader = ctx.configureLoader(iasBean);

        // Set the class loader on the DOL object
        if (wbd != null && wbd.hasWebServices()) {
            wbd.addExtraAttribute("WEBLOADER", loader);
        }

        // Configure the session manager and other related settings
        ctx.configureSessionSettings(wbd, wmInfo);

        // set i18n info from locale-charset-info tag in sun-web.xml
        ctx.setI18nInfo();

        if (wbd != null) {
            String resourceType = wmInfo.getObjectType();
            boolean isSystem = resourceType != null &&
                    resourceType.startsWith("system-");
            // security will generate policy for system default web module
            if (!wmName.startsWith(Constants.DEFAULT_WEB_MODULE_NAME)) {
                // TODO : v3 : dochez Need to remove dependency on security
                Realm realm = habitat.getByContract(Realm.class);
                if ("null".equals(j2eeApplication)) {
                    /*
                     * Standalone webapps inherit the realm referenced by
                     * the virtual server on which they are being deployed,
                     * unless they specify their own
                     */
                    if (realm != null && realm instanceof RealmInitializer) {
                        ((RealmInitializer) realm).initializeRealm(
                                wbd, isSystem, vs.getAuthRealmName());
                        ctx.setRealm(realm);
                    }
                } else {
                    if (realm != null && realm instanceof RealmInitializer) {
                        ((RealmInitializer) realm).initializeRealm(
                                wbd, isSystem, null);
                        ctx.setRealm(realm);
                    }
                }
            }

            // post processing DOL object for standalone web module
            if (wbd.getApplication() != null &&
                    wbd.getApplication().isVirtual()) {
                wbd.visit(new WebValidatorWithoutCL());
            }
        }

        // Add virtual server mime mappings, if present
        addMimeMappings(ctx, vs.getMimeMap());

        String moduleName = Constants.DEFAULT_WEB_MODULE_NAME;
        String monitoringNodeName = moduleName;
        if (wbd != null && wbd.getApplication() != null) {
            // Not a dummy web module
            com.sun.enterprise.deployment.Application app =
                    wbd.getApplication();
            ctx.setStandalone(app.isVirtual());
            // S1AS BEGIN WORKAROUND FOR 6174360
            if (app.isVirtual()) {
                // Standalone web module
                moduleName = app.getRegistrationName();
                monitoringNodeName = wbd.getModuleID();
            } else {
                // Nested (inside EAR) web module
                moduleName = wbd.getModuleDescriptor().getArchiveUri();
                StringBuilder sb = new StringBuilder();
                sb.append(app.getRegistrationName()).
                        append(MONITORING_NODE_SEPARATOR).append(moduleName);
                monitoringNodeName = sb.toString().replaceAll("\\.", "\\\\.").
                        replaceAll("_war", "\\\\.war");
            }
            // S1AS END WORKAROUND FOR 6174360
        }
        ctx.setModuleName(moduleName);
        ctx.setMonitoringNodeName(monitoringNodeName);

        List<String> servletNames = new ArrayList<String>();
        if (wbd != null) {
            for (WebComponentDescriptor webCompDesc : wbd.getWebComponentDescriptors()) {
                if (webCompDesc.isServlet()) {
                    servletNames.add(webCompDesc.getCanonicalName());
                }
            }
        }

        webStatsProviderBootstrap.registerApplicationStatsProviders(monitoringNodeName,
                vs.getName(), servletNames);

        vs.addChild(ctx);

        ctx.loadSessions(deploymentProperties);

        return ctx;
    }


    /*
     * Updates the given virtual server with the given default path.
     *
     * The given default path corresponds to the context path of one of the
     * web contexts deployed on the virtual server that has been designated
     * as the virtual server's new default-web-module.
     *
     * @param virtualServer The virtual server to update
     * @param ports The port numbers of the HTTP listeners with which the
     * given virtual server is associated
     * @param defaultContextPath The context path of the web module that has
     * been designated as the virtual server's new default web module, or null
     * if the virtual server no longer has any default-web-module
     */

    protected void updateDefaultWebModule(VirtualServer virtualServer,
                                          String[] listenerNames,
                                          WebModuleConfig wmInfo)
            throws LifecycleException {

        String defaultContextPath = null;
        if (wmInfo != null) {
            defaultContextPath = wmInfo.getContextPath();
        }
        if (defaultContextPath != null
                && !defaultContextPath.startsWith("/")) {
            defaultContextPath = "/" + defaultContextPath;
            wmInfo.getDescriptor().setContextRoot(defaultContextPath);
        }

        Connector[] connectors = _embedded.findConnectors();
        for (Connector connector : connectors) {
            PECoyoteConnector conn = (PECoyoteConnector) connector;
            String name = conn.getName();
            for (String listenerName : listenerNames) {
                if (name.equals(listenerName)) {
                    Mapper mapper = conn.getMapper();
                    try {
                        mapper.setDefaultContextPath(virtualServer.getName(),
                                defaultContextPath);
                        for (String alias : virtualServer.findAliases()) {
                            mapper.setDefaultContextPath(alias,
                                    defaultContextPath);
                        }
                        virtualServer.setDefaultContextPath(defaultContextPath);
                    } catch (Exception e) {
                        throw new LifecycleException(e);
                    }
                }
            }
        }
    }


    /**
     * Utility Method to access the ServerContext
     */
    public ServerContext getServerContext() {
        return _serverContext;
    }


    ServerConfigLookup getServerConfigLookup() {
        return serverConfigLookup;
    }


    File getLibPath() {
        return instance.getLibPath();
    }


    /**
     * The application id for this web module
     * HERCULES:add
     */
    public String getApplicationId(WebModule wm) {
        return wm.getID();
    }


    /**
     * Return the Absolute path for location where all the deployed
     * standalone modules are stored for this Server Instance.
     */
    public File getModulesRoot() {
        return _modulesRoot;
    }


    /**
     * Get the persistence frequency for this web module
     * (this is the value from sun-web.xml if defined
     *
     * @param smBean the session manager config bean
     *               HERCULES:add
     */
    private String getPersistenceFrequency(SessionManager smBean) {
        String persistenceFrequency = null;
        ManagerProperties mgrBean = smBean.getManagerProperties();
        if (mgrBean != null && mgrBean.sizeWebProperty() > 0) {
            WebProperty[] props = mgrBean.getWebProperty();
            for (WebProperty prop : props) {
                String name = prop.getAttributeValue(WebProperty.NAME);
                String value = prop.getAttributeValue(WebProperty.VALUE);
                if (name == null || value == null) {
                    throw new IllegalArgumentException(
                            rb.getString("webcontainer.nullWebProperty"));
                }
                if (name.equalsIgnoreCase("persistenceFrequency")) {
                    persistenceFrequency = value;
                    break;
                }
            }
        }
        return persistenceFrequency;
    }

    /**
     * Get the persistence scope for this web module
     * (this is the value from sun-web.xml if defined
     *
     * @param smBean the session manager config bean
     *               HERCULES:add
     */
    private String getPersistenceScope(SessionManager smBean) {
        String persistenceScope = null;
        StoreProperties storeBean = smBean.getStoreProperties();
        if (storeBean != null && storeBean.sizeWebProperty() > 0) {
            WebProperty[] props = storeBean.getWebProperty();
            for (WebProperty prop : props) {
                String name = prop.getAttributeValue(WebProperty.NAME);
                String value = prop.getAttributeValue(WebProperty.VALUE);
                if (name == null || value == null) {
                    throw new IllegalArgumentException(
                            rb.getString("webcontainer.nullWebProperty"));
                }
                if (name.equalsIgnoreCase("persistenceScope")) {
                    persistenceScope = value;
                    break;
                }
            }
        }
        return persistenceScope;
    }


    /**
     * Undeploy a web application.
     *
     * @param contextRoot    the context's name to undeploy
     * @param appName        the J2EE appname used at deployment time
     * @param virtualServers List of current virtual-server object.
     */
    public void unloadWebModule(String contextRoot,
                                String appName,
                                String virtualServers,
                                Properties props) {
        unloadWebModule(contextRoot, appName, virtualServers, false, props);
    }

    /**
     * Undeploy a web application.
     *
     * @param contextRoot    the context's name to undeploy
     * @param appName        the J2EE appname used at deployment time
     * @param virtualServers List of current virtual-server object.
     * @param dummy          true if the web module to be undeployed is a dummy web
     *                       module, that is, a web module created off of a virtual server's
     *                       docroot
     */
    public void unloadWebModule(String contextRoot,
                                String appName,
                                String virtualServers,
                                boolean dummy,
                                Properties props) {

        if (_logger.isLoggable(Level.FINEST)) {
            _logger.finest("WebContainer.unloadWebModule(): contextRoot: "
                    + contextRoot + " appName:" + appName);
        }

        // tomcat contextRoot starts with "/"
        if (contextRoot.length() != 0 && !contextRoot.startsWith("/")) {
            contextRoot = "/" + contextRoot;
        } else if ("/".equals(contextRoot)) {
            // Make corresponding change as in WebModuleConfig.getContextPath()
            contextRoot = "";
        }

        List<String> hostList = StringUtils.parseStringList(virtualServers, " ,");
        boolean unloadFromAll = hostList == null || hostList.isEmpty();
        boolean hasBeenUndeployed = false;
        VirtualServer host = null;
        WebModule context = null;
        Container[] hostArray = getEngine().findChildren();
        for (Container aHostArray : hostArray) {
            host = (VirtualServer) aHostArray;
            if (unloadFromAll || hostList.contains(host.getName())
                    || verifyAlias(hostList, host)) {
                context = (WebModule) host.findChild(contextRoot);
                if (context != null) {
                    context.saveSessions(props);
                    host.removeChild(context);

                    webStatsProviderBootstrap.unregisterApplicationStatsProviders(
                            context.getMonitoringNodeName(), host.getName());

                    try {
                        /*
                         * If the webapp is being undeployed as part of a
                         * domain shutdown, we don't want to destroy it,
                         * as that would remove any sessions persisted to
                         * file. Any active sessions need to survive the
                         * domain shutdown, so that they may be resumed
                         * after the domain has been restarted.
                         */
                        if (!isShutdown) {
                            context.destroy();
                        }
                    } catch (Exception ex) {
                        String msg = rb.getString(
                                "webcontainer.webmodule.exceptionDuringDestroy");
                        msg = MessageFormat.format(msg, contextRoot,
                                host.getName());
                        _logger.log(Level.WARNING, msg, ex);
                    }
                    if (_logger.isLoggable(Level.FINEST)) {
                        _logger.log(Level.FINEST,
                                "[WebContainer] Context " + contextRoot
                                        + " undeployed from " + host);
                    }
                    hasBeenUndeployed = true;
                    host.fireContainerEvent(Deployer.REMOVE_EVENT, context);
                    /*
                     * If the web module that has been unloaded
                     * contained any mappings for ad-hoc paths,
                     * those mappings must be preserved by registering an
                     * ad-hoc web module at the same context root
                     */
                    if (context.hasAdHocPaths()
                            || context.hasAdHocSubtrees()) {
                        WebModule wm = createAdHocWebModule(
                                context.getID(),
                                host,
                                contextRoot,
                                context.getJ2EEApplication());
                        wm.addAdHocPaths(context.getAdHocPaths());
                        wm.addAdHocSubtrees(context.getAdHocSubtrees());
                    }
                    // START GlassFish 141
                    if (!dummy && !isShutdown) {
                        WebModuleConfig wmInfo =
                                host.createSystemDefaultWebModuleIfNecessary(
                                        habitat.getComponent(
                                                WebArchivist.class));
                        if (wmInfo != null) {
                            loadStandaloneWebModule(host, wmInfo);
                        }
                    }
                    // END GlassFish 141
                }
            }
        }

        if (!hasBeenUndeployed) {
            _logger.log(Level.SEVERE, "webContainer.undeployError", contextRoot);
        }
    }


    /**
     * Suspends the web application with the given appName that has been
     * deployed at the given contextRoot on the given virtual servers.
     *
     * @param contextRoot the context root
     * @param appName     the J2EE appname used at deployment time
     * @param hosts       the list of virtual servers
     */
    public boolean suspendWebModule(String contextRoot,
                                    String appName,
                                    String hosts) {
        boolean hasBeenSuspended = false;
        List<String> hostList = StringUtils.parseStringList(hosts, " ,");
        if (hostList == null || hostList.isEmpty()) {
            return hasBeenSuspended;
        }

        // tomcat contextRoot starts with "/"
        if (contextRoot.length() != 0 && !contextRoot.startsWith("/")) {
            contextRoot = "/" + contextRoot;
        }
        VirtualServer host = null;
        Context context = null;
        for (Container aHostArray : getEngine().findChildren()) {
            host = (VirtualServer) aHostArray;
            if (hostList.contains(host.getName()) ||
                    verifyAlias(hostList, host)) {
                context = (Context) host.findChild(contextRoot);
                if (context != null) {
                    context.setAvailable(false);
                    if (_logger.isLoggable(Level.FINEST)) {
                        _logger.log(Level.FINEST,
                                "[WebContainer] Context "
                                        + contextRoot + " disabled from "
                                        + host);
                    }
                    hasBeenSuspended = true;
                }
            }
        }

        if (!hasBeenSuspended) {
            _logger.log(Level.WARNING, "webContainer.disableWebModuleError", contextRoot);
        }

        return hasBeenSuspended;
    }


    /**
     * Save the server-wide dynamic reloading settings for use when
     * configuring each web module.
     */
    private void configureDynamicReloadingSettings() {
        if (dasConfig != null) {
            _reloadingEnabled = Boolean.parseBoolean(dasConfig.getDynamicReloadEnabled());
            String seconds = dasConfig.getDynamicReloadPollIntervalInSeconds();
            if (seconds != null) {
                try {
                    _pollInterval = Integer.parseInt(seconds);
                } catch (NumberFormatException e) {
                }
            }
        }
    }


    /**
     * Sets the debug level for Catalina's containers based on the logger's
     * log level.
     */
    private void setDebugLevel() {
        Level logLevel = _logger.getLevel() != null ?
                _logger.getLevel() : Level.INFO;
        if (logLevel.equals(Level.FINE))
            _debug = 1;
        else if (logLevel.equals(Level.FINER))
            _debug = 2;
        else if (logLevel.equals(Level.FINEST))
            _debug = 5;
        else
            _debug = 0;
    }


    /**
     * Get the lifecycle listeners associated with this lifecycle. If this
     * Lifecycle has no listeners registered, a zero-length array is returned.
     */
    public LifecycleListener[] findLifecycleListeners() {
        return new LifecycleListener[0];
    }


    /**
     * Gets all the virtual servers whose http-listeners attribute value
     * contains the given http-listener id.
     */
    List<VirtualServer> getVirtualServersForHttpListenerId(
            HttpService httpService, String httpListenerId) {

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

        List<VirtualServer> result = new ArrayList<VirtualServer>();

        for (com.sun.enterprise.config.serverbeans.VirtualServer vs : httpService.getVirtualServer()) {
            List<String> listeners = StringUtils.parseStringList(vs.getNetworkListeners(), ",");
            if (listeners != null) {
                ListIterator<String> iter = listeners.listIterator();
                while (iter.hasNext()) {
                    if (httpListenerId.equals(iter.next())) {
                        VirtualServer match = (VirtualServer)
                                getEngine().findChild(vs.getId());
                        if (match != null) {
                            result.add(match);
                        }
                        break;
                    }
                }
            }
        }

        return result;
    }


    /**
     * Adds the given mime mappings to those of the specified context, unless
     * they're already present in the context (that is, the mime mappings of
     * the specified context, which correspond to those in default-web.xml,
     * can't be overridden).
     *
     * @param ctx     The StandardContext to whose mime mappings to add
     * @param mimeMap The mime mappings to be added
     */
    private void addMimeMappings(StandardContext ctx, MimeMap mimeMap) {
        if (mimeMap == null) {
            return;
        }

        for (Iterator<String> itr = mimeMap.getExtensions(); itr.hasNext();) {
            String extension = itr.next();
            if (ctx.findMimeMapping(extension) == null) {
                ctx.addMimeMapping(extension, mimeMap.getType(extension));
            }
        }
    }

    /**
     * Return the parent/top-level container in _embedded for virtual
     * servers.
     */
    public Engine getEngine() {
        return _embedded.getEngines()[0];
    }


    /**
     * Registers the given ad-hoc path at the given context root.
     *
     * @param path        The ad-hoc path to register
     * @param ctxtRoot    The context root at which to register
     * @param appName     The name of the application with which the ad-hoc path is
     *                    associated
     * @param servletInfo Info about the ad-hoc servlet that will service
     *                    requests on the given path
     */
    public void registerAdHocPath(
            String path,
            String ctxtRoot,
            String appName,
            AdHocServletInfo servletInfo) {

        registerAdHocPathAndSubtree(path, null, ctxtRoot, appName,
                servletInfo);
    }


    /**
     * Registers the given ad-hoc path and subtree at the given context root.
     *
     * @param path        The ad-hoc path to register
     * @param subtree     The ad-hoc subtree path to register
     * @param ctxtRoot    The context root at which to register
     * @param appName     The name of the application with which the ad-hoc path
     *                    and subtree are associated
     * @param servletInfo Info about the ad-hoc servlet that will service
     *                    requests on the given ad-hoc path and subtree
     */
    public void registerAdHocPathAndSubtree(
            String path,
            String subtree,
            String ctxtRoot,
            String appName,
            AdHocServletInfo servletInfo) {

        WebModule wm = null;

        Container[] vsList = getEngine().findChildren();
        for (Container aVsList : vsList) {
            VirtualServer vs = (VirtualServer) aVsList;
            if (vs.getName().equalsIgnoreCase(
                    org.glassfish.api.web.Constants.ADMIN_VS)) {
                // Do not deploy on admin vs
                continue;
            }
            wm = (WebModule) vs.findChild(ctxtRoot);
            if (wm == null) {
                wm = createAdHocWebModule(vs, ctxtRoot, appName);
            }
            wm.addAdHocPathAndSubtree(path, subtree, servletInfo);
        }
    }


    /**
     * Unregisters the given ad-hoc path from the given context root.
     *
     * @param path     The ad-hoc path to unregister
     * @param ctxtRoot The context root from which to unregister
     */
    public void unregisterAdHocPath(String path, String ctxtRoot) {
        unregisterAdHocPathAndSubtree(path, null, ctxtRoot);
    }


    /**
     * Unregisters the given ad-hoc path and subtree from the given context
     * root.
     *
     * @param path     The ad-hoc path to unregister
     * @param subtree  The ad-hoc subtree to unregister
     * @param ctxtRoot The context root from which to unregister
     */
    public void unregisterAdHocPathAndSubtree(String path,
                                              String subtree,
                                              String ctxtRoot) {

        WebModule wm = null;

        Container[] vsList = getEngine().findChildren();
        for (Container aVsList : vsList) {
            VirtualServer vs = (VirtualServer) aVsList;
            if (vs.getName().equalsIgnoreCase(
                    org.glassfish.api.web.Constants.ADMIN_VS)) {
                // Do not undeploy from admin vs, because we never
                // deployed onto it
                continue;
            }
            wm = (WebModule) vs.findChild(ctxtRoot);
            if (wm == null) {
                continue;
            }
            /*
            * If the web module was created by the container for the
            * sole purpose of mapping ad-hoc paths and subtrees,
            * and does no longer contain any ad-hoc paths or subtrees,
            * remove the web module.
            */
            wm.removeAdHocPath(path);
            wm.removeAdHocSubtree(subtree);
            if (wm instanceof AdHocWebModule && !wm.hasAdHocPaths()
                    && !wm.hasAdHocSubtrees()) {
                vs.removeChild(wm);
                try {
                    wm.destroy();
                } catch (Exception ex) {
                    String msg = rb.getString(
                            "webcontainer.webmodule.exceptionDuringDestroy");
                    msg = MessageFormat.format(msg, wm.getPath(), vs.getName());
                    _logger.log(Level.WARNING, msg, ex);
                }
            }
        }
    }

    /*
     * Creates an ad-hoc web module and registers it on the given virtual
     * server at the given context root.
     *
     * @param vs The virtual server on which to add the ad-hoc web module
     * @param ctxtRoot The context root at which to register the ad-hoc
     * web module
     * @param appName The name of the application to which the ad-hoc module
     * being generated belongs
     *
     * @return The newly created ad-hoc web module
     */

    private WebModule createAdHocWebModule(
            VirtualServer vs,
            String ctxtRoot,
            String appName) {
        return createAdHocWebModule(appName, vs, ctxtRoot, appName);
    }

    /*
     * Creates an ad-hoc web module and registers it on the given virtual
     * server at the given context root.
     *
     * @param id the id of the ad-hoc web module
     * @param vs The virtual server on which to add the ad-hoc web module
     * @param ctxtRoot The context root at which to register the ad-hoc
     * web module
     * @param appName The name of the application to which the ad-hoc module
     * being generated belongs
     *
     * @return The newly created ad-hoc web module
     */

    private WebModule createAdHocWebModule(
            String id,
            VirtualServer vs,
            String ctxtRoot,
            String appName) {

        AdHocWebModule wm = new AdHocWebModule();
        wm.setID(id);
        wm.setWebContainer(this);

        wm.restrictedSetPipeline(new WebPipeline(wm));

        // The Parent ClassLoader of the AdhocWebModule was null
        // [System ClassLoader]. With the new hierarchy, the thread context
        // classloader needs to be set.
        //if (Boolean.getBoolean(com.sun.enterprise.server.PELaunch.USE_NEW_CLASSLOADER_PROPERTY)) {
        wm.setParentClassLoader(
                Thread.currentThread().getContextClassLoader());
        //}

        wm.setContextRoot(ctxtRoot);
        wm.setJ2EEApplication(appName);
        wm.setName(ctxtRoot);
        wm.setDocBase(vs.getAppBase());
        wm.setEngineName(vs.getParent().getName());

        String domain = _serverContext.getDefaultDomainName();
        wm.setDomain(domain);

        String j2eeServer = _serverContext.getInstanceName();
        wm.setJ2EEServer(j2eeServer);

        wm.setCrossContext(true);
        //wm.setJavaVMs(J2EEModuleUtil.getjavaVMs());

        vs.addChild(wm);

        return wm;
    }


    /**
     * Removes the dummy module (the module created off of a virtual server's
     * docroot) from the given virtual server if such a module exists.
     *
     * @param vs The virtual server whose dummy module is to be removed
     */
    void removeDummyModule(VirtualServer vs) {
        WebModule ctx = (WebModule) vs.findChild("");
        if (ctx != null
                && Constants.DEFAULT_WEB_MODULE_NAME.equals(
                ctx.getModuleName())) {
            unloadWebModule("", ctx.getJ2EEApplication(),
                    vs.getName(), true, null);
        }
    }


    /**
     * Initializes the instance-level session properties (read from
     * config.web-container.session-config.session-properties in domain.xml).
     */
    private void initInstanceSessionProperties() {

        SessionProperties spBean =
                serverConfigLookup.getInstanceSessionProperties();

        if (spBean == null || spBean.getProperty() == null) {
            return;
        }

        List<Property> props = spBean.getProperty();
        if (props == null) {
            return;
        }

        for (Property prop : props) {
            String propName = prop.getName();
            String propValue = prop.getValue();
            if (propName == null || propValue == null) {
                throw new IllegalArgumentException(
                        rb.getString("webcontainer.nullWebProperty"));
            }

            if (propName.equalsIgnoreCase("enableCookies")) {
                instanceEnableCookies = ConfigBeansUtilities.toBoolean(propValue);
            } else if (_logger.isLoggable(Level.INFO)) {
                Object[] params = {propName};
                _logger.log(Level.INFO, "webcontainer.notYet", params);
            }
        }
    }

    private static synchronized void setJspFactory() {
        if (JspFactory.getDefaultFactory() == null) {
            JspFactory.setDefaultFactory(new JspFactoryImpl());
        }
    }


    /**
     * Delete virtual-server.
     *
     * @param httpService element which contains the configuration info.
     */
    public void deleteHost(HttpService httpService) throws LifecycleException {

        VirtualServer virtualServer;

        // First we need to find which virtual-server was deleted. In
        // reconfig/VirtualServerReconfig, it is impossible to lookup
        // the vsBean because the element is removed from domain.xml
        // before handleDelete is invoked.
        Container[] virtualServers = getEngine().findChildren();
        for (int i = 0; i < virtualServers.length; i++) {
            for (com.sun.enterprise.config.serverbeans.VirtualServer vse : httpService.getVirtualServer()) {
                if (virtualServers[i].getName().equals(vse.getId())) {
                    virtualServers[i] = null;
                    break;
                }
            }
        }
        for (Container virtualServer1 : virtualServers) {
            virtualServer = (VirtualServer) virtualServer1;
            if (virtualServer != null) {
                if (virtualServer.getID().equals(
                        org.glassfish.api.web.Constants.ADMIN_VS)) {
                    throw new LifecycleException(
                            "Cannot delete admin virtual-server.");
                }
                Container[] webModules = virtualServer.findChildren();
                for (Container webModule : webModules) {
                    unloadWebModule(webModule.getName(),
                            webModule.getName(),
                            virtualServer.getID(),
                            null);
                }
                try {
                    virtualServer.destroy();
                } catch (Exception e) {
                    String msg = rb.getString("webContainer.destroyVsError");
                    msg = MessageFormat.format(msg, virtualServer.getID());
                    _logger.log(Level.WARNING, msg, e);
                }
            }
        }
    }


    /**
     * Updates a virtual-server element.
     *
     * @param vsBean the virtual-server config bean.
     */
    public void updateHost(com.sun.enterprise.config.serverbeans.VirtualServer vsBean) throws LifecycleException {

        if (org.glassfish.api.web.Constants.ADMIN_VS.equals(vsBean.getId())) {
            return;
        }
        final VirtualServer vs = (VirtualServer) getEngine().findChild(vsBean.getId());

        if (vs == null) {
            _logger.log(Level.WARNING, "webContainer.cannotUpdateNonExistenceVs", vsBean.getId());
            return;
        }

        boolean updateListeners = false;

        // Only update connectors if virtual-server.http-listeners is changed dynamically
        if (vs.getNetworkListeners() == null) {
            if (vsBean.getNetworkListeners() == null) {
                updateListeners = false;
            } else {
                updateListeners = true;
            }
        } else if (vs.getNetworkListeners().equals(vsBean.getNetworkListeners())) {
            updateListeners = false;
        } else {
            List<String> vsList = StringUtils.parseStringList(
                vs.getNetworkListeners(), ",");
            List<String> vsBeanList = StringUtils.parseStringList(
                vsBean.getNetworkListeners(), ",");
            for (String vsBeanName : vsBeanList) {
                if (!vsList.contains(vsBeanName)) {
                    updateListeners = true;
                    if (_logger.isLoggable(Level.FINE)) {
                        _logger.fine(vsBeanName
                                + "is not included network listeners "
                                + vs.getNetworkListeners());
                    }
                    break;
                }
            }
        }

        // Must retrieve the old default-web-module before updating the
        // virtual server with the new vsBean, because default-web-module is
        // read from vsBean
        String oldDefaultWebModule = vs.getDefaultWebModuleID();

        vs.setBean(vsBean);

        String vsLogFile = vsBean.getLogFile();
        vs.setLogFile(vsLogFile, logLevel, logServiceFile);

        vs.configureState();

        vs.clearAliases();
        vs.configureAliases();

        // support both docroot property and attribute
        String docroot = vsBean.getPropertyValue("docroot");
        if (docroot == null) {
            docroot = vsBean.getDocroot();
        }
        if (docroot != null) {
            // Only update docroot if it is modified
            if (!vs.getDocRoot().getAbsolutePath().equals(docroot)) {
                updateDocroot(docroot, vs, vsBean);
            }
        }

        List<Property> props = vs.getProperties();
        for (Property prop : props) {
            updateHostProperties(vsBean, prop.getName(), prop.getValue(), securityService, vs);
        }
        vs.configureSingleSignOn(globalSSOEnabled, webContainerFeatureFactory, isSsoFailoverEnabled());
        vs.reconfigureAccessLog(globalAccessLogBufferSize, globalAccessLogWriteInterval, habitat, domain,
                globalAccessLoggingEnabled);

        // old listener names
        List<String> oldListenerList = StringUtils.parseStringList(
                vsBean.getNetworkListeners(), ",");
        String[] oldListeners = (oldListenerList != null) ?
                oldListenerList.toArray(new String[oldListenerList.size()]) :
                new String[0];
        // new listener config
        HashSet<NetworkListener> networkListeners = new HashSet<NetworkListener>();
        if (oldListenerList != null) {
            for (String listener : oldListeners) {
                boolean found = false;
                for (NetworkListener httpListener :
                        serverConfig.getNetworkConfig().getNetworkListeners().getNetworkListener()) {
                    if (httpListener.getName().equals(listener)) {
                        networkListeners.add(httpListener);
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    String msg = rb.getString(
                            "webcontainer.listenerReferencedByHostNotExist");
                    msg = MessageFormat.format(msg, listener, vs.getName());
                    _logger.log(Level.SEVERE, msg);
                }
            }
            // Update the port numbers with which the virtual server is
            // associated
            configureHostPortNumbers(vs, networkListeners);
        } else {
            // The virtual server is not associated with any http listeners
            vs.setNetworkListenerNames(new String[0]);
        }

        // Disassociate the virtual server from all http listeners that
        // have been removed from its http-listeners attribute
        for (String oldListener : oldListeners) {
            boolean found = false;
            for (NetworkListener httpListener : networkListeners) {
                if (httpListener.getName().equals(oldListener)) {
                    found = true;
                }
            }
            if (!found) {
                // http listener was removed
                Connector[] connectors = _embedded.findConnectors();
                for (Connector connector : connectors) {
                    WebConnector conn = (WebConnector) connector;
                    if (oldListener.equals(conn.getName())) {
                        try {
                            conn.getMapperListener().unregisterHost(
                                    vs.getJmxName());
                        } catch (Exception e) {
                            throw new LifecycleException(e);
                        }
                    }
                }

            }
        }

        // Associate the virtual server with all http listeners that
        // have been added to its http-listeners attribute
        for (NetworkListener httpListener : networkListeners) {
            boolean found = false;
            for (String oldListener : oldListeners) {
                if (httpListener.getName().equals(oldListener)) {
                    found = true;
                }
            }
            if (!found) {
                // http listener was added
                Connector[] connectors = _embedded.findConnectors();
                for (Connector connector : connectors) {
                    WebConnector conn = (WebConnector)
                            connector;
                    if (httpListener.getName().equals(conn.getName())) {
                        if (!conn.isAvailable()) {
                            conn.start();
                        }
                        try {
                            conn.getMapperListener().registerHost(
                                    vs.getJmxName());
                        } catch (Exception e) {
                            throw new LifecycleException(e);
                        }
                    }
                }
            }
        }

        // Remove the old default web module if one was configured, by
        // passing in "null" as the default context path
        if (oldDefaultWebModule != null) {
            updateDefaultWebModule(vs, oldListeners, null);
        }

        /*
         * Add default web module if one has been configured for the
         * virtual server. If the module declared as the default web module
         * has already been deployed at the root context, we don't have
         * to do anything.
         */
        WebModuleConfig wmInfo = vs.getDefaultWebModule(domain,
                habitat.getComponent(WebArchivist.class),
                appRegistry);
        if ((wmInfo != null) && (wmInfo.getContextPath() != null) &&
                !"".equals(wmInfo.getContextPath()) &&
                !"/".equals(wmInfo.getContextPath())) {
            // Remove dummy context that was created off of docroot, if such
            // a context exists
            removeDummyModule(vs);
            updateDefaultWebModule(vs,
                    vs.getNetworkListenerNames(),
                    wmInfo);
        } else {
            WebModuleConfig wmc =
                    vs.createSystemDefaultWebModuleIfNecessary(
                            habitat.getComponent(WebArchivist.class));
            if (wmc != null) {
                loadStandaloneWebModule(vs, wmc);
            }
        }

        if (updateListeners) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("Virtual server " + vs.getName()
                        + " network listeners are updated from "
                        + vs.getNetworkListeners() +" to " + vsBean.getNetworkListeners());
            }
            /*
             * Need to update connector and mapper restart is required
             * when virtual-server.http-listeners is changed dynamically
             */
            List<NetworkListener> httpListeners =
                    serverConfig.getNetworkConfig().getNetworkListeners().getNetworkListener();
            if (httpListeners != null) {
                for (NetworkListener httpListener : httpListeners) {
                    updateConnector(httpListener, habitat.getByType(HttpService.class));
                }
            }
        }

    }


    /**
     * Update virtual-server properties.
     */
    public void updateHostProperties(
            com.sun.enterprise.config.serverbeans.VirtualServer vsBean,
            String name, String value, SecurityService securityService, final VirtualServer vs) {
        if (vs == null) {
            return;
        }
        vs.setBean(vsBean);

        if (name == null) {
            return;
        }

        if (name.startsWith("alternatedocroot_")) {
            updateAlternateDocroot(vs);
        } else if ("setCacheControl".equals(name)) {
            vs.configureCacheControl(value);
        } else if (Constants.ACCESS_LOGGING_ENABLED.equals(name)) {
            vs.reconfigureAccessLog(globalAccessLogBufferSize,
                    globalAccessLogWriteInterval, habitat, domain,
                    globalAccessLoggingEnabled);
        } else if (Constants.ACCESS_LOG_PROPERTY.equals(name)) {
            vs.reconfigureAccessLog(globalAccessLogBufferSize,
                    globalAccessLogWriteInterval, habitat, domain,
                    globalAccessLoggingEnabled);
        } else if (Constants.ACCESS_LOG_WRITE_INTERVAL_PROPERTY.equals(name)) {
            vs.reconfigureAccessLog(globalAccessLogBufferSize,
                    globalAccessLogWriteInterval,
                    habitat,
                    domain,
                    globalAccessLoggingEnabled);
        } else if (Constants.ACCESS_LOG_BUFFER_SIZE_PROPERTY.equals(name)) {
            vs.reconfigureAccessLog(globalAccessLogBufferSize,
                    globalAccessLogWriteInterval,
                    habitat,
                    domain,
                    globalAccessLoggingEnabled);
        } else if ("allowRemoteHost".equals(name)
                || "denyRemoteHost".equals(name)) {
            vs.configureRemoteHostFilterValve();
        } else if ("allowRemoteAddress".equals(name)
                || "denyRemoteAddress".equals(name)) {
            vs.configureRemoteAddressFilterValve();
        } else if (Constants.SSO_ENABLED.equals(name)) {
            vs.configureSingleSignOn(globalSSOEnabled, webContainerFeatureFactory, isSsoFailoverEnabled());
        } else if ("authRealm".equals(name)) {
            vs.configureAuthRealm(securityService);
        } else if (name.startsWith("send-error")) {
            vs.configureErrorPage();
        } else if (Constants.ERROR_REPORT_VALVE.equals(name)) {
            vs.setErrorReportValveClass(value);
        } else if (name.startsWith("redirect")) {
            vs.configureRedirect();
        } else if (name.startsWith("contextXmlDefault")) {
            vs.setDefaultContextXmlLocation(value);
        }
    }

    private boolean isSsoFailoverEnabled() {
        boolean webContainerAvailabilityEnabled =
            serverConfigLookup.calculateWebAvailabilityEnabledFromConfig();
        boolean isSsoFailoverEnabled =
            serverConfigLookup.isSsoFailoverEnabledFromConfig();
        return isSsoFailoverEnabled && webContainerAvailabilityEnabled;
    }

    /**
     * Processes an update to the http-service element
     */
    public void updateHttpService(HttpService httpService) throws LifecycleException {

        if (httpService == null) {
            return;
        }

        /*
         * Update each virtual server with the sso-enabled and
         * access logging related properties of the updated http-service
         */
        globalSSOEnabled = ConfigBeansUtilities.toBoolean(httpService.getSsoEnabled());
        globalAccessLogWriteInterval = httpService.getAccessLog().getWriteIntervalSeconds();
        globalAccessLogBufferSize = httpService.getAccessLog().getBufferSizeBytes();
        globalAccessLoggingEnabled = ConfigBeansUtilities.toBoolean(httpService.getAccessLoggingEnabled());

        // for availability-service.web-container-availability
        webContainerFeatureFactory = getWebContainerFeatureFactory();

        List<com.sun.enterprise.config.serverbeans.VirtualServer> virtualServers =
                httpService.getVirtualServer();
        for (com.sun.enterprise.config.serverbeans.VirtualServer virtualServer : virtualServers) {
            final VirtualServer vs = (VirtualServer) getEngine().findChild(virtualServer.getId());
            if (vs != null) {
                vs.configureSingleSignOn(globalSSOEnabled, webContainerFeatureFactory, isSsoFailoverEnabled());
                vs.reconfigureAccessLog(globalAccessLogBufferSize, globalAccessLogWriteInterval, habitat, domain,
                        globalAccessLoggingEnabled);
                updateHost(virtualServer);
            }
        }

    }


    /**
     * Update an http-listener property
     *
     * @param listener  the configuration bean.
     * @param propName  the property name
     * @param propValue the property value
     */
    public void updateConnectorProperty(NetworkListener listener,
                                        String propName,
                                        String propValue)
            throws LifecycleException {

        WebConnector connector = connectorMap.get(listener.getName());
        if (connector != null) {
            connector.configHttpProperties(listener.findHttpProtocol().getHttp(),
                    listener.findTransport(), listener.findHttpProtocol().getSsl());
            connector.configureHttpListenerProperty(propName, propValue);
        }
    }


    /**
     * Update an network-listener
     *
     * @param httpService the configuration bean.
     */
    public void updateConnector(NetworkListener networkListener,
                                HttpService httpService)
            throws LifecycleException {

        synchronized (mapperUpdateSync) {
            // Disable dynamic reconfiguration of the http listener at which
            // the admin related webapps (including the admingui) are accessible.
            // Notice that in GlassFish v3, we support a domain.xml configuration
            // that does not declare any admin-listener, in which case the
            // admin-related webapps are accessible on http-listener-1.
            if (networkListener.findHttpProtocol().getHttp().getDefaultVirtualServer().equals(
                    org.glassfish.api.web.Constants.ADMIN_VS) ||
                    "http-listener-1".equals(networkListener.getName()) &&
                            connectorMap.get("admin-listener") == null) {
                return;
            }

            WebConnector connector = connectorMap.get(networkListener.getName());
            if (connector != null) {
                deleteConnector(connector);
            }

            if (!Boolean.valueOf(networkListener.getEnabled())) {
                return;
            }

            connector = addConnector(networkListener, httpService, false);

            // Update the list of listener names of all associated virtual servers with
            // the listener's new listener name , so that the associated virtual
            // servers will be registered with the listener's request mapper when
            // the listener is started
            List<VirtualServer> virtualServers =
                    getVirtualServersForHttpListenerId(httpService, networkListener.getName());
            if (virtualServers != null) {
                Mapper mapper = connector.getMapper();
                for (VirtualServer vs : virtualServers) {
                    boolean found = false;
                    String[] listenerNames = vs.getNetworkListenerNames();
                    String name = connector.getName();
                    for (String listenerName : listenerNames) {
                        if (listenerName.equals(name)) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        String[] newListenerNames = new String[listenerNames.length + 1];
                        System.arraycopy(listenerNames, 0, newListenerNames, 0, listenerNames.length);
                        newListenerNames[listenerNames.length] = connector.getName();
                        vs.setNetworkListenerNames(newListenerNames);
                    }

                    // Check if virtual server has default-web-module configured,
                    // and if so, configure the http listener's mapper with this
                    // information
                    String defaultWebModulePath = vs.getDefaultContextPath(
                            domain, appRegistry);
                    if (defaultWebModulePath != null) {
                        try {
                            mapper.setDefaultContextPath(vs.getName(),
                                    defaultWebModulePath);
                            vs.setDefaultContextPath(defaultWebModulePath);
                        } catch (Exception e) {
                            throw new LifecycleException(e);
                        }
                    }
                }
            }

            connector.start();
        }
    }

    /**
     * Method gets called, when GrizzlyService changes HTTP Mapper, associated
     * with specific port.
     *
     * @param httpService  {@link HttpService}
     * @param httpListener {@link NetworkListener}, which {@link Mapper} was changed
     * @param mapper       new {@link Mapper} value
     */
    public void updateMapper(HttpService httpService, NetworkListener httpListener,
                             Mapper mapper) {
        synchronized (mapperUpdateSync) {
            WebConnector connector = connectorMap.get(httpListener.getName());
            if (connector != null && connector.getMapper() != mapper) {
                try {
                    updateConnector(httpListener, httpService);
                } catch (LifecycleException le) {
                    _logger.log(Level.SEVERE, "webcontainer.exceptionConfigHttpService", le);
                }
            }
        }
    }


    public WebConnector addConnector(NetworkListener httpListener,
                                     HttpService httpService,
                                     boolean start)
            throws LifecycleException {

        synchronized (mapperUpdateSync) {
            int port = Integer.parseInt(httpListener.getPort());

            // Add the listener name of the new http-listener to its
            // default-virtual-server, so that when the new http-listener
            // and its MapperListener are started, they will recognize the
            // default-virtual-server as one of their own, and add it to the
            // Mapper
            String virtualServerName = httpListener.findHttpProtocol().getHttp().getDefaultVirtualServer();
            VirtualServer vs =
                    (VirtualServer) getEngine().findChild(virtualServerName);
            List<String> list = Arrays.asList(vs.getNetworkListenerNames());
            // Avoid adding duplicate network-listener name
            if (!list.contains(httpListener.getName())) {
                String[] oldListenerNames = vs.getNetworkListenerNames();
                String[] newListenerNames = new String[oldListenerNames.length + 1];
                System.arraycopy(oldListenerNames, 0, newListenerNames, 0, oldListenerNames.length);
                newListenerNames[oldListenerNames.length] = httpListener.getName();
                vs.setNetworkListenerNames(newListenerNames);
            }

            Mapper mapper = null;
            for (Mapper m : habitat.getAllByContract(Mapper.class)) {
                if (m.getPort() == port && m instanceof ContextMapper) {
                    ContextMapper cm = (ContextMapper) m;
                    if (httpListener.getName().equals(cm.getId())) {
                        mapper = m;
                        break;
                    }
                }
            }

            WebConnector connector = null;
            if (ConfigBeansUtilities.toBoolean(httpListener.getJkEnabled())) {
                connector = createJKConnector(httpListener, httpService);
            } else {
                connector = createHttpListener(httpListener, httpService, mapper);
            }

            if (connector.getRedirectPort() == -1) {
                connector.setRedirectPort(defaultRedirectPort);
            }

            if (start) {
                connector.start();
            }
            return connector;
        }
    }


    /**
     * Stops and deletes the specified http listener.
     */
    public void deleteConnector(WebConnector connector)
            throws LifecycleException {

        String name = connector.getName();

        Connector[] connectors = _embedded.findConnectors();
        for (Connector conn : connectors) {
            if (name.equals(conn.getName())) {
                _embedded.removeConnector(conn);
                connectorMap.remove(connector.getName());
            }
        }
    }


    /**
     * Stops and deletes the specified http listener.
     */
    public void deleteConnector(NetworkListener httpListener)
            throws LifecycleException {

        Connector[] connectors = _embedded.findConnectors();
        String name = httpListener.getName();
        for (Connector conn : connectors) {
            if (name.equals(conn.getName())) {
                _embedded.removeConnector(conn);
                connectorMap.remove(name);
            }
        }

    }


    /**
     * Reconfigures the access log valve of each virtual server with the
     * updated attributes of the <access-log> element from domain.xml.
     */
    public void updateAccessLog(HttpService httpService) {
        Container[] virtualServers = getEngine().findChildren();
        for (Container virtualServer : virtualServers) {
            ((VirtualServer) virtualServer).reconfigureAccessLog(
                    httpService, webContainerFeatureFactory);
        }
    }


    /**
     * Updates the docroot of the given virtual server
     */
    private void updateDocroot(
            String docroot,
            VirtualServer vs,
            com.sun.enterprise.config.serverbeans.VirtualServer vsBean) {

        validateDocroot(docroot, vsBean.getId(),
                vsBean.getDefaultWebModule());
        vs.setAppBase(docroot);
        removeDummyModule(vs);
        WebModuleConfig wmInfo =
                vs.createSystemDefaultWebModuleIfNecessary(
                        habitat.getComponent(WebArchivist.class));
        if (wmInfo != null) {
            loadStandaloneWebModule(vs, wmInfo);
        }
    }


    private void updateAlternateDocroot(VirtualServer vs) {
        removeDummyModule(vs);
        WebModuleConfig wmInfo = vs.createSystemDefaultWebModuleIfNecessary(
                habitat.getComponent(WebArchivist.class));
        if (wmInfo != null) {
            loadStandaloneWebModule(vs, wmInfo);
        }
    }


    /**
     * is Tomcat using default domain name as its domain
     */
    protected boolean isTomcatUsingDefaultDomain() {
        // need to be careful and make sure tomcat jmx mapping works
        // since setting this to true might result in undeployment problems
        return true;
    }


    /**
     * Creates probe providers for Servlet, JSP, Session, and
     * Request/Response related events.
     * <p/>
     * While the Servlet, JSP, and Session related probe providers are
     * shared by all web applications (where every web application
     * qualifies its probe events with its application name), the
     * Request/Response related probe provider is shared by all HTTP
     * listeners.
     */
    private void createProbeProviders() {
        webModuleProbeProvider = new WebModuleProbeProvider();
        servletProbeProvider = new ServletProbeProvider();
        jspProbeProvider = new JspProbeProvider();
        sessionProbeProvider = new SessionProbeProvider();
        requestProbeProvider = new RequestProbeProvider();
    }


    /**
     * Creates statistics providers for Servlet, JSP, Session, and
     * Request/Response related events.
     */
    private void createStatsProviders() {
        HttpServiceStatsProviderBootstrap httpStatsProviderBootstrap =
                habitat.getByType(HttpServiceStatsProviderBootstrap.class);
        webStatsProviderBootstrap =
                habitat.getByType(WebStatsProviderBootstrap.class);
    }


    /*
     * Loads the class with the given name using the common classloader,
     * which is responsible for loading any classes from the domain's
     * lib directory
     *
     * @param className the name of the class to load
     */

    public Class loadCommonClass(String className) throws Exception {
        return clh.getCommonClassLoader().loadClass(className);
    }

    /**
     * According to SRV 15.5.15, Servlets, Filters, Listeners can only be
     * without any scope annotation or are annotated with
     *
     * @Dependent scope. All other scopes are invalid and must be rejected.
     */
    private void validateJSR299Scope(Class<?> clazz) {
        if (jcdiService != null && jcdiService.isCDIScoped(clazz)) {
            String msg = rb.getString("webcontainer.invalidAnnotationScope");
            msg = MessageFormat.format(msg, clazz.getName());
            throw new IllegalArgumentException(msg);
        }
    }

    /**
     * Return the WebContainerFeatureFactory according to the configuration.
     * @return WebContainerFeatuerFactory
     */
    private WebContainerFeatureFactory getWebContainerFeatureFactory() {
        String featureFactoryName =
                    (serverConfigLookup.calculateWebAvailabilityEnabledFromConfig() ? "ha" : "pe");
        return webContainerFeatureFactory = habitat.getComponent(
                    WebContainerFeatureFactory.class, featureFactoryName);
    }
}
TOP

Related Classes of com.sun.enterprise.web.WebContainer

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.