Package org.apache.catalina.startup

Source Code of org.apache.catalina.startup.ContextConfig

/*
* JBoss, Home of Professional Open Source
* Copyright 2009, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 1999-2009 The Apache Software Foundation
*
* 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.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.servlet.DispatcherType;
import javax.servlet.HttpMethodConstraintElement;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletSecurityElement;
import javax.servlet.annotation.HandlesTypes;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebListener;
import javax.servlet.annotation.WebServlet;
import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
import javax.servlet.annotation.ServletSecurity.TransportGuarantee;

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.JarRepository;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Pipeline;
import org.apache.catalina.Valve;
import org.apache.catalina.Wrapper;
import org.apache.catalina.core.ContainerBase;
import org.apache.catalina.core.ContextJarRepository;
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.SecurityCollection;
import org.apache.catalina.deploy.SecurityConstraint;
import org.apache.catalina.deploy.WebAbsoluteOrdering;
import org.apache.catalina.deploy.WebOrdering;
import org.apache.catalina.deploy.jsp.TagLibraryInfo;
import org.apache.catalina.util.StringManager;
import org.apache.naming.resources.JARDirContext;
import org.apache.naming.resources.ProxyDirContext;
import org.apache.tomcat.util.digester.Digester;
import org.apache.tomcat.util.digester.RuleSet;
import org.xml.sax.ErrorHandler;
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 $Revision: 1252 $ $Date: 2009-11-07 02:30:50 +0100 (Sat, 07 Nov 2009) $
*/

public class ContextConfig
    implements LifecycleListener {

    protected static org.jboss.logging.Logger log=
        org.jboss.logging.Logger.getLogger( ContextConfig.class );

    // ----------------------------------------------------- Instance Variables


    /**
     * Custom mappings of login methods to authenticators
     */
    protected Map customAuthenticators;


    /**
     * 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 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;


    /**
     * Any parse error which occurred while parsing XML descriptors.
     */
    protected SAXParseException parseException = null;

   
    /**
     * Original docBase.
     */
    protected String originalDocBase = null;
   

    /**
     * The string resources for this package.
     */
    protected static final StringManager sm =
        StringManager.getManager(Constants.Package);


    /**
     * The <code>Digester</code> we will use to process web application
     * context files.
     */
    protected static Digester contextDigester = null;
   
   
    /**
     * The <code>Digester</code> we will use to process web application
     * deployment descriptor files.
     */
    protected static Digester webDigester = null;
   
   
    /**
     * The <code>Digester</code> we will use to process web application
     * fragment descriptor files.
     */
    protected static Digester webFragmentDigester = null;
   
   
    /**
     * The <code>Digester</code> we will use to process tag library
     * descriptor files.
     */
    protected static Digester tldDigester = null;
   
   
    /**
     * The <code>Digester</code> we will use to parse fragment ordering.
     */
    protected static Digester fragmentOrderingDigester = null;
   
   
    /**
     * The <code>Digester</code> we will use to parse absolute ordering in web.xml.
     */
    protected static Digester orderingDigester = null;
   
   
    /**
     * The <code>Rule</code> used to parse the web.xml.
     */
    protected static WebRuleSet webRuleSet = new WebRuleSet();


    /**
     * The <code>Rule</code> used to parse web-fragment.xml files.
     */
    protected static WebRuleSet webFragmentRuleSet = new WebRuleSet("", true);


    /**
     * Deployment count.
     */
    protected static long deploymentCount = 0L;
   
   
    protected static final LoginConfig DUMMY_LOGIN_CONFIG =
                                new LoginConfig("NONE", null, null, null);


    protected ArrayList<String> overlays = new ArrayList<String>();
    protected ArrayList<String> webFragments = new ArrayList<String>();
    protected Map<String, Set<String>> TLDs = new HashMap<String, Set<String>>();
    protected Map<String, ServletContainerInitializerInfo> servletContainerInitializerInfos =
        new HashMap<String, ServletContainerInitializerInfo>();
    protected LinkedList<String> order = new LinkedList<String>();
   
    /**
     * Used to speed up scanning for the services interest classes.
     */
    protected Class<?>[] handlesTypesArray = null;
    protected Map<Class<?>, ServletContainerInitializerInfo> handlesTypes =
        new HashMap<Class<?>, ServletContainerInitializerInfo>();


    // ------------------------------------------------------------- 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 customAuthenticators) {
        this.customAuthenticators = customAuthenticators;
    }


    // -------------------------------------------------- WarComponents Methods


    public Iterator<String> getOverlays() {
        return overlays.iterator();
    }


    public Iterator<String> getWebFragments() {
        return order.iterator();
    }


    public Map<String, Set<String>> getTLDs() {
        return TLDs;
    }
   
   
    public Map<String, ServletContainerInitializerInfo> getServletContainerInitializerInfo() {
        return servletContainerInitializerInfos;
    }
   
   
    // --------------------------------------------------------- Public Methods


    /**
     * Process events for an associated Context.
     *
     * @param event The lifecycle event that has occurred
     */
    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.START_EVENT)) {
            start();
        } 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;
            }
            // Invoke Servlet container initializer: instantiate and call onStartup
            if (ok) {
                Iterator<ServletContainerInitializerInfo> initializers =
                    getServletContainerInitializerInfo().values().iterator();
                while (initializers.hasNext()) {
                    ServletContainerInitializerInfo service = initializers.next();
                    try {
                        ServletContainerInitializer servletContainerInitializer =
                            (ServletContainerInitializer) service.getServletContainerInitializer().newInstance();
                        servletContainerInitializer.onStartup(service.getStartupNotifySet(), context.getServletContext());
                    } catch (Throwable t) {
                        log.error(sm.getString("contextConfig.servletContainerInitializer",
                                service.getServletContainerInitializer().getName()), t);
                        ok = false;
                    }
                }
            }
        } else if (event.getType().equals(Context.COMPLETE_CONFIG_EVENT)) {
            completeConfig();
        } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
            if (originalDocBase != null) {
                String docBase = context.getDocBase();
                context.setDocBase(originalDocBase);
                originalDocBase = docBase;
            }
            stop();
        } else if (event.getType().equals(Lifecycle.INIT_EVENT)) {
            init();
        } else if (event.getType().equals(Lifecycle.DESTROY_EVENT)) {
            destroy();
        }

    }


    // -------------------------------------------------------- Protected Methods


    /**
     * Process the application classes annotations, if it exists.
     */
    protected void processConfigAnnotations(Class<?> clazz) {

        if (clazz.isAnnotationPresent(WebFilter.class)) {
            WebFilter annotation = clazz.getAnnotation(WebFilter.class);
            // Add servlet filter
            String filterName = annotation.filterName();
            FilterDef filterDef = new FilterDef();
            filterDef.setFilterName(annotation.filterName());
            filterDef.setFilterClass(clazz.getName());
            WebInitParam[] params = annotation.initParams();
            for (int i = 0; i < params.length; i++) {
                filterDef.addInitParameter(params[i].name(), params[i].value());
            }
            context.addFilterDef(filterDef);
            FilterMap filterMap = new FilterMap();
            filterMap.setFilterName(filterName);
            String[] urlPatterns = annotation.urlPatterns();
            if (urlPatterns != null) {
                for (int i = 0; i < urlPatterns.length; i++) {
                    filterMap.addURLPattern(urlPatterns[i]);
                }
            }
            String[] servletNames = annotation.servletNames();
            if (servletNames != null) {
                for (int i = 0; i < servletNames.length; i++) {
                    filterMap.addServletName(servletNames[i]);
                }
            }
            DispatcherType[] dispatcherTypes = annotation.dispatcherTypes();
            if (dispatcherTypes != null) {
                for (int i = 0; i < dispatcherTypes.length; i++) {
                    filterMap.setDispatcher(dispatcherTypes[i].toString());
                }
            }
            context.addFilterMap(filterMap);
        }
        if (clazz.isAnnotationPresent(WebServlet.class)) {
            WebServlet annotation = clazz.getAnnotation(WebServlet.class);
            // Add servlet
            Wrapper wrapper = context.createWrapper();
            wrapper.setName(annotation.name());
            wrapper.setServletClass(clazz.getName());
            wrapper.setLoadOnStartup(annotation.loadOnStartup());
            WebInitParam[] params = annotation.initParams();
            for (int i = 0; i < params.length; i++) {
                wrapper.addInitParameter(params[i].name(), params[i].value());
            }
            context.addChild(wrapper);
            String[] urlPatterns = annotation.urlPatterns();
            if (urlPatterns != null) {
                for (int i = 0; i < urlPatterns.length; i++) {
                    context.addServletMapping(urlPatterns[i], annotation.name());
                }
            }
        }
        if (clazz.isAnnotationPresent(WebListener.class)) {
            // Add listener
            context.addApplicationListener(clazz.getName());
        }

    }


    /**
     * Process the application configuration file, if it exists.
     */
    protected void applicationWebConfig() {

        String altDDName = null;

        // Open the application web.xml file, if it exists
        InputStream stream = null;
        ServletContext servletContext = context.getServletContext();
        if (servletContext != null) {
            altDDName = (String)servletContext.getAttribute(
                                                        Globals.ALT_DD_ATTR);
            if (altDDName != null) {
                try {
                    stream = new FileInputStream(altDDName);
                } catch (FileNotFoundException e) {
                    log.error(sm.getString("contextConfig.altDDNotFound",
                                           altDDName));
                }
            }
            else {
                stream = servletContext.getResourceAsStream
                    (Constants.ApplicationWebXml);
            }
        }
        if (stream == null) {
            if (log.isDebugEnabled()) {
                log.debug(sm.getString("contextConfig.applicationMissing") + " " + context);
            }
            return;
        }
       
        URL url=null;
        // Process the application web.xml file
        synchronized (webDigester) {
            try {
                if (altDDName != null) {
                    url = new File(altDDName).toURI().toURL();
                } else {
                    url = servletContext.getResource(
                                                Constants.ApplicationWebXml);
                }
                if( url!=null ) {
                    InputSource is = new InputSource(url.toExternalForm());
                    is.setByteStream(stream);
                    if (context instanceof StandardContext) {
                        ((StandardContext) context).setReplaceWelcomeFiles(true);
                    }
                    webDigester.push(context);
                    webDigester.setErrorHandler(new ContextErrorHandler());

                    if(log.isDebugEnabled()) {
                        log.debug("Parsing application web.xml file at " + url.toExternalForm());
                    }

                    webDigester.parse(is);

                    if (parseException != null) {
                        ok = false;
                    }
                } else {
                    log.info("No web.xml, using defaults " + context );
                }
            } catch (SAXParseException e) {
                log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e);
                log.error(sm.getString("contextConfig.applicationPosition",
                                 "" + e.getLineNumber(),
                                 "" + e.getColumnNumber()));
                ok = false;
            } catch (Exception e) {
                log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e);
                ok = false;
            } finally {
                webDigester.reset();
                webRuleSet.recycle();
                parseException = null;
                try {
                    if (stream != null) {
                        stream.close();
                    }
                } catch (IOException e) {
                    log.error(sm.getString("contextConfig.applicationClose"), e);
                }
            }
        }

    }
   
   
    /**
     * Parse TLDs. This is separate, and is not subject to the order defined. Also,
     * all TLDs from all JARs are parsed.
     */
    protected void applicationTldConfig() {
       
        Map<String, Set<String>> TLDs = getTLDs();
        Set<String> warTLDs = TLDs.get("");
        ArrayList<TagLibraryInfo> tagLibraries = new ArrayList<TagLibraryInfo>();

        // Parse all TLDs from the WAR
        Iterator<String> warTLDsIterator = warTLDs.iterator();
        InputStream stream = null;
        while (warTLDsIterator.hasNext()) {
            String tldPath = warTLDsIterator.next();
            try {
                stream = context.getServletContext().getResourceAsStream(tldPath);
                if (stream == null) {
                    log.error(sm.getString("contextConfig.tldResourcePath", tldPath));
                    ok = false;
                } else {
                    synchronized (tldDigester) {
                        TagLibraryInfo tagLibraryInfo = new TagLibraryInfo();
                        try {
                            tldDigester.push(tagLibraryInfo);
                            tldDigester.parse(new InputSource(stream));
                        } finally {
                            tldDigester.reset();
                        }
                        tagLibraryInfo.setLocation("");
                        tagLibraryInfo.setPath(tldPath);
                        tagLibraries.add(tagLibraryInfo);
                        context.addJspTagLibrary(tagLibraryInfo);
                        context.addJspTagLibrary(tldPath, tagLibraryInfo);
                    }
                }
            } catch (Exception e) {
                log.error(sm.getString("contextConfig.tldFileException", tldPath,
                        context.getPath()), e);
                ok = false;
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (Throwable t) {
                        // Ignore
                    }
                }
            }

        }

        // Parse all TLDs from JARs
        Iterator<String> jarPaths = TLDs.keySet().iterator();
        while (jarPaths.hasNext()) {
            String jarPath = jarPaths.next();
            if (jarPath.equals("")) {
                continue;
            }
            JarRepository jarRepository = context.getJarRepository();
            JarFile jarFile = jarRepository.findJar(jarPath);
            Iterator<String> jarTLDsIterator =  TLDs.get(jarPath).iterator();
            while (jarTLDsIterator.hasNext()) {
                try {
                    String tldPath = jarTLDsIterator.next();
                    stream = jarFile.getInputStream(jarFile.getEntry(tldPath));
                    synchronized (tldDigester) {
                        TagLibraryInfo tagLibraryInfo = new TagLibraryInfo();
                        try {
                            tldDigester.push(tagLibraryInfo);
                            tldDigester.parse(new InputSource(stream));
                        } finally {
                            tldDigester.reset();
                            if (stream != null) {
                                try {
                                    stream.close();
                                } catch (Throwable t) {
                                    // Ignore
                                }
                            }
                        }
                        tagLibraryInfo.setLocation(jarPath);
                        tagLibraryInfo.setPath(tldPath);
                        tagLibraries.add(tagLibraryInfo);
                        context.addJspTagLibrary(tagLibraryInfo);
                        if (tldPath.equals("META-INF/taglib.tld")) {
                            context.addJspTagLibrary(jarPath, tagLibraryInfo);
                        }
                    }
                } catch (Exception e) {
                    log.error(sm.getString("contextConfig.tldJarException",
                            jarPath, context.getPath()), e);
                    ok = false;
                } finally {
                    if (stream != null) {
                        try {
                            stream.close();
                        } catch (Throwable t) {
                            // Ignore
                        }
                    }
                }
            }
        }
       
        // Add additional TLDs URIs from explicit web config
        String taglibs[] = context.findTaglibs();
        for (int i = 0; i < taglibs.length; i++) {
            String uri = taglibs[i];
            String path = context.findTaglib(taglibs[i]);
            String location = "";
            if (path.indexOf(':') == -1 && !path.startsWith("/")) {
                path = "/WEB-INF/" + path;
            }
            if (path.endsWith(".jar")) {
                location = path;
                path = "META-INF/taglib.tld";
            }
            for (int j = 0; j < tagLibraries.size(); j++) {
                TagLibraryInfo tagLibraryInfo = tagLibraries.get(j);
                if (tagLibraryInfo.getLocation().equals(location) && tagLibraryInfo.getPath().equals(path)) {
                    context.addJspTagLibrary(uri, tagLibraryInfo);
                }
            }
        }

    }
   

    /**
     * Set up an Authenticator automatically if required, and one has not
     * already been configured.
     */
    protected void authenticatorConfig() {

        // Does this Context require an Authenticator?
        SecurityConstraint constraints[] = context.findConstraints();
        if ((constraints == null) || (constraints.length == 0))
            return;
        LoginConfig loginConfig = context.getLoginConfig();
        if (loginConfig == null) {
            loginConfig = DUMMY_LOGIN_CONFIG;
            context.setLoginConfig(loginConfig);
        }

        // Has an authenticator been configured already?
        if (context instanceof Authenticator)
            return;
        if (context instanceof ContainerBase) {
            Pipeline pipeline = ((ContainerBase) context).getPipeline();
            if (pipeline != null) {
                Valve basic = pipeline.getBasic();
                if ((basic != null) && (basic instanceof Authenticator))
                    return;
                Valve valves[] = pipeline.getValves();
                for (int i = 0; i < valves.length; i++) {
                    if (valves[i] instanceof Authenticator)
                        return;
                }
            }
        } else {
            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) {
                log.error(sm.getString(
                                    "contextConfig.authenticatorInstantiate",
                                    authenticatorName),
                          t);
                ok = false;
            }
        }

        if (authenticator instanceof Authenticator) {
            context.setAuthenticator((Authenticator) authenticator);
        }
        if (authenticator != null && context instanceof ContainerBase) {
            Pipeline pipeline = ((ContainerBase) context).getPipeline();
            if (pipeline != null) {
                ((ContainerBase) context).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).
     */
    protected static Digester createWebDigester() {
        return DigesterFactory.newDigester(Globals.XML_NAMESPACE_AWARE, Globals.XML_VALIDATION, webRuleSet);
    }


    /**
     * Create (if necessary) and return a Digester configured to process the
     * web application fragment descriptors (web-fragment.xml).
     */
    protected static Digester createWebFragmentDigester() {
        return DigesterFactory.newDigester(Globals.XML_NAMESPACE_AWARE, Globals.XML_VALIDATION, webFragmentRuleSet);
    }


    /**
     * Create (if necessary) and return a Digester configured to process tag
     * library descriptors.
     */
    protected static Digester createTldDigester() {
        return DigesterFactory.newDigester(Globals.XML_NAMESPACE_AWARE, Globals.XML_VALIDATION, new TldRuleSet());
    }


    /**
     * Create (if necessary) and return a Digester configured to process web fragments ordering.
     */
    protected static Digester createFragmentOrderingDigester() {
        return DigesterFactory.newDigester(Globals.XML_NAMESPACE_AWARE,
                Globals.XML_VALIDATION, new WebOrderingRuleSet());
    }


    /**
     * Create (if necessary) and return a Digester configured to process the
     * context configuration descriptor for an application.
     */
    protected static Digester createContextDigester() {
        Digester digester = new Digester();
        digester.setValidating(false);
        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("catalina.base");
    }

    /**
     * Process the default configuration file, if it exists.
     * The default config must be read with the container loader - so
     * container servlets can be loaded
     */
    protected void defaultWebConfig() {
        long t1=System.currentTimeMillis();

        // Open the default web.xml file, if it exists
        if( defaultWebXml==null && context instanceof StandardContext ) {
            defaultWebXml=((StandardContext)context).getDefaultWebXml();
        }
        // set the default if we don't have any overrides
        if( defaultWebXml==null ) getDefaultWebXml();

        File file = new File(this.defaultWebXml);
        if (!file.isAbsolute()) {
            file = new File(getBaseDir(),
                            this.defaultWebXml);
        }

        InputStream stream = null;
        InputSource source = null;

        try {
            if ( ! file.exists() ) {
                // Use getResource and getResourceAsStream
                stream = getClass().getClassLoader()
                    .getResourceAsStream(defaultWebXml);
                if( stream != null ) {
                    source = new InputSource
                            (getClass().getClassLoader()
                            .getResource(defaultWebXml).toString());
                }
                if( stream== null ) {
                    // maybe embedded
                    stream = getClass().getClassLoader()
                        .getResourceAsStream("web-embed.xml");
                    if( stream != null ) {
                        source = new InputSource
                        (getClass().getClassLoader()
                                .getResource("web-embed.xml").toString());
                    }                                        
                }
               
                if( stream== null ) {
                    log.info("No default web.xml");
                }
            } else {
                source =
                    new InputSource("file://" + file.getAbsolutePath());
                stream = new FileInputStream(file);
                context.addWatchedResource(file.getAbsolutePath());
            }
        } catch (Exception e) {
            log.error(sm.getString("contextConfig.defaultMissing")
                      + " " + defaultWebXml + " " + file , e);
        }

        if (stream != null) {
            processDefaultWebConfig(webDigester, stream, source);
            webRuleSet.recycle();
        }

        long t2=System.currentTimeMillis();
        if( (t2-t1) > 200 )
            log.debug("Processed default web.xml " + file + " "  + ( t2-t1));

        stream = null;
        source = null;

        String resourceName = getHostConfigPath(Constants.HostWebXml);
        file = new File(getConfigBase(), resourceName);
       
        try {
            if ( ! file.exists() ) {
                // Use getResource and getResourceAsStream
                stream = getClass().getClassLoader()
                    .getResourceAsStream(resourceName);
                if( stream != null ) {
                    source = new InputSource
                            (getClass().getClassLoader()
                            .getResource(resourceName).toString());
                }
            } else {
                source =
                    new InputSource("file://" + file.getAbsolutePath());
                stream = new FileInputStream(file);
            }
        } catch (Exception e) {
            log.error(sm.getString("contextConfig.defaultMissing")
                      + " " + resourceName + " " + file , e);
        }

        if (stream != null) {
            processDefaultWebConfig(webDigester, stream, source);
            webRuleSet.recycle();
        }

    }


    /**
     * Process a default web.xml.
     */
    protected void processDefaultWebConfig(Digester digester, InputStream stream,
            InputSource source) {

        if (log.isDebugEnabled())
            log.debug("Processing context [" + context.getName()
                    + "] web configuration resource " + source.getSystemId());

        // Process the default web.xml file
        synchronized (digester) {
            try {
                source.setByteStream(stream);
               
                if (context instanceof StandardContext)
                    ((StandardContext) context).setReplaceWelcomeFiles(true);
                digester.setClassLoader(this.getClass().getClassLoader());
                digester.setUseContextClassLoader(false);
                digester.push(context);
                digester.setErrorHandler(new ContextErrorHandler());
                digester.parse(source);
                if (parseException != null) {
                    ok = false;
                }
            } catch (SAXParseException e) {
                log.error(sm.getString("contextConfig.defaultParse"), e);
                log.error(sm.getString("contextConfig.defaultPosition",
                                 "" + e.getLineNumber(),
                                 "" + e.getColumnNumber()));
                ok = false;
            } catch (Exception e) {
                log.error(sm.getString("contextConfig.defaultParse"), e);
                ok = false;
            } finally {
                digester.reset();
                parseException = null;
                try {
                    if (stream != null) {
                        stream.close();
                    }
                } catch (IOException e) {
                    log.error(sm.getString("contextConfig.defaultClose"), e);
                }
            }
        }
    }

   
    /**
     * Parse fragments order.
     */
    protected void createFragmentsOrder() {
       
        WebAbsoluteOrdering absoluteOrdering = context.getWebAbsoluteOrdering();
        List<WebOrdering> orderings = new ArrayList<WebOrdering>();
        HashSet<String> jarsSet = new HashSet<String>();
        boolean fragmentFound = false;
       
        // Parse the ordering defined in web fragments
        JarRepository jarRepository = context.getJarRepository();
        JarFile[] jars = jarRepository.findJars();
        for (int i = 0; i < jars.length; i++) {
            // Find webapp descriptor fragments
            jarsSet.add(jars[i].getName());
            JarFile jarFile = jars[i];
            InputStream is = null;
            ZipEntry entry = jarFile.getEntry(Globals.WEB_FRAGMENT_PATH);
            if (entry != null) {
                fragmentFound = true;
                try {
                    webFragments.add(jars[i].getName());
                    is = jarFile.getInputStream(entry);
                    InputSource input = new InputSource((new File(jars[i].getName())).toURI().toURL().toExternalForm());
                    input.setByteStream(is);
                    synchronized (fragmentOrderingDigester) {
                        try {
                            fragmentOrderingDigester.parse(input);
                            WebOrdering ordering = (WebOrdering) fragmentOrderingDigester.peek();
                            if (ordering != null) {
                                ordering.setJar(jars[i].getName());
                                orderings.add(ordering);
                            }
                        } finally {
                            fragmentOrderingDigester.reset();
                        }
                    }
                } catch (Exception e) {
                    log.error(sm.getString("contextConfig.fragmentOrderingParse", jars[i].getName()), e);
                    ok = false;
                } finally {
                    try {
                        if (is != null) {
                            is.close();
                        }
                    } catch (IOException e) {
                        // Ignore
                    }
                }
            } else {
                // If there is no fragment, still consider it for ordering as a
                // fragment specifying no name and no order
                WebOrdering ordering = new WebOrdering();
                ordering.setJar(jars[i].getName());
                orderings.add(ordering);
            }
        }
        if (!fragmentFound) {
            // Drop the order as there is no fragment in the webapp
            orderings.clear();
        }
       
        // Generate web fragments parsing order
        if (absoluteOrdering != null) {
            // Absolute ordering from web.xml, any relative fragment ordering is ignored
            List<String> fragmentNames = absoluteOrdering.getOrder();
            int otherPos = -1;
            for (int i = 0; i < fragmentNames.size(); i++) {
                String fragmentName = fragmentNames.get(i);
                if (fragmentName.equals("*")) {
                    if (otherPos >= 0) {
                        log.error(sm.getString("contextConfig.invalidAbsoluteOrder"));
                        ok = false;
                    }
                    otherPos = i;
                } else {
                    Iterator<WebOrdering> orderingsIterator = orderings.iterator();
                    while (orderingsIterator.hasNext()) {
                        WebOrdering ordering = orderingsIterator.next();
                        if (fragmentName.equals(ordering.getName())) {
                            order.add(ordering.getJar());
                            jarsSet.remove(ordering.getJar());
                            break;
                        }
                    }
                }
            }
            if (otherPos >= 0) {
                order.addAll(otherPos, jarsSet);
            }
        } else if (orderings.size() > 0) {
            // Resolve relative ordering
            try {
                OrderingResolver.resolveOrder(orderings, order);
            } catch (IllegalStateException e) {
                log.error(e.getMessage(), e);
                ok = false;
            }
        } else {
            // No order specified
            order.addAll(jarsSet);
        }
       
    }
   
   
    /**
     * Get the jar name corresponding to the ordering name.
     */
    protected String getJarName(List<WebOrdering> orderings, String name) {
        Iterator<WebOrdering> orderingsIterator = orderings.iterator();
        while (orderingsIterator.hasNext()) {
            WebOrdering ordering = orderingsIterator.next();
            if (name.equals(ordering.getName())) {
                return ordering.getJar();
            }
        }
        return null;
    }
   
   
    /**
     * Process additional descriptors: TLDs, web fragments, and map overlays.
     */
    protected void applicationExtraDescriptorsConfig() {
       
        JarRepository jarRepository = context.getJarRepository();

        HashSet<String> warTLDs = new HashSet<String>();

        // Find any TLD file in /WEB-INF
        DirContext resources = context.getResources();
        if (resources != null) {
            tldScanResourcePathsWebInf(resources, "/WEB-INF", warTLDs);
        }
        TLDs.put("", warTLDs);
       
        File[] explodedJars = jarRepository.findExplodedJars();
        for (int i = 0; i < explodedJars.length; i++) {
            scanClasses(explodedJars[i], "", !context.getIgnoreAnnotations());
        }
       
        // Parse web fragment according to order
        Iterator<String> orderIterator = order.iterator();
        while (orderIterator.hasNext()) {
            String jar = orderIterator.next();
            JarFile jarFile = jarRepository.findJar(jar);
            InputStream is = null;
            ZipEntry entry = jarFile.getEntry(Globals.WEB_FRAGMENT_PATH);
            if (entry != null) {
                try {
                    is = jarFile.getInputStream(entry);
                    InputSource input = new InputSource((new File(jar)).toURI().toURL().toExternalForm());
                    input.setByteStream(is);
                    synchronized (webFragmentDigester) {
                        try {
                            webFragmentDigester.push(context);
                            webFragmentDigester.setErrorHandler(new ContextErrorHandler());
                            webFragmentDigester.parse(input);
                            if (parseException != null) {
                                ok = false;
                            }
                        } finally {
                            webFragmentDigester.reset();
                            webFragmentRuleSet.recycle();
                            parseException = null;
                        }
                    }
                } catch (Exception e) {
                    log.error(sm.getString("contextConfig.applicationParse", jar), e);
                    ok = false;
                } finally {
                    try {
                        if (is != null) {
                            is.close();
                        }
                    } catch (IOException e) {
                        // Ignore
                    }
                }
            }
            // Scan the JAR for TLDs and annotations
            scanJar(jarFile, true);
        }
       
        // Process any Jar not in the order
        JarFile[] jarFiles = jarRepository.findJars();
        for (int i = 0; i < jarFiles.length; i++) {
            if (!order.contains(jarFiles[i].getName())) {
                // Scan the JAR for TLDs only
                scanJar(jarFiles[i], false);
            }
        }
       
    }
   
   
    protected void scanJar(JarFile jarFile, boolean annotations) {
       
        // Scan Jar for annotations and TLDs
        HashSet<String> jarTLDs = new HashSet<String>();
        Enumeration<JarEntry> entries = jarFile.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String name = entry.getName();
            if (name.endsWith(".class")) {
                String className = getClassName(entry.getName());
                scanClass(className, annotations);
            } else if (name.startsWith("META-INF/") && name.endsWith(".tld")) {
                jarTLDs.add(name);
            }
        }
        if (jarTLDs.size() > 0) {
            TLDs.put(jarFile.getName(), jarTLDs);
        }

    }
   

    /**
     * Scans the web application's subdirectory identified by rootPath,
     * along with its subdirectories, for TLDs.
     *
     * Initially, rootPath equals /WEB-INF. The /WEB-INF/classes and
     * /WEB-INF/lib subdirectories are excluded from the search, as per the
     * JSP 2.0 spec.
     *
     * @param resources The web application's resources
     * @param rootPath The path whose subdirectories are to be searched for
     * TLDs
     * @param tldPaths The set of TLD resource paths to add to
     */
    protected void tldScanResourcePathsWebInf(DirContext resources,
                                            String rootPath,
                                            HashSet<String> tldPaths) {
        try {
            NamingEnumeration<NameClassPair> items = resources.list(rootPath);
            while (items.hasMoreElements()) {
                NameClassPair item = items.nextElement();
                String resourcePath = rootPath + "/" + item.getName();
                if (!resourcePath.endsWith(".tld")
                        && (resourcePath.startsWith("/WEB-INF/classes")
                            || resourcePath.startsWith("/WEB-INF/lib"))) {
                    continue;
                }
                if (resourcePath.endsWith(".tld")) {
                    tldPaths.add(resourcePath);
                } else {
                    tldScanResourcePathsWebInf(resources, resourcePath,
                                               tldPaths);
                }
            }
        } catch (NamingException e) {
            ; // Silent catch: it's valid that no /WEB-INF directory exists
        }
    }


    /**
     * Scan folder containing class files.
     */
    protected void scanClasses(File folder, String path, boolean annotations) {
        String[] files = folder.list();
        for (int i = 0; i < files.length; i++) {
            File file = new File(folder, files[i]);
            if (file.isDirectory()) {
                scanClasses(file, path + "/" + files[i], annotations);
            } else if (files[i].endsWith(".class")) {
                String className = getClassName(path + "/" + files[i]);
                scanClass(className, annotations);
            }
        }
    }
   
   
    protected void scanClass(String className, boolean annotations) {
        if (!annotations && (handlesTypesArray == null)) {
            return;
        }
        try {
            Class<?> clazz = context.getLoader().getClassLoader().loadClass(className);
            if (handlesTypesArray != null) {
                for (int i = 0; i < handlesTypesArray.length; i++) {
                    if (handlesTypesArray[i].isAssignableFrom(clazz)) {
                        ServletContainerInitializerInfo jarServletContainerInitializerService =
                            handlesTypes.get(handlesTypesArray[i]);
                        jarServletContainerInitializerService.addStartupNotifyClass(clazz);
                    }
                }
            }
            if (annotations &&
                    (clazz.isAnnotationPresent(MultipartConfig.class)
                    || clazz.isAnnotationPresent(WebFilter.class)
                    || clazz.isAnnotationPresent(WebInitParam.class)
                    || clazz.isAnnotationPresent(WebListener.class)
                    || clazz.isAnnotationPresent(WebServlet.class))) {
                processConfigAnnotations(clazz);
            }
        } catch (Throwable t) {
            // Ignore classloading errors here
        }
    }
   
   
    /**
     * Get class name given a path to a classfile.
     * /my/class/MyClass.class -> my.class.MyClass
     */
    protected String getClassName(String filePath) {
        if (filePath.startsWith("/")) {
            filePath = filePath.substring(1);
        }
        if (filePath.endsWith(".class")) {
            filePath = filePath.substring(0, filePath.length() - ".class".length());
        }
        return filePath.replace('/', '.');
    }
   
   
    /**
     * Find and parse ServletContainerInitializer service in specified JAR.
     */
    public void applicationServletContainerInitializerConfig() {
        JarRepository jarRepository = context.getJarRepository();
        if (jarRepository != null) {
            JarFile[] jars = jarRepository.findJars();
            for (int i = 0; i < jars.length; i++) {
                scanJarForServletContainerInitializer(jars[i]);
            }
        }
        // Do the same for the context parent
        jarRepository = context.getParent().getJarRepository();
        if (jarRepository != null) {
            JarFile[] jars = jarRepository.findJars();
            for (int i = 0; i < jars.length; i++) {
                scanJarForServletContainerInitializer(jars[i]);
            }
        }
    }
   
   
    /**
     * Find and parse ServletContainerInitializer service in specified JAR.
     */
    public void scanJarForServletContainerInitializer(JarFile file) {
        // Find ServletContainerInitializer services
        JarEntry servletContainerInitializerEntry = file.getJarEntry(Globals.SERVLET_CONTAINER_INITIALIZER_SERVICE_PATH);
        String servletContainerInitializerClassName = null;
        if (servletContainerInitializerEntry != null) {
            // Read Servlet container initializer service file
            InputStream is = null;
            try {
                is = file.getInputStream(servletContainerInitializerEntry);
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                servletContainerInitializerClassName = reader.readLine();
                int pos = servletContainerInitializerClassName.indexOf('#');
                if (pos > 0) {
                    servletContainerInitializerClassName = servletContainerInitializerClassName.substring(0, pos);
                }
                servletContainerInitializerClassName = servletContainerInitializerClassName.trim();
            } catch (Exception e) {
                log.warn(sm.getString("contextConfig.servletContainerInitializer", file.getName()), e);
                return;
            } finally {
                try {
                    if (is != null) {
                        is.close();
                    }
                } catch (IOException e) {
                    // Ignore
                }
            }
            // Load Servlet container initializer class and read HandlesTypes annotation
            Class<?> servletContainerInitializerClass = null;
            Class<?>[] typesArray = null;
            if (servletContainerInitializerClassName != null) {
                try {
                    servletContainerInitializerClass = context.getLoader().getClassLoader()
                        .loadClass(servletContainerInitializerClassName);
                    if (servletContainerInitializerClass.isAnnotationPresent(HandlesTypes.class)) {
                        HandlesTypes handlesTypes = servletContainerInitializerClass.getAnnotation(HandlesTypes.class);
                        typesArray = handlesTypes.value();
                    }
                } catch (Throwable t) {
                    log.warn(sm.getString("contextConfig.servletContainerInitializer", file.getName()), t);
                    return;
                }
            }
            // Add in jarService map, and add in the local map used to speed up lookups
            ServletContainerInitializerInfo jarServletContainerInitializerService =
                new ServletContainerInitializerInfo(servletContainerInitializerClass, handlesTypesArray);
            servletContainerInitializerInfos.put(file.getName(), jarServletContainerInitializerService);
            if (typesArray != null) {
                ArrayList<Class<?>> handlesTypesList = new ArrayList<Class<?>>();
                if (handlesTypesArray != null) {
                    for (int i = 0; i < handlesTypesArray.length; i++) {
                        handlesTypesList.add(handlesTypesArray[i]);
                    }
                }
                for (int i = 0; i < typesArray.length; i++) {
                    handlesTypesList.add(typesArray[i]);
                    handlesTypes.put(typesArray[i], jarServletContainerInitializerService);
                }
                handlesTypesArray = handlesTypesList.toArray(handlesTypesArray);
            }
        }
    }
   
   
    /**
     * Process the default configuration file, if it exists.
     */
    protected void contextConfig() {
       
        // Open the default web.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()) {
            processContextConfig(new File(getBaseDir()), defaultContextXml);
            processContextConfig(getConfigBase(), getHostConfigPath(Constants.HostContextXml));
        }
        if (context.getConfigFile() != null)
            processContextConfig(new File(context.getConfigFile()), null);
       
        if (context.getJarRepository() == null) {
            context.setJarRepository(new ContextJarRepository());
        }

    }

   
    /**
     * Process a context.xml.
     */
    protected void processContextConfig(File baseDir, String resourceName) {
       
        if (log.isDebugEnabled())
            log.debug("Processing context [" + context.getName()
                    + "] configuration file " + baseDir + " " + resourceName);

        InputSource source = null;
        InputStream stream = null;

        File file = baseDir;
        if (resourceName != null) {
            file = new File(baseDir, resourceName);
        }
       
        try {
            if ( !file.exists() ) {
                if (resourceName != null) {
                    // Use getResource and getResourceAsStream
                    stream = getClass().getClassLoader()
                        .getResourceAsStream(resourceName);
                    if( stream != null ) {
                        source = new InputSource
                            (getClass().getClassLoader()
                            .getResource(resourceName).toString());
                    }
                }
            } else {
                source =
                    new InputSource("file://" + file.getAbsolutePath());
                stream = new FileInputStream(file);
                // Add as watched resource so that cascade reload occurs if a default
                // config file is modified/added/removed
                context.addWatchedResource(file.getAbsolutePath());
            }
        } catch (Exception e) {
            log.error(sm.getString("contextConfig.contextMissing"
                      resourceName + " " + file) , 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);
                contextDigester.setErrorHandler(new ContextErrorHandler());
                contextDigester.parse(source);
                if (parseException != null) {
                    ok = false;
                }
                if (log.isDebugEnabled())
                    log.debug("Successfully processed context [" + context.getName()
                            + "] configuration file " + baseDir + " " + resourceName);
            } 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();
                parseException = null;
                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();
        String appBase = host.getAppBase();

        boolean unpackWARs = true;
        if (host instanceof StandardHost) {
            unpackWARs = ((StandardHost) host).isUnpackWARs()
                && ((StandardContext) context).getUnpackWAR();
        }

        File canonicalAppBase = new File(appBase);
        if (canonicalAppBase.isAbsolute()) {
            canonicalAppBase = canonicalAppBase.getCanonicalFile();
        } else {
            canonicalAppBase =
                new File(System.getProperty("catalina.base"), appBase)
                .getCanonicalFile();
        }

        String docBase = context.getDocBase();
        if (docBase == null) {
            // Trying to guess the docBase according to the path
            String path = context.getPath();
            if (path == null) {
                return;
            }
            if (path.equals("")) {
                docBase = "ROOT";
            } else {
                if (path.startsWith("/")) {
                    docBase = path.substring(1).replace('/', '#');
                } else {
                    docBase = path.replace('/', '#');
                }
            }
        }

        File file = new File(docBase);
        if (!file.isAbsolute()) {
            docBase = (new File(canonicalAppBase, docBase)).getPath();
        } else {
            docBase = file.getCanonicalPath();
        }
        file = new File(docBase);
        String origDocBase = docBase;
       
        String contextPath = context.getPath();
        if (contextPath.equals("")) {
            contextPath = "ROOT";
        } else {
            if (contextPath.lastIndexOf('/') > 0) {
                contextPath = "/" + contextPath.substring(1).replace('/','#');
            }
        }
        if (docBase.toLowerCase().endsWith(".war") && !file.isDirectory() && unpackWARs) {
            URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/");
            docBase = ExpandWar.expand(host, war, contextPath);
            file = new File(docBase);
            docBase = file.getCanonicalPath();
            if (context instanceof StandardContext) {
                ((StandardContext) context).setOriginalDocBase(origDocBase);
            }
        } else {
            File docDir = new File(docBase);
            if (!docDir.exists()) {
                File warFile = new File(docBase + ".war");
                if (warFile.exists()) {
                    if (unpackWARs) {
                        URL war = new URL("jar:" + warFile.toURI().toURL() + "!/");
                        docBase = ExpandWar.expand(host, war, contextPath);
                        file = new File(docBase);
                        docBase = file.getCanonicalPath();
                    } else {
                        docBase = warFile.getCanonicalPath();
                    }
                }
                if (context instanceof StandardContext) {
                    ((StandardContext) context).setOriginalDocBase(origDocBase);
                }
            }
        }

        if (docBase.startsWith(canonicalAppBase.getPath() + File.separatorChar)) {
            docBase = docBase.substring(canonicalAppBase.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 appBase = host.getAppBase();
            String docBase = context.getDocBase();
            if (docBase == null)
                return;
            if (originalDocBase == null) {
                originalDocBase = docBase;
            } else {
                docBase = originalDocBase;
            }
            File docBaseFile = new File(docBase);
            if (!docBaseFile.isAbsolute()) {
                File file = new File(appBase);
                if (!file.isAbsolute()) {
                    file = new File(System.getProperty("catalina.base"), appBase);
                }
                docBaseFile = new File(file, docBase);
            }
           
            String path = context.getPath();
            if (path == null) {
                return;
            }
            if (path.equals("")) {
                docBase = "ROOT";
            } else {
                if (path.startsWith("/")) {
                    docBase = path.substring(1);
                } else {
                    docBase = path;
                }
            }

            File file = null;
            if (docBase.toLowerCase().endsWith(".war")) {
                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.getPath()
                        + "] 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 (webDigester == null){
            webDigester = createWebDigester();
            webDigester.getParser();
        }

        if (webFragmentDigester == null){
            webFragmentDigester = createWebFragmentDigester();
            webFragmentDigester.getParser();
        }

        if (tldDigester == null){
            tldDigester = createTldDigester();
            tldDigester.getParser();
        }

        if (fragmentOrderingDigester == null){
            fragmentOrderingDigester = createFragmentOrderingDigester();
            fragmentOrderingDigester.getParser();
        }

        if (contextDigester == null){
            contextDigester = createContextDigester();
            contextDigester.getParser();
        }

        if (log.isDebugEnabled())
            log.debug(sm.getString("contextConfig.init"));
        context.setConfigured(false);
        ok = true;
       
        contextConfig();
       
        try {
            fixDocBase();
        } catch (IOException e) {
            log.error(sm.getString("contextConfig.fixDocBase"), e);
        }
       
    }
   
   
    /**
     * Process a "before start" event for this Context.
     */
    protected void beforeStart() {
        antiLocking();
    }
   
   
    /**
     * Process a "start" event for this Context.
     */
    protected void start() {
        // Called from StandardContext.start()

        if (log.isDebugEnabled())
            log.debug(sm.getString("contextConfig.start"));

        // Process the default and application web.xml files
        if (ok) {
            defaultWebConfig();
        }
        // Scan the main descriptors
        if (ok) {
            applicationWebConfig();
        }
        // Parse any Servlet context initializer defined in a Jar
        if (ok) {
            applicationServletContainerInitializerConfig();
        }
        // Parse fragment order
        if (ok && !context.getIgnoreAnnotations()) {
            createFragmentsOrder();
        }
        // Scan fragments, TLDs and annotations
        if (ok) {
            applicationExtraDescriptorsConfig();
        }
        // Parse any TLDs found for listeners
        if (ok) {
            applicationTldConfig();
        }

        // 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 "start" event for this Context.
     */
    protected void completeConfig() {
        // Called from StandardContext.start()

        // Scan all Servlet API related annotations
        if (ok && !context.getIgnoreAnnotations()) {
            WebAnnotationSet.loadApplicationAnnotations(context);
        }
        // Resolve security
        if (ok) {
            resolveServletSecurity();
        }
        if (ok) {
            validateSecurityRoles();
        }

        // Configure an authenticator if we need one
        if (ok) {
            authenticatorConfig();
        }

        // Find and configure overlays
        if (ok) {
            JarRepository jarRepository = context.getJarRepository();
            JarFile[] jars = jarRepository.findJars();
            for (int i = 0; i < jars.length; i++) {
                if (jars[i].getEntry(Globals.OVERLAY_PATH) != null) {
                    if (context.getResources() instanceof ProxyDirContext) {
                        ProxyDirContext resources = (ProxyDirContext) context.getResources();
                        JARDirContext overlay = new JARDirContext();
                        overlay.setJarFile(jars[i], Globals.OVERLAY_PATH);
                        resources.addOverlay(overlay);
                    } else {
                        // Error, overlays need a ProxyDirContext to compose results
                        log.error(sm.getString("contextConfig.noOverlay", jars[i].getName()));
                        ok = false;
                    }
                    overlays.add(jars[i].getName());
                }
            }
        }

        // Make our application unavailable if problems were encountered
        if (!ok) {
            log.error(sm.getString("contextConfig.unavailable"));
            context.setConfigured(false);
        }

    }

    /**
     * Process a "stop" event for this Context.
     */
    protected void stop() {

        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 sercurity 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 taglibs
        String[] taglibs = context.findTaglibs();
        for (i = 0; i < taglibs.length; i++) {
            context.removeTaglib(taglibs[i]);
        }

        // FIXME: remove JSP property groups
       
        // FIXME: remove JSP tag libraries
       
        // 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 appBase = host.getAppBase();
        String docBase = context.getDocBase();
        if ((docBase != null) && (originalDocBase != null)) {
            File docBaseFile = new File(docBase);
            if (!docBaseFile.isAbsolute()) {
                docBaseFile = new File(appBase, docBase);
            }
            ExpandWar.delete(docBaseFile);
        }
       
        overlays.clear();
        webFragments.clear();
        TLDs.clear();
        servletContainerInitializerInfos.clear();
        order.clear();
        handlesTypesArray = null;
        handlesTypes.clear();
       
        ok = true;

    }
   
   
    /**
     * Process a "destroy" event for this Context.
     */
    protected void destroy() {
        // Called from StandardContext.destroy()
        if (log.isDebugEnabled())
            log.debug(sm.getString("contextConfig.destroy"));

        // Changed to getWorkPath per Bugzilla 35819.
        String workDir = ((StandardContext) context).getWorkPath();
        if (workDir != null)
            ExpandWar.delete(new File(workDir));
    }
   
   
    /**
     * Translate servlet security associated with Servlets to security constraints.
     */
    protected void resolveServletSecurity() {
        Container wrappers[] = context.findChildren();
        for (int i = 0; i < wrappers.length; i++) {
            Wrapper wrapper = (Wrapper) wrappers[i];
            ServletSecurityElement servletSecurity = wrapper.getServletSecurity();
            if (servletSecurity != null) {
               
                ArrayList<String> methodOmissions = new ArrayList<String>();
                boolean classPA = servletSecurity.getEmptyRoleSemantic().equals(EmptyRoleSemantic.PERMIT);
                boolean classDA = servletSecurity.getEmptyRoleSemantic().equals(EmptyRoleSemantic.DENY);
                boolean classTP = servletSecurity.getTransportGuarantee().equals(TransportGuarantee.CONFIDENTIAL);
                String[] classRA = servletSecurity.getRolesAllowed();
                Collection<HttpMethodConstraintElement> httpMethodConstraints =
                    servletSecurity.getHttpMethodConstraints();

                // Process method constraints
                if (httpMethodConstraints != null && httpMethodConstraints.size() > 0)
                {
                   for (HttpMethodConstraintElement httpMethodConstraint : httpMethodConstraints)
                   {
                      methodOmissions.add(httpMethodConstraint.getMethodName());
                      boolean methodPA = httpMethodConstraint.getEmptyRoleSemantic().equals(EmptyRoleSemantic.PERMIT);
                      boolean methodDA = httpMethodConstraint.getEmptyRoleSemantic().equals(EmptyRoleSemantic.DENY);
                      boolean methodTP = httpMethodConstraint.getTransportGuarantee().equals(TransportGuarantee.CONFIDENTIAL);
                      String[] methodRA = httpMethodConstraint.getRolesAllowed();
                      if (methodDA || methodTP || (methodRA != null && methodRA.length > 0))
                      {
                         // Define a constraint specific for the method
                         SecurityConstraint constraint = new SecurityConstraint();
                         if (methodDA) {
                             constraint.setAuthConstraint(true);
                         }
                         if (methodPA) {
                             constraint.addAuthRole("*");
                         }
                         if (methodRA != null) {
                             for (String role : methodRA) {
                                 constraint.addAuthRole(role);
                             }
                         }
                         if (methodTP) {
                             constraint.setUserConstraint(org.apache.catalina.realm.Constants.CONFIDENTIAL_TRANSPORT);
                         }
                         SecurityCollection collection = new SecurityCollection();
                         collection.addMethod(httpMethodConstraint.getMethodName());
                         // Determine pattern set
                         String[] urlPatterns = wrapper.findMappings();
                         Set<String> servletSecurityPatterns = new HashSet<String>();
                         for (String urlPattern : urlPatterns) {
                             servletSecurityPatterns.add(urlPattern);
                         }
                         SecurityConstraint[] constraints = context.findConstraints();
                         for (SecurityConstraint constraint2 : constraints) {
                             for (SecurityCollection collection2 : constraint2.findCollections()) {
                                 for (String urlPattern : collection2.findPatterns()) {
                                     if (servletSecurityPatterns.contains(urlPattern)) {
                                         servletSecurityPatterns.remove(urlPattern);
                                     }
                                 }
                             }
                         }
                         for (String urlPattern : servletSecurityPatterns) {
                             collection.addPattern(urlPattern);
                         }
                         constraint.addCollection(collection);
                         context.addConstraint(constraint);
                      }

                   }

                }

                if (classDA || classTP || (classRA != null && classRA.length > 0))
                {
                    // Define a constraint for the class
                    SecurityConstraint constraint = new SecurityConstraint();
                    if (classPA) {
                        constraint.addAuthRole("*");
                    }
                    if (classDA) {
                        constraint.setAuthConstraint(true);
                    }
                    if (classRA != null) {
                        for (String role : classRA) {
                            constraint.addAuthRole(role);
                        }
                    }
                    if (classTP) {
                        constraint.setUserConstraint(org.apache.catalina.realm.Constants.CONFIDENTIAL_TRANSPORT);
                    }
                    SecurityCollection collection = new SecurityCollection();
                    // Determine pattern set
                    String[] urlPatterns = wrapper.findMappings();
                    Set<String> servletSecurityPatterns = new HashSet<String>();
                    for (String urlPattern : urlPatterns) {
                        servletSecurityPatterns.add(urlPattern);
                    }
                    SecurityConstraint[] constraints = context.findConstraints();
                    for (SecurityConstraint constraint2 : constraints) {
                        for (SecurityCollection collection2 : constraint2.findCollections()) {
                            for (String urlPattern : collection2.findPatterns()) {
                                if (servletSecurityPatterns.contains(urlPattern)) {
                                    servletSecurityPatterns.remove(urlPattern);
                                }
                            }
                        }
                    }
                    for (String urlPattern : servletSecurityPatterns) {
                        collection.addPattern(urlPattern);
                    }
                    for (String methodOmission : methodOmissions) {
                        collection.addMethodOmission(methodOmission);
                    }
                    constraint.addCollection(collection);
                    context.addConstraint(constraint);
                }
               
            }
        }
    }
   
   
    /**
     * 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("catalina.base"), "conf");
        if (!configBase.exists()) {
            return null;
        } else {
            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();
    }


    protected class ContextErrorHandler
        implements ErrorHandler {

        public void error(SAXParseException exception) {
            parseException = exception;
        }

        public void fatalError(SAXParseException exception) {
            parseException = exception;
        }

        public void warning(SAXParseException exception) {
            parseException = exception;
        }

    }


    protected class ServletContainerInitializerInfo {
        protected Class<?> servletContainerInitializer = null;
        protected Class<?>[] interestClasses = null;
        protected HashSet<Class<?>> startupNotifySet = new HashSet<Class<?>>();
        protected ServletContainerInitializerInfo(Class<?> servletContainerInitializer, Class<?>[] interestClasses) {
            this.servletContainerInitializer = servletContainerInitializer;
            this.interestClasses = interestClasses;
        }
        public Class<?> getServletContainerInitializer() {
            return servletContainerInitializer;
        }
        public Class<?>[] getInterestClasses() {
            return interestClasses;
        }
        protected void addStartupNotifyClass(Class<?> clazz) {
            startupNotifySet.add(clazz);
        }
        public Set<Class<?>> getStartupNotifySet() {
            return startupNotifySet;
        }
    }
   
   
}
TOP

Related Classes of org.apache.catalina.startup.ContextConfig

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.