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;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.net.URL;
28 import java.util.Map;
29 import java.util.Properties;
30
31 import javax.servlet.ServletContext;
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;
58 import org.xml.sax.InputSource;
59 import org.xml.sax.SAXParseException;
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: 556489 $ $Date: 2007-07-16 04:01:01 +0200 (lun., 16 juil. 2007) $
68 */
69
70 public class ContextConfig
71 implements LifecycleListener {
72
73 protected static org.apache.juli.logging.Log log=
74 org.apache.juli.logging.LogFactory.getLog( ContextConfig.class );
75
76 // ----------------------------------------------------- Instance Variables
77
78
79 /**
80 * Custom mappings of login methods to authenticators
81 */
82 protected Map 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 authenticators = null;
91
92
93 /**
94 * The Context we are associated with.
95 */
96 protected Context context = null;
97
98
99 /**
100 * The default web application's context file location.
101 */
102 protected String defaultContextXml = null;
103
104
105 /**
106 * The default web application's deployment descriptor location.
107 */
108 protected String 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 parseException = null;
121
122
123 /**
124 * Original docBase.
125 */
126 protected String 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 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 path) {
199
200 this.defaultWebXml = path;
201
202 }
203
204
205 /**
206 * Return the location of the default context file
207 */
208 public String 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 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 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) event.getLifecycle();
254 } catch (ClassCastException 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 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 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 altDDName = null;
313
314 // Open the application web.xml file, if it exists
315 InputStream stream = null;
316 ServletContext servletContext = context.getServletContext();
317 if (servletContext != null) {
318 altDDName = (String)servletContext.getAttribute(
319 Globals.ALT_DD_ATTR);
320 if (altDDName != null) {
321 try {
322 stream = new FileInputStream(altDDName);
323 } catch (FileNotFoundException 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 url=null;
347 // Process the application web.xml file
348 synchronized (webDigester) {
349 try {
350 if (altDDName != null) {
351 url = new File(altDDName).toURL();
352 } else {
353 url = servletContext.getResource(
354 Constants.ApplicationWebXml);
355 }
356 if( url!=null ) {
357 InputSource is = new InputSource(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 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 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 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 is=this.getClass().getClassLoader().getResourceAsStream("org/apache/catalina/startup/Authenticators.properties");
464 if( is!=null ) {
465 authenticators = new Properties();
466 authenticators.load(is);
467 } else {
468 log.error(sm.getString(
469 "contextConfig.authenticatorResources"));
470 ok=false;
471 return;
472 }
473 } catch (IOException 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 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 authenticatorClass = Class.forName(authenticatorName);
495 authenticator = (Valve) authenticatorClass.newInstance();
496 } catch (Throwable 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 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 file = new File(this.defaultWebXml);
584 if (!file.isAbsolute()) {
585 file = new File(getBaseDir(),
586 this.defaultWebXml);
587 }
588
589 InputStream stream = null;
590 InputSource 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
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
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("file://" + file.getAbsolutePath());
619 stream = new FileInputStream(file);
620 context.addWatchedResource(file.getAbsolutePath());
621 }
622 } catch (Exception 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 resourceName = getHostConfigPath(Constants.HostWebXml);
644 file = new File(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
653 (getClass().getClassLoader()
654 .getResource(resourceName).toString());
655 }
656 } else {
657 source =
658 new InputSource("file://" + file.getAbsolutePath());
659 stream = new FileInputStream(file);
660 }
661 } catch (Exception 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 stream,
678 InputSource 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 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 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 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(getBaseDir()), defaultContextXml);
737 processContextConfig(getConfigBase(), getHostConfigPath(Constants.HostContextXml));
738 }
739 if (context.getConfigFile() != null)
740 processContextConfig(new File(context.getConfigFile()), null);
741
742 }
743
744
745 /**
746 * Process a context.xml.
747 */
748 protected void processContextConfig(File baseDir, String resourceName) {
749
750 if (log.isDebugEnabled())
751 log.debug("Processing context [" + context.getName()
752 + "] configuration file " + baseDir + " " + resourceName);
753
754 InputSource source = null;
755 InputStream stream = null;
756
757 File file = baseDir;
758 if (resourceName != null) {
759 file = new File(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
770 (getClass().getClassLoader()
771 .getResource(resourceName).toString());
772 }
773 }
774 } else {
775 source =
776 new InputSource("file://" + file.getAbsolutePath());
777 stream = new FileInputStream(file);
778 // Add as watched resource so that cascade reload occurs if a default
779 // config file is modified/added/removed
780 context.addWatchedResource(file.getAbsolutePath());
781 }
782 } catch (Exception e) {
783 log.error(sm.getString("contextConfig.contextMissing",
784 resourceName + " " + file) , e);
785 }
786
787 if (source == null)
788 return;
789 if (contextDigester == null){
790 contextDigester = createContextDigester();
791 }
792 synchronized (contextDigester) {
793 try {
794 source.setByteStream(stream);
795 contextDigester.setClassLoader(this.getClass().getClassLoader());
796 contextDigester.setUseContextClassLoader(false);
797 contextDigester.push(context.getParent());
798 contextDigester.push(context);
799 contextDigester.setErrorHandler(new ContextErrorHandler());
800 contextDigester.parse(source);
801 if (parseException != null) {
802 ok = false;
803 }
804 if (log.isDebugEnabled())
805 log.debug("Successfully processed context [" + context.getName()
806 + "] configuration file " + baseDir + " " + resourceName);
807 } catch (SAXParseException e) {
808 log.error(sm.getString("contextConfig.contextParse",
809 context.getName()), e);
810 log.error(sm.getString("contextConfig.defaultPosition",
811 "" + e.getLineNumber(),
812 "" + e.getColumnNumber()));
813 ok = false;
814 } catch (Exception e) {
815 log.error(sm.getString("contextConfig.contextParse",
816 context.getName()), e);
817 ok = false;
818 } finally {
819 contextDigester.reset();
820 parseException = null;
821 try {
822 if (stream != null) {
823 stream.close();
824 }
825 } catch (IOException e) {
826 log.error(sm.getString("contextConfig.contextClose"), e);
827 }
828 }
829 }
830 }
831
832
833 /**
834 * Adjust docBase.
835 */
836 protected void fixDocBase()
837 throws IOException {
838
839 Host host = (Host) context.getParent();
840 String appBase = host.getAppBase();
841
842 boolean unpackWARs = true;
843 if (host instanceof StandardHost) {
844 unpackWARs = ((StandardHost) host).isUnpackWARs()
845 && ((StandardContext) context).getUnpackWAR();
846 }
847
848 File canonicalAppBase = new File(appBase);
849 if (canonicalAppBase.isAbsolute()) {
850 canonicalAppBase = canonicalAppBase.getCanonicalFile();
851 } else {
852 canonicalAppBase =
853 new File(System.getProperty("catalina.base"), appBase)
854 .getCanonicalFile();
855 }
856
857 String docBase = context.getDocBase();
858 if (docBase == null) {
859 // Trying to guess the docBase according to the path
860 String path = context.getPath();
861 if (path == null) {
862 return;
863 }
864 if (path.equals("")) {
865 docBase = "ROOT";
866 } else {
867 if (path.startsWith("/")) {
868 docBase = path.substring(1);
869 } else {
870 docBase = path;
871 }
872 }
873 }
874
875 File file = new File(docBase);
876 if (!file.isAbsolute()) {
877 docBase = (new File(canonicalAppBase, docBase)).getPath();
878 } else {
879 docBase = file.getCanonicalPath();
880 }
881 file = new File(docBase);
882 String origDocBase = docBase;
883
884 String contextPath = context.getPath();
885 if (contextPath.equals("")) {
886 contextPath = "ROOT";
887 }
888 if (docBase.toLowerCase().endsWith(".war") && !file.isDirectory() && unpackWARs) {
889 URL war = new URL("jar:" + (new File(docBase)).toURL() + "!/");
890 docBase = ExpandWar.expand(host, war, contextPath);
891 file = new File(docBase);
892 docBase = file.getCanonicalPath();
893 if (context instanceof StandardContext) {
894 ((StandardContext) context).setOriginalDocBase(origDocBase);
895 }
896 } else {
897 File docDir = new File(docBase);
898 if (!docDir.exists()) {
899 File warFile = new File(docBase + ".war");
900 if (warFile.exists()) {
901 if (unpackWARs) {
902 URL war = new URL("jar:" + warFile.toURL() + "!/");
903 docBase = ExpandWar.expand(host, war, contextPath);
904 file = new File(docBase);
905 docBase = file.getCanonicalPath();
906 } else {
907 docBase = warFile.getCanonicalPath();
908 }
909 }
910 if (context instanceof StandardContext) {
911 ((StandardContext) context).setOriginalDocBase(origDocBase);
912 }
913 }
914 }
915
916 if (docBase.startsWith(canonicalAppBase.getPath())) {
917 docBase = docBase.substring(canonicalAppBase.getPath().length());
918 docBase = docBase.replace(File.separatorChar, '/');
919 if (docBase.startsWith("/")) {
920 docBase = docBase.substring(1);
921 }
922 } else {
923 docBase = docBase.replace(File.separatorChar, '/');
924 }
925
926 context.setDocBase(docBase);
927
928 }
929
930
931 protected void antiLocking()
932 throws IOException {
933
934 if ((context instanceof StandardContext)
935 && ((StandardContext) context).getAntiResourceLocking()) {
936
937 Host host = (Host) context.getParent();
938 String appBase = host.getAppBase();
939 String docBase = context.getDocBase();
940 if (docBase == null)
941 return;
942 if (originalDocBase == null) {
943 originalDocBase = docBase;
944 } else {
945 docBase = originalDocBase;
946 }
947 File docBaseFile = new File(docBase);
948 if (!docBaseFile.isAbsolute()) {
949 File file = new File(appBase);
950 if (!file.isAbsolute()) {
951 file = new File(System.getProperty("catalina.base"), appBase);
952 }
953 docBaseFile = new File(file, docBase);
954 }
955
956 String path = context.getPath();
957 if (path == null) {
958 return;
959 }
960 if (path.equals("")) {
961 docBase = "ROOT";
962 } else {
963 if (path.startsWith("/")) {
964 docBase = path.substring(1);
965 } else {
966 docBase = path;
967 }
968 }
969
970 File file = null;
971 if (docBase.toLowerCase().endsWith(".war")) {
972 file = new File(System.getProperty("java.io.tmpdir"),
973 deploymentCount++ + "-" + docBase + ".war");
974 } else {
975 file = new File(System.getProperty("java.io.tmpdir"),
976 deploymentCount++ + "-" + docBase);
977 }
978
979 if (log.isDebugEnabled())
980 log.debug("Anti locking context[" + context.getPath()
981 + "] setting docBase to " + file);
982
983 // Cleanup just in case an old deployment is lying around
984 ExpandWar.delete(file);
985 if (ExpandWar.copy(docBaseFile, file)) {
986 context.setDocBase(file.getAbsolutePath());
987 }
988
989 }
990
991 }
992
993
994 /**
995 * Process a "init" event for this Context.
996 */
997 protected void init() {
998 // Called from StandardContext.init()
999
1000 if (log.isDebugEnabled())
1001 log.debug(sm.getString("contextConfig.init"));
1002 context.setConfigured(false);
1003 ok = true;
1004
1005 contextConfig();
1006
1007 try {
1008 fixDocBase();
1009 } catch (IOException e) {
1010 log.error(sm.getString("contextConfig.fixDocBase"), e);
1011 }
1012
1013 }
1014
1015
1016 /**
1017 * Process a "before start" event for this Context.
1018 */
1019 protected synchronized void beforeStart() {
1020
1021 try {
1022 antiLocking();
1023 } catch (IOException e) {
1024 log.error(sm.getString("contextConfig.antiLocking"), e);
1025 }
1026
1027 }
1028
1029
1030 /**
1031 * Process a "start" event for this Context.
1032 */
1033 protected synchronized void start() {
1034 // Called from StandardContext.start()
1035
1036 if (log.isDebugEnabled())
1037 log.debug(sm.getString("contextConfig.start"));
1038
1039 // Set properties based on DefaultContext
1040 Container container = context.getParent();
1041 if( !context.getOverride() ) {
1042 if( container instanceof Host ) {
1043 // Reset the value only if the attribute wasn't
1044 // set on the context.
1045 xmlValidation = context.getXmlValidation();
1046 if (!xmlValidation) {
1047 xmlValidation = ((Host)container).getXmlValidation();
1048 }
1049
1050 xmlNamespaceAware = context.getXmlNamespaceAware();
1051 if (!xmlNamespaceAware){
1052 xmlNamespaceAware
1053 = ((Host)container).getXmlNamespaceAware();
1054 }
1055
1056 container = container.getParent();
1057 }
1058 }
1059
1060 // Process the default and application web.xml files
1061 defaultWebConfig();
1062 applicationWebConfig();
1063 if (!context.getIgnoreAnnotations()) {
1064 applicationAnnotationsConfig();
1065 }
1066 if (ok) {
1067 validateSecurityRoles();
1068 }
1069
1070 // Configure an authenticator if we need one
1071 if (ok)
1072 authenticatorConfig();
1073
1074 // Dump the contents of this pipeline if requested
1075 if ((log.isDebugEnabled()) && (context instanceof ContainerBase)) {
1076 log.debug("Pipeline Configuration:");
1077 Pipeline pipeline = ((ContainerBase) context).getPipeline();
1078 Valve valves[] = null;
1079 if (pipeline != null)
1080 valves = pipeline.getValves();
1081 if (valves != null) {
1082 for (int i = 0; i < valves.length; i++) {
1083 log.debug(" " + valves[i].getInfo());
1084 }
1085 }
1086 log.debug("======================");
1087 }
1088
1089 // Make our application available if no problems were encountered
1090 if (ok)
1091 context.setConfigured(true);
1092 else {
1093 log.error(sm.getString("contextConfig.unavailable"));
1094 context.setConfigured(false);
1095 }
1096
1097 }
1098
1099
1100 /**
1101 * Process a "stop" event for this Context.
1102 */
1103 protected synchronized void stop() {
1104
1105 if (log.isDebugEnabled())
1106 log.debug(sm.getString("contextConfig.stop"));
1107
1108 int i;
1109
1110 // Removing children
1111 Container[] children = context.findChildren();
1112 for (i = 0; i < children.length; i++) {
1113 context.removeChild(children[i]);
1114 }
1115
1116 // Removing application parameters
1117 /*
1118 ApplicationParameter[] applicationParameters =
1119 context.findApplicationParameters();
1120 for (i = 0; i < applicationParameters.length; i++) {
1121 context.removeApplicationParameter
1122 (applicationParameters[i].getName());
1123 }
1124 */
1125
1126 // Removing security constraints
1127 SecurityConstraint[] securityConstraints = context.findConstraints();
1128 for (i = 0; i < securityConstraints.length; i++) {
1129 context.removeConstraint(securityConstraints[i]);
1130 }
1131
1132 // Removing Ejbs
1133 /*
1134 ContextEjb[] contextEjbs = context.findEjbs();
1135 for (i = 0; i < contextEjbs.length; i++) {
1136 context.removeEjb(contextEjbs[i].getName());
1137 }
1138 */
1139
1140 // Removing environments
1141 /*
1142 ContextEnvironment[] contextEnvironments = context.findEnvironments();
1143 for (i = 0; i < contextEnvironments.length; i++) {
1144 context.removeEnvironment(contextEnvironments[i].getName());
1145 }
1146 */
1147
1148 // Removing errors pages
1149 ErrorPage[] errorPages = context.findErrorPages();
1150 for (i = 0; i < errorPages.length; i++) {
1151 context.removeErrorPage(errorPages[i]);
1152 }
1153
1154 // Removing filter defs
1155 FilterDef[] filterDefs = context.findFilterDefs();
1156 for (i = 0; i < filterDefs.length; i++) {
1157 context.removeFilterDef(filterDefs[i]);
1158 }
1159
1160 // Removing filter maps
1161 FilterMap[] filterMaps = context.findFilterMaps();
1162 for (i = 0; i < filterMaps.length; i++) {
1163 context.removeFilterMap(filterMaps[i]);
1164 }
1165
1166 // Removing local ejbs
1167 /*
1168 ContextLocalEjb[] contextLocalEjbs = context.findLocalEjbs();
1169 for (i = 0; i < contextLocalEjbs.length; i++) {
1170 context.removeLocalEjb(contextLocalEjbs[i].getName());
1171 }
1172 */
1173
1174 // Removing Mime mappings
1175 String[] mimeMappings = context.findMimeMappings();
1176 for (i = 0; i < mimeMappings.length; i++) {
1177 context.removeMimeMapping(mimeMappings[i]);
1178 }
1179
1180 // Removing parameters
1181 String[] parameters = context.findParameters();
1182 for (i = 0; i < parameters.length; i++) {
1183 context.removeParameter(parameters[i]);
1184 }
1185
1186 // Removing resource env refs
1187 /*
1188 String[] resourceEnvRefs = context.findResourceEnvRefs();
1189 for (i = 0; i < resourceEnvRefs.length; i++) {
1190 context.removeResourceEnvRef(resourceEnvRefs[i]);
1191 }
1192 */
1193
1194 // Removing resource links
1195 /*
1196 ContextResourceLink[] contextResourceLinks =
1197 context.findResourceLinks();
1198 for (i = 0; i < contextResourceLinks.length; i++) {
1199 context.removeResourceLink(contextResourceLinks[i].getName());
1200 }
1201 */
1202
1203 // Removing resources
1204 /*
1205 ContextResource[] contextResources = context.findResources();
1206 for (i = 0; i < contextResources.length; i++) {
1207 context.removeResource(contextResources[i].getName());
1208 }
1209 */
1210
1211 // Removing sercurity role
1212 String[] securityRoles = context.findSecurityRoles();
1213 for (i = 0; i < securityRoles.length; i++) {
1214 context.removeSecurityRole(securityRoles[i]);
1215 }
1216
1217 // Removing servlet mappings
1218 String[] servletMappings = context.findServletMappings();
1219 for (i = 0; i < servletMappings.length; i++) {
1220 context.removeServletMapping(servletMappings[i]);
1221 }
1222
1223 // FIXME : Removing status pages
1224
1225 // Removing taglibs
1226 String[] taglibs = context.findTaglibs();
1227 for (i = 0; i < taglibs.length; i++) {
1228 context.removeTaglib(taglibs[i]);
1229 }
1230
1231 // Removing welcome files
1232 String[] welcomeFiles = context.findWelcomeFiles();
1233 for (i = 0; i < welcomeFiles.length; i++) {
1234 context.removeWelcomeFile(welcomeFiles[i]);
1235 }
1236
1237 // Removing wrapper lifecycles
1238 String[] wrapperLifecycles = context.findWrapperLifecycles();
1239 for (i = 0; i < wrapperLifecycles.length; i++) {
1240 context.removeWrapperLifecycle(wrapperLifecycles[i]);
1241 }
1242
1243 // Removing wrapper listeners
1244 String[] wrapperListeners = context.findWrapperListeners();
1245 for (i = 0; i < wrapperListeners.length; i++) {
1246 context.removeWrapperListener(wrapperListeners[i]);
1247 }
1248
1249 // Remove (partially) folders and files created by antiLocking
1250 Host host = (Host) context.getParent();
1251 String appBase = host.getAppBase();
1252 String docBase = context.getDocBase();
1253 if ((docBase != null) && (originalDocBase != null)) {
1254 File docBaseFile = new File(docBase);
1255 if (!docBaseFile.isAbsolute()) {
1256 docBaseFile = new File(appBase, docBase);
1257 }
1258 ExpandWar.delete(docBaseFile);
1259 }
1260
1261 ok = true;
1262
1263 }
1264
1265
1266 /**
1267 * Process a "destroy" event for this Context.
1268 */
1269 protected synchronized void destroy() {
1270 // Called from StandardContext.destroy()
1271 if (log.isDebugEnabled())
1272 log.debug(sm.getString("contextConfig.destroy"));
1273
1274 // Changed to getWorkPath per Bugzilla 35819.
1275 String workDir = ((StandardContext) context).getWorkPath();
1276 if (workDir != null)
1277 ExpandWar.delete(new File(workDir));
1278 }
1279
1280
1281 /**
1282 * Validate the usage of security role names in the web application
1283 * deployment descriptor. If any problems are found, issue warning
1284 * messages (for backwards compatibility) and add the missing roles.
1285 * (To make these problems fatal instead, simply set the <code>ok</code>
1286 * instance variable to <code>false</code> as well).
1287 */
1288 protected void validateSecurityRoles() {
1289
1290 // Check role names used in <security-constraint> elements
1291 SecurityConstraint constraints[] = context.findConstraints();
1292 for (int i = 0; i < constraints.length; i++) {
1293 String roles[] = constraints[i].findAuthRoles();
1294 for (int j = 0; j < roles.length; j++) {
1295 if (!"*".equals(roles[j]) &&
1296 !context.findSecurityRole(roles[j])) {
1297 log.info(sm.getString("contextConfig.role.auth", roles[j]));
1298 context.addSecurityRole(roles[j]);
1299 }
1300 }
1301 }
1302
1303 // Check role names used in <servlet> elements
1304 Container wrappers[] = context.findChildren();
1305 for (int i = 0; i < wrappers.length; i++) {
1306 Wrapper wrapper = (Wrapper) wrappers[i];
1307 String runAs = wrapper.getRunAs();
1308 if ((runAs != null) && !context.findSecurityRole(runAs)) {
1309 log.info(sm.getString("contextConfig.role.runas", runAs));
1310 context.addSecurityRole(runAs);
1311 }
1312 String names[] = wrapper.findSecurityReferences();
1313 for (int j = 0; j < names.length; j++) {
1314 String link = wrapper.findSecurityReference(names[j]);
1315 if ((link != null) && !context.findSecurityRole(link)) {
1316 log.info(sm.getString("contextConfig.role.link", link));
1317 context.addSecurityRole(link);
1318 }
1319 }
1320 }
1321
1322 }
1323
1324
1325 /**
1326 * Get config base.
1327 */
1328 protected File getConfigBase() {
1329 File configBase =
1330 new File(System.getProperty("catalina.base"), "conf");
1331 if (!configBase.exists()) {
1332 return null;
1333 } else {
1334 return configBase;
1335 }
1336 }
1337
1338
1339 protected String getHostConfigPath(String resourceName) {
1340 StringBuffer result = new StringBuffer();
1341 Container container = context;
1342 Container host = null;
1343 Container engine = null;
1344 while (container != null) {
1345 if (container instanceof Host)
1346 host = container;
1347 if (container instanceof Engine)
1348 engine = container;
1349 container = container.getParent();
1350 }
1351 if (engine != null) {
1352 result.append(engine.getName()).append('/');
1353 }
1354 if (host != null) {
1355 result.append(host.getName()).append('/');
1356 }
1357 result.append(resourceName);
1358 return result.toString();
1359 }
1360
1361
1362 protected class ContextErrorHandler
1363 implements ErrorHandler {
1364
1365 public void error(SAXParseException exception) {
1366 parseException = exception;
1367 }
1368
1369 public void fatalError(SAXParseException exception) {
1370 parseException = exception;
1371 }
1372
1373 public void warning(SAXParseException exception) {
1374 parseException = exception;
1375 }
1376
1377 }
1378
1379
1380 }