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.startup;
0018:
0019: import java.io.BufferedOutputStream;
0020: import java.io.File;
0021: import java.io.FileOutputStream;
0022: import java.io.IOException;
0023: import java.io.InputStream;
0024: import java.net.URL;
0025: import java.util.ArrayList;
0026: import java.util.HashMap;
0027: import java.util.Iterator;
0028: import java.util.List;
0029: import java.util.jar.JarEntry;
0030: import java.util.jar.JarFile;
0031:
0032: import javax.naming.NamingException;
0033: import javax.naming.directory.DirContext;
0034:
0035: import org.apache.catalina.Container;
0036: import org.apache.catalina.Context;
0037: import org.apache.catalina.Deployer;
0038: import org.apache.catalina.Engine;
0039: import org.apache.catalina.Host;
0040: import org.apache.catalina.Lifecycle;
0041: import org.apache.catalina.LifecycleEvent;
0042: import org.apache.catalina.LifecycleListener;
0043: import org.apache.catalina.Logger;
0044: import org.apache.catalina.core.StandardContext;
0045: import org.apache.catalina.core.StandardHost;
0046: import org.apache.catalina.util.StringManager;
0047: import org.apache.naming.resources.ResourceAttributes;
0048:
0049: /**
0050: * Startup event listener for a <b>Host</b> that configures the properties
0051: * of that Host, and the associated defined contexts.
0052: *
0053: * @author Craig R. McClanahan
0054: * @author Remy Maucherat
0055: * @version $Revision: 1.31.2.1 $ $Date: 2004/08/21 19:14:28 $
0056: */
0057:
0058: public class HostConfig implements LifecycleListener {
0059:
0060: private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
0061: .getLog(HostConfig.class);
0062:
0063: // ----------------------------------------------------- Instance Variables
0064:
0065: /**
0066: * App base.
0067: */
0068: private File appBase = null;
0069:
0070: /**
0071: * Config base.
0072: */
0073: private File configBase = null;
0074:
0075: /**
0076: * The Java class name of the Context configuration class we should use.
0077: */
0078: protected String configClass = "org.apache.catalina.startup.ContextConfig";
0079:
0080: /**
0081: * The Java class name of the Context implementation we should use.
0082: */
0083: protected String contextClass = "org.apache.catalina.core.StandardContext";
0084:
0085: /**
0086: * The debugging detail level for this component.
0087: */
0088: protected int debug = 0;
0089:
0090: /**
0091: * The names of applications that we have auto-deployed (to avoid
0092: * double deployment attempts).
0093: */
0094: protected ArrayList deployed = new ArrayList();
0095:
0096: /**
0097: * The Host we are associated with.
0098: */
0099: protected Host host = null;
0100:
0101: /**
0102: * The string resources for this package.
0103: */
0104: protected static final StringManager sm = StringManager
0105: .getManager(Constants.Package);
0106:
0107: /**
0108: * Should we deploy XML Context config files?
0109: */
0110: private boolean deployXML = false;
0111:
0112: /**
0113: * Should we unpack WAR files when auto-deploying applications in the
0114: * <code>appBase</code> directory?
0115: */
0116: private boolean unpackWARs = false;
0117:
0118: /**
0119: * Last modified dates of the web.xml files of the contexts, keyed by
0120: * context name.
0121: */
0122: private HashMap webXmlLastModified = new HashMap();
0123:
0124: /**
0125: * Last modified dates of the Context xml files of the contexts, keyed by
0126: * context name.
0127: */
0128: private HashMap contextXmlLastModified = new HashMap();
0129:
0130: /**
0131: * Last modified dates of the source WAR files, keyed by WAR name.
0132: */
0133: private HashMap warLastModified = new HashMap();
0134:
0135: /**
0136: * Attribute value used to turn on/off XML validation
0137: */
0138: private boolean xmlValidation = false;
0139:
0140: /**
0141: * Attribute value used to turn on/off XML namespace awarenes.
0142: */
0143: private boolean xmlNamespaceAware = false;
0144:
0145: // ------------------------------------------------------------- Properties
0146:
0147: /**
0148: * Return the Context configuration class name.
0149: */
0150: public String getConfigClass() {
0151:
0152: return (this .configClass);
0153:
0154: }
0155:
0156: /**
0157: * Set the Context configuration class name.
0158: *
0159: * @param configClass The new Context configuration class name.
0160: */
0161: public void setConfigClass(String configClass) {
0162:
0163: this .configClass = configClass;
0164:
0165: }
0166:
0167: /**
0168: * Return the Context implementation class name.
0169: */
0170: public String getContextClass() {
0171:
0172: return (this .contextClass);
0173:
0174: }
0175:
0176: /**
0177: * Set the Context implementation class name.
0178: *
0179: * @param contextClass The new Context implementation class name.
0180: */
0181: public void setContextClass(String contextClass) {
0182:
0183: this .contextClass = contextClass;
0184:
0185: }
0186:
0187: /**
0188: * Return the debugging detail level for this component.
0189: */
0190: public int getDebug() {
0191:
0192: return (this .debug);
0193:
0194: }
0195:
0196: /**
0197: * Set the debugging detail level for this component.
0198: *
0199: * @param debug The new debugging detail level
0200: */
0201: public void setDebug(int debug) {
0202:
0203: this .debug = debug;
0204:
0205: }
0206:
0207: /**
0208: * Return the deploy XML config file flag for this component.
0209: */
0210: public boolean isDeployXML() {
0211:
0212: return (this .deployXML);
0213:
0214: }
0215:
0216: /**
0217: * Set the deploy XML config file flag for this component.
0218: *
0219: * @param deployXML The new deploy XML flag
0220: */
0221: public void setDeployXML(boolean deployXML) {
0222:
0223: this .deployXML = deployXML;
0224:
0225: }
0226:
0227: /**
0228: * Return the unpack WARs flag.
0229: */
0230: public boolean isUnpackWARs() {
0231:
0232: return (this .unpackWARs);
0233:
0234: }
0235:
0236: /**
0237: * Set the unpack WARs flag.
0238: *
0239: * @param unpackWARs The new unpack WARs flag
0240: */
0241: public void setUnpackWARs(boolean unpackWARs) {
0242:
0243: this .unpackWARs = unpackWARs;
0244:
0245: }
0246:
0247: /**
0248: * Set the validation feature of the XML parser used when
0249: * parsing xml instances.
0250: * @param xmlValidation true to enable xml instance validation
0251: */
0252: public void setXmlValidation(boolean xmlValidation) {
0253: this .xmlValidation = xmlValidation;
0254: }
0255:
0256: /**
0257: * Get the server.xml <host> attribute's xmlValidation.
0258: * @return true if validation is enabled.
0259: *
0260: */
0261: public boolean getXmlValidation() {
0262: return xmlValidation;
0263: }
0264:
0265: /**
0266: * Get the server.xml <host> attribute's xmlNamespaceAware.
0267: * @return true if namespace awarenes is enabled.
0268: *
0269: */
0270: public boolean getXmlNamespaceAware() {
0271: return xmlNamespaceAware;
0272: }
0273:
0274: /**
0275: * Set the namespace aware feature of the XML parser used when
0276: * parsing xml instances.
0277: * @param xmlNamespaceAware true to enable namespace awareness
0278: */
0279: public void setXmlNamespaceAware(boolean xmlNamespaceAware) {
0280: this .xmlNamespaceAware = xmlNamespaceAware;
0281: }
0282:
0283: // --------------------------------------------------------- Public Methods
0284:
0285: /**
0286: * Process the START event for an associated Host.
0287: *
0288: * @param event The lifecycle event that has occurred
0289: */
0290: public void lifecycleEvent(LifecycleEvent event) {
0291:
0292: if (event.getType().equals("check"))
0293: check();
0294:
0295: // Identify the host we are associated with
0296: try {
0297: host = (Host) event.getLifecycle();
0298: if (host instanceof StandardHost) {
0299: int hostDebug = ((StandardHost) host).getDebug();
0300: if (hostDebug > this .debug) {
0301: this .debug = hostDebug;
0302: }
0303: setDeployXML(((StandardHost) host).isDeployXML());
0304: setUnpackWARs(((StandardHost) host).isUnpackWARs());
0305: setXmlNamespaceAware(((StandardHost) host)
0306: .getXmlNamespaceAware());
0307: setXmlValidation(((StandardHost) host)
0308: .getXmlValidation());
0309: }
0310: } catch (ClassCastException e) {
0311: log.error(sm.getString("hostConfig.cce", event
0312: .getLifecycle()), e);
0313: return;
0314: }
0315:
0316: // Process the event that has occurred
0317: if (event.getType().equals(Lifecycle.START_EVENT))
0318: start();
0319: else if (event.getType().equals(Lifecycle.STOP_EVENT))
0320: stop();
0321:
0322: }
0323:
0324: // ------------------------------------------------------ Protected Methods
0325:
0326: /**
0327: * Return a File object representing the "application root" directory
0328: * for our associated Host.
0329: */
0330: protected File appBase() {
0331:
0332: if (appBase != null) {
0333: return appBase;
0334: }
0335:
0336: File file = new File(host.getAppBase());
0337: if (!file.isAbsolute())
0338: file = new File(System.getProperty("catalina.base"), host
0339: .getAppBase());
0340: try {
0341: appBase = file.getCanonicalFile();
0342: } catch (IOException e) {
0343: appBase = file;
0344: }
0345: return (appBase);
0346:
0347: }
0348:
0349: /**
0350: * Return a File object representing the "configuration root" directory
0351: * for our associated Host.
0352: */
0353: protected File configBase() {
0354:
0355: if (configBase != null) {
0356: return configBase;
0357: }
0358:
0359: File file = new File(System.getProperty("catalina.base"),
0360: "conf");
0361: Container parent = host.getParent();
0362: if ((parent != null) && (parent instanceof Engine)) {
0363: file = new File(file, parent.getName());
0364: }
0365: file = new File(file, host.getName());
0366: try {
0367: configBase = file.getCanonicalFile();
0368: } catch (IOException e) {
0369: configBase = file;
0370: }
0371: return (configBase);
0372:
0373: }
0374:
0375: /**
0376: * Deploy applications for any directories or WAR files that are found
0377: * in our "application root" directory.
0378: */
0379: protected void deployApps() {
0380:
0381: if (!(host instanceof Deployer))
0382: return;
0383:
0384: // Initialize the deployer
0385: ((Deployer) host).findDeployedApps();
0386:
0387: File appBase = appBase();
0388: if (!appBase.exists() || !appBase.isDirectory())
0389: return;
0390: File configBase = configBase();
0391: if (configBase.exists() && configBase.isDirectory()) {
0392: String configFiles[] = configBase.list();
0393: deployDescriptors(configBase, configFiles);
0394: }
0395:
0396: String files[] = appBase.list();
0397: deployWARs(appBase, files);
0398: deployDirectories(appBase, files);
0399:
0400: }
0401:
0402: /**
0403: * Deploy XML context descriptors.
0404: */
0405: protected void deployDescriptors(File configBase, String[] files) {
0406:
0407: if (!deployXML || (files == null)) {
0408: return;
0409: }
0410:
0411: for (int i = 0; i < files.length; i++) {
0412:
0413: if (files[i].equalsIgnoreCase("META-INF"))
0414: continue;
0415: if (files[i].equalsIgnoreCase("WEB-INF"))
0416: continue;
0417: if (deployed.contains(files[i]))
0418: continue;
0419: File dir = new File(configBase, files[i]);
0420: if (files[i].toLowerCase().endsWith(".xml")) {
0421:
0422: deployed.add(files[i]);
0423:
0424: // Calculate the context path and make sure it is unique
0425: String file = files[i].substring(0,
0426: files[i].length() - 4);
0427: String contextPath = "/" + file.replace('#', '/');
0428: if (file.equals("ROOT")) {
0429: contextPath = "";
0430: }
0431:
0432: // Assume this is a configuration descriptor and deploy it
0433: log.debug(sm.getString("hostConfig.deployDescriptor",
0434: files[i]));
0435: try {
0436: if (host.findChild(contextPath) != null) {
0437: if ((deployed.contains(file))
0438: || (deployed.contains(file + ".war"))) {
0439: // If this is a newly added context file and
0440: // it overrides a context with a simple path,
0441: // that was previously deployed by the auto
0442: // deployer, undeploy the context
0443: ((Deployer) host).remove(contextPath);
0444: } else {
0445: continue;
0446: }
0447: }
0448: URL config = new URL("file", null, dir
0449: .getCanonicalPath());
0450: ((Deployer) host).install(config, null);
0451: } catch (Throwable t) {
0452: log.error(sm.getString(
0453: "hostConfig.deployDescriptor.error",
0454: files[i]), t);
0455: }
0456:
0457: }
0458:
0459: }
0460:
0461: }
0462:
0463: /**
0464: * Deploy WAR files.
0465: */
0466: protected void deployWARs(File appBase, String[] files) {
0467: if (files == null) {
0468: return;
0469: }
0470:
0471: for (int i = 0; i < files.length; i++) {
0472:
0473: if (files[i].equalsIgnoreCase("META-INF"))
0474: continue;
0475: if (files[i].equalsIgnoreCase("WEB-INF"))
0476: continue;
0477: if (deployed.contains(files[i]))
0478: continue;
0479: File dir = new File(appBase, files[i]);
0480:
0481: if (files[i].toLowerCase().endsWith(".war")) {
0482:
0483: deployed.add(files[i]);
0484:
0485: // Calculate the context path and make sure it is unique
0486: String contextPath = "/" + files[i];
0487: int period = contextPath.lastIndexOf(".");
0488: if (period >= 0)
0489: contextPath = contextPath.substring(0, period);
0490: if (contextPath.equals("/ROOT"))
0491: contextPath = "";
0492: if (host.findChild(contextPath) != null)
0493: continue;
0494:
0495: // Checking for a nested /META-INF/context.xml
0496: JarFile jar = null;
0497: JarEntry entry = null;
0498: InputStream istream = null;
0499: BufferedOutputStream ostream = null;
0500: File xml = new File(configBase, files[i].substring(0,
0501: files[i].lastIndexOf("."))
0502: + ".xml");
0503:
0504: if (!xml.exists()) {
0505:
0506: try {
0507: // Added for Bugzilla 29038
0508: if (!configBase.exists()) {
0509: configBase.mkdirs();
0510: }
0511:
0512: jar = new JarFile(dir);
0513: entry = jar.getJarEntry("META-INF/context.xml");
0514: if (entry != null) {
0515: istream = jar.getInputStream(entry);
0516: ostream = new BufferedOutputStream(
0517: new FileOutputStream(xml), 1024);
0518: byte buffer[] = new byte[1024];
0519: while (true) {
0520: int n = istream.read(buffer);
0521: if (n < 0) {
0522: break;
0523: }
0524: ostream.write(buffer, 0, n);
0525: }
0526: ostream.flush();
0527: ostream.close();
0528: ostream = null;
0529: istream.close();
0530: istream = null;
0531: entry = null;
0532: jar.close();
0533: jar = null;
0534: deployDescriptors(configBase(), configBase
0535: .list());
0536: return;
0537: }
0538: } catch (Exception e) {
0539: // Ignore and continue
0540: if (ostream != null) {
0541: try {
0542: ostream.close();
0543: } catch (Throwable t) {
0544: ;
0545: }
0546: ostream = null;
0547: }
0548: if (istream != null) {
0549: try {
0550: istream.close();
0551: } catch (Throwable t) {
0552: ;
0553: }
0554: istream = null;
0555: }
0556: } finally {
0557: entry = null;
0558: if (jar != null) {
0559: try {
0560: jar.close();
0561: } catch (Throwable t) {
0562: ;
0563: }
0564: jar = null;
0565: }
0566: }
0567: }
0568:
0569: if (isUnpackWARs()) {
0570:
0571: // Expand and deploy this application as a directory
0572: log.debug(sm.getString("hostConfig.expand",
0573: files[i]));
0574: URL url = null;
0575: String path = null;
0576: try {
0577: url = new URL("jar:file:"
0578: + dir.getCanonicalPath() + "!/");
0579: path = ExpandWar.expand(host, url);
0580: } catch (IOException e) {
0581: // JAR decompression failure
0582: log.warn(sm.getString(
0583: "hostConfig.expand.error", files[i]));
0584: continue;
0585: } catch (Throwable t) {
0586: log
0587: .error(sm.getString(
0588: "hostConfig.expand.error",
0589: files[i]), t);
0590: continue;
0591: }
0592: try {
0593: if (path != null) {
0594: url = new URL("file:" + path);
0595: ((Deployer) host).install(contextPath, url);
0596: }
0597: } catch (Throwable t) {
0598: log
0599: .error(sm.getString(
0600: "hostConfig.expand.error",
0601: files[i]), t);
0602: }
0603:
0604: } else {
0605:
0606: // Deploy the application in this WAR file
0607: log.info(sm.getString("hostConfig.deployJar",
0608: files[i]));
0609: try {
0610: URL url = new URL("file", null, dir
0611: .getCanonicalPath());
0612: url = new URL("jar:" + url.toString() + "!/");
0613: ((Deployer) host).install(contextPath, url);
0614: } catch (Throwable t) {
0615: log.error(
0616: sm.getString(
0617: "hostConfig.deployJar.error",
0618: files[i]), t);
0619: }
0620:
0621: }
0622:
0623: }
0624:
0625: }
0626:
0627: }
0628:
0629: /**
0630: * Deploy directories.
0631: *
0632: * @param appBase The Host appBase
0633: * @param files[] The files to deploy
0634: */
0635: protected void deployDirectories(File appBase, String[] files) {
0636: if (files == null) {
0637: return;
0638: }
0639:
0640: for (int i = 0; i < files.length; i++) {
0641:
0642: if (files[i].equalsIgnoreCase("META-INF"))
0643: continue;
0644: if (files[i].equalsIgnoreCase("WEB-INF"))
0645: continue;
0646: if (deployed.contains(files[i]))
0647: continue;
0648: File dir = new File(appBase, files[i]);
0649: if (dir.isDirectory()) {
0650:
0651: deployed.add(files[i]);
0652:
0653: // Make sure there is an application configuration directory
0654: // This is needed if the Context appBase is the same as the
0655: // web server document root to make sure only web applications
0656: // are deployed and not directories for web space.
0657: File webInf = new File(dir, "/WEB-INF");
0658: if (!webInf.exists() || !webInf.isDirectory()
0659: || !webInf.canRead())
0660: continue;
0661:
0662: // Calculate the context path and make sure it is unique
0663: String contextPath = "/" + files[i];
0664: if (files[i].equals("ROOT"))
0665: contextPath = "";
0666: if (host.findChild(contextPath) != null)
0667: continue;
0668:
0669: // Deploy the application in this directory
0670: if (log.isDebugEnabled())
0671: log.debug(sm.getString("hostConfig.deployDir",
0672: files[i]));
0673: long t1 = System.currentTimeMillis();
0674: try {
0675: URL url = new URL("file", null, dir
0676: .getCanonicalPath());
0677: ((Deployer) host).install(contextPath, url);
0678: } catch (Throwable t) {
0679: log.error(sm.getString(
0680: "hostConfig.deployDir.error", files[i]), t);
0681: }
0682: long t2 = System.currentTimeMillis();
0683: if ((t2 - t1) > 200)
0684: log.debug("Deployed " + files[i] + " " + (t2 - t1));
0685: }
0686:
0687: }
0688:
0689: }
0690:
0691: /**
0692: * Check deployment descriptors last modified date.
0693: */
0694: protected void checkContextLastModified() {
0695:
0696: if (!(host instanceof Deployer))
0697: return;
0698:
0699: Deployer deployer = (Deployer) host;
0700:
0701: String[] contextNames = deployer.findDeployedApps();
0702:
0703: for (int i = 0; i < contextNames.length; i++) {
0704:
0705: String contextName = contextNames[i];
0706: Context context = deployer.findDeployedApp(contextName);
0707:
0708: if (!(context instanceof Lifecycle))
0709: continue;
0710:
0711: try {
0712: DirContext resources = context.getResources();
0713: if (resources == null) {
0714: // This can happen if there was an error initializing
0715: // the context
0716: continue;
0717: }
0718: ResourceAttributes webXmlAttributes = (ResourceAttributes) resources
0719: .getAttributes("/WEB-INF/web.xml");
0720: ResourceAttributes webInfAttributes = (ResourceAttributes) resources
0721: .getAttributes("/WEB-INF");
0722: long newLastModified = webXmlAttributes
0723: .getLastModified();
0724: long webInfLastModified = webInfAttributes
0725: .getLastModified();
0726: Long lastModified = (Long) webXmlLastModified
0727: .get(contextName);
0728: if (lastModified == null) {
0729: webXmlLastModified.put(contextName, new Long(
0730: newLastModified));
0731: } else {
0732: if (lastModified.longValue() != newLastModified) {
0733: if (newLastModified > (webInfLastModified + 5000)) {
0734: webXmlLastModified.remove(contextName);
0735: restartContext(context);
0736: } else {
0737: webXmlLastModified.put(contextName,
0738: new Long(newLastModified));
0739: }
0740: }
0741: }
0742: } catch (NamingException e) {
0743: ; // Ignore
0744: }
0745:
0746: Long lastModified = (Long) contextXmlLastModified
0747: .get(contextName);
0748: String configBase = configBase().getPath();
0749: String configFileName = context.getConfigFile();
0750: if (configFileName != null) {
0751: File configFile = new File(configFileName);
0752: if (!configFile.isAbsolute()) {
0753: configFile = new File(System
0754: .getProperty("catalina.base"), configFile
0755: .getPath());
0756: }
0757: long newLastModified = configFile.lastModified();
0758: if (lastModified == null) {
0759: contextXmlLastModified.put(contextName, new Long(
0760: newLastModified));
0761: } else {
0762: if (lastModified.longValue() != newLastModified) {
0763: contextXmlLastModified.remove(contextName);
0764: String fileName = configFileName;
0765: if (fileName.startsWith(configBase)) {
0766: fileName = fileName.substring(configBase
0767: .length() + 1);
0768: try {
0769: deployed.remove(fileName);
0770: if (host.findChild(contextName) != null) {
0771: ((Deployer) host)
0772: .remove(contextName);
0773: }
0774: } catch (Throwable t) {
0775: log.error(sm.getString(
0776: "hostConfig.undeployJar.error",
0777: fileName), t);
0778: }
0779: deployApps();
0780: }
0781: }
0782: }
0783: }
0784:
0785: }
0786:
0787: // Check for WAR modification
0788: if (isUnpackWARs()) {
0789: File appBase = appBase();
0790: if (!appBase.exists() || !appBase.isDirectory())
0791: return;
0792: String files[] = appBase.list();
0793:
0794: if (files != null) {
0795: for (int i = 0; i < files.length; i++) {
0796: if (files[i].endsWith(".war")) {
0797: File dir = new File(appBase, files[i]);
0798: Long lastModified = (Long) warLastModified
0799: .get(files[i]);
0800: long dirLastModified = dir.lastModified();
0801: if (lastModified == null) {
0802: warLastModified.put(files[i], new Long(dir
0803: .lastModified()));
0804: } else if (dirLastModified > lastModified
0805: .longValue()) {
0806: // The WAR has been modified: redeploy
0807: String expandedDir = files[i];
0808: int period = expandedDir.lastIndexOf(".");
0809: if (period >= 0)
0810: expandedDir = expandedDir.substring(0,
0811: period);
0812: File expanded = new File(appBase,
0813: expandedDir);
0814: String contextPath = "/" + expandedDir;
0815: if (contextPath.equals("/ROOT"))
0816: contextPath = "";
0817: if (dirLastModified > expanded
0818: .lastModified()) {
0819: try {
0820: // Undeploy current application
0821: deployed.remove(files[i]);
0822: deployed.remove(expandedDir
0823: + ".xml");
0824: if (host.findChild(contextPath) != null) {
0825: ((Deployer) host).remove(
0826: contextPath, false);
0827: ExpandWar.deleteDir(expanded);
0828: }
0829: } catch (Throwable t) {
0830: log
0831: .error(
0832: sm
0833: .getString(
0834: "hostConfig.undeployJar.error",
0835: files[i]),
0836: t);
0837: }
0838: deployApps();
0839: }
0840: // If deployment was successful, reset
0841: // the last modified values
0842: if (host.findChild(contextPath) != null) {
0843: webXmlLastModified.remove(contextPath);
0844: warLastModified.put(files[i], new Long(
0845: dir.lastModified()));
0846: }
0847: }
0848: }
0849: }
0850: }
0851: }
0852: }
0853:
0854: protected boolean restartContext(Context context) {
0855: boolean result = true;
0856: log.info("restartContext(" + context.getName() + ")");
0857:
0858: if (context instanceof StandardContext) {
0859: try {
0860: StandardContext sctx = (StandardContext) context;
0861: sctx.reload();
0862: } catch (Exception e) {
0863: log.warn(sm.getString("hostConfig.context.restart",
0864: context.getName()), e);
0865: result = false;
0866: }
0867: } else {
0868: try {
0869: ((Lifecycle) context).stop();
0870: } catch (Exception e) {
0871: log.warn(sm.getString("hostConfig.context.restart",
0872: context.getName()), e);
0873: }
0874: // If the context was not started (for example an error
0875: // in web.xml) we'll still get to try to start
0876: try {
0877: ((Lifecycle) context).start();
0878: } catch (Exception e) {
0879: log.warn(sm.getString("hostConfig.context.restart",
0880: context.getName()), e);
0881: result = false;
0882: }
0883: }
0884:
0885: return result;
0886: }
0887:
0888: /**
0889: * Expand the WAR file found at the specified URL into an unpacked
0890: * directory structure, and return the absolute pathname to the expanded
0891: * directory.
0892: *
0893: * @param war URL of the web application archive to be expanded
0894: * (must start with "jar:")
0895: *
0896: * @exception IllegalArgumentException if this is not a "jar:" URL
0897: * @exception IOException if an input/output error was encountered
0898: * during expansion
0899: */
0900: protected String expand(URL war) throws IOException {
0901:
0902: return ExpandWar.expand(host, war);
0903: }
0904:
0905: /**
0906: * Expand the specified input stream into the specified directory, creating
0907: * a file named from the specified relative path.
0908: *
0909: * @param input InputStream to be copied
0910: * @param docBase Document base directory into which we are expanding
0911: * @param name Relative pathname of the file to be created
0912: *
0913: * @exception IOException if an input/output error occurs
0914: */
0915: protected void expand(InputStream input, File docBase, String name)
0916: throws IOException {
0917:
0918: ExpandWar.expand(input, docBase, name);
0919: }
0920:
0921: /**
0922: * Log a message on the Logger associated with our Host (if any)
0923: *
0924: * @param message Message to be logged
0925: */
0926: protected void log(String message) {
0927:
0928: Logger logger = null;
0929: if (host != null)
0930: logger = host.getLogger();
0931: if (logger != null)
0932: logger
0933: .log("HostConfig[" + host.getName() + "]: "
0934: + message);
0935: else
0936: log.info(message);
0937: }
0938:
0939: /**
0940: * Log a message on the Logger associated with our Host (if any)
0941: *
0942: * @param message Message to be logged
0943: * @param throwable Associated exception
0944: */
0945: protected void log(String message, Throwable throwable) {
0946:
0947: Logger logger = null;
0948: if (host != null)
0949: logger = host.getLogger();
0950: if (logger != null)
0951: logger.log("HostConfig[" + host.getName() + "] " + message,
0952: throwable);
0953: else {
0954: log.error(message, throwable);
0955: }
0956:
0957: }
0958:
0959: /**
0960: * Process a "start" event for this Host.
0961: */
0962: public void start() {
0963:
0964: if (log.isDebugEnabled())
0965: log.debug(sm.getString("hostConfig.start"));
0966:
0967: if (host.getDeployOnStartup()) {
0968: deployApps();
0969: } else {
0970: // Deploy descriptors anyway (it should be equivalent to being
0971: // part of server.xml)
0972: File configBase = configBase();
0973: if (configBase.exists() && configBase.isDirectory()) {
0974: String configFiles[] = configBase.list();
0975: deployDescriptors(configBase, configFiles);
0976: }
0977: }
0978:
0979: }
0980:
0981: /**
0982: * Process a "stop" event for this Host.
0983: */
0984: public void stop() {
0985:
0986: if (log.isDebugEnabled())
0987: log.debug(sm.getString("hostConfig.stop"));
0988:
0989: undeployApps();
0990:
0991: appBase = null;
0992: configBase = null;
0993:
0994: }
0995:
0996: /**
0997: * Undeploy all deployed applications.
0998: */
0999: protected void undeployApps() {
1000:
1001: if (!(host instanceof Deployer))
1002: return;
1003: if (log.isDebugEnabled())
1004: log.debug(sm.getString("hostConfig.undeploying"));
1005:
1006: String contextPaths[] = ((Deployer) host).findDeployedApps();
1007: for (int i = 0; i < contextPaths.length; i++) {
1008: if (log.isDebugEnabled())
1009: log.debug(sm.getString("hostConfig.undeploy",
1010: contextPaths[i]));
1011: try {
1012: ((Deployer) host).remove(contextPaths[i]);
1013: } catch (Throwable t) {
1014: log.error(sm.getString("hostConfig.undeploy.error",
1015: contextPaths[i]), t);
1016: }
1017: }
1018:
1019: webXmlLastModified.clear();
1020: deployed.clear();
1021:
1022: }
1023:
1024: /**
1025: * Check remove wars, dir and context xml's
1026: */
1027: protected void checkRemoveApps() {
1028: File appBase = appBase();
1029: File configBase = configBase();
1030: List currentDeployed = (List) deployed.clone();
1031: Iterator iter = currentDeployed.iterator();
1032: while (iter.hasNext()) {
1033: String filename = (String) iter.next();
1034: if (filename.toLowerCase().endsWith(".xml")) {
1035: File file = new File(configBase, filename);
1036: if (!file.exists()) {
1037: log.debug(sm.getString("hostConfig.removeXML",
1038: filename));
1039: deployed.remove(filename);
1040: }
1041: continue;
1042: }
1043: File file = new File(appBase, filename);
1044: if (!file.exists()) {
1045: if (log.isDebugEnabled()) {
1046: if (filename.toLowerCase().endsWith(".war"))
1047: log.debug(sm.getString("hostConfig.removeDIR",
1048: filename));
1049: else
1050: log.debug(sm.getString("hostConfig.removeWAR",
1051: filename));
1052: }
1053: deployed.remove(filename);
1054: }
1055: }
1056: }
1057:
1058: /**
1059: * Deploy webapps.
1060: */
1061: protected void check() {
1062:
1063: if (host.getAutoDeploy()) {
1064: checkRemoveApps();
1065: // Deploy apps if the Host allows auto deploying
1066: deployApps();
1067: // Check for web.xml modification
1068: checkContextLastModified();
1069: }
1070:
1071: }
1072:
1073: }
|