bug 466387: Add property for initialized context. Tune ConfigManager.hasBeenInitialized so that ConfigureListener.contextDestroyed will not harm the correct ServletContext.
diff --git a/hotfix/plugins/org.glassfish.com.sun.faces_2.1.18.v201304210537-virgo-1.jar b/hotfix/plugins/org.glassfish.com.sun.faces_2.1.18.v201304210537-virgo-2.jar
old mode 100755
new mode 100644
similarity index 76%
rename from hotfix/plugins/org.glassfish.com.sun.faces_2.1.18.v201304210537-virgo-1.jar
rename to hotfix/plugins/org.glassfish.com.sun.faces_2.1.18.v201304210537-virgo-2.jar
index 6e8922e..a47d741
--- a/hotfix/plugins/org.glassfish.com.sun.faces_2.1.18.v201304210537-virgo-1.jar
+++ b/hotfix/plugins/org.glassfish.com.sun.faces_2.1.18.v201304210537-virgo-2.jar
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$1.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$1.class
new file mode 100644
index 0000000..3eb0e03
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$1.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$AnnotationScanTask.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$AnnotationScanTask.class
new file mode 100644
index 0000000..b7d47eb
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$AnnotationScanTask.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$ParseTask.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$ParseTask.class
new file mode 100644
index 0000000..ba4031c
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$ParseTask.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$ProvideMetadataToAnnotationScanTask.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$ProvideMetadataToAnnotationScanTask.class
new file mode 100644
index 0000000..2f83f9e
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$ProvideMetadataToAnnotationScanTask.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$URITask.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$URITask.class
new file mode 100644
index 0000000..4ce5d47
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager$URITask.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager.class
new file mode 100644
index 0000000..5903a13
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager.java b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager.java
new file mode 100644
index 0000000..1f0e966
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigManager.java
@@ -0,0 +1,1209 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.faces.config;
+
+import com.sun.faces.RIConstants;
+import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.ValidateFacesConfigFiles;
+import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.DisableFaceletJSFViewHandler;
+import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.EnableThreading;
+import com.sun.faces.spi.ConfigurationResourceProvider;
+import com.sun.faces.spi.ConfigurationResourceProviderFactory;
+import com.sun.faces.spi.AnnotationProvider;
+import com.sun.faces.spi.AnnotationProviderFactory;
+import com.sun.faces.spi.HighAvailabilityEnabler;
+import static com.sun.faces.spi.ConfigurationResourceProviderFactory.ProviderType.*;
+import com.sun.faces.config.configprovider.MetaInfFacesConfigResourceProvider;
+import com.sun.faces.config.configprovider.MojarraFacesConfigResourceProvider;
+import com.sun.faces.config.configprovider.WebFacesConfigResourceProvider;
+import com.sun.faces.config.configprovider.MetaInfFaceletTaglibraryConfigProvider;
+import com.sun.faces.config.configprovider.WebFaceletTaglibResourceProvider;
+import com.sun.faces.config.processor.ApplicationConfigProcessor;
+import com.sun.faces.config.processor.BehaviorConfigProcessor;
+import com.sun.faces.config.processor.ComponentConfigProcessor;
+import com.sun.faces.config.processor.ConfigProcessor;
+import com.sun.faces.config.processor.ConverterConfigProcessor;
+import com.sun.faces.config.processor.FactoryConfigProcessor;
+import com.sun.faces.config.processor.LifecycleConfigProcessor;
+import com.sun.faces.config.processor.ManagedBeanConfigProcessor;
+import com.sun.faces.config.processor.NavigationConfigProcessor;
+import com.sun.faces.config.processor.RenderKitConfigProcessor;
+import com.sun.faces.config.processor.ValidatorConfigProcessor;
+import com.sun.faces.config.processor.FaceletTaglibConfigProcessor;
+import com.sun.faces.config.processor.FacesConfigExtensionProcessor;
+import com.sun.faces.spi.InjectionProvider;
+import com.sun.faces.spi.InjectionProviderFactory;
+import com.sun.faces.util.FacesLogger;
+import com.sun.faces.util.Timer;
+import com.sun.faces.util.Util;
+import org.xml.sax.InputSource;
+
+import javax.faces.FacesException;
+import javax.faces.FactoryFinder;
+import javax.faces.event.PostConstructApplicationEvent;
+import javax.faces.application.Application;
+import javax.faces.context.FacesContext;
+import javax.servlet.ServletContext;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamSource;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.lang.annotation.Annotation;
+import java.net.URI;
+import java.util.Iterator;
+
+import org.w3c.dom.*;
+import org.xml.sax.SAXParseException;
+
+/**
+ * <p>
+ *  This class manages the initialization of each web application that uses
+ *  JSF.
+ * </p>
+ */
+public class ConfigManager {
+
+    private static final String SERVLET_CONTEXT_INITIALISED = "com.sap.core.context.initialized";
+
+	private static final Logger LOGGER = FacesLogger.CONFIG.getLogger();
+
+    private static final Pattern JAR_PATTERN = Pattern.compile("(.*/(\\S*\\.jar)).*(/faces-config.xml|/*.\\.faces-config.xml)");
+
+    /**
+     * <p>
+     * A List of resource providers that search for faces-config documents.
+     * By default, this contains a provider for the Mojarra, and two other
+     * providers to satisfy the requirements of the specification.
+     * </p>
+     */
+    private static final List<ConfigurationResourceProvider> FACES_CONFIG_RESOURCE_PROVIDERS;
+
+    /**
+     * <p>
+     * A List of resource providers that search for faces-config documents.
+     * By default, this contains a provider for the Mojarra, and one other
+     * providers to satisfy the requirements of the specification.
+     * </p>
+     */
+    private static final List<ConfigurationResourceProvider> FACELET_TAGLIBRARY_RESOURCE_PROVIDERS;
+
+    /**
+     * <p>
+     *  The <code>ConfigManager</code> will multithread the calls to the
+     *  <code>ConfigurationResourceProvider</code>s as well as any calls
+     *  to parse a resources into a DOM.  By default, we'll use only 5 threads
+     *  per web application.
+     * </p>
+     */
+    private static final int NUMBER_OF_TASK_THREADS = 5;
+
+    /**
+     * <p>
+     *  There is only once instance of <code>ConfigManager</code>.
+     * <p>
+     */
+    private static final ConfigManager CONFIG_MANAGER = new ConfigManager();
+
+
+    /**
+     * The application-scoped key under which the Future responsible for annotation
+     * scanning is associated with.
+     */
+    private static final String ANNOTATIONS_SCAN_TASK_KEY =
+          ConfigManager.class.getName() + "_ANNOTATION_SCAN_TASK";
+
+
+    /**
+     * The initialization time FacesContext scoped key under which the
+     * InjectionProvider is stored.
+     */
+    public static final String INJECTION_PROVIDER_KEY =
+          ConfigManager.class.getName() + "_INJECTION_PROVIDER_TASK";
+
+
+    /**
+     * Name of the attribute added by ParseTask to indicate a
+     * {@link Document} instance as a representation of
+     * <code>/WEB-INF/faces-config.xml</code>.
+     */
+    public static final String WEB_INF_MARKER = "com.sun.faces.webinf";
+
+
+    /**
+     * <p>
+     *   Contains each <code>ServletContext</code> that we've initialized.
+     *   The <code>ServletContext</code> will be removed when the application
+     *   is destroyed.
+     * </p>
+     */
+    @SuppressWarnings({"CollectionWithoutInitialCapacity"})
+    private List<ServletContext> initializedContexts =
+         new CopyOnWriteArrayList<ServletContext>();
+
+    /**
+     * <p>
+     *  The chain of {@link ConfigProcessor} instances to processing of
+     *  faces-config documents.
+     * </p>
+     */
+    private static final ConfigProcessor FACES_CONFIG_PROCESSOR_CHAIN;
+
+
+    /**
+     * <p>
+     *  The chain of {@link ConfigProcessor} instances to processing of
+     *  facelet-taglib documents.
+     * </p>
+     */
+    private static final ConfigProcessor FACELET_TAGLIB_CONFIG_PROCESSOR_CHAIN;
+
+    /**
+     * Stylesheet to convert 1.0 and 1.1 based faces-config documents
+     * to our private 1.1 schema for validation.
+     */
+    private static final String FACES_TO_1_1_PRIVATE_XSL =
+          "/com/sun/faces/jsf1_0-1_1toSchema.xsl";
+
+    /**
+     * Stylesheet to convert 1.0 facelet-taglib documents
+     * from 1.0 to 2.0 for schema validation purposes.
+     */
+    private static final String FACELETS_TO_2_0_XSL =
+          "/com/sun/faces/facelets1_0-2_0toSchema.xsl";
+
+    private static final String FACES_CONFIG_1_X_DEFAULT_NS =
+          "http://java.sun.com/JSF/Configuration";
+
+    private static final String FACELETS_1_0_DEFAULT_NS =
+          "http://java.sun.com/JSF/Facelet";
+
+
+    static {
+
+        // initialize the resource providers for faces-config documents
+        List<ConfigurationResourceProvider> facesConfigProviders =
+          new ArrayList<ConfigurationResourceProvider>(3);
+        facesConfigProviders.add(new MojarraFacesConfigResourceProvider());
+        facesConfigProviders.add(new MetaInfFacesConfigResourceProvider());
+        facesConfigProviders.add(new WebFacesConfigResourceProvider());
+        FACES_CONFIG_RESOURCE_PROVIDERS = Collections.unmodifiableList(facesConfigProviders);
+
+        // initialize the resource providers for facelet-taglib documents
+        List<ConfigurationResourceProvider> faceletTaglibProviders =
+              new ArrayList<ConfigurationResourceProvider>(3);
+        faceletTaglibProviders.add(new MetaInfFaceletTaglibraryConfigProvider());
+        faceletTaglibProviders.add(new WebFaceletTaglibResourceProvider());
+        FACELET_TAGLIBRARY_RESOURCE_PROVIDERS = Collections.unmodifiableList(faceletTaglibProviders);
+
+        // initialize the config processors for faces-config documents
+        ConfigProcessor[] configProcessors = {
+             new FactoryConfigProcessor(),
+             new LifecycleConfigProcessor(),
+             new ApplicationConfigProcessor(),
+             new ComponentConfigProcessor(),
+             new ConverterConfigProcessor(),
+             new ValidatorConfigProcessor(),
+             new ManagedBeanConfigProcessor(),
+             new RenderKitConfigProcessor(),
+             new NavigationConfigProcessor(),
+             new BehaviorConfigProcessor(),
+             new FacesConfigExtensionProcessor()
+        };
+        for (int i = 0; i < configProcessors.length; i++) {
+            ConfigProcessor p = configProcessors[i];
+            if ((i + 1) < configProcessors.length) {
+                p.setNext(configProcessors[i + 1]);
+            }
+        }
+        FACES_CONFIG_PROCESSOR_CHAIN = configProcessors[0];
+
+        // initialize the config processor for facelet-taglib documents
+        FACELET_TAGLIB_CONFIG_PROCESSOR_CHAIN = new FaceletTaglibConfigProcessor();
+
+    }
+
+
+    // ---------------------------------------------------------- Public Methods
+
+
+    /**
+     * @return a <code>ConfigManager</code> instance
+     */
+    public static ConfigManager getInstance() {
+
+        return CONFIG_MANAGER;
+
+    }
+
+
+    /**
+     * <p>
+     *   This method bootstraps JSF based on the parsed configuration resources.
+     * </p>
+     *
+     * @param sc the <code>ServletContext</code> for the application that
+     *  requires initialization
+     */
+    public void initialize(ServletContext sc) {
+
+        if (!hasBeenInitialized(sc)) {
+            initializedContexts.add(sc);
+            sc.setAttribute(SERVLET_CONTEXT_INITIALISED, true);
+            ExecutorService executor = null;
+            try {
+                WebConfiguration webConfig = WebConfiguration.getInstance(sc);
+                boolean validating = webConfig.isOptionEnabled(ValidateFacesConfigFiles);
+                if (useThreads(sc)) {
+                    executor = createExecutorService();
+                }
+
+                DocumentInfo[] facesDocuments =
+                      getConfigDocuments(sc,
+                                         getFacesConfigResourceProviders(),
+                                         executor,
+                                         validating);
+
+                FacesConfigInfo webInfFacesConfigInfo =
+                      new FacesConfigInfo(facesDocuments[facesDocuments.length - 1]);
+
+                facesDocuments = sortDocuments(facesDocuments, webInfFacesConfigInfo);
+                InitFacesContext context = (InitFacesContext) FacesContext.getCurrentInstance();
+
+                InjectionProvider containerConnector =
+                        InjectionProviderFactory.createInstance(context.getExternalContext());
+                context.getAttributes().put(INJECTION_PROVIDER_KEY, containerConnector);
+
+                boolean isFaceletsDisabled =
+                      isFaceletsDisabled(webConfig, webInfFacesConfigInfo);
+                if (!webInfFacesConfigInfo.isWebInfFacesConfig() || !webInfFacesConfigInfo.isMetadataComplete()) {
+                    // execute the Task responsible for finding annotation classes
+                    ProvideMetadataToAnnotationScanTask taskMetadata = new ProvideMetadataToAnnotationScanTask(facesDocuments, containerConnector);
+                    Future<Map<Class<? extends Annotation>,Set<Class<?>>>> annotationScan;
+                    if (executor != null) {
+                        annotationScan = executor.submit(new AnnotationScanTask(sc, context, taskMetadata));
+                        pushTaskToContext(sc, annotationScan);
+                    } else {
+                        annotationScan =
+                              new FutureTask<Map<Class<? extends Annotation>,Set<Class<?>>>>(new AnnotationScanTask(sc, context, taskMetadata));
+                        ((FutureTask) annotationScan).run();
+                    }
+                    pushTaskToContext(sc, annotationScan);
+                }
+
+                //see if the app is running in a HA enabled env               
+                if (containerConnector instanceof HighAvailabilityEnabler) {                   
+                    ((HighAvailabilityEnabler)containerConnector).enableHighAvailability(sc);
+                }
+                // process the ordered documents
+                FACES_CONFIG_PROCESSOR_CHAIN.process(sc, facesDocuments);
+                if (!isFaceletsDisabled) {
+                    FACELET_TAGLIB_CONFIG_PROCESSOR_CHAIN.process(
+                          sc, getConfigDocuments(sc,
+                                             getFaceletConfigResourceProviders(),
+                                             executor,
+                                             validating));
+                }
+
+                publishPostConfigEvent();
+            } catch (Exception e) {
+                // clear out any configured factories
+                releaseFactories();
+                Throwable t = e;
+                if (!(e instanceof ConfigurationException)) {
+                    t = new ConfigurationException("CONFIGURATION FAILED! " + t.getMessage(), t);
+                }
+                throw (ConfigurationException)t;
+            } finally {
+                if (executor != null) {
+                    executor.shutdown();
+                }
+                sc.removeAttribute(ANNOTATIONS_SCAN_TASK_KEY);
+            }
+        }
+
+    }
+
+
+
+
+    /**
+     * <p>
+     *   This method will remove any information about the application.
+     * </p>
+     * @param sc the <code>ServletContext</code> for the application that
+     *  needs to be removed
+     */
+    public void destroy(ServletContext sc) {
+
+        releaseFactories();
+        initializedContexts.remove(sc);
+        sc.removeAttribute(SERVLET_CONTEXT_INITIALISED);
+
+    }
+
+
+    /**
+     * @param sc the <code>ServletContext</code> for the application in question
+     * @return <code>true</code> if this application has already been initialized,
+     *  otherwise returns </code>fase</code>
+     */
+    public boolean hasBeenInitialized(ServletContext sc) {
+        if (sc.getAttribute(SERVLET_CONTEXT_INITIALISED) == null) {
+            return  initializedContexts.contains(sc);
+        } else {
+            sc.removeAttribute(SERVLET_CONTEXT_INITIALISED);
+            return true;
+        }
+    }
+
+
+    /**
+     * @return the results of the annotation scan task
+     */
+    public static Map<Class<? extends Annotation>,Set<Class<?>>> getAnnotatedClasses(FacesContext ctx) {
+
+        Map<String, Object> appMap =
+              ctx.getExternalContext().getApplicationMap();
+        //noinspection unchecked
+        Future<Map<Class<? extends Annotation>,Set<Class<?>>>> scanTask =
+              (Future<Map<Class<? extends Annotation>,Set<Class<?>>>>) appMap.get(ANNOTATIONS_SCAN_TASK_KEY);
+        try {
+            return ((scanTask != null)
+                    ? scanTask.get()
+                    : Collections.<Class<? extends Annotation>,Set<Class<?>>>emptyMap());
+        } catch (Exception e) {
+            throw new FacesException(e);
+        }
+
+    }
+
+
+    // --------------------------------------------------------- Private Methods
+
+
+    private static boolean useThreads(ServletContext ctx) {
+
+        WebConfiguration config = WebConfiguration.getInstance(ctx);
+        return config.isOptionEnabled(EnableThreading);
+
+    }
+
+
+    private List<ConfigurationResourceProvider> getFacesConfigResourceProviders() {
+
+        return getConfigurationResourceProviders(FACES_CONFIG_RESOURCE_PROVIDERS,
+                                                 FacesConfig);
+
+    }
+
+
+    private List<ConfigurationResourceProvider> getFaceletConfigResourceProviders() {
+
+        return getConfigurationResourceProviders(FACELET_TAGLIBRARY_RESOURCE_PROVIDERS,
+                                                 FaceletConfig);
+
+    }
+
+
+    private List<ConfigurationResourceProvider> getConfigurationResourceProviders(List<ConfigurationResourceProvider> defaultProviders,
+                                                                                  ConfigurationResourceProviderFactory.ProviderType providerType) {
+
+        ConfigurationResourceProvider[] custom =
+              ConfigurationResourceProviderFactory.createProviders(providerType);
+        if (custom.length == 0) {
+            return defaultProviders;
+        } else {
+            List<ConfigurationResourceProvider> list = new ArrayList<ConfigurationResourceProvider>();
+            list.addAll(defaultProviders);
+            // insert the custom providers after the META-INF providers and
+            // before those that scan /WEB-INF
+            list.addAll((defaultProviders.size() - 1), Arrays.asList(custom));
+            return Collections.unmodifiableList(list);
+        }
+
+    }
+
+
+    /**
+     * <p>
+     * Sort the <code>faces-config</code> documents found on the classpath
+     * and those specified by the <code>javax.faces.CONFIG_FILES</code> context
+     * init parameter.
+     * </p>
+     *
+     * @param facesDocuments an array of <em>all</em> <code>faces-config</code>
+     *  documents
+     * @param webInfFacesConfig FacesConfigInfo representing the WEB-INF/faces-config.xml
+     *  for this app
+     *
+     * @return the sorted documents
+     */
+    private DocumentInfo[] sortDocuments(DocumentInfo[] facesDocuments,
+                                         FacesConfigInfo webInfFacesConfig) {
+
+
+        int len = (webInfFacesConfig.isWebInfFacesConfig()
+                     ? facesDocuments.length - 1
+                     : facesDocuments.length);
+
+        List<String> absoluteOrdering = webInfFacesConfig.getAbsoluteOrdering();
+
+        if (len > 1) {
+            List<DocumentOrderingWrapper> list =
+                  new ArrayList<DocumentOrderingWrapper>();
+            for (int i = 1; i < len; i++) {
+                list.add(new DocumentOrderingWrapper(facesDocuments[i]));
+            }
+            DocumentOrderingWrapper[] ordering =
+                  list.toArray(new DocumentOrderingWrapper[list.size()]);
+            if (absoluteOrdering == null) {
+                DocumentOrderingWrapper.sort(ordering);
+                // sorting complete, now update the appropriate locations within
+                // the original array with the sorted documentation.
+                for (int i = 1; i < len; i++) {
+                    facesDocuments[i] = ordering[i - 1].getDocument();
+                }
+                return facesDocuments;
+            } else {
+                DocumentOrderingWrapper[] result =
+                      DocumentOrderingWrapper.sort(ordering, absoluteOrdering);
+                DocumentInfo[] ret = new DocumentInfo[((webInfFacesConfig.isWebInfFacesConfig()) ? (result.length + 2) : (result.length + 1))];
+                for (int i = 1; i < len; i++) {
+                    ret[i] = result[i - 1].getDocument();
+                }
+                // add the impl specific config file
+                ret[0] = facesDocuments[0];
+                // add the WEB-INF if necessary
+                if (webInfFacesConfig.isWebInfFacesConfig()) {
+                    ret[ret.length - 1] = facesDocuments[facesDocuments.length - 1];
+                }
+                return ret;
+            }
+        }
+
+        return facesDocuments;
+    }
+
+
+    /**
+     * <p>
+     * Utility method to check if JSF 2.0 Facelets should be disabled.
+     * If it's not explicitly disabled by the context init parameter, then
+     * check the version of the WEB-INF/faces-config.xml document.  If the version
+     * is less than 2.0, then override the default value for the context init
+     * parameter so that other parts of the system that use that config option
+     * will know it has been disabled.
+     * </p>
+     *
+     * <p>
+     * NOTE:  Since this method overrides a configuration value, it should
+     * be called before *any* document parsing is performed the configuration
+     * value may be queried by the <code>ConfigParser</code>s.
+     * </p>
+     *
+     * @param webconfig configuration for this application
+     * @param facesConfigInfo object representing WEB-INF/faces-config.xml
+     * @return <code>true</code> if Facelets should be disabled
+     */
+    private boolean isFaceletsDisabled(WebConfiguration webconfig,
+                                       FacesConfigInfo facesConfigInfo) {
+
+        boolean isFaceletsDisabled = webconfig.isOptionEnabled(DisableFaceletJSFViewHandler);
+        if (!isFaceletsDisabled) {
+            // if not explicitly disabled, make a sanity check against
+            // /WEB-INF/faces-config.xml
+            isFaceletsDisabled = !facesConfigInfo.isVersionGreaterOrEqual(2.0);
+            webconfig.overrideContextInitParameter(DisableFaceletJSFViewHandler, isFaceletsDisabled);
+        }
+        return isFaceletsDisabled;
+
+    }
+
+
+    /**
+     * Push the provided <code>Future</code> to the specified <code>ServletContext</code>.
+     */
+    private void pushTaskToContext(ServletContext sc,
+                                   Future<Map<Class<? extends Annotation>,Set<Class<?>>>> scanTask) {
+
+        sc.setAttribute(ANNOTATIONS_SCAN_TASK_KEY, scanTask);
+
+    }
+
+
+    /**
+     * Publishes a {@link javax.faces.event.PostConstructApplicationEvent} event for the current
+     * {@link Application} instance.
+     */
+    private void publishPostConfigEvent() {
+
+        FacesContext ctx = FacesContext.getCurrentInstance();
+        Application app = ctx.getApplication();
+        app.publishEvent(ctx,
+                         PostConstructApplicationEvent.class,
+                         Application.class,
+                         app);
+
+    }
+
+
+    /**
+     * <p>
+     *   Obtains an array of <code>Document</code>s to be processed
+     *   by {@link ConfigManager#FACES_CONFIG_PROCESSOR_CHAIN}.
+     * </p>
+     *
+     * @param sc the <code>ServletContext</code> for the application to be
+     *  processed
+     * @param providers <code>List</code> of <code>ConfigurationResourceProvider</code>
+     *  instances that provide the URL of the documents to parse.
+     * @param executor the <code>ExecutorService</code> used to dispatch parse
+     *  request to
+     * @param validating flag indicating whether or not the documents
+     *  should be validated
+     * @return an array of <code>DocumentInfo</code>s
+     */
+    private static DocumentInfo[] getConfigDocuments(ServletContext sc,
+                                                 List<ConfigurationResourceProvider> providers,
+                                                 ExecutorService executor,
+                                                 boolean validating) {
+
+        List<FutureTask<Collection<URI>>> urlTasks =
+             new ArrayList<FutureTask<Collection<URI>>>(providers.size());
+        for (ConfigurationResourceProvider p : providers) {
+            FutureTask<Collection<URI>> t =
+                 new FutureTask<Collection<URI>>(new URITask(p, sc));
+            urlTasks.add(t);
+            if (executor != null) {
+                executor.execute(t);
+            } else {
+                t.run();
+            }
+        }
+
+        List<FutureTask<DocumentInfo>> docTasks =
+             new ArrayList<FutureTask<DocumentInfo>>(providers.size() << 1);
+
+        for (FutureTask<Collection<URI>> t : urlTasks) {
+            try {
+                Collection<URI> l = t.get();
+                for (URI u : l) {
+                    FutureTask<DocumentInfo> d =
+                         new FutureTask<DocumentInfo>(new ParseTask(validating, u));
+                    docTasks.add(d);
+                    if (executor != null) {
+                        executor.execute(d);
+                    } else {
+                        d.run();
+                    }
+                }
+            } catch (InterruptedException ignored) {
+            } catch (Exception e) {
+                throw new ConfigurationException(e);
+            }
+        }
+
+        List<DocumentInfo> docs = new ArrayList<DocumentInfo>(docTasks.size());
+        for (FutureTask<DocumentInfo> t : docTasks) {
+            try {
+                docs.add(t.get());
+            } catch (ExecutionException e) {
+                throw new ConfigurationException(e);
+            } catch (InterruptedException ignored) { }
+        }
+
+        return docs.toArray(new DocumentInfo[docs.size()]);
+
+    }
+
+
+    /**
+     * Create a new <code>ExecutorService</code> with
+     * {@link #NUMBER_OF_TASK_THREADS} threads.
+     */
+    private static ExecutorService createExecutorService() {
+
+        int tc = Runtime.getRuntime().availableProcessors();
+        if (tc > NUMBER_OF_TASK_THREADS) {
+            tc = NUMBER_OF_TASK_THREADS;
+        }
+        return Executors.newFixedThreadPool(tc);
+
+    }
+
+
+    /**
+     * @param throwable Throwable
+     * @return the root cause of this error
+     */
+    private Throwable unwind(Throwable throwable) {
+
+          Throwable t = null;
+          if (throwable != null) {
+              t =  unwind(throwable.getCause());
+              if (t == null) {
+                  t = throwable;
+              }
+          }
+          return t;
+
+    }
+
+
+    /**
+     * Calls through to {@link javax.faces.FactoryFinder#releaseFactories()}
+     * ignoring any exceptions.
+     */
+    private void releaseFactories() {
+        try {
+            FactoryFinder.releaseFactories();
+        } catch (FacesException ignored) {
+            if (LOGGER.isLoggable(Level.FINE)) {
+                LOGGER.log(Level.FINE,
+                           "Exception thrown from FactoryFinder.releaseFactories()",
+                           ignored);
+            }
+        }
+    }
+
+
+    // ----------------------------------------------------------- Inner Classes
+
+    private static final class ProvideMetadataToAnnotationScanTask {
+        DocumentInfo [] documentInfos;
+        InjectionProvider containerConnector;
+        Set<URI> uris = null;
+        Set<String> jarNames = null;
+
+        private ProvideMetadataToAnnotationScanTask(DocumentInfo [] documentInfos,
+                InjectionProvider containerConnector) {
+            this.documentInfos = documentInfos;
+            this.containerConnector = containerConnector;
+        }
+
+        private void initializeIvars() {
+            if (null != uris || null != jarNames) {
+                assert(null != uris && null != jarNames);
+                return;
+            }
+            uris = new HashSet<URI>(documentInfos.length);
+            jarNames = new HashSet<String>(documentInfos.length);
+            for (DocumentInfo docInfo : documentInfos) {
+                URI sourceURI = docInfo.getSourceURI();
+                Matcher m = JAR_PATTERN.matcher(sourceURI.toString());
+                if (m.matches()) {
+                    String jarName = m.group(2);
+                    if (!jarNames.contains(jarName)) {
+                        FacesConfigInfo configInfo = new FacesConfigInfo(docInfo);
+                        if (!configInfo.isMetadataComplete()) {
+                            uris.add(sourceURI);
+                            jarNames.add(jarName);
+                        }
+                    }
+                }
+            }
+        }
+
+        private Set<URI> getAnnotationScanURIs() {
+            initializeIvars();
+
+            return uris;
+
+        }
+
+        private Set<String> getJarNames() {
+            initializeIvars();
+
+            return jarNames;
+        }
+
+        private com.sun.faces.spi.AnnotationScanner getAnnotationScanner() {
+            com.sun.faces.spi.AnnotationScanner result = null;
+            if (this.containerConnector instanceof com.sun.faces.spi.AnnotationScanner) {
+                result = (com.sun.faces.spi.AnnotationScanner) this.containerConnector;
+            }
+            return result;
+        }
+    }
+
+
+    /**
+     * Scans the class files within a web application returning a <code>Set</code>
+     * of classes that have been annotated with a standard Faces annotation.
+     */
+    private static class AnnotationScanTask implements Callable<Map<Class<? extends Annotation>,Set<Class<?>>>> {
+
+        private ServletContext sc;
+        private InitFacesContext facesContext;
+        private AnnotationProvider provider;
+        private ProvideMetadataToAnnotationScanTask metadataGetter;
+
+        // -------------------------------------------------------- Constructors
+
+
+        public AnnotationScanTask(ServletContext sc, InitFacesContext facesContext, ProvideMetadataToAnnotationScanTask metadataGetter) {
+            this.facesContext = facesContext;
+            this.provider = AnnotationProviderFactory.createAnnotationProvider(sc);
+            this.metadataGetter = metadataGetter;
+
+        }
+
+
+        // ----------------------------------------------- Methods from Callable
+
+
+        public Map<Class<? extends Annotation>,Set<Class<?>>> call() throws Exception {
+
+            Timer t = Timer.getInstance();
+            if (t != null) {
+                t.startTiming();
+            }
+
+            // We are executing on a different thread.
+            facesContext.callSetCurrentInstance();
+            Set<URI> scanUris = null;
+            com.sun.faces.spi.AnnotationScanner annotationScanner =
+                    metadataGetter.getAnnotationScanner();
+
+            // This is where we discover what kind of InjectionProvider
+            // we have.
+            if (provider instanceof DelegatingAnnotationProvider &&
+                null != annotationScanner) {
+                // This InjectionProvider is capable of annotation scanning *and*
+                // injection.
+                ((DelegatingAnnotationProvider)provider).setAnnotationScanner(annotationScanner,
+                        metadataGetter.getJarNames());
+                scanUris = Collections.emptySet();
+            } else {
+                // This InjectionProvider is capable of annotation scanning only
+                scanUris = metadataGetter.getAnnotationScanURIs();
+            }
+            //AnnotationScanner scanner = new AnnotationScanner(sc);
+            Map<Class<? extends Annotation>,Set<Class<?>>> annotatedClasses =
+                  provider.getAnnotatedClasses(scanUris);
+
+            if (t != null) {
+                t.stopTiming();
+                t.logResult("Configuration annotation scan complete.");
+            }
+
+            return annotatedClasses;
+
+        }
+
+
+    } // END AnnotationScanTask
+
+
+    /**
+     * <p>
+     *  This <code>Callable</code> will be used by {@link ConfigManager#getConfigDocuments(javax.servlet.ServletContext, java.util.List, java.util.concurrent.ExecutorService, boolean)}.
+     *  It represents a single configuration resource to be parsed into a DOM.
+     * </p>
+     */
+    private static class ParseTask implements Callable<DocumentInfo> {
+        private static final String JAVAEE_SCHEMA_DEFAULT_NS =
+            "http://java.sun.com/xml/ns/javaee";
+        private static final String EMPTY_FACES_CONFIG =
+                "com/sun/faces/empty-faces-config.xml";
+        private URI documentURI;
+        private DocumentBuilderFactory factory;
+        private boolean validating;
+
+        // -------------------------------------------------------- Constructors
+
+
+        /**
+         * <p>
+         *   Constructs a new ParseTask instance
+         * </p>
+         *
+         * @param validating whether or not we're validating
+         * @param documentURI a URL to the configuration resource to be parsed
+         * @throws Exception general error
+         */
+        public ParseTask(boolean validating, URI documentURI)
+        throws Exception {
+
+            this.documentURI = documentURI;
+            this.validating = validating;
+
+        }
+
+
+        // ----------------------------------------------- Methods from Callable
+
+
+        /**
+         * @return the result of the parse operation (a DOM)
+         * @throws Exception if an error occurs during the parsing process
+         */
+        public DocumentInfo call() throws Exception {
+
+            try {
+                Timer timer = Timer.getInstance();
+                if (timer != null) {
+                    timer.startTiming();
+                }
+
+                Document d = getDocument();
+
+                if (timer != null) {
+                    timer.stopTiming();
+                    timer.logResult("Parse " + documentURI.toURL().toExternalForm());
+                }
+
+                return new DocumentInfo(d, documentURI);
+            } catch (Exception e) {
+                throw new ConfigurationException(MessageFormat.format(
+                     "Unable to parse document ''{0}'': {1}",
+                     documentURI.toURL().toExternalForm(),
+                     e.getMessage()), e);
+            }
+        }
+
+
+        // ----------------------------------------------------- Private Methods
+
+
+        /**
+         * @return <code>Document</code> based on <code>documentURI</code>.
+         * @throws Exception if an error occurs during the process of building a
+         *  <code>Document</code>
+         */
+        private Document getDocument() throws Exception {
+
+            Document returnDoc;
+            DocumentBuilder db = getNonValidatingBuilder();
+            URL documentURL = documentURI.toURL();
+            InputSource is = new InputSource(getInputStream(documentURL));
+                is.setSystemId(documentURI.toURL().toExternalForm());
+            Document doc = null;
+
+            try {
+                doc = db.parse(is);
+            } catch (SAXParseException spe) {
+                // [mojarra-1693]
+                // Test if this is a zero length or whitespace only faces-config.xml file.
+                // If so, just make an empty Document
+                InputStream stream = is.getByteStream();
+                stream.close();
+
+                is = new InputSource(getInputStream(documentURL));
+                stream = is.getByteStream();
+                if (streamIsZeroLengthOrEmpty(stream) &&
+                    documentURL.toExternalForm().endsWith("faces-config.xml")) {
+                    ClassLoader loader = this.getClass().getClassLoader();
+                    is = new InputSource(getInputStream(loader.getResource(EMPTY_FACES_CONFIG)));
+                    doc = db.parse(is);
+                } 
+
+            }
+            String documentNS = doc.getDocumentElement().getNamespaceURI();
+            if (validating && documentNS != null) {
+                DOMSource domSource
+                     = new DOMSource(doc, documentURL.toExternalForm());
+
+                /*
+                 * If the Document in question is 1.2 (i.e. it has a namespace matching
+                 * JAVAEE_SCHEMA_DEFAULT_NS, then perform validation using the cached schema
+                 * and return.  Otherwise we assume a 1.0 or 1.1 faces-config in which case
+                 * we need to transform it to reference a special 1.1 schema before validating.
+                 */
+                Node documentElement = ((Document) domSource.getNode()).getDocumentElement();
+                if (JAVAEE_SCHEMA_DEFAULT_NS.equals(documentNS)) {
+                    Attr version = (Attr)
+                            documentElement.getAttributes().getNamedItem("version");
+                    DbfFactory.FacesSchema schema;
+                    if (version != null) {
+                        String versionStr = version.getValue();
+                        if ("2.0".equals(versionStr)) {
+                            if ("facelet-taglib".equals(documentElement.getLocalName())) {
+                                schema = DbfFactory.FacesSchema.FACELET_TAGLIB_20;
+                            } else {
+                                schema = DbfFactory.FacesSchema.FACES_20;
+                            }
+                        } else if ("2.1".equals(versionStr)) {
+                            if ("facelet-taglib".equals(documentElement.getLocalName())) {
+                                schema = DbfFactory.FacesSchema.FACELET_TAGLIB_20;
+                            } else {
+                                schema = DbfFactory.FacesSchema.FACES_21;
+                            }
+                        } else if ("1.2".equals(versionStr)) {
+                            schema = DbfFactory.FacesSchema.FACES_12;
+                        } else {
+                            throw new ConfigurationException("Unknown Schema version: " + versionStr);
+                        }
+                        DocumentBuilder builder = getBuilderForSchema(schema);
+                        if (builder.isValidating()) {
+                            builder.getSchema().newValidator().validate(domSource);
+                            returnDoc = ((Document) domSource.getNode());
+                        } else {
+                            returnDoc = ((Document) domSource.getNode());
+                        }
+                    } else {
+                        // this shouldn't happen, but...
+                        throw new ConfigurationException("No document version available.");
+                    }
+                } else {
+                    DOMResult domResult = new DOMResult();
+                    Transformer transformer = getTransformer(documentNS);
+                    transformer.transform(domSource, domResult);
+                    // copy the source document URI to the transformed result
+                    // so that processes that need to build URLs relative to the
+                    // document will work as expected.
+                    ((Document) domResult.getNode())
+                          .setDocumentURI(((Document) domSource
+                                .getNode()).getDocumentURI());
+                    DbfFactory.FacesSchema schemaToApply;
+                    if (FACES_CONFIG_1_X_DEFAULT_NS.equals(documentNS)) {
+                        schemaToApply = DbfFactory.FacesSchema.FACES_11;
+                    } else if (FACELETS_1_0_DEFAULT_NS.equals(documentNS)) {
+                        schemaToApply = DbfFactory.FacesSchema.FACELET_TAGLIB_20;
+                    } else {
+                        throw new IllegalStateException();
+                    }
+                    DocumentBuilder builder = getBuilderForSchema(schemaToApply);
+                    if (builder.isValidating()) {
+                        builder.getSchema().newValidator().validate(new DOMSource(domResult.getNode()));
+                        returnDoc = (Document) domResult.getNode();
+                    } else {
+                        returnDoc = (Document) domResult.getNode();
+                    }
+                }
+            } else {
+                returnDoc = doc;
+            }
+
+            // mark this document as the parsed representation of the
+            // WEB-INF/faces-config.xml.  This is used later in the configuration
+            // processing.
+            if (documentURL.toExternalForm().contains("/WEB-INF/faces-config.xml")) {
+                Attr webInf = returnDoc.createAttribute(WEB_INF_MARKER);
+                webInf.setValue("true");
+                returnDoc.getDocumentElement().getAttributes().setNamedItem(webInf);
+            }
+            return returnDoc;
+
+        }
+
+        private boolean streamIsZeroLengthOrEmpty(InputStream is) throws IOException {
+            boolean isZeroLengthOrEmpty = (0 == is.available());
+            final int size = 1024;
+            byte[] b = new byte[size];
+            String s;
+            while (!isZeroLengthOrEmpty && -1 != is.read(b, 0, size)) {
+                s = (new String(b, RIConstants.CHAR_ENCODING)).trim();
+                isZeroLengthOrEmpty = 0 == s.length();
+                b[0] = 0;
+                for (int i = 1; i < size; i += i) {
+                    System.arraycopy(b, 0, b, i, ((size - i) < i) ? (size - i) : i);
+                }
+            }
+
+            return isZeroLengthOrEmpty;
+        }
+
+
+        /**
+         * Obtain a <code>Transformer</code> using the style sheet
+         * referenced by the <code>XSL</code> constant.
+         *
+         * @return a new Tranformer instance
+         * @throws Exception if a Tranformer instance could not be created
+         */
+        private static Transformer getTransformer(String documentNS)
+        throws Exception {
+
+            TransformerFactory factory = Util.createTransformerFactory();
+
+            String xslToApply;
+            if (FACES_CONFIG_1_X_DEFAULT_NS.equals(documentNS)) {
+                xslToApply = FACES_TO_1_1_PRIVATE_XSL;
+            } else if (FACELETS_1_0_DEFAULT_NS.equals(documentNS)) {
+                xslToApply = FACELETS_TO_2_0_XSL;
+            } else {
+                throw new IllegalStateException();
+            }
+            return factory
+                 .newTransformer(new StreamSource(getInputStream(ConfigManager
+                      .class.getResource(xslToApply))));
+
+        }
+
+
+        /**
+         * @return an <code>InputStream</code> to the resource referred to by
+         *         <code>url</code>
+         * @param url source <code>URL</code>
+         * @throws IOException if an error occurs
+         */
+        private static InputStream getInputStream(URL url) throws IOException {
+
+            URLConnection conn = url.openConnection();
+            conn.setUseCaches(false);
+            return new BufferedInputStream(conn.getInputStream());
+
+        }
+
+
+
+        private DocumentBuilder getNonValidatingBuilder() throws Exception {
+
+            DocumentBuilderFactory tFactory = DbfFactory.getFactory();
+            tFactory.setValidating(false);
+            DocumentBuilder tBuilder = tFactory.newDocumentBuilder();
+            tBuilder.setEntityResolver(DbfFactory.FACES_ENTITY_RESOLVER);
+            tBuilder.setErrorHandler(DbfFactory.FACES_ERROR_HANDLER);
+            return tBuilder;
+
+        }
+
+        private DocumentBuilder getBuilderForSchema(DbfFactory.FacesSchema schema)
+        throws Exception {
+            schema.initSchema();
+            this.factory = DbfFactory.getFactory();
+
+            try {
+                factory.setSchema(schema.getSchema());
+            } catch (UnsupportedOperationException upe) {
+                return getNonValidatingBuilder();
+            }
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            builder.setEntityResolver(DbfFactory.FACES_ENTITY_RESOLVER);
+            builder.setErrorHandler(DbfFactory.FACES_ERROR_HANDLER);
+            return builder;
+        }
+
+    } // END ParseTask
+
+
+    /**
+     * <p>
+     *  This <code>Callable</code> will be used by {@link ConfigManager#getConfigDocuments(javax.servlet.ServletContext, java.util.List, java.util.concurrent.ExecutorService, boolean)}.
+     *  It represents one or more URLs to configuration resources that require
+     *  processing.
+     * </p>
+     */
+    private static class URITask implements Callable<Collection<URI>> {
+
+        private ConfigurationResourceProvider provider;
+        private ServletContext sc;
+
+
+        // -------------------------------------------------------- Constructors
+
+
+        /**
+         * Constructs a new <code>URITask</code> instance.
+         * @param provider the <code>ConfigurationResourceProvider</code> from
+         *  which zero or more <code>URL</code>s will be returned
+         * @param sc the <code>ServletContext</code> of the current application
+         */
+        public URITask(ConfigurationResourceProvider provider,
+                       ServletContext sc) {
+            this.provider = provider;
+            this.sc = sc;
+        }
+
+
+        // ----------------------------------------------- Methods from Callable
+
+
+        /**
+         * @return zero or more <code>URL</code> instances
+         * @throws Exception if an Exception is thrown by the underlying
+         *  <code>ConfigurationResourceProvider</code> 
+         */
+        public Collection<URI> call() throws Exception {
+            Collection untypedCollection = provider.getResources(sc);
+            Iterator untypedCollectionIterator = untypedCollection.iterator();
+            Collection<URI> result = Collections.emptyList();
+            if (untypedCollectionIterator.hasNext()) {
+                Object cur = untypedCollectionIterator.next();
+                // account for older versions of the provider that return Collection<URL>.
+                if (cur instanceof URL) {
+                    result = new ArrayList<URI>(untypedCollection.size());
+                    result.add(new URI(((URL)cur).toExternalForm()));
+                    while (untypedCollectionIterator.hasNext()) {
+                        cur = untypedCollectionIterator.next();
+                        result.add(new URI(((URL)cur).toExternalForm()));
+                    }
+                } else {
+                    result = (Collection<URI>) untypedCollection;
+                }
+            }
+
+            return result;
+        }
+
+    } // END URITask
+
+
+}
\ No newline at end of file
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$1.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$1.class
new file mode 100644
index 0000000..1a471f8
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$1.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebConfigResourceMonitor$Monitor.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebConfigResourceMonitor$Monitor.class
new file mode 100644
index 0000000..45f99b8
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebConfigResourceMonitor$Monitor.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebConfigResourceMonitor.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebConfigResourceMonitor.class
new file mode 100644
index 0000000..2cb55c3
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebConfigResourceMonitor.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebXmlProcessor$WebXmlHandler.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebXmlProcessor$WebXmlHandler.class
new file mode 100644
index 0000000..1a15bb4
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebXmlProcessor$WebXmlHandler.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebXmlProcessor.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebXmlProcessor.class
new file mode 100644
index 0000000..393b9cc
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener$WebXmlProcessor.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener.class b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener.class
new file mode 100644
index 0000000..751cc7a
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener.class
Binary files differ
diff --git a/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener.java b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener.java
new file mode 100644
index 0000000..f853735
--- /dev/null
+++ b/hotfix/source/org.glassfish.com.sun.faces_2.1.18/ConfigureListener.java
@@ -0,0 +1,1120 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+package com.sun.faces.config;
+
+import com.sun.faces.RIConstants;
+import com.sun.faces.application.ApplicationAssociate;
+import com.sun.faces.application.WebappLifecycleListener;
+import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.EnableGroovyScripting;
+import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.EnableLazyBeanValidation;
+import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.EnableThreading;
+import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.ForceLoadFacesConfigFiles;
+import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.VerifyFacesConfigObjects;
+import static com.sun.faces.config.WebConfiguration.WebContextInitParameter.JavaxFacesProjectStage;
+import com.sun.faces.config.InitFacesContext;
+import com.sun.faces.config.WebConfiguration.WebContextInitParameter;
+import com.sun.faces.el.ChainTypeCompositeELResolver;
+import com.sun.faces.el.ELContextImpl;
+import com.sun.faces.el.ELContextListenerImpl;
+import com.sun.faces.el.ELUtils;
+import com.sun.faces.el.FacesCompositeELResolver;
+import com.sun.faces.mgbean.BeanBuilder;
+import com.sun.faces.mgbean.BeanManager;
+import com.sun.faces.scripting.groovy.GroovyHelper;
+import com.sun.faces.scripting.groovy.GroovyHelperFactory;
+import com.sun.faces.util.FacesLogger;
+import com.sun.faces.util.MessageUtils;
+import com.sun.faces.util.MojarraThreadFactory;
+import com.sun.faces.util.ReflectionUtils;
+import com.sun.faces.util.Timer;
+import com.sun.faces.util.Util;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+import javax.el.ELContext;
+import javax.el.ExpressionFactory;
+import javax.faces.FactoryFinder;
+import javax.faces.application.Application;
+import javax.faces.application.ApplicationFactory;
+import javax.faces.application.ProjectStage;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PreDestroyApplicationEvent;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextAttributeEvent;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+import javax.servlet.jsp.JspApplicationContext;
+import javax.servlet.jsp.JspFactory;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * <p>Parse all relevant JavaServer Faces configuration resources, and
+ * configure the Reference Implementation runtime environment.</p>
+ * <p/>
+ */
+public class ConfigureListener implements ServletRequestListener,
+        HttpSessionListener,
+        ServletRequestAttributeListener,
+        HttpSessionAttributeListener,
+        ServletContextAttributeListener,
+        ServletContextListener {
+
+
+    private static final Logger LOGGER = FacesLogger.CONFIG.getLogger();
+
+    private ScheduledThreadPoolExecutor webResourcePool;
+
+    protected WebappLifecycleListener webAppListener;
+    protected WebConfiguration webConfig;
+
+
+    // ------------------------------------------ ServletContextListener Methods
+
+
+    public void contextInitialized(ServletContextEvent sce) {
+        ServletContext context = sce.getServletContext();
+
+        Timer timer = Timer.getInstance();
+        if (timer != null) {
+            timer.startTiming();
+        }
+
+        InitFacesContext initContext = new InitFacesContext(context);
+
+        if (LOGGER.isLoggable(Level.FINE)) {
+            LOGGER.log(Level.FINE,
+                    MessageFormat.format(
+                            "ConfigureListener.contextInitialized({0})",
+                            getServletContextIdentifier(context)));
+        }
+
+        webConfig = WebConfiguration.getInstance(context);
+        ConfigManager configManager = ConfigManager.getInstance();
+
+        if (configManager.hasBeenInitialized(context)) {
+            return;
+        }
+
+        // Check to see if the FacesServlet is present in the
+        // web.xml.   If it is, perform faces configuration as normal,
+        // otherwise, simply return.
+        Object mappingsAdded = context.getAttribute(RIConstants.FACES_INITIALIZER_MAPPINGS_ADDED);
+        if (mappingsAdded != null) {
+            context.removeAttribute(RIConstants.FACES_INITIALIZER_MAPPINGS_ADDED);
+        }
+
+        WebXmlProcessor webXmlProcessor = new WebXmlProcessor(context);
+        if (mappingsAdded == null) {
+            if (!webXmlProcessor.isFacesServletPresent()) {
+                if (!webConfig.isOptionEnabled(ForceLoadFacesConfigFiles)) {
+                    if (LOGGER.isLoggable(Level.FINE)) {
+                        LOGGER.log(Level.FINE,
+                                "No FacesServlet found in deployment descriptor - bypassing configuration");
+                    }
+                    WebConfiguration.clear(context);
+                    return;
+                }
+            } else {
+                if (LOGGER.isLoggable(Level.FINE)) {
+                    LOGGER.log(Level.FINE,
+                            "FacesServlet found in deployment descriptor - processing configuration.");
+                }
+            }
+        }
+
+
+        // bootstrap of faces required
+        webAppListener = new WebappLifecycleListener(context);
+        webAppListener.contextInitialized(sce);
+        ReflectionUtils.initCache(Thread.currentThread().getContextClassLoader());
+        Throwable caughtThrowable = null;
+
+        try {
+
+            if (LOGGER.isLoggable(Level.INFO)) {
+                LOGGER.log(Level.INFO,
+                        "jsf.config.listener.version",
+                        getServletContextIdentifier(context));
+            }
+
+            if (webConfig.isOptionEnabled(VerifyFacesConfigObjects)) {
+                if (LOGGER.isLoggable(Level.WARNING)) {
+                    LOGGER.warning("jsf.config.verifyobjects.development_only");
+                }
+                // if we're verifying, force bean validation to occur at startup as well
+                webConfig.overrideContextInitParameter(EnableLazyBeanValidation, false);
+                Verifier.setCurrentInstance(new Verifier());
+            }
+            initScripting();
+            configManager.initialize(context);
+            if (shouldInitConfigMonitoring()) {
+                initConfigMonitoring(context);
+            }
+
+            // Step 7, verify that all the configured factories are available
+            // and optionall that configured objects can be created. 
+            Verifier v = Verifier.getCurrentInstance();
+            if (v != null && !v.isApplicationValid()) {
+                if (LOGGER.isLoggable(Level.SEVERE)) {
+                    LOGGER.severe("jsf.config.verifyobjects.failures_detected");
+                    StringBuilder sb = new StringBuilder(128);
+                    for (String m : v.getMessages()) {
+                        sb.append(m).append('\n');
+                    }
+                    LOGGER.severe(sb.toString());
+                }
+            }
+            registerELResolverAndListenerWithJsp(context, false);
+            ELContext elctx = new ELContextImpl(initContext.getApplication().getELResolver());
+            elctx.putContext(FacesContext.class, initContext);
+            initContext.setELContext(elctx);
+            ApplicationAssociate associate =
+                    ApplicationAssociate.getInstance(context);
+            if (associate != null) {
+                associate.setContextName(getServletContextIdentifier(context));
+                BeanManager manager = associate.getBeanManager();
+                List<String> eagerBeans = manager.getEagerBeanNames();
+                if (!eagerBeans.isEmpty()) {
+                    for (String name : eagerBeans) {
+                        manager.create(name, initContext);
+                    }
+                }
+                boolean isErrorPagePresent = webXmlProcessor.isErrorPagePresent();
+                associate.setErrorPagePresent(isErrorPagePresent);
+                context.setAttribute(RIConstants.ERROR_PAGE_PRESENT_KEY_NAME,
+                        isErrorPagePresent);
+
+            }
+
+            webConfig.doPostBringupActions();
+
+        } catch (Throwable t) {
+            if (LOGGER.isLoggable(Level.SEVERE)) {
+                LOGGER.log(Level.SEVERE, "Critical error during deployment: ", t);
+            }
+            caughtThrowable = t;
+
+        } finally {
+            Verifier.setCurrentInstance(null);
+            if (LOGGER.isLoggable(Level.FINE)) {
+                LOGGER.log(Level.FINE,
+                        "jsf.config.listener.version.complete");
+            }
+            if (timer != null) {
+                timer.stopTiming();
+                timer.logResult("Initialization of context " +
+                        getServletContextIdentifier(context));
+            }
+            if (null != caughtThrowable) {
+                throw new RuntimeException(caughtThrowable);
+            }
+        }
+    }
+
+
+    public void contextDestroyed(ServletContextEvent sce) {
+        ServletContext context = sce.getServletContext();
+        InitFacesContext initContext = null;
+        boolean initialized = true;
+        try {
+            initContext = getInitFacesContext(context);
+            if (null == initContext) {
+                initContext = new InitFacesContext(context);
+            } else {
+                InitFacesContext.getThreadInitContextMap().put(Thread.currentThread(), initContext);
+            }
+
+            if (webAppListener != null) {
+                webAppListener.contextDestroyed(sce);
+                webAppListener = null;
+            }
+            if (webResourcePool != null) {
+                webResourcePool.shutdownNow();
+            }
+            if (!ConfigManager.getInstance().hasBeenInitialized(context)) {
+                initialized = false;
+                return;
+            }
+            GroovyHelper helper = GroovyHelper.getCurrentInstance(context);
+            if (helper != null) {
+                helper.setClassLoader();
+            }
+            if (LOGGER.isLoggable(Level.FINE)) {
+                LOGGER.log(Level.FINE,
+                           "ConfigureListener.contextDestroyed({0})",
+                           context.getServletContextName());
+            }
+
+
+            ELContext elctx = new ELContextImpl(initContext.getApplication().getELResolver());
+            elctx.putContext(FacesContext.class, initContext);
+            initContext.setELContext(elctx);
+            Application app = initContext.getApplication();
+            app.publishEvent(initContext,
+                    PreDestroyApplicationEvent.class,
+                    Application.class,
+                    app);
+
+        } catch (Exception e) {
+            if (LOGGER.isLoggable(Level.SEVERE)) {
+                LOGGER.log(Level.SEVERE,
+                        "Unexpected exception when attempting to tear down the Mojarra runtime",
+                        e);
+            }
+        } finally {
+            if (initialized) {
+                ApplicationAssociate.clearInstance(context);
+                ApplicationAssociate.setCurrentInstance(null);
+                // Release the initialization mark on this web application
+                ConfigManager.getInstance().destroy(context);
+                FactoryFinder.releaseFactories();
+                ReflectionUtils.clearCache(Thread.currentThread()
+                        .getContextClassLoader());
+                WebConfiguration.clear(context);
+                InitFacesContext.cleanupInitMaps(context);
+            }
+        }
+
+    }
+
+
+    // ------------------------------------- Methods from ServletRequestListener
+
+
+    public void requestDestroyed(ServletRequestEvent event) {
+        if (webAppListener != null) {
+            webAppListener.requestDestroyed(event);
+        }
+    }
+
+
+    public void requestInitialized(ServletRequestEvent event) {
+        if (webAppListener != null) {
+            webAppListener.requestInitialized(event);
+        }
+        InitFacesContext.cleanupInitMaps(event.getServletContext());
+    }
+
+
+    // ----------------------------------------- Methods from HttpSessionListener
+
+
+    public void sessionCreated(HttpSessionEvent event) {
+        if (webAppListener != null) {
+            webAppListener.sessionCreated(event);
+        }
+    }
+
+
+    public void sessionDestroyed(HttpSessionEvent event) {
+        if (webAppListener != null) {
+            webAppListener.sessionDestroyed(event);
+        }
+    }
+
+
+    // ---------------------------- Methods from ServletRequestAttributeListener
+
+
+    public void attributeAdded(ServletRequestAttributeEvent event) {
+        // ignored
+    }
+
+
+    public void attributeRemoved(ServletRequestAttributeEvent event) {
+        if (webAppListener != null) {
+            webAppListener.attributeRemoved(event);
+        }
+    }
+
+
+    public void attributeReplaced(ServletRequestAttributeEvent event) {
+        if (webAppListener != null) {
+            webAppListener.attributeReplaced(event);
+        }
+    }
+
+
+    // ------------------------------- Methods from HttpSessionAttributeListener
+
+
+    public void attributeAdded(HttpSessionBindingEvent event) {
+        // ignored
+    }
+
+
+    public void attributeRemoved(HttpSessionBindingEvent event) {
+        if (webAppListener != null) {
+            webAppListener.attributeRemoved(event);
+        }
+    }
+
+
+    public void attributeReplaced(HttpSessionBindingEvent event) {
+        if (webAppListener != null) {
+            webAppListener.attributeReplaced(event);
+        }
+    }
+
+
+    // ---------------------------- Methods from ServletContextAttributeListener
+
+
+    public void attributeAdded(ServletContextAttributeEvent event) {
+        // ignored
+    }
+
+    public void attributeRemoved(ServletContextAttributeEvent event) {
+        if (webAppListener != null) {
+            webAppListener.attributeRemoved(event);
+        }
+    }
+
+    public void attributeReplaced(ServletContextAttributeEvent event) {
+        if (webAppListener != null) {
+            webAppListener.attributeReplaced(event);
+        }
+    }
+
+
+    // --------------------------------------------------------- Private Methods
+
+    private boolean shouldInitConfigMonitoring() {
+
+        boolean development = isDevModeEnabled();
+        boolean threadingOptionSpecified = webConfig.isSet(EnableThreading);
+        if (development && !threadingOptionSpecified) {
+            return true;
+        }
+        boolean threadingOption = webConfig.isOptionEnabled(EnableThreading);
+        return (development && threadingOptionSpecified && threadingOption);
+
+    }
+
+    private void initConfigMonitoring(ServletContext context) {
+
+        //noinspection unchecked
+        Collection<URI> webURIs =
+                (Collection<URI>) context.getAttribute("com.sun.faces.webresources");
+        if (isDevModeEnabled() && webURIs != null && !webURIs.isEmpty()) {
+            webResourcePool = new ScheduledThreadPoolExecutor(1, new MojarraThreadFactory("WebResourceMonitor"));
+            webResourcePool.scheduleAtFixedRate(new WebConfigResourceMonitor(context, webURIs),
+                    2000,
+                    2000,
+                    TimeUnit.MILLISECONDS);
+        }
+        context.removeAttribute("com.sun.faces.webresources");
+
+    }
+
+    private void initScripting() {
+        if (webConfig.isOptionEnabled(EnableGroovyScripting)) {
+            GroovyHelper helper = GroovyHelperFactory.createHelper();
+            if (helper != null) {
+                helper.setClassLoader();
+            }
+        }
+    }
+
+
+    private boolean isDevModeEnabled() {
+
+        // interrogate the init parameter directly vs looking up the application
+        return "Development".equals(webConfig.getOptionValue(JavaxFacesProjectStage));
+
+    }
+
+
+    /**
+     * This method will be invoked {@link WebConfigResourceMonitor} when
+     * changes to any of the faces-config.xml files included in WEB-INF
+     * are modified.
+     */
+    private void reload(ServletContext sc) {
+
+        if (LOGGER.isLoggable(Level.INFO)) {
+            LOGGER.log(Level.INFO,
+                    "Reloading JSF configuration for context {0}",
+                    getServletContextIdentifier(sc));
+        }
+        GroovyHelper helper = GroovyHelper.getCurrentInstance();
+        if (helper != null) {
+            helper.setClassLoader();
+        }
+        // tear down the application
+        try {
+            // this will only be true in the automated test usage scenario
+            if (null != webAppListener) {
+                List<HttpSession> sessions = webAppListener.getActiveSessions();
+                if (sessions != null) {
+                    for (HttpSession session : sessions) {
+                        if (LOGGER.isLoggable(Level.INFO)) {
+                            LOGGER.log(Level.INFO,
+                                    "Invalidating Session {0}",
+                                    session.getId());
+                        }
+                        session.invalidate();
+                    }
+                }
+            }
+            ApplicationAssociate associate = ApplicationAssociate.getInstance(sc);
+            if (associate != null) {
+                BeanManager manager = associate.getBeanManager();
+                for (Map.Entry<String, BeanBuilder> entry : manager.getRegisteredBeans().entrySet()) {
+                    String name = entry.getKey();
+                    BeanBuilder bean = entry.getValue();
+                    if (ELUtils.Scope.APPLICATION.toString().equals(bean.getScope())) {
+                        if (LOGGER.isLoggable(Level.INFO)) {
+                            LOGGER.log(Level.INFO,
+                                    "Removing application scoped managed bean: {0}",
+                                    name);
+                        }
+                        sc.removeAttribute(name);
+                    }
+
+                }
+            }
+            // Release any allocated application resources
+            FactoryFinder.releaseFactories();
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            FacesContext initContext = new InitFacesContext(sc);
+            ApplicationAssociate
+                    .clearInstance(initContext.getExternalContext());
+            ApplicationAssociate.setCurrentInstance(null);
+            // Release the initialization mark on this web application
+            ConfigManager.getInstance().destroy(sc);
+            initContext.release();
+            ReflectionUtils.clearCache(Thread.currentThread().getContextClassLoader());
+            WebConfiguration.clear(sc);
+        }
+
+        // bring the application back up, avoid re-registration of certain JSP
+        // artifacts.  No verification will be performed either to make this
+        // light weight.
+
+        // init a new WebAppLifecycleListener so that the cached ApplicationAssociate
+        // is removed.
+        webAppListener = new WebappLifecycleListener(sc);
+
+        FacesContext initContext = new InitFacesContext(sc);
+        ReflectionUtils
+                .initCache(Thread.currentThread().getContextClassLoader());
+
+        try {
+            ConfigManager configManager = ConfigManager.getInstance();
+            configManager.initialize(sc);
+
+
+            registerELResolverAndListenerWithJsp(sc, true);
+            ApplicationAssociate associate =
+                    ApplicationAssociate.getInstance(sc);
+            if (associate != null) {
+                Boolean errorPagePresent = (Boolean) sc.getAttribute(RIConstants.ERROR_PAGE_PRESENT_KEY_NAME);
+                if (null != errorPagePresent) {
+                    associate.setErrorPagePresent(errorPagePresent);
+                    associate.setContextName(getServletContextIdentifier(sc));
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            initContext.release();
+        }
+
+        if (LOGGER.isLoggable(Level.INFO)) {
+            LOGGER.log(Level.INFO,
+                    "Reload complete.",
+                    getServletContextIdentifier(sc));
+        }
+
+    }
+
+
+    private static String getServletContextIdentifier(ServletContext context) {
+        if (context.getMajorVersion() == 2 && context.getMinorVersion() < 5) {
+            return context.getServletContextName();
+        } else {
+            return context.getContextPath();
+        }
+    }
+
+
+    private static boolean isJspTwoOne(ServletContext context) {
+
+        // 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 ignored) {
+            // ignored
+        }
+
+        if (JspFactory.getDefaultFactory() == null) {
+            return false;
+        }
+        try {
+            JspFactory.class.getMethod("getJspApplicationContext",
+                    ServletContext.class);
+        } catch (Exception e) {
+            return false;
+        }
+        try {
+            JspFactory.getDefaultFactory().getJspApplicationContext(context);
+        } catch (Throwable e) {
+            return false;
+        }
+        return true;
+
+    }
+
+    public void registerELResolverAndListenerWithJsp(ServletContext context, boolean reloaded) {
+
+        if (webConfig.isSet(WebContextInitParameter.ExpressionFactory)
+                || !isJspTwoOne(context)) {
+
+            // first try to load a factory defined in web.xml
+            if (!installExpressionFactory(context,
+                    webConfig.getOptionValue(
+                            WebContextInitParameter.ExpressionFactory))) {
+
+                throw new ConfigurationException(
+                        MessageUtils.getExceptionMessageString(
+                                MessageUtils.INCORRECT_JSP_VERSION_ID,
+                                WebContextInitParameter.ExpressionFactory.getDefaultValue(),
+                                WebContextInitParameter.ExpressionFactory.getQualifiedName()));
+
+            }
+
+        } else {
+
+            // 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.
+            FacesCompositeELResolver compositeELResolverForJsp =
+                    new ChainTypeCompositeELResolver(FacesCompositeELResolver.ELResolverChainType.JSP);
+            ApplicationAssociate associate =
+                    ApplicationAssociate.getInstance(context);
+            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) {
+                ApplicationFactory factory = (ApplicationFactory)
+                        FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
+                Application app = factory.getApplication();
+                if (app.getProjectStage() != ProjectStage.UnitTest && !reloaded) {
+                    throw e;
+                }
+            }
+
+            // register JSF ELContextListenerImpl with Jsp
+            ELContextListenerImpl elContextListener = new ELContextListenerImpl();
+            jspAppContext.addELContextListener(elContextListener);
+        }
+    }
+
+    private boolean installExpressionFactory(ServletContext sc,
+                                             String elFactoryType) {
+
+        if (elFactoryType == null) {
+            return false;
+        }
+        try {
+            ExpressionFactory factory = (ExpressionFactory)
+                    Util.loadClass(elFactoryType, this).newInstance();
+            ApplicationAssociate associate =
+                    ApplicationAssociate.getInstance(sc);
+            if (associate != null) {
+                associate.setExpressionFactory(factory);
+            }
+            return true;
+        } catch (Exception e) {
+            if (LOGGER.isLoggable(Level.SEVERE)) {
+                LOGGER.severe(MessageFormat.format("Unable to instantiate ExpressionFactory ''{0}''",
+                        elFactoryType));
+            }
+            return false;
+        }
+
+    }
+
+
+    private InitFacesContext getInitFacesContext(ServletContext context) {
+        Map initContextServletContext = InitFacesContext.getInitContextServletContextMap();
+        Set entries = initContextServletContext.entrySet();
+        InitFacesContext initContext = null;
+        for (Iterator iterator1 = entries.iterator(); iterator1.hasNext();) {
+            Map.Entry entry1 = (Map.Entry)iterator1.next();
+            Object initContextKey = entry1.getKey();
+            Object value1 = entry1.getValue();
+            if (context == value1) {
+                initContext =  (InitFacesContext)initContextKey;
+                break;
+            }
+        }
+        return initContext;
+    }
+
+    // ----------------------------------------------------------- Inner classes
+
+
+    /**
+     * <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 static final String WEB_FRAGMENT_PATH = "META-INF/web-fragment.xml";
+
+        private boolean facesServletPresent;
+        private boolean errorPagePresent;
+
+
+        /**
+         * <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
+
+
+        /**
+         * @return <code>true</code> if <code>WEB-INF/web.xml</code> contains
+         *         a <code>&lt;error-page&gt;</code> element.
+         */
+        boolean isErrorPagePresent() {
+
+            return errorPagePresent;
+
+        }
+
+
+        /**
+         * <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) {
+            InputStream in = context.getResourceAsStream(WEB_XML_PATH);
+            if (in == null) {
+                if (context.getMajorVersion() < 3) {
+                    throw new ConfigurationException("no web.xml present");
+                }
+            }
+            SAXParserFactory factory = getConfiguredFactory();
+            if (in != null) {
+                try {
+                    SAXParser parser = factory.newSAXParser();
+                    parser.parse(in, new WebXmlHandler());
+                } catch (Exception e) {
+                    warnProcessingError(e, context);
+                    facesServletPresent = true;
+                    return;
+                } finally {
+                    if (in != null) {
+                        try {
+                            in.close();
+                        } catch (Exception ioe) {
+                            if (LOGGER.isLoggable(Level.FINEST)) {
+                                LOGGER.log(Level.FINEST, "Closing stream", ioe);
+                            }
+                        }
+                    }
+                }
+            }
+            if (!facesServletPresent && context.getMajorVersion() >= 3) {
+                ClassLoader cl = Util.getCurrentLoader(this);
+                Enumeration<URL> urls;
+                try {
+                    urls = cl.getResources(WEB_FRAGMENT_PATH);
+                } catch (IOException ioe) {
+                    throw new ConfigurationException(ioe);
+                }
+                if (urls != null) {
+                    while (urls.hasMoreElements() && !facesServletPresent) {
+                        InputStream fragmentStream = null;
+                        try {
+                            URL url = urls.nextElement();
+                            URLConnection conn = url.openConnection();
+                            conn.setUseCaches(false);
+                            fragmentStream = conn.getInputStream();
+                            SAXParser parser = factory.newSAXParser();
+                            parser.parse(fragmentStream, new WebXmlHandler());
+                        } catch (Exception e) {
+                            warnProcessingError(e, context);
+                            facesServletPresent = true;
+                            return;
+                        } finally {
+                            if (fragmentStream != null) {
+                                try {
+                                    fragmentStream.close();
+                                } catch (IOException ioe) {
+                                    // ignore
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+        } // 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 = Util.createSAXParserFactory();
+            factory.setValidating(false);
+            factory.setNamespaceAware(true);
+            return factory;
+
+        } // END getConfiguredFactory
+
+
+        private void warnProcessingError(Exception e, ServletContext sc) {
+
+            if (LOGGER.isLoggable(Level.WARNING)) {
+                LOGGER.log(Level.WARNING,
+                        MessageFormat.format(
+                                "jsf.configuration.web.xml.parse.failed",
+                                getServletContextIdentifier(sc)),
+                        e);
+            }
+
+        }
+
+
+        /**
+         * <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 ERROR_PAGE = "error-page";
+            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 (!errorPagePresent) {
+                    if (ERROR_PAGE.equals(localName)) {
+                        errorPagePresent = true;
+                        return;
+                    }
+                }
+                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
+
+
+    private class WebConfigResourceMonitor implements Runnable {
+
+        private List<Monitor> monitors;
+        private ServletContext sc;
+
+        // -------------------------------------------------------- Constructors
+
+
+        public WebConfigResourceMonitor(ServletContext sc, Collection<URI> uris) {
+
+            assert (uris != null);
+            this.sc = sc;
+            for (URI uri : uris) {
+                if (monitors == null) {
+                    monitors = new ArrayList<Monitor>(uris.size());
+                }
+                try {
+                    Monitor m = new Monitor(uri);
+                    monitors.add(m);
+                } catch (IOException ioe) {
+                    if (LOGGER.isLoggable(Level.SEVERE)) {
+                        LOGGER.severe("Unable to setup resource monitor for "
+                                      + uri.toString()
+                                      + ".  Resource will not be monitored for changes.");
+                    }
+                    if (LOGGER.isLoggable(Level.FINE)) {
+                        LOGGER.log(Level.FINE,
+                                   ioe.toString(),
+                                   ioe);
+                    }
+                }
+            }
+
+        }
+
+
+        // ----------------------------------------------- Methods from Runnable
+
+        /**
+         * PENDING javadocs
+         */
+        public void run() {
+
+            assert (monitors != null);
+            boolean reloaded = false;
+            for (Iterator<Monitor> i = monitors.iterator(); i.hasNext(); ) {
+                Monitor m = i.next();
+                try {
+                    if (m.hasBeenModified()) {
+                        if (!reloaded) {
+                            reloaded = true;
+                        }
+                    }
+                } catch (IOException ioe) {
+                    if (LOGGER.isLoggable(Level.SEVERE)) {
+                        LOGGER.severe("Unable to access url "
+                                      + m.uri.toString()
+                                      + ".  Monitoring for this resource will no longer occur.");
+                    }
+                    if (LOGGER.isLoggable(Level.FINE)) {
+                        LOGGER.log(Level.FINE,
+                                   ioe.toString(),
+                                   ioe);
+                    }
+                    i.remove();
+                }
+            }
+            if (reloaded) {
+                reload(sc);
+            }
+
+        }
+
+
+        // ------------------------------------------------------- Inner Classes
+
+
+        private class Monitor {
+
+            private URI uri;
+            private long timestamp = -1;
+
+            // ---------------------------------------------------- Constructors
+
+
+            Monitor(URI uri) throws IOException {
+
+                this.uri = uri;
+                this.timestamp = getLastModified();
+                if (LOGGER.isLoggable(Level.INFO)) {
+                    LOGGER.log(Level.INFO,
+                            "Monitoring {0} for modifications",
+                            uri.toURL().toExternalForm());
+                }
+
+            }
+
+
+            // ----------------------------------------- Package Private Methods
+
+
+            boolean hasBeenModified() throws IOException {
+                long temp = getLastModified();
+                if (timestamp < temp) {
+                    timestamp = temp;
+                    if (LOGGER.isLoggable(Level.INFO)) {
+                        LOGGER.log(Level.INFO,
+                                "{0} changed!",
+                                uri.toURL().toExternalForm());
+                    }
+                    return true;
+                }
+                return false;
+
+            }
+
+
+            // ------------------------------------------------- Private Methods
+
+
+            private long getLastModified() throws IOException {
+
+                InputStream in = null;
+                try {
+                    URLConnection conn = uri.toURL().openConnection();
+                    conn.connect();
+                    in = conn.getInputStream();
+                    return conn.getLastModified();
+                } finally {
+                    if (in != null) {
+                        try {
+                            in.close();
+                        } catch (IOException ignored) {
+                        }
+                    }
+                }
+
+            }
+
+        } // END Monitor
+
+    } // END WebConfigResourceMonitor
+
+}
+