org.apache.catalina.core.StandardHost.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.catalina.core.StandardHost.java

Source

/*
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *catalina run
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * [Additional notices, if required by prior licensing conditions]
 *
 */

package org.apache.catalina.core;

import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.DefaultContext;
import org.apache.catalina.Deployer;
import org.apache.catalina.Host;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Valve;
import org.apache.catalina.valves.ValveBase;
import org.apache.commons.modeler.Registry;

/**
 * Standard implementation of the <b>Host</b> interface.  Each
 * child container must be a Context implementation to process the
 * requests directed to a particular web application.
 *
 * @author Craig R. McClanahan
 * @author Remy Maucherat
 * @version $Revision: 1.27 $ $Date: 2004/01/08 05:32:25 $
 */

public class StandardHost extends ContainerBase implements Deployer, Host {
    /* Why do we implement deployer and delegate to deployer ??? */

    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
            .getLog(StandardHost.class);

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

    /**
     * Create a new StandardHost component with the default basic Valve.
     */
    public StandardHost() {

        super();
        pipeline.setBasic(new StandardHostValve());

    }

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

    /**
     * The set of aliases for this Host.
     */
    private String[] aliases = new String[0];

    /**
     * The application root for this Host.
     */
    private String appBase = ".";

    /**
     * The auto deploy flag for this Host.
     */
    private boolean autoDeploy = true;

    /**
     * The Java class name of the default context configuration class
     * for deployed web applications.
     */
    private String configClass = "org.apache.catalina.startup.ContextConfig";

    /**
     * The Java class name of the default Context implementation class for
     * deployed web applications.
     */
    private String contextClass = "org.apache.catalina.core.StandardContext";

    /**
     * The <code>Deployer</code> to whom we delegate application
     * deployment requests.
     */
    private Deployer deployer = null;

    /**
     * The deploy on startup flag for this Host.
     */
    private boolean deployOnStartup = true;

    /**
     * deploy Context XML config files property.
     */
    private boolean deployXML = true;

    /**
     * The Java class name of the default error reporter implementation class 
     * for deployed web applications.
     */
    private String errorReportValveClass = "org.apache.catalina.valves.ErrorReportValve";

    /**
     * The object name for the errorReportValve.
     */
    private ObjectName errorReportValveObjectName = null;

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

    /**
     * The live deploy flag for this Host.
     */
    private boolean liveDeploy = true;

    /**
     * Unpack WARs property.
     */
    private boolean unpackWARs = true;

    /**
     * Work Directory base for applications.
     */
    private String workDir = null;

    /**
     * DefaultContext config
     */
    private DefaultContext defaultContext;

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

    /**
     * Attribute value used to turn on/off XML namespace awarenes.
     */
    private boolean xmlNamespaceAware = false;

    // ------------------------------------------------------------- Properties

    /**
     * Return the application root for this Host.  This can be an absolute
     * pathname, a relative pathname, or a URL.
     */
    public String getAppBase() {

        return (this.appBase);

    }

    /**
     * Set the application root for this Host.  This can be an absolute
     * pathname, a relative pathname, or a URL.
     *
     * @param appBase The new application root
     */
    public void setAppBase(String appBase) {

        String oldAppBase = this.appBase;
        this.appBase = appBase;
        support.firePropertyChange("appBase", oldAppBase, this.appBase);

    }

    /**
     * Return the value of the auto deploy flag.  If true, it indicates that 
     * this host's child webapps will be dynamically deployed.
     */
    public boolean getAutoDeploy() {

        return (this.autoDeploy);

    }

    /**
     * Set the auto deploy flag value for this host.
     * 
     * @param autoDeploy The new auto deploy flag
     */
    public void setAutoDeploy(boolean autoDeploy) {

        boolean oldAutoDeploy = this.autoDeploy;
        this.autoDeploy = autoDeploy;
        support.firePropertyChange("autoDeploy", oldAutoDeploy, this.autoDeploy);

    }

    /**
     * Return the Java class name of the context configuration class
     * for new web applications.
     */
    public String getConfigClass() {

        return (this.configClass);

    }

    /**
     * Set the Java class name of the context configuration class
     * for new web applications.
     *
     * @param configClass The new context configuration class
     */
    public void setConfigClass(String configClass) {

        String oldConfigClass = this.configClass;
        this.configClass = configClass;
        support.firePropertyChange("configClass", oldConfigClass, this.configClass);

    }

    /**
     * Set the DefaultContext
     * for new web applications.
     *
     * @param defaultContext The new DefaultContext
     */
    public void addDefaultContext(DefaultContext defaultContext) {

        DefaultContext oldDefaultContext = this.defaultContext;
        this.defaultContext = defaultContext;
        support.firePropertyChange("defaultContext", oldDefaultContext, this.defaultContext);

    }

    /**
     * Retrieve the DefaultContext for new web applications.
     */
    public DefaultContext getDefaultContext() {
        return (this.defaultContext);
    }

    /**
     * Return the Java class name of the Context implementation class
     * for new web applications.
     */
    public String getContextClass() {

        return (this.contextClass);

    }

    /**
     * Set the Java class name of the Context implementation class
     * for new web applications.
     *
     * @param contextClass The new context implementation class
     */
    public void setContextClass(String contextClass) {

        String oldContextClass = this.contextClass;
        this.contextClass = contextClass;
        support.firePropertyChange("contextClass", oldContextClass, this.contextClass);

    }

    /**
     * Return the value of the deploy on startup flag.  If true, it indicates 
     * that this host's child webapps should be discovred and automatically 
     * deployed at startup time.
     */
    public boolean getDeployOnStartup() {

        return (this.deployOnStartup);

    }

    /**
     * Set the deploy on startup flag value for this host.
     * 
     * @param autoDeploy The new deploy on startup flag
     */
    public void setDeployOnStartup(boolean deployOnStartup) {

        boolean oldDeployOnStartup = this.deployOnStartup;
        this.deployOnStartup = deployOnStartup;
        support.firePropertyChange("deployOnStartup", oldDeployOnStartup, this.deployOnStartup);

    }

    /**
     * Deploy XML Context config files flag accessor.
     */
    public boolean isDeployXML() {

        return (deployXML);

    }

    /**
     * Deploy XML Context config files flag mutator.
     */
    public void setDeployXML(boolean deployXML) {

        this.deployXML = deployXML;

    }

    /**
     * Return the value of the live deploy flag.  If true, it indicates that 
     * a background thread should be started that looks for web application
     * context files, WAR files, or unpacked directories being dropped in to
     * the <code>appBase</code> directory, and deploys new ones as they are
     * encountered.
     */
    public boolean getLiveDeploy() {
        return (this.autoDeploy);
    }

    /**
     * Set the live deploy flag value for this host.
     * 
     * @param liveDeploy The new live deploy flag
     */
    public void setLiveDeploy(boolean liveDeploy) {
        setAutoDeploy(liveDeploy);
    }

    /**
     * Return the Java class name of the error report valve class
     * for new web applications.
     */
    public String getErrorReportValveClass() {

        return (this.errorReportValveClass);

    }

    /**
     * Set the Java class name of the error report valve class
     * for new web applications.
     *
     * @param errorReportValveClass The new error report valve class
     */
    public void setErrorReportValveClass(String errorReportValveClass) {

        String oldErrorReportValveClassClass = this.errorReportValveClass;
        this.errorReportValveClass = errorReportValveClass;
        support.firePropertyChange("errorReportValveClass", oldErrorReportValveClassClass,
                this.errorReportValveClass);

    }

    /**
     * Return the canonical, fully qualified, name of the virtual host
     * this Container represents.
     */
    public String getName() {

        return (name);

    }

    /**
     * Set the canonical, fully qualified, name of the virtual host
     * this Container represents.
     *
     * @param name Virtual host name
     *
     * @exception IllegalArgumentException if name is null
     */
    public void setName(String name) {

        if (name == null)
            throw new IllegalArgumentException(sm.getString("standardHost.nullName"));

        name = name.toLowerCase(); // Internally all names are lower case

        String oldName = this.name;
        this.name = name;
        support.firePropertyChange("name", oldName, this.name);

    }

    /**
     * Unpack WARs flag accessor.
     */
    public boolean isUnpackWARs() {

        return (unpackWARs);

    }

    /**
     * Unpack WARs flag mutator.
     */
    public void setUnpackWARs(boolean unpackWARs) {

        this.unpackWARs = unpackWARs;

    }

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

        this.xmlValidation = xmlValidation;

    }

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

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

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

    /**
     * Host work directory base.
     */
    public String getWorkDir() {

        return (workDir);
    }

    /**
     * Host work directory base.
     */
    public void setWorkDir(String workDir) {

        this.workDir = workDir;
    }

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

    /**
     * Install the StandardContext portion of the DefaultContext
     * configuration into current Context.
     *
     * @param context current web application context
     */
    public void installDefaultContext(Context context) {

        if (defaultContext != null && defaultContext instanceof StandardDefaultContext) {

            ((StandardDefaultContext) defaultContext).installDefaultContext(context);
        }

    }

    /**
     * Import the DefaultContext config into a web application context.
     *
     * @param context web application context to import default context
     */
    public void importDefaultContext(Context context) {

        if (this.defaultContext != null)
            this.defaultContext.importDefaultContext(context);

    }

    /**
     * Add an alias name that should be mapped to this same Host.
     *
     * @param alias The alias to be added
     */
    public void addAlias(String alias) {

        alias = alias.toLowerCase();

        // Skip duplicate aliases
        for (int i = 0; i < aliases.length; i++) {
            if (aliases[i].equals(alias))
                return;
        }

        // Add this alias to the list
        String newAliases[] = new String[aliases.length + 1];
        for (int i = 0; i < aliases.length; i++)
            newAliases[i] = aliases[i];
        newAliases[aliases.length] = alias;

        aliases = newAliases;

        // Inform interested listeners
        fireContainerEvent(ADD_ALIAS_EVENT, alias);

    }

    /**
     * Add a child Container, only if the proposed child is an implementation
     * of Context.
     *
     * @param child Child container to be added
     */
    public void addChild(Container child) {

        if (!(child instanceof Context))
            throw new IllegalArgumentException(sm.getString("standardHost.notContext"));
        super.addChild(child);

    }

    /**
     * Return the set of alias names for this Host.  If none are defined,
     * a zero length array is returned.
     */
    public String[] findAliases() {

        return (this.aliases);

    }

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

        return (info);

    }

    /**
     * Return the Context that would be used to process the specified
     * host-relative request URI, if any; otherwise return <code>null</code>.
     *
     * @param uri Request URI to be mapped
     */
    public Context map(String uri) {

        if (log.isDebugEnabled())
            log.debug("Mapping request URI '" + uri + "'");
        if (uri == null)
            return (null);

        // Match on the longest possible context path prefix
        if (log.isTraceEnabled())
            log.trace("  Trying the longest context path prefix");
        Context context = null;
        String mapuri = uri;
        while (true) {
            context = (Context) findChild(mapuri);
            if (context != null)
                break;
            int slash = mapuri.lastIndexOf('/');
            if (slash < 0)
                break;
            mapuri = mapuri.substring(0, slash);
        }

        // If no Context matches, select the default Context
        if (context == null) {
            if (log.isTraceEnabled())
                log.trace("  Trying the default context");
            context = (Context) findChild("");
        }

        // Complain if no Context has been selected
        if (context == null) {
            log.error(sm.getString("standardHost.mappingError", uri));
            return (null);
        }

        // Return the mapped Context (if any)
        if (log.isDebugEnabled())
            log.debug(" Mapped to context '" + context.getPath() + "'");
        return (context);

    }

    /**
     * Remove the specified alias name from the aliases for this Host.
     *
     * @param alias Alias name to be removed
     */
    public void removeAlias(String alias) {

        alias = alias.toLowerCase();

        synchronized (aliases) {

            // Make sure this alias is currently present
            int n = -1;
            for (int i = 0; i < aliases.length; i++) {
                if (aliases[i].equals(alias)) {
                    n = i;
                    break;
                }
            }
            if (n < 0)
                return;

            // Remove the specified alias
            int j = 0;
            String results[] = new String[aliases.length - 1];
            for (int i = 0; i < aliases.length; i++) {
                if (i != n)
                    results[j++] = aliases[i];
            }
            aliases = results;

        }

        // Inform interested listeners
        fireContainerEvent(REMOVE_ALIAS_EVENT, alias);

    }

    /**
     * Return a String representation of this component.
     */
    public String toString() {

        StringBuffer sb = new StringBuffer();
        if (getParent() != null) {
            sb.append(getParent().toString());
            sb.append(".");
        }
        sb.append("StandardHost[");
        sb.append(getName());
        sb.append("]");
        return (sb.toString());

    }

    /**
     * Start this host.
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents it from being started
     */
    public synchronized void start() throws LifecycleException {
        if (started) {
            return;
        }
        if (!initialized)
            init();

        // Look for a realm - that may have been configured earlier. 
        // If the realm is added after context - it'll set itself.
        if (realm == null) {
            ObjectName realmName = null;
            try {
                realmName = new ObjectName(domain + ":type=Host,host=" + getName());
                if (mserver.isRegistered(realmName)) {
                    mserver.invoke(realmName, "setContext", new Object[] { this },
                            new String[] { "org.apache.catalina.Container" });
                }
            } catch (Throwable t) {
                log.debug("No realm for this host " + realmName);
            }
        }

        // Set error report valve
        if ((errorReportValveClass != null) && (!errorReportValveClass.equals(""))) {
            try {
                boolean found = false;
                if (errorReportValveObjectName != null) {
                    ObjectName[] names = ((StandardPipeline) pipeline).getValveObjectNames();
                    for (int i = 0; !found && i < names.length; i++)
                        if (errorReportValveObjectName.equals(names[i]))
                            found = true;
                }
                if (!found) {
                    Valve valve = (Valve) Class.forName(errorReportValveClass).newInstance();
                    addValve(valve);
                    errorReportValveObjectName = ((ValveBase) valve).getObjectName();
                }
            } catch (Throwable t) {
                log.error(sm.getString("standardHost.invalidErrorReportValveClass", errorReportValveClass));
            }
        }

        if (xmlValidation)
            log.info(sm.getString("standardHost.validationEnabled"));
        else
            log.info(sm.getString("standardHost.validationDisabled"));

        super.start();

    }

    /**
     * Execute a periodic task, such as reloading, etc. This method will be
     * invoked inside the classloading context of this container. Unexpected
     * throwables will be caught and logged.
     */
    public void backgroundProcess() {
        lifecycle.fireLifecycleEvent("check", null);
    }

    // ------------------------------------------------------- Deployer Methods

    /**
     * Install a new web application, whose web application archive is at the
     * specified URL, into this container with the specified context path.
     * A context path of "" (the empty string) should be used for the root
     * application for this container.  Otherwise, the context path must
     * start with a slash.
     * <p>
     * If this application is successfully installed, a ContainerEvent of type
     * <code>INSTALL_EVENT</code> will be sent to all registered listeners,
     * with the newly created <code>Context</code> as an argument.
     *
     * @param contextPath The context path to which this application should
     *  be installed (must be unique)
     * @param war A URL of type "jar:" that points to a WAR file, or type
     *  "file:" that points to an unpacked directory structure containing
     *  the web application to be installed
     *
     * @exception IllegalArgumentException if the specified context path
     *  is malformed (it must be "" or start with a slash)
     * @exception IllegalStateException if the specified context path
     *  is already attached to an existing web application
     * @exception IOException if an input/output error was encountered
     *  during install
     */
    public void install(String contextPath, URL war) throws IOException {
        getDeployer().install(contextPath, war);

    }

    /**
     * <p>Install a new web application, whose context configuration file
     * (consisting of a <code>&lt;Context&gt;</code> element) and web
     * application archive are at the specified URLs.</p>
     *
     * <p>If this application is successfully installed, a ContainerEvent
     * of type <code>INSTALL_EVENT</code> will be sent to all registered
     * listeners, with the newly created <code>Context</code> as an argument.
     * </p>
     *
     * @param config A URL that points to the context configuration file to
     *  be used for configuring the new Context
     * @param war A URL of type "jar:" that points to a WAR file, or type
     *  "file:" that points to an unpacked directory structure containing
     *  the web application to be installed
     *
     * @exception IllegalArgumentException if one of the specified URLs is
     *  null
     * @exception IllegalStateException if the context path specified in the
     *  context configuration file is already attached to an existing web
     *  application
     * @exception IOException if an input/output error was encountered
     *  during installation
     */
    public synchronized void install(URL config, URL war) throws IOException {

        getDeployer().install(config, war);

    }

    /**
     * Return the Context for the deployed application that is associated
     * with the specified context path (if any); otherwise return
     * <code>null</code>.
     *
     * @param contextPath The context path of the requested web application
     */
    public Context findDeployedApp(String contextPath) {

        return (getDeployer().findDeployedApp(contextPath));

    }

    /**
     * Return the context paths of all deployed web applications in this
     * Container.  If there are no deployed applications, a zero-length
     * array is returned.
     */
    public String[] findDeployedApps() {

        return (getDeployer().findDeployedApps());

    }

    /**
     * Remove an existing web application, attached to the specified context
     * path.  If this application is successfully removed, a
     * ContainerEvent of type <code>REMOVE_EVENT</code> will be sent to all
     * registered listeners, with the removed <code>Context</code> as
     * an argument.
     *
     * @param contextPath The context path of the application to be removed
     *
     * @exception IllegalArgumentException if the specified context path
     *  is malformed (it must be "" or start with a slash)
     * @exception IllegalArgumentException if the specified context path does
     *  not identify a currently installed web application
     * @exception IOException if an input/output error occurs during
     *  removal
     */
    public void remove(String contextPath) throws IOException {

        getDeployer().remove(contextPath);

    }

    /**
     * Remove an existing web application, attached to the specified context
     * path.  If this application is successfully removed, a
     * ContainerEvent of type <code>REMOVE_EVENT</code> will be sent to all
     * registered listeners, with the removed <code>Context</code> as
     * an argument. Deletes the web application war file and/or directory
     * if they exist in the Host's appBase.
     *
     * @param contextPath The context path of the application to be removed
     * @param undeploy boolean flag to remove web application from server
     *
     * @exception IllegalArgumentException if the specified context path
     *  is malformed (it must be "" or start with a slash)
     * @exception IllegalArgumentException if the specified context path does
     *  not identify a currently installed web application
     * @exception IOException if an input/output error occurs during
     *  removal
     */
    public void remove(String contextPath, boolean undeploy) throws IOException {

        getDeployer().remove(contextPath, undeploy);

    }

    /**
     * Start an existing web application, attached to the specified context
     * path.  Only starts a web application if it is not running.
     *
     * @param contextPath The context path of the application to be started
     *
     * @exception IllegalArgumentException if the specified context path
     *  is malformed (it must be "" or start with a slash)
     * @exception IllegalArgumentException if the specified context path does
     *  not identify a currently installed web application
     * @exception IOException if an input/output error occurs during
     *  startup
     */
    public void start(String contextPath) throws IOException {

        getDeployer().start(contextPath);

    }

    /**
     * Stop an existing web application, attached to the specified context
     * path.  Only stops a web application if it is running.
     *
     * @param contextPath The context path of the application to be stopped
     *
     * @exception IllegalArgumentException if the specified context path
     *  is malformed (it must be "" or start with a slash)
     * @exception IllegalArgumentException if the specified context path does
     *  not identify a currently installed web application
     * @exception IOException if an input/output error occurs while stopping
     *  the web application
     */
    public void stop(String contextPath) throws IOException {

        getDeployer().stop(contextPath);

    }

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

    static String STANDARD_HOST_DEPLOYER = "org.apache.catalina.core.StandardHostDeployer";

    public Deployer getDeployer() {
        if (deployer != null)
            return deployer;
        log.info("Create Host deployer for direct deployment ( non-jmx ) ");
        try {
            Class c = Class.forName(STANDARD_HOST_DEPLOYER);
            deployer = (Deployer) c.newInstance();
            Method m = c.getMethod("setHost", new Class[] { Host.class });
            m.invoke(deployer, new Object[] { this });
        } catch (Throwable t) {
            log.error("Error creating deployer ", t);
        }
        return deployer;
    }

    public void setDeployer(Deployer d) {
        this.deployer = d;
    }

    // -------------------- JMX  --------------------
    /**
      * Return the MBean Names of the Valves assoicated with this Host
      *
      * @exception Exception if an MBean cannot be created or registered
      */
    public String[] getValveNames() throws Exception {
        Valve[] valves = this.getValves();
        String[] mbeanNames = new String[valves.length];
        for (int i = 0; i < valves.length; i++) {
            if (valves[i] == null)
                continue;
            if (((ValveBase) valves[i]).getObjectName() == null)
                continue;
            mbeanNames[i] = ((ValveBase) valves[i]).getObjectName().toString();
        }

        return mbeanNames;

    }

    public String[] getAliases() {
        return aliases;
    }

    private boolean initialized = false;

    public void init() {
        if (initialized)
            return;
        initialized = true;

        // already registered.
        if (getParent() == null) {
            try {
                // Register with the Engine
                ObjectName serviceName = new ObjectName(domain + ":type=Engine");

                if (mserver.isRegistered(serviceName)) {
                    log.debug("Registering with the Engine");
                    mserver.invoke(serviceName, "addChild", new Object[] { this },
                            new String[] { "org.apache.catalina.Container" });
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        if (oname == null) {
            // not registered in JMX yet - standalone mode
            try {
                StandardEngine engine = (StandardEngine) parent;
                domain = engine.getName();
                log.debug("Register " + domain);
                oname = new ObjectName(domain + ":type=Host,host=" + this.getName());
                Registry.getRegistry().registerComponent(this, oname, null);
            } catch (Throwable t) {
                log.info("Error registering ", t);
            }
        }
    }

    public ObjectName preRegister(MBeanServer server, ObjectName oname) throws Exception {
        ObjectName res = super.preRegister(server, oname);
        String name = oname.getKeyProperty("host");
        if (name != null)
            setName(name);
        return res;
    }

    public ObjectName createObjectName(String domain, ObjectName parent) throws Exception {
        if (log.isDebugEnabled())
            log.debug("Create ObjectName " + domain + " " + parent);
        return new ObjectName(domain + ":type=Host,host=" + getName());
    }

}