KickJava   Java API By Example, From Geeks To Geeks.

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


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.File JavaDoc;
23 import java.io.FileInputStream JavaDoc;
24 import java.io.FileNotFoundException JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Properties JavaDoc;
30
31 import javax.servlet.ServletContext JavaDoc;
32
33 import org.apache.catalina.Authenticator;
34 import org.apache.catalina.Container;
35 import org.apache.catalina.Context;
36 import org.apache.catalina.Engine;
37 import org.apache.catalina.Globals;
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.Pipeline;
43 import org.apache.catalina.Valve;
44 import org.apache.catalina.Wrapper;
45 import org.apache.catalina.core.ContainerBase;
46 import org.apache.catalina.core.StandardContext;
47 import org.apache.catalina.core.StandardEngine;
48 import org.apache.catalina.core.StandardHost;
49 import org.apache.catalina.deploy.ErrorPage;
50 import org.apache.catalina.deploy.FilterDef;
51 import org.apache.catalina.deploy.FilterMap;
52 import org.apache.catalina.deploy.LoginConfig;
53 import org.apache.catalina.deploy.SecurityConstraint;
54 import org.apache.catalina.util.StringManager;
55 import org.apache.tomcat.util.digester.Digester;
56 import org.apache.tomcat.util.digester.RuleSet;
57 import org.xml.sax.ErrorHandler JavaDoc;
58 import org.xml.sax.InputSource JavaDoc;
59 import org.xml.sax.SAXParseException JavaDoc;
60
61 /**
62  * Startup event listener for a <b>Context</b> that configures the properties
63  * of that Context, and the associated defined servlets.
64  *
65  * @author Craig R. McClanahan
66  * @author Jean-Francois Arcand
67  * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
68  */

69
70 public class ContextConfig
71     implements LifecycleListener {
72
73     protected static org.apache.commons.logging.Log log=
74         org.apache.commons.logging.LogFactory.getLog( ContextConfig.class );
75
76     // ----------------------------------------------------- Instance Variables
77

78
79     /**
80      * Custom mappings of login methods to authenticators
81      */

82     protected Map JavaDoc customAuthenticators;
83
84
85     /**
86      * The set of Authenticators that we know how to configure. The key is
87      * the name of the implemented authentication method, and the value is
88      * the fully qualified Java class name of the corresponding Valve.
89      */

90     protected static Properties JavaDoc authenticators = null;
91
92
93     /**
94      * The Context we are associated with.
95      */

96     protected Context JavaDoc context = null;
97
98
99     /**
100      * The default web application's context file location.
101      */

102     protected String JavaDoc defaultContextXml = null;
103     
104     
105     /**
106      * The default web application's deployment descriptor location.
107      */

108     protected String JavaDoc defaultWebXml = null;
109     
110     
111     /**
112      * Track any fatal errors during startup configuration processing.
113      */

114     protected boolean ok = false;
115
116
117     /**
118      * Any parse error which occurred while parsing XML descriptors.
119      */

120     protected SAXParseException JavaDoc parseException = null;
121
122     
123     /**
124      * Original docBase.
125      */

126     protected String JavaDoc originalDocBase = null;
127     
128
129     /**
130      * The string resources for this package.
131      */

132     protected static final StringManager sm =
133         StringManager.getManager(Constants.Package);
134
135
136     /**
137      * The <code>Digester</code> we will use to process web application
138      * context files.
139      */

140     protected static Digester contextDigester = null;
141     
142     
143     /**
144      * The <code>Digester</code> we will use to process web application
145      * deployment descriptor files.
146      */

147     protected static Digester webDigester = null;
148     
149     
150     /**
151      * The <code>Rule</code> used to parse the web.xml
152      */

153     protected static WebRuleSet webRuleSet = new WebRuleSet();
154
155     /**
156      * Attribute value used to turn on/off XML validation
157      */

158      protected static boolean xmlValidation = false;
159
160
161     /**
162      * Attribute value used to turn on/off XML namespace awarenes.
163      */

164     protected static boolean xmlNamespaceAware = false;
165
166     
167     /**
168      * Deployment count.
169      */

170     protected static long deploymentCount = 0L;
171     
172     
173     protected static final LoginConfig DUMMY_LOGIN_CONFIG =
174                                 new LoginConfig("NONE", null, null, null);
175
176
177     // ------------------------------------------------------------- Properties
178

179
180     /**
181      * Return the location of the default deployment descriptor
182      */

183     public String JavaDoc getDefaultWebXml() {
184         if( defaultWebXml == null ) {
185             defaultWebXml=Constants.DefaultWebXml;
186         }
187
188         return (this.defaultWebXml);
189
190     }
191
192
193     /**
194      * Set the location of the default deployment descriptor
195      *
196      * @param path Absolute/relative path to the default web.xml
197      */

198     public void setDefaultWebXml(String JavaDoc path) {
199
200         this.defaultWebXml = path;
201
202     }
203
204
205     /**
206      * Return the location of the default context file
207      */

208     public String JavaDoc getDefaultContextXml() {
209         if( defaultContextXml == null ) {
210             defaultContextXml=Constants.DefaultContextXml;
211         }
212
213         return (this.defaultContextXml);
214
215     }
216
217
218     /**
219      * Set the location of the default context file
220      *
221      * @param path Absolute/relative path to the default context.xml
222      */

223     public void setDefaultContextXml(String JavaDoc path) {
224
225         this.defaultContextXml = path;
226
227     }
228
229
230     /**
231      * Sets custom mappings of login methods to authenticators.
232      *
233      * @param customAuthenticators Custom mappings of login methods to
234      * authenticators
235      */

236     public void setCustomAuthenticators(Map JavaDoc customAuthenticators) {
237         this.customAuthenticators = customAuthenticators;
238     }
239
240
241     // --------------------------------------------------------- Public Methods
242

243
244     /**
245      * Process events for an associated Context.
246      *
247      * @param event The lifecycle event that has occurred
248      */

249     public void lifecycleEvent(LifecycleEvent event) {
250
251         // Identify the context we are associated with
252
try {
253             context = (Context JavaDoc) event.getLifecycle();
254         } catch (ClassCastException JavaDoc e) {
255             log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);
256             return;
257         }
258
259         // Process the event that has occurred
260
if (event.getType().equals(Lifecycle.START_EVENT)) {
261             start();
262         } else if (event.getType().equals(StandardContext.BEFORE_START_EVENT)) {
263             beforeStart();
264         } else if (event.getType().equals(StandardContext.AFTER_START_EVENT)) {
265             // Restore docBase for management tools
266
if (originalDocBase != null) {
267                 String JavaDoc docBase = context.getDocBase();
268                 context.setDocBase(originalDocBase);
269                 originalDocBase = docBase;
270             }
271         } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
272             if (originalDocBase != null) {
273                 String JavaDoc docBase = context.getDocBase();
274                 context.setDocBase(originalDocBase);
275                 originalDocBase = docBase;
276             }
277             stop();
278         } else if (event.getType().equals(Lifecycle.INIT_EVENT)) {
279             init();
280         } else if (event.getType().equals(Lifecycle.DESTROY_EVENT)) {
281             destroy();
282         }
283
284     }
285
286
287     // -------------------------------------------------------- protected Methods
288

289
290     /**
291      * Process the application classes annotations, if it exists.
292      */

293     protected void applicationAnnotationsConfig() {
294         
295         long t1=System.currentTimeMillis();
296         
297         WebAnnotationSet.loadApplicationAnnotations(context);
298         
299         long t2=System.currentTimeMillis();
300         if (context instanceof StandardContext) {
301             ((StandardContext) context).setStartupTime(t2-t1+
302                     ((StandardContext) context).getStartupTime());
303         }
304     }
305
306
307     /**
308      * Process the application configuration file, if it exists.
309      */

310     protected void applicationWebConfig() {
311
312         String JavaDoc altDDName = null;
313
314         // Open the application web.xml file, if it exists
315
InputStream JavaDoc stream = null;
316         ServletContext JavaDoc servletContext = context.getServletContext();
317         if (servletContext != null) {
318             altDDName = (String JavaDoc)servletContext.getAttribute(
319                                                         Globals.ALT_DD_ATTR);
320             if (altDDName != null) {
321                 try {
322                     stream = new FileInputStream JavaDoc(altDDName);
323                 } catch (FileNotFoundException JavaDoc e) {
324                     log.error(sm.getString("contextConfig.altDDNotFound",
325                                            altDDName));
326                 }
327             }
328             else {
329                 stream = servletContext.getResourceAsStream
330                     (Constants.ApplicationWebXml);
331             }
332         }
333         if (stream == null) {
334             if (log.isDebugEnabled()) {
335                 log.debug(sm.getString("contextConfig.applicationMissing") + " " + context);
336             }
337             return;
338         }
339         
340         long t1=System.currentTimeMillis();
341
342         if (webDigester == null){
343             webDigester = createWebDigester();
344         }
345         
346         URL JavaDoc url=null;
347         // Process the application web.xml file
348
synchronized (webDigester) {
349             try {
350                 if (altDDName != null) {
351                     url = new File JavaDoc(altDDName).toURL();
352                 } else {
353                     url = servletContext.getResource(
354                                                 Constants.ApplicationWebXml);
355                 }
356                 if( url!=null ) {
357                     InputSource JavaDoc is = new InputSource JavaDoc(url.toExternalForm());
358                     is.setByteStream(stream);
359                     if (context instanceof StandardContext) {
360                         ((StandardContext) context).setReplaceWelcomeFiles(true);
361                     }
362                     webDigester.push(context);
363                     webDigester.setErrorHandler(new ContextErrorHandler());
364
365                     if(log.isDebugEnabled()) {
366                         log.debug("Parsing application web.xml file at " + url.toExternalForm());
367                     }
368
369                     webDigester.parse(is);
370
371                     if (parseException != null) {
372                         ok = false;
373                     }
374                 } else {
375                     log.info("No web.xml, using defaults " + context );
376                 }
377             } catch (SAXParseException JavaDoc e) {
378                 log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e);
379                 log.error(sm.getString("contextConfig.applicationPosition",
380                                  "" + e.getLineNumber(),
381                                  "" + e.getColumnNumber()));
382                 ok = false;
383             } catch (Exception JavaDoc e) {
384                 log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e);
385                 ok = false;
386             } finally {
387                 webDigester.reset();
388                 parseException = null;
389                 try {
390                     if (stream != null) {
391                         stream.close();
392                     }
393                 } catch (IOException JavaDoc e) {
394                     log.error(sm.getString("contextConfig.applicationClose"), e);
395                 }
396             }
397         }
398         webRuleSet.recycle();
399
400         long t2=System.currentTimeMillis();
401         if (context instanceof StandardContext) {
402             ((StandardContext) context).setStartupTime(t2-t1);
403         }
404     }
405
406
407     /**
408      * Set up an Authenticator automatically if required, and one has not
409      * already been configured.
410      */

411     protected synchronized void authenticatorConfig() {
412
413         // Does this Context require an Authenticator?
414
SecurityConstraint constraints[] = context.findConstraints();
415         if ((constraints == null) || (constraints.length == 0))
416             return;
417         LoginConfig loginConfig = context.getLoginConfig();
418         if (loginConfig == null) {
419             loginConfig = DUMMY_LOGIN_CONFIG;
420             context.setLoginConfig(loginConfig);
421         }
422
423         // Has an authenticator been configured already?
424
if (context instanceof Authenticator)
425             return;
426         if (context instanceof ContainerBase) {
427             Pipeline pipeline = ((ContainerBase) context).getPipeline();
428             if (pipeline != null) {
429                 Valve basic = pipeline.getBasic();
430                 if ((basic != null) && (basic instanceof Authenticator))
431                     return;
432                 Valve valves[] = pipeline.getValves();
433                 for (int i = 0; i < valves.length; i++) {
434                     if (valves[i] instanceof Authenticator)
435                         return;
436                 }
437             }
438         } else {
439             return; // Cannot install a Valve even if it would be needed
440
}
441
442         // Has a Realm been configured for us to authenticate against?
443
if (context.getRealm() == null) {
444             log.error(sm.getString("contextConfig.missingRealm"));
445             ok = false;
446             return;
447         }
448
449         /*
450          * First check to see if there is a custom mapping for the login
451          * method. If so, use it. Otherwise, check if there is a mapping in
452          * org/apache/catalina/startup/Authenticators.properties.
453          */

454         Valve authenticator = null;
455         if (customAuthenticators != null) {
456             authenticator = (Valve)
457                 customAuthenticators.get(loginConfig.getAuthMethod());
458         }
459         if (authenticator == null) {
460             // Load our mapping properties if necessary
461
if (authenticators == null) {
462                 try {
463                     InputStream JavaDoc is=this.getClass().getClassLoader().getResourceAsStream("org/apache/catalina/startup/Authenticators.properties");
464                     if( is!=null ) {
465                         authenticators = new Properties JavaDoc();
466                         authenticators.load(is);
467                     } else {
468                         log.error(sm.getString(
469                                 "contextConfig.authenticatorResources"));
470                         ok=false;
471                         return;
472                     }
473                 } catch (IOException JavaDoc e) {
474                     log.error(sm.getString(
475                                 "contextConfig.authenticatorResources"), e);
476                     ok = false;
477                     return;
478                 }
479             }
480
481             // Identify the class name of the Valve we should configure
482
String JavaDoc authenticatorName = null;
483             authenticatorName =
484                     authenticators.getProperty(loginConfig.getAuthMethod());
485             if (authenticatorName == null) {
486                 log.error(sm.getString("contextConfig.authenticatorMissing",
487                                  loginConfig.getAuthMethod()));
488                 ok = false;
489                 return;
490             }
491
492             // Instantiate and install an Authenticator of the requested class
493
try {
494                 Class JavaDoc authenticatorClass = Class.forName(authenticatorName);
495                 authenticator = (Valve) authenticatorClass.newInstance();
496             } catch (Throwable JavaDoc t) {
497                 log.error(sm.getString(
498                                     "contextConfig.authenticatorInstantiate",
499                                     authenticatorName),
500                           t);
501                 ok = false;
502             }
503         }
504
505         if (authenticator != null && context instanceof ContainerBase) {
506             Pipeline pipeline = ((ContainerBase) context).getPipeline();
507             if (pipeline != null) {
508                 ((ContainerBase) context).addValve(authenticator);
509                 if (log.isDebugEnabled()) {
510                     log.debug(sm.getString(
511                                     "contextConfig.authenticatorConfigured",
512                                     loginConfig.getAuthMethod()));
513                 }
514             }
515         }
516
517     }
518
519
520     /**
521      * Create (if necessary) and return a Digester configured to process the
522      * web application deployment descriptor (web.xml).
523      */

524     protected static Digester createWebDigester() {
525         Digester webDigester =
526             createWebXmlDigester(xmlNamespaceAware, xmlValidation);
527         return webDigester;
528     }
529
530
531     /**
532      * Create (if necessary) and return a Digester configured to process the
533      * web application deployment descriptor (web.xml).
534      */

535     public static Digester createWebXmlDigester(boolean namespaceAware,
536                                                 boolean validation) {
537         
538         Digester webDigester = DigesterFactory.newDigester(xmlValidation,
539                                                             xmlNamespaceAware,
540                                                             webRuleSet);
541         return webDigester;
542     }
543
544     
545     /**
546      * Create (if necessary) and return a Digester configured to process the
547      * context configuration descriptor for an application.
548      */

549     protected Digester createContextDigester() {
550         Digester digester = new Digester();
551         digester.setValidating(false);
552         RuleSet contextRuleSet = new ContextRuleSet("", false);
553         digester.addRuleSet(contextRuleSet);
554         RuleSet namingRuleSet = new NamingRuleSet("Context/");
555         digester.addRuleSet(namingRuleSet);
556         return digester;
557     }
558
559
560     protected String JavaDoc getBaseDir() {
561         Container engineC=context.getParent().getParent();
562         if( engineC instanceof StandardEngine ) {
563             return ((StandardEngine)engineC).getBaseDir();
564         }
565         return System.getProperty("catalina.base");
566     }
567
568     /**
569      * Process the default configuration file, if it exists.
570      * The default config must be read with the container loader - so
571      * container servlets can be loaded
572      */

573     protected void defaultWebConfig() {
574         long t1=System.currentTimeMillis();
575
576         // Open the default web.xml file, if it exists
577
if( defaultWebXml==null && context instanceof StandardContext ) {
578             defaultWebXml=((StandardContext)context).getDefaultWebXml();
579         }
580         // set the default if we don't have any overrides
581
if( defaultWebXml==null ) getDefaultWebXml();
582
583         File JavaDoc file = new File JavaDoc(this.defaultWebXml);
584         if (!file.isAbsolute()) {
585             file = new File JavaDoc(getBaseDir(),
586                             this.defaultWebXml);
587         }
588
589         InputStream JavaDoc stream = null;
590         InputSource JavaDoc source = null;
591
592         try {
593             if ( ! file.exists() ) {
594                 // Use getResource and getResourceAsStream
595
stream = getClass().getClassLoader()
596                     .getResourceAsStream(defaultWebXml);
597                 if( stream != null ) {
598                     source = new InputSource JavaDoc
599                             (getClass().getClassLoader()
600                             .getResource(defaultWebXml).toString());
601                 }
602                 if( stream== null ) {
603                     // maybe embedded
604
stream = getClass().getClassLoader()
605                         .getResourceAsStream("web-embed.xml");
606                     if( stream != null ) {
607                         source = new InputSource JavaDoc
608                         (getClass().getClassLoader()
609                                 .getResource("web-embed.xml").toString());
610                     }
611                 }
612                 
613                 if( stream== null ) {
614                     log.info("No default web.xml");
615                 }
616             } else {
617                 source =
618                     new InputSource JavaDoc("file://" + file.getAbsolutePath());
619                 stream = new FileInputStream JavaDoc(file);
620                 context.addWatchedResource(file.getAbsolutePath());
621             }
622         } catch (Exception JavaDoc e) {
623             log.error(sm.getString("contextConfig.defaultMissing")
624                       + " " + defaultWebXml + " " + file , e);
625         }
626
627         if (webDigester == null){
628             webDigester = createWebDigester();
629         }
630         
631         if (stream != null) {
632             processDefaultWebConfig(webDigester, stream, source);
633             webRuleSet.recycle();
634         }
635
636         long t2=System.currentTimeMillis();
637         if( (t2-t1) > 200 )
638             log.debug("Processed default web.xml " + file + " " + ( t2-t1));
639
640         stream = null;
641         source = null;
642
643         String JavaDoc resourceName = getHostConfigPath(Constants.HostWebXml);
644         file = new File JavaDoc(getConfigBase(), resourceName);
645         
646         try {
647             if ( ! file.exists() ) {
648                 // Use getResource and getResourceAsStream
649
stream = getClass().getClassLoader()
650                     .getResourceAsStream(resourceName);
651                 if( stream != null ) {
652                     source = new InputSource JavaDoc
653                             (getClass().getClassLoader()
654                             .getResource(resourceName).toString());
655                 }
656             } else {
657                 source =
658                     new InputSource JavaDoc("file://" + file.getAbsolutePath());
659                 stream = new FileInputStream JavaDoc(file);
660             }
661         } catch (Exception JavaDoc e) {
662             log.error(sm.getString("contextConfig.defaultMissing")
663                       + " " + resourceName + " " + file , e);
664         }
665
666         if (stream != null) {
667             processDefaultWebConfig(webDigester, stream, source);
668             webRuleSet.recycle();
669         }
670
671     }
672
673
674     /**
675      * Process a default web.xml.
676      */

677     protected void processDefaultWebConfig(Digester digester, InputStream JavaDoc stream,
678             InputSource JavaDoc source) {
679
680         if (log.isDebugEnabled())
681             log.debug("Processing context [" + context.getName()
682                     + "] web configuration resource " + source.getSystemId());
683
684         // Process the default web.xml file
685
synchronized (digester) {
686             try {
687                 source.setByteStream(stream);
688                 
689                 if (context instanceof StandardContext)
690                     ((StandardContext) context).setReplaceWelcomeFiles(true);
691                 digester.setClassLoader(this.getClass().getClassLoader());
692                 digester.setUseContextClassLoader(false);
693                 digester.push(context);
694                 digester.setErrorHandler(new ContextErrorHandler());
695                 digester.parse(source);
696                 if (parseException != null) {
697                     ok = false;
698                 }
699             } catch (SAXParseException JavaDoc e) {
700                 log.error(sm.getString("contextConfig.defaultParse"), e);
701                 log.error(sm.getString("contextConfig.defaultPosition",
702                                  "" + e.getLineNumber(),
703                                  "" + e.getColumnNumber()));
704                 ok = false;
705             } catch (Exception JavaDoc e) {
706                 log.error(sm.getString("contextConfig.defaultParse"), e);
707                 ok = false;
708             } finally {
709                 digester.reset();
710                 parseException = null;
711                 try {
712                     if (stream != null) {
713                         stream.close();
714                     }
715                 } catch (IOException JavaDoc e) {
716                     log.error(sm.getString("contextConfig.defaultClose"), e);
717                 }
718             }
719         }
720     }
721
722
723     /**
724      * Process the default configuration file, if it exists.
725      */

726     protected void contextConfig() {
727         
728         // Open the default web.xml file, if it exists
729
if( defaultContextXml==null && context instanceof StandardContext ) {
730             defaultContextXml = ((StandardContext)context).getDefaultContextXml();
731         }
732         // set the default if we don't have any overrides
733
if( defaultContextXml==null ) getDefaultContextXml();
734
735         if (!context.getOverride()) {
736             processContextConfig(new File JavaDoc(getBaseDir()), defaultContextXml);
737             processContextConfig(getConfigBase(), getHostConfigPath(Constants.HostContextXml));
738         }
739         if (context.getConfigFile() != null)
740             processContextConfig(new File JavaDoc(context.getConfigFile()), null);
741         
742     }
743
744     
745     /**
746      * Process a context.xml.
747      */

748     protected void processContextConfig(File JavaDoc baseDir, String JavaDoc resourceName) {
749         
750         if (log.isDebugEnabled())
751             log.debug("Processing context [" + context.getName()
752                     + "] configuration file " + baseDir + " " + resourceName);
753
754         InputSource JavaDoc source = null;
755         InputStream JavaDoc stream = null;
756
757         File JavaDoc file = baseDir;
758         if (resourceName != null) {
759             file = new File JavaDoc(baseDir, resourceName);
760         }
761         
762         try {
763             if ( !file.exists() ) {
764                 if (resourceName != null) {
765                     // Use getResource and getResourceAsStream
766
stream = getClass().getClassLoader()
767                         .getResourceAsStream(resourceName);
768                     if( stream != null ) {
769                         source = new InputSource JavaDoc
770                             (getClass().getClassLoader()
771                             .getResource(resourceName).toString());
772                     }
773                 }
774             } else {
775                 source =
776                     new InputSource JavaDoc("file://" + file.getAbsolutePath());
777                 stream = new