KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > startup > HostConfig


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18
19 package org.apache.catalina.startup;
20
21
22 import java.io.BufferedOutputStream JavaDoc;
23 import java.io.File JavaDoc;
24 import java.io.FileOutputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.LinkedHashMap JavaDoc;
30 import java.util.jar.JarEntry JavaDoc;
31 import java.util.jar.JarFile JavaDoc;
32
33 import javax.management.ObjectName JavaDoc;
34
35 import org.apache.catalina.Container;
36 import org.apache.catalina.Context;
37 import org.apache.catalina.Engine;
38 import org.apache.catalina.Host;
39 import org.apache.catalina.Lifecycle;
40 import org.apache.catalina.LifecycleEvent;
41 import org.apache.catalina.LifecycleListener;
42 import org.apache.catalina.core.ContainerBase;
43 import org.apache.catalina.core.StandardHost;
44 import org.apache.catalina.util.StringManager;
45 import org.apache.tomcat.util.digester.Digester;
46 import org.apache.tomcat.util.modeler.Registry;
47
48
49 /**
50  * Startup event listener for a <b>Host</b> that configures the properties
51  * of that Host, and the associated defined contexts.
52  *
53  * @author Craig R. McClanahan
54  * @author Remy Maucherat
55  * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
56  */

57 public class HostConfig
58     implements LifecycleListener {
59     
60     protected static org.apache.commons.logging.Log log=
61          org.apache.commons.logging.LogFactory.getLog( HostConfig.class );
62
63     // ----------------------------------------------------- Instance Variables
64

65
66     /**
67      * App base.
68      */

69     protected File JavaDoc appBase = null;
70
71
72     /**
73      * Config base.
74      */

75     protected File JavaDoc configBase = null;
76
77
78     /**
79      * The Java class name of the Context configuration class we should use.
80      */

81     protected String JavaDoc configClass = "org.apache.catalina.startup.ContextConfig";
82
83
84     /**
85      * The Java class name of the Context implementation we should use.
86      */

87     protected String JavaDoc contextClass = "org.apache.catalina.core.StandardContext";
88
89
90     /**
91      * The Host we are associated with.
92      */

93     protected Host host = null;
94
95     
96     /**
97      * The JMX ObjectName of this component.
98      */

99     protected ObjectName JavaDoc oname = null;
100     
101
102     /**
103      * The string resources for this package.
104      */

105     protected static final StringManager sm =
106         StringManager.getManager(Constants.Package);
107
108
109     /**
110      * Should we deploy XML Context config files?
111      */

112     protected boolean deployXML = false;
113
114
115     /**
116      * Should we unpack WAR files when auto-deploying applications in the
117      * <code>appBase</code> directory?
118      */

119     protected boolean unpackWARs = false;
120
121
122     /**
123      * Map of deployed applications.
124      */

125     protected HashMap JavaDoc deployed = new HashMap JavaDoc();
126
127     
128     /**
129      * List of applications which are being serviced, and shouldn't be
130      * deployed/undeployed/redeployed at the moment.
131      */

132     protected ArrayList JavaDoc serviced = new ArrayList JavaDoc();
133     
134
135     /**
136      * Attribute value used to turn on/off XML validation
137      */

138     protected boolean xmlValidation = false;
139
140
141     /**
142      * Attribute value used to turn on/off XML namespace awarenes.
143      */

144     protected boolean xmlNamespaceAware = false;
145
146
147     /**
148      * The <code>Digester</code> instance used to parse context descriptors.
149      */

150     protected static Digester digester = createDigester();
151
152
153     // ------------------------------------------------------------- Properties
154

155
156     /**
157      * Return the Context configuration class name.
158      */

159     public String JavaDoc getConfigClass() {
160
161         return (this.configClass);
162
163     }
164
165
166     /**
167      * Set the Context configuration class name.
168      *
169      * @param configClass The new Context configuration class name.
170      */

171     public void setConfigClass(String JavaDoc configClass) {
172
173         this.configClass = configClass;
174
175     }
176
177
178     /**
179      * Return the Context implementation class name.
180      */

181     public String JavaDoc getContextClass() {
182
183         return (this.contextClass);
184
185     }
186
187
188     /**
189      * Set the Context implementation class name.
190      *
191      * @param contextClass The new Context implementation class name.
192      */

193     public void setContextClass(String JavaDoc contextClass) {
194
195         this.contextClass = contextClass;
196
197     }
198
199
200     /**
201      * Return the deploy XML config file flag for this component.
202      */

203     public boolean isDeployXML() {
204
205         return (this.deployXML);
206
207     }
208
209
210     /**
211      * Set the deploy XML config file flag for this component.
212      *
213      * @param deployXML The new deploy XML flag
214      */

215     public void setDeployXML(boolean deployXML) {
216
217         this.deployXML= deployXML;
218
219     }
220
221
222     /**
223      * Return the unpack WARs flag.
224      */

225     public boolean isUnpackWARs() {
226
227         return (this.unpackWARs);
228
229     }
230
231
232     /**
233      * Set the unpack WARs flag.
234      *
235      * @param unpackWARs The new unpack WARs flag
236      */

237     public void setUnpackWARs(boolean unpackWARs) {
238
239         this.unpackWARs = unpackWARs;
240
241     }
242     
243     
244      /**
245      * Set the validation feature of the XML parser used when
246      * parsing xml instances.
247      * @param xmlValidation true to enable xml instance validation
248      */

249     public void setXmlValidation(boolean xmlValidation){
250         this.xmlValidation = xmlValidation;
251     }
252
253     /**
254      * Get the server.xml <host> attribute's xmlValidation.
255      * @return true if validation is enabled.
256      *
257      */

258     public boolean getXmlValidation(){
259         return xmlValidation;
260     }
261
262     /**
263      * Get the server.xml <host> attribute's xmlNamespaceAware.
264      * @return true if namespace awarenes is enabled.
265      *
266      */

267     public boolean getXmlNamespaceAware(){
268         return xmlNamespaceAware;
269     }
270
271
272     /**
273      * Set the namespace aware feature of the XML parser used when
274      * parsing xml instances.
275      * @param xmlNamespaceAware true to enable namespace awareness
276      */

277     public void setXmlNamespaceAware(boolean xmlNamespaceAware){
278         this.xmlNamespaceAware=xmlNamespaceAware;
279     }
280
281
282     // --------------------------------------------------------- Public Methods
283

284
285     /**
286      * Process the START event for an associated Host.
287      *
288      * @param event The lifecycle event that has occurred
289      */

290     public void lifecycleEvent(LifecycleEvent event) {
291
292         if (event.getType().equals(Lifecycle.PERIODIC_EVENT))
293             check();
294
295         // Identify the host we are associated with
296
try {
297             host = (Host) event.getLifecycle();
298             if (host instanceof StandardHost) {
299                 setDeployXML(((StandardHost) host).isDeployXML());
300                 setUnpackWARs(((StandardHost) host).isUnpackWARs());
301                 setXmlNamespaceAware(((StandardHost) host).getXmlNamespaceAware());
302                 setXmlValidation(((StandardHost) host).getXmlValidation());
303             }
304         } catch (ClassCastException JavaDoc e) {
305             log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
306             return;
307         }
308
309         // Process the event that has occurred
310
if (event.getType().equals(Lifecycle.START_EVENT))
311             start();
312         else if (event.getType().equals(Lifecycle.STOP_EVENT))
313             stop();
314
315     }
316
317     
318     /**
319      * Add a serviced application to the list.
320      */

321     public synchronized void addServiced(String JavaDoc name) {
322         serviced.add(name);
323     }
324     
325     
326     /**
327      * Is application serviced ?
328      * @return state of the application
329      */

330     public synchronized boolean isServiced(String JavaDoc name) {
331         return (serviced.contains(name));
332     }
333     
334
335     /**
336      * Removed a serviced application from the list.
337      */

338     public synchronized void removeServiced(String JavaDoc name) {
339         serviced.remove(name);
340     }
341
342     
343     /**
344      * Get the instant where an application was deployed.
345      * @return 0L if no application with that name is deployed, or the instant
346      * on which the application was deployed
347      */

348     public long getDeploymentTime(String JavaDoc name) {
349         DeployedApplication app = (DeployedApplication) deployed.get(name);
350         if (app == null) {
351             return 0L;
352         } else {
353             return app.timestamp;
354         }
355     }
356     
357     
358     /**
359      * Has the specified application been deployed? Note applications defined
360      * in server.xml will not have been deployed.
361      * @return <code>true</code> if the application has been deployed and
362      * <code>false</code> if the applciation has not been deployed or does not
363      * exist
364      */

365     public boolean isDeployed(String JavaDoc name) {
366         DeployedApplication app = (DeployedApplication) deployed.get(name);
367         if (app == null) {
368             return false;
369         } else {
370             return true;
371         }
372     }
373     
374     
375     // ------------------------------------------------------ Protected Methods
376

377     
378     /**
379      * Create the digester which will be used to parse context config files.
380      */

381     protected static Digester createDigester() {
382         Digester digester = new Digester();
383         digester.setValidating(false);
384         // Add object creation rule
385
digester.addObjectCreate("Context", "org.apache.catalina.core.StandardContext",
386             "className");
387         // Set the properties on that object (it doesn't matter if extra
388
// properties are set)
389
digester.addSetProperties("Context");
390         return (digester);
391     }
392     
393
394     /**
395      * Return a File object representing the "application root" directory
396      * for our associated Host.
397      */

398     protected File JavaDoc appBase() {
399
400         if (appBase != null) {
401             return appBase;
402         }
403
404         File JavaDoc file = new File JavaDoc(host.getAppBase());
405         if (!file.isAbsolute())
406             file = new File JavaDoc(System.getProperty("catalina.base"),
407                             host.getAppBase());
408         try {
409             appBase = file.getCanonicalFile();
410         } catch (IOException JavaDoc e) {
411             appBase = file;
412         }
413         return (appBase);
414
415     }
416
417
418     /**
419      * Return a File object representing the "configuration root" directory
420      * for our associated Host.
421      */

422     protected File JavaDoc configBase() {
423
424         if (configBase != null) {
425             return configBase;
426         }
427
428         File JavaDoc file = new File JavaDoc(System.getProperty("catalina.base"), "conf");
429         Container parent = host.getParent();
430         if ((parent != null) && (parent instanceof Engine)) {
431             file = new File JavaDoc(file, parent.getName());
432         }
433         file = new File JavaDoc(file, host.getName());
434         try {
435             configBase = file.getCanonicalFile();
436         } catch (IOException JavaDoc e) {
437             configBase = file;
438         }
439         return (configBase);
440
441     }
442
443     /**
444      * Get the name of the configBase.
445      * For use with JMX management.
446      */

447     public String JavaDoc getConfigBaseName() {
448         return configBase().getAbsolutePath();
449     }
450
451     /**
452      * Given a context path, get the config file name.
453      */

454     protected String JavaDoc getConfigFile(String JavaDoc path) {
455         String JavaDoc basename = null;
456         if (path.equals("")) {
457             basename = "ROOT";
458         } else {
459             basename = path.substring(1).replace('/', '#');
460         }
461         return (basename);
462     }
463
464     
465     /**
466      * Given a context path, get the config file name.
467      */

468     protected String JavaDoc getDocBase(String JavaDoc path) {
469         String JavaDoc basename = null;
470         if (path.equals("")) {
471             basename = "ROOT";
472         } else {
473             basename = path.substring(1);
474         }
475         return (basename);
476     }
477
478     
479     /**
480      * Deploy applications for any directories or WAR files that are found
481      * in our "application root" directory.
482      */

483     protected void deployApps() {
484
485         File JavaDoc appBase = appBase();
486         File JavaDoc configBase = configBase();
487         // Deploy XML descriptors from configBase
488
deployDescriptors(configBase, configBase.list());
489         // Deploy WARs, and loop if additional descriptors are found
490
deployWARs(appBase, appBase.list());
491         // Deploy expanded folders
492
deployDirectories(appBase, appBase.list());
493         
494     }
495
496
497     /**
498      * Deploy applications for any directories or WAR files that are found
499      * in our "application root" directory.
500      */

501     protected void deployApps(String JavaDoc name) {
502
503         File JavaDoc appBase = appBase();
504         File JavaDoc configBase = configBase();
505         String JavaDoc baseName = getConfigFile(name);
506         String JavaDoc docBase = getConfigFile(name);
507         
508         // Deploy XML descriptors from configBase
509
File JavaDoc xml = new File JavaDoc(configBase, baseName + ".xml");
510         if (xml.exists())
511             deployDescriptor(name, xml, baseName + ".xml");
512         // Deploy WARs, and loop if additional descriptors are found
513
File JavaDoc war = new File JavaDoc(appBase, docBase + ".war");
514         if (war.exists())
515             deployWAR(name, war, docBase + ".war");
516         // Deploy expanded folders
517
File JavaDoc dir = new File JavaDoc(appBase, docBase);
518         if (dir.exists())
519             deployDirectory(name, dir, docBase);
520         
521     }
522
523
524     /**
525      * Deploy XML context descriptors.
526      */

527     protected void deployDescriptors(File JavaDoc configBase, String JavaDoc[] files) {
528
529         if (files == null)
530             return;
531         
532         for (int i = 0; i < files.length; i++) {
533
534             if (files[i].equalsIgnoreCase("META-INF"))
535                 continue;
536             if (files[i].equalsIgnoreCase("WEB-INF"))
537                 continue;
538             File JavaDoc contextXml = new File JavaDoc(configBase, files[i]);
539             if (files[i].toLowerCase().endsWith(".xml")) {
540
541                 // Calculate the context path and make sure it is unique
542
String JavaDoc nameTmp = files[i].substring(0, files[i].length() - 4);
543                 String JavaDoc contextPath = "/" + nameTmp.replace('#', '/');
544                 if (nameTmp.equals("ROOT")) {
545                     contextPath = "";
546                 }
547
548                 if (isServiced(contextPath))
549                     continue;
550                 
551                 String JavaDoc file = files[i];
552
553                 deployDescriptor(contextPath, contextXml, file);
554                 
555             }
556
557         }
558
559     }
560
561
562     /**
563      * @param contextPath
564      * @param contextXml
565      * @param file
566      */

567     protected void deployDescriptor(String JavaDoc contextPath, File JavaDoc contextXml, String JavaDoc file) {
568         if (deploymentExists(contextPath)) {
569             return;
570         }
571         
572         DeployedApplication deployedApp = new DeployedApplication(contextPath);
573
574         // Assume this is a configuration descriptor and deploy it
575
if(log.isDebugEnabled()) {
576             log.debug(sm.getString("hostConfig.deployDescriptor", file));
577         }
578
579         Context context = null;
580         try {
581             synchronized (digester) {
582                 try {
583                     context = (Context) digester.parse(contextXml);
584                     if (context == null) {
585                         log.error(sm.getString("hostConfig.deployDescriptor.error",
586                                 file));
587                         return;
588                     }
589                 } finally {
590                     digester.reset();
591                 }
592             }
593             if (context instanceof Lifecycle) {
594                 Class JavaDoc clazz = Class.forName(host.getConfigClass());
595                 LifecycleListener listener =
596                     (LifecycleListener) clazz.newInstance();
597                 ((Lifecycle) context).addLifecycleListener(listener);
598             }
599             context.setConfigFile(contextXml.getAbsolutePath());
600             context.setPath(contextPath);
601             // Add the associated docBase to the redeployed list if it's a WAR
602
boolean isWar = false;
603             boolean isExternal = false;
604             if (context.getDocBase() != null) {
605                 File JavaDoc docBase = new File JavaDoc(context.getDocBase());
606                 if (!docBase.isAbsolute()) {
607                     docBase = new File JavaDoc(appBase(), context.getDocBase());
608                 }
609                 // If external docBase, register .xml as redeploy first
610
if (!docBase.getCanonicalPath().startsWith(appBase().getAbsolutePath())) {
611                     isExternal = true;
612                     deployedApp.redeployResources.put
613                         (contextXml.getAbsolutePath(), new Long JavaDoc(contextXml.lastModified()));
614                     deployedApp.redeployResources.put(docBase.getAbsolutePath(),
615                         new Long JavaDoc(docBase.lastModified()));
616                     if (docBase.getAbsolutePath().toLowerCase().endsWith(".war")) {
617                         isWar = true;
618                     }
619                 } else {
620                     log.warn(sm.getString("hostConfig.deployDescriptor.localDocBaseSpecified",
621                              docBase));
622                     // Ignore specified docBase
623
context.setDocBase(null);
624                 }
625             }
626             host.addChild(context);
627             // Get paths for WAR and expanded WAR in appBase
628
String JavaDoc name = null;
629             String JavaDoc path = context.getPath();
630             if (path.equals("")) {
631                 name = "ROOT";
632             } else {
633                 if (path.startsWith("/")) {
634                     name = path.substring(1);
635                 } else {
636                     name = path;
637                 }
638             }
639             File JavaDoc expandedDocBase = new File JavaDoc(name);
640             File JavaDoc warDocBase = new File JavaDoc(name + ".war");
641             if (!expandedDocBase.isAbsolute()) {
642                 expandedDocBase = new File JavaDoc(appBase(), name);
643                 warDocBase = new File JavaDoc(appBase(), name + ".war");
644             }
645             // Add the eventual unpacked WAR and all the resources which will be
646
// watched inside it
647
if (isWar && unpackWARs) {
648                 deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(),
649                         new Long JavaDoc(expandedDocBase.lastModified()));
650                 deployedApp.redeployResources.put
651                     (contextXml.getAbsolutePath(), new Long JavaDoc(contextXml.lastModified()));
652                 addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), context);
653             } else {
654                 // Find an existing matching war and expanded folder
655
if (warDocBase.exists()) {
656                     deployedApp.redeployResources.put(warDocBase.getAbsolutePath(),
657                             new Long JavaDoc(warDocBase.lastModified()));
658                 }
659                 if (expandedDocBase.exists()) {
660                     deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(),
661                             new Long JavaDoc(expandedDocBase.lastModified()));
662                     addWatchedResources(deployedApp,
663                             expandedDocBase.getAbsolutePath(), context);
664                 } else {
665                     addWatchedResources(deployedApp, null, context);
666                 }
667                 // Add the context XML to the list of files which should trigger a redeployment
668
if (!isExternal) {
669                     deployedApp.redeployResources.put
670                         (contextXml.getAbsolutePath(), new Long JavaDoc(contextXml.lastModified()));
671                 }
672             }
673         } catch (Throwable JavaDoc t) {
674             log.error(sm.getString("hostConfig.deployDescriptor.error",
675                                    file), t);
676         }
677
678         if (context != null && host.findChild(context.getName()) != null) {
679             deployed.put(contextPath, deployedApp);
680         }
681     }
682
683
684     /**
685      * Deploy WAR files.
686      */

687     protected void deployWARs(File JavaDoc appBase, String JavaDoc[] files) {
688         
689         if (files == null)
690             return;
691         
692         for (int i = 0; i < files.length; i++) {
693             
694             if (files[i].equalsIgnoreCase("META-INF"))
695                 continue;
696             if (files[i].equalsIgnoreCase("WEB-INF"))
697                 continue;
698             File JavaDoc dir = new File JavaDoc(appBase, files[i]);
699             if (files[i].toLowerCase().endsWith(".war")) {
700                 
701                 // Calculate the context path and make sure it is unique
702
String JavaDoc contextPath = "/" + files[i];
703                 int period = contextPath.lastIndexOf(".");
704                 if (period >= 0)
705                     contextPath = contextPath.substring(0, period);
706                 if (contextPath.equals("/ROOT"))
707                     contextPath = "";
708                 
709                 if (isServiced(contextPath))
710                     continue;
711                 
712                 String JavaDoc file = files[i];
713                 
714                 deployWAR(contextPath, dir, file);
715                 
716             }
717             
718         }
719         
720     }
721
722
723     /**
724      * @param contextPath
725      * @param dir
726      * @param file
727      */

728     protected void deployWAR(String JavaDoc contextPath, File JavaDoc dir, String JavaDoc file) {
729         
730         if (deploymentExists(contextPath))
731             return;
732         
733         // Checking for a nested /META-INF/context.xml
734
JarFile JavaDoc jar = null;
735         JarEntry JavaDoc entry = null;
736         InputStream JavaDoc istream = null;
737         BufferedOutputStream JavaDoc ostream = null;
738         File JavaDoc xml = new File JavaDoc
739             (configBase, file.substring(0, file.lastIndexOf(".")) + ".xml");
740         if (deployXML && !xml.exists()) {
741             try {
742                 jar = new JarFile JavaDoc(dir);
743                 entry = jar.getJarEntry(Constants.ApplicationContextXml);
744                 if (entry != null) {
745                     istream = jar.getInputStream(entry);
746                     
747                     configBase.mkdirs();
748                     
749                     ostream =
750                         new BufferedOutputStream JavaDoc
751                         (new FileOutputStream JavaDoc(xml), 1024);
752                     byte buffer[] = new byte[1024];
753                     while (true) {
754                         int n = istream.read(buffer);
755                         if (n < 0) {
756                             break;
757                         }
758                         ostream.write(buffer, 0, n);
759                     }
760                     ostream.flush();
761                     ostream.close();
762                     ostream = null;
763                     istream.close();
764                     istream = null;
765                     entry = null;
766                     jar.close();
767                     jar = null;
768                 }
769             } catch (Exception JavaDoc e) {
770                 // Ignore and continue
771
if (ostream != null) {
772                     try {
773                         ostream.close();
774                     } catch (Throwable JavaDoc t) {
775                         ;
776                     }
777                     ostream = null;
778                 }
779                 if (istream != null) {
780                     try {
781                         istream.close();
782                     } catch (Throwable JavaDoc t) {
783                         ;
784                     }
785                     istream = null;
786                 }
787             } finally {
788                 entry = null;
789                 if (jar != null) {
790                     try {
791                         jar.close();
792                     } catch (Throwable JavaDoc t) {
793                         ;
794                     }
795                     jar = null;
796                 }
797             }
798         }
799         
800         DeployedApplication deployedApp = new DeployedApplication(contextPath);
801         
802         // Deploy the application in this WAR file
803
if(log.isInfoEnabled())
804             log.info(sm.getString("hostConfig.deployJar", file));
805
806         // Populate redeploy resources with the WAR file
807
deployedApp.redeployResources.put
808             (dir.getAbsolutePath(), new Long JavaDoc(dir.lastModified()));
809
810         try {
811             Context context = (Context) Class.forName(contextClass).newInstance();
812             if (context instanceof Lifecycle) {
813                 Class JavaDoc clazz = Class.forName(host.getConfigClass());
814                 LifecycleListener listener =
815                     (LifecycleListener) clazz.newInstance();
816                 ((Lifecycle) context).addLifecycleListener(listener);
817             }
818             context.setPath(contextPath);
819             context.setDocBase(file);
820             if (xml.exists()) {
821                 context.setConfigFile(xml.getAbsolutePath());
822                 deployedApp.redeployResources.put
823                     (xml.getAbsolutePath(), new Long JavaDoc(xml.lastModified()));
824             }
825             host.addChild(context);
826             // If we're unpacking WARs, the docBase will be mutated after
827
// starting the context
828
if (unpackWARs && (context.getDocBase() != null)) {
829                 String JavaDoc name = null;
830                 String JavaDoc path = context.getPath();
831                 if (path.equals("")) {
832                     name = "ROOT";
833                 } else {
834                     if (path.startsWith("/")) {
835                         name = path.substring(1);
836                     } else {
837                         name = path;
838                     }
839                 }
840                 File JavaDoc docBase = new File JavaDoc(name);
841                 if (!docBase.isAbsolute()) {
842                     docBase = new File JavaDoc(appBase(), name);
843                 }
844                 deployedApp.redeployResources.put(docBase.getAbsolutePath(),
845                         new Long JavaDoc(docBase.lastModified()));
846                 addWatchedResources(deployedApp, docBase.getAbsolutePath(), context);
847             } else {
848                 addWatchedResources(deployedApp, null, context);
849             }
850         } catch (Throwable JavaDoc t) {
851             log.error(sm.getString("hostConfig.deployJar.error", file), t);
852         }
853         
854         deployed.put(contextPath, deployedApp);
855     }
856
857
858     /**
859      * Deploy directories.
860      */

861     protected void deployDirectories(File JavaDoc appBase, String JavaDoc[] files) {
862
863         if (files == null)
864             return;
865         
866         for (int i = 0; i < files.length; i++) {
867
868             if (files[i].equalsIgnoreCase("META-INF"))
869                 continue;
870             if (files[i].equalsIgnoreCase("WEB-INF"))
871                 continue;
872             File JavaDoc dir = new File JavaDoc(appBase, files[i]);
873             if (dir.isDirectory()) {
874
875                 // Calculate the context path and make sure it is unique
876
String JavaDoc contextPath = "/" + files[i];
877                 if (files[i].equals("ROOT"))
878                     contextPath = "";
879
880                 if (isServiced(contextPath))
881                     continue;
882
883                 deployDirectory(contextPath, dir, files[i]);
884             
885             }
886
887         }
888
889     }
890
891     
892     /**
893      * @param contextPath
894      * @param dir
895      * @param file
896      */

897     protected void deployDirectory(String JavaDoc contextPath, File JavaDoc dir, String JavaDoc file) {
898         DeployedApplication deployedApp = new DeployedApplication(contextPath);
899         
900         if (deploymentExists(contextPath))
901             return;
902
903         // Deploy the application in this directory
904
if( log.isDebugEnabled() )
905             log.debug(sm.getString("hostConfig.deployDir", file));
906         try {
907             Context context = (Context) Class.forName(contextClass).newInstance();
908             if (context instanceof Lifecycle) {
909                 Class JavaDoc clazz = Class.forName(host.getConfigClass());
910                 LifecycleListener listener =
911                     (LifecycleListener) clazz.newInstance();
912                 ((Lifecycle) context).addLifecycleListener(listener);
913             }
914             context.setPath(contextPath);
915             context.setDocBase(file);
916             File JavaDoc configFile = new File JavaDoc(dir, Constants.ApplicationContextXml);
917             if (deployXML) {
918                 context.setConfigFile(configFile.getAbsolutePath());
919             }
920             host.addChild(context);
921             deployedApp.redeployResources.put(dir.getAbsolutePath(),
922                     new Long JavaDoc(dir.lastModified()));
923             if (deployXML) {
924                 deployedApp.redeployResources.put(configFile.getAbsolutePath(),
925                         new Long JavaDoc(configFile.lastModified()));
926             }
927             addWatchedResources(deployedApp, dir.getAbsolutePath(), context);
928         } catch (Throwable JavaDoc t) {
929             log.error(sm.getString("hostConfig.deployDir.error", file), t);
930         }
931
932         deployed.put(contextPath, deployedApp);
933     }
934
935     
936     /**
937      * Check if a webapp is already deployed in this host.
938      *
939      * @param contextPath of the context which will be checked
940      */

941     protected boolean deploymentExists(String JavaDoc contextPath) {
942         return (deployed.containsKey(contextPath) || (host.findChild(contextPath) != null));
943     }
944     
945
946     /**
947      * Add watched resources to the specified Context.
948      * @param app HostConfig deployed app
949      * @param docBase web app docBase
950      * @param context web application context
951      */

952     protected void addWatchedResources(DeployedApplication app, String JavaDoc docBase, Context context) {
953         // FIXME: Feature idea. Add support for patterns (ex: WEB-INF/*, WEB-INF/*.xml), where
954
// we would only check if at least one resource is newer than app.timestamp
955
File JavaDoc docBaseFile = null;
956         if (docBase != null) {
957             docBaseFile = new File JavaDoc(docBase);
958             if (!docBaseFile.isAbsolute()) {
959                 docBaseFile = new File JavaDoc(appBase(), docBase);
960             }
961         }
962         String JavaDoc[] watchedResources = context.findWatchedResources();
963         for (int i = 0; i < watchedResources.length; i++) {
964             File JavaDoc resource = new File JavaDoc(watchedResources[i]);
965             if (!resource.isAbsolute()) {
966                 if (docBase != null) {
967                     resource = new File JavaDoc(docBaseFile, watchedResources[i]);
968                 } else {
969                     continue;
970                 }
971             }
972             app.reloadResources.put(resource.getAbsolutePath(),
973                     new Long JavaDoc(resource.lastModified()));
974         }
975     }
976     
977
978     /**
979      * Check resources for redeployment and reloading.
980      */

981     protected synchronized void checkResources(DeployedApplication app) {
982         String JavaDoc[] resources = (String JavaDoc[]) app.redeployResources.keySet().toArray(new String JavaDoc[0]);
983         for (int i = 0; i < resources.length; i++) {
984             File JavaDoc resource = new File JavaDoc(resources[i]);
985             if (log.isDebugEnabled())
986                 log.debug("Checking context[" + app.name + "] redeploy resource " + resource);
987             if (resource.exists()) {
988                 long lastModified = ((Long JavaDoc) app.redeployResources.get(resources[i])).longValue();
989                 if ((!resource.isDirectory()) && resource.lastModified() > lastModified) {
990                     // Undeploy application
991
if (log.isInfoEnabled())
992                         log.info(sm.getString("hostConfig.undeploy", app.name));
993                     ContainerBase context = (ContainerBase) host.findChild(app.name);
994                     try {
995                         host.removeChild(context);
996                     } catch (Throwable JavaDoc t) {
997                         log.warn(sm.getString
998                                  ("hostConfig.context.remove", app.name), t);
999                     }
1000                    try {
1001                        context.destroy();
1002                    } catch (Throwable JavaDoc t) {
1003                        log.warn(sm.getString
1004                                 ("hostConfig.context.destroy", app.name), t);
1005                    }
1006                    // Delete other redeploy resources
1007
for (int j = i + 1; j < resources.length; j++) {
1008                        try {
1009                            File JavaDoc current = new File JavaDoc(resources[j]);
1010                            current = current.getCanonicalFile();
1011                            if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath()))
1012                                    || (current.getAbsolutePath().startsWith(configBase().getAbsolutePath()))) {
1013                                if (log.isDebugEnabled())
1014                                    log.debug("Delete " + current);
1015                                ExpandWar.delete(current);
1016                            }
1017                        } catch (IOException JavaDoc e) {
1018                            log.warn(sm.getString
1019                                    ("hostConfig.canonicalizing", app.name), e);
1020                        }
1021                    }
1022                    deployed.remove(app.name);
1023                    return;
1024                }
1025            } else {
1026                long lastModified = ((Long JavaDoc) app.redeployResources.get(resources[i])).longValue();
1027                if (lastModified == 0L) {
1028                    continue;
1029                }
1030                // Undeploy application
1031
if (log.isInfoEnabled())
1032                    log.info(sm.getString("hostConfig.undeploy", app.name));
1033                ContainerBase context = (ContainerBase) host.findChild(app.name);
1034                try {
1035                    host.removeChild(context);
1036                } catch (Throwable JavaDoc t) {
1037                    log.warn(sm.getString
1038                             ("hostConfig.context.remove", app.name), t);
1039                }
1040                try {
1041                    context.destroy();
1042                } catch (Throwable JavaDoc t) {
1043                    log.warn(sm.getString
1044                             ("hostConfig.context.destroy", app.name), t);
1045                }
1046                // Delete all redeploy resources
1047
for (int j = i + 1; j < resources.length; j++) {
1048                    try {
1049                        File JavaDoc current = new File JavaDoc(resources[j]);
1050                        current = current.getCanonicalFile();
1051                        if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath()))
1052                            || (current.getAbsolutePath().startsWith(configBase().getAbsolutePath()))) {
1053                            if (log.isDebugEnabled())
1054                                log.debug("Delete " + current);
1055                            ExpandWar.delete(current);
1056                        }
1057                    } catch (IOException JavaDoc e) {
1058                        log.warn(sm.getString
1059                                ("hostConfig.canonicalizing", app.name), e);
1060                    }
1061                }
1062                // Delete reload resources as well (to remove any remaining .xml descriptor)
1063
String JavaDoc[] resources2 = (String JavaDoc[]) app.reloadResources.keySet().toArray(new String JavaDoc[0]);
1064                for (int j = 0; j < resources2.length; j++) {
1065                    try {
1066                        File JavaDoc current = new File JavaDoc(resources2[j]);
1067                        current = current.getCanonicalFile();
1068                        if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath()))
1069                            || ((current.getAbsolutePath().startsWith(configBase().getAbsolutePath())
1070                                 && (current.getAbsolutePath().endsWith(".xml"))))) {
1071                            if (log.isDebugEnabled())
1072                                log.debug("Delete " + current);
1073                            ExpandWar.delete(current);
1074                        }
1075                    } catch (IOException JavaDoc e) {
1076                        log.warn(sm.getString
1077                                ("hostConfig.canonicalizing", app.name), e);
1078                    }
1079                }
1080                deployed.remove(app.name);
1081                return;
1082            }
1083        }
1084        resources = (String JavaDoc[]) app.reloadResources.keySet().toArray(new String JavaDoc[0]);
1085        for (int i = 0; i < resources.length; i++) {
1086            File JavaDoc resource = new File JavaDoc(resources[i]);
1087            if (log.isDebugEnabled())
1088                log.debug("Checking context[" + app.name + "] reload resource " + resource);
1089            long lastModified = ((Long JavaDoc) app.reloadResources.get(resources[i])).longValue();
1090            if ((!resource.exists() && lastModified != 0L)
1091                || (resource.lastModified() != lastModified)) {
1092                // Reload application
1093
if(log.isInfoEnabled())
1094                    log.info(sm.getString("hostConfig.reload", app.name));
1095                Container context = host.findChild(app.name);
1096                try {
1097                    ((Lifecycle) context).stop();
1098                } catch (Exception JavaDoc e) {
1099                    log.warn(sm.getString
1100                             ("hostConfig.context.restart", app.name), e);
1101                }
1102                // If the context was not started (for example an error
1103
// in web.xml) we'll still get to try to start
1104
try {
1105                    ((Lifecycle) context).start();
1106                } catch (Exception JavaDoc e) {
1107                    log.warn(sm.getString
1108                             ("hostConfig.context.restart", app.name), e);
1109                }
1110                // Update times
1111
app.reloadResources.put(resources[i], new Long JavaDoc(resource.lastModified()));
1112                app.timestamp = System.currentTimeMillis();
1113                return;
1114            }
1115        }
1116    }
1117    
1118    
1119    /**
1120     * Process a "start" event for this Host.
1121     */

1122    public void start() {
1123
1124        if (log.isDebugEnabled())
1125            log.debug(sm.getString("hostConfig.start"));
1126
1127        try {
1128            ObjectName JavaDoc hostON = new ObjectName JavaDoc(host.getObjectName());
1129            oname = new ObjectName JavaDoc
1130                (hostON.getDomain() + ":type=Deployer,host=" + host.getName());
1131            Registry.getRegistry(null, null).registerComponent
1132                (this, oname, this.getClass().getName());
1133        } catch (Exception JavaDoc e) {
1134            log.error(sm.getString("hostConfig.jmx.register", oname), e);
1135        }
1136
1137        if (host.getDeployOnStartup())
1138            deployApps();
1139        
1140    }
1141
1142
1143    /**
1144     * Process a "stop" event for this Host.
1145     */

1146    public void stop() {
1147
1148        if (log.isDebugEnabled())
1149            log.debug(sm.getString("hostConfig.stop"));
1150
1151        undeployApps();
1152
1153        if (oname != null) {
1154            try {
1155                Registry.getRegistry(null, null).unregisterComponent(oname);
1156            } catch (Exception JavaDoc e) {
1157                log.error(sm.getString("hostConfig.jmx.unregister", oname), e);
1158            }
1159        }
1160        oname = null;
1161        appBase = null;
1162        configBase = null;
1163
1164    }
1165
1166
1167    /**
1168     * Undeploy all deployed applications.
1169     */

1170    protected void undeployApps() {
1171
1172        if (log.isDebugEnabled())
1173            log.debug(sm.getString("hostConfig.undeploying"));
1174
1175        // Soft undeploy all contexts we have deployed
1176
DeployedApplication[] apps =
1177            (DeployedApplication[]) deployed.values().toArray(new DeployedApplication[0]);
1178        for (int i = 0; i < apps.length; i++) {
1179            try {
1180                host.removeChild(host.findChild(apps[i].name));
1181            } catch (Throwable JavaDoc t) {
1182                log.warn(sm.getString
1183                        ("hostConfig.context.remove", apps[i].name), t);
1184            }
1185        }
1186        
1187        deployed.clear();
1188
1189    }
1190
1191
1192    /**
1193     * Check status of all webapps.
1194     */

1195    protected void check() {
1196
1197        if (host.getAutoDeploy()) {
1198            // Check for resources modification to trigger redeployment
1199
DeployedApplication[] apps =
1200                (DeployedApplication[]) deployed.values().toArray(new DeployedApplication[0]);
1201            for (int i = 0; i < apps.length; i++) {
1202                if (!isServiced(apps[i].name))
1203                    checkResources(apps[i]);
1204            }
1205            // Hotdeploy applications
1206
deployApps();
1207        }
1208
1209    }
1210
1211    
1212    /**
1213     * Check status of a specific webapp, for use with stuff like management webapps.
1214     */

1215    public void check(String JavaDoc name) {
1216        DeployedApplication app = (DeployedApplication) deployed.get(name);
1217        if (app != null) {
1218            checkResources(app);
1219        } else {
1220            deployApps(name);
1221        }
1222    }
1223
1224    /**
1225     * Add a new Context to be managed by us.
1226     * Entry point for the admin webapp, and other JMX Context controlers.
1227     */

1228    public void manageApp(Context context) {
1229
1230        String JavaDoc contextPath = context.getPath();
1231        
1232        if (deployed.containsKey(contextPath))
1233            return;
1234
1235        DeployedApplication deployedApp = new DeployedApplication(contextPath);
1236        
1237        // Add the associated docBase to the redeployed list if it's a WAR
1238
boolean isWar = false;
1239        if (context.getDocBase() != null) {
1240            File JavaDoc docBase = new File JavaDoc(context.getDocBase());
1241            if (!docBase.isAbsolute()) {
1242                docBase = new File JavaDoc(appBase(), context.getDocBase());
1243            }
1244            deployedApp.redeployResources.put(docBase.getAbsolutePath(),
1245                                          new Long JavaDoc(docBase.lastModified()));
1246            if (docBase.getAbsolutePath().toLowerCase().endsWith(".war")) {
1247                isWar = true;
1248            }
1249        }
1250        host.addChild(context);
1251        // Add the eventual unpacked WAR and all the resources which will be
1252
// watched inside it
1253
if (isWar && unpackWARs) {
1254            String JavaDoc name = null;
1255            String JavaDoc path = context.getPath();
1256            if (path.equals("")) {
1257                name = "ROOT";
1258            } else {
1259                if (path.startsWith("/")) {
1260                    name = path.substring(1);
1261                } else {
1262                    name = path;
1263                }
1264            }
1265            File JavaDoc docBase = new File JavaDoc(name);
1266            if (!docBase.isAbsolute()) {
1267                docBase = new File JavaDoc(appBase(), name);
1268            }
1269            deployedApp.redeployResources.put(docBase.getAbsolutePath(),
1270                        new Long JavaDoc(docBase.lastModified()));
1271            addWatchedResources(deployedApp, docBase.getAbsolutePath(), context);
1272        } else {
1273            addWatchedResources(deployedApp, null, context);
1274        }
1275        deployed.put(contextPath, deployedApp);
1276    }
1277
1278    /**
1279     * Remove a webapp from our control.
1280     * Entry point for the admin webapp, and other JMX Context controlers.
1281     */

1282    public void unmanageApp(String JavaDoc contextPath) {
1283        if(isServiced(contextPath)) {
1284            deployed.remove(contextPath);
1285            host.removeChild(host.findChild(contextPath));
1286        }
1287    }
1288
1289    // ----------------------------------------------------- Instance Variables
1290

1291
1292    /**
1293     * This class represents the state of a deployed application, as well as
1294     * the monitored resources.
1295     */

1296    protected class DeployedApplication {
1297        public DeployedApplication(String JavaDoc name) {
1298            this.name = name;
1299        }
1300        
1301        /**
1302         * Application context path. The assertion is that
1303         * (host.getChild(name) != null).
1304         */

1305        public String JavaDoc name;
1306        
1307        /**
1308         * Any modification of the specified (static) resources will cause a
1309         * redeployment of the application. If any of the specified resources is
1310         * removed, the application will be undeployed. Typically, this will
1311         * contain resources like the context.xml file, a compressed WAR path.
1312         * The value is the last modification time.
1313         */

1314        public LinkedHashMap JavaDoc redeployResources = new LinkedHashMap JavaDoc();
1315
1316        /**
1317         * Any modification of the specified (static) resources will cause a
1318         * reload of the application. This will typically contain resources
1319         * such as the web.xml of a webapp, but can be configured to contain
1320         * additional descriptors.
1321         * The value is the last modification time.
1322         */

1323        public HashMap JavaDoc reloadResources = new HashMap JavaDoc();
1324
1325        /**
1326         * Instant where the application was last put in service.
1327         */

1328        public long timestamp = System.currentTimeMillis();
1329    }
1330
1331}
1332
Popular Tags