0001: /*
0002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/ContextConfig.java,v 1.66 2002/06/23 20:35:30 remm Exp $
0003: * $Revision: 1.66 $
0004: * $Date: 2002/06/23 20:35:30 $
0005: *
0006: * ====================================================================
0007: *
0008: * The Apache Software License, Version 1.1
0009: *
0010: * Copyright (c) 1999-2001 The Apache Software Foundation. All rights
0011: * reserved.
0012: *
0013: * Redistribution and use in source and binary forms, with or without
0014: * modification, are permitted provided that the following conditions
0015: * are met:
0016: *
0017: * 1. Redistributions of source code must retain the above copyright
0018: * notice, this list of conditions and the following disclaimer.
0019: *
0020: * 2. Redistributions in binary form must reproduce the above copyright
0021: * notice, this list of conditions and the following disclaimer in
0022: * the documentation and/or other materials provided with the
0023: * distribution.
0024: *
0025: * 3. The end-user documentation included with the redistribution, if
0026: * any, must include the following acknowlegement:
0027: * "This product includes software developed by the
0028: * Apache Software Foundation (http://www.apache.org/)."
0029: * Alternately, this acknowlegement may appear in the software itself,
0030: * if and wherever such third-party acknowlegements normally appear.
0031: *
0032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0033: * Foundation" must not be used to endorse or promote products derived
0034: * from this software without prior written permission. For written
0035: * permission, please contact apache@apache.org.
0036: *
0037: * 5. Products derived from this software may not be called "Apache"
0038: * nor may "Apache" appear in their names without prior written
0039: * permission of the Apache Group.
0040: *
0041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0052: * SUCH DAMAGE.
0053: * ====================================================================
0054: *
0055: * This software consists of voluntary contributions made by many
0056: * individuals on behalf of the Apache Software Foundation. For more
0057: * information on the Apache Software Foundation, please see
0058: * <http://www.apache.org/>.
0059: *
0060: * [Additional notices, if required by prior licensing conditions]
0061: *
0062: */
0063:
0064: package org.apache.catalina.startup;
0065:
0066: import java.io.File;
0067: import java.io.FileInputStream;
0068: import java.io.FileNotFoundException;
0069: import java.io.InputStream;
0070: import java.io.IOException;
0071: import java.lang.reflect.InvocationTargetException;
0072: import java.lang.reflect.Method;
0073: import java.net.JarURLConnection;
0074: import java.net.MalformedURLException;
0075: import java.net.URL;
0076: import java.util.ArrayList;
0077: import java.util.Enumeration;
0078: import java.util.HashSet;
0079: import java.util.Iterator;
0080: import java.util.MissingResourceException;
0081: import java.util.ResourceBundle;
0082: import java.util.Set;
0083: import java.util.Stack;
0084: import java.util.jar.JarEntry;
0085: import java.util.jar.JarFile;
0086: import javax.naming.NamingException;
0087: import javax.naming.NameClassPair;
0088: import javax.naming.NamingEnumeration;
0089: import javax.naming.directory.DirContext;
0090: import javax.servlet.ServletContext;
0091: import javax.servlet.ServletException;
0092: import org.apache.catalina.Authenticator;
0093: import org.apache.catalina.Connector;
0094: import org.apache.catalina.Container;
0095: import org.apache.catalina.Context;
0096: import org.apache.catalina.DefaultContext;
0097: import org.apache.catalina.Engine;
0098: import org.apache.catalina.Globals;
0099: import org.apache.catalina.Host;
0100: import org.apache.catalina.Lifecycle;
0101: import org.apache.catalina.LifecycleEvent;
0102: import org.apache.catalina.LifecycleListener;
0103: import org.apache.catalina.Logger;
0104: import org.apache.catalina.Pipeline;
0105: import org.apache.catalina.Service;
0106: import org.apache.catalina.Valve;
0107: import org.apache.catalina.Wrapper;
0108: import org.apache.catalina.core.ContainerBase;
0109: import org.apache.catalina.core.StandardContext;
0110: import org.apache.catalina.deploy.ApplicationParameter;
0111: import org.apache.catalina.deploy.ContextEjb;
0112: import org.apache.catalina.deploy.ContextEnvironment;
0113: import org.apache.catalina.deploy.ContextLocalEjb;
0114: import org.apache.catalina.deploy.ContextResource;
0115: import org.apache.catalina.deploy.ContextResourceLink;
0116: import org.apache.catalina.deploy.ErrorPage;
0117: import org.apache.catalina.deploy.FilterDef;
0118: import org.apache.catalina.deploy.FilterMap;
0119: import org.apache.catalina.deploy.LoginConfig;
0120: import org.apache.catalina.deploy.SecurityConstraint;
0121: import org.apache.catalina.loader.Extension;
0122: import org.apache.catalina.util.StringManager;
0123: import org.apache.catalina.valves.ValveBase;
0124: import org.apache.commons.digester.Digester;
0125: import org.xml.sax.InputSource;
0126: import org.xml.sax.SAXParseException;
0127:
0128: /**
0129: * Startup event listener for a <b>Context</b> that configures the properties
0130: * of that Context, and the associated defined servlets.
0131: *
0132: * @author Craig R. McClanahan
0133: * @version $Revision: 1.66 $ $Date: 2002/06/23 20:35:30 $
0134: */
0135:
0136: public final class ContextConfig implements LifecycleListener {
0137:
0138: // ----------------------------------------------------- Instance Variables
0139:
0140: /**
0141: * The set of Authenticators that we know how to configure. The key is
0142: * the name of the implemented authentication method, and the value is
0143: * the fully qualified Java class name of the corresponding Valve.
0144: */
0145: private static ResourceBundle authenticators = null;
0146:
0147: /**
0148: * The Context we are associated with.
0149: */
0150: private Context context = null;
0151:
0152: /**
0153: * The debugging detail level for this component.
0154: */
0155: private int debug = 0;
0156:
0157: /**
0158: * Track any fatal errors during startup configuration processing.
0159: */
0160: private boolean ok = false;
0161:
0162: /**
0163: * The string resources for this package.
0164: */
0165: private static final StringManager sm = StringManager
0166: .getManager(Constants.Package);
0167:
0168: /**
0169: * The <code>Digester</code> we will use to process tag library
0170: * descriptor files.
0171: */
0172: private static Digester tldDigester = createTldDigester();
0173:
0174: /**
0175: * The <code>Digester</code> we will use to process web application
0176: * deployment descriptor files.
0177: */
0178: private static Digester webDigester = createWebDigester();
0179:
0180: // ------------------------------------------------------------- Properties
0181:
0182: /**
0183: * Return the debugging detail level for this component.
0184: */
0185: public int getDebug() {
0186:
0187: return (this .debug);
0188:
0189: }
0190:
0191: /**
0192: * Set the debugging detail level for this component.
0193: *
0194: * @param debug The new debugging detail level
0195: */
0196: public void setDebug(int debug) {
0197:
0198: this .debug = debug;
0199:
0200: }
0201:
0202: // --------------------------------------------------------- Public Methods
0203:
0204: /**
0205: * Process the START event for an associated Context.
0206: *
0207: * @param event The lifecycle event that has occurred
0208: */
0209: public void lifecycleEvent(LifecycleEvent event) {
0210:
0211: // Identify the context we are associated with
0212: try {
0213: context = (Context) event.getLifecycle();
0214: if (context instanceof StandardContext) {
0215: int contextDebug = ((StandardContext) context)
0216: .getDebug();
0217: if (contextDebug > this .debug)
0218: this .debug = contextDebug;
0219: }
0220: } catch (ClassCastException e) {
0221: log(
0222: sm.getString("contextConfig.cce", event
0223: .getLifecycle()), e);
0224: return;
0225: }
0226:
0227: // Process the event that has occurred
0228: if (event.getType().equals(Lifecycle.START_EVENT))
0229: start();
0230: else if (event.getType().equals(Lifecycle.STOP_EVENT))
0231: stop();
0232:
0233: }
0234:
0235: // -------------------------------------------------------- Private Methods
0236:
0237: /**
0238: * Process the application configuration file, if it exists.
0239: */
0240: private void applicationConfig() {
0241:
0242: // Open the application web.xml file, if it exists
0243: InputStream stream = null;
0244: ServletContext servletContext = context.getServletContext();
0245: if (servletContext != null)
0246: stream = servletContext
0247: .getResourceAsStream(Constants.ApplicationWebXml);
0248: if (stream == null) {
0249: log(sm.getString("contextConfig.applicationMissing"));
0250: return;
0251: }
0252:
0253: // Process the application web.xml file
0254: synchronized (webDigester) {
0255: try {
0256: URL url = servletContext
0257: .getResource(Constants.ApplicationWebXml);
0258: InputSource is = new InputSource(url.toExternalForm());
0259: is.setByteStream(stream);
0260: webDigester.setDebug(getDebug());
0261: if (context instanceof StandardContext) {
0262: ((StandardContext) context)
0263: .setReplaceWelcomeFiles(true);
0264: }
0265: webDigester.clear();
0266: webDigester.push(context);
0267: webDigester.parse(is);
0268: } catch (SAXParseException e) {
0269: log(sm.getString("contextConfig.applicationParse"), e);
0270: log(sm.getString("contextConfig.applicationPosition",
0271: "" + e.getLineNumber(), ""
0272: + e.getColumnNumber()));
0273: ok = false;
0274: } catch (Exception e) {
0275: log(sm.getString("contextConfig.applicationParse"), e);
0276: ok = false;
0277: } finally {
0278: try {
0279: if (stream != null) {
0280: stream.close();
0281: }
0282: } catch (IOException e) {
0283: log(sm.getString("contextConfig.applicationClose"),
0284: e);
0285: }
0286: }
0287: }
0288:
0289: }
0290:
0291: /**
0292: * Set up an Authenticator automatically if required, and one has not
0293: * already been configured.
0294: */
0295: private synchronized void authenticatorConfig() {
0296:
0297: // Does this Context require an Authenticator?
0298: SecurityConstraint constraints[] = context.findConstraints();
0299: if ((constraints == null) || (constraints.length == 0))
0300: return;
0301: LoginConfig loginConfig = context.getLoginConfig();
0302: if (loginConfig == null) {
0303: loginConfig = new LoginConfig("NONE", null, null, null);
0304: context.setLoginConfig(loginConfig);
0305: }
0306:
0307: // Has an authenticator been configured already?
0308: if (context instanceof Authenticator)
0309: return;
0310: if (context instanceof ContainerBase) {
0311: Pipeline pipeline = ((ContainerBase) context).getPipeline();
0312: if (pipeline != null) {
0313: Valve basic = pipeline.getBasic();
0314: if ((basic != null) && (basic instanceof Authenticator))
0315: return;
0316: Valve valves[] = pipeline.getValves();
0317: for (int i = 0; i < valves.length; i++) {
0318: if (valves[i] instanceof Authenticator)
0319: return;
0320: }
0321: }
0322: } else {
0323: return; // Cannot install a Valve even if it would be needed
0324: }
0325:
0326: // Has a Realm been configured for us to authenticate against?
0327: if (context.getRealm() == null) {
0328: log(sm.getString("contextConfig.missingRealm"));
0329: ok = false;
0330: return;
0331: }
0332:
0333: // Load our mapping properties if necessary
0334: if (authenticators == null) {
0335: try {
0336: authenticators = ResourceBundle
0337: .getBundle("org.apache.catalina.startup.Authenticators");
0338: } catch (MissingResourceException e) {
0339: log(
0340: sm
0341: .getString("contextConfig.authenticatorResources"),
0342: e);
0343: ok = false;
0344: return;
0345: }
0346: }
0347:
0348: // Identify the class name of the Valve we should configure
0349: String authenticatorName = null;
0350: try {
0351: authenticatorName = authenticators.getString(loginConfig
0352: .getAuthMethod());
0353: } catch (MissingResourceException e) {
0354: authenticatorName = null;
0355: }
0356: if (authenticatorName == null) {
0357: log(sm.getString("contextConfig.authenticatorMissing",
0358: loginConfig.getAuthMethod()));
0359: ok = false;
0360: return;
0361: }
0362:
0363: // Instantiate and install an Authenticator of the requested class
0364: Valve authenticator = null;
0365: try {
0366: Class authenticatorClass = Class.forName(authenticatorName);
0367: authenticator = (Valve) authenticatorClass.newInstance();
0368: if (context instanceof ContainerBase) {
0369: Pipeline pipeline = ((ContainerBase) context)
0370: .getPipeline();
0371: if (pipeline != null) {
0372: ((ContainerBase) context).addValve(authenticator);
0373: log(sm.getString(
0374: "contextConfig.authenticatorConfigured",
0375: loginConfig.getAuthMethod()));
0376: }
0377: }
0378: } catch (Throwable t) {
0379: log(sm.getString("contextConfig.authenticatorInstantiate",
0380: authenticatorName), t);
0381: ok = false;
0382: }
0383:
0384: }
0385:
0386: /**
0387: * Create and deploy a Valve to expose the SSL certificates presented
0388: * by this client, if any. If we cannot instantiate such a Valve
0389: * (because the JSSE classes are not available), silently continue.
0390: * This is only instantiated for those Contexts being served by
0391: * a Connector with secure set to true.
0392: */
0393: private void certificatesConfig() {
0394:
0395: // Only install this valve if there is a Connector installed
0396: // which has secure set to true.
0397: boolean secure = false;
0398: Container container = context.getParent();
0399: if (container instanceof Host) {
0400: container = container.getParent();
0401: }
0402: if (container instanceof Engine) {
0403: Service service = ((Engine) container).getService();
0404: // The service can be null when Tomcat is run in embedded mode
0405: if (service == null) {
0406: secure = true;
0407: } else {
0408: Connector[] connectors = service.findConnectors();
0409: for (int i = 0; i < connectors.length; i++) {
0410: secure = connectors[i].getSecure();
0411: if (secure) {
0412: break;
0413: }
0414: }
0415: }
0416: }
0417: if (!secure) {
0418: return;
0419: }
0420:
0421: // Validate that the JSSE classes are present
0422: try {
0423: Class clazz = this .getClass().getClassLoader().loadClass(
0424: "javax.net.ssl.SSLSocket");
0425: if (clazz == null)
0426: return;
0427: } catch (Throwable t) {
0428: return;
0429: }
0430:
0431: // Instantiate a new CertificatesValve if possible
0432: Valve certificates = null;
0433: try {
0434: Class clazz = Class
0435: .forName("org.apache.catalina.valves.CertificatesValve");
0436: certificates = (Valve) clazz.newInstance();
0437: } catch (Throwable t) {
0438: return; // Probably JSSE classes not present
0439: }
0440:
0441: // Add this Valve to our Pipeline
0442: try {
0443: if (context instanceof ContainerBase) {
0444: Pipeline pipeline = ((ContainerBase) context)
0445: .getPipeline();
0446: if (pipeline != null) {
0447: ((ContainerBase) context).addValve(certificates);
0448: log(sm
0449: .getString("contextConfig.certificatesConfig.added"));
0450: }
0451: }
0452: } catch (Throwable t) {
0453: log(sm.getString("contextConfig.certificatesConfig.error"),
0454: t);
0455: ok = false;
0456: }
0457:
0458: }
0459:
0460: /**
0461: * Create (if necessary) and return a Digester configured to process a tag
0462: * library descriptor, looking for additional listener classes to be
0463: * registered.
0464: */
0465: private static Digester createTldDigester() {
0466:
0467: URL url = null;
0468: Digester tldDigester = new Digester();
0469: tldDigester.setValidating(true);
0470: url = ContextConfig.class
0471: .getResource(Constants.TldDtdResourcePath_11);
0472: tldDigester.register(Constants.TldDtdPublicId_11, url
0473: .toString());
0474: url = ContextConfig.class
0475: .getResource(Constants.TldDtdResourcePath_12);
0476: tldDigester.register(Constants.TldDtdPublicId_12, url
0477: .toString());
0478: tldDigester.addRuleSet(new TldRuleSet());
0479: return (tldDigester);
0480:
0481: }
0482:
0483: /**
0484: * Create (if necessary) and return a Digester configured to process the
0485: * web application deployment descriptor (web.xml).
0486: */
0487: private static Digester createWebDigester() {
0488:
0489: URL url = null;
0490: Digester webDigester = new Digester();
0491: webDigester.setValidating(true);
0492: url = ContextConfig.class
0493: .getResource(Constants.WebDtdResourcePath_22);
0494: webDigester.register(Constants.WebDtdPublicId_22, url
0495: .toString());
0496: url = ContextConfig.class
0497: .getResource(Constants.WebDtdResourcePath_23);
0498: webDigester.register(Constants.WebDtdPublicId_23, url
0499: .toString());
0500: webDigester.addRuleSet(new WebRuleSet());
0501: return (webDigester);
0502:
0503: }
0504:
0505: /**
0506: * Process the default configuration file, if it exists.
0507: */
0508: private void defaultConfig() {
0509:
0510: // Open the default web.xml file, if it exists
0511: File file = new File(Constants.DefaultWebXml);
0512: if (!file.isAbsolute())
0513: file = new File(System.getProperty("catalina.base"),
0514: Constants.DefaultWebXml);
0515: FileInputStream stream = null;
0516: try {
0517: stream = new FileInputStream(file.getCanonicalPath());
0518: stream.close();
0519: stream = null;
0520: } catch (FileNotFoundException e) {
0521: log(sm.getString("contextConfig.defaultMissing"));
0522: return;
0523: } catch (IOException e) {
0524: log(sm.getString("contextConfig.defaultMissing"), e);
0525: return;
0526: }
0527:
0528: // Process the default web.xml file
0529: synchronized (webDigester) {
0530: try {
0531: InputSource is = new InputSource("file://"
0532: + file.getAbsolutePath());
0533: stream = new FileInputStream(file);
0534: is.setByteStream(stream);
0535: webDigester.setDebug(getDebug());
0536: if (context instanceof StandardContext)
0537: ((StandardContext) context)
0538: .setReplaceWelcomeFiles(true);
0539: webDigester.clear();
0540: webDigester.push(context);
0541: webDigester.parse(is);
0542: } catch (SAXParseException e) {
0543: log(sm.getString("contextConfig.defaultParse"), e);
0544: log(sm.getString("contextConfig.defaultPosition", ""
0545: + e.getLineNumber(), "" + e.getColumnNumber()));
0546: ok = false;
0547: } catch (Exception e) {
0548: log(sm.getString("contextConfig.defaultParse"), e);
0549: ok = false;
0550: } finally {
0551: try {
0552: if (stream != null) {
0553: stream.close();
0554: }
0555: } catch (IOException e) {
0556: log(sm.getString("contextConfig.defaultClose"), e);
0557: }
0558: }
0559: }
0560:
0561: }
0562:
0563: /**
0564: * Log a message on the Logger associated with our Context (if any)
0565: *
0566: * @param message Message to be logged
0567: */
0568: private void log(String message) {
0569:
0570: Logger logger = null;
0571: if (context != null)
0572: logger = context.getLogger();
0573: if (logger != null)
0574: logger.log("ContextConfig[" + context.getName() + "]: "
0575: + message);
0576: else
0577: System.out.println("ContextConfig[" + context.getName()
0578: + "]: " + message);
0579:
0580: }
0581:
0582: /**
0583: * Log a message on the Logger associated with our Context (if any)
0584: *
0585: * @param message Message to be logged
0586: * @param throwable Associated exception
0587: */
0588: private void log(String message, Throwable throwable) {
0589:
0590: Logger logger = null;
0591: if (context != null)
0592: logger = context.getLogger();
0593: if (logger != null)
0594: logger.log("ContextConfig[" + context.getName() + "] "
0595: + message, throwable);
0596: else {
0597: System.out.println("ContextConfig[" + context.getName()
0598: + "]: " + message);
0599: System.out.println("" + throwable);
0600: throwable.printStackTrace(System.out);
0601: }
0602:
0603: }
0604:
0605: /**
0606: * Process a "start" event for this Context.
0607: */
0608: private synchronized void start() {
0609:
0610: if (debug > 0)
0611: log(sm.getString("contextConfig.start"));
0612: context.setConfigured(false);
0613: ok = true;
0614:
0615: // Set properties based on DefaultContext
0616: Container container = context.getParent();
0617: if (!context.getOverride()) {
0618: if (container instanceof Host) {
0619: ((Host) container).importDefaultContext(context);
0620: container = container.getParent();
0621: }
0622: if (container instanceof Engine) {
0623: ((Engine) container).importDefaultContext(context);
0624: }
0625: }
0626:
0627: // Process the default and application web.xml files
0628: defaultConfig();
0629: applicationConfig();
0630: if (ok) {
0631: validateSecurityRoles();
0632: }
0633:
0634: // Scan tag library descriptor files for additional listener classes
0635: if (ok) {
0636: try {
0637: tldScan();
0638: } catch (Exception e) {
0639: log(e.getMessage(), e);
0640: ok = false;
0641: }
0642: }
0643:
0644: // Configure a certificates exposer valve, if required
0645: if (ok)
0646: certificatesConfig();
0647:
0648: // Configure an authenticator if we need one
0649: if (ok)
0650: authenticatorConfig();
0651:
0652: // Dump the contents of this pipeline if requested
0653: if ((debug >= 1) && (context instanceof ContainerBase)) {
0654: log("Pipline Configuration:");
0655: Pipeline pipeline = ((ContainerBase) context).getPipeline();
0656: Valve valves[] = null;
0657: if (pipeline != null)
0658: valves = pipeline.getValves();
0659: if (valves != null) {
0660: for (int i = 0; i < valves.length; i++) {
0661: log(" " + valves[i].getInfo());
0662: }
0663: }
0664: log("======================");
0665: }
0666:
0667: // Make our application available if no problems were encountered
0668: if (ok)
0669: context.setConfigured(true);
0670: else {
0671: log(sm.getString("contextConfig.unavailable"));
0672: context.setConfigured(false);
0673: }
0674:
0675: }
0676:
0677: /**
0678: * Process a "stop" event for this Context.
0679: */
0680: private synchronized void stop() {
0681:
0682: if (debug > 0)
0683: log(sm.getString("contextConfig.stop"));
0684:
0685: int i;
0686:
0687: // Removing children
0688: Container[] children = context.findChildren();
0689: for (i = 0; i < children.length; i++) {
0690: context.removeChild(children[i]);
0691: }
0692:
0693: // Removing application listeners
0694: String[] applicationListeners = context
0695: .findApplicationListeners();
0696: for (i = 0; i < applicationListeners.length; i++) {
0697: context.removeApplicationListener(applicationListeners[i]);
0698: }
0699:
0700: // Removing application parameters
0701: ApplicationParameter[] applicationParameters = context
0702: .findApplicationParameters();
0703: for (i = 0; i < applicationParameters.length; i++) {
0704: context.removeApplicationParameter(applicationParameters[i]
0705: .getName());
0706: }
0707:
0708: // Removing security constraints
0709: SecurityConstraint[] securityConstraints = context
0710: .findConstraints();
0711: for (i = 0; i < securityConstraints.length; i++) {
0712: context.removeConstraint(securityConstraints[i]);
0713: }
0714:
0715: // Removing Ejbs
0716: /*
0717: ContextEjb[] contextEjbs = context.findEjbs();
0718: for (i = 0; i < contextEjbs.length; i++) {
0719: context.removeEjb(contextEjbs[i].getName());
0720: }
0721: */
0722:
0723: // Removing environments
0724: /*
0725: ContextEnvironment[] contextEnvironments = context.findEnvironments();
0726: for (i = 0; i < contextEnvironments.length; i++) {
0727: context.removeEnvironment(contextEnvironments[i].getName());
0728: }
0729: */
0730:
0731: // Removing errors pages
0732: ErrorPage[] errorPages = context.findErrorPages();
0733: for (i = 0; i < errorPages.length; i++) {
0734: context.removeErrorPage(errorPages[i]);
0735: }
0736:
0737: // Removing filter defs
0738: FilterDef[] filterDefs = context.findFilterDefs();
0739: for (i = 0; i < filterDefs.length; i++) {
0740: context.removeFilterDef(filterDefs[i]);
0741: }
0742:
0743: // Removing filter maps
0744: FilterMap[] filterMaps = context.findFilterMaps();
0745: for (i = 0; i < filterMaps.length; i++) {
0746: context.removeFilterMap(filterMaps[i]);
0747: }
0748:
0749: // Removing instance listeners
0750: String[] instanceListeners = context.findInstanceListeners();
0751: for (i = 0; i < instanceListeners.length; i++) {
0752: context.removeInstanceListener(instanceListeners[i]);
0753: }
0754:
0755: // Removing local ejbs
0756: /*
0757: ContextLocalEjb[] contextLocalEjbs = context.findLocalEjbs();
0758: for (i = 0; i < contextLocalEjbs.length; i++) {
0759: context.removeLocalEjb(contextLocalEjbs[i].getName());
0760: }
0761: */
0762:
0763: // Removing Mime mappings
0764: String[] mimeMappings = context.findMimeMappings();
0765: for (i = 0; i < mimeMappings.length; i++) {
0766: context.removeMimeMapping(mimeMappings[i]);
0767: }
0768:
0769: // Removing parameters
0770: String[] parameters = context.findParameters();
0771: for (i = 0; i < parameters.length; i++) {
0772: context.removeParameter(parameters[i]);
0773: }
0774:
0775: // Removing resource env refs
0776: /*
0777: String[] resourceEnvRefs = context.findResourceEnvRefs();
0778: for (i = 0; i < resourceEnvRefs.length; i++) {
0779: context.removeResourceEnvRef(resourceEnvRefs[i]);
0780: }
0781: */
0782:
0783: // Removing resource links
0784: /*
0785: ContextResourceLink[] contextResourceLinks =
0786: context.findResourceLinks();
0787: for (i = 0; i < contextResourceLinks.length; i++) {
0788: context.removeResourceLink(contextResourceLinks[i].getName());
0789: }
0790: */
0791:
0792: // Removing resources
0793: /*
0794: ContextResource[] contextResources = context.findResources();
0795: for (i = 0; i < contextResources.length; i++) {
0796: context.removeResource(contextResources[i].getName());
0797: }
0798: */
0799:
0800: // Removing sercurity role
0801: String[] securityRoles = context.findSecurityRoles();
0802: for (i = 0; i < securityRoles.length; i++) {
0803: context.removeSecurityRole(securityRoles[i]);
0804: }
0805:
0806: // Removing servlet mappings
0807: String[] servletMappings = context.findServletMappings();
0808: for (i = 0; i < servletMappings.length; i++) {
0809: context.removeServletMapping(servletMappings[i]);
0810: }
0811:
0812: // FIXME : Removing status pages
0813:
0814: // Removing taglibs
0815: String[] taglibs = context.findTaglibs();
0816: for (i = 0; i < taglibs.length; i++) {
0817: context.removeTaglib(taglibs[i]);
0818: }
0819:
0820: // Removing welcome files
0821: String[] welcomeFiles = context.findWelcomeFiles();
0822: for (i = 0; i < welcomeFiles.length; i++) {
0823: context.removeWelcomeFile(welcomeFiles[i]);
0824: }
0825:
0826: // Removing wrapper lifecycles
0827: String[] wrapperLifecycles = context.findWrapperLifecycles();
0828: for (i = 0; i < wrapperLifecycles.length; i++) {
0829: context.removeWrapperLifecycle(wrapperLifecycles[i]);
0830: }
0831:
0832: // Removing wrapper listeners
0833: String[] wrapperListeners = context.findWrapperListeners();
0834: for (i = 0; i < wrapperListeners.length; i++) {
0835: context.removeWrapperListener(wrapperListeners[i]);
0836: }
0837:
0838: ok = true;
0839:
0840: }
0841:
0842: /**
0843: * Scan for and configure all tag library descriptors found in this
0844: * web application.
0845: *
0846: * @exception Exception if a fatal input/output or parsing error occurs
0847: */
0848: private void tldScan() throws Exception {
0849:
0850: // Acquire this list of TLD resource paths to be processed
0851: Set resourcePaths = tldScanResourcePaths();
0852:
0853: // Scan each accumulated resource paths for TLDs to be processed
0854: Iterator paths = resourcePaths.iterator();
0855: while (paths.hasNext()) {
0856: String path = (String) paths.next();
0857: if (path.endsWith(".jar")) {
0858: tldScanJar(path);
0859: } else {
0860: tldScanTld(path);
0861: }
0862: }
0863:
0864: }
0865:
0866: /**
0867: * Scan the JAR file at the specified resource path for TLDs in the
0868: * <code>META-INF</code> subdirectory, and scan them for application
0869: * event listeners that need to be registered.
0870: *
0871: * @param resourcePath Resource path of the JAR file to scan
0872: *
0873: * @exception Exception if an exception occurs while scanning this JAR
0874: */
0875: private void tldScanJar(String resourcePath) throws Exception {
0876:
0877: if (debug >= 1) {
0878: log(" Scanning JAR at resource path '" + resourcePath + "'");
0879: }
0880:
0881: JarFile jarFile = null;
0882: String name = null;
0883: InputStream inputStream = null;
0884: try {
0885: URL url = context.getServletContext().getResource(
0886: resourcePath);
0887: if (url == null) {
0888: throw new IllegalArgumentException(sm.getString(
0889: "contextConfig.tldResourcePath", resourcePath));
0890: }
0891: url = new URL("jar:" + url.toString() + "!/");
0892: JarURLConnection conn = (JarURLConnection) url
0893: .openConnection();
0894: conn.setUseCaches(false);
0895: jarFile = conn.getJarFile();
0896: Enumeration entries = jarFile.entries();
0897: while (entries.hasMoreElements()) {
0898: JarEntry entry = (JarEntry) entries.nextElement();
0899: name = entry.getName();
0900: if (!name.startsWith("META-INF/")) {
0901: continue;
0902: }
0903: if (!name.endsWith(".tld")) {
0904: continue;
0905: }
0906: if (debug >= 2) {
0907: log(" Processing TLD at '" + name + "'");
0908: }
0909: inputStream = jarFile.getInputStream(entry);
0910: tldScanStream(inputStream);
0911: inputStream.close();
0912: inputStream = null;
0913: name = null;
0914: }
0915: // FIXME - Closing the JAR file messes up the class loader???
0916: // jarFile.close();
0917: } catch (Exception e) {
0918: if (name == null) {
0919: throw new ServletException(sm.getString(
0920: "contextConfig.tldJarException", resourcePath),
0921: e);
0922: } else {
0923: throw new ServletException(sm.getString(
0924: "contextConfig.tldEntryException", name,
0925: resourcePath), e);
0926: }
0927: } finally {
0928: if (inputStream != null) {
0929: try {
0930: inputStream.close();
0931: } catch (Throwable t) {
0932: ;
0933: }
0934: inputStream = null;
0935: }
0936: if (jarFile != null) {
0937: // FIXME - Closing the JAR file messes up the class loader???
0938: // try {
0939: // jarFile.close();
0940: // } catch (Throwable t) {
0941: // ;
0942: // }
0943: jarFile = null;
0944: }
0945: }
0946:
0947: }
0948:
0949: /**
0950: * Scan the TLD contents in the specified input stream, and register
0951: * any application event listeners found there. <b>NOTE</b> - It is
0952: * the responsibility of the caller to close the InputStream after this
0953: * method returns.
0954: *
0955: * @param resourceStream InputStream containing a tag library descriptor
0956: *
0957: * @exception Exception if an exception occurs while scanning this TLD
0958: */
0959: private void tldScanStream(InputStream resourceStream)
0960: throws Exception {
0961:
0962: synchronized (tldDigester) {
0963: tldDigester.clear();
0964: tldDigester.push(context);
0965: tldDigester.parse(resourceStream);
0966: }
0967:
0968: }
0969:
0970: /**
0971: * Scan the TLD contents at the specified resource path, and register
0972: * any application event listeners found there.
0973: *
0974: * @param resourcePath Resource path being scanned
0975: *
0976: * @exception Exception if an exception occurs while scanning this TLD
0977: */
0978: private void tldScanTld(String resourcePath) throws Exception {
0979:
0980: if (debug >= 1) {
0981: log(" Scanning TLD at resource path '" + resourcePath + "'");
0982: }
0983:
0984: InputStream inputStream = null;
0985: try {
0986: inputStream = context.getServletContext()
0987: .getResourceAsStream(resourcePath);
0988: if (inputStream == null) {
0989: throw new IllegalArgumentException(sm.getString(
0990: "contextConfig.tldResourcePath", resourcePath));
0991: }
0992: tldScanStream(inputStream);
0993: inputStream.close();
0994: inputStream = null;
0995: } catch (Exception e) {
0996: throw new ServletException(sm.getString(
0997: "contextConfig.tldFileException", resourcePath), e);
0998: } finally {
0999: if (inputStream != null) {
1000: try {
1001: inputStream.close();
1002: } catch (Throwable t) {
1003: ;
1004: }
1005: inputStream = null;
1006: }
1007: }
1008:
1009: }
1010:
1011: /**
1012: * Accumulate and return a Set of resource paths to be analyzed for
1013: * tag library descriptors. Each element of the returned set will be
1014: * the context-relative path to either a tag library descriptor file,
1015: * or to a JAR file that may contain tag library descriptors in its
1016: * <code>META-INF</code> subdirectory.
1017: *
1018: * @exception IOException if an input/output error occurs while
1019: * accumulating the list of resource paths
1020: */
1021: private Set tldScanResourcePaths() throws IOException {
1022:
1023: if (debug >= 1) {
1024: log(" Accumulating TLD resource paths");
1025: }
1026: Set resourcePaths = new HashSet();
1027:
1028: // Accumulate resource paths explicitly listed in the web application
1029: // deployment descriptor
1030: if (debug >= 2) {
1031: log(" Scanning <taglib> elements in web.xml");
1032: }
1033: String taglibs[] = context.findTaglibs();
1034: for (int i = 0; i < taglibs.length; i++) {
1035: String resourcePath = context.findTaglib(taglibs[i]);
1036: // FIXME - Servlet 2.3 DTD implies that the location MUST be
1037: // a context-relative path starting with '/'?
1038: if (!resourcePath.startsWith("/")) {
1039: resourcePath = "/WEB-INF/web.xml/../" + resourcePath;
1040: }
1041: if (debug >= 3) {
1042: log(" Adding path '" + resourcePath + "' for URI '"
1043: + taglibs[i] + "'");
1044: }
1045: resourcePaths.add(resourcePath);
1046: }
1047:
1048: // Scan TLDs in the /WEB-INF subdirectory of the web application
1049: if (debug >= 2) {
1050: log(" Scanning TLDs in /WEB-INF subdirectory");
1051: }
1052: DirContext resources = context.getResources();
1053: try {
1054: NamingEnumeration items = resources.list("/WEB-INF");
1055: while (items.hasMoreElements()) {
1056: NameClassPair item = (NameClassPair) items
1057: .nextElement();
1058: String resourcePath = "/WEB-INF/" + item.getName();
1059: // FIXME - JSP 1.2 is not explicit about whether we should
1060: // scan subdirectories of /WEB-INF for TLDs also
1061: if (!resourcePath.endsWith(".tld")) {
1062: continue;
1063: }
1064: if (debug >= 3) {
1065: log(" Adding path '" + resourcePath + "'");
1066: }
1067: resourcePaths.add(resourcePath);
1068: }
1069: } catch (NamingException e) {
1070: ; // Silent catch: it's valid that no /WEB-INF directory exists
1071: }
1072:
1073: // Scan JARs in the /WEB-INF/lib subdirectory of the web application
1074: if (debug >= 2) {
1075: log(" Scanning JARs in /WEB-INF/lib subdirectory");
1076: }
1077: try {
1078: NamingEnumeration items = resources.list("/WEB-INF/lib");
1079: while (items.hasMoreElements()) {
1080: NameClassPair item = (NameClassPair) items
1081: .nextElement();
1082: String resourcePath = "/WEB-INF/lib/" + item.getName();
1083: if (!resourcePath.endsWith(".jar")) {
1084: continue;
1085: }
1086: if (debug >= 3) {
1087: log(" Adding path '" + resourcePath + "'");
1088: }
1089: resourcePaths.add(resourcePath);
1090: }
1091: } catch (NamingException e) {
1092: ; // Silent catch: it's valid that no /WEB-INF/lib directory exists
1093: }
1094:
1095: // Return the completed set
1096: return (resourcePaths);
1097:
1098: }
1099:
1100: /**
1101: * Validate the usage of security role names in the web application
1102: * deployment descriptor. If any problems are found, issue warning
1103: * messages (for backwards compatibility) and add the missing roles.
1104: * (To make these problems fatal instead, simply set the <code>ok</code>
1105: * instance variable to <code>false</code> as well).
1106: */
1107: private void validateSecurityRoles() {
1108:
1109: // Check role names used in <security-constraint> elements
1110: SecurityConstraint constraints[] = context.findConstraints();
1111: for (int i = 0; i < constraints.length; i++) {
1112: String roles[] = constraints[i].findAuthRoles();
1113: for (int j = 0; j < roles.length; j++) {
1114: if (!"*".equals(roles[j])
1115: && !context.findSecurityRole(roles[j])) {
1116: log(sm.getString("contextConfig.role.auth",
1117: roles[j]));
1118: context.addSecurityRole(roles[j]);
1119: }
1120: }
1121: }
1122:
1123: // Check role names used in <servlet> elements
1124: Container wrappers[] = context.findChildren();
1125: for (int i = 0; i < wrappers.length; i++) {
1126: Wrapper wrapper = (Wrapper) wrappers[i];
1127: String runAs = wrapper.getRunAs();
1128: if ((runAs != null) && !context.findSecurityRole(runAs)) {
1129: log(sm.getString("contextConfig.role.runas", runAs));
1130: context.addSecurityRole(runAs);
1131: }
1132: String names[] = wrapper.findSecurityReferences();
1133: for (int j = 0; j < names.length; j++) {
1134: String link = wrapper.findSecurityReference(names[j]);
1135: if ((link != null) && !context.findSecurityRole(link)) {
1136: log(sm.getString("contextConfig.role.link", link));
1137: context.addSecurityRole(link);
1138: }
1139: }
1140: }
1141:
1142: }
1143:
1144: }
|