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: 892815 $ $Date: 2009-12-21 14:27:57 +0100 (Mon, 21 Dec 2009) $
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 URL url=null;
343 // Process the application web.xml file
344 synchronized (webDigester) {
345 try {
346 if (altDDName != null) {
347 url = new File(altDDName).toURL();
348 } else {
349 url = servletContext.getResource(
350 Constants.ApplicationWebXml);
351 }
352 if( url!=null ) {
353 InputSource is = new InputSource(url.toExternalForm());
354 is.setByteStream(stream);
355 if (context instanceof StandardContext) {
356 ((StandardContext) context).setReplaceWelcomeFiles(true);
357 }
358 webDigester.push(context);
359 webDigester.setErrorHandler(new ContextErrorHandler());
360
361 if(log.isDebugEnabled()) {
362 log.debug("Parsing application web.xml file at " + url.toExternalForm());
363 }
364
365 webDigester.parse(is);
366
367 if (parseException != null) {
368 ok = false;
369 }
370 } else {
371 log.info("No web.xml, using defaults " + context );
372 }
373 } catch (SAXParseException e) {
374 log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e);
375 log.error(sm.getString("contextConfig.applicationPosition",
376 "" + e.getLineNumber(),
377 "" + e.getColumnNumber()));
378 ok = false;
379 } catch (Exception e) {
380 log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e);
381 ok = false;
382 } finally {
383 webDigester.reset();
384 parseException = null;
385 try {
386 if (stream != null) {
387 stream.close();
388 }
389 } catch (IOException e) {
390 log.error(sm.getString("contextConfig.applicationClose"), e);
391 }
392 }
393 }
394 webRuleSet.recycle();
395
396 long t2=System.currentTimeMillis();
397 if (context instanceof StandardContext) {
398 ((StandardContext) context).setStartupTime(t2-t1);
399 }
400 }
401
402
403 /**
404 * Set up an Authenticator automatically if required, and one has not
405 * already been configured.
406 */
407 protected synchronized void authenticatorConfig() {
408
409 // Does this Context require an Authenticator?
410 SecurityConstraint constraints[] = context.findConstraints();
411 if ((constraints == null) || (constraints.length == 0))
412 return;
413 LoginConfig loginConfig = context.getLoginConfig();
414 if (loginConfig == null) {
415 loginConfig = DUMMY_LOGIN_CONFIG;
416 context.setLoginConfig(loginConfig);
417 }
418
419 // Has an authenticator been configured already?
420 if (context instanceof Authenticator)
421 return;
422 if (context instanceof ContainerBase) {
423 Pipeline pipeline = ((ContainerBase) context).getPipeline();
424 if (pipeline != null) {
425 Valve basic = pipeline.getBasic();
426 if ((basic != null) && (basic instanceof Authenticator))
427 return;
428 Valve valves[] = pipeline.getValves();
429 for (int i = 0; i < valves.length; i++) {
430 if (valves[i] instanceof Authenticator)
431 return;
432 }
433 }
434 } else {
435 return; // Cannot install a Valve even if it would be needed
436 }
437
438 // Has a Realm been configured for us to authenticate against?
439 if (context.getRealm() == null) {
440 log.error(sm.getString("contextConfig.missingRealm"));
441 ok = false;
442 return;
443 }
444
445 /*
446 * First check to see if there is a custom mapping for the login
447 * method. If so, use it. Otherwise, check if there is a mapping in
448 * org/apache/catalina/startup/Authenticators.properties.
449 */
450 Valve authenticator = null;
451 if (customAuthenticators != null) {
452 authenticator = (Valve)
453 customAuthenticators.get(loginConfig.getAuthMethod());
454 }
455 if (authenticator == null) {
456 // Load our mapping properties if necessary
457 if (authenticators == null) {
458 try {
459 InputStream is=this.getClass().getClassLoader().getResourceAsStream("org/apache/catalina/startup/Authenticators.properties");
460 if( is!=null ) {
461 authenticators = new Properties();
462 authenticators.load(is);
463 } else {
464 log.error(sm.getString(
465 "contextConfig.authenticatorResources"));
466 ok=false;
467 return;
468 }
469 } catch (IOException e) {
470 log.error(sm.getString(
471 "contextConfig.authenticatorResources"), e);
472 ok = false;
473 return;
474 }
475 }
476
477 // Identify the class name of the Valve we should configure
478 String authenticatorName = null;
479 authenticatorName =
480 authenticators.getProperty(loginConfig.getAuthMethod());
481 if (authenticatorName == null) {
482 log.error(sm.getString("contextConfig.authenticatorMissing",
483 loginConfig.getAuthMethod()));
484 ok = false;
485 return;
486 }
487
488 // Instantiate and install an Authenticator of the requested class
489 try {
490 Class authenticatorClass = Class.forName(authenticatorName);
491 authenticator = (Valve) authenticatorClass.newInstance();
492 } catch (Throwable t) {
493 log.error(sm.getString(
494 "contextConfig.authenticatorInstantiate",
495 authenticatorName),
496 t);
497 ok = false;
498 }
499 }
500
501 if (authenticator != null && context instanceof ContainerBase) {
502 Pipeline pipeline = ((ContainerBase) context).getPipeline();
503 if (pipeline != null) {
504 ((ContainerBase) context).addValve(authenticator);
505 if (log.isDebugEnabled()) {
506 log.debug(sm.getString(
507 "contextConfig.authenticatorConfigured",
508 loginConfig.getAuthMethod()));
509 }
510 }
511 }
512
513 }
514
515
516 /**
517 * Create (if necessary) and return a Digester configured to process the
518 * web application deployment descriptor (web.xml).
519 */
520 protected static Digester createWebDigester() {
521 Digester webDigester =
522 createWebXmlDigester(xmlNamespaceAware, xmlValidation);
523 return webDigester;
524 }
525
526
527 /**
528 * Create (if necessary) and return a Digester configured to process the
529 * web application deployment descriptor (web.xml).
530 */
531 public static Digester createWebXmlDigester(boolean namespaceAware,
532 boolean validation) {
533
534 Digester webDigester = DigesterFactory.newDigester(xmlValidation,
535 xmlNamespaceAware,
536 webRuleSet);
537 return webDigester;
538 }
539
540
541 /**
542 * Create (if necessary) and return a Digester configured to process the
543 * context configuration descriptor for an application.
544 */
545 protected Digester createContextDigester() {
546 Digester digester = new Digester();
547 digester.setValidating(false);
548 RuleSet contextRuleSet = new ContextRuleSet("", false);
549 digester.addRuleSet(contextRuleSet);
550 RuleSet namingRuleSet = new NamingRuleSet("Context/");
551 digester.addRuleSet(namingRuleSet);
552 return digester;
553 }
554
555
556 protected String getBaseDir() {
557 Container engineC=context.getParent().getParent();
558 if( engineC instanceof StandardEngine ) {
559 return ((StandardEngine)engineC).getBaseDir();
560 }
561 return System.getProperty("catalina.base");
562 }
563
564 /**
565 * Process the default configuration file, if it exists.
566 * The default config must be read with the container loader - so
567 * container servlets can be loaded
568 */
569 protected void defaultWebConfig() {
570 long t1=System.currentTimeMillis();
571
572 // Open the default web.xml file, if it exists
573 if( defaultWebXml==null && context instanceof StandardContext ) {
574 defaultWebXml=((StandardContext)context).getDefaultWebXml();
575 }
576 // set the default if we don't have any overrides
577 if( defaultWebXml==null ) getDefaultWebXml();
578
579 File file = new File(this.defaultWebXml);
580 if (!file.isAbsolute()) {
581 file = new File(getBaseDir(),
582 this.defaultWebXml);
583 }
584
585 InputStream stream = null;
586 InputSource source = null;
587
588 try {
589 if ( ! file.exists() ) {
590 // Use getResource and getResourceAsStream
591 stream = getClass().getClassLoader()
592 .getResourceAsStream(defaultWebXml);
593 if( stream != null ) {
594 source = new InputSource
595 (getClass().getClassLoader()
596 .getResource(defaultWebXml).toString());
597 }
598 if( stream== null ) {
599 // maybe embedded
600 stream = getClass().getClassLoader()
601 .getResourceAsStream("web-embed.xml");
602 if( stream != null ) {
603 source = new InputSource
604 (getClass().getClassLoader()
605 .getResource("web-embed.xml").toString());
606 }
607 }
608
609 if( stream== null ) {
610 log.info("No default web.xml");
611 }
612 } else {
613 source =
614 new InputSource("file://" + file.getAbsolutePath());
615 stream = new FileInputStream(file);
616 context.addWatchedResource(file.getAbsolutePath());
617 }
618 } catch (Exception e) {
619 log.error(sm.getString("contextConfig.defaultMissing")
620 + " " + defaultWebXml + " " + file , e);
621 }
622
623 if (stream != null) {
624 processDefaultWebConfig(webDigester, stream, source);
625 webRuleSet.recycle();
626 }
627
628 long t2=System.currentTimeMillis();
629 if( (t2-t1) > 200 )
630 log.debug("Processed default web.xml " + file + " " + ( t2-t1));
631
632 stream = null;
633 source = null;
634
635 String resourceName = getHostConfigPath(Constants.HostWebXml);
636 file = new File(getConfigBase(), resourceName);
637
638 try {
639 if ( ! file.exists() ) {
640 // Use getResource and getResourceAsStream
641 stream = getClass().getClassLoader()
642 .getResourceAsStream(resourceName);
643 if( stream != null ) {
644 source = new InputSource
645 (getClass().getClassLoader()
646 .getResource(resourceName).toString());
647 }
648 } else {
649 source =
650 new InputSource("file://" + file.getAbsolutePath());
651 stream = new FileInputStream(file);
652 }
653 } catch (Exception e) {
654 log.error(sm.getString("contextConfig.defaultMissing")
655 + " " + resourceName + " " + file , e);
656 }
657
658 if (stream != null) {
659 processDefaultWebConfig(webDigester, stream, source);
660 webRuleSet.recycle();
661 }
662
663 }
664
665
666 /**
667 * Process a default web.xml.
668 */
669 protected void processDefaultWebConfig(Digester digester, InputStream stream,
670 InputSource source) {
671
672 if (log.isDebugEnabled())
673 log.debug("Processing context [" + context.getName()
674 + "] web configuration resource " + source.getSystemId());
675
676 // Process the default web.xml file
677 synchronized (digester) {
678 try {
679 source.setByteStream(stream);
680
681 if (context instanceof StandardContext)
682 ((StandardContext) context).setReplaceWelcomeFiles(true);
683 digester.setClassLoader(this.getClass().getClassLoader());
684 digester.setUseContextClassLoader(false);
685 digester.push(context);
686 digester.setErrorHandler(new ContextErrorHandler());
687 digester.parse(source);
688 if (parseException != null) {
689 ok = false;
690 }
691 } catch (SAXParseException e) {
692 log.error(sm.getString("contextConfig.defaultParse"), e);
693 log.error(sm.getString("contextConfig.defaultPosition",
694 "" + e.getLineNumber(),
695 "" + e.getColumnNumber()));
696 ok = false;
697 } catch (Exception e) {
698 log.error(sm.getString("contextConfig.defaultParse"), e);
699 ok = false;
700 } finally {
701 digester.reset();
702 parseException = null;
703 try {
704 if (stream != null) {
705 stream.close();
706 }
707 } catch (IOException e) {
708 log.error(sm.getString("contextConfig.defaultClose"), e);
709 }
710 }
711 }
712 }
713
714
715 /**
716 * Process the default configuration file, if it exists.
717 */
718 protected void contextConfig() {
719
720 // Open the default web.xml file, if it exists
721 if( defaultContextXml==null && context instanceof StandardContext ) {
722 defaultContextXml = ((StandardContext)context).getDefaultContextXml();
723 }
724 // set the default if we don't have any overrides
725 if( defaultContextXml==null ) getDefaultContextXml();
726
727 if (!context.getOverride()) {
728 processContextConfig(new File(getBaseDir()), defaultContextXml);
729 processContextConfig(getConfigBase(), getHostConfigPath(Constants.HostContextXml));
730 }
731 if (context.getConfigFile() != null)
732 processContextConfig(new File(context.getConfigFile()), null);
733
734 }
735
736
737 /**
738 * Process a context.xml.
739 */
740 protected void processContextConfig(File baseDir, String resourceName) {
741
742 if (log.isDebugEnabled())
743 log.debug("Processing context [" + context.getName()
744 + "] configuration file " + baseDir + " " + resourceName);
745
746 InputSource source = null;
747 InputStream stream = null;
748
749 File file = baseDir;
750 if (resourceName != null) {
751 file = new File(baseDir, resourceName);
752 }
753
754 try {
755 if ( !file.exists() ) {
756 if (resourceName != null) {
757 // Use getResource and getResourceAsStream
758 stream = getClass().getClassLoader()
759 .getResourceAsStream(resourceName);
760 if( stream != null ) {
761 source = new InputSource
762 (getClass().getClassLoader()
763 .getResource(resourceName).toString());
764 }
765 }
766 } else {
767 source =
768 new InputSource("file://" + file.getAbsolutePath());
769 stream = new FileInputStream(file);
770 // Add as watched resource so that cascade reload occurs if a default
771 // config file is modified/added/removed
772 context.addWatchedResource(file.getAbsolutePath());
773 }
774 } catch (Exception e) {
775 log.error(sm.getString("contextConfig.contextMissing",
776 resourceName + " " + file) , e);
777 }
778
779 if (source == null)
780 return;
781 synchronized (contextDigester) {
782 try {
783 source.setByteStream(stream);
784 contextDigester.setClassLoader(this.getClass().getClassLoader());
785 contextDigester.setUseContextClassLoader(false);
786 contextDigester.push(context.getParent());
787 contextDigester.push(context);
788 contextDigester.setErrorHandler(new ContextErrorHandler());
789 contextDigester.parse(source);
790 if (parseException != null) {
791 ok = false;
792 }
793 if (log.isDebugEnabled())
794 log.debug("Successfully processed context [" + context.getName()
795 + "] configuration file " + baseDir + " " + resourceName);
796 } catch (SAXParseException e) {
797 log.error(sm.getString("contextConfig.contextParse",
798 context.getName()), e);
799 log.error(sm.getString("contextConfig.defaultPosition",
800 "" + e.getLineNumber(),
801 "" + e.getColumnNumber()));
802 ok = false;
803 } catch (Exception e) {
804 log.error(sm.getString("contextConfig.contextParse",
805 context.getName()), e);
806 ok = false;
807 } finally {
808 contextDigester.reset();
809 parseException = null;
810 try {
811 if (stream != null) {
812 stream.close();
813 }
814 } catch (IOException e) {
815 log.error(sm.getString("contextConfig.contextClose"), e);
816 }
817 }
818 }
819 }
820
821
822 /**
823 * Adjust docBase.
824 */
825 protected void fixDocBase()
826 throws IOException {
827
828 Host host = (Host) context.getParent();
829 String appBase = host.getAppBase();
830
831 boolean unpackWARs = true;
832 if (host instanceof StandardHost) {
833 unpackWARs = ((StandardHost) host).isUnpackWARs()
834 && ((StandardContext) context).getUnpackWAR();
835 }
836
837 File canonicalAppBase = new File(appBase);
838 if (canonicalAppBase.isAbsolute()) {
839 canonicalAppBase = canonicalAppBase.getCanonicalFile();
840 } else {
841 canonicalAppBase =
842 new File(System.getProperty("catalina.base"), appBase)
843 .getCanonicalFile();
844 }
845
846 String docBase = context.getDocBase();
847 if (docBase == null) {
848 // Trying to guess the docBase according to the path
849 String path = context.getPath();
850 if (path == null) {
851 return;
852 }
853 if (path.equals("")) {
854 docBase = "ROOT";
855 } else {
856 if (path.startsWith("/")) {
857 docBase = path.substring(1).replace('/', '#');
858 } else {
859 docBase = path.replace('/', '#');
860 }
861 }
862 }
863
864 File file = new File(docBase);
865 if (!file.isAbsolute()) {
866 docBase = (new File(canonicalAppBase, docBase)).getPath();
867 } else {
868 docBase = file.getCanonicalPath();
869 }
870 file = new File(docBase);
871 String origDocBase = docBase;
872
873 String pathName = context.getPath();
874 if (pathName.equals("")) {
875 pathName = "ROOT";
876 } else {
877 // Context path must start with '/'
878 pathName = pathName.substring(1).replace('/', '#');
879 }
880 if (docBase.toLowerCase().endsWith(".war") && !file.isDirectory() && unpackWARs) {
881 URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/");
882 docBase = ExpandWar.expand(host, war, pathName);
883 file = new File(docBase);
884 docBase = file.getCanonicalPath();
885 if (context instanceof StandardContext) {
886 ((StandardContext) context).setOriginalDocBase(origDocBase);
887 }
888 } else if (docBase.toLowerCase().endsWith(".war") &&
889 !file.isDirectory() && !unpackWARs) {
890 URL war =
891 new URL("jar:" + (new File (docBase)).toURI().toURL() + "!/");
892 ExpandWar.validate(host, war, pathName);
893 } else {
894 File docDir = new File(docBase);
895 if (!docDir.exists()) {
896 File warFile = new File(docBase + ".war");
897 if (warFile.exists()) {
898 URL war =
899 new URL("jar:" + warFile.toURI().toURL() + "!/");
900 if (unpackWARs) {
901 docBase = ExpandWar.expand(host, war, pathName);
902 file = new File(docBase);
903 docBase = file.getCanonicalPath();
904 } else {
905 docBase = warFile.getCanonicalPath();
906 ExpandWar.validate(host, war, pathName);
907 }
908 }
909 if (context instanceof StandardContext) {
910 ((StandardContext) context).setOriginalDocBase(origDocBase);
911 }
912 }
913 }
914
915 if (docBase.startsWith(canonicalAppBase.getPath() + File.separatorChar)) {
916 docBase = docBase.substring(canonicalAppBase.getPath().length());
917 docBase = docBase.replace(File.separatorChar, '/');
918 if (docBase.startsWith("/")) {
919 docBase = docBase.substring(1);
920 }
921 } else {
922 docBase = docBase.replace(File.separatorChar, '/');
923 }
924
925 context.setDocBase(docBase);
926
927 }
928
929
930 protected void antiLocking()
931 throws IOException {
932
933 if ((context instanceof StandardContext)
934 && ((StandardContext) context).getAntiResourceLocking()) {
935
936 Host host = (Host) context.getParent();
937 String appBase = host.getAppBase();
938 String docBase = context.getDocBase();
939 if (docBase == null)
940 return;
941 if (originalDocBase == null) {
942 originalDocBase = docBase;
943 } else {
944 docBase = originalDocBase;
945 }
946 File docBaseFile = new File(docBase);
947 if (!docBaseFile.isAbsolute()) {
948 File file = new File(appBase);
949 if (!file.isAbsolute()) {
950 file = new File(System.getProperty("catalina.base"), appBase);
951 }
952 docBaseFile = new File(file, docBase);
953 }
954
955 String path = context.getPath();
956 if (path == null) {
957 return;
958 }
959 if (path.equals("")) {
960 docBase = "ROOT";
961 } else {
962 if (path.startsWith("/")) {
963 docBase = path.substring(1);
964 } else {
965 docBase = path;
966 }
967 }
968
969 File file = null;
970 if (docBase.toLowerCase().endsWith(".war")) {
971 file = new File(System.getProperty("java.io.tmpdir"),
972 deploymentCount++ + "-" + docBase + ".war");
973 } else {
974 file = new File(System.getProperty("java.io.tmpdir"),
975 deploymentCount++ + "-" + docBase);
976 }
977
978 if (log.isDebugEnabled())
979 log.debug("Anti locking context[" + context.getPath()
980 + "] setting docBase to " + file);
981
982 // Cleanup just in case an old deployment is lying around
983 ExpandWar.delete(file);
984 if (ExpandWar.copy(docBaseFile, file)) {
985 context.setDocBase(file.getAbsolutePath());
986 }
987
988 }
989
990 }
991
992
993 /**
994 * Process a "init" event for this Context.
995 */
996 protected void init() {
997 // Called from StandardContext.init()
998
999 if (webDigester == null){
1000 webDigester = createWebDigester();
1001 webDigester.getParser();
1002 }
1003
1004 if (contextDigester == null){
1005 contextDigester = createContextDigester();
1006 contextDigester.getParser();
1007 }
1008
1009 if (log.isDebugEnabled())
1010 log.debug(sm.getString("contextConfig.init"));
1011 context.setConfigured(false);
1012 ok = true;
1013
1014 contextConfig();
1015
1016 try {
1017 fixDocBase();
1018 } catch (IOException e) {
1019 log.error(sm.getString(
1020 "contextConfig.fixDocBase", context.getPath()), e);
1021 }
1022
1023 }
1024
1025
1026 /**
1027 * Process a "before start" event for this Context.
1028 */
1029 protected synchronized void beforeStart() {
1030
1031 try {
1032 antiLocking();
1033 } catch (IOException e) {
1034 log.error(sm.getString("contextConfig.antiLocking"), e);
1035 }
1036
1037 }
1038
1039
1040 /**
1041 * Process a "start" event for this Context.
1042 */
1043 protected synchronized void start() {
1044 // Called from StandardContext.start()
1045
1046 if (log.isDebugEnabled())
1047 log.debug(sm.getString("contextConfig.start"));
1048
1049 // Set properties based on DefaultContext
1050 Container container = context.getParent();
1051 if( !context.getOverride() ) {
1052 if( container instanceof Host ) {
1053 // Reset the value only if the attribute wasn't
1054 // set on the context.
1055 xmlValidation = context.getXmlValidation();
1056 if (!xmlValidation) {
1057 xmlValidation = ((Host)container).getXmlValidation();
1058 }
1059
1060 xmlNamespaceAware = context.getXmlNamespaceAware();
1061 if (!xmlNamespaceAware){
1062 xmlNamespaceAware
1063 = ((Host)container).getXmlNamespaceAware();
1064 }
1065
1066 container = container.getParent();
1067 }
1068 }
1069
1070 // Process the default and application web.xml files
1071 defaultWebConfig();
1072 applicationWebConfig();
1073 if (!context.getIgnoreAnnotations()) {
1074 applicationAnnotationsConfig();
1075 }
1076 if (ok) {
1077 validateSecurityRoles();
1078 }
1079
1080 // Configure an authenticator if we need one
1081 if (ok)
1082 authenticatorConfig();
1083
1084 // Dump the contents of this pipeline if requested
1085 if ((log.isDebugEnabled()) && (context instanceof ContainerBase)) {
1086 log.debug("Pipeline Configuration:");
1087 Pipeline pipeline = ((ContainerBase) context).getPipeline();
1088 Valve valves[] = null;
1089 if (pipeline != null)
1090 valves = pipeline.getValves();
1091 if (valves != null) {
1092 for (int i = 0; i < valves.length; i++) {
1093 log.debug(" " + valves[i].getInfo());
1094 }
1095 }
1096 log.debug("======================");
1097 }
1098
1099 // Make our application available if no problems were encountered
1100 if (ok)
1101 context.setConfigured(true);
1102 else {
1103 log.error(sm.getString("contextConfig.unavailable"));
1104 context.setConfigured(false);
1105 }
1106
1107 }
1108
1109
1110 /**
1111 * Process a "stop" event for this Context.
1112 */
1113 protected synchronized void stop() {
1114
1115 if (log.isDebugEnabled())
1116 log.debug(sm.getString("contextConfig.stop"));
1117
1118 int i;
1119
1120 // Removing children
1121 Container[] children = context.findChildren();
1122 for (i = 0; i < children.length; i++) {
1123 context.removeChild(children[i]);
1124 }
1125
1126 // Removing application parameters
1127 /*
1128 ApplicationParameter[] applicationParameters =
1129 context.findApplicationParameters();
1130 for (i = 0; i < applicationParameters.length; i++) {
1131 context.removeApplicationParameter
1132 (applicationParameters[i].getName());
1133 }
1134 */
1135
1136 // Removing security constraints
1137 SecurityConstraint[] securityConstraints = context.findConstraints();
1138 for (i = 0; i < securityConstraints.length; i++) {
1139 context.removeConstraint(securityConstraints[i]);
1140 }
1141
1142 // Removing Ejbs
1143 /*
1144 ContextEjb[] contextEjbs = context.findEjbs();
1145 for (i = 0; i < contextEjbs.length; i++) {
1146 context.removeEjb(contextEjbs[i].getName());
1147 }
1148 */
1149
1150 // Removing environments
1151 /*
1152 ContextEnvironment[] contextEnvironments = context.findEnvironments();
1153 for (i = 0; i < contextEnvironments.length; i++) {
1154 context.removeEnvironment(contextEnvironments[i].getName());
1155 }
1156 */
1157
1158 // Removing errors pages
1159 ErrorPage[] errorPages = context.findErrorPages();
1160 for (i = 0; i < errorPages.length; i++) {
1161 context.removeErrorPage(errorPages[i]);
1162 }
1163
1164 // Removing filter defs
1165 FilterDef[] filterDefs = context.findFilterDefs();
1166 for (i = 0; i < filterDefs.length; i++) {
1167 context.removeFilterDef(filterDefs[i]);
1168 }
1169
1170 // Removing filter maps
1171 FilterMap[] filterMaps = context.findFilterMaps();
1172 for (i = 0; i < filterMaps.length; i++) {
1173 context.removeFilterMap(filterMaps[i]);
1174 }
1175
1176 // Removing local ejbs
1177 /*
1178 ContextLocalEjb[] contextLocalEjbs = context.findLocalEjbs();
1179 for (i = 0; i < contextLocalEjbs.length; i++) {
1180 context.removeLocalEjb(contextLocalEjbs[i].getName());
1181 }
1182 */
1183
1184 // Removing Mime mappings
1185 String[] mimeMappings = context.findMimeMappings();
1186 for (i = 0; i < mimeMappings.length; i++) {
1187 context.removeMimeMapping(mimeMappings[i]);
1188 }
1189
1190 // Removing parameters
1191 String[] parameters = context.findParameters();
1192 for (i = 0; i < parameters.length; i++) {
1193 context.removeParameter(parameters[i]);
1194 }
1195
1196 // Removing resource env refs
1197 /*
1198 String[] resourceEnvRefs = context.findResourceEnvRefs();
1199 for (i = 0; i < resourceEnvRefs.length; i++) {
1200 context.removeResourceEnvRef(resourceEnvRefs[i]);
1201 }
1202 */
1203
1204 // Removing resource links
1205 /*
1206 ContextResourceLink[] contextResourceLinks =
1207 context.findResourceLinks();
1208 for (i = 0; i < contextResourceLinks.length; i++) {
1209 context.removeResourceLink(contextResourceLinks[i].getName());
1210 }
1211 */
1212
1213 // Removing resources
1214 /*
1215 ContextResource[] contextResources = context.findResources();
1216 for (i = 0; i < contextResources.length; i++) {
1217 context.removeResource(contextResources[i].getName());
1218 }
1219 */
1220
1221 // Removing sercurity role
1222 String[] securityRoles = context.findSecurityRoles();
1223 for (i = 0; i < securityRoles.length; i++) {
1224 context.removeSecurityRole(securityRoles[i]);
1225 }
1226
1227 // Removing servlet mappings
1228 String[] servletMappings = context.findServletMappings();
1229 for (i = 0; i < servletMappings.length; i++) {
1230 context.removeServletMapping(servletMappings[i]);
1231 }
1232
1233 // FIXME : Removing status pages
1234
1235 // Removing taglibs
1236 String[] taglibs = context.findTaglibs();
1237 for (i = 0; i < taglibs.length; i++) {
1238 context.removeTaglib(taglibs[i]);
1239 }
1240
1241 // Removing welcome files
1242 String[] welcomeFiles = context.findWelcomeFiles();
1243 for (i = 0; i < welcomeFiles.length; i++) {
1244 context.removeWelcomeFile(welcomeFiles[i]);
1245 }
1246
1247 // Removing wrapper lifecycles
1248 String[] wrapperLifecycles = context.findWrapperLifecycles();
1249 for (i = 0; i < wrapperLifecycles.length; i++) {
1250 context.removeWrapperLifecycle(wrapperLifecycles[i]);
1251 }
1252
1253 // Removing wrapper listeners
1254 String[] wrapperListeners = context.findWrapperListeners();
1255 for (i = 0; i < wrapperListeners.length; i++) {
1256 context.removeWrapperListener(wrapperListeners[i]);
1257 }
1258
1259 // Remove (partially) folders and files created by antiLocking
1260 Host host = (Host) context.getParent();
1261 String appBase = host.getAppBase();
1262 String docBase = context.getDocBase();
1263 if ((docBase != null) && (originalDocBase != null)) {
1264 File docBaseFile = new File(docBase);
1265 if (!docBaseFile.isAbsolute()) {
1266 docBaseFile = new File(appBase, docBase);
1267 }
1268 // No need to log failure - it is expected in this case
1269 ExpandWar.delete(docBaseFile, false);
1270 }
1271
1272 ok = true;
1273
1274 }
1275
1276
1277 /**
1278 * Process a "destroy" event for this Context.
1279 */
1280 protected synchronized void destroy() {
1281 // Called from StandardContext.destroy()
1282 if (log.isDebugEnabled())
1283 log.debug(sm.getString("contextConfig.destroy"));
1284
1285 // Changed to getWorkPath per Bugzilla 35819.
1286 String workDir = ((StandardContext) context).getWorkPath();
1287 if (workDir != null)
1288 ExpandWar.delete(new File(workDir));
1289 }
1290
1291
1292 /**
1293 * Validate the usage of security role names in the web application
1294 * deployment descriptor. If any problems are found, issue warning
1295 * messages (for backwards compatibility) and add the missing roles.
1296 * (To make these problems fatal instead, simply set the <code>ok</code>
1297 * instance variable to <code>false</code> as well).
1298 */
1299 protected void validateSecurityRoles() {
1300
1301 // Check role names used in <security-constraint> elements
1302 SecurityConstraint constraints[] = context.findConstraints();
1303 for (int i = 0; i < constraints.length; i++) {
1304 String roles[] = constraints[i].findAuthRoles();
1305 for (int j = 0; j < roles.length; j++) {
1306 if (!"*".equals(roles[j]) &&
1307 !context.findSecurityRole(roles[j])) {
1308 log.info(sm.getString("contextConfig.role.auth", roles[j]));
1309 context.addSecurityRole(roles[j]);
1310 }
1311 }
1312 }
1313
1314 // Check role names used in <servlet> elements
1315 Container wrappers[] = context.findChildren();
1316 for (int i = 0; i < wrappers.length; i++) {
1317 Wrapper wrapper = (Wrapper) wrappers[i];
1318 String runAs = wrapper.getRunAs();
1319 if ((runAs != null) && !context.findSecurityRole(runAs)) {
1320 log.info(sm.getString("contextConfig.role.runas", runAs));
1321 context.addSecurityRole(runAs);
1322 }
1323 String names[] = wrapper.findSecurityReferences();
1324 for (int j = 0; j < names.length; j++) {
1325 String link = wrapper.findSecurityReference(names[j]);
1326 if ((link != null) && !context.findSecurityRole(link)) {
1327 log.info(sm.getString("contextConfig.role.link", link));
1328 context.addSecurityRole(link);
1329 }
1330 }
1331 }
1332
1333 }
1334
1335
1336 /**
1337 * Get config base.
1338 */
1339 protected File getConfigBase() {
1340 File configBase =
1341 new File(System.getProperty("catalina.base"), "conf");
1342 if (!configBase.exists()) {
1343 return null;
1344 } else {
1345 return configBase;
1346 }
1347 }
1348
1349
1350 protected String getHostConfigPath(String resourceName) {
1351 StringBuffer result = new StringBuffer();
1352 Container container = context;
1353 Container host = null;
1354 Container engine = null;
1355 while (container != null) {
1356 if (container instanceof Host)
1357 host = container;
1358 if (container instanceof Engine)
1359 engine = container;
1360 container = container.getParent();
1361 }
1362 if (engine != null) {
1363 result.append(engine.getName()).append('/');
1364 }
1365 if (host != null) {
1366 result.append(host.getName()).append('/');
1367 }
1368 result.append(resourceName);
1369 return result.toString();
1370 }
1371
1372
1373 protected class ContextErrorHandler
1374 implements ErrorHandler {
1375
1376 public void error(SAXParseException exception) {
1377 parseException = exception;
1378 }
1379
1380 public void fatalError(SAXParseException exception) {
1381 parseException = exception;
1382 }
1383
1384 public void warning(SAXParseException exception) {
1385 parseException = exception;
1386 }
1387
1388 }
1389
1390
1391 }