0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.catalina.startup;
0019:
0020: import java.io.File;
0021: import java.io.FileInputStream;
0022: import java.io.FileNotFoundException;
0023: import java.io.IOException;
0024: import java.io.InputStream;
0025: import java.net.URL;
0026: import java.util.Map;
0027: import java.util.Properties;
0028:
0029: import javax.servlet.ServletContext;
0030:
0031: import org.apache.catalina.Authenticator;
0032: import org.apache.catalina.Container;
0033: import org.apache.catalina.Context;
0034: import org.apache.catalina.Engine;
0035: import org.apache.catalina.Globals;
0036: import org.apache.catalina.Host;
0037: import org.apache.catalina.Lifecycle;
0038: import org.apache.catalina.LifecycleEvent;
0039: import org.apache.catalina.LifecycleListener;
0040: import org.apache.catalina.Pipeline;
0041: import org.apache.catalina.Valve;
0042: import org.apache.catalina.Wrapper;
0043: import org.apache.catalina.core.ContainerBase;
0044: import org.apache.catalina.core.StandardContext;
0045: import org.apache.catalina.core.StandardEngine;
0046: import org.apache.catalina.core.StandardHost;
0047: import org.apache.catalina.deploy.ErrorPage;
0048: import org.apache.catalina.deploy.FilterDef;
0049: import org.apache.catalina.deploy.FilterMap;
0050: import org.apache.catalina.deploy.LoginConfig;
0051: import org.apache.catalina.deploy.SecurityConstraint;
0052: import org.apache.catalina.util.StringManager;
0053: import org.apache.tomcat.util.digester.Digester;
0054: import org.apache.tomcat.util.digester.RuleSet;
0055: import org.xml.sax.ErrorHandler;
0056: import org.xml.sax.InputSource;
0057: import org.xml.sax.SAXParseException;
0058:
0059: /**
0060: * Startup event listener for a <b>Context</b> that configures the properties
0061: * of that Context, and the associated defined servlets.
0062: *
0063: * @author Craig R. McClanahan
0064: * @author Jean-Francois Arcand
0065: * @version $Revision: 556489 $ $Date: 2007-07-16 04:01:01 +0200 (lun., 16 juil. 2007) $
0066: */
0067:
0068: public class ContextConfig implements LifecycleListener {
0069:
0070: protected static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
0071: .getLog(ContextConfig.class);
0072:
0073: // ----------------------------------------------------- Instance Variables
0074:
0075: /**
0076: * Custom mappings of login methods to authenticators
0077: */
0078: protected Map customAuthenticators;
0079:
0080: /**
0081: * The set of Authenticators that we know how to configure. The key is
0082: * the name of the implemented authentication method, and the value is
0083: * the fully qualified Java class name of the corresponding Valve.
0084: */
0085: protected static Properties authenticators = null;
0086:
0087: /**
0088: * The Context we are associated with.
0089: */
0090: protected Context context = null;
0091:
0092: /**
0093: * The default web application's context file location.
0094: */
0095: protected String defaultContextXml = null;
0096:
0097: /**
0098: * The default web application's deployment descriptor location.
0099: */
0100: protected String defaultWebXml = null;
0101:
0102: /**
0103: * Track any fatal errors during startup configuration processing.
0104: */
0105: protected boolean ok = false;
0106:
0107: /**
0108: * Any parse error which occurred while parsing XML descriptors.
0109: */
0110: protected SAXParseException parseException = null;
0111:
0112: /**
0113: * Original docBase.
0114: */
0115: protected String originalDocBase = null;
0116:
0117: /**
0118: * The string resources for this package.
0119: */
0120: protected static final StringManager sm = StringManager
0121: .getManager(Constants.Package);
0122:
0123: /**
0124: * The <code>Digester</code> we will use to process web application
0125: * context files.
0126: */
0127: protected static Digester contextDigester = null;
0128:
0129: /**
0130: * The <code>Digester</code> we will use to process web application
0131: * deployment descriptor files.
0132: */
0133: protected static Digester webDigester = null;
0134:
0135: /**
0136: * The <code>Rule</code> used to parse the web.xml
0137: */
0138: protected static WebRuleSet webRuleSet = new WebRuleSet();
0139:
0140: /**
0141: * Attribute value used to turn on/off XML validation
0142: */
0143: protected static boolean xmlValidation = false;
0144:
0145: /**
0146: * Attribute value used to turn on/off XML namespace awarenes.
0147: */
0148: protected static boolean xmlNamespaceAware = false;
0149:
0150: /**
0151: * Deployment count.
0152: */
0153: protected static long deploymentCount = 0L;
0154:
0155: protected static final LoginConfig DUMMY_LOGIN_CONFIG = new LoginConfig(
0156: "NONE", null, null, null);
0157:
0158: // ------------------------------------------------------------- Properties
0159:
0160: /**
0161: * Return the location of the default deployment descriptor
0162: */
0163: public String getDefaultWebXml() {
0164: if (defaultWebXml == null) {
0165: defaultWebXml = Constants.DefaultWebXml;
0166: }
0167:
0168: return (this .defaultWebXml);
0169:
0170: }
0171:
0172: /**
0173: * Set the location of the default deployment descriptor
0174: *
0175: * @param path Absolute/relative path to the default web.xml
0176: */
0177: public void setDefaultWebXml(String path) {
0178:
0179: this .defaultWebXml = path;
0180:
0181: }
0182:
0183: /**
0184: * Return the location of the default context file
0185: */
0186: public String getDefaultContextXml() {
0187: if (defaultContextXml == null) {
0188: defaultContextXml = Constants.DefaultContextXml;
0189: }
0190:
0191: return (this .defaultContextXml);
0192:
0193: }
0194:
0195: /**
0196: * Set the location of the default context file
0197: *
0198: * @param path Absolute/relative path to the default context.xml
0199: */
0200: public void setDefaultContextXml(String path) {
0201:
0202: this .defaultContextXml = path;
0203:
0204: }
0205:
0206: /**
0207: * Sets custom mappings of login methods to authenticators.
0208: *
0209: * @param customAuthenticators Custom mappings of login methods to
0210: * authenticators
0211: */
0212: public void setCustomAuthenticators(Map customAuthenticators) {
0213: this .customAuthenticators = customAuthenticators;
0214: }
0215:
0216: // --------------------------------------------------------- Public Methods
0217:
0218: /**
0219: * Process events for an associated Context.
0220: *
0221: * @param event The lifecycle event that has occurred
0222: */
0223: public void lifecycleEvent(LifecycleEvent event) {
0224:
0225: // Identify the context we are associated with
0226: try {
0227: context = (Context) event.getLifecycle();
0228: } catch (ClassCastException e) {
0229: log.error(sm.getString("contextConfig.cce", event
0230: .getLifecycle()), e);
0231: return;
0232: }
0233:
0234: // Process the event that has occurred
0235: if (event.getType().equals(Lifecycle.START_EVENT)) {
0236: start();
0237: } else if (event.getType().equals(
0238: StandardContext.BEFORE_START_EVENT)) {
0239: beforeStart();
0240: } else if (event.getType().equals(
0241: StandardContext.AFTER_START_EVENT)) {
0242: // Restore docBase for management tools
0243: if (originalDocBase != null) {
0244: String docBase = context.getDocBase();
0245: context.setDocBase(originalDocBase);
0246: originalDocBase = docBase;
0247: }
0248: } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
0249: if (originalDocBase != null) {
0250: String docBase = context.getDocBase();
0251: context.setDocBase(originalDocBase);
0252: originalDocBase = docBase;
0253: }
0254: stop();
0255: } else if (event.getType().equals(Lifecycle.INIT_EVENT)) {
0256: init();
0257: } else if (event.getType().equals(Lifecycle.DESTROY_EVENT)) {
0258: destroy();
0259: }
0260:
0261: }
0262:
0263: // -------------------------------------------------------- protected Methods
0264:
0265: /**
0266: * Process the application classes annotations, if it exists.
0267: */
0268: protected void applicationAnnotationsConfig() {
0269:
0270: long t1 = System.currentTimeMillis();
0271:
0272: WebAnnotationSet.loadApplicationAnnotations(context);
0273:
0274: long t2 = System.currentTimeMillis();
0275: if (context instanceof StandardContext) {
0276: ((StandardContext) context).setStartupTime(t2 - t1
0277: + ((StandardContext) context).getStartupTime());
0278: }
0279: }
0280:
0281: /**
0282: * Process the application configuration file, if it exists.
0283: */
0284: protected void applicationWebConfig() {
0285:
0286: String altDDName = null;
0287:
0288: // Open the application web.xml file, if it exists
0289: InputStream stream = null;
0290: ServletContext servletContext = context.getServletContext();
0291: if (servletContext != null) {
0292: altDDName = (String) servletContext
0293: .getAttribute(Globals.ALT_DD_ATTR);
0294: if (altDDName != null) {
0295: try {
0296: stream = new FileInputStream(altDDName);
0297: } catch (FileNotFoundException e) {
0298: log.error(sm.getString(
0299: "contextConfig.altDDNotFound", altDDName));
0300: }
0301: } else {
0302: stream = servletContext
0303: .getResourceAsStream(Constants.ApplicationWebXml);
0304: }
0305: }
0306: if (stream == null) {
0307: if (log.isDebugEnabled()) {
0308: log.debug(sm
0309: .getString("contextConfig.applicationMissing")
0310: + " " + context);
0311: }
0312: return;
0313: }
0314:
0315: long t1 = System.currentTimeMillis();
0316:
0317: if (webDigester == null) {
0318: webDigester = createWebDigester();
0319: }
0320:
0321: URL url = null;
0322: // Process the application web.xml file
0323: synchronized (webDigester) {
0324: try {
0325: if (altDDName != null) {
0326: url = new File(altDDName).toURL();
0327: } else {
0328: url = servletContext
0329: .getResource(Constants.ApplicationWebXml);
0330: }
0331: if (url != null) {
0332: InputSource is = new InputSource(url
0333: .toExternalForm());
0334: is.setByteStream(stream);
0335: if (context instanceof StandardContext) {
0336: ((StandardContext) context)
0337: .setReplaceWelcomeFiles(true);
0338: }
0339: webDigester.push(context);
0340: webDigester
0341: .setErrorHandler(new ContextErrorHandler());
0342:
0343: if (log.isDebugEnabled()) {
0344: log
0345: .debug("Parsing application web.xml file at "
0346: + url.toExternalForm());
0347: }
0348:
0349: webDigester.parse(is);
0350:
0351: if (parseException != null) {
0352: ok = false;
0353: }
0354: } else {
0355: log.info("No web.xml, using defaults " + context);
0356: }
0357: } catch (SAXParseException e) {
0358: log.error(sm.getString(
0359: "contextConfig.applicationParse", url
0360: .toExternalForm()), e);
0361: log.error(sm.getString(
0362: "contextConfig.applicationPosition", ""
0363: + e.getLineNumber(), ""
0364: + e.getColumnNumber()));
0365: ok = false;
0366: } catch (Exception e) {
0367: log.error(sm.getString(
0368: "contextConfig.applicationParse", url
0369: .toExternalForm()), e);
0370: ok = false;
0371: } finally {
0372: webDigester.reset();
0373: parseException = null;
0374: try {
0375: if (stream != null) {
0376: stream.close();
0377: }
0378: } catch (IOException e) {
0379: log
0380: .error(
0381: sm
0382: .getString("contextConfig.applicationClose"),
0383: e);
0384: }
0385: }
0386: }
0387: webRuleSet.recycle();
0388:
0389: long t2 = System.currentTimeMillis();
0390: if (context instanceof StandardContext) {
0391: ((StandardContext) context).setStartupTime(t2 - t1);
0392: }
0393: }
0394:
0395: /**
0396: * Set up an Authenticator automatically if required, and one has not
0397: * already been configured.
0398: */
0399: protected synchronized void authenticatorConfig() {
0400:
0401: // Does this Context require an Authenticator?
0402: SecurityConstraint constraints[] = context.findConstraints();
0403: if ((constraints == null) || (constraints.length == 0))
0404: return;
0405: LoginConfig loginConfig = context.getLoginConfig();
0406: if (loginConfig == null) {
0407: loginConfig = DUMMY_LOGIN_CONFIG;
0408: context.setLoginConfig(loginConfig);
0409: }
0410:
0411: // Has an authenticator been configured already?
0412: if (context instanceof Authenticator)
0413: return;
0414: if (context instanceof ContainerBase) {
0415: Pipeline pipeline = ((ContainerBase) context).getPipeline();
0416: if (pipeline != null) {
0417: Valve basic = pipeline.getBasic();
0418: if ((basic != null) && (basic instanceof Authenticator))
0419: return;
0420: Valve valves[] = pipeline.getValves();
0421: for (int i = 0; i < valves.length; i++) {
0422: if (valves[i] instanceof Authenticator)
0423: return;
0424: }
0425: }
0426: } else {
0427: return; // Cannot install a Valve even if it would be needed
0428: }
0429:
0430: // Has a Realm been configured for us to authenticate against?
0431: if (context.getRealm() == null) {
0432: log.error(sm.getString("contextConfig.missingRealm"));
0433: ok = false;
0434: return;
0435: }
0436:
0437: /*
0438: * First check to see if there is a custom mapping for the login
0439: * method. If so, use it. Otherwise, check if there is a mapping in
0440: * org/apache/catalina/startup/Authenticators.properties.
0441: */
0442: Valve authenticator = null;
0443: if (customAuthenticators != null) {
0444: authenticator = (Valve) customAuthenticators
0445: .get(loginConfig.getAuthMethod());
0446: }
0447: if (authenticator == null) {
0448: // Load our mapping properties if necessary
0449: if (authenticators == null) {
0450: try {
0451: InputStream is = this
0452: .getClass()
0453: .getClassLoader()
0454: .getResourceAsStream(
0455: "org/apache/catalina/startup/Authenticators.properties");
0456: if (is != null) {
0457: authenticators = new Properties();
0458: authenticators.load(is);
0459: } else {
0460: log
0461: .error(sm
0462: .getString("contextConfig.authenticatorResources"));
0463: ok = false;
0464: return;
0465: }
0466: } catch (IOException e) {
0467: log
0468: .error(
0469: sm
0470: .getString("contextConfig.authenticatorResources"),
0471: e);
0472: ok = false;
0473: return;
0474: }
0475: }
0476:
0477: // Identify the class name of the Valve we should configure
0478: String authenticatorName = null;
0479: authenticatorName = authenticators.getProperty(loginConfig
0480: .getAuthMethod());
0481: if (authenticatorName == null) {
0482: log.error(sm.getString(
0483: "contextConfig.authenticatorMissing",
0484: loginConfig.getAuthMethod()));
0485: ok = false;
0486: return;
0487: }
0488:
0489: // Instantiate and install an Authenticator of the requested class
0490: try {
0491: Class authenticatorClass = Class
0492: .forName(authenticatorName);
0493: authenticator = (Valve) authenticatorClass
0494: .newInstance();
0495: } catch (Throwable t) {
0496: log.error(sm.getString(
0497: "contextConfig.authenticatorInstantiate",
0498: authenticatorName), t);
0499: ok = false;
0500: }
0501: }
0502:
0503: if (authenticator != null && context instanceof ContainerBase) {
0504: Pipeline pipeline = ((ContainerBase) context).getPipeline();
0505: if (pipeline != null) {
0506: ((ContainerBase) context).addValve(authenticator);
0507: if (log.isDebugEnabled()) {
0508: log.debug(sm.getString(
0509: "contextConfig.authenticatorConfigured",
0510: loginConfig.getAuthMethod()));
0511: }
0512: }
0513: }
0514:
0515: }
0516:
0517: /**
0518: * Create (if necessary) and return a Digester configured to process the
0519: * web application deployment descriptor (web.xml).
0520: */
0521: protected static Digester createWebDigester() {
0522: Digester webDigester = createWebXmlDigester(xmlNamespaceAware,
0523: xmlValidation);
0524: return webDigester;
0525: }
0526:
0527: /**
0528: * Create (if necessary) and return a Digester configured to process the
0529: * web application deployment descriptor (web.xml).
0530: */
0531: public static Digester createWebXmlDigester(boolean namespaceAware,
0532: boolean validation) {
0533:
0534: Digester webDigester = DigesterFactory.newDigester(
0535: xmlValidation, xmlNamespaceAware, webRuleSet);
0536: return webDigester;
0537: }
0538:
0539: /**
0540: * Create (if necessary) and return a Digester configured to process the
0541: * context configuration descriptor for an application.
0542: */
0543: protected Digester createContextDigester() {
0544: Digester digester = new Digester();
0545: digester.setValidating(false);
0546: RuleSet contextRuleSet = new ContextRuleSet("", false);
0547: digester.addRuleSet(contextRuleSet);
0548: RuleSet namingRuleSet = new NamingRuleSet("Context/");
0549: digester.addRuleSet(namingRuleSet);
0550: return digester;
0551: }
0552:
0553: protected String getBaseDir() {
0554: Container engineC = context.getParent().getParent();
0555: if (engineC instanceof StandardEngine) {
0556: return ((StandardEngine) engineC).getBaseDir();
0557: }
0558: return System.getProperty("catalina.base");
0559: }
0560:
0561: /**
0562: * Process the default configuration file, if it exists.
0563: * The default config must be read with the container loader - so
0564: * container servlets can be loaded
0565: */
0566: protected void defaultWebConfig() {
0567: long t1 = System.currentTimeMillis();
0568:
0569: // Open the default web.xml file, if it exists
0570: if (defaultWebXml == null && context instanceof StandardContext) {
0571: defaultWebXml = ((StandardContext) context)
0572: .getDefaultWebXml();
0573: }
0574: // set the default if we don't have any overrides
0575: if (defaultWebXml == null)
0576: getDefaultWebXml();
0577:
0578: File file = new File(this .defaultWebXml);
0579: if (!file.isAbsolute()) {
0580: file = new File(getBaseDir(), this .defaultWebXml);
0581: }
0582:
0583: InputStream stream = null;
0584: InputSource source = null;
0585:
0586: try {
0587: if (!file.exists()) {
0588: // Use getResource and getResourceAsStream
0589: stream = getClass().getClassLoader()
0590: .getResourceAsStream(defaultWebXml);
0591: if (stream != null) {
0592: source = new InputSource(getClass()
0593: .getClassLoader()
0594: .getResource(defaultWebXml).toString());
0595: }
0596: if (stream == null) {
0597: // maybe embedded
0598: stream = getClass().getClassLoader()
0599: .getResourceAsStream("web-embed.xml");
0600: if (stream != null) {
0601: source = new InputSource(getClass()
0602: .getClassLoader().getResource(
0603: "web-embed.xml").toString());
0604: }
0605: }
0606:
0607: if (stream == null) {
0608: log.info("No default web.xml");
0609: }
0610: } else {
0611: source = new InputSource("file://"
0612: + file.getAbsolutePath());
0613: stream = new FileInputStream(file);
0614: context.addWatchedResource(file.getAbsolutePath());
0615: }
0616: } catch (Exception e) {
0617: log.error(sm.getString("contextConfig.defaultMissing")
0618: + " " + defaultWebXml + " " + file, e);
0619: }
0620:
0621: if (webDigester == null) {
0622: webDigester = createWebDigester();
0623: }
0624:
0625: if (stream != null) {
0626: processDefaultWebConfig(webDigester, stream, source);
0627: webRuleSet.recycle();
0628: }
0629:
0630: long t2 = System.currentTimeMillis();
0631: if ((t2 - t1) > 200)
0632: log.debug("Processed default web.xml " + file + " "
0633: + (t2 - t1));
0634:
0635: stream = null;
0636: source = null;
0637:
0638: String resourceName = getHostConfigPath(Constants.HostWebXml);
0639: file = new File(getConfigBase(), resourceName);
0640:
0641: try {
0642: if (!file.exists()) {
0643: // Use getResource and getResourceAsStream
0644: stream = getClass().getClassLoader()
0645: .getResourceAsStream(resourceName);
0646: if (stream != null) {
0647: source = new InputSource(getClass()
0648: .getClassLoader().getResource(resourceName)
0649: .toString());
0650: }
0651: } else {
0652: source = new InputSource("file://"
0653: + file.getAbsolutePath());
0654: stream = new FileInputStream(file);
0655: }
0656: } catch (Exception e) {
0657: log.error(sm.getString("contextConfig.defaultMissing")
0658: + " " + resourceName + " " + file, e);
0659: }
0660:
0661: if (stream != null) {
0662: processDefaultWebConfig(webDigester, stream, source);
0663: webRuleSet.recycle();
0664: }
0665:
0666: }
0667:
0668: /**
0669: * Process a default web.xml.
0670: */
0671: protected void processDefaultWebConfig(Digester digester,
0672: InputStream stream, InputSource source) {
0673:
0674: if (log.isDebugEnabled())
0675: log.debug("Processing context [" + context.getName()
0676: + "] web configuration resource "
0677: + source.getSystemId());
0678:
0679: // Process the default web.xml file
0680: synchronized (digester) {
0681: try {
0682: source.setByteStream(stream);
0683:
0684: if (context instanceof StandardContext)
0685: ((StandardContext) context)
0686: .setReplaceWelcomeFiles(true);
0687: digester.setClassLoader(this .getClass()
0688: .getClassLoader());
0689: digester.setUseContextClassLoader(false);
0690: digester.push(context);
0691: digester.setErrorHandler(new ContextErrorHandler());
0692: digester.parse(source);
0693: if (parseException != null) {
0694: ok = false;
0695: }
0696: } catch (SAXParseException e) {
0697: log
0698: .error(
0699: sm
0700: .getString("contextConfig.defaultParse"),
0701: e);
0702: log.error(sm.getString("contextConfig.defaultPosition",
0703: "" + e.getLineNumber(), ""
0704: + e.getColumnNumber()));
0705: ok = false;
0706: } catch (Exception e) {
0707: log
0708: .error(
0709: sm
0710: .getString("contextConfig.defaultParse"),
0711: e);
0712: ok = false;
0713: } finally {
0714: digester.reset();
0715: parseException = null;
0716: try {
0717: if (stream != null) {
0718: stream.close();
0719: }
0720: } catch (IOException e) {
0721: log
0722: .error(
0723: sm
0724: .getString("contextConfig.defaultClose"),
0725: e);
0726: }
0727: }
0728: }
0729: }
0730:
0731: /**
0732: * Process the default configuration file, if it exists.
0733: */
0734: protected void contextConfig() {
0735:
0736: // Open the default web.xml file, if it exists
0737: if (defaultContextXml == null
0738: && context instanceof StandardContext) {
0739: defaultContextXml = ((StandardContext) context)
0740: .getDefaultContextXml();
0741: }
0742: // set the default if we don't have any overrides
0743: if (defaultContextXml == null)
0744: getDefaultContextXml();
0745:
0746: if (!context.getOverride()) {
0747: processContextConfig(new File(getBaseDir()),
0748: defaultContextXml);
0749: processContextConfig(getConfigBase(),
0750: getHostConfigPath(Constants.HostContextXml));
0751: }
0752: if (context.getConfigFile() != null)
0753: processContextConfig(new File(context.getConfigFile()),
0754: null);
0755:
0756: }
0757:
0758: /**
0759: * Process a context.xml.
0760: */
0761: protected void processContextConfig(File baseDir,
0762: String resourceName) {
0763:
0764: if (log.isDebugEnabled())
0765: log.debug("Processing context [" + context.getName()
0766: + "] configuration file " + baseDir + " "
0767: + resourceName);
0768:
0769: InputSource source = null;
0770: InputStream stream = null;
0771:
0772: File file = baseDir;
0773: if (resourceName != null) {
0774: file = new File(baseDir, resourceName);
0775: }
0776:
0777: try {
0778: if (!file.exists()) {
0779: if (resourceName != null) {
0780: // Use getResource and getResourceAsStream
0781: stream = getClass().getClassLoader()
0782: .getResourceAsStream(resourceName);
0783: if (stream != null) {
0784: source = new InputSource(getClass()
0785: .getClassLoader().getResource(
0786: resourceName).toString());
0787: }
0788: }
0789: } else {
0790: source = new InputSource("file://"
0791: + file.getAbsolutePath());
0792: stream = new FileInputStream(file);
0793: // Add as watched resource so that cascade reload occurs if a default
0794: // config file is modified/added/removed
0795: context.addWatchedResource(file.getAbsolutePath());
0796: }
0797: } catch (Exception e) {
0798: log.error(sm.getString("contextConfig.contextMissing",
0799: resourceName + " " + file), e);
0800: }
0801:
0802: if (source == null)
0803: return;
0804: if (contextDigester == null) {
0805: contextDigester = createContextDigester();
0806: }
0807: synchronized (contextDigester) {
0808: try {
0809: source.setByteStream(stream);
0810: contextDigester.setClassLoader(this .getClass()
0811: .getClassLoader());
0812: contextDigester.setUseContextClassLoader(false);
0813: contextDigester.push(context.getParent());
0814: contextDigester.push(context);
0815: contextDigester
0816: .setErrorHandler(new ContextErrorHandler());
0817: contextDigester.parse(source);
0818: if (parseException != null) {
0819: ok = false;
0820: }
0821: if (log.isDebugEnabled())
0822: log.debug("Successfully processed context ["
0823: + context.getName()
0824: + "] configuration file " + baseDir + " "
0825: + resourceName);
0826: } catch (SAXParseException e) {
0827: log.error(sm.getString("contextConfig.contextParse",
0828: context.getName()), e);
0829: log.error(sm.getString("contextConfig.defaultPosition",
0830: "" + e.getLineNumber(), ""
0831: + e.getColumnNumber()));
0832: ok = false;
0833: } catch (Exception e) {
0834: log.error(sm.getString("contextConfig.contextParse",
0835: context.getName()), e);
0836: ok = false;
0837: } finally {
0838: contextDigester.reset();
0839: parseException = null;
0840: try {
0841: if (stream != null) {
0842: stream.close();
0843: }
0844: } catch (IOException e) {
0845: log
0846: .error(
0847: sm
0848: .getString("contextConfig.contextClose"),
0849: e);
0850: }
0851: }
0852: }
0853: }
0854:
0855: /**
0856: * Adjust docBase.
0857: */
0858: protected void fixDocBase() throws IOException {
0859:
0860: Host host = (Host) context.getParent();
0861: String appBase = host.getAppBase();
0862:
0863: boolean unpackWARs = true;
0864: if (host instanceof StandardHost) {
0865: unpackWARs = ((StandardHost) host).isUnpackWARs()
0866: && ((StandardContext) context).getUnpackWAR();
0867: }
0868:
0869: File canonicalAppBase = new File(appBase);
0870: if (canonicalAppBase.isAbsolute()) {
0871: canonicalAppBase = canonicalAppBase.getCanonicalFile();
0872: } else {
0873: canonicalAppBase = new File(System
0874: .getProperty("catalina.base"), appBase)
0875: .getCanonicalFile();
0876: }
0877:
0878: String docBase = context.getDocBase();
0879: if (docBase == null) {
0880: // Trying to guess the docBase according to the path
0881: String path = context.getPath();
0882: if (path == null) {
0883: return;
0884: }
0885: if (path.equals("")) {
0886: docBase = "ROOT";
0887: } else {
0888: if (path.startsWith("/")) {
0889: docBase = path.substring(1);
0890: } else {
0891: docBase = path;
0892: }
0893: }
0894: }
0895:
0896: File file = new File(docBase);
0897: if (!file.isAbsolute()) {
0898: docBase = (new File(canonicalAppBase, docBase)).getPath();
0899: } else {
0900: docBase = file.getCanonicalPath();
0901: }
0902: file = new File(docBase);
0903: String origDocBase = docBase;
0904:
0905: String contextPath = context.getPath();
0906: if (contextPath.equals("")) {
0907: contextPath = "ROOT";
0908: }
0909: if (docBase.toLowerCase().endsWith(".war")
0910: && !file.isDirectory() && unpackWARs) {
0911: URL war = new URL("jar:" + (new File(docBase)).toURL()
0912: + "!/");
0913: docBase = ExpandWar.expand(host, war, contextPath);
0914: file = new File(docBase);
0915: docBase = file.getCanonicalPath();
0916: if (context instanceof StandardContext) {
0917: ((StandardContext) context)
0918: .setOriginalDocBase(origDocBase);
0919: }
0920: } else {
0921: File docDir = new File(docBase);
0922: if (!docDir.exists()) {
0923: File warFile = new File(docBase + ".war");
0924: if (warFile.exists()) {
0925: if (unpackWARs) {
0926: URL war = new URL("jar:" + warFile.toURL()
0927: + "!/");
0928: docBase = ExpandWar.expand(host, war,
0929: contextPath);
0930: file = new File(docBase);
0931: docBase = file.getCanonicalPath();
0932: } else {
0933: docBase = warFile.getCanonicalPath();
0934: }
0935: }
0936: if (context instanceof StandardContext) {
0937: ((StandardContext) context)
0938: .setOriginalDocBase(origDocBase);
0939: }
0940: }
0941: }
0942:
0943: if (docBase.startsWith(canonicalAppBase.getPath())) {
0944: docBase = docBase.substring(canonicalAppBase.getPath()
0945: .length());
0946: docBase = docBase.replace(File.separatorChar, '/');
0947: if (docBase.startsWith("/")) {
0948: docBase = docBase.substring(1);
0949: }
0950: } else {
0951: docBase = docBase.replace(File.separatorChar, '/');
0952: }
0953:
0954: context.setDocBase(docBase);
0955:
0956: }
0957:
0958: protected void antiLocking() throws IOException {
0959:
0960: if ((context instanceof StandardContext)
0961: && ((StandardContext) context).getAntiResourceLocking()) {
0962:
0963: Host host = (Host) context.getParent();
0964: String appBase = host.getAppBase();
0965: String docBase = context.getDocBase();
0966: if (docBase == null)
0967: return;
0968: if (originalDocBase == null) {
0969: originalDocBase = docBase;
0970: } else {
0971: docBase = originalDocBase;
0972: }
0973: File docBaseFile = new File(docBase);
0974: if (!docBaseFile.isAbsolute()) {
0975: File file = new File(appBase);
0976: if (!file.isAbsolute()) {
0977: file = new File(
0978: System.getProperty("catalina.base"),
0979: appBase);
0980: }
0981: docBaseFile = new File(file, docBase);
0982: }
0983:
0984: String path = context.getPath();
0985: if (path == null) {
0986: return;
0987: }
0988: if (path.equals("")) {
0989: docBase = "ROOT";
0990: } else {
0991: if (path.startsWith("/")) {
0992: docBase = path.substring(1);
0993: } else {
0994: docBase = path;
0995: }
0996: }
0997:
0998: File file = null;
0999: if (docBase.toLowerCase().endsWith(".war")) {
1000: file = new File(System.getProperty("java.io.tmpdir"),
1001: deploymentCount++ + "-" + docBase + ".war");
1002: } else {
1003: file = new File(System.getProperty("java.io.tmpdir"),
1004: deploymentCount++ + "-" + docBase);
1005: }
1006:
1007: if (log.isDebugEnabled())
1008: log.debug("Anti locking context[" + context.getPath()
1009: + "] setting docBase to " + file);
1010:
1011: // Cleanup just in case an old deployment is lying around
1012: ExpandWar.delete(file);
1013: if (ExpandWar.copy(docBaseFile, file)) {
1014: context.setDocBase(file.getAbsolutePath());
1015: }
1016:
1017: }
1018:
1019: }
1020:
1021: /**
1022: * Process a "init" event for this Context.
1023: */
1024: protected void init() {
1025: // Called from StandardContext.init()
1026:
1027: if (log.isDebugEnabled())
1028: log.debug(sm.getString("contextConfig.init"));
1029: context.setConfigured(false);
1030: ok = true;
1031:
1032: contextConfig();
1033:
1034: try {
1035: fixDocBase();
1036: } catch (IOException e) {
1037: log.error(sm.getString("contextConfig.fixDocBase"), e);
1038: }
1039:
1040: }
1041:
1042: /**
1043: * Process a "before start" event for this Context.
1044: */
1045: protected synchronized void beforeStart() {
1046:
1047: try {
1048: antiLocking();
1049: } catch (IOException e) {
1050: log.error(sm.getString("contextConfig.antiLocking"), e);
1051: }
1052:
1053: }
1054:
1055: /**
1056: * Process a "start" event for this Context.
1057: */
1058: protected synchronized void start() {
1059: // Called from StandardContext.start()
1060:
1061: if (log.isDebugEnabled())
1062: log.debug(sm.getString("contextConfig.start"));
1063:
1064: // Set properties based on DefaultContext
1065: Container container = context.getParent();
1066: if (!context.getOverride()) {
1067: if (container instanceof Host) {
1068: // Reset the value only if the attribute wasn't
1069: // set on the context.
1070: xmlValidation = context.getXmlValidation();
1071: if (!xmlValidation) {
1072: xmlValidation = ((Host) container)
1073: .getXmlValidation();
1074: }
1075:
1076: xmlNamespaceAware = context.getXmlNamespaceAware();
1077: if (!xmlNamespaceAware) {
1078: xmlNamespaceAware = ((Host) container)
1079: .getXmlNamespaceAware();
1080: }
1081:
1082: container = container.getParent();
1083: }
1084: }
1085:
1086: // Process the default and application web.xml files
1087: defaultWebConfig();
1088: applicationWebConfig();
1089: if (!context.getIgnoreAnnotations()) {
1090: applicationAnnotationsConfig();
1091: }
1092: if (ok) {
1093: validateSecurityRoles();
1094: }
1095:
1096: // Configure an authenticator if we need one
1097: if (ok)
1098: authenticatorConfig();
1099:
1100: // Dump the contents of this pipeline if requested
1101: if ((log.isDebugEnabled())
1102: && (context instanceof ContainerBase)) {
1103: log.debug("Pipeline Configuration:");
1104: Pipeline pipeline = ((ContainerBase) context).getPipeline();
1105: Valve valves[] = null;
1106: if (pipeline != null)
1107: valves = pipeline.getValves();
1108: if (valves != null) {
1109: for (int i = 0; i < valves.length; i++) {
1110: log.debug(" " + valves[i].getInfo());
1111: }
1112: }
1113: log.debug("======================");
1114: }
1115:
1116: // Make our application available if no problems were encountered
1117: if (ok)
1118: context.setConfigured(true);
1119: else {
1120: log.error(sm.getString("contextConfig.unavailable"));
1121: context.setConfigured(false);
1122: }
1123:
1124: }
1125:
1126: /**
1127: * Process a "stop" event for this Context.
1128: */
1129: protected synchronized void stop() {
1130:
1131: if (log.isDebugEnabled())
1132: log.debug(sm.getString("contextConfig.stop"));
1133:
1134: int i;
1135:
1136: // Removing children
1137: Container[] children = context.findChildren();
1138: for (i = 0; i < children.length; i++) {
1139: context.removeChild(children[i]);
1140: }
1141:
1142: // Removing application parameters
1143: /*
1144: ApplicationParameter[] applicationParameters =
1145: context.findApplicationParameters();
1146: for (i = 0; i < applicationParameters.length; i++) {
1147: context.removeApplicationParameter
1148: (applicationParameters[i].getName());
1149: }
1150: */
1151:
1152: // Removing security constraints
1153: SecurityConstraint[] securityConstraints = context
1154: .findConstraints();
1155: for (i = 0; i < securityConstraints.length; i++) {
1156: context.removeConstraint(securityConstraints[i]);
1157: }
1158:
1159: // Removing Ejbs
1160: /*
1161: ContextEjb[] contextEjbs = context.findEjbs();
1162: for (i = 0; i < contextEjbs.length; i++) {
1163: context.removeEjb(contextEjbs[i].getName());
1164: }
1165: */
1166:
1167: // Removing environments
1168: /*
1169: ContextEnvironment[] contextEnvironments = context.findEnvironments();
1170: for (i = 0; i < contextEnvironments.length; i++) {
1171: context.removeEnvironment(contextEnvironments[i].getName());
1172: }
1173: */
1174:
1175: // Removing errors pages
1176: ErrorPage[] errorPages = context.findErrorPages();
1177: for (i = 0; i < errorPages.length; i++) {
1178: context.removeErrorPage(errorPages[i]);
1179: }
1180:
1181: // Removing filter defs
1182: FilterDef[] filterDefs = context.findFilterDefs();
1183: for (i = 0; i < filterDefs.length; i++) {
1184: context.removeFilterDef(filterDefs[i]);
1185: }
1186:
1187: // Removing filter maps
1188: FilterMap[] filterMaps = context.findFilterMaps();
1189: for (i = 0; i < filterMaps.length; i++) {
1190: context.removeFilterMap(filterMaps[i]);
1191: }
1192:
1193: // Removing local ejbs
1194: /*
1195: ContextLocalEjb[] contextLocalEjbs = context.findLocalEjbs();
1196: for (i = 0; i < contextLocalEjbs.length; i++) {
1197: context.removeLocalEjb(contextLocalEjbs[i].getName());
1198: }
1199: */
1200:
1201: // Removing Mime mappings
1202: String[] mimeMappings = context.findMimeMappings();
1203: for (i = 0; i < mimeMappings.length; i++) {
1204: context.removeMimeMapping(mimeMappings[i]);
1205: }
1206:
1207: // Removing parameters
1208: String[] parameters = context.findParameters();
1209: for (i = 0; i < parameters.length; i++) {
1210: context.removeParameter(parameters[i]);
1211: }
1212:
1213: // Removing resource env refs
1214: /*
1215: String[] resourceEnvRefs = context.findResourceEnvRefs();
1216: for (i = 0; i < resourceEnvRefs.length; i++) {
1217: context.removeResourceEnvRef(resourceEnvRefs[i]);
1218: }
1219: */
1220:
1221: // Removing resource links
1222: /*
1223: ContextResourceLink[] contextResourceLinks =
1224: context.findResourceLinks();
1225: for (i = 0; i < contextResourceLinks.length; i++) {
1226: context.removeResourceLink(contextResourceLinks[i].getName());
1227: }
1228: */
1229:
1230: // Removing resources
1231: /*
1232: ContextResource[] contextResources = context.findResources();
1233: for (i = 0; i < contextResources.length; i++) {
1234: context.removeResource(contextResources[i].getName());
1235: }
1236: */
1237:
1238: // Removing sercurity role
1239: String[] securityRoles = context.findSecurityRoles();
1240: for (i = 0; i < securityRoles.length; i++) {
1241: context.removeSecurityRole(securityRoles[i]);
1242: }
1243:
1244: // Removing servlet mappings
1245: String[] servletMappings = context.findServletMappings();
1246: for (i = 0; i < servletMappings.length; i++) {
1247: context.removeServletMapping(servletMappings[i]);
1248: }
1249:
1250: // FIXME : Removing status pages
1251:
1252: // Removing taglibs
1253: String[] taglibs = context.findTaglibs();
1254: for (i = 0; i < taglibs.length; i++) {
1255: context.removeTaglib(taglibs[i]);
1256: }
1257:
1258: // Removing welcome files
1259: String[] welcomeFiles = context.findWelcomeFiles();
1260: for (i = 0; i < welcomeFiles.length; i++) {
1261: context.removeWelcomeFile(welcomeFiles[i]);
1262: }
1263:
1264: // Removing wrapper lifecycles
1265: String[] wrapperLifecycles = context.findWrapperLifecycles();
1266: for (i = 0; i < wrapperLifecycles.length; i++) {
1267: context.removeWrapperLifecycle(wrapperLifecycles[i]);
1268: }
1269:
1270: // Removing wrapper listeners
1271: String[] wrapperListeners = context.findWrapperListeners();
1272: for (i = 0; i < wrapperListeners.length; i++) {
1273: context.removeWrapperListener(wrapperListeners[i]);
1274: }
1275:
1276: // Remove (partially) folders and files created by antiLocking
1277: Host host = (Host) context.getParent();
1278: String appBase = host.getAppBase();
1279: String docBase = context.getDocBase();
1280: if ((docBase != null) && (originalDocBase != null)) {
1281: File docBaseFile = new File(docBase);
1282: if (!docBaseFile.isAbsolute()) {
1283: docBaseFile = new File(appBase, docBase);
1284: }
1285: ExpandWar.delete(docBaseFile);
1286: }
1287:
1288: ok = true;
1289:
1290: }
1291:
1292: /**
1293: * Process a "destroy" event for this Context.
1294: */
1295: protected synchronized void destroy() {
1296: // Called from StandardContext.destroy()
1297: if (log.isDebugEnabled())
1298: log.debug(sm.getString("contextConfig.destroy"));
1299:
1300: // Changed to getWorkPath per Bugzilla 35819.
1301: String workDir = ((StandardContext) context).getWorkPath();
1302: if (workDir != null)
1303: ExpandWar.delete(new File(workDir));
1304: }
1305:
1306: /**
1307: * Validate the usage of security role names in the web application
1308: * deployment descriptor. If any problems are found, issue warning
1309: * messages (for backwards compatibility) and add the missing roles.
1310: * (To make these problems fatal instead, simply set the <code>ok</code>
1311: * instance variable to <code>false</code> as well).
1312: */
1313: protected void validateSecurityRoles() {
1314:
1315: // Check role names used in <security-constraint> elements
1316: SecurityConstraint constraints[] = context.findConstraints();
1317: for (int i = 0; i < constraints.length; i++) {
1318: String roles[] = constraints[i].findAuthRoles();
1319: for (int j = 0; j < roles.length; j++) {
1320: if (!"*".equals(roles[j])
1321: && !context.findSecurityRole(roles[j])) {
1322: log.info(sm.getString("contextConfig.role.auth",
1323: roles[j]));
1324: context.addSecurityRole(roles[j]);
1325: }
1326: }
1327: }
1328:
1329: // Check role names used in <servlet> elements
1330: Container wrappers[] = context.findChildren();
1331: for (int i = 0; i < wrappers.length; i++) {
1332: Wrapper wrapper = (Wrapper) wrappers[i];
1333: String runAs = wrapper.getRunAs();
1334: if ((runAs != null) && !context.findSecurityRole(runAs)) {
1335: log.info(sm
1336: .getString("contextConfig.role.runas", runAs));
1337: context.addSecurityRole(runAs);
1338: }
1339: String names[] = wrapper.findSecurityReferences();
1340: for (int j = 0; j < names.length; j++) {
1341: String link = wrapper.findSecurityReference(names[j]);
1342: if ((link != null) && !context.findSecurityRole(link)) {
1343: log.info(sm.getString("contextConfig.role.link",
1344: link));
1345: context.addSecurityRole(link);
1346: }
1347: }
1348: }
1349:
1350: }
1351:
1352: /**
1353: * Get config base.
1354: */
1355: protected File getConfigBase() {
1356: File configBase = new File(System.getProperty("catalina.base"),
1357: "conf");
1358: if (!configBase.exists()) {
1359: return null;
1360: } else {
1361: return configBase;
1362: }
1363: }
1364:
1365: protected String getHostConfigPath(String resourceName) {
1366: StringBuffer result = new StringBuffer();
1367: Container container = context;
1368: Container host = null;
1369: Container engine = null;
1370: while (container != null) {
1371: if (container instanceof Host)
1372: host = container;
1373: if (container instanceof Engine)
1374: engine = container;
1375: container = container.getParent();
1376: }
1377: if (engine != null) {
1378: result.append(engine.getName()).append('/');
1379: }
1380: if (host != null) {
1381: result.append(host.getName()).append('/');
1382: }
1383: result.append(resourceName);
1384: return result.toString();
1385: }
1386:
1387: protected class ContextErrorHandler implements ErrorHandler {
1388:
1389: public void error(SAXParseException exception) {
1390: parseException = exception;
1391: }
1392:
1393: public void fatalError(SAXParseException exception) {
1394: parseException = exception;
1395: }
1396:
1397: public void warning(SAXParseException exception) {
1398: parseException = exception;
1399: }
1400:
1401: }
1402:
1403: }
|