Package com.sun.faces.config

Source Code of com.sun.faces.config.ConfigureListener$ApplicationMap

/*
* $Id: ConfigureListener.java,v 1.98.2.2 2007/04/30 22:44:34 youngm Exp $
*/
/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* https://javaserverfaces.dev.java.net/CDDL.html or
* legal/CDDLv1.0.txt.
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at legal/CDDLv1.0.txt.   
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* [Name of File] [ver.__] [Date]
*
* Copyright 2005 Sun Microsystems Inc. All Rights Reserved
*/

package com.sun.faces.config;

import javax.el.CompositeELResolver;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.ELContext;
import javax.el.VariableMapper;
import javax.el.FunctionMapper;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.application.Application;
import javax.faces.application.ApplicationFactory;
import javax.faces.application.NavigationHandler;
import javax.faces.application.StateManager;
import javax.faces.application.ViewHandler;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseStream;
import javax.faces.context.ResponseWriter;
import javax.faces.el.PropertyResolver;
import javax.faces.el.VariableResolver;
import javax.faces.event.ActionListener;
import javax.faces.event.PhaseListener;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.faces.render.Renderer;
import javax.faces.webapp.FacesServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.text.MessageFormat;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

import com.sun.faces.RIConstants;
import com.sun.faces.application.ApplicationAssociate;
import com.sun.faces.application.ConfigNavigationCase;
import com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter;
import com.sun.faces.config.WebConfiguration.WebContextInitParameter;
import com.sun.faces.config.beans.ApplicationBean;
import com.sun.faces.config.beans.ComponentBean;
import com.sun.faces.config.beans.ConverterBean;
import com.sun.faces.config.beans.FacesConfigBean;
import com.sun.faces.config.beans.FactoryBean;
import com.sun.faces.config.beans.LifecycleBean;
import com.sun.faces.config.beans.LocaleConfigBean;
import com.sun.faces.config.beans.ManagedBeanBean;
import com.sun.faces.config.beans.NavigationCaseBean;
import com.sun.faces.config.beans.NavigationRuleBean;
import com.sun.faces.config.beans.RenderKitBean;
import com.sun.faces.config.beans.RendererBean;
import com.sun.faces.config.beans.ResourceBundleBean;
import com.sun.faces.config.beans.ValidatorBean;
import com.sun.faces.config.rules.FacesConfigRuleSet;
import com.sun.faces.el.ChainAwareVariableResolver;
import com.sun.faces.el.DummyPropertyResolverImpl;
import com.sun.faces.el.FacesCompositeELResolver;
import com.sun.faces.renderkit.JsfJsResourcePhaseListener;
import com.sun.faces.renderkit.RenderKitUtils;
import com.sun.faces.spi.ManagedBeanFactory;
import com.sun.faces.util.MessageUtils;
import com.sun.faces.util.Util;
import com.sun.org.apache.commons.digester.Digester;

/**
* <p>Parse all relevant JavaServer Faces configuration resources, and
* configure the Reference Implementation runtime environment.</p>
* <p/>
*/
@SuppressWarnings({"ForLoopReplaceableByForEach"})
public class ConfigureListener implements ServletContextListener {


    // -------------------------------------------------------- Static Variables

    /**
     * <p><code>ServletContext</code> attribute key.</p>
     */
    protected static final String FACES_CONFIG_BEAN_KEY =
        RIConstants.FACES_PREFIX + "FACES_CONFIG_BEAN";

    /**
     * <p>The path to the RI main configuration file.</p>
     */
    protected static final String JSF_RI_CONFIG =
            "com/sun/faces/jsf-ri-runtime.xml";   

    /**
     * <p>The resource path for faces-config files included in the
     * <code>META-INF</code> directory of JAR files.</p>
     */
    protected static final String META_INF_RESOURCES =
            "META-INF/faces-config.xml";

    /**
     * <p>The resource path for the faces configuration in the
     * <code>WEB-INF</code> directory of an application.</p>
     */
    protected static final String WEB_INF_RESOURCE =
            "/WEB-INF/faces-config.xml";
       
   
    protected WebConfiguration webConfig;

    /**
     * <p>All known factory names.</p>
     */
    private static final String[] FACTORY_NAMES = {
        FactoryFinder.APPLICATION_FACTORY,
        FactoryFinder.FACES_CONTEXT_FACTORY,
        FactoryFinder.LIFECYCLE_FACTORY,
        FactoryFinder.RENDER_KIT_FACTORY
    };   


    /**
     * <p>The set of <code>ClassLoader</code> instances that have
     * already been configured by this <code>ConfigureListener</code>.</p>
     */
    @SuppressWarnings({"CollectionWithoutInitialCapacity"})
    private static final Set<ClassLoader> LOADERS = new HashSet<ClassLoader>();
   
    //The default ExpressionFactory impl if run in a jsp 2.0 container
    //and no other ExpressionFactory was specified.
    private static final String DEFAULT_JSP_TWO_ZERO_EXPRESSION_FACTORY = "com.sun.el.ExpressionFactoryImpl";

    /**
     * <p>The <code>Log</code> instance for this class.</p>
     */   
    private static final Logger LOGGER = Util.getLogger(Util.FACES_LOGGER
            + Util.CONFIG_LOGGER);  

    private ArrayList<ELResolver> elResolversFromFacesConfig = null;
    private Application application;
    private ApplicationAssociate associate;
  
   
    // ------------------------------------------ ServletContextListener Methods


    /**
     * A subclass of ConfigureListener can override isFeatureEnabled and reset
     * one of the boolean values.  This method lets the user know that this
     * happened for a particular feature.
     */
    public void logOverriddenContextConfigValues() {
        for (BooleanWebContextInitParameter param : BooleanWebContextInitParameter.values()) {

            if (webConfig.getBooleanContextInitParameter(param) != isFeatureEnabled(param)) {
                if (LOGGER.isLoggable(Level.INFO)) {
                    LOGGER.log(Level.INFO,
                               (isFeatureEnabled(param)
                                ? "jsf.config.webconfig.configinfo.reset.enabled"
                                : "jsf.config.webconfig.configinfo.reset.disabled"),
                               new Object[]{webConfig.getServletContextName(),
                                            param.getQualifiedName()});
                }
            }
        }
    }


    public void contextInitialized(ServletContextEvent sce) {       
        ServletContext context = sce.getServletContext();
        webConfig = WebConfiguration.getInstance(context);
        logOverriddenContextConfigValues();
        Digester digester = null;
        boolean initialized;

        // Ensure that we initialize a particular application ony once.
        // Note that we need to cache this in a local variable so we
        // can check it from our finally block.
        if (initialized = initialized()) {
            return;
        }

        // Check to see if the FacesServlet is present in the
        // web.xml.   If it is, perform faces configuration as normal,
        // otherwise, simply return.
        if (!isFeatureEnabled(BooleanWebContextInitParameter.ForceLoadFacesConfigFiles)) {
            WebXmlProcessor processor = new WebXmlProcessor(context);
            if (!processor.isFacesServletPresent()) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine(
                         "No FacesServlet found in deployment descriptor -"
                              +
                              " bypassing configuration.");
                }
                return;
            }

            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("FacesServlet found in deployment descriptor -"
                     +
                     " processing configuration.");
            }
        }

        FacesContext initContext = new InitFacesContext(context);

        try {

            if (LOGGER.isLoggable(Level.INFO)) {
                LOGGER.log(Level.INFO,
                           "jsf.config.listener.version",
                           getServletContextIdentifier(context));
            }

            // Prepare local variables we will need
            FacesConfigBean fcb = new FacesConfigBean();           

            // see if we're operating in the unit test environment
            try {
                if (Util.isUnitTestModeEnabled()) {
                    // if so, put the fcb in the servletContext
                    context.setAttribute(FACES_CONFIG_BEAN_KEY, fcb);
                }
            }
            catch (Exception e) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine("Can't query for test environment");
                }
            }

            // see if we need to disable our TLValidator
            Util.setHtmlTLVActive(
                  isFeatureEnabled(BooleanWebContextInitParameter.EnableHtmlTagLibraryValidator));
           
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine(MessageFormat.format("contextInitialized({0})", context.getServletContextName()));
            }

            // Step 1, configure a Digester instance we can use
            digester = digester(isFeatureEnabled(BooleanWebContextInitParameter.ValidateFacesConfigFiles));
           
            // Step 2, parse the RI configuration resource
            Bootstrapper bootstrapper = new Bootstrapper();
            bootstrapper.populateFacesConfigBean(fcb);
           
            // Step 3, parse any "/META-INF/faces-config.xml" resources       
            SortedMap<String, URL> sortedJarMap = new TreeMap<String, URL>();
            //noinspection CollectionWithoutInitialCapacity
            List<URL> unsortedResourceList = new ArrayList<URL>();
                         
            try {
                for (Enumeration<URL> items = Util.getCurrentLoader(this)
                      .getResources(META_INF_RESOURCES);
                     items.hasMoreElements();) {
              
                    URL nextElement = items.nextElement();
                    String jarUrl = nextElement.toString();
                    String jarName = null;
                    int resourceIndex;
                    // If this resource has a faces-config file inside of it
                    if (-1 != (resourceIndex =
                          jarUrl.indexOf(META_INF_RESOURCES))) {
                        // Search backwards for the previous occurrence of File.SEPARATOR
                        int sepIndex = resourceIndex - 2;
                        char sep = ' ';
                        while (0 < sepIndex) {
                            sep = jarUrl.charAt(sepIndex);
                            if ('/' == sep) {
                                break;
                            }
                            sepIndex--;
                        }
                        if ('/' == sep) {
                            jarName =
                                  jarUrl.substring(sepIndex + 1, resourceIndex);
                        }
                    }
                    if (null != jarName) {
                        sortedJarMap.put(jarName, nextElement);
                    } else {
                        unsortedResourceList.add(0, nextElement);
                    }
                }
            } catch (IOException e) {
                throw new FacesException(e);
            }
            // Load the sorted resources first:         
            URL url;
            for (Entry<String, URL> entry : sortedJarMap.entrySet()) {
                url = entry.getValue();
                parse(digester, url, fcb);
            }
            // Then load the unsorted resources          
            for (Iterator<URL> resources = unsortedResourceList.iterator();
                 resources.hasNext(); ) {           
                url = resources.next();
                parse(digester, url, fcb);
            }

            // Step 4, parse any context-relative resources specified in
            // the web application deployment descriptor
            String paths =
                  context.getInitParameter(FacesServlet.CONFIG_FILES_ATTR);
            if (paths != null) {                              
                for (String token : Util.split(paths.trim(), ",")) {
                    if (!WEB_INF_RESOURCE.equals(token.trim())) {
                        url = getContextURLForPath(context, token.trim());
                        if (url != null) {
                            parse(digester, url, fcb);
                        }
                    }

                }
            }

            // Step 5, parse "/WEB-INF/faces-config.xml" if it exists
            url = getContextURLForPath(context, WEB_INF_RESOURCE);
            if (url != null) {
                parse(digester, url, fcb);
            }

            // Step 6, use the accumulated configuration beans to configure the RI
            try {
                configure(context, fcb);
            } catch (FacesException e) {
                e.printStackTrace();
                throw e;
            } catch (Exception e) {
                e.printStackTrace();
                throw new FacesException(e);
            }

            // Step 7, verify that all the configured factories are available
            // and optionall that configured objects can be created
            // Release the InitFacesContext prior to invoking any
            // of the verification methods
            initContext.release();
            verifyFactories();
            if (isFeatureEnabled(BooleanWebContextInitParameter.VerifyFacesConfigObjects)) {
                verifyObjects(context, fcb);
            }
            // Re-establish the InitFacesContext
            initContext = new InitFacesContext(context);
            // Step 8, register FacesCompositeELResolver and ELContextListener with
            // Jsp.
            registerELResolverAndListenerWithJsp(context);
        } finally {
           if (!initialized) {
                JSFVersionTracker tracker = getJSFVersionTracker();
                if (null != tracker) {
                    tracker.publishInstanceToApplication();
                }
                releaseDigester(digester);
           }
         
            if (associate != null) {
                associate.setContextName(getServletContextIdentifier(context));
            }
            RenderKitUtils.loadSunJsfJs(initContext.getExternalContext());
            initContext.release();
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE,
                           "jsf.config.listener.version.complete",
                           getServletContextIdentifier(context));
            }
           
        }       
    }


    public void contextDestroyed(ServletContextEvent sce) {
        ServletContext context = sce.getServletContext();
        try {           
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine(MessageFormat.format("contextDestroyed({0})", context.getServletContextName()));
            }          

            // Release any allocated application resources
            FactoryFinder.releaseFactories();           

        } finally {
            FacesContext initContext = new InitFacesContext(context);
            ApplicationAssociate
                  .clearInstance(initContext.getExternalContext());
            // Release the initialization mark on this web application
            release();
            initContext.release();
            WebConfiguration.clear(context);
        }

    }   

    // --------------------------------------------------------- Private Methods

   

    /**
     * <p>Return the implementation-specific <code>Application</code>
     * instance for this application.  You must <strong>NOT</strong>
     * call this method prior to configuring the appropriate
     * <code>ApplicationFactory</code> class.</p>
     * @return the <code>Application</code> object for this web
     *  application
     */
    private Application application() {

        if (application == null) {
            ApplicationFactory afactory = (ApplicationFactory)
                FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
            application = afactory.getApplication();
        }
        return application;

    }           


    /**
     * <p>Configure the JavaServer Faces reference implementation based on
     * the accumulated configuration beans.</p>
     *
     * @param context <code>ServletContext</code> for this web application
     * @param config  <code>FacesConfigBean</code> that is the root of the
     *                tree of configuration information
     * @throws Exception if an error occurs during the boostrap process
     */
    protected void configure(ServletContext context, FacesConfigBean config)
    throws Exception {
        configure(config.getFactory());
        configure(config.getLifecycle());
        configure(config.getApplication());
        configure(config.getComponents());
        configure(config.getConvertersByClass());
        configure(config.getConvertersById());
        configure(config.getManagedBeans());
        configure(config.getNavigationRules());
        configure(config.getRenderKits());
        configure(config.getValidators());

    }


    /**
     * <p>Configure the application objects for this application.</p>
     *
     * @param config   <code>ApplicationBean</code> that contains our
     *                 configuration information
     * @throws Exception if an error occurs configuring the Application instance
     */
    @SuppressWarnings("deprecation")
    private void configure(ApplicationBean config)
        throws Exception {

        if (config == null) {
            return;
        }
        Application application = application();
        associate =
                ApplicationAssociate.getInstance(
                     FacesContext.getCurrentInstance().getExternalContext());                             

        // Configure scalar properties

        configure(config.getLocaleConfig());
        configure(config.getResourceBundles());

        String value = config.getMessageBundle();
        if (value != null) {
            if (LOGGER.isLoggable(Level.FINER)) {
                LOGGER.finer(MessageFormat.format("setMessageBundle({0})", value));
            }
            application.setMessageBundle(value);
        }

        value = config.getDefaultRenderKitId();
        if (value != null) {
            if (LOGGER.isLoggable(Level.FINER)) {
                LOGGER.finer(MessageFormat.format("setDefaultRenderKitId({0})", value));
            }
            application.setDefaultRenderKitId(value);
        }

        // Configure chains of handlers

        String[] values = config.getActionListeners();
        if ((values != null) && (values.length > 0)) {
            for (int i = 0, len = values.length; i < len; i++) {
               if (LOGGER.isLoggable(Level.FINER)) {
                   LOGGER.finer(MessageFormat.format("setActionListener({0})", values[i]));
                }
                Object instance = Util.createInstance
                    (values[i], ActionListener.class,
                     application.getActionListener());
                if (instance != null) {
                    application.setActionListener((ActionListener) instance);
                }
            }
        }

        values = config.getNavigationHandlers();
        if ((values != null) && (values.length > 0)) {
            for (int i = 0, len = values.length; i < len; i++) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("setNavigationHandler({0})", values[i]));
                }
                Object instance = Util.createInstance
                    (values[i], NavigationHandler.class,
                     application.getNavigationHandler());
                if (instance != null) {
                    application.setNavigationHandler
                        ((NavigationHandler) instance);
                }
            }
        }

        values = config.getPropertyResolvers();
        if ((values != null) && (values.length > 0)) {
            // initialize the prevInChain to DummyPropertyResolver instance
            // to satisfy decorator pattern as well as satisfy the requirements
            // of unified EL. This resolver sets propertyResolved to false on
            // invocation of its method, so that variable resolution can move
            // further in the chain.
            Object prevInChain = new DummyPropertyResolverImpl();           
            for (int i = 0, len = values.length; i < len; i++) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("setPropertyResolver({0}}", values[i]));
                }
                prevInChain = Util.createInstance(values[i],
                                               PropertyResolver.class,
                                               prevInChain);
            }
            PropertyResolver legacyPRChainHead= (PropertyResolver) prevInChain;
            if (associate != null) {
                associate.setLegacyPRChainHead(legacyPRChainHead);
            }
        }
       
        // process custom el-resolver elements if any
        values = config.getELResolvers();
        if ((values != null) && (values.length > 0)) {
            for (int i = 0, len = values.length; i < len; i++) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("setELResolver({0})", values[i]));
                }
                Object instance = Util.createInstance(values[i]);
                if (elResolversFromFacesConfig == null) {
                    elResolversFromFacesConfig =
                        new ArrayList<ELResolver>(values.length);
                }
                if (null != instance) {
                    elResolversFromFacesConfig.add((ELResolver) instance);
                }
            }
            associate.setELResolversFromFacesConfig(elResolversFromFacesConfig);
        }

        values = config.getStateManagers();
        if ((values != null) && (values.length > 0)) {
            for (int i = 0, len = values.length; i < len; i++) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("setStateManager({0})", values[i]));
                }
                Object instance = Util.createInstance
                    (values[i], StateManager.class,
                     application.getStateManager());
                if (instance != null) {
                    application.setStateManager
                        ((StateManager) instance);
                }
            }
        }
               
        values = config.getVariableResolvers();
        if ((values != null) && (values.length > 0)) {
            Object prevInChain = new ChainAwareVariableResolver();
            for (int i = 0, len = values.length; i < len; i++) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("setVariableResolver({0})", values[i]));
                }
                Object instance = Util.createInstance(values[i],
                                                      VariableResolver.class,
                                                      prevInChain);
                if (instance != null) {
                    prevInChain = instance;
                }
            }
            VariableResolver legacyVRChainHead = (VariableResolver) prevInChain;
            if (associate != null) {
                associate.setLegacyVRChainHead(legacyVRChainHead);
            }
        }

        values = config.getViewHandlers();
        if ((values != null) && (values.length > 0)) {
            for (int i = 0, len = values.length; i < len; i++) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("setViewHandler({0})", values[i]));
                }
                Object instance = Util.createInstance
                    (values[i], ViewHandler.class,
                     application.getViewHandler());              
                if (instance != null) {
                    application.setViewHandler
                        ((ViewHandler) instance);
                }
            }
        }

    }


    /**
     * <p>Configure all registered components.</p>
     *
     * @param config Array of <code>ComponentBean</code> that contains
     *               our configuration information
     * @throws Exception if an error occurs configuring the application
     *  components
     */
    private void configure(ComponentBean[] config) throws Exception {

        if (config == null) {
            return;
        }
        Application application = application();

        for (int i = 0, len = config.length; i < len; i++) {
            if (LOGGER.isLoggable(Level.FINER)) {
                LOGGER.finer(MessageFormat.format("addComponent(componentType={0},componentClass={1})",
                                                  config[i].getComponentType(),
                                                  config[i].getComponentClass()));
            }
            application.addComponent(config[i].getComponentType(),
                                     config[i].getComponentClass());
        }

    }


    /**
     * <p>Configure all registered converters.</p>
     *
     * @param config Array of <code>ConverterBean</code> that contains
     *               our configuration information
     * @throws Exception if an error occurs configuring the application
     *  converters
     */
    private void configure(ConverterBean[] config) throws Exception {
      
        Application application = application();

        if (config == null) {
            return;
        }

        for (int i = 0, len = config.length; i < len; i++) {
            if (config[i].getConverterId() != null) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("addConverterById(converterId={0},converterClass={1})",
                                                      config[i].getConverterId(),
                                                      config[i].getConverterClass()));
                }
                application.addConverter(config[i].getConverterId(),
                                         config[i].getConverterClass());
            } else {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("addConverterByClass(converterForClass={0},converterClass={1})",
                                                      config[i].getConverterForClass(),
                                                      config[i].getConverterClass()));
                }               
                application.addConverter(config[i].getConverterForClass(),
                                         config[i].getConverterClass());
            }
        }

    }


    /**
     * <p>Configure the object factories for this application.</p>
     *
     * @param config <code>FactoryBean</code> that contains our
     *               configuration information
     * @throws Exception if an error occurs configuring the application
     *  factories
     */
    private void configure(FactoryBean config) throws Exception {

        if (config == null) {
            return;
        }

        for (String value : config.getApplicationFactories()) {           
            if (value != null) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("setApplicationFactory({0})", value));
                }
                FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY,
                                         value);
            }
        }

        for (String value : config.getFacesContextFactories()) {
            if (value != null) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("setFacesContextFactory({0})", value));
                }
                FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY,
                                         value);
            }
        }
     
       for (String value : config.getLifecycleFactories()) {
            if (value != null) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("setLifecycleFactory({0})", value));
                }
                FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY,
                                         value);
            }
        }
      
       for (String value : config.getRenderKitFactories()) {
            if (value != null) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("setRenderKitFactory({0})", value));
                }
                FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY,
                                         value);
            }
        }

    }


    /**
     * <p>Configure the lifecycle listeners for this application.</p>
     *
     * @param config <code>LifecycleBean</code> that contains our
     * @throws Exception if an error occurs configuring the application's
     *  Lifecycle
     */
    private void configure(LifecycleBean config) throws Exception {

        if (config == null) {
            return;
        }
        String[] listeners = config.getPhaseListeners();
        LifecycleFactory factory = (LifecycleFactory)
            FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
       
        for (Iterator<String> iter = factory.getLifecycleIds(); iter.hasNext();) {      
            String lifecycleId = iter.next();
            if (lifecycleId == null) {
                lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
            }
            Lifecycle lifecycle =
                    factory.getLifecycle(lifecycleId);
            if (webConfig.getBooleanContextInitParameter(
                  BooleanWebContextInitParameter.ExternalizeJavaScript)) {
                lifecycle.addPhaseListener(new JsfJsResourcePhaseListener());
            }
            for (int i = 0, len = listeners.length; i < len; i++) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("addPhaseListener({0})", listeners[i]));
                }
                try {
                    Class clazz = Util.loadClass(listeners[i], this);
                    lifecycle.addPhaseListener((PhaseListener) clazz.newInstance());
                } catch (Exception e) {
                    Object [] args = {MessageFormat.format("phase-listener: {0}", listeners[i])};
                    String message =
                        MessageUtils.getExceptionMessageString(MessageUtils.CANT_INSTANTIATE_CLASS_ERROR_MESSAGE_ID,  args);
                    LOGGER.log(Level.SEVERE, message);
                    throw e;
                }
            }
        }
    }


    /**
     * <p>Configure the locale support for this application.</p>
     *
     * @param config <code>LocaleConfigBean</code> that contains our
     *               configuration information
     * @throws Exception if an error occurs configuring the application
     *  locales
     */
    private void configure(LocaleConfigBean config) throws Exception {

        if (config == null) {
            return;
        }
        Application application = application();
        String value;
        String[] values;

        value = config.getDefaultLocale();
        if (value != null) {
            if (LOGGER.isLoggable(Level.FINER)) {
                LOGGER.finer(MessageFormat.format("setDefaultLocale({0})", value));
            }
            application.setDefaultLocale
                (Util.getLocaleFromString(value));
        }

        values = config.getSupportedLocales();
        if ((values != null) && (values.length > 0)) {
            List<Locale> locales = new ArrayList<Locale>(values.length);
            for (int i = 0, len = values.length; i < len; i++) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("addSupportedLocale({0})", values[i]));
                }
                locales.add(Util.getLocaleFromString(values[i]));
            }
            application.setSupportedLocales(locales);
        }

    }


    /**
     * <p>Configure all registered managed beans.</p>
     *
     * @param config Array of <code>ManagedBeanBean</code> that contains
     *               our configuration information
     * @throws Exception if an error occurs configuring the application
     *  managed beans
     */
    private void configure(ManagedBeanBean[] config) throws Exception {
       
        if (config == null || associate == null) {
            return;
        }    

        for (int i = 0, len = config.length; i < len; i++) {
            if (LOGGER.isLoggable(Level.FINER)) {
                LOGGER.finer(MessageFormat.format("addManagedBean(managedBeanName={0},managedBeanClass={1})",
                                                  config[i].getManagedBeanName(),
                                                  config[i].getManagedBeanClass()));
            }
            ManagedBeanFactory mbf = new ManagedBeanFactoryImpl(config[i]);
           
            // See if the RI specific MANAGED_BEAN_FACTORY_DECORATOR is available
            String mbfdClassName =
                  webConfig.getContextInitParameter(
                        WebContextInitParameter.ManagedBeanFactoryDecorator);
            if (mbfdClassName != null) {
                ManagedBeanFactory newMbf =
                        (ManagedBeanFactory) Util.createInstance(mbfdClassName,
                            ManagedBeanFactory.class, mbf);
                if (null != newMbf) {
                    mbf = newMbf;
                }
            }
            associate.addManagedBeanFactory(config[i].getManagedBeanName(),
                                            mbf);
        }
    }


    /**
     * <p>Configure all registered navigation rules.</p>
     *
     * @param config Array of <code>NavigationRuleBean</code> that contains
     *               our configuration information
     */
    private void configure(NavigationRuleBean[] config) {

        if (config == null || associate == null) {
            return;
        }                

        for (int i = 0, len = config.length; i < len; i++) {
            if (LOGGER.isLoggable(Level.FINER)) {
                LOGGER.finer(MessageFormat.format("addNavigationRule({0})", config[i].getFromViewId()));
            }
            NavigationCaseBean[] ncb = config[i].getNavigationCases();
            for (int j = 0, len2 = ncb.length; j < len2; j++) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(
                         MessageFormat.format("addNavigationCase(fromAction={0},fromOutcome={1},isRedirect={2},toViewId={3})",
                                              ncb[j].getFromAction(),
                                              ncb[j].getFromOutcome(),
                                              ncb[j].isRedirect(),
                                              ncb[j].getToViewId()));
                }
                ConfigNavigationCase cnc = new ConfigNavigationCase();
                if (config[i].getFromViewId() == null) {
                    cnc.setFromViewId("*");
                } else {
                    cnc.setFromViewId(config[i].getFromViewId());
                }
                cnc.setFromAction(ncb[j].getFromAction());
                String fromAction = ncb[j].getFromAction();
                if (fromAction == null) {
                    fromAction = "-";
                }
                cnc.setFromOutcome(ncb[j].getFromOutcome());
                String fromOutcome = ncb[j].getFromOutcome();
                if (fromOutcome == null) {
                    fromOutcome = "-";
                }
                cnc.setToViewId(ncb[j].getToViewId());               
              
                cnc.setKey(new StringBuilder(64).append(cnc.getFromViewId()).append(fromAction).append(fromOutcome).toString());
                if (ncb[j].isRedirect()) {
                    cnc.setRedirect("true");
                } else {
                    cnc.setRedirect(null);
                }
                associate.addNavigationCase(cnc);
            }
        }

    }


    /**
     * <p>Configure all registered renderers for this renderkit.</p>
     *
     * @param config Array of <code>RendererBean</code> that contains
     *               our configuration information
     * @param rk     RenderKit to be configured
     * @throws Exception if an error occurs configuring the the renderers
     *  for the specified RenderKit
     */
    private void configure(RendererBean[] config, RenderKit rk)
        throws Exception {

        if (config == null) {
            return;
        }

        for (int i = 0, len = config.length; i < len; i++) {
            if (LOGGER.isLoggable(Level.FINER)) {
                LOGGER.finer(
                     MessageFormat.format("addRenderer(family={0},rendererType={2},rendererClass={3})",
                                          config[i].getComponentFamily(),
                                          config[i].getRendererType(),
                                          config[i].getRendererClass()));
            }
            try {
                Renderer r = (Renderer)
                Util.loadClass(
                        config[i].getRendererClass(), this).newInstance();
                rk.addRenderer(config[i].getComponentFamily(),
                        config[i].getRendererType(),
                        r);
            }
            catch (Exception e) {
                Object[] args = { MessageFormat.format("family={0},rendererType={2},rendererClass={3}",
                                          config[i].getComponentFamily(),
                                          config[i].getRendererType(),
                                          config[i].getRendererClass()) };
                String message =
                        MessageUtils.getExceptionMessageString(MessageUtils.CANT_INSTANTIATE_CLASS_ERROR_MESSAGE_ID,  args);
                LOGGER.log(Level.SEVERE, message);
                throw e;
            }
        }

    }


    /**
     * <p>Configure all registered renderKits.</p>
     *
     * @param config Array of <code>RenderKitBean</code> that contains
     *               our configuration information
     * @throws Exception if an error occurs configuring the application
     *  RenderKit
     */
    private void configure(RenderKitBean[] config) throws Exception {

        if (config == null) {
            return;
        }
        RenderKitFactory rkFactory = (RenderKitFactory)
            FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);

        for (int i = 0, len = config.length; i < len; i++) {
            RenderKit rk = rkFactory.getRenderKit
                (null, config[i].getRenderKitId());
            if (rk == null) {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("createRenderKit(renderKitId={0},renderKitClass={2})",
                                                      config[i].getRenderKitId(),
                                                      config[i].getRenderKitClass()));
                }
                if (config[i].getRenderKitClass() == null) {
                    throw new IllegalArgumentException// PENDING - i18n
                        ("No renderKitClass for renderKit " +
                         config[i].getRenderKitId());
                }
                try {
                    rk = (RenderKit)
                    Util.loadClass(
                            config[i].getRenderKitClass(), this).newInstance();
                    rkFactory.addRenderKit(config[i].getRenderKitId(), rk);
                } catch (Exception e) {
                    Object [] args = { MessageFormat.format("renderKitId={0},renderKitClass={2}",
                                                      config[i].getRenderKitId(),
                                                      config[i].getRenderKitClass()) };
                    String message =
                        MessageUtils.getExceptionMessageString(MessageUtils.CANT_INSTANTIATE_CLASS_ERROR_MESSAGE_ID,  args);
                    LOGGER.log(Level.SEVERE, message);
                    throw e;
                           
                }
            } else {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer(MessageFormat.format("getRenderKit({0})", config[i].getRenderKitId()));
                }
            }
            configure(config[i].getRenderers(), rk);
        }

    }

    /**
     * <p>Configure all registered ResourceBundles.</p>
     *
     * @param config Array of <code>ResourceBundleBean</code> that contains
     *               our configuration information
     * @throws Exception if an error occurs configuring the application
     *  ResourceBundle
     */
    private void configure(ResourceBundleBean[] config) throws Exception {

        if (config == null || associate == null) {
            return;
        }
               
        String baseName;
        String var;
       
        for (int i = 0, len = config.length; i < len; i++) {
            if ((null == (baseName = config[i].getBasename())) ||
                (null == (var = config[i].getVar()))) {
                String message =
                     MessageFormat.format("Application ResourceBundle: null base-name or var.base-name:{0}, var:{1}",
                                          baseName,
                                          config[i].getVar());
                // PENDING(edburns): I18N all levels above info
                if (LOGGER.isLoggable(Level.WARNING)) {
                    LOGGER.finer(message);
                }
                throw new IllegalArgumentException(message);
            }
            associate.addResourceBundleBean(var, config[i]);
        }
       
    }


    /**
     * <p>Configure all registered validators.</p>
     *
     * @param config Array of <code>ValidatorBean</code> that contains
     *               our configuration information
     * @throws Exception if an error occurs configuring the application
     *  Validators
     */
    private void configure(ValidatorBean[] config) throws Exception {

        if (config == null) {
            return;
        }
        Application application = application();

        for (int i = 0, len = config.length; i < len; i++) {
            if (LOGGER.isLoggable(Level.FINER)) {
                LOGGER.finer(MessageFormat.format("addValidator(validatorId={0},validatorClass={2})",
                                                  config[i].getValidatorId(),
                                                  config[i].getValidatorClass()));
            }
            application.addValidator(config[i].getValidatorId(),
                                     config[i].getValidatorClass());
        }

    }


    /**
     * <p>Configure and return a <code>Digester</code> instance suitable for
     * parsing the runtime configuration information we need.</p>
     *
     * @param validateXml if true, validation is turned on during parsing.
     * @return a <code>Digester<code> instance suitable for parsing
     *  faces-config documents
     */
    protected Digester digester(boolean validateXml) {

        Digester digester;
        DigesterFactory.VersionListener listener = null;
        final JSFVersionTracker tracker = getJSFVersionTracker();
       
        if (null != tracker) {
            listener =
                    new DigesterFactory.VersionListener() {
                public void takeActionOnGrammar(String grammar) {
                    tracker.pushJSFVersionNumberFromGrammar(grammar);
                }

                public void takeActionOnArtifact(String artifactName) {
                    tracker.putTrackedClassName(artifactName);
                }
            };
        }
           
        try {
            if (null != listener) {
                digester = DigesterFactory.newInstance(validateXml,
                        listener).createDigester();
            }
            else {
                digester = DigesterFactory.newInstance(validateXml).createDigester();
            }
        }
        catch (RuntimeException e) {
            Object [] args = { "Digester" };
            String message =
                   MessageUtils.getExceptionMessageString(MessageUtils.CANT_INSTANTIATE_CLASS_ERROR_MESSAGE_ID,  args);
            LOGGER.log(Level.SEVERE, message);
            throw e;
        }

        // Configure parsing rules
        // PENDING - Read from file?
        digester.addRuleSet(new FacesConfigRuleSet(false, false, true));

        // Push an initial FacesConfigBean onto the stack
        digester.push(new FacesConfigBean());

        return (digester);

    }
   
    protected void releaseDigester(Digester toRelease) {
        DigesterFactory.releaseDigester(toRelease);
    }
   
    private JSFVersionTracker versionTracker = null;

    /**
     * <p>This is the single access point for accessing the
     * JSFVersionTracker instance during initialization.  It returns
     * null if the feature has been disabled via user configuration.</p>
     * @return <code>JSFVersionTracker</code> that can be used to query
     *  the version of application artifacts
     */
   
    private JSFVersionTracker getJSFVersionTracker() {
        // If the feature is disabled...
        if (isFeatureEnabled(BooleanWebContextInitParameter.DisableArtifactVersioning)) {
            // make sure the tracker is released.
            versionTracker = null;
            return null;
        }
       
        if (null == versionTracker) {
            versionTracker = new JSFVersionTracker();
        }
        return versionTracker;
    }
       

    /**
     * <p>Verify that all of the required factory objects are available.</p>
     *
     * @throws FacesException if a factory cannot be created
     */
    private void verifyFactories() throws FacesException {

        for (int i = 0, len = FACTORY_NAMES.length; i < len; i++) {
            try {
                FactoryFinder.getFactory(FACTORY_NAMES[i]);
            } catch (Exception e) {
                throw new FacesException(e);
            }
        }

    }


    /**
     * <p>Return <code>true</code> if this web application has already
     * been initialized.  If it has not been initialized, also record
     * the initialization of this application until removed by a call to
     * <code>release()</code>.</p>
     * @return <code>true</code> if this application has been initialized,
     *  otherwise <code>false</code>
     */
    private boolean initialized() {

        // Initialize at most once per web application class loader
        ClassLoader cl = Util.getCurrentLoader(this);
        synchronized (LOADERS) {
            if (!LOADERS.contains(cl)) {
                LOADERS.add(cl);
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer("Initializing this webapp");
                }
                return false;
            } else {
                if (LOGGER.isLoggable(Level.FINER)) {
                    LOGGER.finer("Listener already completed for this webapp");
                }
                return true;
            }
        }

    }


    /**
     * <p>Verify that all of the application-defined objects that have been
     * configured can be successfully instantiated.</p>
     *
     * @param context <code>ServletContext</code> instance for this application
     * @param fcb     <code>FacesConfigBean</code> containing the
     *                configuration information
     * @throws FacesException if an application-defined object cannot
     *                        be instantiated
     */
    private void verifyObjects(ServletContext context, FacesConfigBean fcb)
        throws FacesException {

        if (LOGGER.isLoggable(Level.FINER)) {
            LOGGER.finer("Verifying application objects");
        }

        ApplicationFactory af = (ApplicationFactory)
            FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
        Application app = af.getApplication();
        RenderKitFactory rkf = (RenderKitFactory)
            FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
        boolean success = true;

        // Check components
        ComponentBean[] comp = fcb.getComponents();
        for (int i = 0, len = comp.length; i < len; i++) {
            try {
                app.createComponent(comp[i].getComponentType());
            } catch (Exception e) {
                context.log(comp[i].getComponentClass(), e);
                success = false;
            }
        }

        // Check converters
        ConverterBean[] conv1 = fcb.getConvertersByClass();
        for (int i = 0, len = conv1.length; i < len; i++) {
            try {
                app.createConverter(conv1[i].getConverterForClass());
            } catch (Exception e) {
                context.log(conv1[i].getConverterForClass().getName(), e);              
                success = false;
            }
        }
        ConverterBean[] conv2 = fcb.getConvertersById();
        for (int i = 0, len = conv2.length; i < len; i++) {
            try {
                app.createConverter(conv2[i].getConverterId());
            } catch (Exception e) {
                context.log(conv2[i].getConverterClass());
                success = false;
            }
        }

        // Check renderers
        RenderKitBean[] rkb = fcb.getRenderKits();
        RenderKit rk;
        for (int i = 0, len = rkb.length; i < len; i++) {
            try {
                rk = rkf.getRenderKit(null, rkb[i].getRenderKitId());
                RendererBean[] rb = rkb[i].getRenderers();
                for (int j = 0, len2 = rb.length; j < len2; j++) {
                    try {
                        rk.getRenderer(rb[j].getComponentFamily(),
                                       rb[j].getRendererType());
                    } catch (Exception e) {
                        context.log(rb[j].getRendererClass(), e);
                        success = false;
                    }
                }
            } catch (Exception e) {
                context.log(rkb[i].getRenderKitId());
                success = false;
            }
        }

        // Check validators
        ValidatorBean[] val = fcb.getValidators();
        for (int i = 0, len = val.length; i < len; i++) {
            try {
                app.createValidator(val[i].getValidatorId());
            } catch (Exception e) {
                context.log(val[i].getValidatorClass(), e);
                success = false;
            }
        }

        // Throw an exception on any failures
        if (!success) {
            String message;
            try {
                message = MessageUtils.getExceptionMessageString
                    (MessageUtils.OBJECT_CREATION_ERROR_ID);
            } catch (Exception ee) {
                message = "One or more configured application objects " +
                    "cannot be created.  See your web application logs " +
                    "for details.";
            }
            if (LOGGER.isLoggable(Level.WARNING)) {
                LOGGER.warning(message);
            }
            throw new FacesException(message);
        } else {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine(
                    "Application object verification completed successfully");
            }
        }

    }


    /**
     * <p>Parse the configuration resource at the specified URL, using
     * the specified <code>Digester</code> instance.</p>
     *
     * @param digester Digester to use for parsing
     * @param url      URL of the configuration resource to be parsed
     * @param fcb      FacesConfigBean to accumulate results
     */
    protected void parse(Digester digester, URL url, FacesConfigBean fcb) {

        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine(MessageFormat.format("parse({0})", url.toExternalForm()));
        }

        InputStream stream = null;
        URLConnection conn;       
        InputSource source;
        JSFVersionTracker tracker = getJSFVersionTracker();
        try {
            conn = url.openConnection();
            conn.setUseCaches(false);
            stream = new BufferedInputStream(conn.getInputStream());
            source = new InputSource(url.toExternalForm());
            source.setSystemId(url.toExternalForm());
            source.setByteStream(stream);           
            digester.clear();
            digester.push(fcb);
            if (null != tracker) {
                tracker.startParse();
            }
            digester.parse(source);
        }
        catch (Exception e) {
            int ln = -1;
            int cn = -1;           
            if (e instanceof SAXParseException) {
                SAXParseException spe = (SAXParseException) e;
                ln = spe.getLineNumber();
                cn = spe.getColumnNumber();                          
            }
            String message;
            try {
                message = MessageUtils.getExceptionMessageString
                    (MessageUtils.CANT_PARSE_FILE_ERROR_MESSAGE_ID,
                     url.toExternalForm(),
                     ln,
                     cn,
                     e.getMessage());
            } catch (Exception ee) {
                message = MessageFormat.format("Can''t parse configuration file: {0}: Error at line {1} column {2}: {3}", url.toExternalForm(), ln, cn, e.getMessage());
            }
            throw new FacesException(message);
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (Exception e) {
                    // ignore
                }
            }
            if (null != tracker) {
                tracker.endParse();
            }
        }
       
       

    }
   
    /**
     * <p>Determines if a particular feature, configured via the web
     * deployment descriptor as a <code>true/false</code> value, is
     * enabled or not.</p>
     * @param param the <code>BooleanWebContextInitParameter</code>
     *  of interest
     *
     * @return <code>true</code> if the feature in question is enabled, otherwise
     *  <code>false</code>
     */
    protected boolean isFeatureEnabled(BooleanWebContextInitParameter param) {
        return webConfig.getBooleanContextInitParameter(param);     
    }

    private String getServletContextIdentifier(ServletContext context) {
        if (context.getMajorVersion() == 2 && context.getMinorVersion() < 5) {
            return context.getServletContextName();
        } else {
            return context.getContextPath();
        }
    }

    /**
     * <p>Return the URL for the given path.</p>
     * @param context the <code>ServletContext</code> of the current application
     * @param path the resource path
     * @return the URL for the given resource or <code>null</code>
     */
    private URL getContextURLForPath(ServletContext context, String path) {
        try {
            return context.getResource(path);
        } catch (MalformedURLException mue) {
            throw new FacesException(mue);
        }
    }
   
    private static boolean isJspTwoOne() {

        // The following try/catch is a hack to work around
        // a bug in Tomcat 6 where JspFactory.getDefaultFactory() will
        // return null unless JspRuntimeContext has been loaded.
        try {
            Class.forName("org.apache.jasper.compiler.JspRuntimeContext");
        } catch (ClassNotFoundException cnfe) {
            ;
        }

        if (JspFactory.getDefaultFactory() == null) {
            return false;
        }
        try {
            JspFactory.class.getMethod("getJspApplicationContext",
                                       ServletContext.class );
        } catch (NoSuchMethodException nsme) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine(MessageUtils.getExceptionMessageString(MessageUtils.INCORRECT_JSP_VERSION_ID,
               "getJspApplicationContext"));
            }
            return false;
        }
        return true;
    }
   
    private void installExpressionFactory(String elFactType) {
        try {
            ExpressionFactory factory = (ExpressionFactory) Class.forName(
                    elFactType).newInstance();
            if (associate != null) {
                associate.setExpressionFactory(factory);
            }
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "Error Instantiating ExpressionFactory", e);
        }                       
    }

    public void registerELResolverAndListenerWithJsp(ServletContext context) {              
       

        // first try to load a factory defined in web.xml
        String elFactType = webConfig.getContextInitParameter(
              WebContextInitParameter.ExpressionFactory);

        if (elFactType != null && !"".equals(elFactType.trim())) {
         
          installExpressionFactory(elFactType);
       
        } else if (!isJspTwoOne()) {
           
            // not JSP 2.1 use default EL-RI
            installExpressionFactory(DEFAULT_JSP_TWO_ZERO_EXPRESSION_FACTORY);
          
        } else {
           
            // Is JSP 2.1
           
            // JSP 2.1 specific check
            if (JspFactory.getDefaultFactory().getJspApplicationContext(context) == null) {
                return;
            }
           
            // register an empty resolver for now. It will be populated after the
            // first request is serviced.
            CompositeELResolver compositeELResolverForJsp =
                new FacesCompositeELResolver(FacesCompositeELResolver.ELResolverChainType.JSP);  
            if (associate != null) {
                associate.setFacesELResolverForJsp(compositeELResolverForJsp);
            }
                   
            // get JspApplicationContext.
            JspApplicationContext jspAppContext = JspFactory.getDefaultFactory()
                    .getJspApplicationContext(context);
   
            // cache the ExpressionFactory instance in ApplicationAssociate
            if (associate != null) {
                associate.setExpressionFactory(jspAppContext.getExpressionFactory());
            }
   
            // register compositeELResolver with JSP
            try {
                jspAppContext.addELResolver(compositeELResolverForJsp);
            }
            catch (IllegalStateException e) {
                if (!Util.isUnitTestModeEnabled()) {
                    throw e;
                }
            }
   
            // register JSF ELContextListenerImpl with Jsp
            ELContextListenerImpl elContextListener = new ELContextListenerImpl();
            jspAppContext.addELContextListener(elContextListener);
         }
    }

    /**
     * <p>
     * Release the mark that this web application has been initialized.
     * </p>
     */
    private void release() {

        ClassLoader cl = Util.getCurrentLoader(this);
        synchronized (LOADERS) {
            LOADERS.remove(cl);
        }

    }

     private static class InitFacesContext extends FacesContext {

        private ExternalContext ec;
        private UIViewRoot viewRoot;

        public InitFacesContext(ServletContext sc) {
            ec = new ServletContextAdapter(sc);
            setCurrentInstance(this);
        }

        public Application getApplication() {
            ApplicationFactory factory = (ApplicationFactory)
                 FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
            return factory.getApplication();
        }

        public Iterator<String> getClientIdsWithMessages() {
            List<String> list = Collections.emptyList();
            return list.iterator();
        }

        public ExternalContext getExternalContext() {
            return ec;
        }

        public FacesMessage.Severity getMaximumSeverity() {
            return FacesMessage.SEVERITY_INFO;
        }

        public Iterator<FacesMessage> getMessages() {
            List<FacesMessage> list = Collections.emptyList();
            return list.iterator();
        }

        public Iterator<FacesMessage> getMessages(String clientId) {
            return getMessages();
        }

        public RenderKit getRenderKit() {
            return null;
        }

        public boolean getRenderResponse() {
            return true;
        }

        public boolean getResponseComplete() {
            return true;
        }

        public ResponseStream getResponseStream() {
            return null;
        }

        public void setResponseStream(ResponseStream responseStream) {
            ;
        }

        public ResponseWriter getResponseWriter() {
            return null;
        }

        public void setResponseWriter(ResponseWriter responseWriter) {
            ;
        }

        public UIViewRoot getViewRoot() {
            if (viewRoot == null) {
                viewRoot = new UIViewRoot();
                viewRoot.setLocale(Locale.getDefault());
            }
            return viewRoot;
        }

        public void setViewRoot(UIViewRoot root) {
            ;
        }

        public void addMessage(String clientId, FacesMessage message) {
            ;
        }

        public void release() {
            setCurrentInstance(null);
        }

        public void renderResponse() {
            ;
        }

        public void responseComplete() {
            ;
        }

        public ELContext getELContext() {
            return new ELContext() {
                public ELResolver getELResolver() {
                    return null;
                }

                public FunctionMapper getFunctionMapper() {
                    return null;
                }

                public VariableMapper getVariableMapper() {
                    return null;
                }
            };
        }
    }

    private static class ServletContextAdapter extends ExternalContext {
       
        private ServletContext servletContext = null;
        private ApplicationMap applicationMap = null;
       
        public ServletContextAdapter(ServletContext sc) {
            this.servletContext = sc;
        }
       
        public void dispatch(String path) throws IOException {
        }
   
        public String encodeActionURL(String url) {
            return null;
        }  

        public String encodeNamespace(String name) {
            return null;
        }


        public String encodeResourceURL(String url) {
            return null;
        }

       @SuppressWarnings("unchecked")
       public Map<String,Object> getApplicationMap() {
            if (applicationMap == null) {
                applicationMap =
                    new ApplicationMap(servletContext);
            }
            return applicationMap;
        }
       
        public String getAuthType() {
            return null;
        }

        public Object getContext() {
            return servletContext;
        }

        public String getInitParameter(String name) {
            return null;
        }

        public Map getInitParameterMap() {
            return null;
        }

        public String getRemoteUser() {
            return null;
        }


        public Object getRequest() {
            return null;
        }

  public void setRequest(Object request) {
  }

        public String getRequestContextPath() {
            return null;
        }

        public Map<String,Object> getRequestCookieMap() {
            return null;
        }

        public Map<String,String> getRequestHeaderMap() {
            return null;
        }


        public Map<String,String[]> getRequestHeaderValuesMap() {
            return null;
        }


        public Locale getRequestLocale() {
            return null;
        }

        public Iterator<Locale> getRequestLocales() {
            return null;
        }



        public Map<String,Object> getRequestMap() {
            return null;
        }


        public Map<String,String> getRequestParameterMap() {
            return null;
        }


        public Iterator<String> getRequestParameterNames() {
            return null;
        }


        public Map<String,String[]> getRequestParameterValuesMap() {
            return null;
        }


        public String getRequestPathInfo() {
            return null;
        }


        public String getRequestServletPath() {
            return null;
        }
       
        
    public String getRequestContentType() {
        return null;
    }

    public String getResponseContentType() {
        return null;
    }

        public URL getResource(String path) throws MalformedURLException {
            return null;
        }


        public InputStream getResourceAsStream(String path) {
            return null;
        }

        public Set<String> getResourcePaths(String path) {
            return null;
        }

        public Object getResponse() {
            return null;
        }

        public void setResponse(Object response) {
        }

        public Object getSession(boolean create) {
            return null;
        }

        public Map<String,Object> getSessionMap() {
            return null;
        }

        public java.security.Principal getUserPrincipal() {
            return null;
        }
       
        public boolean isUserInRole(String role) {
            return false;
        }

        public void log(String message) {
        }
       
        public void log(String message, Throwable exception){
        }
       
        public void redirect(String url) throws IOException {
        }

        public String getRequestCharacterEncoding() {
            return null;
        }

        public void setRequestCharacterEncoding(String requestCharacterEncoding) throws UnsupportedEncodingException {

        }

        public String getResponseCharacterEncoding() {
            return null;
        }

        public void setResponseCharacterEncoding(String responseCharacterEncoding) {
        }

    }
   
    static class ApplicationMap extends java.util.AbstractMap {

        private final ServletContext servletContext;

        ApplicationMap(ServletContext servletContext) {
            this.servletContext = servletContext;
        }


        public Object get(Object key) {
            if (key == null) {
                throw new NullPointerException();
            }
            return servletContext.getAttribute(key.toString());
        }


        public Object put(Object key, Object value) {
            if (key == null) {
                throw new NullPointerException();
            }
            String keyString = key.toString();
            Object result = servletContext.getAttribute(keyString);
            servletContext.setAttribute(keyString, value);
            return (result);
        }


        public Object remove(Object key) {
            if (key == null) {
                return null;
            }
            String keyString = key.toString();
            Object result = servletContext.getAttribute(keyString);
            servletContext.removeAttribute(keyString);
            return (result);
        }


        public Set entrySet() {
           throw new UnsupportedOperationException();
        }


        public boolean equals(Object obj) {
            return !(obj == null || !(obj instanceof ApplicationMap))
                 && super.equals(obj);
        }


        public int hashCode() {
            int hashCode = 7 * servletContext.hashCode();
            for (Object o : entrySet()) {
                hashCode += o.hashCode();
            }
            return hashCode;
        }
       
        public void clear() {
            throw new UnsupportedOperationException();
        }

        public void putAll(Map t) {
            throw new UnsupportedOperationException();
        }
      

    } // END ApplicationMap


    /**
     * <p>Processes a web application's deployment descriptor looking
     * for a reference to <code>javax.faces.webapp.FacesServlet</code>.</p>
     */
    private static class WebXmlProcessor {

        private static final String WEB_XML_PATH = "/WEB-INF/web.xml";

        private boolean facesServletPresent;


        /**
         * <p>When instantiated, the web.xml of the current application
         * will be scanned looking for a references to the
         * <code>FacesServlet</code><code>isFacesServletPresent()</code>
         * will return the appropriate value based on the scan.</p>
         * @param context the <code>ServletContext</code> for the application
         *  of interest
         */
        WebXmlProcessor(ServletContext context) {

            if (context != null) {
                scanForFacesServlet(context);
            }

        } // END WebXmlProcessor


        /**
         * @return <code>true</code> if the <code>WebXmlProcessor</code>
         * detected a <code>FacesServlet</code> entry, otherwise return
         * <code>false</code>.</p>       
         */
        boolean isFacesServletPresent() {

            return facesServletPresent;

        } // END isFacesServletPresent


        /**
         * <p>Parse the web.xml for the current application and scan
         * for a FacesServlet entry, if found, set the
         * <code>facesServletPresent</code> property to true.
         * @param context the ServletContext instance for this application
         */
        private void scanForFacesServlet(ServletContext context) {

            SAXParserFactory factory = getConfiguredFactory();
            try {
                SAXParser parser = factory.newSAXParser();
                parser.parse(context.getResourceAsStream(WEB_XML_PATH),
                              new WebXmlHandler());
            } catch (Exception e) {
                // This probably won't happen since the container would
                // catch it before we would, but, if we catch an exception
                // processing the web.xml, set facesServletFound to true to
                // default to our previous behavior of processing the faces
                // configuration.
                if (LOGGER.isLoggable(Level.WARNING)) {
                    LOGGER.warning(MessageFormat.format("Unable to process deployment descriptor for context ''{0}''", context.getServletContextName()));
                }
                facesServletPresent = true;
            }

        } // END scanForFacesServlet

        /**
         * <p>Return a <code>SAXParserFactory</code> instance that is
         * non-validating and is namespace aware.</p>
         * @return configured <code>SAXParserFactory</code>
         */
        private SAXParserFactory getConfiguredFactory() {

            SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setValidating(false);
            factory.setNamespaceAware(true);
            return factory;

        } // END getConfiguredFactory


        /**
         * <p>A simple SAX handler to process the elements of interested
         * within a web application's deployment descriptor.</p>
         */
        private class WebXmlHandler extends DefaultHandler {

            private static final String SERVLET_CLASS = "servlet-class";
            private static final String FACES_SERVLET =
                "javax.faces.webapp.FacesServlet";

            private boolean servletClassFound;
            @SuppressWarnings({"StringBufferField"})
            private StringBuffer content;

            public InputSource resolveEntity(String publicId, String systemId)
            throws SAXException {

                return new InputSource(new StringReader(""));

            } // END resolveEntity


            public void startElement(String uri, String localName,
                                     String qName, Attributes attributes)
            throws SAXException {

                if (!facesServletPresent) {
                    if (SERVLET_CLASS.equals(localName)) {
                        servletClassFound = true;
                        //noinspection StringBufferWithoutInitialCapacity
                        content = new StringBuffer();
                    } else {
                        servletClassFound = false;
                    }
                }

            } // END startElement


            public void characters(char[] ch, int start, int length)
            throws SAXException {

                if (servletClassFound && !facesServletPresent) {
                    content.append(ch, start, length);
                }

            } // END characters


            public void endElement(String uri, String localName, String qName)
            throws SAXException {

                if (servletClassFound && !facesServletPresent) {
                    if (FACES_SERVLET.equals(content.toString().trim())) {
                        facesServletPresent = true;
                    }
                }

            } // END endElement

        } // END WebXmlHandler

    } // END WebXmlProcessor

}
TOP

Related Classes of com.sun.faces.config.ConfigureListener$ApplicationMap

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.