Fix typo
authormarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Fri, 14 Oct 2011 12:55:55 +0000 (12:55 +0000)
committermarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Fri, 14 Oct 2011 12:55:55 +0000 (12:55 +0000)
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1183340 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/catalina/startup/ContextConfig.java

index ae78221..3c885ac 100644 (file)
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.catalina.startup;
-
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-import java.net.JarURLConnection;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.servlet.ServletContainerInitializer;
-import javax.servlet.ServletContext;
-import javax.servlet.annotation.HandlesTypes;
-
-import org.apache.catalina.Authenticator;
-import org.apache.catalina.Container;
-import org.apache.catalina.Context;
-import org.apache.catalina.Engine;
-import org.apache.catalina.Globals;
-import org.apache.catalina.Host;
-import org.apache.catalina.Lifecycle;
-import org.apache.catalina.LifecycleEvent;
-import org.apache.catalina.LifecycleListener;
-import org.apache.catalina.Pipeline;
-import org.apache.catalina.Server;
-import org.apache.catalina.Service;
-import org.apache.catalina.Valve;
-import org.apache.catalina.Wrapper;
-import org.apache.catalina.core.ContainerBase;
-import org.apache.catalina.core.StandardContext;
-import org.apache.catalina.core.StandardEngine;
-import org.apache.catalina.core.StandardHost;
-import org.apache.catalina.deploy.ErrorPage;
-import org.apache.catalina.deploy.FilterDef;
-import org.apache.catalina.deploy.FilterMap;
-import org.apache.catalina.deploy.LoginConfig;
-import org.apache.catalina.deploy.SecurityConstraint;
-import org.apache.catalina.deploy.ServletDef;
-import org.apache.catalina.deploy.WebXml;
-import org.apache.catalina.util.ContextName;
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.naming.resources.DirContextURLConnection;
-import org.apache.naming.resources.ResourceAttributes;
-import org.apache.tomcat.JarScanner;
-import org.apache.tomcat.JarScannerCallback;
-import org.apache.tomcat.util.ExceptionUtils;
-import org.apache.tomcat.util.bcel.classfile.AnnotationElementValue;
-import org.apache.tomcat.util.bcel.classfile.AnnotationEntry;
-import org.apache.tomcat.util.bcel.classfile.ArrayElementValue;
-import org.apache.tomcat.util.bcel.classfile.ClassFormatException;
-import org.apache.tomcat.util.bcel.classfile.ClassParser;
-import org.apache.tomcat.util.bcel.classfile.ElementValue;
-import org.apache.tomcat.util.bcel.classfile.ElementValuePair;
-import org.apache.tomcat.util.bcel.classfile.JavaClass;
-import org.apache.tomcat.util.digester.Digester;
-import org.apache.tomcat.util.digester.RuleSet;
-import org.apache.tomcat.util.res.StringManager;
-import org.apache.tomcat.util.scan.Jar;
-import org.apache.tomcat.util.scan.JarFactory;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXParseException;
-
-/**
- * Startup event listener for a <b>Context</b> that configures the properties
- * of that Context, and the associated defined servlets.
- *
- * @author Craig R. McClanahan
- * @author Jean-Francois Arcand
- * @version $Id$
- */
-
-public class ContextConfig
-    implements LifecycleListener {
-
-    private static final Log log = LogFactory.getLog( ContextConfig.class );
-    
-    private static final String SCI_LOCATION =
-        "META-INF/services/javax.servlet.ServletContainerInitializer";
-
-
-    /**
-     * The string resources for this package.
-     */
-    protected static final StringManager sm =
-        StringManager.getManager(Constants.Package);
-
-
-    protected static final LoginConfig DUMMY_LOGIN_CONFIG =
-        new LoginConfig("NONE", null, null, null);
-
-    /**
-     * The <code>Digester</code> we will use to process web application
-     * context files.
-     */
-    protected static Digester contextDigester = null;
-    
-
-    /**
-     * The set of Authenticators that we know how to configure.  The key is
-     * the name of the implemented authentication method, and the value is
-     * the fully qualified Java class name of the corresponding Valve.
-     */
-    protected static Properties authenticators = null;
-
-
-    /**
-     * The <code>Digester</code>s available to process web deployment descriptor
-     * files.
-     */
-    protected static Digester[] webDigesters = new Digester[4];
-
-
-    /**
-     * The <code>Digester</code>s available to process web fragment deployment
-     * descriptor files.
-     */
-    protected static Digester[] webFragmentDigesters = new Digester[4];
-
-
-    /**
-     * The <code>Rule</code>s used to parse the web.xml
-     */
-    protected static WebRuleSet webRuleSet = new WebRuleSet(false);
-
-
-    /**
-     * The <code>Rule</code>s used to parse the web-fragment.xml
-     */
-    protected static WebRuleSet webFragmentRuleSet = new WebRuleSet(true);
-
-
-    /**
-     * Deployment count.
-     */
-    protected static long deploymentCount = 0L;
-
-
-    /**
-     * Cache of default web.xml fragments per Host
-     */
-    protected static final Map<Host,DefaultWebXmlCacheEntry> hostWebXmlCache =
-        new ConcurrentHashMap<Host,DefaultWebXmlCacheEntry>();
-
-
-    // ----------------------------------------------------- Instance Variables
-    /**
-     * Custom mappings of login methods to authenticators
-     */
-    protected Map<String,Authenticator> customAuthenticators;
-
-
-    /**
-     * The Context we are associated with.
-     */
-    protected Context context = null;
-
-
-    /**
-     * The default web application's context file location.
-     */
-    protected String defaultContextXml = null;
-    
-    
-    /**
-     * The default web application's deployment descriptor location.
-     */
-    protected String defaultWebXml = null;
-    
-    
-    /**
-     * Track any fatal errors during startup configuration processing.
-     */
-    protected boolean ok = false;
-
-
-    /**
-     * Original docBase.
-     */
-    protected String originalDocBase = null;
-    
-
-    /**
-     * Map of ServletContainerInitializer to classes they expressed interest in.
-     */
-    protected Map<ServletContainerInitializer, Set<Class<?>>> initializerClassMap =
-        new LinkedHashMap<ServletContainerInitializer, Set<Class<?>>>();
-    
-    /**
-     * Map of Types to ServletContainerInitializer that are interested in those
-     * types.
-     */
-    protected Map<Class<?>, Set<ServletContainerInitializer>> typeInitializerMap =
-        new HashMap<Class<?>, Set<ServletContainerInitializer>>();
-
-    /**
-     * The <code>Digester</code> we will use to process web application
-     * deployment descriptor files.
-     */
-    protected Digester webDigester = null;
-
-    /**
-     * The <code>Digester</code> we will use to process web fragment
-     * deployment descriptor files.
-     */
-    protected Digester webFragmentDigester = null;
-
-    
-    // ------------------------------------------------------------- Properties
-    /**
-     * Return the location of the default deployment descriptor
-     */
-    public String getDefaultWebXml() {
-        if( defaultWebXml == null ) {
-            defaultWebXml=Constants.DefaultWebXml;
-        }
-
-        return (this.defaultWebXml);
-
-    }
-
-
-    /**
-     * Set the location of the default deployment descriptor
-     *
-     * @param path Absolute/relative path to the default web.xml
-     */
-    public void setDefaultWebXml(String path) {
-
-        this.defaultWebXml = path;
-
-    }
-
-
-    /**
-     * Return the location of the default context file
-     */
-    public String getDefaultContextXml() {
-        if( defaultContextXml == null ) {
-            defaultContextXml=Constants.DefaultContextXml;
-        }
-
-        return (this.defaultContextXml);
-
-    }
-
-
-    /**
-     * Set the location of the default context file
-     *
-     * @param path Absolute/relative path to the default context.xml
-     */
-    public void setDefaultContextXml(String path) {
-
-        this.defaultContextXml = path;
-
-    }
-
-
-    /**
-     * Sets custom mappings of login methods to authenticators.
-     *
-     * @param customAuthenticators Custom mappings of login methods to
-     * authenticators
-     */
-    public void setCustomAuthenticators(
-            Map<String,Authenticator> customAuthenticators) {
-        this.customAuthenticators = customAuthenticators;
-    }
-
-
-    // --------------------------------------------------------- Public Methods
-
-
-    /**
-     * Process events for an associated Context.
-     *
-     * @param event The lifecycle event that has occurred
-     */
-    @Override
-    public void lifecycleEvent(LifecycleEvent event) {
-
-        // Identify the context we are associated with
-        try {
-            context = (Context) event.getLifecycle();
-        } catch (ClassCastException e) {
-            log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);
-            return;
-        }
-
-        // Process the event that has occurred
-        if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
-            configureStart();
-        } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
-            beforeStart();
-        } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {
-            // Restore docBase for management tools
-            if (originalDocBase != null) {
-                String docBase = context.getDocBase();
-                context.setDocBase(originalDocBase);
-                originalDocBase = docBase;
-            }
-        } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {
-            if (originalDocBase != null) {
-                String docBase = context.getDocBase();
-                context.setDocBase(originalDocBase);
-                originalDocBase = docBase;
-            }
-            configureStop();
-        } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {
-            init();
-        } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {
-            destroy();
-        }
-
-    }
-
-
-    // -------------------------------------------------------- protected Methods
-
-
-    /**
-     * Process the application classes annotations, if it exists.
-     */
-    protected void applicationAnnotationsConfig() {
-        
-        long t1=System.currentTimeMillis();
-        
-        WebAnnotationSet.loadApplicationAnnotations(context);
-        
-        long t2=System.currentTimeMillis();
-        if (context instanceof StandardContext) {
-            ((StandardContext) context).setStartupTime(t2-t1+
-                    ((StandardContext) context).getStartupTime());
-        }
-    }
-
-
-    /**
-     * Set up an Authenticator automatically if required, and one has not
-     * already been configured.
-     */
-    protected synchronized void authenticatorConfig() {
-
-        LoginConfig loginConfig = context.getLoginConfig();
-
-        SecurityConstraint constraints[] = context.findConstraints();
-        if (context.getIgnoreAnnotations() &&
-                (constraints == null || constraints.length ==0) &&
-                !context.getPreemptiveAuthentication())  {
-            return;
-        } else {
-            if (loginConfig == null) {
-                // Not metadata-complete or security constraints present, need
-                // an authenticator to support @ServletSecurity annotations
-                // and/or constraints
-                loginConfig = DUMMY_LOGIN_CONFIG;
-                context.setLoginConfig(loginConfig);
-            }
-        }
-
-        // Has an authenticator been configured already?
-        if (context.getAuthenticator() != null)
-            return;
-        
-        if (!(context instanceof ContainerBase)) {
-            return;     // Cannot install a Valve even if it would be needed
-        }
-
-        // Has a Realm been configured for us to authenticate against?
-        if (context.getRealm() == null) {
-            log.error(sm.getString("contextConfig.missingRealm"));
-            ok = false;
-            return;
-        }
-
-        /*
-         * First check to see if there is a custom mapping for the login
-         * method. If so, use it. Otherwise, check if there is a mapping in
-         * org/apache/catalina/startup/Authenticators.properties.
-         */
-        Valve authenticator = null;
-        if (customAuthenticators != null) {
-            authenticator = (Valve)
-                customAuthenticators.get(loginConfig.getAuthMethod());
-        }
-        if (authenticator == null) {
-            // Load our mapping properties if necessary
-            if (authenticators == null) {
-                try {
-                    InputStream is=this.getClass().getClassLoader().getResourceAsStream("org/apache/catalina/startup/Authenticators.properties");
-                    if( is!=null ) {
-                        authenticators = new Properties();
-                        authenticators.load(is);
-                    } else {
-                        log.error(sm.getString(
-                                "contextConfig.authenticatorResources"));
-                        ok=false;
-                        return;
-                    }
-                } catch (IOException e) {
-                    log.error(sm.getString(
-                                "contextConfig.authenticatorResources"), e);
-                    ok = false;
-                    return;
-                }
-            }
-
-            // Identify the class name of the Valve we should configure
-            String authenticatorName = null;
-            authenticatorName =
-                    authenticators.getProperty(loginConfig.getAuthMethod());
-            if (authenticatorName == null) {
-                log.error(sm.getString("contextConfig.authenticatorMissing",
-                                 loginConfig.getAuthMethod()));
-                ok = false;
-                return;
-            }
-
-            // Instantiate and install an Authenticator of the requested class
-            try {
-                Class<?> authenticatorClass = Class.forName(authenticatorName);
-                authenticator = (Valve) authenticatorClass.newInstance();
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                log.error(sm.getString(
-                                    "contextConfig.authenticatorInstantiate",
-                                    authenticatorName),
-                          t);
-                ok = false;
-            }
-        }
-
-        if (authenticator != null && context instanceof ContainerBase) {
-            Pipeline pipeline = ((ContainerBase) context).getPipeline();
-            if (pipeline != null) {
-                ((ContainerBase) context).getPipeline().addValve(authenticator);
-                if (log.isDebugEnabled()) {
-                    log.debug(sm.getString(
-                                    "contextConfig.authenticatorConfigured",
-                                    loginConfig.getAuthMethod()));
-                }
-            }
-        }
-
-    }
-
-
-    /**
-     * Create (if necessary) and return a Digester configured to process the
-     * web application deployment descriptor (web.xml).
-     */
-    public void createWebXmlDigester(boolean namespaceAware,
-            boolean validation) {
-        
-        if (!namespaceAware && !validation) {
-            if (webDigesters[0] == null) {
-                webDigesters[0] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webRuleSet);
-                webFragmentDigesters[0] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webFragmentRuleSet);
-                webDigesters[0].getParser();
-                webFragmentDigesters[0].getParser();
-            }
-            webDigester = webDigesters[0];
-            webFragmentDigester = webFragmentDigesters[0];
-            
-        } else if (!namespaceAware && validation) {
-            if (webDigesters[1] == null) {
-                webDigesters[1] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webRuleSet);
-                webFragmentDigesters[1] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webFragmentRuleSet);
-                webDigesters[1].getParser();
-                webFragmentDigesters[1].getParser();
-            }
-            webDigester = webDigesters[1];
-            webFragmentDigester = webFragmentDigesters[1];
-            
-        } else if (namespaceAware && !validation) {
-            if (webDigesters[2] == null) {
-                webDigesters[2] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webRuleSet);
-                webFragmentDigesters[2] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webFragmentRuleSet);
-                webDigesters[2].getParser();
-                webFragmentDigesters[2].getParser();
-            }
-            webDigester = webDigesters[2];
-            webFragmentDigester = webFragmentDigesters[2];
-            
-        } else {
-            if (webDigesters[3] == null) {
-                webDigesters[3] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webRuleSet);
-                webFragmentDigesters[3] = DigesterFactory.newDigester(validation,
-                        namespaceAware, webFragmentRuleSet);
-                webDigesters[3].getParser();
-                webFragmentDigesters[3].getParser();
-            }
-            webDigester = webDigesters[3];
-            webFragmentDigester = webFragmentDigesters[3];
-        }
-    }
-
-    
-    /**
-     * Create (if necessary) and return a Digester configured to process the
-     * context configuration descriptor for an application.
-     */
-    protected Digester createContextDigester() {
-        Digester digester = new Digester();
-        digester.setValidating(false);
-        digester.setRulesValidation(true);
-        HashMap<Class<?>, List<String>> fakeAttributes =
-            new HashMap<Class<?>, List<String>>();
-        ArrayList<String> attrs = new ArrayList<String>();
-        attrs.add("className");
-        fakeAttributes.put(Object.class, attrs);
-        digester.setFakeAttributes(fakeAttributes);
-        RuleSet contextRuleSet = new ContextRuleSet("", false);
-        digester.addRuleSet(contextRuleSet);
-        RuleSet namingRuleSet = new NamingRuleSet("Context/");
-        digester.addRuleSet(namingRuleSet);
-        return digester;
-    }
-
-
-    protected String getBaseDir() {
-        Container engineC=context.getParent().getParent();
-        if( engineC instanceof StandardEngine ) {
-            return ((StandardEngine)engineC).getBaseDir();
-        }
-        return System.getProperty(Globals.CATALINA_BASE_PROP);
-    }
-
-    
-    /**
-     * Process the default configuration file, if it exists.
-     */
-    protected void contextConfig() {
-        
-        // Open the default context.xml file, if it exists
-        if( defaultContextXml==null && context instanceof StandardContext ) {
-            defaultContextXml = ((StandardContext)context).getDefaultContextXml();
-        }
-        // set the default if we don't have any overrides
-        if( defaultContextXml==null ) getDefaultContextXml();
-
-        if (!context.getOverride()) {
-            File defaultContextFile = new File(defaultContextXml);
-            if (!defaultContextFile.isAbsolute()) {
-                defaultContextFile =new File(getBaseDir(), defaultContextXml);
-            }
-            if (defaultContextFile.exists()) {
-                try {
-                    URL defaultContextUrl = defaultContextFile.toURI().toURL();
-                    processContextConfig(defaultContextUrl);
-                } catch (MalformedURLException e) {
-                    log.error(sm.getString(
-                            "contextConfig.badUrl", defaultContextFile), e);
-                }
-            }
-            
-            File hostContextFile = new File(getConfigBase(),
-                    getHostConfigPath(Constants.HostContextXml));
-            if (hostContextFile.exists()) {
-                try {
-                    URL hostContextUrl = hostContextFile.toURI().toURL();
-                    processContextConfig(hostContextUrl);
-                } catch (MalformedURLException e) {
-                    log.error(sm.getString(
-                            "contextConfig.badUrl", hostContextFile), e);
-                }
-            }
-        }
-        if (context.getConfigFile() != null)
-            processContextConfig(context.getConfigFile());
-        
-    }
-
-    
-    /**
-     * Process a context.xml.
-     */
-    protected void processContextConfig(URL contextXml) {
-        
-        if (log.isDebugEnabled())
-            log.debug("Processing context [" + context.getName() 
-                    + "] configuration file [" + contextXml + "]");
-
-        InputSource source = null;
-        InputStream stream = null;
-
-        try {
-            source = new InputSource(contextXml.toString());
-            stream = contextXml.openStream();
-            
-            // Add as watched resource so that cascade reload occurs if a default
-            // config file is modified/added/removed
-            if ("file".equals(contextXml.getProtocol())) {
-                context.addWatchedResource(
-                        (new File(contextXml.toURI())).getAbsolutePath());
-            }
-        } catch (Exception e) {
-            log.error(sm.getString("contextConfig.contextMissing",  
-                      contextXml) , e);
-        }
-        
-        if (source == null)
-            return;
-        synchronized (contextDigester) {
-            try {
-                source.setByteStream(stream);
-                contextDigester.setClassLoader(this.getClass().getClassLoader());
-                contextDigester.setUseContextClassLoader(false);
-                contextDigester.push(context.getParent());
-                contextDigester.push(context);
-                XmlErrorHandler errorHandler = new XmlErrorHandler();
-                contextDigester.setErrorHandler(errorHandler);
-                contextDigester.parse(source);
-                if (errorHandler.getWarnings().size() > 0 ||
-                        errorHandler.getErrors().size() > 0) {
-                    errorHandler.logFindings(log, contextXml.toString());
-                    ok = false;
-                }
-                if (log.isDebugEnabled())
-                    log.debug("Successfully processed context [" + context.getName() 
-                            + "] configuration file [" + contextXml + "]");
-            } catch (SAXParseException e) {
-                log.error(sm.getString("contextConfig.contextParse",
-                        context.getName()), e);
-                log.error(sm.getString("contextConfig.defaultPosition",
-                                 "" + e.getLineNumber(),
-                                 "" + e.getColumnNumber()));
-                ok = false;
-            } catch (Exception e) {
-                log.error(sm.getString("contextConfig.contextParse",
-                        context.getName()), e);
-                ok = false;
-            } finally {
-                contextDigester.reset();
-                try {
-                    if (stream != null) {
-                        stream.close();
-                    }
-                } catch (IOException e) {
-                    log.error(sm.getString("contextConfig.contextClose"), e);
-                }
-            }
-        }
-    }
-
-    
-    /**
-     * Adjust docBase.
-     */
-    protected void fixDocBase()
-        throws IOException {
-        
-        Host host = (Host) context.getParent();
-        File appBase = host.getAppBaseFile();
-
-        String docBase = context.getDocBase();
-        if (docBase == null) {
-            // Trying to guess the docBase according to the path
-            String path = context.getPath();
-            if (path == null) {
-                return;
-            }
-            ContextName cn = new ContextName(path, context.getWebappVersion());
-            docBase = cn.getBaseName();
-        }
-
-        File file = new File(docBase);
-        if (!file.isAbsolute()) {
-            docBase = (new File(appBase, docBase)).getPath();
-        } else {
-            docBase = file.getCanonicalPath();
-        }
-        file = new File(docBase);
-        String origDocBase = docBase;
-        
-        ContextName cn = new ContextName(context.getPath(),
-                context.getWebappVersion());
-        String pathName = cn.getBaseName();
-
-        boolean unpackWARs = true;
-        if (host instanceof StandardHost) {
-            unpackWARs = ((StandardHost) host).isUnpackWARs() &&
-                    ((StandardContext) context).getUnpackWAR() &&
-                    (docBase.startsWith(host.getAppBaseFile().getPath()));
-        }
-
-        if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") && !file.isDirectory() && unpackWARs) {
-            URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/");
-            docBase = ExpandWar.expand(host, war, pathName);
-            file = new File(docBase);
-            docBase = file.getCanonicalPath();
-            if (context instanceof StandardContext) {
-                ((StandardContext) context).setOriginalDocBase(origDocBase);
-            }
-        } else if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") &&
-                !file.isDirectory() && !unpackWARs) {
-            URL war =
-                new URL("jar:" + (new File (docBase)).toURI().toURL() + "!/");
-            ExpandWar.validate(host, war, pathName);
-        } else {
-            File docDir = new File(docBase);
-            if (!docDir.exists()) {
-                File warFile = new File(docBase + ".war");
-                if (warFile.exists()) {
-                    URL war =
-                        new URL("jar:" + warFile.toURI().toURL() + "!/");
-                    if (unpackWARs) {
-                        docBase = ExpandWar.expand(host, war, pathName);
-                        file = new File(docBase);
-                        docBase = file.getCanonicalPath();
-                    } else {
-                        docBase = warFile.getCanonicalPath();
-                        ExpandWar.validate(host, war, pathName);
-                    }
-                }
-                if (context instanceof StandardContext) {
-                    ((StandardContext) context).setOriginalDocBase(origDocBase);
-                }
-            }
-        }
-
-        if (docBase.startsWith(appBase.getPath() + File.separatorChar)) {
-            docBase = docBase.substring(appBase.getPath().length());
-            docBase = docBase.replace(File.separatorChar, '/');
-            if (docBase.startsWith("/")) {
-                docBase = docBase.substring(1);
-            }
-        } else {
-            docBase = docBase.replace(File.separatorChar, '/');
-        }
-
-        context.setDocBase(docBase);
-
-    }
-    
-    
-    protected void antiLocking() {
-
-        if ((context instanceof StandardContext) 
-            && ((StandardContext) context).getAntiResourceLocking()) {
-            
-            Host host = (Host) context.getParent();
-            String docBase = context.getDocBase();
-            if (docBase == null)
-                return;
-            if (originalDocBase == null) {
-                originalDocBase = docBase;
-            } else {
-                docBase = originalDocBase;
-            }
-            File docBaseFile = new File(docBase);
-            if (!docBaseFile.isAbsolute()) {
-                docBaseFile = new File(host.getAppBaseFile(), docBase);
-            }
-            
-            String path = context.getPath();
-            if (path == null) {
-                return;
-            }
-            ContextName cn = new ContextName(path, context.getWebappVersion());
-            docBase = cn.getBaseName();
-
-            File file = null;
-            if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war")) {
-                // TODO - This is never executed. Bug or code to delete?
-                file = new File(System.getProperty("java.io.tmpdir"),
-                        deploymentCount++ + "-" + docBase + ".war");
-            } else {
-                file = new File(System.getProperty("java.io.tmpdir"), 
-                        deploymentCount++ + "-" + docBase);
-            }
-            
-            if (log.isDebugEnabled())
-                log.debug("Anti locking context[" + context.getName() 
-                        + "] setting docBase to " + file);
-            
-            // Cleanup just in case an old deployment is lying around
-            ExpandWar.delete(file);
-            if (ExpandWar.copy(docBaseFile, file)) {
-                context.setDocBase(file.getAbsolutePath());
-            }
-            
-        }
-        
-    }
-    
-
-    /**
-     * Process a "init" event for this Context.
-     */
-    protected void init() {
-        // Called from StandardContext.init()
-
-        if (contextDigester == null){
-            contextDigester = createContextDigester();
-            contextDigester.getParser();
-        }
-
-        if (log.isDebugEnabled())
-            log.debug(sm.getString("contextConfig.init"));
-        context.setConfigured(false);
-        ok = true;
-        
-        contextConfig();
-        
-        createWebXmlDigester(context.getXmlNamespaceAware(),
-                context.getXmlValidation());
-
-        try {
-            fixDocBase();
-        } catch (IOException e) {
-            log.error(sm.getString(
-                    "contextConfig.fixDocBase", context.getName()), e);
-        }
-        
-    }
-    
-    
-    /**
-     * Process a "before start" event for this Context.
-     */
-    protected synchronized void beforeStart() {
-        
-        antiLocking();
-
-    }
-    
-    
-    /**
-     * Process a "contextConfig" event for this Context.
-     */
-    protected synchronized void configureStart() {
-        // Called from StandardContext.start()
-
-        if (log.isDebugEnabled())
-            log.debug(sm.getString("contextConfig.start"));
-
-        if (log.isDebugEnabled()) {
-            log.debug(sm.getString("contextConfig.xmlSettings",
-                    context.getName(),
-                    Boolean.valueOf(context.getXmlValidation()),
-                    Boolean.valueOf(context.getXmlNamespaceAware())));
-        }
-        
-        webConfig();
-
-        if (!context.getIgnoreAnnotations()) {
-            applicationAnnotationsConfig();
-        }
-        if (ok) {
-            validateSecurityRoles();
-        }
-
-        // Configure an authenticator if we need one
-        if (ok)
-            authenticatorConfig();
-
-        // Dump the contents of this pipeline if requested
-        if ((log.isDebugEnabled()) && (context instanceof ContainerBase)) {
-            log.debug("Pipeline Configuration:");
-            Pipeline pipeline = ((ContainerBase) context).getPipeline();
-            Valve valves[] = null;
-            if (pipeline != null)
-                valves = pipeline.getValves();
-            if (valves != null) {
-                for (int i = 0; i < valves.length; i++) {
-                    log.debug("  " + valves[i].getInfo());
-                }
-            }
-            log.debug("======================");
-        }
-
-        // Make our application available if no problems were encountered
-        if (ok)
-            context.setConfigured(true);
-        else {
-            log.error(sm.getString("contextConfig.unavailable"));
-            context.setConfigured(false);
-        }
-
-    }
-
-
-    /**
-     * Process a "stop" event for this Context.
-     */
-    protected synchronized void configureStop() {
-
-        if (log.isDebugEnabled())
-            log.debug(sm.getString("contextConfig.stop"));
-
-        int i;
-
-        // Removing children
-        Container[] children = context.findChildren();
-        for (i = 0; i < children.length; i++) {
-            context.removeChild(children[i]);
-        }
-
-        // Removing application parameters
-        /*
-        ApplicationParameter[] applicationParameters =
-            context.findApplicationParameters();
-        for (i = 0; i < applicationParameters.length; i++) {
-            context.removeApplicationParameter
-                (applicationParameters[i].getName());
-        }
-        */
-
-        // Removing security constraints
-        SecurityConstraint[] securityConstraints = context.findConstraints();
-        for (i = 0; i < securityConstraints.length; i++) {
-            context.removeConstraint(securityConstraints[i]);
-        }
-
-        // Removing Ejbs
-        /*
-        ContextEjb[] contextEjbs = context.findEjbs();
-        for (i = 0; i < contextEjbs.length; i++) {
-            context.removeEjb(contextEjbs[i].getName());
-        }
-        */
-
-        // Removing environments
-        /*
-        ContextEnvironment[] contextEnvironments = context.findEnvironments();
-        for (i = 0; i < contextEnvironments.length; i++) {
-            context.removeEnvironment(contextEnvironments[i].getName());
-        }
-        */
-
-        // Removing errors pages
-        ErrorPage[] errorPages = context.findErrorPages();
-        for (i = 0; i < errorPages.length; i++) {
-            context.removeErrorPage(errorPages[i]);
-        }
-
-        // Removing filter defs
-        FilterDef[] filterDefs = context.findFilterDefs();
-        for (i = 0; i < filterDefs.length; i++) {
-            context.removeFilterDef(filterDefs[i]);
-        }
-
-        // Removing filter maps
-        FilterMap[] filterMaps = context.findFilterMaps();
-        for (i = 0; i < filterMaps.length; i++) {
-            context.removeFilterMap(filterMaps[i]);
-        }
-
-        // Removing local ejbs
-        /*
-        ContextLocalEjb[] contextLocalEjbs = context.findLocalEjbs();
-        for (i = 0; i < contextLocalEjbs.length; i++) {
-            context.removeLocalEjb(contextLocalEjbs[i].getName());
-        }
-        */
-
-        // Removing Mime mappings
-        String[] mimeMappings = context.findMimeMappings();
-        for (i = 0; i < mimeMappings.length; i++) {
-            context.removeMimeMapping(mimeMappings[i]);
-        }
-
-        // Removing parameters
-        String[] parameters = context.findParameters();
-        for (i = 0; i < parameters.length; i++) {
-            context.removeParameter(parameters[i]);
-        }
-
-        // Removing resource env refs
-        /*
-        String[] resourceEnvRefs = context.findResourceEnvRefs();
-        for (i = 0; i < resourceEnvRefs.length; i++) {
-            context.removeResourceEnvRef(resourceEnvRefs[i]);
-        }
-        */
-
-        // Removing resource links
-        /*
-        ContextResourceLink[] contextResourceLinks =
-            context.findResourceLinks();
-        for (i = 0; i < contextResourceLinks.length; i++) {
-            context.removeResourceLink(contextResourceLinks[i].getName());
-        }
-        */
-
-        // Removing resources
-        /*
-        ContextResource[] contextResources = context.findResources();
-        for (i = 0; i < contextResources.length; i++) {
-            context.removeResource(contextResources[i].getName());
-        }
-        */
-
-        // Removing security role
-        String[] securityRoles = context.findSecurityRoles();
-        for (i = 0; i < securityRoles.length; i++) {
-            context.removeSecurityRole(securityRoles[i]);
-        }
-
-        // Removing servlet mappings
-        String[] servletMappings = context.findServletMappings();
-        for (i = 0; i < servletMappings.length; i++) {
-            context.removeServletMapping(servletMappings[i]);
-        }
-
-        // FIXME : Removing status pages
-
-        // Removing welcome files
-        String[] welcomeFiles = context.findWelcomeFiles();
-        for (i = 0; i < welcomeFiles.length; i++) {
-            context.removeWelcomeFile(welcomeFiles[i]);
-        }
-
-        // Removing wrapper lifecycles
-        String[] wrapperLifecycles = context.findWrapperLifecycles();
-        for (i = 0; i < wrapperLifecycles.length; i++) {
-            context.removeWrapperLifecycle(wrapperLifecycles[i]);
-        }
-
-        // Removing wrapper listeners
-        String[] wrapperListeners = context.findWrapperListeners();
-        for (i = 0; i < wrapperListeners.length; i++) {
-            context.removeWrapperListener(wrapperListeners[i]);
-        }
-
-        // Remove (partially) folders and files created by antiLocking
-        Host host = (Host) context.getParent();
-        String docBase = context.getDocBase();
-        if ((docBase != null) && (originalDocBase != null)) {
-            File docBaseFile = new File(docBase);
-            if (!docBaseFile.isAbsolute()) {
-                docBaseFile = new File(host.getAppBaseFile(), docBase);
-            }
-            // No need to log failure - it is expected in this case
-            ExpandWar.delete(docBaseFile, false);
-        }
-        
-        // Reset ServletContextInitializer scanning
-        initializerClassMap.clear();
-        typeInitializerMap.clear();
-        
-        ok = true;
-
-    }
-    
-    
-    /**
-     * Process a "destroy" event for this Context.
-     */
-    protected synchronized void destroy() {
-        // Called from StandardContext.destroy()
-        if (log.isDebugEnabled())
-            log.debug(sm.getString("contextConfig.destroy"));
-
-        // Skip clearing the work directory if Tomcat is being shutdown
-        Server s = getServer();
-        if (s != null && !s.getState().isAvailable()) {
-            return;
-        }
-        
-        // Changed to getWorkPath per Bugzilla 35819.
-        String workDir = ((StandardContext) context).getWorkPath();
-        if (workDir != null)
-            ExpandWar.delete(new File(workDir));
-    }
-    
-    
-    private Server getServer() {
-        Container c = context;
-        while (c != null && !(c instanceof Engine)) {
-            c = c.getParent();
-        }
-        
-        if (c == null) {
-            return null;
-        }
-        
-        Service s = ((Engine)c).getService();
-        
-        if (s == null) {
-            return null;
-        }
-        
-        return s.getServer();
-    }
-
-    /**
-     * Validate the usage of security role names in the web application
-     * deployment descriptor.  If any problems are found, issue warning
-     * messages (for backwards compatibility) and add the missing roles.
-     * (To make these problems fatal instead, simply set the <code>ok</code>
-     * instance variable to <code>false</code> as well).
-     */
-    protected void validateSecurityRoles() {
-
-        // Check role names used in <security-constraint> elements
-        SecurityConstraint constraints[] = context.findConstraints();
-        for (int i = 0; i < constraints.length; i++) {
-            String roles[] = constraints[i].findAuthRoles();
-            for (int j = 0; j < roles.length; j++) {
-                if (!"*".equals(roles[j]) &&
-                    !context.findSecurityRole(roles[j])) {
-                    log.info(sm.getString("contextConfig.role.auth", roles[j]));
-                    context.addSecurityRole(roles[j]);
-                }
-            }
-        }
-
-        // Check role names used in <servlet> elements
-        Container wrappers[] = context.findChildren();
-        for (int i = 0; i < wrappers.length; i++) {
-            Wrapper wrapper = (Wrapper) wrappers[i];
-            String runAs = wrapper.getRunAs();
-            if ((runAs != null) && !context.findSecurityRole(runAs)) {
-                log.info(sm.getString("contextConfig.role.runas", runAs));
-                context.addSecurityRole(runAs);
-            }
-            String names[] = wrapper.findSecurityReferences();
-            for (int j = 0; j < names.length; j++) {
-                String link = wrapper.findSecurityReference(names[j]);
-                if ((link != null) && !context.findSecurityRole(link)) {
-                    log.info(sm.getString("contextConfig.role.link", link));
-                    context.addSecurityRole(link);
-                }
-            }
-        }
-
-    }
-
-
-    /**
-     * Get config base.
-     */
-    protected File getConfigBase() {
-        File configBase = 
-            new File(System.getProperty(Globals.CATALINA_BASE_PROP), "conf");
-        if (!configBase.exists()) {
-            return null;
-        }
-        return configBase;
-    }  
-
-    
-    protected String getHostConfigPath(String resourceName) {
-        StringBuilder result = new StringBuilder();
-        Container container = context;
-        Container host = null;
-        Container engine = null;
-        while (container != null) {
-            if (container instanceof Host)
-                host = container;
-            if (container instanceof Engine)
-                engine = container;
-            container = container.getParent();
-        }
-        if (engine != null) {
-            result.append(engine.getName()).append('/');
-        }
-        if (host != null) {
-            result.append(host.getName()).append('/');
-        }
-        result.append(resourceName);
-        return result.toString();
-    }
-
-
-    /**
-     * Scan the web.xml files that apply to the web application and merge them
-     * using the rules defined in the spec. For the global web.xml files,
-     * where there is duplicate configuration, the most specific level wins. ie
-     * an application's web.xml takes precedence over the host level or global
-     * web.xml file.
-     */
-    protected void webConfig() {
-        /* Anything and everything can override the global and host defaults.
-         * This is implemented in two parts
-         * - Handle as a web fragment that gets added after everything else so
-         *   everything else takes priority
-         * - Mark Servlets as overridable so SCI configuration can replace
-         *   configuration from the defaults
-         */ 
-        Set<WebXml> defaults = new HashSet<WebXml>();
-        defaults.add(getDefaultWebXmlFragment());
-
-        WebXml webXml = createWebXml();
-
-        // Parse context level web.xml
-        InputSource contextWebXml = getContextWebXmlSource();
-        parseWebXml(contextWebXml, webXml, false);
-        
-        if (webXml.getMajorVersion() >= 3) {
-            // Ordering is important here
-
-            // Step 1. Identify all the JARs packaged with the application
-            // If the JARs have a web-fragment.xml it will be parsed at this
-            // point.
-            Map<String,WebXml> fragments = processJarsForWebFragments();
-
-            // Only need to process fragments and annotations if metadata is
-            // not complete
-            Set<WebXml> orderedFragments = null;
-            if  (!webXml.isMetadataComplete()) {
-                // Step 2. Order the fragments.
-                orderedFragments = WebXml.orderWebFragments(webXml, fragments);
-    
-                // Step 3. Look for ServletContainerInitializer implementations
-                if (ok) {
-                    processServletContainerInitializers(orderedFragments);
-                }
-    
-                // Step 4. Process /WEB-INF/classes for annotations
-                // This will add any matching classes to the typeInitializerMap
-                if (ok) {
-                    URL webinfClasses;
-                    try {
-                        webinfClasses = context.getServletContext().getResource(
-                                "/WEB-INF/classes");
-                        processAnnotationsUrl(webinfClasses, webXml);
-                    } catch (MalformedURLException e) {
-                        log.error(sm.getString(
-                                "contextConfig.webinfClassesUrl"), e);
-                    }
-                }
-    
-                // Step 5. Process JARs for annotations - only need to process
-                // those fragments we are going to use
-                // This will add any matching classes to the typeInitializerMap
-                if (ok) {
-                    processAnnotations(orderedFragments);
-                }
-    
-                // Step 6. Merge web-fragment.xml files into the main web.xml
-                // file.
-                if (ok) {
-                    ok = webXml.merge(orderedFragments);
-                }
-    
-                // Step 7. Apply global defaults
-                // Have to merge defaults before JSP conversion since defaults
-                // provide JSP servlet definition.
-                webXml.merge(defaults);
-
-                // Step 8. Convert explicitly mentioned jsps to servlets
-                if (ok) {
-                    convertJsps(webXml);
-                }
-                
-                // Step 9. Apply merged web.xml to Context
-                if (ok) {
-                    webXml.configureContext(context);
-    
-                    // Step 9a. Make the merged web.xml available to other
-                    // components, specifically Jasper, to save those components
-                    // from having to re-generate it.
-                    // TODO Use a ServletContainerInitializer for Jasper
-                    String mergedWebXml = webXml.toXml();
-                    context.getServletContext().setAttribute(
-                           org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML,
-                            mergedWebXml);
-                    if (context.getLogEffectiveWebXml()) {
-                        log.info("web.xml:\n" + mergedWebXml);
-                    }
-                }
-            } else {
-                webXml.merge(defaults);
-                webXml.configureContext(context);
-            }
-            
-            // Always need to look for static resources
-            // Step 10. Look for static resources packaged in JARs
-            if (ok) {
-                // Spec does not define an order.
-                // Use ordered JARs followed by remaining JARs
-                Set<WebXml> resourceJars = new LinkedHashSet<WebXml>();
-                if (orderedFragments != null) {
-                    for (WebXml fragment : orderedFragments) {
-                        resourceJars.add(fragment);
-                    }
-                }
-                for (WebXml fragment : fragments.values()) {
-                    if (!resourceJars.contains(fragment)) {
-                        resourceJars.add(fragment);
-                    }
-                }
-                processResourceJARs(resourceJars);
-                // See also StandardContext.resourcesStart() for
-                // WEB-INF/classes/META-INF/resources configuration
-            }
-            
-            // Only look for ServletContainerInitializer if metadata is not
-            // complete
-            if (!webXml.isMetadataComplete()) {
-                // Step 11. Apply the ServletContainerInitializer config to the
-                // context
-                if (ok) {
-                    for (Map.Entry<ServletContainerInitializer,
-                            Set<Class<?>>> entry : 
-                                initializerClassMap.entrySet()) {
-                        if (entry.getValue().isEmpty()) {
-                            context.addServletContainerInitializer(
-                                    entry.getKey(), null);
-                        } else {
-                            context.addServletContainerInitializer(
-                                    entry.getKey(), entry.getValue());
-                        }
-                    }
-                }
-            }
-        } else {
-            // Apply unmerged web.xml to Context
-            webXml.merge(defaults);
-            convertJsps(webXml);
-            webXml.configureContext(context);
-        }
-    }
-
-    private WebXml getDefaultWebXmlFragment() {
-
-        // Host should never be null
-        Host host = (Host) context.getParent();
-
-        DefaultWebXmlCacheEntry entry = hostWebXmlCache.get(host);
-        
-        InputSource globalWebXml = getGlobalWebXmlSource();
-        InputSource hostWebXml = getHostWebXmlSource();
-        
-        long globalTimeStamp = 0;
-        long hostTimeStamp = 0;
-        
-        if (globalWebXml != null) {
-            try {
-                File f = new File(new URI(globalWebXml.getSystemId()));
-                globalTimeStamp = f.lastModified();
-            } catch (URISyntaxException e) {
-                globalTimeStamp = -1;
-            }
-        }
-        
-        if (hostWebXml != null) {
-            try {
-                File f = new File(new URI(hostWebXml.getSystemId()));
-                hostTimeStamp = f.lastModified();
-            } catch (URISyntaxException e) {
-                hostTimeStamp = -1;
-            }
-        }
-        
-        if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp &&
-                entry.getHostTimeStamp() == hostTimeStamp) {
-            return entry.getWebXml();
-        }
-        
-        // Parsing global web.xml is relatively expensive. Use a sync block to
-        // make sure it only happens once
-        synchronized (host) {
-            entry = hostWebXmlCache.get(host);
-            if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp &&
-                    entry.getHostTimeStamp() == hostTimeStamp) {
-                return entry.getWebXml();
-            }
-
-            WebXml webXmlDefaultFragment = createWebXml();
-            webXmlDefaultFragment.setOverridable(true);
-            // Set to distributable else every app will be prevented from being
-            // distributable when the default fragment is merged with the main
-            // web.xml
-            webXmlDefaultFragment.setDistributable(true);
-            // When merging, the default welcome files are only used if the app has
-            // not defined any welcomes files.
-            webXmlDefaultFragment.setAlwaysAddWelcomeFiles(false);
-
-            // Parse global web.xml if present
-            if (globalWebXml == null) {
-                // This is unusual enough to log
-                log.info(sm.getString("contextConfig.defaultMissing"));
-            } else {
-                parseWebXml(globalWebXml, webXmlDefaultFragment, false);
-            }
-            
-            // Parse host level web.xml if present
-            // Additive apart from welcome pages
-            webXmlDefaultFragment.setReplaceWelcomeFiles(true);
-            
-            parseWebXml(hostWebXml, webXmlDefaultFragment, false);
-            
-            // Don't update the cache if an error occurs
-            if (globalTimeStamp != -1 && hostTimeStamp != -1) {
-                entry = new DefaultWebXmlCacheEntry(webXmlDefaultFragment,
-                        globalTimeStamp, hostTimeStamp);
-                hostWebXmlCache.put(host, entry);
-            }
-
-            return webXmlDefaultFragment;
-        }
-    }
-
-
-    private void convertJsps(WebXml webXml) {
-        Map<String,String> jspInitParams;
-        ServletDef jspServlet = webXml.getServlets().get("jsp");
-        if (jspServlet == null) {
-            jspInitParams = new HashMap<String,String>();
-            Wrapper w = (Wrapper) context.findChild("jsp");
-            if (w != null) {
-                String[] params = w.findInitParameters();
-                for (String param : params) {
-                    jspInitParams.put(param, w.findInitParameter(param));
-                }
-            }
-        } else {
-            jspInitParams = jspServlet.getParameterMap();
-        }
-        for (ServletDef servletDef: webXml.getServlets().values()) {
-            if (servletDef.getJspFile() != null) {
-                convertJsp(servletDef, jspInitParams);
-            }
-        }
-    }
-
-    private void convertJsp(ServletDef servletDef,
-            Map<String,String> jspInitParams) {
-        servletDef.setServletClass(org.apache.catalina.core.Constants.JSP_SERVLET_CLASS);
-        String jspFile = servletDef.getJspFile();
-        if ((jspFile != null) && !jspFile.startsWith("/")) {
-            if (context.isServlet22()) {
-                if(log.isDebugEnabled())
-                    log.debug(sm.getString("contextConfig.jspFile.warning",
-                                       jspFile));
-                jspFile = "/" + jspFile;
-            } else {
-                throw new IllegalArgumentException
-                    (sm.getString("contextConfig.jspFile.error", jspFile));
-            }
-        }
-        servletDef.getParameterMap().put("jspFile", jspFile);
-        servletDef.setJspFile(null);
-        for (Map.Entry<String, String> initParam: jspInitParams.entrySet()) {
-            servletDef.addInitParameter(initParam.getKey(), initParam.getValue());
-        }
-    }
-
-    protected WebXml createWebXml() {
-        return new WebXml();
-    }
-
-    /**
-     * Scan JARs for ServletContainerInitializer implementations.
-     * Implementations will be added in web-fragment.xml priority order.
-     */
-    protected void processServletContainerInitializers(
-            Set<WebXml> fragments) {
-        
-        for (WebXml fragment : fragments) {
-            URL url = fragment.getURL();
-            Jar jar = null;
-            InputStream is = null;
-            ServletContainerInitializer sci = null;
-            try {
-                if ("jar".equals(url.getProtocol())) {
-                    jar = JarFactory.newInstance(url);
-                    is = jar.getInputStream(SCI_LOCATION);
-                } else if ("file".equals(url.getProtocol())) {
-                    String path = url.getPath();
-                    File file = new File(path, SCI_LOCATION);
-                    if (file.exists()) {
-                        is = new FileInputStream(file);
-                    }
-                }
-                if (is != null) {
-                    sci = getServletContainerInitializer(is);
-                }
-            } catch (IOException ioe) {
-                log.error(sm.getString(
-                        "contextConfig.servletContainerInitializerFail", url,
-                        context.getName()));
-                ok = false;
-                return;
-            } finally {
-                if (is != null) {
-                    try {
-                        is.close();
-                    } catch (IOException e) {
-                        // Ignore
-                    }
-                }
-                if (jar != null) {
-                    jar.close();
-                }
-            }
-            
-            if (sci == null) {
-                continue;
-            }
-
-            initializerClassMap.put(sci, new HashSet<Class<?>>());
-            
-            HandlesTypes ht =
-                sci.getClass().getAnnotation(HandlesTypes.class);
-            if (ht != null) {
-                Class<?>[] types = ht.value();
-                if (types != null) {
-                    for (Class<?> type : types) {
-                        Set<ServletContainerInitializer> scis =
-                            typeInitializerMap.get(type);
-                        if (scis == null) {
-                            scis = new HashSet<ServletContainerInitializer>();
-                            typeInitializerMap.put(type, scis);
-                        }
-                        scis.add(sci);
-                    }
-                }
-            }
-
-        }
-    }
-    
-    
-    /**
-     * Extract the name of the ServletContainerInitializer.
-     * 
-     * @param is    The resource where the name is defined 
-     * @return      The class name
-     * @throws IOException
-     */
-    protected ServletContainerInitializer getServletContainerInitializer(
-            InputStream is) throws IOException {
-
-        String className = null;
-        
-        if (is != null) {
-            String line = null;
-            try {
-                BufferedReader br =
-                    new BufferedReader(new InputStreamReader(is, "UTF-8"));
-                line = br.readLine();
-                if (line != null && line.trim().length() > 0) {
-                    className = line.trim();
-                }
-            } catch (UnsupportedEncodingException e) {
-                // Should never happen with UTF-8
-                // If it does - ignore & return null
-            }
-        }
-        
-        ServletContainerInitializer sci = null;
-        try {
-            Class<?> clazz = Class.forName(className,true,
-                    context.getLoader().getClassLoader());
-             sci = (ServletContainerInitializer) clazz.newInstance();
-        } catch (ClassNotFoundException e) {
-            log.error(sm.getString("contextConfig.invalidSci", className), e);
-            throw new IOException(e);
-        } catch (InstantiationException e) {
-            log.error(sm.getString("contextConfig.invalidSci", className), e);
-            throw new IOException(e);
-        } catch (IllegalAccessException e) {
-            log.error(sm.getString("contextConfig.invalidSci", className), e);
-            throw new IOException(e);
-        }
-        
-        return sci;
-    }
-
-    
-    /**
-     * Scan JARs that contain web-fragment.xml files that will be used to
-     * configure this application to see if they also contain static resources.
-     * If static resources are found, add them to the context. Resources are
-     * added in web-fragment.xml priority order.
-     */
-    protected void processResourceJARs(Set<WebXml> fragments) {
-        for (WebXml fragment : fragments) {
-            URL url = fragment.getURL();
-            Jar jar = null;
-            try {
-                // Note: Ignore file URLs for now since only jar URLs will be accepted
-                if ("jar".equals(url.getProtocol())) {
-                    jar = JarFactory.newInstance(url);
-                    if (jar.entryExists("META-INF/resources/")) {
-                        context.addResourceJarUrl(url);
-                    }
-                }
-            } catch (IOException ioe) {
-                log.error(sm.getString("contextConfig.resourceJarFail", url,
-                        context.getName()));
-            } finally {
-                if (jar != null) {
-                    jar.close();
-                }
-            }
-        }
-    }
-    
-    
-    /**
-     * Identify the default web.xml to be used and obtain an input source for
-     * it.
-     */
-    protected InputSource getGlobalWebXmlSource() {
-        // Is a default web.xml specified for the Context?
-        if (defaultWebXml == null && context instanceof StandardContext) {
-            defaultWebXml = ((StandardContext) context).getDefaultWebXml();
-        }
-        // Set the default if we don't have any overrides
-        if (defaultWebXml == null) getDefaultWebXml();
-
-        // Is it explicitly suppressed, e.g. in embedded environment?
-        if (Constants.NoDefaultWebXml.equals(defaultWebXml)) {
-            return null;
-        }
-        return getWebXmlSource(defaultWebXml, getBaseDir());
-    }
-    
-    
-    /**
-     * Identify the host web.xml to be used and obtain an input source for
-     * it.
-     */
-    protected InputSource getHostWebXmlSource() {
-        String resourceName = getHostConfigPath(Constants.HostWebXml);
-        
-        // In an embedded environment, configBase might not be set
-        File configBase = getConfigBase();
-        if (configBase == null)
-            return null;
-        
-        String basePath = null;
-        try {
-            basePath = configBase.getCanonicalPath();
-        } catch (IOException e) {
-            log.error(sm.getString("contectConfig.baseError"), e);
-            return null;
-        }
-
-        return getWebXmlSource(resourceName, basePath);
-    }
-    
-    /**
-     * Identify the application web.xml to be used and obtain an input source
-     * for it.
-     */
-    protected InputSource getContextWebXmlSource() {
-        InputStream stream = null;
-        InputSource source = null;
-        URL url = null;
-        
-        String altDDName = null;
-
-        // Open the application web.xml file, if it exists
-        ServletContext servletContext = context.getServletContext();
-        if (servletContext != null) {
-            altDDName = (String)servletContext.getAttribute(
-                                                        Globals.ALT_DD_ATTR);
-            if (altDDName != null) {
-                try {
-                    stream = new FileInputStream(altDDName);
-                    url = new File(altDDName).toURI().toURL();
-                } catch (FileNotFoundException e) {
-                    log.error(sm.getString("contextConfig.altDDNotFound",
-                                           altDDName));
-                } catch (MalformedURLException e) {
-                    log.error(sm.getString("contextConfig.applicationUrl"));
-                }
-            }
-            else {
-                stream = servletContext.getResourceAsStream
-                    (Constants.ApplicationWebXml);
-                try {
-                    url = servletContext.getResource(
-                            Constants.ApplicationWebXml);
-                } catch (MalformedURLException e) {
-                    log.error(sm.getString("contextConfig.applicationUrl"));
-                }
-            }
-        }
-        if (stream == null || url == null) {
-            if (log.isDebugEnabled()) {
-                log.debug(sm.getString("contextConfig.applicationMissing") + " " + context);
-            }
-        } else {
-            source = new InputSource(url.toExternalForm());
-            source.setByteStream(stream);
-        }
-        
-        return source;
-    }
-    
-    /**
-     * 
-     * @param filename  Name of the file (possibly with one or more leading path
-     *                  segments) to read
-     * @param path      Location that filename is relative to 
-     */
-    protected InputSource getWebXmlSource(String filename, String path) {
-        File file = new File(filename);
-        if (!file.isAbsolute()) {
-            file = new File(path, filename);
-        }
-
-        InputStream stream = null;
-        InputSource source = null;
-
-        try {
-            if (!file.exists()) {
-                // Use getResource and getResourceAsStream
-                stream =
-                    getClass().getClassLoader().getResourceAsStream(filename);
-                if(stream != null) {
-                    source =
-                        new InputSource(getClass().getClassLoader().getResource(
-                                filename).toURI().toString());
-                } 
-            } else {
-                source = new InputSource(file.getAbsoluteFile().toURI().toString());
-                stream = new FileInputStream(file);
-                context.addWatchedResource(file.getAbsolutePath());
-            }
-
-            if (stream != null && source != null) {
-                source.setByteStream(stream);
-            }
-        } catch (Exception e) {
-            log.error(sm.getString(
-                    "contextConfig.defaultError", filename, file), e);
-        }
-
-        return source;
-    }
-
-
-    protected void parseWebXml(InputSource source, WebXml dest,
-            boolean fragment) {
-        
-        if (source == null) return;
-
-        XmlErrorHandler handler = new XmlErrorHandler();
-
-        // Web digesters and rulesets are shared between contexts but are not
-        // thread safe. Whilst there should only be one thread at a time
-        // processing a config, play safe and sync.
-        Digester digester;
-        WebRuleSet ruleSet;
-        if (fragment) {
-            digester = webFragmentDigester;
-            ruleSet = webFragmentRuleSet;
-        } else {
-            digester = webDigester;
-            ruleSet = webRuleSet;
-        }
-        
-        // Sync on the ruleSet since the same ruleSet is shared across all four
-        // digesters
-        synchronized(ruleSet) {
-            
-            digester.push(dest);
-            digester.setErrorHandler(handler);
-            
-            if(log.isDebugEnabled()) {
-                log.debug(sm.getString("contextConfig.applicationStart",
-                        source.getSystemId()));
-            }
-
-            try {
-                digester.parse(source);
-
-                if (handler.getWarnings().size() > 0 ||
-                        handler.getErrors().size() > 0) {
-                    ok = false;
-                    handler.logFindings(log, source.getSystemId());
-                }
-            } catch (SAXParseException e) {
-                log.error(sm.getString("contextConfig.applicationParse",
-                        source.getSystemId()), e);
-                log.error(sm.getString("contextConfig.applicationPosition",
-                                 "" + e.getLineNumber(),
-                                 "" + e.getColumnNumber()));
-                ok = false;
-            } catch (Exception e) {
-                log.error(sm.getString("contextConfig.applicationParse",
-                        source.getSystemId()), e);
-                ok = false;
-            } finally {
-                digester.reset();
-                ruleSet.recycle();
-            }
-        }
-    }
-
-
-    /**
-     * Scan /META-INF/lib for JARs and for each one found add it and any
-     * /META-INF/web-fragment.xml to the resulting Map. web-fragment.xml files
-     * will be parsed before being added to the map. Every JAR will be added and
-     * <code>null</code> will be used if no web-fragment.xml was found. Any JARs
-     * known not contain fragments will be skipped.
-     * 
-     * @return A map of JAR name to processed web fragment (if any)
-     */
-    protected Map<String,WebXml> processJarsForWebFragments() {
-        
-        JarScanner jarScanner = context.getJarScanner();
-        FragmentJarScannerCallback callback = new FragmentJarScannerCallback();
-        
-        jarScanner.scan(context.getServletContext(),
-                context.getLoader().getClassLoader(), callback, null);
-        
-        return callback.getFragments();
-    }
-
-    protected void processAnnotations(Set<WebXml> fragments) {
-        for(WebXml fragment : fragments) {
-            if (!fragment.isMetadataComplete()) {
-                WebXml annotations = new WebXml();
-                // no impact on distributable
-                annotations.setDistributable(true);
-                URL url = fragment.getURL();
-                processAnnotationsUrl(url, annotations);
-                Set<WebXml> set = new HashSet<WebXml>();
-                set.add(annotations);
-                // Merge annotations into fragment - fragment takes priority
-                fragment.merge(set);
-            }
-        }
-    }
-
-    protected void processAnnotationsUrl(URL url, WebXml fragment) {
-        if (url == null) {
-            // Nothing to do.
-            return;
-        } else if ("jar".equals(url.getProtocol())) {
-            processAnnotationsJar(url, fragment);
-        } else if ("jndi".equals(url.getProtocol())) {
-            processAnnotationsJndi(url, fragment);
-        } else if ("file".equals(url.getProtocol())) {
-            try {
-                processAnnotationsFile(new File(url.toURI()), fragment);
-            } catch (URISyntaxException e) {
-                log.error(sm.getString("contextConfig.fileUrl", url), e);
-            }
-        } else {
-            log.error(sm.getString("contextConfig.unknownUrlProtocol",
-                    url.getProtocol(), url));
-        }
-        
-    }
-
-
-    protected void processAnnotationsJar(URL url, WebXml fragment) {
-
-        Jar jar = null;
-        InputStream is;
-        
-        try {
-            jar = JarFactory.newInstance(url);
-            
-            jar.nextEntry();
-            String entryName = jar.getEntryName();
-            while (entryName != null) {
-                if (entryName.endsWith(".class")) {
-                    is = null;
-                    try {
-                        is = jar.getEntryInputStream();
-                        processAnnotationsStream(is, fragment);
-                    } catch (IOException e) {
-                        log.error(sm.getString("contextConfig.inputStreamJar",
-                                entryName, url),e);
-                    } finally {
-                        if (is != null) {
-                            try {
-                                is.close();
-                            } catch (IOException ioe) {
-                                // Ignore
-                            }
-                        }
-                    }
-                }
-                jar.nextEntry();
-                entryName = jar.getEntryName();
-            }
-        } catch (IOException e) {
-            log.error(sm.getString("contextConfig.jarFile", url), e);
-        } finally {
-            if (jar != null) {
-                jar.close();
-            }
-        }
-    }
-
-    
-    protected void processAnnotationsJndi(URL url, WebXml fragment) {
-        try {
-            URLConnection urlConn = url.openConnection();
-            DirContextURLConnection dcUrlConn;
-            if (!(urlConn instanceof DirContextURLConnection)) {
-                // This should never happen
-                sm.getString("contextConfig.jndiUrlNotDirContextConn", url);
-                return;
-            }
-            
-            dcUrlConn = (DirContextURLConnection) urlConn;
-            dcUrlConn.setUseCaches(false);
-            
-            String type = dcUrlConn.getHeaderField(ResourceAttributes.TYPE);
-            if (ResourceAttributes.COLLECTION_TYPE.equals(type)) {
-                // Collection
-                Enumeration<String> dirs = dcUrlConn.list();
-                while (dirs.hasMoreElements()) {
-                    String dir = dirs.nextElement();
-                    URL dirUrl = new URL(url.toString() + '/' + dir);
-                    processAnnotationsJndi(dirUrl, fragment);
-                }
-                
-            } else {
-                // Single file
-                if (url.getPath().endsWith(".class")) {
-                    InputStream is = null;
-                    try {
-                        is = dcUrlConn.getInputStream();
-                        processAnnotationsStream(is, fragment);
-                    } catch (IOException e) {
-                        log.error(sm.getString("contextConfig.inputStreamJndi",
-                                url),e);
-                    } finally {
-                        if (is != null) {
-                            try {
-                                is.close();
-                            } catch (Throwable t) {
-                                ExceptionUtils.handleThrowable(t);
-                            }
-                        }
-                    }
-                }
-            }
-        } catch (IOException e) {
-            log.error(sm.getString("contextConfig.jndiUrl", url), e);
-        }
-    }
-    
-    
-    protected void processAnnotationsFile(File file, WebXml fragment) {
-        
-        if (file.isDirectory()) {
-            String[] dirs = file.list();
-            for (String dir : dirs) {
-                processAnnotationsFile(new File(file,dir), fragment);
-            }
-        } else if (file.canRead() && file.getName().endsWith(".class")) {
-            FileInputStream fis = null;
-            try {
-                fis = new FileInputStream(file);
-                processAnnotationsStream(fis, fragment);
-            } catch (IOException e) {
-                log.error(sm.getString("contextConfig.inputStreamFile",
-                        file.getAbsolutePath()),e);
-            } finally {
-                if (fis != null) {
-                    try {
-                        fis.close();
-                    } catch (Throwable t) {
-                        ExceptionUtils.handleThrowable(t);
-                    }
-                }
-            }
-        }
-    }
-
-
-    protected void processAnnotationsStream(InputStream is, WebXml fragment)
-            throws ClassFormatException, IOException {
-        
-        ClassParser parser = new ClassParser(is, null);
-        JavaClass clazz = parser.parse();
-        
-        checkHandlesTypes(clazz);
-        
-        String className = clazz.getClassName();
-        
-        AnnotationEntry[] annotationsEntries = clazz.getAnnotationEntries();
-
-        for (AnnotationEntry ae : annotationsEntries) {
-            String type = ae.getAnnotationType();
-            if ("Ljavax/servlet/annotation/WebServlet;".equals(type)) {
-                processAnnotationWebServlet(className, ae, fragment);
-            }else if ("Ljavax/servlet/annotation/WebFilter;".equals(type)) {
-                processAnnotationWebFilter(className, ae, fragment);
-            }else if ("Ljavax/servlet/annotation/WebListener;".equals(type)) {
-                fragment.addListener(className);
-            } else {
-                // Unknown annotation - ignore
-            }
-        }
-    }
-
-    /**
-     * For classes packaged with the web application, the class and each
-     * super class needs to be checked for a match with {@link HandlesTypes} or
-     * for an annotation that matches {@link HandlesTypes}.
-     * @param javaClass
-     */
-    protected void checkHandlesTypes(JavaClass javaClass) {
-        
-        // Skip this if we can
-        if (typeInitializerMap.size() == 0)
-            return;
-        
-        // No choice but to load the class
-        String className = javaClass.getClassName();
-        
-        Class<?> clazz = null;
-        try {
-            clazz = context.getLoader().getClassLoader().loadClass(className);
-        } catch (NoClassDefFoundError e) {
-            log.debug(sm.getString("contextConfig.invalidSciHandlesTypes",
-                    className), e);
-            return;
-        } catch (ClassNotFoundException e) {
-            log.warn(sm.getString("contextConfig.invalidSciHandlesTypes",
-                    className), e);
-            return;
-        } catch (ClassFormatError e) {
-            log.warn(sm.getString("contextConfig.invalidSciHandlesTypes",
-                    className), e);
-            return;
-        } catch (Throwable t) {
-            ExceptionUtils.handleThrowable(t);
-            log.warn(sm.getString("contextConfig.invalidSciHandlesTypes",
-                    className), t);
-            return;
-        }
-
-        if (clazz.isAnnotation()) {
-            // Skip
-            return;
-        }
-        
-        boolean match = false;
-        
-        for (Map.Entry<Class<?>, Set<ServletContainerInitializer>> entry :
-                typeInitializerMap.entrySet()) {
-            if (entry.getKey().isAnnotation()) {
-                AnnotationEntry[] annotationEntries = javaClass.getAnnotationEntries();
-                for (AnnotationEntry annotationEntry : annotationEntries) {
-                    if (entry.getKey().getName().equals(
-                        getClassName(annotationEntry.getAnnotationType()))) {
-                        match = true;
-                        break;
-                    }
-                }
-            } else if (entry.getKey().isAssignableFrom(clazz)) {
-                match = true;
-            }
-            if (match) {
-                for (ServletContainerInitializer sci : entry.getValue()) {
-                    initializerClassMap.get(sci).add(clazz);
-                }
-                match = false;
-            }
-        }
-    }
-
-    private static final String getClassName(String internalForm) {
-        if (!internalForm.startsWith("L")) {
-            return internalForm;
-        }
-        
-        // Assume starts with L, ends with ; and uses / rather than .
-        return internalForm.substring(1,
-                internalForm.length() - 1).replace('/', '.');
-    }
-
-    protected void processAnnotationWebServlet(String className,
-            AnnotationEntry ae, WebXml fragment) {
-        String servletName = null;
-        // must search for name s. Spec Servlet API 3.0 - 8.2.3.3.n.ii page 81
-        ElementValuePair[] evps = ae.getElementValuePairs();
-        for (ElementValuePair evp : evps) {
-            String name = evp.getNameString();
-            if ("name".equals(name)) {
-                servletName = evp.getValue().stringifyValue();
-                break;
-            }
-        }
-        if (servletName == null) {
-            // classname is default servletName as annotation has no name!
-            servletName = className;
-        }
-        ServletDef servletDef = fragment.getServlets().get(servletName);
-        
-        boolean isWebXMLservletDef;
-        if (servletDef == null) {
-            servletDef = new ServletDef();
-            servletDef.setServletName(servletName);
-            servletDef.setServletClass(className);
-            isWebXMLservletDef = false;
-        } else {
-            isWebXMLservletDef = true;
-        }
-
-        boolean urlPatternsSet = false;
-        String[] urlPatterns = null;
-
-        // ElementValuePair[] evps = ae.getElementValuePairs();
-        for (ElementValuePair evp : evps) {
-            String name = evp.getNameString();
-            if ("value".equals(name) || "urlPatterns".equals(name)) {
-                if (urlPatternsSet) {
-                    throw new IllegalArgumentException(sm.getString(
-                            "contextConfig.urlPatternValue", className));
-                }
-                urlPatternsSet = true;
-                urlPatterns = processAnnotationsStringArray(evp.getValue());
-            } else if ("description".equals(name)) {
-                if (servletDef.getDescription() == null) {
-                    servletDef.setDescription(evp.getValue().stringifyValue());
-                }
-            } else if ("displayName".equals(name)) {
-                if (servletDef.getDisplayName() == null) {
-                    servletDef.setDisplayName(evp.getValue().stringifyValue());
-                }
-            } else if ("largeIcon".equals(name)) {
-                if (servletDef.getLargeIcon() == null) {
-                    servletDef.setLargeIcon(evp.getValue().stringifyValue());
-                }
-            } else if ("smallIcon".equals(name)) {
-                if (servletDef.getSmallIcon() == null) {
-                    servletDef.setSmallIcon(evp.getValue().stringifyValue());
-                }
-            } else if ("asyncSupported".equals(name)) {
-                if (servletDef.getAsyncSupported() == null) {
-                    servletDef.setAsyncSupported(evp.getValue()
-                            .stringifyValue());
-                }
-            } else if ("loadOnStartup".equals(name)) {
-                if (servletDef.getLoadOnStartup() == null) {
-                    servletDef
-                            .setLoadOnStartup(evp.getValue().stringifyValue());
-                }
-            } else if ("initParams".equals(name)) {
-                Map<String, String> initParams = processAnnotationWebInitParams(evp
-                        .getValue());
-                if (isWebXMLservletDef) {
-                    Map<String, String> webXMLInitParams = servletDef
-                            .getParameterMap();
-                    for (Map.Entry<String, String> entry : initParams
-                            .entrySet()) {
-                        if (webXMLInitParams.get(entry.getKey()) == null) {
-                            servletDef.addInitParameter(entry.getKey(), entry
-                                    .getValue());
-                        }
-                    }
-                } else {
-                    for (Map.Entry<String, String> entry : initParams
-                            .entrySet()) {
-                        servletDef.addInitParameter(entry.getKey(), entry
-                                .getValue());
-                    }
-                }
-            }
-        }
-        if (!isWebXMLservletDef && urlPatterns != null) {
-            fragment.addServlet(servletDef);
-        }
-        if (urlPatterns != null) {
-            if (!fragment.getServletMappings().containsValue(servletName)) {
-                for (String urlPattern : urlPatterns) {
-                    fragment.addServletMapping(urlPattern, servletName);
-                }
-            }
-        }
-
-    }
-
-    /**
-     * process filter annotation and merge with existing one!
-     * FIXME: refactoring method to long and has redundant subroutines with processAnnotationWebServlet!
-     * @param className
-     * @param ae
-     * @param fragment
-     */
-    protected void processAnnotationWebFilter(String className,
-            AnnotationEntry ae, WebXml fragment) {
-        String filterName = null;
-        // must search for name s. Spec Servlet API 3.0 - 8.2.3.3.n.ii page 81
-        ElementValuePair[] evps = ae.getElementValuePairs();
-        for (ElementValuePair evp : evps) {
-            String name = evp.getNameString();
-            if ("filterName".equals(name)) {
-                filterName = evp.getValue().stringifyValue();
-                break;
-            }
-        }
-        if (filterName == null) {
-            // classname is default filterName as annotation has no name!
-            filterName = className;
-        }
-        FilterDef filterDef = fragment.getFilters().get(filterName);
-        FilterMap filterMap = new FilterMap();
-
-        boolean isWebXMLfilterDef;
-        if (filterDef == null) {
-            filterDef = new FilterDef();
-            filterDef.setFilterName(filterName);
-            filterDef.setFilterClass(className);
-            isWebXMLfilterDef = false;
-        } else {
-            isWebXMLfilterDef = true;
-        }
-
-        boolean urlPatternsSet = false;
-        boolean dispatchTypesSet = false;
-        String[] urlPatterns = null;
-
-        for (ElementValuePair evp : evps) {
-            String name = evp.getNameString();
-            if ("value".equals(name) || "urlPatterns".equals(name)) {
-                if (urlPatternsSet) {
-                    throw new IllegalArgumentException(sm.getString(
-                            "contextConfig.urlPatternValue", className));
-                }
-                urlPatterns = processAnnotationsStringArray(evp.getValue());
-                urlPatternsSet = urlPatterns.length > 0;
-                for (String urlPattern : urlPatterns) {
-                    filterMap.addURLPattern(urlPattern);
-                }
-            } else if ("servletNames".equals(name)) {
-                String[] servletNames = processAnnotationsStringArray(evp
-                        .getValue());
-                for (String servletName : servletNames) {
-                    filterMap.addServletName(servletName);
-                }
-            } else if ("dispatcherTypes".equals(name)) {
-                String[] dispatcherTypes = processAnnotationsStringArray(evp
-                        .getValue());
-                dispatchTypesSet = dispatcherTypes.length > 0;
-                for (String dispatcherType : dispatcherTypes) {
-                    filterMap.setDispatcher(dispatcherType);
-                }
-            } else if ("description".equals(name)) {
-                if (filterDef.getDescription() == null) {
-                    filterDef.setDescription(evp.getValue().stringifyValue());
-                }
-            } else if ("displayName".equals(name)) {
-                if (filterDef.getDisplayName() == null) {
-                    filterDef.setDisplayName(evp.getValue().stringifyValue());
-                }
-            } else if ("largeIcon".equals(name)) {
-                if (filterDef.getLargeIcon() == null) {
-                    filterDef.setLargeIcon(evp.getValue().stringifyValue());
-                }
-            } else if ("smallIcon".equals(name)) {
-                if (filterDef.getSmallIcon() == null) {
-                    filterDef.setSmallIcon(evp.getValue().stringifyValue());
-                }
-            } else if ("asyncSupported".equals(name)) {
-                if (filterDef.getAsyncSupported() == null) {
-                    filterDef
-                            .setAsyncSupported(evp.getValue().stringifyValue());
-                }
-            } else if ("initParams".equals(name)) {
-                Map<String, String> initParams = processAnnotationWebInitParams(evp
-                        .getValue());
-                if (isWebXMLfilterDef) {
-                    Map<String, String> webXMLInitParams = filterDef
-                            .getParameterMap();
-                    for (Map.Entry<String, String> entry : initParams
-                            .entrySet()) {
-                        if (webXMLInitParams.get(entry.getKey()) == null) {
-                            filterDef.addInitParameter(entry.getKey(), entry
-                                    .getValue());
-                        }
-                    }
-                } else {
-                    for (Map.Entry<String, String> entry : initParams
-                            .entrySet()) {
-                        filterDef.addInitParameter(entry.getKey(), entry
-                                .getValue());
-                    }
-                }
-
-            }
-        }
-        if (!isWebXMLfilterDef) {
-            fragment.addFilter(filterDef);
-            filterMap.setFilterName(filterName);
-            fragment.addFilterMapping(filterMap);
-        }
-        if (urlPatternsSet || dispatchTypesSet) {
-            Set<FilterMap> fmap = fragment.getFilterMappings();
-            FilterMap descMap = null;
-            for (FilterMap map : fmap) {
-                if (filterName.equals(map.getFilterName())) {
-                    descMap = map;
-                    break;
-                }
-            }
-            if (descMap != null) {
-                String[] urlsPatterns = descMap.getURLPatterns();
-                if (urlPatternsSet
-                        && (urlsPatterns == null || urlsPatterns.length == 0)) {
-                    for (String urlPattern : filterMap.getURLPatterns()) {
-                        descMap.addURLPattern(urlPattern);
-                    }
-                }
-                String[] dispatcherNames = descMap.getDispatcherNames();
-                if (dispatchTypesSet
-                        && (dispatcherNames == null || dispatcherNames.length == 0)) {
-                    for (String dis : filterMap.getDispatcherNames()) {
-                        descMap.setDispatcher(dis);
-                    }
-                }
-            }
-        }
-
-    }
-
-    protected String[] processAnnotationsStringArray(ElementValue ev) {
-        ArrayList<String> values = new ArrayList<String>();
-        if (ev instanceof ArrayElementValue) {
-            ElementValue[] arrayValues =
-                ((ArrayElementValue) ev).getElementValuesArray();
-            for (ElementValue value : arrayValues) {
-                values.add(value.stringifyValue());
-            }
-        } else {
-            values.add(ev.stringifyValue());
-        }
-        String[] result = new String[values.size()];
-        return values.toArray(result);
-    }
-    
-    protected Map<String,String> processAnnotationWebInitParams(
-            ElementValue ev) {
-        Map<String, String> result = new HashMap<String,String>();
-        if (ev instanceof ArrayElementValue) {
-            ElementValue[] arrayValues =
-                ((ArrayElementValue) ev).getElementValuesArray();
-            for (ElementValue value : arrayValues) {
-                if (value instanceof AnnotationElementValue) {
-                    ElementValuePair[] evps = ((AnnotationElementValue)
-                            value).getAnnotationEntry().getElementValuePairs();
-                    String initParamName = null;
-                    String initParamValue = null;
-                    for (ElementValuePair evp : evps) {
-                        if ("name".equals(evp.getNameString())) {
-                            initParamName = evp.getValue().stringifyValue();
-                        } else if ("value".equals(evp.getNameString())) {
-                            initParamValue = evp.getValue().stringifyValue();
-                        } else {
-                            // Ignore
-                        }
-                    }
-                    result.put(initParamName, initParamValue);
-                }
-            }
-        }
-        return result;
-    }
-    
-    private class FragmentJarScannerCallback implements JarScannerCallback {
-
-        private static final String FRAGMENT_LOCATION =
-            "META-INF/web-fragment.xml";
-        private Map<String,WebXml> fragments = new HashMap<String,WebXml>();
-        
-        @Override
-        public void scan(JarURLConnection jarConn) throws IOException {
-            
-            URL url = jarConn.getURL();
-            URL resourceURL = jarConn.getJarFileURL();
-            Jar jar = null;
-            InputStream is = null;
-            WebXml fragment = new WebXml();
-
-            try {
-                jar = JarFactory.newInstance(url);
-                is = jar.getInputStream(FRAGMENT_LOCATION);
-
-                if (is == null) {
-                    // If there is no web.xml, normal JAR no impact on
-                    // distributable
-                    fragment.setDistributable(true);
-                } else {
-                    InputSource source = new InputSource(
-                            resourceURL.toString() + "!/" + FRAGMENT_LOCATION);
-                    source.setByteStream(is);
-                    parseWebXml(source, fragment, true);
-                }
-            } finally {
-                if (is != null) {
-                    try {
-                        is.close();
-                    } catch (IOException ioe) {
-                        // Ignore
-                    }
-                }
-                if (jar != null) {
-                    jar.close();
-                }
-                fragment.setURL(url);
-                if (fragment.getName() == null) {
-                    fragment.setName(fragment.getURL().toString());
-                }
-                fragments.put(fragment.getName(), fragment);
-            }
-        }
-
-        @Override
-        public void scan(File file) throws IOException {
-
-            InputStream stream = null;
-            WebXml fragment = new WebXml();
-            
-            try {
-                File fragmentFile = new File(file, FRAGMENT_LOCATION);
-                if (fragmentFile.isFile()) {
-                    stream = new FileInputStream(fragmentFile);
-                    InputSource source =
-                        new InputSource(fragmentFile.toURI().toURL().toString());
-                    source.setByteStream(stream);
-                    parseWebXml(source, fragment, true);
-                }
-            } finally {
-                if (stream != null) {
-                    try {
-                        stream.close();
-                    } catch (Throwable t) {
-                        ExceptionUtils.handleThrowable(t);
-                    }
-                }
-                fragment.setURL(file.toURI().toURL());
-                if (fragment.getName() == null) {
-                    fragment.setName(fragment.getURL().toString());
-                }
-                fragments.put(fragment.getName(), fragment);
-            }
-        }
-        
-        public Map<String,WebXml> getFragments() {
-            return fragments;
-        }
-    }
-
-    private static class DefaultWebXmlCacheEntry {
-        private final WebXml webXml;
-        private final long globalTimeStamp;
-        private final long hostTimeStamp;
-
-        public DefaultWebXmlCacheEntry(WebXml webXml, long globalTimeStamp,
-                long hostTimeStamp) {
-            this.webXml = webXml;
-            this.globalTimeStamp = globalTimeStamp;
-            this.hostTimeStamp = hostTimeStamp;
-        }
-
-        public WebXml getWebXml() {
-            return webXml;
-        }
-
-        public long getGlobalTimeStamp() {
-            return globalTimeStamp;
-        }
-
-        public long getHostTimeStamp() {
-            return hostTimeStamp;
-        }
-    }
-}
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+\r
+package org.apache.catalina.startup;\r
+\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.InputStreamReader;\r
+import java.io.UnsupportedEncodingException;\r
+import java.net.JarURLConnection;\r
+import java.net.MalformedURLException;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.net.URL;\r
+import java.net.URLConnection;\r
+import java.util.ArrayList;\r
+import java.util.Enumeration;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.LinkedHashMap;\r
+import java.util.LinkedHashSet;\r
+import java.util.List;\r
+import java.util.Locale;\r
+import java.util.Map;\r
+import java.util.Properties;\r
+import java.util.Set;\r
+import java.util.concurrent.ConcurrentHashMap;\r
+\r
+import javax.servlet.ServletContainerInitializer;\r
+import javax.servlet.ServletContext;\r
+import javax.servlet.annotation.HandlesTypes;\r
+\r
+import org.apache.catalina.Authenticator;\r
+import org.apache.catalina.Container;\r
+import org.apache.catalina.Context;\r
+import org.apache.catalina.Engine;\r
+import org.apache.catalina.Globals;\r
+import org.apache.catalina.Host;\r
+import org.apache.catalina.Lifecycle;\r
+import org.apache.catalina.LifecycleEvent;\r
+import org.apache.catalina.LifecycleListener;\r
+import org.apache.catalina.Pipeline;\r
+import org.apache.catalina.Server;\r
+import org.apache.catalina.Service;\r
+import org.apache.catalina.Valve;\r
+import org.apache.catalina.Wrapper;\r
+import org.apache.catalina.core.ContainerBase;\r
+import org.apache.catalina.core.StandardContext;\r
+import org.apache.catalina.core.StandardEngine;\r
+import org.apache.catalina.core.StandardHost;\r
+import org.apache.catalina.deploy.ErrorPage;\r
+import org.apache.catalina.deploy.FilterDef;\r
+import org.apache.catalina.deploy.FilterMap;\r
+import org.apache.catalina.deploy.LoginConfig;\r
+import org.apache.catalina.deploy.SecurityConstraint;\r
+import org.apache.catalina.deploy.ServletDef;\r
+import org.apache.catalina.deploy.WebXml;\r
+import org.apache.catalina.util.ContextName;\r
+import org.apache.juli.logging.Log;\r
+import org.apache.juli.logging.LogFactory;\r
+import org.apache.naming.resources.DirContextURLConnection;\r
+import org.apache.naming.resources.ResourceAttributes;\r
+import org.apache.tomcat.JarScanner;\r
+import org.apache.tomcat.JarScannerCallback;\r
+import org.apache.tomcat.util.ExceptionUtils;\r
+import org.apache.tomcat.util.bcel.classfile.AnnotationElementValue;\r
+import org.apache.tomcat.util.bcel.classfile.AnnotationEntry;\r
+import org.apache.tomcat.util.bcel.classfile.ArrayElementValue;\r
+import org.apache.tomcat.util.bcel.classfile.ClassFormatException;\r
+import org.apache.tomcat.util.bcel.classfile.ClassParser;\r
+import org.apache.tomcat.util.bcel.classfile.ElementValue;\r
+import org.apache.tomcat.util.bcel.classfile.ElementValuePair;\r
+import org.apache.tomcat.util.bcel.classfile.JavaClass;\r
+import org.apache.tomcat.util.digester.Digester;\r
+import org.apache.tomcat.util.digester.RuleSet;\r
+import org.apache.tomcat.util.res.StringManager;\r
+import org.apache.tomcat.util.scan.Jar;\r
+import org.apache.tomcat.util.scan.JarFactory;\r
+import org.xml.sax.InputSource;\r
+import org.xml.sax.SAXParseException;\r
+\r
+/**\r
+ * Startup event listener for a <b>Context</b> that configures the properties\r
+ * of that Context, and the associated defined servlets.\r
+ *\r
+ * @author Craig R. McClanahan\r
+ * @author Jean-Francois Arcand\r
+ * @version $Id$\r
+ */\r
+\r
+public class ContextConfig\r
+    implements LifecycleListener {\r
+\r
+    private static final Log log = LogFactory.getLog( ContextConfig.class );\r
+    \r
+    private static final String SCI_LOCATION =\r
+        "META-INF/services/javax.servlet.ServletContainerInitializer";\r
+\r
+\r
+    /**\r
+     * The string resources for this package.\r
+     */\r
+    protected static final StringManager sm =\r
+        StringManager.getManager(Constants.Package);\r
+\r
+\r
+    protected static final LoginConfig DUMMY_LOGIN_CONFIG =\r
+        new LoginConfig("NONE", null, null, null);\r
+\r
+    /**\r
+     * The <code>Digester</code> we will use to process web application\r
+     * context files.\r
+     */\r
+    protected static Digester contextDigester = null;\r
+    \r
+\r
+    /**\r
+     * The set of Authenticators that we know how to configure.  The key is\r
+     * the name of the implemented authentication method, and the value is\r
+     * the fully qualified Java class name of the corresponding Valve.\r
+     */\r
+    protected static Properties authenticators = null;\r
+\r
+\r
+    /**\r
+     * The <code>Digester</code>s available to process web deployment descriptor\r
+     * files.\r
+     */\r
+    protected static Digester[] webDigesters = new Digester[4];\r
+\r
+\r
+    /**\r
+     * The <code>Digester</code>s available to process web fragment deployment\r
+     * descriptor files.\r
+     */\r
+    protected static Digester[] webFragmentDigesters = new Digester[4];\r
+\r
+\r
+    /**\r
+     * The <code>Rule</code>s used to parse the web.xml\r
+     */\r
+    protected static WebRuleSet webRuleSet = new WebRuleSet(false);\r
+\r
+\r
+    /**\r
+     * The <code>Rule</code>s used to parse the web-fragment.xml\r
+     */\r
+    protected static WebRuleSet webFragmentRuleSet = new WebRuleSet(true);\r
+\r
+\r
+    /**\r
+     * Deployment count.\r
+     */\r
+    protected static long deploymentCount = 0L;\r
+\r
+\r
+    /**\r
+     * Cache of default web.xml fragments per Host\r
+     */\r
+    protected static final Map<Host,DefaultWebXmlCacheEntry> hostWebXmlCache =\r
+        new ConcurrentHashMap<Host,DefaultWebXmlCacheEntry>();\r
+\r
+\r
+    // ----------------------------------------------------- Instance Variables\r
+    /**\r
+     * Custom mappings of login methods to authenticators\r
+     */\r
+    protected Map<String,Authenticator> customAuthenticators;\r
+\r
+\r
+    /**\r
+     * The Context we are associated with.\r
+     */\r
+    protected Context context = null;\r
+\r
+\r
+    /**\r
+     * The default web application's context file location.\r
+     */\r
+    protected String defaultContextXml = null;\r
+    \r
+    \r
+    /**\r
+     * The default web application's deployment descriptor location.\r
+     */\r
+    protected String defaultWebXml = null;\r
+    \r
+    \r
+    /**\r
+     * Track any fatal errors during startup configuration processing.\r
+     */\r
+    protected boolean ok = false;\r
+\r
+\r
+    /**\r
+     * Original docBase.\r
+     */\r
+    protected String originalDocBase = null;\r
+    \r
+\r
+    /**\r
+     * Map of ServletContainerInitializer to classes they expressed interest in.\r
+     */\r
+    protected Map<ServletContainerInitializer, Set<Class<?>>> initializerClassMap =\r
+        new LinkedHashMap<ServletContainerInitializer, Set<Class<?>>>();\r
+    \r
+    /**\r
+     * Map of Types to ServletContainerInitializer that are interested in those\r
+     * types.\r
+     */\r
+    protected Map<Class<?>, Set<ServletContainerInitializer>> typeInitializerMap =\r
+        new HashMap<Class<?>, Set<ServletContainerInitializer>>();\r
+\r
+    /**\r
+     * The <code>Digester</code> we will use to process web application\r
+     * deployment descriptor files.\r
+     */\r
+    protected Digester webDigester = null;\r
+\r
+    /**\r
+     * The <code>Digester</code> we will use to process web fragment\r
+     * deployment descriptor files.\r
+     */\r
+    protected Digester webFragmentDigester = null;\r
+\r
+    \r
+    // ------------------------------------------------------------- Properties\r
+    /**\r
+     * Return the location of the default deployment descriptor\r
+     */\r
+    public String getDefaultWebXml() {\r
+        if( defaultWebXml == null ) {\r
+            defaultWebXml=Constants.DefaultWebXml;\r
+        }\r
+\r
+        return (this.defaultWebXml);\r
+\r
+    }\r
+\r
+\r
+    /**\r
+     * Set the location of the default deployment descriptor\r
+     *\r
+     * @param path Absolute/relative path to the default web.xml\r
+     */\r
+    public void setDefaultWebXml(String path) {\r
+\r
+        this.defaultWebXml = path;\r
+\r
+    }\r
+\r
+\r
+    /**\r
+     * Return the location of the default context file\r
+     */\r
+    public String getDefaultContextXml() {\r
+        if( defaultContextXml == null ) {\r
+            defaultContextXml=Constants.DefaultContextXml;\r
+        }\r
+\r
+        return (this.defaultContextXml);\r
+\r
+    }\r
+\r
+\r
+    /**\r
+     * Set the location of the default context file\r
+     *\r
+     * @param path Absolute/relative path to the default context.xml\r
+     */\r
+    public void setDefaultContextXml(String path) {\r
+\r
+        this.defaultContextXml = path;\r
+\r
+    }\r
+\r
+\r
+    /**\r
+     * Sets custom mappings of login methods to authenticators.\r
+     *\r
+     * @param customAuthenticators Custom mappings of login methods to\r
+     * authenticators\r
+     */\r
+    public void setCustomAuthenticators(\r
+            Map<String,Authenticator> customAuthenticators) {\r
+        this.customAuthenticators = customAuthenticators;\r
+    }\r
+\r
+\r
+    // --------------------------------------------------------- Public Methods\r
+\r
+\r
+    /**\r
+     * Process events for an associated Context.\r
+     *\r
+     * @param event The lifecycle event that has occurred\r
+     */\r
+    @Override\r
+    public void lifecycleEvent(LifecycleEvent event) {\r
+\r
+        // Identify the context we are associated with\r
+        try {\r
+            context = (Context) event.getLifecycle();\r
+        } catch (ClassCastException e) {\r
+            log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);\r
+            return;\r
+        }\r
+\r
+        // Process the event that has occurred\r
+        if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {\r
+            configureStart();\r
+        } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {\r
+            beforeStart();\r
+        } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {\r
+            // Restore docBase for management tools\r
+            if (originalDocBase != null) {\r
+                String docBase = context.getDocBase();\r
+                context.setDocBase(originalDocBase);\r
+                originalDocBase = docBase;\r
+            }\r
+        } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {\r
+            if (originalDocBase != null) {\r
+                String docBase = context.getDocBase();\r
+                context.setDocBase(originalDocBase);\r
+                originalDocBase = docBase;\r
+            }\r
+            configureStop();\r
+        } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {\r
+            init();\r
+        } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {\r
+            destroy();\r
+        }\r
+\r
+    }\r
+\r
+\r
+    // -------------------------------------------------------- protected Methods\r
+\r
+\r
+    /**\r
+     * Process the application classes annotations, if it exists.\r
+     */\r
+    protected void applicationAnnotationsConfig() {\r
+        \r
+        long t1=System.currentTimeMillis();\r
+        \r
+        WebAnnotationSet.loadApplicationAnnotations(context);\r
+        \r
+        long t2=System.currentTimeMillis();\r
+        if (context instanceof StandardContext) {\r
+            ((StandardContext) context).setStartupTime(t2-t1+\r
+                    ((StandardContext) context).getStartupTime());\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * Set up an Authenticator automatically if required, and one has not\r
+     * already been configured.\r
+     */\r
+    protected synchronized void authenticatorConfig() {\r
+\r
+        LoginConfig loginConfig = context.getLoginConfig();\r
+\r
+        SecurityConstraint constraints[] = context.findConstraints();\r
+        if (context.getIgnoreAnnotations() &&\r
+                (constraints == null || constraints.length ==0) &&\r
+                !context.getPreemptiveAuthentication())  {\r
+            return;\r
+        } else {\r
+            if (loginConfig == null) {\r
+                // Not metadata-complete or security constraints present, need\r
+                // an authenticator to support @ServletSecurity annotations\r
+                // and/or constraints\r
+                loginConfig = DUMMY_LOGIN_CONFIG;\r
+                context.setLoginConfig(loginConfig);\r
+            }\r
+        }\r
+\r
+        // Has an authenticator been configured already?\r
+        if (context.getAuthenticator() != null)\r
+            return;\r
+        \r
+        if (!(context instanceof ContainerBase)) {\r
+            return;     // Cannot install a Valve even if it would be needed\r
+        }\r
+\r
+        // Has a Realm been configured for us to authenticate against?\r
+        if (context.getRealm() == null) {\r
+            log.error(sm.getString("contextConfig.missingRealm"));\r
+            ok = false;\r
+            return;\r
+        }\r
+\r
+        /*\r
+         * First check to see if there is a custom mapping for the login\r
+         * method. If so, use it. Otherwise, check if there is a mapping in\r
+         * org/apache/catalina/startup/Authenticators.properties.\r
+         */\r
+        Valve authenticator = null;\r
+        if (customAuthenticators != null) {\r
+            authenticator = (Valve)\r
+                customAuthenticators.get(loginConfig.getAuthMethod());\r
+        }\r
+        if (authenticator == null) {\r
+            // Load our mapping properties if necessary\r
+            if (authenticators == null) {\r
+                try {\r
+                    InputStream is=this.getClass().getClassLoader().getResourceAsStream("org/apache/catalina/startup/Authenticators.properties");\r
+                    if( is!=null ) {\r
+                        authenticators = new Properties();\r
+                        authenticators.load(is);\r
+                    } else {\r
+                        log.error(sm.getString(\r
+                                "contextConfig.authenticatorResources"));\r
+                        ok=false;\r
+                        return;\r
+                    }\r
+                } catch (IOException e) {\r
+                    log.error(sm.getString(\r
+                                "contextConfig.authenticatorResources"), e);\r
+                    ok = false;\r
+                    return;\r
+                }\r
+            }\r
+\r
+            // Identify the class name of the Valve we should configure\r
+            String authenticatorName = null;\r
+            authenticatorName =\r
+                    authenticators.getProperty(loginConfig.getAuthMethod());\r
+            if (authenticatorName == null) {\r
+                log.error(sm.getString("contextConfig.authenticatorMissing",\r
+                                 loginConfig.getAuthMethod()));\r
+                ok = false;\r
+                return;\r
+            }\r
+\r
+            // Instantiate and install an Authenticator of the requested class\r
+            try {\r
+                Class<?> authenticatorClass = Class.forName(authenticatorName);\r
+                authenticator = (Valve) authenticatorClass.newInstance();\r
+            } catch (Throwable t) {\r
+                ExceptionUtils.handleThrowable(t);\r
+                log.error(sm.getString(\r
+                                    "contextConfig.authenticatorInstantiate",\r
+                                    authenticatorName),\r
+                          t);\r
+                ok = false;\r
+            }\r
+        }\r
+\r
+        if (authenticator != null && context instanceof ContainerBase) {\r
+            Pipeline pipeline = ((ContainerBase) context).getPipeline();\r
+            if (pipeline != null) {\r
+                ((ContainerBase) context).getPipeline().addValve(authenticator);\r
+                if (log.isDebugEnabled()) {\r
+                    log.debug(sm.getString(\r
+                                    "contextConfig.authenticatorConfigured",\r
+                                    loginConfig.getAuthMethod()));\r
+                }\r
+            }\r
+        }\r
+\r
+    }\r
+\r
+\r
+    /**\r
+     * Create (if necessary) and return a Digester configured to process the\r
+     * web application deployment descriptor (web.xml).\r
+     */\r
+    public void createWebXmlDigester(boolean namespaceAware,\r
+            boolean validation) {\r
+        \r
+        if (!namespaceAware && !validation) {\r
+            if (webDigesters[0] == null) {\r
+                webDigesters[0] = DigesterFactory.newDigester(validation,\r
+                        namespaceAware, webRuleSet);\r
+                webFragmentDigesters[0] = DigesterFactory.newDigester(validation,\r
+                        namespaceAware, webFragmentRuleSet);\r
+                webDigesters[0].getParser();\r
+                webFragmentDigesters[0].getParser();\r
+            }\r
+            webDigester = webDigesters[0];\r
+            webFragmentDigester = webFragmentDigesters[0];\r
+            \r
+        } else if (!namespaceAware && validation) {\r
+            if (webDigesters[1] == null) {\r
+                webDigesters[1] = DigesterFactory.newDigester(validation,\r
+                        namespaceAware, webRuleSet);\r
+                webFragmentDigesters[1] = DigesterFactory.newDigester(validation,\r
+                        namespaceAware, webFragmentRuleSet);\r
+                webDigesters[1].getParser();\r
+                webFragmentDigesters[1].getParser();\r
+            }\r
+            webDigester = webDigesters[1];\r
+            webFragmentDigester = webFragmentDigesters[1];\r
+            \r
+        } else if (namespaceAware && !validation) {\r
+            if (webDigesters[2] == null) {\r
+                webDigesters[2] = DigesterFactory.newDigester(validation,\r
+                        namespaceAware, webRuleSet);\r
+                webFragmentDigesters[2] = DigesterFactory.newDigester(validation,\r
+                        namespaceAware, webFragmentRuleSet);\r
+                webDigesters[2].getParser();\r
+                webFragmentDigesters[2].getParser();\r
+            }\r
+            webDigester = webDigesters[2];\r
+            webFragmentDigester = webFragmentDigesters[2];\r
+            \r
+        } else {\r
+            if (webDigesters[3] == null) {\r
+                webDigesters[3] = DigesterFactory.newDigester(validation,\r
+                        namespaceAware, webRuleSet);\r
+                webFragmentDigesters[3] = DigesterFactory.newDigester(validation,\r
+                        namespaceAware, webFragmentRuleSet);\r
+                webDigesters[3].getParser();\r
+                webFragmentDigesters[3].getParser();\r
+            }\r
+            webDigester = webDigesters[3];\r
+            webFragmentDigester = webFragmentDigesters[3];\r
+        }\r
+    }\r
+\r
+    \r
+    /**\r
+     * Create (if necessary) and return a Digester configured to process the\r
+     * context configuration descriptor for an application.\r
+     */\r
+    protected Digester createContextDigester() {\r
+        Digester digester = new Digester();\r
+        digester.setValidating(false);\r
+        digester.setRulesValidation(true);\r
+        HashMap<Class<?>, List<String>> fakeAttributes =\r
+            new HashMap<Class<?>, List<String>>();\r
+        ArrayList<String> attrs = new ArrayList<String>();\r
+        attrs.add("className");\r
+        fakeAttributes.put(Object.class, attrs);\r
+        digester.setFakeAttributes(fakeAttributes);\r
+        RuleSet contextRuleSet = new ContextRuleSet("", false);\r
+        digester.addRuleSet(contextRuleSet);\r
+        RuleSet namingRuleSet = new NamingRuleSet("Context/");\r
+        digester.addRuleSet(namingRuleSet);\r
+        return digester;\r
+    }\r
+\r
+\r
+    protected String getBaseDir() {\r
+        Container engineC=context.getParent().getParent();\r
+        if( engineC instanceof StandardEngine ) {\r
+            return ((StandardEngine)engineC).getBaseDir();\r
+        }\r
+        return System.getProperty(Globals.CATALINA_BASE_PROP);\r
+    }\r
+\r
+    \r
+    /**\r
+     * Process the default configuration file, if it exists.\r
+     */\r
+    protected void contextConfig() {\r
+        \r
+        // Open the default context.xml file, if it exists\r
+        if( defaultContextXml==null && context instanceof StandardContext ) {\r
+            defaultContextXml = ((StandardContext)context).getDefaultContextXml();\r
+        }\r
+        // set the default if we don't have any overrides\r
+        if( defaultContextXml==null ) getDefaultContextXml();\r
+\r
+        if (!context.getOverride()) {\r
+            File defaultContextFile = new File(defaultContextXml);\r
+            if (!defaultContextFile.isAbsolute()) {\r
+                defaultContextFile =new File(getBaseDir(), defaultContextXml);\r
+            }\r
+            if (defaultContextFile.exists()) {\r
+                try {\r
+                    URL defaultContextUrl = defaultContextFile.toURI().toURL();\r
+                    processContextConfig(defaultContextUrl);\r
+                } catch (MalformedURLException e) {\r
+                    log.error(sm.getString(\r
+                            "contextConfig.badUrl", defaultContextFile), e);\r
+                }\r
+            }\r
+            \r
+            File hostContextFile = new File(getConfigBase(),\r
+                    getHostConfigPath(Constants.HostContextXml));\r
+            if (hostContextFile.exists()) {\r
+                try {\r
+                    URL hostContextUrl = hostContextFile.toURI().toURL();\r
+                    processContextConfig(hostContextUrl);\r
+                } catch (MalformedURLException e) {\r
+                    log.error(sm.getString(\r
+                            "contextConfig.badUrl", hostContextFile), e);\r
+                }\r
+            }\r
+        }\r
+        if (context.getConfigFile() != null)\r
+            processContextConfig(context.getConfigFile());\r
+        \r
+    }\r
+\r
+    \r
+    /**\r
+     * Process a context.xml.\r
+     */\r
+    protected void processContextConfig(URL contextXml) {\r
+        \r
+        if (log.isDebugEnabled())\r
+            log.debug("Processing context [" + context.getName() \r
+                    + "] configuration file [" + contextXml + "]");\r
+\r
+        InputSource source = null;\r
+        InputStream stream = null;\r
+\r
+        try {\r
+            source = new InputSource(contextXml.toString());\r
+            stream = contextXml.openStream();\r
+            \r
+            // Add as watched resource so that cascade reload occurs if a default\r
+            // config file is modified/added/removed\r
+            if ("file".equals(contextXml.getProtocol())) {\r
+                context.addWatchedResource(\r
+                        (new File(contextXml.toURI())).getAbsolutePath());\r
+            }\r
+        } catch (Exception e) {\r
+            log.error(sm.getString("contextConfig.contextMissing",  \r
+                      contextXml) , e);\r
+        }\r
+        \r
+        if (source == null)\r
+            return;\r
+        synchronized (contextDigester) {\r
+            try {\r
+                source.setByteStream(stream);\r
+                contextDigester.setClassLoader(this.getClass().getClassLoader());\r
+                contextDigester.setUseContextClassLoader(false);\r
+                contextDigester.push(context.getParent());\r
+                contextDigester.push(context);\r
+                XmlErrorHandler errorHandler = new XmlErrorHandler();\r
+                contextDigester.setErrorHandler(errorHandler);\r
+                contextDigester.parse(source);\r
+                if (errorHandler.getWarnings().size() > 0 ||\r
+                        errorHandler.getErrors().size() > 0) {\r
+                    errorHandler.logFindings(log, contextXml.toString());\r
+                    ok = false;\r
+                }\r
+                if (log.isDebugEnabled())\r
+                    log.debug("Successfully processed context [" + context.getName() \r
+                            + "] configuration file [" + contextXml + "]");\r
+            } catch (SAXParseException e) {\r
+                log.error(sm.getString("contextConfig.contextParse",\r
+                        context.getName()), e);\r
+                log.error(sm.getString("contextConfig.defaultPosition",\r
+                                 "" + e.getLineNumber(),\r
+                                 "" + e.getColumnNumber()));\r
+                ok = false;\r
+            } catch (Exception e) {\r
+                log.error(sm.getString("contextConfig.contextParse",\r
+                        context.getName()), e);\r
+                ok = false;\r
+            } finally {\r
+                contextDigester.reset();\r
+                try {\r
+                    if (stream != null) {\r
+                        stream.close();\r
+                    }\r
+                } catch (IOException e) {\r
+                    log.error(sm.getString("contextConfig.contextClose"), e);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    \r
+    /**\r
+     * Adjust docBase.\r
+     */\r
+    protected void fixDocBase()\r
+        throws IOException {\r
+        \r
+        Host host = (Host) context.getParent();\r
+        File appBase = host.getAppBaseFile();\r
+\r
+        String docBase = context.getDocBase();\r
+        if (docBase == null) {\r
+            // Trying to guess the docBase according to the path\r
+            String path = context.getPath();\r
+            if (path == null) {\r
+                return;\r
+            }\r
+            ContextName cn = new ContextName(path, context.getWebappVersion());\r
+            docBase = cn.getBaseName();\r
+        }\r
+\r
+        File file = new File(docBase);\r
+        if (!file.isAbsolute()) {\r
+            docBase = (new File(appBase, docBase)).getPath();\r
+        } else {\r
+            docBase = file.getCanonicalPath();\r
+        }\r
+        file = new File(docBase);\r
+        String origDocBase = docBase;\r
+        \r
+        ContextName cn = new ContextName(context.getPath(),\r
+                context.getWebappVersion());\r
+        String pathName = cn.getBaseName();\r
+\r
+        boolean unpackWARs = true;\r
+        if (host instanceof StandardHost) {\r
+            unpackWARs = ((StandardHost) host).isUnpackWARs() &&\r
+                    ((StandardContext) context).getUnpackWAR() &&\r
+                    (docBase.startsWith(host.getAppBaseFile().getPath()));\r
+        }\r
+\r
+        if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") && !file.isDirectory() && unpackWARs) {\r
+            URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/");\r
+            docBase = ExpandWar.expand(host, war, pathName);\r
+            file = new File(docBase);\r
+            docBase = file.getCanonicalPath();\r
+            if (context instanceof StandardContext) {\r
+                ((StandardContext) context).setOriginalDocBase(origDocBase);\r
+            }\r
+        } else if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") &&\r
+                !file.isDirectory() && !unpackWARs) {\r
+            URL war =\r
+                new URL("jar:" + (new File (docBase)).toURI().toURL() + "!/");\r
+            ExpandWar.validate(host, war, pathName);\r
+        } else {\r
+            File docDir = new File(docBase);\r
+            if (!docDir.exists()) {\r
+                File warFile = new File(docBase + ".war");\r
+                if (warFile.exists()) {\r
+                    URL war =\r
+                        new URL("jar:" + warFile.toURI().toURL() + "!/");\r
+                    if (unpackWARs) {\r
+                        docBase = ExpandWar.expand(host, war, pathName);\r
+                        file = new File(docBase);\r
+                        docBase = file.getCanonicalPath();\r
+                    } else {\r
+                        docBase = warFile.getCanonicalPath();\r
+                        ExpandWar.validate(host, war, pathName);\r
+                    }\r
+                }\r
+                if (context instanceof StandardContext) {\r
+                    ((StandardContext) context).setOriginalDocBase(origDocBase);\r
+                }\r
+            }\r
+        }\r
+\r
+        if (docBase.startsWith(appBase.getPath() + File.separatorChar)) {\r
+            docBase = docBase.substring(appBase.getPath().length());\r
+            docBase = docBase.replace(File.separatorChar, '/');\r
+            if (docBase.startsWith("/")) {\r
+                docBase = docBase.substring(1);\r
+            }\r
+        } else {\r
+            docBase = docBase.replace(File.separatorChar, '/');\r
+        }\r
+\r
+        context.setDocBase(docBase);\r
+\r
+    }\r
+    \r
+    \r
+    protected void antiLocking() {\r
+\r
+        if ((context instanceof StandardContext) \r
+            && ((StandardContext) context).getAntiResourceLocking()) {\r
+            \r
+            Host host = (Host) context.getParent();\r
+            String docBase = context.getDocBase();\r
+            if (docBase == null)\r
+                return;\r
+            if (originalDocBase == null) {\r
+                originalDocBase = docBase;\r
+            } else {\r
+                docBase = originalDocBase;\r
+            }\r
+            File docBaseFile = new File(docBase);\r
+            if (!docBaseFile.isAbsolute()) {\r
+                docBaseFile = new File(host.getAppBaseFile(), docBase);\r
+            }\r
+            \r
+            String path = context.getPath();\r
+            if (path == null) {\r
+                return;\r
+            }\r
+            ContextName cn = new ContextName(path, context.getWebappVersion());\r
+            docBase = cn.getBaseName();\r
+\r
+            File file = null;\r
+            if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war")) {\r
+                // TODO - This is never executed. Bug or code to delete?\r
+                file = new File(System.getProperty("java.io.tmpdir"),\r
+                        deploymentCount++ + "-" + docBase + ".war");\r
+            } else {\r
+                file = new File(System.getProperty("java.io.tmpdir"), \r
+                        deploymentCount++ + "-" + docBase);\r
+            }\r
+            \r
+            if (log.isDebugEnabled())\r
+                log.debug("Anti locking context[" + context.getName() \r
+                        + "] setting docBase to " + file);\r
+            \r
+            // Cleanup just in case an old deployment is lying around\r
+            ExpandWar.delete(file);\r
+            if (ExpandWar.copy(docBaseFile, file)) {\r
+                context.setDocBase(file.getAbsolutePath());\r
+            }\r
+            \r
+        }\r
+        \r
+    }\r
+    \r
+\r
+    /**\r
+     * Process a "init" event for this Context.\r
+     */\r
+    protected void init() {\r
+        // Called from StandardContext.init()\r
+\r
+        if (contextDigester == null){\r
+            contextDigester = createContextDigester();\r
+            contextDigester.getParser();\r
+        }\r
+\r
+        if (log.isDebugEnabled())\r
+            log.debug(sm.getString("contextConfig.init"));\r
+        context.setConfigured(false);\r
+        ok = true;\r
+        \r
+        contextConfig();\r
+        \r
+        createWebXmlDigester(context.getXmlNamespaceAware(),\r
+                context.getXmlValidation());\r
+\r
+        try {\r
+            fixDocBase();\r
+        } catch (IOException e) {\r
+            log.error(sm.getString(\r
+                    "contextConfig.fixDocBase", context.getName()), e);\r
+        }\r
+        \r
+    }\r
+    \r
+    \r
+    /**\r
+     * Process a "before start" event for this Context.\r
+     */\r
+    protected synchronized void beforeStart() {\r
+        \r
+        antiLocking();\r
+\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Process a "contextConfig" event for this Context.\r
+     */\r
+    protected synchronized void configureStart() {\r
+        // Called from StandardContext.start()\r
+\r
+        if (log.isDebugEnabled())\r
+            log.debug(sm.getString("contextConfig.start"));\r
+\r
+        if (log.isDebugEnabled()) {\r
+            log.debug(sm.getString("contextConfig.xmlSettings",\r
+                    context.getName(),\r
+                    Boolean.valueOf(context.getXmlValidation()),\r
+                    Boolean.valueOf(context.getXmlNamespaceAware())));\r
+        }\r
+        \r
+        webConfig();\r
+\r
+        if (!context.getIgnoreAnnotations()) {\r
+            applicationAnnotationsConfig();\r
+        }\r
+        if (ok) {\r
+            validateSecurityRoles();\r
+        }\r
+\r
+        // Configure an authenticator if we need one\r
+        if (ok)\r
+            authenticatorConfig();\r
+\r
+        // Dump the contents of this pipeline if requested\r
+        if ((log.isDebugEnabled()) && (context instanceof ContainerBase)) {\r
+            log.debug("Pipeline Configuration:");\r
+            Pipeline pipeline = ((ContainerBase) context).getPipeline();\r
+            Valve valves[] = null;\r
+            if (pipeline != null)\r
+                valves = pipeline.getValves();\r
+            if (valves != null) {\r
+                for (int i = 0; i < valves.length; i++) {\r
+                    log.debug("  " + valves[i].getInfo());\r
+                }\r
+            }\r
+            log.debug("======================");\r
+        }\r
+\r
+        // Make our application available if no problems were encountered\r
+        if (ok)\r
+            context.setConfigured(true);\r
+        else {\r
+            log.error(sm.getString("contextConfig.unavailable"));\r
+            context.setConfigured(false);\r
+        }\r
+\r
+    }\r
+\r
+\r
+    /**\r
+     * Process a "stop" event for this Context.\r
+     */\r
+    protected synchronized void configureStop() {\r
+\r
+        if (log.isDebugEnabled())\r
+            log.debug(sm.getString("contextConfig.stop"));\r
+\r
+        int i;\r
+\r
+        // Removing children\r
+        Container[] children = context.findChildren();\r
+        for (i = 0; i < children.length; i++) {\r
+            context.removeChild(children[i]);\r
+        }\r
+\r
+        // Removing application parameters\r
+        /*\r
+        ApplicationParameter[] applicationParameters =\r
+            context.findApplicationParameters();\r
+        for (i = 0; i < applicationParameters.length; i++) {\r
+            context.removeApplicationParameter\r
+                (applicationParameters[i].getName());\r
+        }\r
+        */\r
+\r
+        // Removing security constraints\r
+        SecurityConstraint[] securityConstraints = context.findConstraints();\r
+        for (i = 0; i < securityConstraints.length; i++) {\r
+            context.removeConstraint(securityConstraints[i]);\r
+        }\r
+\r
+        // Removing Ejbs\r
+        /*\r
+        ContextEjb[] contextEjbs = context.findEjbs();\r
+        for (i = 0; i < contextEjbs.length; i++) {\r
+            context.removeEjb(contextEjbs[i].getName());\r
+        }\r
+        */\r
+\r
+        // Removing environments\r
+        /*\r
+        ContextEnvironment[] contextEnvironments = context.findEnvironments();\r
+        for (i = 0; i < contextEnvironments.length; i++) {\r
+            context.removeEnvironment(contextEnvironments[i].getName());\r
+        }\r
+        */\r
+\r
+        // Removing errors pages\r
+        ErrorPage[] errorPages = context.findErrorPages();\r
+        for (i = 0; i < errorPages.length; i++) {\r
+            context.removeErrorPage(errorPages[i]);\r
+        }\r
+\r
+        // Removing filter defs\r
+        FilterDef[] filterDefs = context.findFilterDefs();\r
+        for (i = 0; i < filterDefs.length; i++) {\r
+            context.removeFilterDef(filterDefs[i]);\r
+        }\r
+\r
+        // Removing filter maps\r
+        FilterMap[] filterMaps = context.findFilterMaps();\r
+        for (i = 0; i < filterMaps.length; i++) {\r
+            context.removeFilterMap(filterMaps[i]);\r
+        }\r
+\r
+        // Removing local ejbs\r
+        /*\r
+        ContextLocalEjb[] contextLocalEjbs = context.findLocalEjbs();\r
+        for (i = 0; i < contextLocalEjbs.length; i++) {\r
+            context.removeLocalEjb(contextLocalEjbs[i].getName());\r
+        }\r
+        */\r
+\r
+        // Removing Mime mappings\r
+        String[] mimeMappings = context.findMimeMappings();\r
+        for (i = 0; i < mimeMappings.length; i++) {\r
+            context.removeMimeMapping(mimeMappings[i]);\r
+        }\r
+\r
+        // Removing parameters\r
+        String[] parameters = context.findParameters();\r
+        for (i = 0; i < parameters.length; i++) {\r
+            context.removeParameter(parameters[i]);\r
+        }\r
+\r
+        // Removing resource env refs\r
+        /*\r
+        String[] resourceEnvRefs = context.findResourceEnvRefs();\r
+        for (i = 0; i < resourceEnvRefs.length; i++) {\r
+            context.removeResourceEnvRef(resourceEnvRefs[i]);\r
+        }\r
+        */\r
+\r
+        // Removing resource links\r
+        /*\r
+        ContextResourceLink[] contextResourceLinks =\r
+            context.findResourceLinks();\r
+        for (i = 0; i < contextResourceLinks.length; i++) {\r
+            context.removeResourceLink(contextResourceLinks[i].getName());\r
+        }\r
+        */\r
+\r
+        // Removing resources\r
+        /*\r
+        ContextResource[] contextResources = context.findResources();\r
+        for (i = 0; i < contextResources.length; i++) {\r
+            context.removeResource(contextResources[i].getName());\r
+        }\r
+        */\r
+\r
+        // Removing security role\r
+        String[] securityRoles = context.findSecurityRoles();\r
+        for (i = 0; i < securityRoles.length; i++) {\r
+            context.removeSecurityRole(securityRoles[i]);\r
+        }\r
+\r
+        // Removing servlet mappings\r
+        String[] servletMappings = context.findServletMappings();\r
+        for (i = 0; i < servletMappings.length; i++) {\r
+            context.removeServletMapping(servletMappings[i]);\r
+        }\r
+\r
+        // FIXME : Removing status pages\r
+\r
+        // Removing welcome files\r
+        String[] welcomeFiles = context.findWelcomeFiles();\r
+        for (i = 0; i < welcomeFiles.length; i++) {\r
+            context.removeWelcomeFile(welcomeFiles[i]);\r
+        }\r
+\r
+        // Removing wrapper lifecycles\r
+        String[] wrapperLifecycles = context.findWrapperLifecycles();\r
+        for (i = 0; i < wrapperLifecycles.length; i++) {\r
+            context.removeWrapperLifecycle(wrapperLifecycles[i]);\r
+        }\r
+\r
+        // Removing wrapper listeners\r
+        String[] wrapperListeners = context.findWrapperListeners();\r
+        for (i = 0; i < wrapperListeners.length; i++) {\r
+            context.removeWrapperListener(wrapperListeners[i]);\r
+        }\r
+\r
+        // Remove (partially) folders and files created by antiLocking\r
+        Host host = (Host) context.getParent();\r
+        String docBase = context.getDocBase();\r
+        if ((docBase != null) && (originalDocBase != null)) {\r
+            File docBaseFile = new File(docBase);\r
+            if (!docBaseFile.isAbsolute()) {\r
+                docBaseFile = new File(host.getAppBaseFile(), docBase);\r
+            }\r
+            // No need to log failure - it is expected in this case\r
+            ExpandWar.delete(docBaseFile, false);\r
+        }\r
+        \r
+        // Reset ServletContextInitializer scanning\r
+        initializerClassMap.clear();\r
+        typeInitializerMap.clear();\r
+        \r
+        ok = true;\r
+\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Process a "destroy" event for this Context.\r
+     */\r
+    protected synchronized void destroy() {\r
+        // Called from StandardContext.destroy()\r
+        if (log.isDebugEnabled())\r
+            log.debug(sm.getString("contextConfig.destroy"));\r
+\r
+        // Skip clearing the work directory if Tomcat is being shutdown\r
+        Server s = getServer();\r
+        if (s != null && !s.getState().isAvailable()) {\r
+            return;\r
+        }\r
+        \r
+        // Changed to getWorkPath per Bugzilla 35819.\r
+        String workDir = ((StandardContext) context).getWorkPath();\r
+        if (workDir != null)\r
+            ExpandWar.delete(new File(workDir));\r
+    }\r
+    \r
+    \r
+    private Server getServer() {\r
+        Container c = context;\r
+        while (c != null && !(c instanceof Engine)) {\r
+            c = c.getParent();\r
+        }\r
+        \r
+        if (c == null) {\r
+            return null;\r
+        }\r
+        \r
+        Service s = ((Engine)c).getService();\r
+        \r
+        if (s == null) {\r
+            return null;\r
+        }\r
+        \r
+        return s.getServer();\r
+    }\r
+\r
+    /**\r
+     * Validate the usage of security role names in the web application\r
+     * deployment descriptor.  If any problems are found, issue warning\r
+     * messages (for backwards compatibility) and add the missing roles.\r
+     * (To make these problems fatal instead, simply set the <code>ok</code>\r
+     * instance variable to <code>false</code> as well).\r
+     */\r
+    protected void validateSecurityRoles() {\r
+\r
+        // Check role names used in <security-constraint> elements\r
+        SecurityConstraint constraints[] = context.findConstraints();\r
+        for (int i = 0; i < constraints.length; i++) {\r
+            String roles[] = constraints[i].findAuthRoles();\r
+            for (int j = 0; j < roles.length; j++) {\r
+                if (!"*".equals(roles[j]) &&\r
+                    !context.findSecurityRole(roles[j])) {\r
+                    log.info(sm.getString("contextConfig.role.auth", roles[j]));\r
+                    context.addSecurityRole(roles[j]);\r
+                }\r
+            }\r
+        }\r
+\r
+        // Check role names used in <servlet> elements\r
+        Container wrappers[] = context.findChildren();\r
+        for (int i = 0; i < wrappers.length; i++) {\r
+            Wrapper wrapper = (Wrapper) wrappers[i];\r
+            String runAs = wrapper.getRunAs();\r
+            if ((runAs != null) && !context.findSecurityRole(runAs)) {\r
+                log.info(sm.getString("contextConfig.role.runas", runAs));\r
+                context.addSecurityRole(runAs);\r
+            }\r
+            String names[] = wrapper.findSecurityReferences();\r
+            for (int j = 0; j < names.length; j++) {\r
+                String link = wrapper.findSecurityReference(names[j]);\r
+                if ((link != null) && !context.findSecurityRole(link)) {\r
+                    log.info(sm.getString("contextConfig.role.link", link));\r
+                    context.addSecurityRole(link);\r
+                }\r
+            }\r
+        }\r
+\r
+    }\r
+\r
+\r
+    /**\r
+     * Get config base.\r
+     */\r
+    protected File getConfigBase() {\r
+        File configBase = \r
+            new File(System.getProperty(Globals.CATALINA_BASE_PROP), "conf");\r
+        if (!configBase.exists()) {\r
+            return null;\r
+        }\r
+        return configBase;\r
+    }  \r
+\r
+    \r
+    protected String getHostConfigPath(String resourceName) {\r
+        StringBuilder result = new StringBuilder();\r
+        Container container = context;\r
+        Container host = null;\r
+        Container engine = null;\r
+        while (container != null) {\r
+            if (container instanceof Host)\r
+                host = container;\r
+            if (container instanceof Engine)\r
+                engine = container;\r
+            container = container.getParent();\r
+        }\r
+        if (engine != null) {\r
+            result.append(engine.getName()).append('/');\r
+        }\r
+        if (host != null) {\r
+            result.append(host.getName()).append('/');\r
+        }\r
+        result.append(resourceName);\r
+        return result.toString();\r
+    }\r
+\r
+\r
+    /**\r
+     * Scan the web.xml files that apply to the web application and merge them\r
+     * using the rules defined in the spec. For the global web.xml files,\r
+     * where there is duplicate configuration, the most specific level wins. ie\r
+     * an application's web.xml takes precedence over the host level or global\r
+     * web.xml file.\r
+     */\r
+    protected void webConfig() {\r
+        /* Anything and everything can override the global and host defaults.\r
+         * This is implemented in two parts\r
+         * - Handle as a web fragment that gets added after everything else so\r
+         *   everything else takes priority\r
+         * - Mark Servlets as overridable so SCI configuration can replace\r
+         *   configuration from the defaults\r
+         */ \r
+        Set<WebXml> defaults = new HashSet<WebXml>();\r
+        defaults.add(getDefaultWebXmlFragment());\r
+\r
+        WebXml webXml = createWebXml();\r
+\r
+        // Parse context level web.xml\r
+        InputSource contextWebXml = getContextWebXmlSource();\r
+        parseWebXml(contextWebXml, webXml, false);\r
+        \r
+        if (webXml.getMajorVersion() >= 3) {\r
+            // Ordering is important here\r
+\r
+            // Step 1. Identify all the JARs packaged with the application\r
+            // If the JARs have a web-fragment.xml it will be parsed at this\r
+            // point.\r
+            Map<String,WebXml> fragments = processJarsForWebFragments();\r
+\r
+            // Only need to process fragments and annotations if metadata is\r
+            // not complete\r
+            Set<WebXml> orderedFragments = null;\r
+            if  (!webXml.isMetadataComplete()) {\r
+                // Step 2. Order the fragments.\r
+                orderedFragments = WebXml.orderWebFragments(webXml, fragments);\r
+    \r
+                // Step 3. Look for ServletContainerInitializer implementations\r
+                if (ok) {\r
+                    processServletContainerInitializers(orderedFragments);\r
+                }\r
+    \r
+                // Step 4. Process /WEB-INF/classes for annotations\r
+                // This will add any matching classes to the typeInitializerMap\r
+                if (ok) {\r
+                    URL webinfClasses;\r
+                    try {\r
+                        webinfClasses = context.getServletContext().getResource(\r
+                                "/WEB-INF/classes");\r
+                        processAnnotationsUrl(webinfClasses, webXml);\r
+                    } catch (MalformedURLException e) {\r
+                        log.error(sm.getString(\r
+                                "contextConfig.webinfClassesUrl"), e);\r
+                    }\r
+                }\r
+    \r
+                // Step 5. Process JARs for annotations - only need to process\r
+                // those fragments we are going to use\r
+                // This will add any matching classes to the typeInitializerMap\r
+                if (ok) {\r
+                    processAnnotations(orderedFragments);\r
+                }\r
+    \r
+                // Step 6. Merge web-fragment.xml files into the main web.xml\r
+                // file.\r
+                if (ok) {\r
+                    ok = webXml.merge(orderedFragments);\r
+                }\r
+    \r
+                // Step 7. Apply global defaults\r
+                // Have to merge defaults before JSP conversion since defaults\r
+                // provide JSP servlet definition.\r
+                webXml.merge(defaults);\r
+\r
+                // Step 8. Convert explicitly mentioned jsps to servlets\r
+                if (ok) {\r
+                    convertJsps(webXml);\r
+                }\r
+                \r
+                // Step 9. Apply merged web.xml to Context\r
+                if (ok) {\r
+                    webXml.configureContext(context);\r
+    \r
+                    // Step 9a. Make the merged web.xml available to other\r
+                    // components, specifically Jasper, to save those components\r
+                    // from having to re-generate it.\r
+                    // TODO Use a ServletContainerInitializer for Jasper\r
+                    String mergedWebXml = webXml.toXml();\r
+                    context.getServletContext().setAttribute(\r
+                           org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML,\r
+                            mergedWebXml);\r
+                    if (context.getLogEffectiveWebXml()) {\r
+                        log.info("web.xml:\n" + mergedWebXml);\r
+                    }\r
+                }\r
+            } else {\r
+                webXml.merge(defaults);\r
+                webXml.configureContext(context);\r
+            }\r
+            \r
+            // Always need to look for static resources\r
+            // Step 10. Look for static resources packaged in JARs\r
+            if (ok) {\r
+                // Spec does not define an order.\r
+                // Use ordered JARs followed by remaining JARs\r
+                Set<WebXml> resourceJars = new LinkedHashSet<WebXml>();\r
+                if (orderedFragments != null) {\r
+                    for (WebXml fragment : orderedFragments) {\r
+                        resourceJars.add(fragment);\r
+                    }\r
+                }\r
+                for (WebXml fragment : fragments.values()) {\r
+                    if (!resourceJars.contains(fragment)) {\r
+                        resourceJars.add(fragment);\r
+                    }\r
+                }\r
+                processResourceJARs(resourceJars);\r
+                // See also StandardContext.resourcesStart() for\r
+                // WEB-INF/classes/META-INF/resources configuration\r
+            }\r
+            \r
+            // Only look for ServletContainerInitializer if metadata is not\r
+            // complete\r
+            if (!webXml.isMetadataComplete()) {\r
+                // Step 11. Apply the ServletContainerInitializer config to the\r
+                // context\r
+                if (ok) {\r
+                    for (Map.Entry<ServletContainerInitializer,\r
+                            Set<Class<?>>> entry : \r
+                                initializerClassMap.entrySet()) {\r
+                        if (entry.getValue().isEmpty()) {\r
+                            context.addServletContainerInitializer(\r
+                                    entry.getKey(), null);\r
+                        } else {\r
+                            context.addServletContainerInitializer(\r
+                                    entry.getKey(), entry.getValue());\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        } else {\r
+            // Apply unmerged web.xml to Context\r
+            webXml.merge(defaults);\r
+            convertJsps(webXml);\r
+            webXml.configureContext(context);\r
+        }\r
+    }\r
+\r
+    private WebXml getDefaultWebXmlFragment() {\r
+\r
+        // Host should never be null\r
+        Host host = (Host) context.getParent();\r
+\r
+        DefaultWebXmlCacheEntry entry = hostWebXmlCache.get(host);\r
+        \r
+        InputSource globalWebXml = getGlobalWebXmlSource();\r
+        InputSource hostWebXml = getHostWebXmlSource();\r
+        \r
+        long globalTimeStamp = 0;\r
+        long hostTimeStamp = 0;\r
+        \r
+        if (globalWebXml != null) {\r
+            try {\r
+                File f = new File(new URI(globalWebXml.getSystemId()));\r
+                globalTimeStamp = f.lastModified();\r
+            } catch (URISyntaxException e) {\r
+                globalTimeStamp = -1;\r
+            }\r
+        }\r
+        \r
+        if (hostWebXml != null) {\r
+            try {\r
+                File f = new File(new URI(hostWebXml.getSystemId()));\r
+                hostTimeStamp = f.lastModified();\r
+            } catch (URISyntaxException e) {\r
+                hostTimeStamp = -1;\r
+            }\r
+        }\r
+        \r
+        if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp &&\r
+                entry.getHostTimeStamp() == hostTimeStamp) {\r
+            return entry.getWebXml();\r
+        }\r
+        \r
+        // Parsing global web.xml is relatively expensive. Use a sync block to\r
+        // make sure it only happens once\r
+        synchronized (host) {\r
+            entry = hostWebXmlCache.get(host);\r
+            if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp &&\r
+                    entry.getHostTimeStamp() == hostTimeStamp) {\r
+                return entry.getWebXml();\r
+            }\r
+\r
+            WebXml webXmlDefaultFragment = createWebXml();\r
+            webXmlDefaultFragment.setOverridable(true);\r
+            // Set to distributable else every app will be prevented from being\r
+            // distributable when the default fragment is merged with the main\r
+            // web.xml\r
+            webXmlDefaultFragment.setDistributable(true);\r
+            // When merging, the default welcome files are only used if the app has\r
+            // not defined any welcomes files.\r
+            webXmlDefaultFragment.setAlwaysAddWelcomeFiles(false);\r
+\r
+            // Parse global web.xml if present\r
+            if (globalWebXml == null) {\r
+                // This is unusual enough to log\r
+                log.info(sm.getString("contextConfig.defaultMissing"));\r
+            } else {\r
+                parseWebXml(globalWebXml, webXmlDefaultFragment, false);\r
+            }\r
+            \r
+            // Parse host level web.xml if present\r
+            // Additive apart from welcome pages\r
+            webXmlDefaultFragment.setReplaceWelcomeFiles(true);\r
+            \r
+            parseWebXml(hostWebXml, webXmlDefaultFragment, false);\r
+            \r
+            // Don't update the cache if an error occurs\r
+            if (globalTimeStamp != -1 && hostTimeStamp != -1) {\r
+                entry = new DefaultWebXmlCacheEntry(webXmlDefaultFragment,\r
+                        globalTimeStamp, hostTimeStamp);\r
+                hostWebXmlCache.put(host, entry);\r
+            }\r
+\r
+            return webXmlDefaultFragment;\r
+        }\r
+    }\r
+\r
+\r
+    private void convertJsps(WebXml webXml) {\r
+        Map<String,String> jspInitParams;\r
+        ServletDef jspServlet = webXml.getServlets().get("jsp");\r
+        if (jspServlet == null) {\r
+            jspInitParams = new HashMap<String,String>();\r
+            Wrapper w = (Wrapper) context.findChild("jsp");\r
+            if (w != null) {\r
+                String[] params = w.findInitParameters();\r
+                for (String param : params) {\r
+                    jspInitParams.put(param, w.findInitParameter(param));\r
+                }\r
+            }\r
+        } else {\r
+            jspInitParams = jspServlet.getParameterMap();\r
+        }\r
+        for (ServletDef servletDef: webXml.getServlets().values()) {\r
+            if (servletDef.getJspFile() != null) {\r
+                convertJsp(servletDef, jspInitParams);\r
+            }\r
+        }\r
+    }\r
+\r
+    private void convertJsp(ServletDef servletDef,\r
+            Map<String,String> jspInitParams) {\r
+        servletDef.setServletClass(org.apache.catalina.core.Constants.JSP_SERVLET_CLASS);\r
+        String jspFile = servletDef.getJspFile();\r
+        if ((jspFile != null) && !jspFile.startsWith("/")) {\r
+            if (context.isServlet22()) {\r
+                if(log.isDebugEnabled())\r
+                    log.debug(sm.getString("contextConfig.jspFile.warning",\r
+                                       jspFile));\r
+                jspFile = "/" + jspFile;\r
+            } else {\r
+                throw new IllegalArgumentException\r
+                    (sm.getString("contextConfig.jspFile.error", jspFile));\r
+            }\r
+        }\r
+        servletDef.getParameterMap().put("jspFile", jspFile);\r
+        servletDef.setJspFile(null);\r
+        for (Map.Entry<String, String> initParam: jspInitParams.entrySet()) {\r
+            servletDef.addInitParameter(initParam.getKey(), initParam.getValue());\r
+        }\r
+    }\r
+\r
+    protected WebXml createWebXml() {\r
+        return new WebXml();\r
+    }\r
+\r
+    /**\r
+     * Scan JARs for ServletContainerInitializer implementations.\r
+     * Implementations will be added in web-fragment.xml priority order.\r
+     */\r
+    protected void processServletContainerInitializers(\r
+            Set<WebXml> fragments) {\r
+        \r
+        for (WebXml fragment : fragments) {\r
+            URL url = fragment.getURL();\r
+            Jar jar = null;\r
+            InputStream is = null;\r
+            ServletContainerInitializer sci = null;\r
+            try {\r
+                if ("jar".equals(url.getProtocol())) {\r
+                    jar = JarFactory.newInstance(url);\r
+                    is = jar.getInputStream(SCI_LOCATION);\r
+                } else if ("file".equals(url.getProtocol())) {\r
+                    String path = url.getPath();\r
+                    File file = new File(path, SCI_LOCATION);\r
+                    if (file.exists()) {\r
+                        is = new FileInputStream(file);\r
+                    }\r
+                }\r
+                if (is != null) {\r
+                    sci = getServletContainerInitializer(is);\r
+                }\r
+            } catch (IOException ioe) {\r
+                log.error(sm.getString(\r
+                        "contextConfig.servletContainerInitializerFail", url,\r
+                        context.getName()));\r
+                ok = false;\r
+                return;\r
+            } finally {\r
+                if (is != null) {\r
+                    try {\r
+                        is.close();\r
+                    } catch (IOException e) {\r
+                        // Ignore\r
+                    }\r
+                }\r
+                if (jar != null) {\r
+                    jar.close();\r
+                }\r
+            }\r
+            \r
+            if (sci == null) {\r
+                continue;\r
+            }\r
+\r
+            initializerClassMap.put(sci, new HashSet<Class<?>>());\r
+            \r
+            HandlesTypes ht =\r
+                sci.getClass().getAnnotation(HandlesTypes.class);\r
+            if (ht != null) {\r
+                Class<?>[] types = ht.value();\r
+                if (types != null) {\r
+                    for (Class<?> type : types) {\r
+                        Set<ServletContainerInitializer> scis =\r
+                            typeInitializerMap.get(type);\r
+                        if (scis == null) {\r
+                            scis = new HashSet<ServletContainerInitializer>();\r
+                            typeInitializerMap.put(type, scis);\r
+                        }\r
+                        scis.add(sci);\r
+                    }\r
+                }\r
+            }\r
+\r
+        }\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Extract the name of the ServletContainerInitializer.\r
+     * \r
+     * @param is    The resource where the name is defined \r
+     * @return      The class name\r
+     * @throws IOException\r
+     */\r
+    protected ServletContainerInitializer getServletContainerInitializer(\r
+            InputStream is) throws IOException {\r
+\r
+        String className = null;\r
+        \r
+        if (is != null) {\r
+            String line = null;\r
+            try {\r
+                BufferedReader br =\r
+                    new BufferedReader(new InputStreamReader(is, "UTF-8"));\r
+                line = br.readLine();\r
+                if (line != null && line.trim().length() > 0) {\r
+                    className = line.trim();\r
+                }\r
+            } catch (UnsupportedEncodingException e) {\r
+                // Should never happen with UTF-8\r
+                // If it does - ignore & return null\r
+            }\r
+        }\r
+        \r
+        ServletContainerInitializer sci = null;\r
+        try {\r
+            Class<?> clazz = Class.forName(className,true,\r
+                    context.getLoader().getClassLoader());\r
+             sci = (ServletContainerInitializer) clazz.newInstance();\r
+        } catch (ClassNotFoundException e) {\r
+            log.error(sm.getString("contextConfig.invalidSci", className), e);\r
+            throw new IOException(e);\r
+        } catch (InstantiationException e) {\r
+            log.error(sm.getString("contextConfig.invalidSci", className), e);\r
+            throw new IOException(e);\r
+        } catch (IllegalAccessException e) {\r
+            log.error(sm.getString("contextConfig.invalidSci", className), e);\r
+            throw new IOException(e);\r
+        }\r
+        \r
+        return sci;\r
+    }\r
+\r
+    \r
+    /**\r
+     * Scan JARs that contain web-fragment.xml files that will be used to\r
+     * configure this application to see if they also contain static resources.\r
+     * If static resources are found, add them to the context. Resources are\r
+     * added in web-fragment.xml priority order.\r
+     */\r
+    protected void processResourceJARs(Set<WebXml> fragments) {\r
+        for (WebXml fragment : fragments) {\r
+            URL url = fragment.getURL();\r
+            Jar jar = null;\r
+            try {\r
+                // Note: Ignore file URLs for now since only jar URLs will be accepted\r
+                if ("jar".equals(url.getProtocol())) {\r
+                    jar = JarFactory.newInstance(url);\r
+                    if (jar.entryExists("META-INF/resources/")) {\r
+                        context.addResourceJarUrl(url);\r
+                    }\r
+                }\r
+            } catch (IOException ioe) {\r
+                log.error(sm.getString("contextConfig.resourceJarFail", url,\r
+                        context.getName()));\r
+            } finally {\r
+                if (jar != null) {\r
+                    jar.close();\r
+                }\r
+            }\r
+        }\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Identify the default web.xml to be used and obtain an input source for\r
+     * it.\r
+     */\r
+    protected InputSource getGlobalWebXmlSource() {\r
+        // Is a default web.xml specified for the Context?\r
+        if (defaultWebXml == null && context instanceof StandardContext) {\r
+            defaultWebXml = ((StandardContext) context).getDefaultWebXml();\r
+        }\r
+        // Set the default if we don't have any overrides\r
+        if (defaultWebXml == null) getDefaultWebXml();\r
+\r
+        // Is it explicitly suppressed, e.g. in embedded environment?\r
+        if (Constants.NoDefaultWebXml.equals(defaultWebXml)) {\r
+            return null;\r
+        }\r
+        return getWebXmlSource(defaultWebXml, getBaseDir());\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Identify the host web.xml to be used and obtain an input source for\r
+     * it.\r
+     */\r
+    protected InputSource getHostWebXmlSource() {\r
+        String resourceName = getHostConfigPath(Constants.HostWebXml);\r
+        \r
+        // In an embedded environment, configBase might not be set\r
+        File configBase = getConfigBase();\r
+        if (configBase == null)\r
+            return null;\r
+        \r
+        String basePath = null;\r
+        try {\r
+            basePath = configBase.getCanonicalPath();\r
+        } catch (IOException e) {\r
+            log.error(sm.getString("contextConfig.baseError"), e);\r
+            return null;\r
+        }\r
+\r
+        return getWebXmlSource(resourceName, basePath);\r
+    }\r
+    \r
+    /**\r
+     * Identify the application web.xml to be used and obtain an input source\r
+     * for it.\r
+     */\r
+    protected InputSource getContextWebXmlSource() {\r
+        InputStream stream = null;\r
+        InputSource source = null;\r
+        URL url = null;\r
+        \r
+        String altDDName = null;\r
+\r
+        // Open the application web.xml file, if it exists\r
+        ServletContext servletContext = context.getServletContext();\r
+        if (servletContext != null) {\r
+            altDDName = (String)servletContext.getAttribute(\r
+                                                        Globals.ALT_DD_ATTR);\r
+            if (altDDName != null) {\r
+                try {\r
+                    stream = new FileInputStream(altDDName);\r
+                    url = new File(altDDName).toURI().toURL();\r
+                } catch (FileNotFoundException e) {\r
+                    log.error(sm.getString("contextConfig.altDDNotFound",\r
+                                           altDDName));\r
+                } catch (MalformedURLException e) {\r
+                    log.error(sm.getString("contextConfig.applicationUrl"));\r
+                }\r
+            }\r
+            else {\r
+                stream = servletContext.getResourceAsStream\r
+                    (Constants.ApplicationWebXml);\r
+                try {\r
+                    url = servletContext.getResource(\r
+                            Constants.ApplicationWebXml);\r
+                } catch (MalformedURLException e) {\r
+                    log.error(sm.getString("contextConfig.applicationUrl"));\r
+                }\r
+            }\r
+        }\r
+        if (stream == null || url == null) {\r
+            if (log.isDebugEnabled()) {\r
+                log.debug(sm.getString("contextConfig.applicationMissing") + " " + context);\r
+            }\r
+        } else {\r
+            source = new InputSource(url.toExternalForm());\r
+            source.setByteStream(stream);\r
+        }\r
+        \r
+        return source;\r
+    }\r
+    \r
+    /**\r
+     * \r
+     * @param filename  Name of the file (possibly with one or more leading path\r
+     *                  segments) to read\r
+     * @param path      Location that filename is relative to \r
+     */\r
+    protected InputSource getWebXmlSource(String filename, String path) {\r
+        File file = new File(filename);\r
+        if (!file.isAbsolute()) {\r
+            file = new File(path, filename);\r
+        }\r
+\r
+        InputStream stream = null;\r
+        InputSource source = null;\r
+\r
+        try {\r
+            if (!file.exists()) {\r
+                // Use getResource and getResourceAsStream\r
+                stream =\r
+                    getClass().getClassLoader().getResourceAsStream(filename);\r
+                if(stream != null) {\r
+                    source =\r
+                        new InputSource(getClass().getClassLoader().getResource(\r
+                                filename).toURI().toString());\r
+                } \r
+            } else {\r
+                source = new InputSource(file.getAbsoluteFile().toURI().toString());\r
+                stream = new FileInputStream(file);\r
+                context.addWatchedResource(file.getAbsolutePath());\r
+            }\r
+\r
+            if (stream != null && source != null) {\r
+                source.setByteStream(stream);\r
+            }\r
+        } catch (Exception e) {\r
+            log.error(sm.getString(\r
+                    "contextConfig.defaultError", filename, file), e);\r
+        }\r
+\r
+        return source;\r
+    }\r
+\r
+\r
+    protected void parseWebXml(InputSource source, WebXml dest,\r
+            boolean fragment) {\r
+        \r
+        if (source == null) return;\r
+\r
+        XmlErrorHandler handler = new XmlErrorHandler();\r
+\r
+        // Web digesters and rulesets are shared between contexts but are not\r
+        // thread safe. Whilst there should only be one thread at a time\r
+        // processing a config, play safe and sync.\r
+        Digester digester;\r
+        WebRuleSet ruleSet;\r
+        if (fragment) {\r
+            digester = webFragmentDigester;\r
+            ruleSet = webFragmentRuleSet;\r
+        } else {\r
+            digester = webDigester;\r
+            ruleSet = webRuleSet;\r
+        }\r
+        \r
+        // Sync on the ruleSet since the same ruleSet is shared across all four\r
+        // digesters\r
+        synchronized(ruleSet) {\r
+            \r
+            digester.push(dest);\r
+            digester.setErrorHandler(handler);\r
+            \r
+            if(log.isDebugEnabled()) {\r
+                log.debug(sm.getString("contextConfig.applicationStart",\r
+                        source.getSystemId()));\r
+            }\r
+\r
+            try {\r
+                digester.parse(source);\r
+\r
+                if (handler.getWarnings().size() > 0 ||\r
+                        handler.getErrors().size() > 0) {\r
+                    ok = false;\r
+                    handler.logFindings(log, source.getSystemId());\r
+                }\r
+            } catch (SAXParseException e) {\r
+                log.error(sm.getString("contextConfig.applicationParse",\r
+                        source.getSystemId()), e);\r
+                log.error(sm.getString("contextConfig.applicationPosition",\r
+                                 "" + e.getLineNumber(),\r
+                                 "" + e.getColumnNumber()));\r
+                ok = false;\r
+            } catch (Exception e) {\r
+                log.error(sm.getString("contextConfig.applicationParse",\r
+                        source.getSystemId()), e);\r
+                ok = false;\r
+            } finally {\r
+                digester.reset();\r
+                ruleSet.recycle();\r
+            }\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * Scan /META-INF/lib for JARs and for each one found add it and any\r
+     * /META-INF/web-fragment.xml to the resulting Map. web-fragment.xml files\r
+     * will be parsed before being added to the map. Every JAR will be added and\r
+     * <code>null</code> will be used if no web-fragment.xml was found. Any JARs\r
+     * known not contain fragments will be skipped.\r
+     * \r
+     * @return A map of JAR name to processed web fragment (if any)\r
+     */\r
+    protected Map<String,WebXml> processJarsForWebFragments() {\r
+        \r
+        JarScanner jarScanner = context.getJarScanner();\r
+        FragmentJarScannerCallback callback = new FragmentJarScannerCallback();\r
+        \r
+        jarScanner.scan(context.getServletContext(),\r
+                context.getLoader().getClassLoader(), callback, null);\r
+        \r
+        return callback.getFragments();\r
+    }\r
+\r
+    protected void processAnnotations(Set<WebXml> fragments) {\r
+        for(WebXml fragment : fragments) {\r
+            if (!fragment.isMetadataComplete()) {\r
+                WebXml annotations = new WebXml();\r
+                // no impact on distributable\r
+                annotations.setDistributable(true);\r
+                URL url = fragment.getURL();\r
+                processAnnotationsUrl(url, annotations);\r
+                Set<WebXml> set = new HashSet<WebXml>();\r
+                set.add(annotations);\r
+                // Merge annotations into fragment - fragment takes priority\r
+                fragment.merge(set);\r
+            }\r
+        }\r
+    }\r
+\r
+    protected void processAnnotationsUrl(URL url, WebXml fragment) {\r
+        if (url == null) {\r
+            // Nothing to do.\r
+            return;\r
+        } else if ("jar".equals(url.getProtocol())) {\r
+            processAnnotationsJar(url, fragment);\r
+        } else if ("jndi".equals(url.getProtocol())) {\r
+            processAnnotationsJndi(url, fragment);\r
+        } else if ("file".equals(url.getProtocol())) {\r
+            try {\r
+                processAnnotationsFile(new File(url.toURI()), fragment);\r
+            } catch (URISyntaxException e) {\r
+                log.error(sm.getString("contextConfig.fileUrl", url), e);\r
+            }\r
+        } else {\r
+            log.error(sm.getString("contextConfig.unknownUrlProtocol",\r
+                    url.getProtocol(), url));\r
+        }\r
+        \r
+    }\r
+\r
+\r
+    protected void processAnnotationsJar(URL url, WebXml fragment) {\r
+\r
+        Jar jar = null;\r
+        InputStream is;\r
+        \r
+        try {\r
+            jar = JarFactory.newInstance(url);\r
+            \r
+            jar.nextEntry();\r
+            String entryName = jar.getEntryName();\r
+            while (entryName != null) {\r
+                if (entryName.endsWith(".class")) {\r
+                    is = null;\r
+                    try {\r
+                        is = jar.getEntryInputStream();\r
+                        processAnnotationsStream(is, fragment);\r
+                    } catch (IOException e) {\r
+                        log.error(sm.getString("contextConfig.inputStreamJar",\r
+                                entryName, url),e);\r
+                    } finally {\r
+                        if (is != null) {\r
+                            try {\r
+                                is.close();\r
+                            } catch (IOException ioe) {\r
+                                // Ignore\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+                jar.nextEntry();\r
+                entryName = jar.getEntryName();\r
+            }\r
+        } catch (IOException e) {\r
+            log.error(sm.getString("contextConfig.jarFile", url), e);\r
+        } finally {\r
+            if (jar != null) {\r
+                jar.close();\r
+            }\r
+        }\r
+    }\r
+\r
+    \r
+    protected void processAnnotationsJndi(URL url, WebXml fragment) {\r
+        try {\r
+            URLConnection urlConn = url.openConnection();\r
+            DirContextURLConnection dcUrlConn;\r
+            if (!(urlConn instanceof DirContextURLConnection)) {\r
+                // This should never happen\r
+                sm.getString("contextConfig.jndiUrlNotDirContextConn", url);\r
+                return;\r
+            }\r
+            \r
+            dcUrlConn = (DirContextURLConnection) urlConn;\r
+            dcUrlConn.setUseCaches(false);\r
+            \r
+            String type = dcUrlConn.getHeaderField(ResourceAttributes.TYPE);\r
+            if (ResourceAttributes.COLLECTION_TYPE.equals(type)) {\r
+                // Collection\r
+                Enumeration<String> dirs = dcUrlConn.list();\r
+                while (dirs.hasMoreElements()) {\r
+                    String dir = dirs.nextElement();\r
+                    URL dirUrl = new URL(url.toString() + '/' + dir);\r
+                    processAnnotationsJndi(dirUrl, fragment);\r
+                }\r
+                \r
+            } else {\r
+                // Single file\r
+                if (url.getPath().endsWith(".class")) {\r
+                    InputStream is = null;\r
+                    try {\r
+                        is = dcUrlConn.getInputStream();\r
+                        processAnnotationsStream(is, fragment);\r
+                    } catch (IOException e) {\r
+                        log.error(sm.getString("contextConfig.inputStreamJndi",\r
+                                url),e);\r
+                    } finally {\r
+                        if (is != null) {\r
+                            try {\r
+                                is.close();\r
+                            } catch (Throwable t) {\r
+                                ExceptionUtils.handleThrowable(t);\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        } catch (IOException e) {\r
+            log.error(sm.getString("contextConfig.jndiUrl", url), e);\r
+        }\r
+    }\r
+    \r
+    \r
+    protected void processAnnotationsFile(File file, WebXml fragment) {\r
+        \r
+        if (file.isDirectory()) {\r
+            String[] dirs = file.list();\r
+            for (String dir : dirs) {\r
+                processAnnotationsFile(new File(file,dir), fragment);\r
+            }\r
+        } else if (file.canRead() && file.getName().endsWith(".class")) {\r
+            FileInputStream fis = null;\r
+            try {\r
+                fis = new FileInputStream(file);\r
+                processAnnotationsStream(fis, fragment);\r
+            } catch (IOException e) {\r
+                log.error(sm.getString("contextConfig.inputStreamFile",\r
+                        file.getAbsolutePath()),e);\r
+            } finally {\r
+                if (fis != null) {\r
+                    try {\r
+                        fis.close();\r
+                    } catch (Throwable t) {\r
+                        ExceptionUtils.handleThrowable(t);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+\r
+    protected void processAnnotationsStream(InputStream is, WebXml fragment)\r
+            throws ClassFormatException, IOException {\r
+        \r
+        ClassParser parser = new ClassParser(is, null);\r
+        JavaClass clazz = parser.parse();\r
+        \r
+        checkHandlesTypes(clazz);\r
+        \r
+        String className = clazz.getClassName();\r
+        \r
+        AnnotationEntry[] annotationsEntries = clazz.getAnnotationEntries();\r
+\r
+        for (AnnotationEntry ae : annotationsEntries) {\r
+            String type = ae.getAnnotationType();\r
+            if ("Ljavax/servlet/annotation/WebServlet;".equals(type)) {\r
+                processAnnotationWebServlet(className, ae, fragment);\r
+            }else if ("Ljavax/servlet/annotation/WebFilter;".equals(type)) {\r
+                processAnnotationWebFilter(className, ae, fragment);\r
+            }else if ("Ljavax/servlet/annotation/WebListener;".equals(type)) {\r
+                fragment.addListener(className);\r
+            } else {\r
+                // Unknown annotation - ignore\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * For classes packaged with the web application, the class and each\r
+     * super class needs to be checked for a match with {@link HandlesTypes} or\r
+     * for an annotation that matches {@link HandlesTypes}.\r
+     * @param javaClass\r
+     */\r
+    protected void checkHandlesTypes(JavaClass javaClass) {\r
+        \r
+        // Skip this if we can\r
+        if (typeInitializerMap.size() == 0)\r
+            return;\r
+        \r
+        // No choice but to load the class\r
+        String className = javaClass.getClassName();\r
+        \r
+        Class<?> clazz = null;\r
+        try {\r
+            clazz = context.getLoader().getClassLoader().loadClass(className);\r
+        } catch (NoClassDefFoundError e) {\r
+            log.debug(sm.getString("contextConfig.invalidSciHandlesTypes",\r
+                    className), e);\r
+            return;\r
+        } catch (ClassNotFoundException e) {\r
+            log.warn(sm.getString("contextConfig.invalidSciHandlesTypes",\r
+                    className), e);\r
+            return;\r
+        } catch (ClassFormatError e) {\r
+            log.warn(sm.getString("contextConfig.invalidSciHandlesTypes",\r
+                    className), e);\r
+            return;\r
+        } catch (Throwable t) {\r
+            ExceptionUtils.handleThrowable(t);\r
+            log.warn(sm.getString("contextConfig.invalidSciHandlesTypes",\r
+                    className), t);\r
+            return;\r
+        }\r
+\r
+        if (clazz.isAnnotation()) {\r
+            // Skip\r
+            return;\r
+        }\r
+        \r
+        boolean match = false;\r
+        \r
+        for (Map.Entry<Class<?>, Set<ServletContainerInitializer>> entry :\r
+                typeInitializerMap.entrySet()) {\r
+            if (entry.getKey().isAnnotation()) {\r
+                AnnotationEntry[] annotationEntries = javaClass.getAnnotationEntries();\r
+                for (AnnotationEntry annotationEntry : annotationEntries) {\r
+                    if (entry.getKey().getName().equals(\r
+                        getClassName(annotationEntry.getAnnotationType()))) {\r
+                        match = true;\r
+                        break;\r
+                    }\r
+                }\r
+            } else if (entry.getKey().isAssignableFrom(clazz)) {\r
+                match = true;\r
+            }\r
+            if (match) {\r
+                for (ServletContainerInitializer sci : entry.getValue()) {\r
+                    initializerClassMap.get(sci).add(clazz);\r
+                }\r
+                match = false;\r
+            }\r
+        }\r
+    }\r
+\r
+    private static final String getClassName(String internalForm) {\r
+        if (!internalForm.startsWith("L")) {\r
+            return internalForm;\r
+        }\r
+        \r
+        // Assume starts with L, ends with ; and uses / rather than .\r
+        return internalForm.substring(1,\r
+                internalForm.length() - 1).replace('/', '.');\r
+    }\r
+\r
+    protected void processAnnotationWebServlet(String className,\r
+            AnnotationEntry ae, WebXml fragment) {\r
+        String servletName = null;\r
+        // must search for name s. Spec Servlet API 3.0 - 8.2.3.3.n.ii page 81\r
+        ElementValuePair[] evps = ae.getElementValuePairs();\r
+        for (ElementValuePair evp : evps) {\r
+            String name = evp.getNameString();\r
+            if ("name".equals(name)) {\r
+                servletName = evp.getValue().stringifyValue();\r
+                break;\r
+            }\r
+        }\r
+        if (servletName == null) {\r
+            // classname is default servletName as annotation has no name!\r
+            servletName = className;\r
+        }\r
+        ServletDef servletDef = fragment.getServlets().get(servletName);\r
+        \r
+        boolean isWebXMLservletDef;\r
+        if (servletDef == null) {\r
+            servletDef = new ServletDef();\r
+            servletDef.setServletName(servletName);\r
+            servletDef.setServletClass(className);\r
+            isWebXMLservletDef = false;\r
+        } else {\r
+            isWebXMLservletDef = true;\r
+        }\r
+\r
+        boolean urlPatternsSet = false;\r
+        String[] urlPatterns = null;\r
+\r
+        // ElementValuePair[] evps = ae.getElementValuePairs();\r
+        for (ElementValuePair evp : evps) {\r
+            String name = evp.getNameString();\r
+            if ("value".equals(name) || "urlPatterns".equals(name)) {\r
+                if (urlPatternsSet) {\r
+                    throw new IllegalArgumentException(sm.getString(\r
+                            "contextConfig.urlPatternValue", className));\r
+                }\r
+                urlPatternsSet = true;\r
+                urlPatterns = processAnnotationsStringArray(evp.getValue());\r
+            } else if ("description".equals(name)) {\r
+                if (servletDef.getDescription() == null) {\r
+                    servletDef.setDescription(evp.getValue().stringifyValue());\r
+                }\r
+            } else if ("displayName".equals(name)) {\r
+                if (servletDef.getDisplayName() == null) {\r
+                    servletDef.setDisplayName(evp.getValue().stringifyValue());\r
+                }\r
+            } else if ("largeIcon".equals(name)) {\r
+                if (servletDef.getLargeIcon() == null) {\r
+                    servletDef.setLargeIcon(evp.getValue().stringifyValue());\r
+                }\r
+            } else if ("smallIcon".equals(name)) {\r
+                if (servletDef.getSmallIcon() == null) {\r
+                    servletDef.setSmallIcon(evp.getValue().stringifyValue());\r
+                }\r
+            } else if ("asyncSupported".equals(name)) {\r
+                if (servletDef.getAsyncSupported() == null) {\r
+                    servletDef.setAsyncSupported(evp.getValue()\r
+                            .stringifyValue());\r
+                }\r
+            } else if ("loadOnStartup".equals(name)) {\r
+                if (servletDef.getLoadOnStartup() == null) {\r
+                    servletDef\r
+                            .setLoadOnStartup(evp.getValue().stringifyValue());\r
+                }\r
+            } else if ("initParams".equals(name)) {\r
+                Map<String, String> initParams = processAnnotationWebInitParams(evp\r
+                        .getValue());\r
+                if (isWebXMLservletDef) {\r
+                    Map<String, String> webXMLInitParams = servletDef\r
+                            .getParameterMap();\r
+                    for (Map.Entry<String, String> entry : initParams\r
+                            .entrySet()) {\r
+                        if (webXMLInitParams.get(entry.getKey()) == null) {\r
+                            servletDef.addInitParameter(entry.getKey(), entry\r
+                                    .getValue());\r
+                        }\r
+                    }\r
+                } else {\r
+                    for (Map.Entry<String, String> entry : initParams\r
+                            .entrySet()) {\r
+                        servletDef.addInitParameter(entry.getKey(), entry\r
+                                .getValue());\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        if (!isWebXMLservletDef && urlPatterns != null) {\r
+            fragment.addServlet(servletDef);\r
+        }\r
+        if (urlPatterns != null) {\r
+            if (!fragment.getServletMappings().containsValue(servletName)) {\r
+                for (String urlPattern : urlPatterns) {\r
+                    fragment.addServletMapping(urlPattern, servletName);\r
+                }\r
+            }\r
+        }\r
+\r
+    }\r
+\r
+    /**\r
+     * process filter annotation and merge with existing one!\r
+     * FIXME: refactoring method to long and has redundant subroutines with processAnnotationWebServlet!\r
+     * @param className\r
+     * @param ae\r
+     * @param fragment\r
+     */\r
+    protected void processAnnotationWebFilter(String className,\r
+            AnnotationEntry ae, WebXml fragment) {\r
+        String filterName = null;\r
+        // must search for name s. Spec Servlet API 3.0 - 8.2.3.3.n.ii page 81\r
+        ElementValuePair[] evps = ae.getElementValuePairs();\r
+        for (ElementValuePair evp : evps) {\r
+            String name = evp.getNameString();\r
+            if ("filterName".equals(name)) {\r
+                filterName = evp.getValue().stringifyValue();\r
+                break;\r
+            }\r
+        }\r
+        if (filterName == null) {\r
+            // classname is default filterName as annotation has no name!\r
+            filterName = className;\r
+        }\r
+        FilterDef filterDef = fragment.getFilters().get(filterName);\r
+        FilterMap filterMap = new FilterMap();\r
+\r
+        boolean isWebXMLfilterDef;\r
+        if (filterDef == null) {\r
+            filterDef = new FilterDef();\r
+            filterDef.setFilterName(filterName);\r
+            filterDef.setFilterClass(className);\r
+            isWebXMLfilterDef = false;\r
+        } else {\r
+            isWebXMLfilterDef = true;\r
+        }\r
+\r
+        boolean urlPatternsSet = false;\r
+        boolean dispatchTypesSet = false;\r
+        String[] urlPatterns = null;\r
+\r
+        for (ElementValuePair evp : evps) {\r
+            String name = evp.getNameString();\r
+            if ("value".equals(name) || "urlPatterns".equals(name)) {\r
+                if (urlPatternsSet) {\r
+                    throw new IllegalArgumentException(sm.getString(\r
+                            "contextConfig.urlPatternValue", className));\r
+                }\r
+                urlPatterns = processAnnotationsStringArray(evp.getValue());\r
+                urlPatternsSet = urlPatterns.length > 0;\r
+                for (String urlPattern : urlPatterns) {\r
+                    filterMap.addURLPattern(urlPattern);\r
+                }\r
+            } else if ("servletNames".equals(name)) {\r
+                String[] servletNames = processAnnotationsStringArray(evp\r
+                        .getValue());\r
+                for (String servletName : servletNames) {\r
+                    filterMap.addServletName(servletName);\r
+                }\r
+            } else if ("dispatcherTypes".equals(name)) {\r
+                String[] dispatcherTypes = processAnnotationsStringArray(evp\r
+                        .getValue());\r
+                dispatchTypesSet = dispatcherTypes.length > 0;\r
+                for (String dispatcherType : dispatcherTypes) {\r
+                    filterMap.setDispatcher(dispatcherType);\r
+                }\r
+            } else if ("description".equals(name)) {\r
+                if (filterDef.getDescription() == null) {\r
+                    filterDef.setDescription(evp.getValue().stringifyValue());\r
+                }\r
+            } else if ("displayName".equals(name)) {\r
+                if (filterDef.getDisplayName() == null) {\r
+                    filterDef.setDisplayName(evp.getValue().stringifyValue());\r
+                }\r
+            } else if ("largeIcon".equals(name)) {\r
+                if (filterDef.getLargeIcon() == null) {\r
+                    filterDef.setLargeIcon(evp.getValue().stringifyValue());\r
+                }\r
+            } else if ("smallIcon".equals(name)) {\r
+                if (filterDef.getSmallIcon() == null) {\r
+                    filterDef.setSmallIcon(evp.getValue().stringifyValue());\r
+                }\r
+            } else if ("asyncSupported".equals(name)) {\r
+                if (filterDef.getAsyncSupported() == null) {\r
+                    filterDef\r
+                            .setAsyncSupported(evp.getValue().stringifyValue());\r
+                }\r
+            } else if ("initParams".equals(name)) {\r
+                Map<String, String> initParams = processAnnotationWebInitParams(evp\r
+                        .getValue());\r
+                if (isWebXMLfilterDef) {\r
+                    Map<String, String> webXMLInitParams = filterDef\r
+                            .getParameterMap();\r
+                    for (Map.Entry<String, String> entry : initParams\r
+                            .entrySet()) {\r
+                        if (webXMLInitParams.get(entry.getKey()) == null) {\r
+                            filterDef.addInitParameter(entry.getKey(), entry\r
+                                    .getValue());\r
+                        }\r
+                    }\r
+                } else {\r
+                    for (Map.Entry<String, String> entry : initParams\r
+                            .entrySet()) {\r
+                        filterDef.addInitParameter(entry.getKey(), entry\r
+                                .getValue());\r
+                    }\r
+                }\r
+\r
+            }\r
+        }\r
+        if (!isWebXMLfilterDef) {\r
+            fragment.addFilter(filterDef);\r
+            filterMap.setFilterName(filterName);\r
+            fragment.addFilterMapping(filterMap);\r
+        }\r
+        if (urlPatternsSet || dispatchTypesSet) {\r
+            Set<FilterMap> fmap = fragment.getFilterMappings();\r
+            FilterMap descMap = null;\r
+            for (FilterMap map : fmap) {\r
+                if (filterName.equals(map.getFilterName())) {\r
+                    descMap = map;\r
+                    break;\r
+                }\r
+            }\r
+            if (descMap != null) {\r
+                String[] urlsPatterns = descMap.getURLPatterns();\r
+                if (urlPatternsSet\r
+                        && (urlsPatterns == null || urlsPatterns.length == 0)) {\r
+                    for (String urlPattern : filterMap.getURLPatterns()) {\r
+                        descMap.addURLPattern(urlPattern);\r
+                    }\r
+                }\r
+                String[] dispatcherNames = descMap.getDispatcherNames();\r
+                if (dispatchTypesSet\r
+                        && (dispatcherNames == null || dispatcherNames.length == 0)) {\r
+                    for (String dis : filterMap.getDispatcherNames()) {\r
+                        descMap.setDispatcher(dis);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+    }\r
+\r
+    protected String[] processAnnotationsStringArray(ElementValue ev) {\r
+        ArrayList<String> values = new ArrayList<String>();\r
+        if (ev instanceof ArrayElementValue) {\r
+            ElementValue[] arrayValues =\r
+                ((ArrayElementValue) ev).getElementValuesArray();\r
+            for (ElementValue value : arrayValues) {\r
+                values.add(value.stringifyValue());\r
+            }\r
+        } else {\r
+            values.add(ev.stringifyValue());\r
+        }\r
+        String[] result = new String[values.size()];\r
+        return values.toArray(result);\r
+    }\r
+    \r
+    protected Map<String,String> processAnnotationWebInitParams(\r
+            ElementValue ev) {\r
+        Map<String, String> result = new HashMap<String,String>();\r
+        if (ev instanceof ArrayElementValue) {\r
+            ElementValue[] arrayValues =\r
+                ((ArrayElementValue) ev).getElementValuesArray();\r
+            for (ElementValue value : arrayValues) {\r
+                if (value instanceof AnnotationElementValue) {\r
+                    ElementValuePair[] evps = ((AnnotationElementValue)\r
+                            value).getAnnotationEntry().getElementValuePairs();\r
+                    String initParamName = null;\r
+                    String initParamValue = null;\r
+                    for (ElementValuePair evp : evps) {\r
+                        if ("name".equals(evp.getNameString())) {\r
+                            initParamName = evp.getValue().stringifyValue();\r
+                        } else if ("value".equals(evp.getNameString())) {\r
+                            initParamValue = evp.getValue().stringifyValue();\r
+                        } else {\r
+                            // Ignore\r
+                        }\r
+                    }\r
+                    result.put(initParamName, initParamValue);\r
+                }\r
+            }\r
+        }\r
+        return result;\r
+    }\r
+    \r
+    private class FragmentJarScannerCallback implements JarScannerCallback {\r
+\r
+        private static final String FRAGMENT_LOCATION =\r
+            "META-INF/web-fragment.xml";\r
+        private Map<String,WebXml> fragments = new HashMap<String,WebXml>();\r
+        \r
+        @Override\r
+        public void scan(JarURLConnection jarConn) throws IOException {\r
+            \r
+            URL url = jarConn.getURL();\r
+            URL resourceURL = jarConn.getJarFileURL();\r
+            Jar jar = null;\r
+            InputStream is = null;\r
+            WebXml fragment = new WebXml();\r
+\r
+            try {\r
+                jar = JarFactory.newInstance(url);\r
+                is = jar.getInputStream(FRAGMENT_LOCATION);\r
+\r
+                if (is == null) {\r
+                    // If there is no web.xml, normal JAR no impact on\r
+                    // distributable\r
+                    fragment.setDistributable(true);\r
+                } else {\r
+                    InputSource source = new InputSource(\r
+                            resourceURL.toString() + "!/" + FRAGMENT_LOCATION);\r
+                    source.setByteStream(is);\r
+                    parseWebXml(source, fragment, true);\r
+                }\r
+            } finally {\r
+                if (is != null) {\r
+                    try {\r
+                        is.close();\r
+                    } catch (IOException ioe) {\r
+                        // Ignore\r
+                    }\r
+                }\r
+                if (jar != null) {\r
+                    jar.close();\r
+                }\r
+                fragment.setURL(url);\r
+                if (fragment.getName() == null) {\r
+                    fragment.setName(fragment.getURL().toString());\r
+                }\r
+                fragments.put(fragment.getName(), fragment);\r
+            }\r
+        }\r
+\r
+        @Override\r
+        public void scan(File file) throws IOException {\r
+\r
+            InputStream stream = null;\r
+            WebXml fragment = new WebXml();\r
+            \r
+            try {\r
+                File fragmentFile = new File(file, FRAGMENT_LOCATION);\r
+                if (fragmentFile.isFile()) {\r
+                    stream = new FileInputStream(fragmentFile);\r
+                    InputSource source =\r
+                        new InputSource(fragmentFile.toURI().toURL().toString());\r
+                    source.setByteStream(stream);\r
+                    parseWebXml(source, fragment, true);\r
+                }\r
+            } finally {\r
+                if (stream != null) {\r
+                    try {\r
+                        stream.close();\r
+                    } catch (Throwable t) {\r
+                        ExceptionUtils.handleThrowable(t);\r
+                    }\r
+                }\r
+                fragment.setURL(file.toURI().toURL());\r
+                if (fragment.getName() == null) {\r
+                    fragment.setName(fragment.getURL().toString());\r
+                }\r
+                fragments.put(fragment.getName(), fragment);\r
+            }\r
+        }\r
+        \r
+        public Map<String,WebXml> getFragments() {\r
+            return fragments;\r
+        }\r
+    }\r
+\r
+    private static class DefaultWebXmlCacheEntry {\r
+        private final WebXml webXml;\r
+        private final long globalTimeStamp;\r
+        private final long hostTimeStamp;\r
+\r
+        public DefaultWebXmlCacheEntry(WebXml webXml, long globalTimeStamp,\r
+                long hostTimeStamp) {\r
+            this.webXml = webXml;\r
+            this.globalTimeStamp = globalTimeStamp;\r
+            this.hostTimeStamp = hostTimeStamp;\r
+        }\r
+\r
+        public WebXml getWebXml() {\r
+            return webXml;\r
+        }\r
+\r
+        public long getGlobalTimeStamp() {\r
+            return globalTimeStamp;\r
+        }\r
+\r
+        public long getHostTimeStamp() {\r
+            return hostTimeStamp;\r
+        }\r
+    }\r
+}\r