0001: /*
0002: * Copyright 1999,2004 The Apache Software Foundation.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.apache.catalina.core;
0018:
0019: import java.io.IOException;
0020: import java.lang.reflect.Method;
0021: import java.net.URL;
0022:
0023: import javax.management.MBeanServer;
0024: import javax.management.ObjectName;
0025:
0026: import org.apache.catalina.Container;
0027: import org.apache.catalina.Context;
0028: import org.apache.catalina.DefaultContext;
0029: import org.apache.catalina.Deployer;
0030: import org.apache.catalina.Host;
0031: import org.apache.catalina.LifecycleException;
0032: import org.apache.catalina.Valve;
0033: import org.apache.catalina.valves.ValveBase;
0034: import org.apache.commons.modeler.Registry;
0035:
0036: /**
0037: * Standard implementation of the <b>Host</b> interface. Each
0038: * child container must be a Context implementation to process the
0039: * requests directed to a particular web application.
0040: *
0041: * @author Craig R. McClanahan
0042: * @author Remy Maucherat
0043: * @version $Revision: 1.31 $ $Date: 2004/05/26 15:41:07 $
0044: */
0045:
0046: public class StandardHost extends ContainerBase implements Deployer,
0047: Host {
0048: /* Why do we implement deployer and delegate to deployer ??? */
0049:
0050: private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
0051: .getLog(StandardHost.class);
0052:
0053: // ----------------------------------------------------------- Constructors
0054:
0055: /**
0056: * Create a new StandardHost component with the default basic Valve.
0057: */
0058: public StandardHost() {
0059:
0060: super ();
0061: pipeline.setBasic(new StandardHostValve());
0062:
0063: }
0064:
0065: // ----------------------------------------------------- Instance Variables
0066:
0067: /**
0068: * The set of aliases for this Host.
0069: */
0070: private String[] aliases = new String[0];
0071:
0072: /**
0073: * The application root for this Host.
0074: */
0075: private String appBase = ".";
0076:
0077: /**
0078: * The auto deploy flag for this Host.
0079: */
0080: private boolean autoDeploy = true;
0081:
0082: /**
0083: * The Java class name of the default context configuration class
0084: * for deployed web applications.
0085: */
0086: private String configClass = "org.apache.catalina.startup.ContextConfig";
0087:
0088: /**
0089: * The Java class name of the default Context implementation class for
0090: * deployed web applications.
0091: */
0092: private String contextClass = "org.apache.catalina.core.StandardContext";
0093:
0094: /**
0095: * The <code>Deployer</code> to whom we delegate application
0096: * deployment requests.
0097: */
0098: private Deployer deployer = null;
0099:
0100: /**
0101: * The deploy on startup flag for this Host.
0102: */
0103: private boolean deployOnStartup = true;
0104:
0105: /**
0106: * deploy Context XML config files property.
0107: */
0108: private boolean deployXML = true;
0109:
0110: /**
0111: * The Java class name of the default error reporter implementation class
0112: * for deployed web applications.
0113: */
0114: private String errorReportValveClass = "org.apache.catalina.valves.ErrorReportValve";
0115:
0116: /**
0117: * The object name for the errorReportValve.
0118: */
0119: private ObjectName errorReportValveObjectName = null;
0120:
0121: /**
0122: * The descriptive information string for this implementation.
0123: */
0124: private static final String info = "org.apache.catalina.core.StandardHost/1.0";
0125:
0126: /**
0127: * The live deploy flag for this Host.
0128: */
0129: private boolean liveDeploy = true;
0130:
0131: /**
0132: * Unpack WARs property.
0133: */
0134: private boolean unpackWARs = true;
0135:
0136: /**
0137: * Work Directory base for applications.
0138: */
0139: private String workDir = null;
0140:
0141: /**
0142: * DefaultContext config
0143: */
0144: private DefaultContext defaultContext;
0145:
0146: /**
0147: * Attribute value used to turn on/off XML validation
0148: */
0149: private boolean xmlValidation = false;
0150:
0151: /**
0152: * Attribute value used to turn on/off XML namespace awarenes.
0153: */
0154: private boolean xmlNamespaceAware = false;
0155:
0156: // ------------------------------------------------------------- Properties
0157:
0158: /**
0159: * Return the application root for this Host. This can be an absolute
0160: * pathname, a relative pathname, or a URL.
0161: */
0162: public String getAppBase() {
0163:
0164: return (this .appBase);
0165:
0166: }
0167:
0168: /**
0169: * Set the application root for this Host. This can be an absolute
0170: * pathname, a relative pathname, or a URL.
0171: *
0172: * @param appBase The new application root
0173: */
0174: public void setAppBase(String appBase) {
0175:
0176: String oldAppBase = this .appBase;
0177: this .appBase = appBase;
0178: support.firePropertyChange("appBase", oldAppBase, this .appBase);
0179:
0180: }
0181:
0182: /**
0183: * Return the value of the auto deploy flag. If true, it indicates that
0184: * this host's child webapps will be dynamically deployed.
0185: */
0186: public boolean getAutoDeploy() {
0187:
0188: return (this .autoDeploy);
0189:
0190: }
0191:
0192: /**
0193: * Set the auto deploy flag value for this host.
0194: *
0195: * @param autoDeploy The new auto deploy flag
0196: */
0197: public void setAutoDeploy(boolean autoDeploy) {
0198:
0199: boolean oldAutoDeploy = this .autoDeploy;
0200: this .autoDeploy = autoDeploy;
0201: support.firePropertyChange("autoDeploy", oldAutoDeploy,
0202: this .autoDeploy);
0203:
0204: }
0205:
0206: /**
0207: * Return the Java class name of the context configuration class
0208: * for new web applications.
0209: */
0210: public String getConfigClass() {
0211:
0212: return (this .configClass);
0213:
0214: }
0215:
0216: /**
0217: * Set the Java class name of the context configuration class
0218: * for new web applications.
0219: *
0220: * @param configClass The new context configuration class
0221: */
0222: public void setConfigClass(String configClass) {
0223:
0224: String oldConfigClass = this .configClass;
0225: this .configClass = configClass;
0226: support.firePropertyChange("configClass", oldConfigClass,
0227: this .configClass);
0228:
0229: }
0230:
0231: /**
0232: * Set the DefaultContext
0233: * for new web applications.
0234: *
0235: * @param defaultContext The new DefaultContext
0236: */
0237: public void addDefaultContext(DefaultContext defaultContext) {
0238:
0239: DefaultContext oldDefaultContext = this .defaultContext;
0240: this .defaultContext = defaultContext;
0241: support.firePropertyChange("defaultContext", oldDefaultContext,
0242: this .defaultContext);
0243:
0244: }
0245:
0246: /**
0247: * Retrieve the DefaultContext for new web applications.
0248: */
0249: public DefaultContext getDefaultContext() {
0250: return (this .defaultContext);
0251: }
0252:
0253: /**
0254: * Return the Java class name of the Context implementation class
0255: * for new web applications.
0256: */
0257: public String getContextClass() {
0258:
0259: return (this .contextClass);
0260:
0261: }
0262:
0263: /**
0264: * Set the Java class name of the Context implementation class
0265: * for new web applications.
0266: *
0267: * @param contextClass The new context implementation class
0268: */
0269: public void setContextClass(String contextClass) {
0270:
0271: String oldContextClass = this .contextClass;
0272: this .contextClass = contextClass;
0273: support.firePropertyChange("contextClass", oldContextClass,
0274: this .contextClass);
0275:
0276: }
0277:
0278: /**
0279: * Return the value of the deploy on startup flag. If true, it indicates
0280: * that this host's child webapps should be discovred and automatically
0281: * deployed at startup time.
0282: */
0283: public boolean getDeployOnStartup() {
0284:
0285: return (this .deployOnStartup);
0286:
0287: }
0288:
0289: /**
0290: * Set the deploy on startup flag value for this host.
0291: *
0292: * @param deployOnStartup The new deploy on startup flag
0293: */
0294: public void setDeployOnStartup(boolean deployOnStartup) {
0295:
0296: boolean oldDeployOnStartup = this .deployOnStartup;
0297: this .deployOnStartup = deployOnStartup;
0298: support.firePropertyChange("deployOnStartup",
0299: oldDeployOnStartup, this .deployOnStartup);
0300:
0301: }
0302:
0303: /**
0304: * Deploy XML Context config files flag accessor.
0305: */
0306: public boolean isDeployXML() {
0307:
0308: return (deployXML);
0309:
0310: }
0311:
0312: /**
0313: * Deploy XML Context config files flag mutator.
0314: */
0315: public void setDeployXML(boolean deployXML) {
0316:
0317: this .deployXML = deployXML;
0318:
0319: }
0320:
0321: /**
0322: * Return the value of the live deploy flag. If true, it indicates that
0323: * a background thread should be started that looks for web application
0324: * context files, WAR files, or unpacked directories being dropped in to
0325: * the <code>appBase</code> directory, and deploys new ones as they are
0326: * encountered.
0327: */
0328: public boolean getLiveDeploy() {
0329: return (this .autoDeploy);
0330: }
0331:
0332: /**
0333: * Set the live deploy flag value for this host.
0334: *
0335: * @param liveDeploy The new live deploy flag
0336: */
0337: public void setLiveDeploy(boolean liveDeploy) {
0338: setAutoDeploy(liveDeploy);
0339: }
0340:
0341: /**
0342: * Return the Java class name of the error report valve class
0343: * for new web applications.
0344: */
0345: public String getErrorReportValveClass() {
0346:
0347: return (this .errorReportValveClass);
0348:
0349: }
0350:
0351: /**
0352: * Set the Java class name of the error report valve class
0353: * for new web applications.
0354: *
0355: * @param errorReportValveClass The new error report valve class
0356: */
0357: public void setErrorReportValveClass(String errorReportValveClass) {
0358:
0359: String oldErrorReportValveClassClass = this .errorReportValveClass;
0360: this .errorReportValveClass = errorReportValveClass;
0361: support.firePropertyChange("errorReportValveClass",
0362: oldErrorReportValveClassClass,
0363: this .errorReportValveClass);
0364:
0365: }
0366:
0367: /**
0368: * Return the canonical, fully qualified, name of the virtual host
0369: * this Container represents.
0370: */
0371: public String getName() {
0372:
0373: return (name);
0374:
0375: }
0376:
0377: /**
0378: * Set the canonical, fully qualified, name of the virtual host
0379: * this Container represents.
0380: *
0381: * @param name Virtual host name
0382: *
0383: * @exception IllegalArgumentException if name is null
0384: */
0385: public void setName(String name) {
0386:
0387: if (name == null)
0388: throw new IllegalArgumentException(sm
0389: .getString("standardHost.nullName"));
0390:
0391: name = name.toLowerCase(); // Internally all names are lower case
0392:
0393: String oldName = this .name;
0394: this .name = name;
0395: support.firePropertyChange("name", oldName, this .name);
0396:
0397: }
0398:
0399: /**
0400: * Unpack WARs flag accessor.
0401: */
0402: public boolean isUnpackWARs() {
0403:
0404: return (unpackWARs);
0405:
0406: }
0407:
0408: /**
0409: * Unpack WARs flag mutator.
0410: */
0411: public void setUnpackWARs(boolean unpackWARs) {
0412:
0413: this .unpackWARs = unpackWARs;
0414:
0415: }
0416:
0417: /**
0418: * Set the validation feature of the XML parser used when
0419: * parsing xml instances.
0420: * @param xmlValidation true to enable xml instance validation
0421: */
0422: public void setXmlValidation(boolean xmlValidation) {
0423:
0424: this .xmlValidation = xmlValidation;
0425:
0426: }
0427:
0428: /**
0429: * Get the server.xml <host> attribute's xmlValidation.
0430: * @return true if validation is enabled.
0431: *
0432: */
0433: public boolean getXmlValidation() {
0434: return xmlValidation;
0435: }
0436:
0437: /**
0438: * Get the server.xml <host> attribute's xmlNamespaceAware.
0439: * @return true if namespace awarenes is enabled.
0440: *
0441: */
0442: public boolean getXmlNamespaceAware() {
0443: return xmlNamespaceAware;
0444: }
0445:
0446: /**
0447: * Set the namespace aware feature of the XML parser used when
0448: * parsing xml instances.
0449: * @param xmlNamespaceAware true to enable namespace awareness
0450: */
0451: public void setXmlNamespaceAware(boolean xmlNamespaceAware) {
0452: this .xmlNamespaceAware = xmlNamespaceAware;
0453: }
0454:
0455: /**
0456: * Host work directory base.
0457: */
0458: public String getWorkDir() {
0459:
0460: return (workDir);
0461: }
0462:
0463: /**
0464: * Host work directory base.
0465: */
0466: public void setWorkDir(String workDir) {
0467:
0468: this .workDir = workDir;
0469: }
0470:
0471: // --------------------------------------------------------- Public Methods
0472:
0473: /**
0474: * Install the StandardContext portion of the DefaultContext
0475: * configuration into current Context.
0476: *
0477: * @param context current web application context
0478: */
0479: public void installDefaultContext(Context context) {
0480:
0481: if (defaultContext != null
0482: && defaultContext instanceof StandardDefaultContext) {
0483:
0484: ((StandardDefaultContext) defaultContext)
0485: .installDefaultContext(context);
0486: }
0487:
0488: }
0489:
0490: /**
0491: * Import the DefaultContext config into a web application context.
0492: *
0493: * @param context web application context to import default context
0494: */
0495: public void importDefaultContext(Context context) {
0496:
0497: if (this .defaultContext != null)
0498: this .defaultContext.importDefaultContext(context);
0499:
0500: }
0501:
0502: /**
0503: * Add an alias name that should be mapped to this same Host.
0504: *
0505: * @param alias The alias to be added
0506: */
0507: public void addAlias(String alias) {
0508:
0509: alias = alias.toLowerCase();
0510:
0511: // Skip duplicate aliases
0512: for (int i = 0; i < aliases.length; i++) {
0513: if (aliases[i].equals(alias))
0514: return;
0515: }
0516:
0517: // Add this alias to the list
0518: String newAliases[] = new String[aliases.length + 1];
0519: for (int i = 0; i < aliases.length; i++)
0520: newAliases[i] = aliases[i];
0521: newAliases[aliases.length] = alias;
0522:
0523: aliases = newAliases;
0524:
0525: // Inform interested listeners
0526: fireContainerEvent(ADD_ALIAS_EVENT, alias);
0527:
0528: }
0529:
0530: /**
0531: * Add a child Container, only if the proposed child is an implementation
0532: * of Context.
0533: *
0534: * @param child Child container to be added
0535: */
0536: public void addChild(Container child) {
0537:
0538: if (!(child instanceof Context))
0539: throw new IllegalArgumentException(sm
0540: .getString("standardHost.notContext"));
0541: super .addChild(child);
0542:
0543: }
0544:
0545: /**
0546: * Return the set of alias names for this Host. If none are defined,
0547: * a zero length array is returned.
0548: */
0549: public String[] findAliases() {
0550:
0551: return (this .aliases);
0552:
0553: }
0554:
0555: /**
0556: * Return descriptive information about this Container implementation and
0557: * the corresponding version number, in the format
0558: * <code><description>/<version></code>.
0559: */
0560: public String getInfo() {
0561:
0562: return (info);
0563:
0564: }
0565:
0566: /**
0567: * Return the Context that would be used to process the specified
0568: * host-relative request URI, if any; otherwise return <code>null</code>.
0569: *
0570: * @param uri Request URI to be mapped
0571: */
0572: public Context map(String uri) {
0573:
0574: if (log.isDebugEnabled())
0575: log.debug("Mapping request URI '" + uri + "'");
0576: if (uri == null)
0577: return (null);
0578:
0579: // Match on the longest possible context path prefix
0580: if (log.isTraceEnabled())
0581: log.trace(" Trying the longest context path prefix");
0582: Context context = null;
0583: String mapuri = uri;
0584: while (true) {
0585: context = (Context) findChild(mapuri);
0586: if (context != null)
0587: break;
0588: int slash = mapuri.lastIndexOf('/');
0589: if (slash < 0)
0590: break;
0591: mapuri = mapuri.substring(0, slash);
0592: }
0593:
0594: // If no Context matches, select the default Context
0595: if (context == null) {
0596: if (log.isTraceEnabled())
0597: log.trace(" Trying the default context");
0598: context = (Context) findChild("");
0599: }
0600:
0601: // Complain if no Context has been selected
0602: if (context == null) {
0603: log.error(sm.getString("standardHost.mappingError", uri));
0604: return (null);
0605: }
0606:
0607: // Return the mapped Context (if any)
0608: if (log.isDebugEnabled())
0609: log.debug(" Mapped to context '" + context.getPath() + "'");
0610: return (context);
0611:
0612: }
0613:
0614: /**
0615: * Remove the specified alias name from the aliases for this Host.
0616: *
0617: * @param alias Alias name to be removed
0618: */
0619: public void removeAlias(String alias) {
0620:
0621: alias = alias.toLowerCase();
0622:
0623: synchronized (aliases) {
0624:
0625: // Make sure this alias is currently present
0626: int n = -1;
0627: for (int i = 0; i < aliases.length; i++) {
0628: if (aliases[i].equals(alias)) {
0629: n = i;
0630: break;
0631: }
0632: }
0633: if (n < 0)
0634: return;
0635:
0636: // Remove the specified alias
0637: int j = 0;
0638: String results[] = new String[aliases.length - 1];
0639: for (int i = 0; i < aliases.length; i++) {
0640: if (i != n)
0641: results[j++] = aliases[i];
0642: }
0643: aliases = results;
0644:
0645: }
0646:
0647: // Inform interested listeners
0648: fireContainerEvent(REMOVE_ALIAS_EVENT, alias);
0649:
0650: }
0651:
0652: /**
0653: * Return a String representation of this component.
0654: */
0655: public String toString() {
0656:
0657: StringBuffer sb = new StringBuffer();
0658: if (getParent() != null) {
0659: sb.append(getParent().toString());
0660: sb.append(".");
0661: }
0662: sb.append("StandardHost[");
0663: sb.append(getName());
0664: sb.append("]");
0665: return (sb.toString());
0666:
0667: }
0668:
0669: /**
0670: * Start this host.
0671: *
0672: * @exception LifecycleException if this component detects a fatal error
0673: * that prevents it from being started
0674: */
0675: public synchronized void start() throws LifecycleException {
0676: if (started) {
0677: return;
0678: }
0679: if (!initialized)
0680: init();
0681:
0682: // Look for a realm - that may have been configured earlier.
0683: // If the realm is added after context - it'll set itself.
0684: if (realm == null) {
0685: ObjectName realmName = null;
0686: try {
0687: realmName = new ObjectName(domain + ":type=Host,host="
0688: + getName());
0689: if (mserver.isRegistered(realmName)) {
0690: mserver
0691: .invoke(
0692: realmName,
0693: "setContext",
0694: new Object[] { this },
0695: new String[] { "org.apache.catalina.Container" });
0696: }
0697: } catch (Throwable t) {
0698: log.debug("No realm for this host " + realmName);
0699: }
0700: }
0701:
0702: // Set error report valve
0703: if ((errorReportValveClass != null)
0704: && (!errorReportValveClass.equals(""))) {
0705: try {
0706: boolean found = false;
0707: if (errorReportValveObjectName != null) {
0708: ObjectName[] names = ((StandardPipeline) pipeline)
0709: .getValveObjectNames();
0710: for (int i = 0; !found && i < names.length; i++)
0711: if (errorReportValveObjectName.equals(names[i]))
0712: found = true;
0713: }
0714: if (!found) {
0715: Valve valve = (Valve) Class.forName(
0716: errorReportValveClass).newInstance();
0717: addValve(valve);
0718: errorReportValveObjectName = ((ValveBase) valve)
0719: .getObjectName();
0720: }
0721: } catch (Throwable t) {
0722: log.error(sm.getString(
0723: "standardHost.invalidErrorReportValveClass",
0724: errorReportValveClass));
0725: }
0726: }
0727:
0728: if (xmlValidation)
0729: log.info(sm.getString("standardHost.validationEnabled"));
0730: else
0731: log.info(sm.getString("standardHost.validationDisabled"));
0732:
0733: super .start();
0734:
0735: }
0736:
0737: /**
0738: * Execute a periodic task, such as reloading, etc. This method will be
0739: * invoked inside the classloading context of this container. Unexpected
0740: * throwables will be caught and logged.
0741: */
0742: public void backgroundProcess() {
0743: lifecycle.fireLifecycleEvent("check", null);
0744: }
0745:
0746: // ------------------------------------------------------- Deployer Methods
0747:
0748: /**
0749: * Install a new web application, whose web application archive is at the
0750: * specified URL, into this container with the specified context path.
0751: * A context path of "" (the empty string) should be used for the root
0752: * application for this container. Otherwise, the context path must
0753: * start with a slash.
0754: * <p>
0755: * If this application is successfully installed, a ContainerEvent of type
0756: * <code>INSTALL_EVENT</code> will be sent to all registered listeners,
0757: * with the newly created <code>Context</code> as an argument.
0758: *
0759: * @param contextPath The context path to which this application should
0760: * be installed (must be unique)
0761: * @param war A URL of type "jar:" that points to a WAR file, or type
0762: * "file:" that points to an unpacked directory structure containing
0763: * the web application to be installed
0764: *
0765: * @exception IllegalArgumentException if the specified context path
0766: * is malformed (it must be "" or start with a slash)
0767: * @exception IllegalStateException if the specified context path
0768: * is already attached to an existing web application
0769: * @exception IOException if an input/output error was encountered
0770: * during install
0771: */
0772: public void install(String contextPath, URL war) throws IOException {
0773: getDeployer().install(contextPath, war);
0774:
0775: }
0776:
0777: /**
0778: * <p>Install a new web application, whose context configuration file
0779: * (consisting of a <code><Context></code> element) and web
0780: * application archive are at the specified URLs.</p>
0781: *
0782: * <p>If this application is successfully installed, a ContainerEvent
0783: * of type <code>INSTALL_EVENT</code> will be sent to all registered
0784: * listeners, with the newly created <code>Context</code> as an argument.
0785: * </p>
0786: *
0787: * @param config A URL that points to the context configuration file to
0788: * be used for configuring the new Context
0789: * @param war A URL of type "jar:" that points to a WAR file, or type
0790: * "file:" that points to an unpacked directory structure containing
0791: * the web application to be installed
0792: *
0793: * @exception IllegalArgumentException if one of the specified URLs is
0794: * null
0795: * @exception IllegalStateException if the context path specified in the
0796: * context configuration file is already attached to an existing web
0797: * application
0798: * @exception IOException if an input/output error was encountered
0799: * during installation
0800: */
0801: public synchronized void install(URL config, URL war)
0802: throws IOException {
0803:
0804: getDeployer().install(config, war);
0805:
0806: }
0807:
0808: /**
0809: * Installs a new web application from the web application archive at the
0810: * specified URL, which must contain a META-INF/context.xml context
0811: * configuration file (consisting of a <code><Context></code>
0812: * element).
0813: *
0814: * <p>The web application is installed at the path specified inside the
0815: * embedded META-INF/context.xml. The docBase (if any) specified inside the
0816: * embedded META-INF/context.xml is overridden with the web application's
0817: * location.
0818: *
0819: * <p>If the installation succeeds, a ContainerEvent of type
0820: * <code>INSTALL_EVENT</code> is sent to all registered listeners,
0821: * with the newly created <code>Context</code> as its argument.
0822: *
0823: * @param war URL pointing to web application location (WAR-packaged or
0824: * unpacked directory)
0825: *
0826: * @exception IllegalArgumentException if <code>war</code> is null, or if
0827: * this StandardHost does not support any context.xml
0828: * configuration files
0829: * @exception IllegalStateException if the context path specified in the
0830: * context configuration file is already in use by an existing
0831: * web application
0832: * @exception IOException if an input/output error was encountered
0833: * during installation
0834: */
0835: public synchronized void install(URL war) throws IOException {
0836:
0837: getDeployer().install(war);
0838:
0839: }
0840:
0841: /**
0842: * Return the Context for the deployed application that is associated
0843: * with the specified context path (if any); otherwise return
0844: * <code>null</code>.
0845: *
0846: * @param contextPath The context path of the requested web application
0847: */
0848: public Context findDeployedApp(String contextPath) {
0849:
0850: return (getDeployer().findDeployedApp(contextPath));
0851:
0852: }
0853:
0854: /**
0855: * Return the context paths of all deployed web applications in this
0856: * Container. If there are no deployed applications, a zero-length
0857: * array is returned.
0858: */
0859: public String[] findDeployedApps() {
0860:
0861: return (getDeployer().findDeployedApps());
0862:
0863: }
0864:
0865: /**
0866: * Remove an existing web application, attached to the specified context
0867: * path. If this application is successfully removed, a
0868: * ContainerEvent of type <code>REMOVE_EVENT</code> will be sent to all
0869: * registered listeners, with the removed <code>Context</code> as
0870: * an argument.
0871: *
0872: * @param contextPath The context path of the application to be removed
0873: *
0874: * @exception IllegalArgumentException if the specified context path
0875: * is malformed (it must be "" or start with a slash)
0876: * @exception IllegalArgumentException if the specified context path does
0877: * not identify a currently installed web application
0878: * @exception IOException if an input/output error occurs during
0879: * removal
0880: */
0881: public void remove(String contextPath) throws IOException {
0882:
0883: getDeployer().remove(contextPath);
0884:
0885: }
0886:
0887: /**
0888: * Remove an existing web application, attached to the specified context
0889: * path. If this application is successfully removed, a
0890: * ContainerEvent of type <code>REMOVE_EVENT</code> will be sent to all
0891: * registered listeners, with the removed <code>Context</code> as
0892: * an argument. Deletes the web application war file and/or directory
0893: * if they exist in the Host's appBase.
0894: *
0895: * @param contextPath The context path of the application to be removed
0896: * @param undeploy boolean flag to remove web application from server
0897: *
0898: * @exception IllegalArgumentException if the specified context path
0899: * is malformed (it must be "" or start with a slash)
0900: * @exception IllegalArgumentException if the specified context path does
0901: * not identify a currently installed web application
0902: * @exception IOException if an input/output error occurs during
0903: * removal
0904: */
0905: public void remove(String contextPath, boolean undeploy)
0906: throws IOException {
0907:
0908: getDeployer().remove(contextPath, undeploy);
0909:
0910: }
0911:
0912: /**
0913: * Start an existing web application, attached to the specified context
0914: * path. Only starts a web application if it is not running.
0915: *
0916: * @param contextPath The context path of the application to be started
0917: *
0918: * @exception IllegalArgumentException if the specified context path
0919: * is malformed (it must be "" or start with a slash)
0920: * @exception IllegalArgumentException if the specified context path does
0921: * not identify a currently installed web application
0922: * @exception IOException if an input/output error occurs during
0923: * startup
0924: */
0925: public void start(String contextPath) throws IOException {
0926:
0927: getDeployer().start(contextPath);
0928:
0929: }
0930:
0931: /**
0932: * Stop an existing web application, attached to the specified context
0933: * path. Only stops a web application if it is running.
0934: *
0935: * @param contextPath The context path of the application to be stopped
0936: *
0937: * @exception IllegalArgumentException if the specified context path
0938: * is malformed (it must be "" or start with a slash)
0939: * @exception IllegalArgumentException if the specified context path does
0940: * not identify a currently installed web application
0941: * @exception IOException if an input/output error occurs while stopping
0942: * the web application
0943: */
0944: public void stop(String contextPath) throws IOException {
0945:
0946: getDeployer().stop(contextPath);
0947:
0948: }
0949:
0950: // ------------------------------------------------------ Protected Methods
0951:
0952: static String STANDARD_HOST_DEPLOYER = "org.apache.catalina.core.StandardHostDeployer";
0953:
0954: public Deployer getDeployer() {
0955: if (deployer != null)
0956: return deployer;
0957: log
0958: .info("Create Host deployer for direct deployment ( non-jmx ) ");
0959: try {
0960: Class c = Class.forName(STANDARD_HOST_DEPLOYER);
0961: deployer = (Deployer) c.newInstance();
0962: Method m = c.getMethod("setHost",
0963: new Class[] { Host.class });
0964: m.invoke(deployer, new Object[] { this });
0965: } catch (Throwable t) {
0966: log.error("Error creating deployer ", t);
0967: }
0968: return deployer;
0969: }
0970:
0971: public void setDeployer(Deployer d) {
0972: this .deployer = d;
0973: }
0974:
0975: // -------------------- JMX --------------------
0976: /**
0977: * Return the MBean Names of the Valves assoicated with this Host
0978: *
0979: * @exception Exception if an MBean cannot be created or registered
0980: */
0981: public String[] getValveNames() throws Exception {
0982: Valve[] valves = this .getValves();
0983: String[] mbeanNames = new String[valves.length];
0984: for (int i = 0; i < valves.length; i++) {
0985: if (valves[i] == null)
0986: continue;
0987: if (((ValveBase) valves[i]).getObjectName() == null)
0988: continue;
0989: mbeanNames[i] = ((ValveBase) valves[i]).getObjectName()
0990: .toString();
0991: }
0992:
0993: return mbeanNames;
0994:
0995: }
0996:
0997: public String[] getAliases() {
0998: return aliases;
0999: }
1000:
1001: private boolean initialized = false;
1002:
1003: public void init() {
1004: if (initialized)
1005: return;
1006: initialized = true;
1007:
1008: // already registered.
1009: if (getParent() == null) {
1010: try {
1011: // Register with the Engine
1012: ObjectName serviceName = new ObjectName(domain
1013: + ":type=Engine");
1014:
1015: if (mserver.isRegistered(serviceName)) {
1016: log.debug("Registering with the Engine");
1017: mserver
1018: .invoke(
1019: serviceName,
1020: "addChild",
1021: new Object[] { this },
1022: new String[] { "org.apache.catalina.Container" });
1023: }
1024: } catch (Exception ex) {
1025: ex.printStackTrace();
1026: }
1027: }
1028:
1029: if (oname == null) {
1030: // not registered in JMX yet - standalone mode
1031: try {
1032: StandardEngine engine = (StandardEngine) parent;
1033: domain = engine.getName();
1034: log.debug("Register " + domain);
1035: oname = new ObjectName(domain + ":type=Host,host="
1036: + this .getName());
1037: Registry.getRegistry(null, null).registerComponent(
1038: this , oname, null);
1039: } catch (Throwable t) {
1040: log.info("Error registering ", t);
1041: }
1042: }
1043: }
1044:
1045: public ObjectName preRegister(MBeanServer server, ObjectName oname)
1046: throws Exception {
1047: ObjectName res = super .preRegister(server, oname);
1048: String name = oname.getKeyProperty("host");
1049: if (name != null)
1050: setName(name);
1051: return res;
1052: }
1053:
1054: public ObjectName createObjectName(String domain, ObjectName parent)
1055: throws Exception {
1056: if (log.isDebugEnabled())
1057: log.debug("Create ObjectName " + domain + " " + parent);
1058: return new ObjectName(domain + ":type=Host,host=" + getName());
1059: }
1060:
1061: }
|