You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ja...@apache.org on 2009/03/08 17:17:57 UTC

svn commit: r751457 [2/2] - in /myfaces/core/branches/2_0_0: api/src/main/java/javax/faces/convert/ impl/ impl/src/main/java/org/apache/myfaces/config/

Added: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/XMLFacesConfiguratorStrategy.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/XMLFacesConfiguratorStrategy.java?rev=751457&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/XMLFacesConfiguratorStrategy.java (added)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/XMLFacesConfiguratorStrategy.java Sun Mar  8 16:17:56 2009
@@ -0,0 +1,1101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.config;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.application.ApplicationFactoryImpl;
+import org.apache.myfaces.application.ApplicationImpl;
+import org.apache.myfaces.config.element.NavigationRule;
+import org.apache.myfaces.config.element.Renderer;
+import org.apache.myfaces.config.impl.digester.DigesterFacesConfigDispenserImpl;
+import org.apache.myfaces.config.impl.digester.DigesterFacesConfigUnmarshallerImpl;
+import org.apache.myfaces.config.impl.digester.elements.FacesConfig;
+import org.apache.myfaces.context.FacesContextFactoryImpl;
+import org.apache.myfaces.el.DefaultPropertyResolver;
+import org.apache.myfaces.el.VariableResolverImpl;
+import org.apache.myfaces.lifecycle.LifecycleFactoryImpl;
+import org.apache.myfaces.renderkit.RenderKitFactoryImpl;
+import org.apache.myfaces.renderkit.html.HtmlRenderKitImpl;
+import org.apache.myfaces.shared_impl.util.ClassUtils;
+import org.apache.myfaces.shared_impl.util.LocaleUtils;
+import org.apache.myfaces.shared_impl.util.StateUtils;
+import org.apache.myfaces.shared_impl.util.serial.DefaultSerialFactory;
+import org.apache.myfaces.shared_impl.util.serial.SerialFactory;
+import org.xml.sax.SAXException;
+
+import javax.el.ELResolver;
+import javax.faces.FacesException;
+import javax.faces.FactoryFinder;
+import javax.faces.application.*;
+import javax.faces.context.ExternalContext;
+import javax.faces.el.PropertyResolver;
+import javax.faces.el.VariableResolver;
+import javax.faces.event.ActionListener;
+import javax.faces.event.PhaseListener;
+import javax.faces.lifecycle.Lifecycle;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.render.RenderKitFactory;
+import javax.faces.webapp.FacesServlet;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * XML Configurator.
+ *
+ * @author Jan-Kees van Andel
+ * @version $Revision: 743355 $ $Date: 2009-02-11 16:02:41 +0100 (wo, 11 feb 2009) $
+ */
+@SuppressWarnings("deprecation")
+public class XMLFacesConfiguratorStrategy extends FacesConfiguratorStrategy
+{
+    private static final Log log = LogFactory.getLog(XMLFacesConfiguratorStrategy.class);
+
+    private static final String STANDARD_FACES_CONFIG_RESOURCE = "META-INF/standard-faces-config.xml";
+    private static final String FACES_CONFIG_RESOURCE = "META-INF/faces-config.xml";
+
+    private static final String META_INF_SERVICES_RESOURCE_PREFIX = "META-INF/services/";
+
+    private static final String DEFAULT_RENDER_KIT_CLASS = HtmlRenderKitImpl.class.getName();
+    private static final String DEFAULT_APPLICATION_FACTORY = ApplicationFactoryImpl.class.getName();
+    private static final String DEFAULT_FACES_CONTEXT_FACTORY = FacesContextFactoryImpl.class.getName();
+    private static final String DEFAULT_LIFECYCLE_FACTORY = LifecycleFactoryImpl.class.getName();
+    private static final String DEFAULT_RENDER_KIT_FACTORY = RenderKitFactoryImpl.class.getName();
+    private static final String DEFAULT_FACES_CONFIG = "/WEB-INF/faces-config.xml";
+
+    private static final Set<String> FACTORY_NAMES = new HashSet<String>();
+    {
+        FACTORY_NAMES.add(FactoryFinder.APPLICATION_FACTORY);
+        FACTORY_NAMES.add(FactoryFinder.FACES_CONTEXT_FACTORY);
+        FACTORY_NAMES.add(FactoryFinder.LIFECYCLE_FACTORY);
+        FACTORY_NAMES.add(FactoryFinder.RENDER_KIT_FACTORY);
+    }
+
+    private FacesConfigUnmarshaller<? extends FacesConfig> _unmarshaller;
+    private FacesConfigDispenser<FacesConfig> _dispenser;
+
+    private RuntimeConfig _runtimeConfig;
+
+    public static final String MYFACES_API_PACKAGE_NAME = "myfaces-api";
+    public static final String MYFACES_IMPL_PACKAGE_NAME = "myfaces-impl";
+    public static final String MYFACES_TOMAHAWK_PACKAGE_NAME = "tomahawk";
+    public static final String MYFACES_TOMAHAWK_SANDBOX_PACKAGE_NAME = "tomahawk-sandbox";
+    public static final String MYFACES_TOMAHAWK_SANDBOX15_PACKAGE_NAME = "tomahawk-sandbox15";
+    public static final String COMMONS_EL_PACKAGE_NAME = "commons-el";
+    public static final String JSP_API_PACKAGE_NAME = "jsp-api";
+
+    /**
+     * Regular expression used to extract the jar information from the files present in the classpath.
+     * <p>
+     * The groups found with the regular expression are:
+     * </p>
+     * <ul>
+     * <li>Group 1: file path (required)</li>
+     * <li>Group 2: artifact id (required)</li>
+     * <li>Group 3: major version (required)</li>
+     * <li>Group 5: minor version (optional)</li>
+     * <li>Group 7: maintenance version (optional)</li>
+     * <li>Group 9: extra version (optional)</li>
+     * <li>Group 10: SNAPSHOT marker (optional)</li>
+     * </ul>
+     */
+    public static final String REGEX_LIBRARY = "jar:(file:.*/(.+)-"
+            + "(\\d+)(\\.(\\d+)(\\.(\\d+)(\\.(\\d+))?)?)?(-SNAPSHOT)?" + "\\.jar)!/META-INF/MANIFEST.MF";
+
+    /**
+     *
+     * @param externalContext The ExternalContext used when starting up.
+     */
+    public XMLFacesConfiguratorStrategy(ExternalContext externalContext) {
+        super(externalContext);
+    }
+
+    /**
+     * @param unmarshaller
+     *            the unmarshaller to set
+     */
+    public void setUnmarshaller(FacesConfigUnmarshaller<? extends FacesConfig> unmarshaller)
+    {
+        _unmarshaller = unmarshaller;
+    }
+
+    /**
+     * @return the unmarshaller
+     */
+    protected FacesConfigUnmarshaller<? extends FacesConfig> getUnmarshaller()
+    {
+        if (_unmarshaller == null)
+        {
+            _unmarshaller = new DigesterFacesConfigUnmarshallerImpl(_externalContext);
+        }
+
+        return _unmarshaller;
+    }
+
+    public void feed() throws FacesException
+    {
+        try
+        {
+            feedStandardConfig();
+            feedMetaInfServicesFactories();
+            feedClassloaderConfigurations();
+            feedContextSpecifiedConfig();
+            feedWebAppConfig();
+
+            if (log.isInfoEnabled())
+            {
+                logMetaInf();
+            }
+        }
+        catch (IOException e)
+        {
+            throw new FacesException(e);
+        }
+        catch (SAXException e)
+        {
+            throw new FacesException(e);
+        }
+    }
+
+    public void configure() throws FacesException
+    {
+        configureFactories();
+        configureApplication();
+        configureRenderKits();
+        configureRuntimeConfig();
+        configureLifecycle();
+        handleSerialFactory();
+    }
+
+    private void feedStandardConfig() throws IOException, SAXException
+    {
+        InputStream stream = ClassUtils.getResourceAsStream(STANDARD_FACES_CONFIG_RESOURCE);
+        if (stream == null)
+            throw new FacesException("Standard faces config " + STANDARD_FACES_CONFIG_RESOURCE + " not found");
+        if (log.isInfoEnabled())
+            log.info("Reading standard config " + STANDARD_FACES_CONFIG_RESOURCE);
+        getDispenser().feed(getUnmarshaller().getFacesConfig(stream, STANDARD_FACES_CONFIG_RESOURCE));
+        stream.close();
+    }
+
+    /**
+     * This method performs part of the factory search outlined in section 10.2.6.1.
+     */
+    protected void logMetaInf()
+    {
+        try
+        {
+            Map<String, List<JarInfo>> libs = new HashMap<String, List<JarInfo>>(30);
+
+            Pattern pattern = Pattern.compile(REGEX_LIBRARY);
+
+            Iterator<URL> it = ClassUtils.getResources("META-INF/MANIFEST.MF", this);
+            while (it.hasNext())
+            {
+                URL url = it.next();
+                Matcher matcher = pattern.matcher(url.toString());
+                if (matcher.matches())
+                {
+                    // We have a valid JAR
+                    String artifactId = matcher.group(2);
+                    List<JarInfo> versions = libs.get(artifactId);
+                    if (versions == null)
+                    {
+                        versions = new ArrayList<JarInfo>(2);
+                        libs.put(artifactId, versions);
+                    }
+
+                    String path = matcher.group(1);
+
+                    Version version = new Version(matcher.group(3), matcher.group(5), matcher.group(7),
+                                                  matcher.group(9), matcher.group(10));
+
+                    JarInfo newInfo = new JarInfo(path, version);
+                    if (!versions.contains(newInfo))
+                    {
+                        versions.add(newInfo);
+                    }
+                }
+            }
+
+            if (log.isInfoEnabled())
+            {
+                String[] artifactIds = { MYFACES_API_PACKAGE_NAME, MYFACES_IMPL_PACKAGE_NAME,
+                        MYFACES_TOMAHAWK_PACKAGE_NAME, MYFACES_TOMAHAWK_SANDBOX_PACKAGE_NAME,
+                        MYFACES_TOMAHAWK_SANDBOX15_PACKAGE_NAME, COMMONS_EL_PACKAGE_NAME, JSP_API_PACKAGE_NAME };
+
+                if (log.isWarnEnabled())
+                {
+                    for (String artifactId : artifactIds)
+                    {
+                        List<JarInfo> versions = libs.get(artifactId);
+                        if (versions != null && versions.size() > 1)
+                        {
+                            StringBuilder builder = new StringBuilder(1024);
+                            builder.append("You are using the library: ");
+                            builder.append(artifactId);
+                            builder.append(" in different versions; first (and probably used) version is: ");
+                            builder.append(versions.get(0).getVersion());
+                            builder.append(" loaded from: ");
+                            builder.append(versions.get(0).getUrl());
+                            builder.append(", but also found the following versions: ");
+
+                            boolean needComma = false;
+                            for (int i = 1; i < versions.size(); i++)
+                            {
+                                JarInfo info = versions.get(i);
+                                if (needComma)
+                                {
+                                    builder.append(", ");
+                                }
+
+                                builder.append(info.getVersion());
+                                builder.append(" loaded from: ");
+                                builder.append(info.getUrl());
+
+                                needComma = true;
+                            }
+
+                            log.warn(builder);
+                        }
+                    }
+                }
+
+                for (String artifactId : artifactIds)
+                {
+                    startLib(artifactId, libs);
+                }
+            }
+        }
+        catch (Throwable e)
+        {
+            throw new FacesException(e);
+        }
+    }
+
+    /**
+     * This method performs part of the factory search outlined in section 10.2.6.1.
+     */
+    protected void feedMetaInfServicesFactories()
+    {
+        try
+        {
+            for (String factoryName : FACTORY_NAMES)
+            {
+                Iterator<URL> it = ClassUtils.getResources(META_INF_SERVICES_RESOURCE_PREFIX + factoryName, this);
+                while (it.hasNext())
+                {
+                    URL url = it.next();
+                    InputStream stream = openStreamWithoutCache(url);
+                    InputStreamReader isr = new InputStreamReader(stream);
+                    BufferedReader br = new BufferedReader(isr);
+                    String className;
+                    try
+                    {
+                        className = br.readLine();
+                    }
+                    catch (IOException e)
+                    {
+                        throw new FacesException("Unable to read class name from file " + url.toExternalForm(), e);
+                    }
+                    finally
+                    {
+                        if (br != null)
+                        {
+                            br.close();
+                        }
+                        if (isr != null)
+                        {
+                            isr.close();
+                        }
+                        if (stream != null)
+                        {
+                            stream.close();
+                        }
+                    }
+
+
+                    if (log.isInfoEnabled())
+                    {
+                        log.info("Found " + factoryName + " factory implementation: " + className);
+                    }
+
+                    if (factoryName.equals(FactoryFinder.APPLICATION_FACTORY))
+                    {
+                        getDispenser().feedApplicationFactory(className);
+                    } else if (factoryName.equals(FactoryFinder.FACES_CONTEXT_FACTORY))
+                    {
+                        getDispenser().feedFacesContextFactory(className);
+                    } else if (factoryName.equals(FactoryFinder.LIFECYCLE_FACTORY))
+                    {
+                        getDispenser().feedLifecycleFactory(className);
+                    } else if (factoryName.equals(FactoryFinder.RENDER_KIT_FACTORY))
+                    {
+                        getDispenser().feedRenderKitFactory(className);
+                    } else
+                    {
+                        throw new IllegalStateException("Unexpected factory name " + factoryName);
+                    }
+                }
+            }
+        }
+        catch (Throwable e)
+        {
+            throw new FacesException(e);
+        }
+    }
+
+    private InputStream openStreamWithoutCache(URL url) throws IOException
+    {
+        URLConnection connection = url.openConnection();
+        connection.setUseCaches(false);
+        return connection.getInputStream();
+    }
+
+    /**
+     * This method fixes MYFACES-208
+     */
+    private void feedClassloaderConfigurations()
+    {
+        try
+        {
+            Map<String, URL> facesConfigs = new TreeMap<String, URL>();
+            Iterator<URL> it = ClassUtils.getResources(FACES_CONFIG_RESOURCE, this);
+            while (it.hasNext())
+            {
+                URL url = it.next();
+                String systemId = url.toExternalForm();
+                facesConfigs.put(systemId, url);
+            }
+
+            for (Map.Entry<String, URL> entry : facesConfigs.entrySet())
+            {
+                InputStream stream = null;
+                try
+                {
+                    stream = openStreamWithoutCache(entry.getValue());
+                    if (log.isInfoEnabled())
+                    {
+                        log.info("Reading config : " + entry.getKey());
+                    }
+                    getDispenser().feed(getUnmarshaller().getFacesConfig(stream, entry.getKey()));
+                }
+                finally
+                {
+                    if (stream != null)
+                    {
+                        stream.close();
+                    }
+                }
+            }
+        }
+        catch (Throwable e)
+        {
+            throw new FacesException(e);
+        }
+    }
+
+    private void feedContextSpecifiedConfig() throws IOException, SAXException
+    {
+        for (String systemId : getConfigFilesList())
+        {
+            InputStream stream = _externalContext.getResourceAsStream(systemId);
+            if (stream == null)
+            {
+                log.error("Faces config resource " + systemId + " not found");
+                continue;
+            }
+
+            if (log.isInfoEnabled())
+            {
+                log.info("Reading config " + systemId);
+            }
+            getDispenser().feed(getUnmarshaller().getFacesConfig(stream, systemId));
+            stream.close();
+        }
+    }
+
+    private List<String> getConfigFilesList() {
+        String configFiles = _externalContext.getInitParameter(FacesServlet.CONFIG_FILES_ATTR);
+        List<String> configFilesList = new ArrayList<String>();
+        if (configFiles != null)
+        {
+            StringTokenizer st = new StringTokenizer(configFiles, ",", false);
+            while (st.hasMoreTokens())
+            {
+                String systemId = st.nextToken().trim();
+
+                if (DEFAULT_FACES_CONFIG.equals(systemId))
+                {
+                    if (log.isWarnEnabled())
+                    {
+                        log.warn(DEFAULT_FACES_CONFIG + " has been specified in the " + FacesServlet.CONFIG_FILES_ATTR
+                                + " context parameter of "
+                                + "the deployment descriptor. This will automatically be removed, "
+                                + "if we wouldn't do this, it would be loaded twice.  See JSF spec 1.1, 10.3.2");
+                    }
+                }
+                else
+                {
+                    configFilesList.add(systemId);
+                }
+            }
+        }
+        return configFilesList;
+    }
+
+    private void feedWebAppConfig() throws IOException, SAXException
+    {
+        // web application config
+        InputStream stream = _externalContext.getResourceAsStream(DEFAULT_FACES_CONFIG);
+        if (stream != null)
+        {
+            if (log.isInfoEnabled())
+                log.info("Reading config /WEB-INF/faces-config.xml");
+            getDispenser().feed(getUnmarshaller().getFacesConfig(stream, DEFAULT_FACES_CONFIG));
+            stream.close();
+        }
+    }
+
+    private void configureFactories()
+    {
+        FacesConfigDispenser<FacesConfig> dispenser = getDispenser();
+        setFactories(FactoryFinder.APPLICATION_FACTORY, dispenser.getApplicationFactoryIterator(),
+                     DEFAULT_APPLICATION_FACTORY);
+        setFactories(FactoryFinder.FACES_CONTEXT_FACTORY, dispenser.getFacesContextFactoryIterator(),
+                     DEFAULT_FACES_CONTEXT_FACTORY);
+        setFactories(FactoryFinder.LIFECYCLE_FACTORY, dispenser.getLifecycleFactoryIterator(),
+                     DEFAULT_LIFECYCLE_FACTORY);
+        setFactories(FactoryFinder.RENDER_KIT_FACTORY, dispenser.getRenderKitFactoryIterator(),
+                     DEFAULT_RENDER_KIT_FACTORY);
+    }
+
+    private void setFactories(String factoryName, Collection<String> factories, String defaultFactory)
+    {
+        FactoryFinder.setFactory(factoryName, defaultFactory);
+        for (String factory : factories)
+        {
+            if (!factory.equals(defaultFactory))
+            {
+                FactoryFinder.setFactory(factoryName, factory);
+            }
+        }
+    }
+
+    private void startLib(String artifactId, Map<String, List<JarInfo>> libs)
+    {
+        List<JarInfo> versions = libs.get(artifactId);
+        if (versions == null)
+        {
+            log.info("MyFaces-package : " + artifactId + " not found.");
+        }
+        else
+        {
+            JarInfo info = versions.get(0);
+            log.info("Starting up MyFaces-package : " + artifactId + " in version : " + info.getVersion()
+                    + " from path : " + info.getUrl());
+        }
+    }
+
+    private void configureApplication()
+    {
+        Application application = ((ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY)).getApplication();
+
+        FacesConfigDispenser<FacesConfig> dispenser = getDispenser();
+        application.setActionListener(getApplicationObject(ActionListener.class,
+                                                           dispenser.getActionListenerIterator(), null));
+
+        if (dispenser.getDefaultLocale() != null)
+        {
+            application.setDefaultLocale(LocaleUtils.toLocale(dispenser.getDefaultLocale()));
+        }
+
+        if (dispenser.getDefaultRenderKitId() != null)
+        {
+            application.setDefaultRenderKitId(dispenser.getDefaultRenderKitId());
+        }
+
+        if (dispenser.getMessageBundle() != null)
+        {
+            application.setMessageBundle(dispenser.getMessageBundle());
+        }
+
+        application.setNavigationHandler(getApplicationObject(NavigationHandler.class,
+                                                              dispenser.getNavigationHandlerIterator(),
+                                                              application.getNavigationHandler()));
+
+        application.setStateManager(getApplicationObject(StateManager.class,
+                                                         dispenser.getStateManagerIterator(),
+                                                         application.getStateManager()));
+
+        application.setResourceHandler(getApplicationObject(ResourceHandler.class,
+                                                            dispenser.getResourceHandlerIterator(),
+                                                            application.getResourceHandler()));
+
+        List<Locale> locales = new ArrayList<Locale>();
+        for (String locale : dispenser.getSupportedLocalesIterator())
+        {
+            locales.add(LocaleUtils.toLocale(locale));
+        }
+
+        application.setSupportedLocales(locales);
+
+        application.setViewHandler(getApplicationObject(ViewHandler.class,
+                                                        dispenser.getViewHandlerIterator(),
+                                                        application.getViewHandler()));
+
+
+        for (String componentType : dispenser.getComponentTypes())
+        {
+            application.addComponent(componentType, dispenser.getComponentClass(componentType));
+        }
+
+        for (String converterId : dispenser.getConverterIds())
+        {
+            application.addConverter(converterId, dispenser.getConverterClassById(converterId));
+        }
+
+        for (String converterClass : dispenser.getConverterClasses())
+        {
+            try
+            {
+                application.addConverter(ClassUtils.simpleClassForName(converterClass),
+                                         dispenser.getConverterClassByClass(converterClass));
+            }
+            catch (Exception ex)
+            {
+                log.error("Converter could not be added. Reason:", ex);
+            }
+        }
+
+        if (application instanceof ApplicationImpl)
+        {
+            for (String converterClassName : dispenser.getConverterConfigurationByClassName())
+            {
+                ApplicationImpl app = (ApplicationImpl)application;
+                app.addConverterConfiguration(converterClassName, dispenser.getConverterConfiguration(converterClassName));
+            }
+        }
+
+        for (String validatorId : dispenser.getValidatorIds())
+        {
+            application.addValidator(validatorId, dispenser.getValidatorClass(validatorId));
+        }
+
+        RuntimeConfig runtimeConfig = getRuntimeConfig();
+
+        runtimeConfig.setPropertyResolverChainHead(getApplicationObject(PropertyResolver.class,
+                                                                        dispenser.getPropertyResolverIterator(),
+                                                                        new DefaultPropertyResolver()));
+
+        runtimeConfig.setVariableResolverChainHead(getApplicationObject(VariableResolver.class,
+                                                                        dispenser.getVariableResolverIterator(),
+                                                                        new VariableResolverImpl()));
+    }
+
+    protected RuntimeConfig getRuntimeConfig()
+    {
+        if (_runtimeConfig == null)
+        {
+            _runtimeConfig = RuntimeConfig.getCurrentInstance(_externalContext);
+        }
+        return _runtimeConfig;
+    }
+
+    public void setRuntimeConfig(RuntimeConfig runtimeConfig)
+    {
+        _runtimeConfig = runtimeConfig;
+    }
+
+    private <T> T getApplicationObject(Class<T> interfaceClass, Collection<String> classNamesIterator, T defaultObject)
+    {
+        T current = defaultObject;
+
+        for (String implClassName : classNamesIterator)
+        {
+            Class<? extends T> implClass = ClassUtils.simpleClassForName(implClassName);
+
+            // check, if class is of expected interface type
+            if (!interfaceClass.isAssignableFrom(implClass))
+            {
+                throw new IllegalArgumentException("Class " + implClassName + " is no " + interfaceClass.getName());
+            }
+
+            if (current == null)
+            {
+                // nothing to decorate
+                current = (T) ClassUtils.newInstance(implClass);
+            }
+            else
+            {
+                // let's check if class supports the decorator pattern
+                try
+                {
+                    Constructor<? extends T> delegationConstructor =
+                        implClass.getConstructor(new Class[] {interfaceClass});
+                    // impl class supports decorator pattern,
+                    try
+                    {
+                        // create new decorator wrapping current
+                        current = delegationConstructor.newInstance(new Object[] { current });
+                    }
+                    catch (InstantiationException e)
+                    {
+                        log.error(e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (IllegalAccessException e)
+                    {
+                        log.error(e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                    catch (InvocationTargetException e)
+                    {
+                        log.error(e.getMessage(), e);
+                        throw new FacesException(e);
+                    }
+                }
+                catch (NoSuchMethodException e)
+                {
+                    // no decorator pattern support
+                    current = (T) ClassUtils.newInstance(implClass);
+                }
+            }
+        }
+
+        return current;
+    }
+
+    private void configureRuntimeConfig()
+    {
+        RuntimeConfig runtimeConfig = RuntimeConfig.getCurrentInstance(_externalContext);
+
+        FacesConfigDispenser<FacesConfig> dispenser = getDispenser();
+        for (org.apache.myfaces.config.element.ManagedBean bean : dispenser.getManagedBeans())
+        {
+            if (log.isWarnEnabled() && runtimeConfig.getManagedBean(bean.getManagedBeanName()) != null)
+            {
+                log.warn("More than one managed bean w/ the name of '" + bean.getManagedBeanName()
+                        + "' - only keeping the last ");
+            }
+
+            runtimeConfig.addManagedBean(bean.getManagedBeanName(), bean);
+
+        }
+
+        removePurgedBeansFromSessionAndApplication(runtimeConfig);
+
+        for (NavigationRule rule : dispenser.getNavigationRules())
+        {
+            runtimeConfig.addNavigationRule(rule);
+        }
+
+        for (org.apache.myfaces.config.impl.digester.elements.ResourceBundle bundle : dispenser.getResourceBundles())
+        {
+            runtimeConfig.addResourceBundle(bundle);
+        }
+
+        for (String className : dispenser.getElResolvers())
+        {
+            runtimeConfig.addFacesConfigElResolver((ELResolver)ClassUtils.newInstance(className, ELResolver.class));
+        }
+
+    }
+
+    private void removePurgedBeansFromSessionAndApplication(RuntimeConfig runtimeConfig)
+    {
+        Map<String, org.apache.myfaces.config.element.ManagedBean> oldManagedBeans = runtimeConfig.getManagedBeansNotReaddedAfterPurge();
+        if (oldManagedBeans != null)
+        {
+            for (Map.Entry<String, org.apache.myfaces.config.element.ManagedBean> entry : oldManagedBeans.entrySet())
+            {
+                org.apache.myfaces.config.element.ManagedBean bean = entry.getValue();
+
+                String scope = bean.getManagedBeanScope();
+
+                if (scope != null && scope.equalsIgnoreCase("session"))
+                {
+                    _externalContext.getSessionMap().remove(entry.getKey());
+                }
+                else if (scope != null && scope.equalsIgnoreCase("application"))
+                {
+                    _externalContext.getApplicationMap().remove(entry.getKey());
+                }
+            }
+        }
+
+        runtimeConfig.resetManagedBeansNotReaddedAfterPurge();
+    }
+
+    private void configureRenderKits()
+    {
+        RenderKitFactory renderKitFactory = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+
+        FacesConfigDispenser<FacesConfig> dispenser = getDispenser();
+        for (String renderKitId : dispenser.getRenderKitIds())
+        {
+            String renderKitClass = dispenser.getRenderKitClass(renderKitId);
+
+            if (renderKitClass == null)
+            {
+                renderKitClass = DEFAULT_RENDER_KIT_CLASS;
+            }
+
+            javax.faces.render.RenderKit renderKit = (javax.faces.render.RenderKit) ClassUtils.newInstance(renderKitClass);
+
+            for (Renderer element : dispenser.getRenderers(renderKitId))
+            {
+                javax.faces.render.Renderer renderer;
+                try
+                {
+                    renderer = (javax.faces.render.Renderer) ClassUtils.newInstance(element.getRendererClass());
+                }
+                catch (Throwable e)
+                {
+                    // ignore the failure so that the render kit is configured
+                    log.error("failed to configure class " + element.getRendererClass(), e);
+                    continue;
+                }
+
+                renderKit.addRenderer(element.getComponentFamily(), element.getRendererType(), renderer);
+            }
+
+            renderKitFactory.addRenderKit(renderKitId, renderKit);
+        }
+    }
+
+    private void configureLifecycle()
+    {
+        // create the lifecycle used by the app
+        LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+        Lifecycle lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());
+
+        // add phase listeners
+        for (String listenerClassName : getDispenser().getLifecyclePhaseListeners())
+        {
+            try
+            {
+                lifecycle.addPhaseListener((PhaseListener) ClassUtils.newInstance(listenerClassName, PhaseListener.class));
+            }
+            catch (ClassCastException e)
+            {
+                log.error("Class " + listenerClassName + " does not implement PhaseListener");
+            }
+        }
+    }
+
+    private String getLifecycleId()
+    {
+        String id = _externalContext.getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
+
+        if (id != null)
+        {
+            return id;
+        }
+
+        return LifecycleFactory.DEFAULT_LIFECYCLE;
+    }
+
+    /*
+     * public static class VersionInfo { private String artifactId; private List<JarInfo> jarInfos;
+     *
+     * public VersionInfo(String artifactId) { this.artifactId = artifactId; }
+     *
+     * public String getArtifactId() { return packageName; }
+     *
+     * public void addJarInfo(Matcher matcher) { if (jarInfos == null) { jarInfos = new ArrayList<JarInfo>(); }
+     *
+     * String path = matcher.group(1);
+     *
+     * Version version = new Version(matcher.group(3), matcher.group(5), matcher.group(7), matcher.group(9),
+     * matcher.group(10));
+     *
+     * jarInfos.add(new JarInfo(path, version)); }
+     *
+     * public String getLastVersion() { if (jarInfos == null) return null; if (jarInfos.size() == 0) return null;
+     *
+     * return ""; //return jarInfos.get(jarInfos.size() - 1).getVersion(); }
+     *
+     * / Probably, the first encountered version will be used.
+     *
+     * @return probably used version
+     *
+     * public String getUsedVersion() {
+     *
+     * if (jarInfos == null) return null; if (jarInfos.size() == 0) return null; return ""; //return
+     * jarInfos.get(0).getVersion(); }
+     *
+     * / Probably, the first encountered version will be used.
+     *
+     * @return probably used classpath
+     *
+     * public String getUsedVersionPath() {
+     *
+     * if (jarInfos == null) return null; if (jarInfos.size() == 0) return null;
+     *
+     * return jarInfos.get(0).getUrl();
+     *
+     * } }
+     */
+    private static class JarInfo implements Comparable<JarInfo>
+    {
+        private String url;
+        private Version version;
+
+        public JarInfo(String url, Version version)
+        {
+            this.url = url;
+            this.version = version;
+        }
+
+        public Version getVersion()
+        {
+            return version;
+        }
+
+        public String getUrl()
+        {
+            return url;
+        }
+
+        public int compareTo(JarInfo info)
+        {
+            return version.compareTo(info.version);
+        }
+
+        @Override
+        public boolean equals(Object o)
+        {
+            if (o == this)
+            {
+                return true;
+            }
+            else if (o instanceof JarInfo)
+            {
+                JarInfo other = (JarInfo) o;
+                return version.equals(other.version);
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return version.hashCode();
+        }
+    }
+
+    private static class Version implements Comparable<Version>
+    {
+        private Integer[] parts;
+
+        private boolean snapshot;
+
+        public Version(String major, String minor, String maintenance, String extra, String snapshot)
+        {
+            parts = new Integer[4];
+            parts[0] = Integer.valueOf(major);
+
+            if (minor != null)
+            {
+                parts[1] = Integer.valueOf(minor);
+
+                if (maintenance != null)
+                {
+                    parts[2] = Integer.valueOf(maintenance);
+
+                    if (extra != null)
+                    {
+                        parts[3] = Integer.valueOf(extra);
+                    }
+                }
+            }
+
+            this.snapshot = snapshot != null;
+        }
+
+        public int compareTo(Version v)
+        {
+            for (int i = 0; i < parts.length; i++)
+            {
+                Integer left = parts[i];
+                Integer right = v.parts[i];
+                if (left == null)
+                {
+                    if (right == null)
+                    {
+                        break;
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                }
+                else
+                {
+                    if (right == null)
+                    {
+                        return 1;
+                    }
+                    else if (left < right)
+                    {
+                        return -1;
+                    }
+                    else if (left > right)
+                    {
+                        return 1;
+                    }
+                }
+            }
+
+            if (snapshot)
+            {
+                return v.snapshot ? 0 : -1;
+            }
+            else
+            {
+                return v.snapshot ? 1 : 0;
+            }
+        }
+
+        @Override
+        public boolean equals(Object o)
+        {
+            if (o == this)
+            {
+                return true;
+            }
+            else if (o instanceof Version)
+            {
+                Version other = (Version) o;
+                if (snapshot != other.snapshot)
+                {
+                    return false;
+                }
+
+                for (int i = 0; i < parts.length; i++)
+                {
+                    Integer thisPart = parts[i];
+                    Integer otherPart = other.parts[i];
+                    if (thisPart == null ? otherPart != null : !thisPart.equals(otherPart))
+                    {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        @Override
+        public int hashCode()
+        {
+            int hash = 0;
+            for (Integer part : parts)
+            {
+                if (part != null)
+                {
+                    hash ^= part.hashCode();
+                }
+            }
+
+            hash ^= Boolean.valueOf(snapshot).hashCode();
+
+            return hash;
+        }
+
+        @Override
+        public String toString()
+        {
+            StringBuilder builder = new StringBuilder();
+            builder.append(parts[0]);
+            for (int i = 1; i < parts.length; i++)
+            {
+                Integer val = parts[i];
+                if (val != null)
+                {
+                    builder.append('.').append(val);
+                }
+            }
+
+            if (snapshot)
+            {
+                builder.append("-SNAPSHOT");
+            }
+
+            return builder.toString();
+        }
+    }
+
+    private void handleSerialFactory()
+    {
+
+        String serialProvider = _externalContext.getInitParameter(StateUtils.SERIAL_FACTORY);
+        SerialFactory serialFactory = null;
+
+        if (serialProvider == null)
+        {
+            serialFactory = new DefaultSerialFactory();
+        }
+        else
+        {
+            try
+            {
+                serialFactory = (SerialFactory) ClassUtils.newInstance(serialProvider);
+
+            }
+            catch (ClassCastException e)
+            {
+                log.error("Make sure '" + serialProvider + "' implements the correct interface", e);
+            }
+            catch (Exception e)
+            {
+                log.error(e);
+            }
+            finally
+            {
+                if (serialFactory == null)
+                {
+                    serialFactory = new DefaultSerialFactory();
+                    log.error("Using default serialization provider");
+                }
+            }
+
+        }
+
+        log.info("Serialization provider : " + serialFactory.getClass());
+        _externalContext.getApplicationMap().put(StateUtils.SERIAL_FACTORY, serialFactory);
+    }
+}