001: /*
002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/HostConfig.java,v 1.23 2002/05/30 22:12:28 remm Exp $
003: * $Revision: 1.23 $
004: * $Date: 2002/05/30 22:12:28 $
005: *
006: * ====================================================================
007: *
008: * The Apache Software License, Version 1.1
009: *
010: * Copyright (c) 1999 The Apache Software Foundation. All rights
011: * reserved.
012: *
013: * Redistribution and use in source and binary forms, with or without
014: * modification, are permitted provided that the following conditions
015: * are met:
016: *
017: * 1. Redistributions of source code must retain the above copyright
018: * notice, this list of conditions and the following disclaimer.
019: *
020: * 2. Redistributions in binary form must reproduce the above copyright
021: * notice, this list of conditions and the following disclaimer in
022: * the documentation and/or other materials provided with the
023: * distribution.
024: *
025: * 3. The end-user documentation included with the redistribution, if
026: * any, must include the following acknowlegement:
027: * "This product includes software developed by the
028: * Apache Software Foundation (http://www.apache.org/)."
029: * Alternately, this acknowlegement may appear in the software itself,
030: * if and wherever such third-party acknowlegements normally appear.
031: *
032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
033: * Foundation" must not be used to endorse or promote products derived
034: * from this software without prior written permission. For written
035: * permission, please contact apache@apache.org.
036: *
037: * 5. Products derived from this software may not be called "Apache"
038: * nor may "Apache" appear in their names without prior written
039: * permission of the Apache Group.
040: *
041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
052: * SUCH DAMAGE.
053: * ====================================================================
054: *
055: * This software consists of voluntary contributions made by many
056: * individuals on behalf of the Apache Software Foundation. For more
057: * information on the Apache Software Foundation, please see
058: * <http://www.apache.org/>.
059: *
060: * [Additional notices, if required by prior licensing conditions]
061: *
062: */
063:
064: package org.apache.catalina.startup;
065:
066: import java.io.BufferedOutputStream;
067: import java.io.File;
068: import java.io.FileInputStream;
069: import java.io.FileNotFoundException;
070: import java.io.FileOutputStream;
071: import java.io.InputStream;
072: import java.io.IOException;
073: import java.lang.reflect.InvocationTargetException;
074: import java.net.JarURLConnection;
075: import java.net.MalformedURLException;
076: import java.net.URL;
077: import java.util.ArrayList;
078: import java.util.Enumeration;
079: import java.util.HashMap;
080: import java.util.jar.JarEntry;
081: import java.util.jar.JarFile;
082: import javax.naming.NamingException;
083: import javax.naming.directory.DirContext;
084: import org.apache.naming.resources.ResourceAttributes;
085: import org.apache.catalina.Context;
086: import org.apache.catalina.Deployer;
087: import org.apache.catalina.Host;
088: import org.apache.catalina.Lifecycle;
089: import org.apache.catalina.LifecycleEvent;
090: import org.apache.catalina.LifecycleException;
091: import org.apache.catalina.LifecycleListener;
092: import org.apache.catalina.Logger;
093: import org.apache.catalina.core.StandardHost;
094: import org.apache.catalina.util.StringManager;
095:
096: /**
097: * Startup event listener for a <b>Host</b> that configures the properties
098: * of that Host, and the associated defined contexts.
099: *
100: * @author Craig R. McClanahan
101: * @author Remy Maucherat
102: * @version $Revision: 1.23 $ $Date: 2002/05/30 22:12:28 $
103: */
104:
105: public class HostConfig implements LifecycleListener, Runnable {
106:
107: // ----------------------------------------------------- Instance Variables
108:
109: /**
110: * The Java class name of the Context configuration class we should use.
111: */
112: protected String configClass = "org.apache.catalina.startup.ContextConfig";
113:
114: /**
115: * The Java class name of the Context implementation we should use.
116: */
117: protected String contextClass = "org.apache.catalina.core.StandardContext";
118:
119: /**
120: * The debugging detail level for this component.
121: */
122: protected int debug = 0;
123:
124: /**
125: * The names of applications that we have auto-deployed (to avoid
126: * double deployment attempts).
127: */
128: protected ArrayList deployed = new ArrayList();
129:
130: /**
131: * The Host we are associated with.
132: */
133: protected Host host = null;
134:
135: /**
136: * The string resources for this package.
137: */
138: protected static final StringManager sm = StringManager
139: .getManager(Constants.Package);
140:
141: /**
142: * The number of seconds between checks for web app deployment.
143: */
144: private int checkInterval = 15;
145:
146: /**
147: * Should we deploy XML Context config files?
148: */
149: private boolean deployXML = false;
150:
151: /**
152: * Should we monitor the <code>appBase</code> directory for new
153: * applications and automatically deploy them?
154: */
155: private boolean liveDeploy = false;
156:
157: /**
158: * The background thread.
159: */
160: private Thread thread = null;
161:
162: /**
163: * The background thread completion semaphore.
164: */
165: private boolean threadDone = false;
166:
167: /**
168: * Name to register for the background thread.
169: */
170: private String threadName = "HostConfig";
171:
172: /**
173: * Should we unpack WAR files when auto-deploying applications in the
174: * <code>appBase</code> directory?
175: */
176: private boolean unpackWARs = false;
177:
178: /**
179: * Last modified dates of the web.xml files of the contexts, keyed by
180: * context name.
181: */
182: private HashMap webXmlLastModified = new HashMap();
183:
184: // ------------------------------------------------------------- Properties
185:
186: /**
187: * Return the Context configuration class name.
188: */
189: public String getConfigClass() {
190:
191: return (this .configClass);
192:
193: }
194:
195: /**
196: * Set the Context configuration class name.
197: *
198: * @param configClass The new Context configuration class name.
199: */
200: public void setConfigClass(String configClass) {
201:
202: this .configClass = configClass;
203:
204: }
205:
206: /**
207: * Return the Context implementation class name.
208: */
209: public String getContextClass() {
210:
211: return (this .contextClass);
212:
213: }
214:
215: /**
216: * Set the Context implementation class name.
217: *
218: * @param contextClass The new Context implementation class name.
219: */
220: public void setContextClass(String contextClass) {
221:
222: this .contextClass = contextClass;
223:
224: }
225:
226: /**
227: * Return the debugging detail level for this component.
228: */
229: public int getDebug() {
230:
231: return (this .debug);
232:
233: }
234:
235: /**
236: * Set the debugging detail level for this component.
237: *
238: * @param debug The new debugging detail level
239: */
240: public void setDebug(int debug) {
241:
242: this .debug = debug;
243:
244: }
245:
246: /**
247: * Return the deploy XML config file flag for this component.
248: */
249: public boolean isDeployXML() {
250:
251: return (this .deployXML);
252:
253: }
254:
255: /**
256: * Set the deploy XML config file flag for this component.
257: *
258: * @param deployXML The new deploy XML flag
259: */
260: public void setDeployXML(boolean deployXML) {
261:
262: this .deployXML = deployXML;
263:
264: }
265:
266: /**
267: * Return the live deploy flag for this component.
268: */
269: public boolean isLiveDeploy() {
270:
271: return (this .liveDeploy);
272:
273: }
274:
275: /**
276: * Set the live deploy flag for this component.
277: *
278: * @param liveDeploy The new live deploy flag
279: */
280: public void setLiveDeploy(boolean liveDeploy) {
281:
282: this .liveDeploy = liveDeploy;
283:
284: }
285:
286: /**
287: * Return the unpack WARs flag.
288: */
289: public boolean isUnpackWARs() {
290:
291: return (this .unpackWARs);
292:
293: }
294:
295: /**
296: * Set the unpack WARs flag.
297: *
298: * @param unpackWARs The new unpack WARs flag
299: */
300: public void setUnpackWARs(boolean unpackWARs) {
301:
302: this .unpackWARs = unpackWARs;
303:
304: }
305:
306: // --------------------------------------------------------- Public Methods
307:
308: /**
309: * Process the START event for an associated Host.
310: *
311: * @param event The lifecycle event that has occurred
312: */
313: public void lifecycleEvent(LifecycleEvent event) {
314:
315: // Identify the host we are associated with
316: try {
317: host = (Host) event.getLifecycle();
318: if (host instanceof StandardHost) {
319: int hostDebug = ((StandardHost) host).getDebug();
320: if (hostDebug > this .debug) {
321: this .debug = hostDebug;
322: }
323: setDeployXML(((StandardHost) host).isDeployXML());
324: setLiveDeploy(((StandardHost) host).getLiveDeploy());
325: setUnpackWARs(((StandardHost) host).isUnpackWARs());
326: }
327: } catch (ClassCastException e) {
328: log(sm.getString("hostConfig.cce", event.getLifecycle()), e);
329: return;
330: }
331:
332: // Process the event that has occurred
333: if (event.getType().equals(Lifecycle.START_EVENT))
334: start();
335: else if (event.getType().equals(Lifecycle.STOP_EVENT))
336: stop();
337:
338: }
339:
340: // ------------------------------------------------------ Protected Methods
341:
342: /**
343: * Return a File object representing the "application root" directory
344: * for our associated Host.
345: */
346: protected File appBase() {
347:
348: File file = new File(host.getAppBase());
349: if (!file.isAbsolute())
350: file = new File(System.getProperty("catalina.base"), host
351: .getAppBase());
352: return (file);
353:
354: }
355:
356: /**
357: * Deploy applications for any directories or WAR files that are found
358: * in our "application root" directory.
359: */
360: protected void deployApps() {
361:
362: if (!(host instanceof Deployer))
363: return;
364: if (debug >= 1)
365: log(sm.getString("hostConfig.deploying"));
366:
367: File appBase = appBase();
368: if (!appBase.exists() || !appBase.isDirectory())
369: return;
370: String files[] = appBase.list();
371:
372: deployDescriptors(appBase, files);
373: deployWARs(appBase, files);
374: deployDirectories(appBase, files);
375:
376: }
377:
378: /**
379: * Deploy XML context descriptors.
380: */
381: protected void deployDescriptors(File appBase, String[] files) {
382:
383: if (!deployXML)
384: return;
385:
386: for (int i = 0; i < files.length; i++) {
387:
388: if (files[i].equalsIgnoreCase("META-INF"))
389: continue;
390: if (files[i].equalsIgnoreCase("WEB-INF"))
391: continue;
392: if (deployed.contains(files[i]))
393: continue;
394: File dir = new File(appBase, files[i]);
395: if (files[i].toLowerCase().endsWith(".xml")) {
396:
397: deployed.add(files[i]);
398:
399: // Calculate the context path and make sure it is unique
400: String file = files[i].substring(0,
401: files[i].length() - 4);
402: String contextPath = "/" + file;
403: if (file.equals("ROOT")) {
404: contextPath = "";
405: }
406: if (host.findChild(contextPath) != null) {
407: continue;
408: }
409:
410: // Assume this is a configuration descriptor and deploy it
411: log(sm.getString("hostConfig.deployDescriptor",
412: files[i]));
413: try {
414: URL config = new URL("file", null, dir
415: .getCanonicalPath());
416: ((Deployer) host).install(config, null);
417: } catch (Throwable t) {
418: log(sm.getString(
419: "hostConfig.deployDescriptor.error",
420: files[i]), t);
421: }
422:
423: }
424:
425: }
426:
427: }
428:
429: /**
430: * Deploy WAR files.
431: */
432: protected void deployWARs(File appBase, String[] files) {
433:
434: for (int i = 0; i < files.length; i++) {
435:
436: if (files[i].equalsIgnoreCase("META-INF"))
437: continue;
438: if (files[i].equalsIgnoreCase("WEB-INF"))
439: continue;
440: if (deployed.contains(files[i]))
441: continue;
442: File dir = new File(appBase, files[i]);
443: if (files[i].toLowerCase().endsWith(".war")) {
444:
445: deployed.add(files[i]);
446:
447: // Calculate the context path and make sure it is unique
448: String contextPath = "/" + files[i];
449: int period = contextPath.lastIndexOf(".");
450: if (period >= 0)
451: contextPath = contextPath.substring(0, period);
452: if (contextPath.equals("/ROOT"))
453: contextPath = "";
454: if (host.findChild(contextPath) != null)
455: continue;
456:
457: if (isUnpackWARs()) {
458:
459: // Expand and deploy this application as a directory
460: log(sm.getString("hostConfig.expand", files[i]));
461: try {
462: URL url = new URL("jar:file:"
463: + dir.getCanonicalPath() + "!/");
464: String path = expand(url);
465: url = new URL("file:" + path);
466: ((Deployer) host).install(contextPath, url);
467: } catch (Throwable t) {
468: log(sm.getString("hostConfig.expand.error",
469: files[i]), t);
470: }
471:
472: } else {
473:
474: // Deploy the application in this WAR file
475: log(sm.getString("hostConfig.deployJar", files[i]));
476: try {
477: URL url = new URL("file", null, dir
478: .getCanonicalPath());
479: url = new URL("jar:" + url.toString() + "!/");
480: ((Deployer) host).install(contextPath, url);
481: } catch (Throwable t) {
482: log(sm.getString("hostConfig.deployJar.error",
483: files[i]), t);
484: }
485:
486: }
487:
488: }
489:
490: }
491:
492: }
493:
494: /**
495: * Deploy directories.
496: */
497: protected void deployDirectories(File appBase, String[] files) {
498:
499: for (int i = 0; i < files.length; i++) {
500:
501: if (files[i].equalsIgnoreCase("META-INF"))
502: continue;
503: if (files[i].equalsIgnoreCase("WEB-INF"))
504: continue;
505: if (deployed.contains(files[i]))
506: continue;
507: File dir = new File(appBase, files[i]);
508: if (dir.isDirectory()) {
509:
510: deployed.add(files[i]);
511:
512: // Make sure there is an application configuration directory
513: // This is needed if the Context appBase is the same as the
514: // web server document root to make sure only web applications
515: // are deployed and not directories for web space.
516: File webInf = new File(dir, "/WEB-INF");
517: if (!webInf.exists() || !webInf.isDirectory()
518: || !webInf.canRead())
519: continue;
520:
521: // Calculate the context path and make sure it is unique
522: String contextPath = "/" + files[i];
523: if (files[i].equals("ROOT"))
524: contextPath = "";
525: if (host.findChild(contextPath) != null)
526: continue;
527:
528: // Deploy the application in this directory
529: log(sm.getString("hostConfig.deployDir", files[i]));
530: try {
531: URL url = new URL("file", null, dir
532: .getCanonicalPath());
533: ((Deployer) host).install(contextPath, url);
534: } catch (Throwable t) {
535: log(sm.getString("hostConfig.deployDir.error",
536: files[i]), t);
537: }
538:
539: }
540:
541: }
542:
543: }
544:
545: /**
546: * Check deployment descriptors last modified date.
547: */
548: protected void checkWebXmlLastModified() {
549:
550: if (!(host instanceof Deployer))
551: return;
552:
553: Deployer deployer = (Deployer) host;
554:
555: String[] contextNames = deployer.findDeployedApps();
556:
557: for (int i = 0; i < contextNames.length; i++) {
558:
559: String contextName = contextNames[i];
560: Context context = deployer.findDeployedApp(contextName);
561:
562: if (!(context instanceof Lifecycle))
563: continue;
564:
565: try {
566: DirContext resources = context.getResources();
567: if (resources == null) {
568: // This can happen if there was an error initializing
569: // the context
570: continue;
571: }
572: ResourceAttributes webXmlAttributes = (ResourceAttributes) resources
573: .getAttributes("/WEB-INF/web.xml");
574: long newLastModified = webXmlAttributes
575: .getLastModified();
576: Long lastModified = (Long) webXmlLastModified
577: .get(contextName);
578: if (lastModified == null) {
579: webXmlLastModified.put(contextName, new Long(
580: newLastModified));
581: } else {
582: if (lastModified.longValue() != newLastModified) {
583: webXmlLastModified.remove(contextName);
584: ((Lifecycle) context).stop();
585: // Note: If the context was already stopped, a
586: // Lifecycle exception will be thrown, and the context
587: // won't be restarted
588: ((Lifecycle) context).start();
589: }
590: }
591: } catch (LifecycleException e) {
592: ; // Ignore
593: } catch (NamingException e) {
594: ; // Ignore
595: }
596:
597: }
598:
599: }
600:
601: /**
602: * Expand the WAR file found at the specified URL into an unpacked
603: * directory structure, and return the absolute pathname to the expanded
604: * directory.
605: *
606: * @param war URL of the web application archive to be expanded
607: * (must start with "jar:")
608: *
609: * @exception IllegalArgumentException if this is not a "jar:" URL
610: * @exception IOException if an input/output error was encountered
611: * during expansion
612: */
613: protected String expand(URL war) throws IOException {
614:
615: // Calculate the directory name of the expanded directory
616: if (getDebug() >= 1) {
617: log("expand(" + war.toString() + ")");
618: }
619: String pathname = war.toString().replace('\\', '/');
620: if (pathname.endsWith("!/")) {
621: pathname = pathname.substring(0, pathname.length() - 2);
622: }
623: int period = pathname.lastIndexOf('.');
624: if (period >= pathname.length() - 4)
625: pathname = pathname.substring(0, period);
626: int slash = pathname.lastIndexOf('/');
627: if (slash >= 0) {
628: pathname = pathname.substring(slash + 1);
629: }
630: if (getDebug() >= 1) {
631: log(" Proposed directory name: " + pathname);
632: }
633:
634: // Make sure that there is no such directory already existing
635: File appBase = new File(host.getAppBase());
636: if (!appBase.isAbsolute()) {
637: appBase = new File(System.getProperty("catalina.base"),
638: host.getAppBase());
639: }
640: if (!appBase.exists() || !appBase.isDirectory()) {
641: throw new IOException(sm.getString("standardHost.appBase",
642: appBase.getAbsolutePath()));
643: }
644: File docBase = new File(appBase, pathname);
645: if (docBase.exists()) {
646: // War file is already installed
647: return (docBase.getAbsolutePath());
648: }
649:
650: // Create the new document base directory
651: docBase.mkdir();
652: if (getDebug() >= 2) {
653: log(" Have created expansion directory "
654: + docBase.getAbsolutePath());
655: }
656:
657: // Expand the WAR into the new document base directory
658: JarURLConnection juc = (JarURLConnection) war.openConnection();
659: juc.setUseCaches(false);
660: /*
661: JarFile jarFile = juc.getJarFile();
662: if (getDebug() >= 2) {
663: log(" Have opened JAR file successfully");
664: }
665: Enumeration jarEntries = jarFile.entries();
666: if (getDebug() >= 2) {
667: log(" Have retrieved entries enumeration");
668: }
669: while (jarEntries.hasMoreElements()) {
670: JarEntry jarEntry = (JarEntry) jarEntries.nextElement();
671: String name = jarEntry.getName();
672: if (getDebug() >= 2) {
673: log(" Am processing entry " + name);
674: }
675: int last = name.lastIndexOf('/');
676: if (last >= 0) {
677: File parent = new File(docBase,
678: name.substring(0, last));
679: if (getDebug() >= 2) {
680: log(" Creating parent directory " + parent);
681: }
682: parent.mkdirs();
683: }
684: if (name.endsWith("/")) {
685: continue;
686: }
687: if (getDebug() >= 2) {
688: log(" Creating expanded file " + name);
689: }
690: InputStream input = jarFile.getInputStream(jarEntry);
691: expand(input, docBase, name);
692: input.close();
693: }
694: jarFile.close();
695: */
696: JarFile jarFile = null;
697: InputStream input = null;
698: try {
699: jarFile = juc.getJarFile();
700: if (getDebug() >= 2) {
701: log(" Have opened JAR file successfully");
702: }
703: Enumeration jarEntries = jarFile.entries();
704: if (getDebug() >= 2) {
705: log(" Have retrieved entries enumeration");
706: }
707: while (jarEntries.hasMoreElements()) {
708: JarEntry jarEntry = (JarEntry) jarEntries.nextElement();
709: String name = jarEntry.getName();
710: if (getDebug() >= 2) {
711: log(" Am processing entry " + name);
712: }
713: int last = name.lastIndexOf('/');
714: if (last >= 0) {
715: File parent = new File(docBase, name.substring(0,
716: last));
717: if (getDebug() >= 2) {
718: log(" Creating parent directory " + parent);
719: }
720: parent.mkdirs();
721: }
722: if (name.endsWith("/")) {
723: continue;
724: }
725: if (getDebug() >= 2) {
726: log(" Creating expanded file " + name);
727: }
728: input = jarFile.getInputStream(jarEntry);
729: expand(input, docBase, name);
730: input.close();
731: input = null;
732: }
733: jarFile.close();
734: jarFile = null;
735: } finally {
736: if (input != null) {
737: try {
738: input.close();
739: } catch (Throwable t) {
740: ;
741: }
742: input = null;
743: }
744: if (jarFile != null) {
745: try {
746: jarFile.close();
747: } catch (Throwable t) {
748: ;
749: }
750: jarFile = null;
751: }
752: }
753:
754: // Return the absolute path to our new document base directory
755: return (docBase.getAbsolutePath());
756:
757: }
758:
759: /**
760: * Expand the specified input stream into the specified directory, creating
761: * a file named from the specified relative path.
762: *
763: * @param input InputStream to be copied
764: * @param docBase Document base directory into which we are expanding
765: * @param name Relative pathname of the file to be created
766: *
767: * @exception IOException if an input/output error occurs
768: */
769: protected void expand(InputStream input, File docBase, String name)
770: throws IOException {
771:
772: File file = new File(docBase, name);
773: BufferedOutputStream output = new BufferedOutputStream(
774: new FileOutputStream(file));
775: byte buffer[] = new byte[2048];
776: while (true) {
777: int n = input.read(buffer);
778: if (n <= 0)
779: break;
780: output.write(buffer, 0, n);
781: }
782: output.close();
783:
784: }
785:
786: /**
787: * Log a message on the Logger associated with our Host (if any)
788: *
789: * @param message Message to be logged
790: */
791: protected void log(String message) {
792:
793: Logger logger = null;
794: if (host != null)
795: logger = host.getLogger();
796: if (logger != null)
797: logger
798: .log("HostConfig[" + host.getName() + "]: "
799: + message);
800: else
801: System.out.println("HostConfig[" + host.getName() + "]: "
802: + message);
803:
804: }
805:
806: /**
807: * Log a message on the Logger associated with our Host (if any)
808: *
809: * @param message Message to be logged
810: * @param throwable Associated exception
811: */
812: protected void log(String message, Throwable throwable) {
813:
814: Logger logger = null;
815: if (host != null)
816: logger = host.getLogger();
817: if (logger != null)
818: logger.log("HostConfig[" + host.getName() + "] " + message,
819: throwable);
820: else {
821: System.out.println("HostConfig[" + host.getName() + "]: "
822: + message);
823: System.out.println("" + throwable);
824: throwable.printStackTrace(System.out);
825: }
826:
827: }
828:
829: /**
830: * Process a "start" event for this Host.
831: */
832: protected void start() {
833:
834: if (debug >= 1)
835: log(sm.getString("hostConfig.start"));
836:
837: if (host.getAutoDeploy()) {
838: deployApps();
839: }
840:
841: if (isLiveDeploy()) {
842: threadStart();
843: }
844:
845: }
846:
847: /**
848: * Process a "stop" event for this Host.
849: */
850: protected void stop() {
851:
852: if (debug >= 1)
853: log(sm.getString("hostConfig.stop"));
854:
855: threadStop();
856:
857: undeployApps();
858:
859: }
860:
861: /**
862: * Undeploy all deployed applications.
863: */
864: protected void undeployApps() {
865:
866: if (!(host instanceof Deployer))
867: return;
868: if (debug >= 1)
869: log(sm.getString("hostConfig.undeploying"));
870:
871: String contextPaths[] = ((Deployer) host).findDeployedApps();
872: for (int i = 0; i < contextPaths.length; i++) {
873: if (debug >= 1)
874: log(sm
875: .getString("hostConfig.undeploy",
876: contextPaths[i]));
877: try {
878: ((Deployer) host).remove(contextPaths[i]);
879: } catch (Throwable t) {
880: log(sm.getString("hostConfig.undeploy.error",
881: contextPaths[i]), t);
882: }
883: }
884:
885: }
886:
887: /**
888: * Start the background thread that will periodically check for
889: * web application autoDeploy and changes to the web.xml config.
890: *
891: * @exception IllegalStateException if we should not be starting
892: * a background thread now
893: */
894: protected void threadStart() {
895:
896: // Has the background thread already been started?
897: if (thread != null)
898: return;
899:
900: // Start the background thread
901: if (debug >= 1)
902: log(" Starting background thread");
903: threadDone = false;
904: threadName = "HostConfig[" + host.getName() + "]";
905: thread = new Thread(this , threadName);
906: thread.setDaemon(true);
907: thread.start();
908:
909: }
910:
911: /**
912: * Stop the background thread that is periodically checking for
913: * for web application autoDeploy and changes to the web.xml config.
914: */
915: protected void threadStop() {
916:
917: if (thread == null)
918: return;
919:
920: if (debug >= 1)
921: log(" Stopping background thread");
922: threadDone = true;
923: thread.interrupt();
924: try {
925: thread.join();
926: } catch (InterruptedException e) {
927: ;
928: }
929:
930: thread = null;
931:
932: }
933:
934: /**
935: * Sleep for the duration specified by the <code>checkInterval</code>
936: * property.
937: */
938: protected void threadSleep() {
939:
940: try {
941: Thread.sleep(checkInterval * 1000L);
942: } catch (InterruptedException e) {
943: ;
944: }
945:
946: }
947:
948: // ------------------------------------------------------ Background Thread
949:
950: /**
951: * The background thread that checks for web application autoDeploy
952: * and changes to the web.xml config.
953: */
954: public void run() {
955:
956: if (debug >= 1)
957: log("BACKGROUND THREAD Starting");
958:
959: // Loop until the termination semaphore is set
960: while (!threadDone) {
961:
962: // Wait for our check interval
963: threadSleep();
964:
965: // Deploy apps if the Host allows auto deploying
966: deployApps();
967:
968: // Check for web.xml modification
969: checkWebXmlLastModified();
970:
971: }
972:
973: if (debug >= 1)
974: log("BACKGROUND THREAD Stopping");
975:
976: }
977:
978: }
|