All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.faces.FactoryFinder Maven / Gradle / Ivy

There is a newer version: 4.1.0
Show newest version
/*
 * 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 javax.faces;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.faces.application.ApplicationFactory;
import javax.faces.component.visit.VisitContextFactory;
import javax.faces.context.ExceptionHandlerFactory;
import javax.faces.context.ExternalContextFactory;
import javax.faces.context.FacesContextFactory;
import javax.faces.context.PartialViewContextFactory;
import javax.faces.lifecycle.LifecycleFactory;
import javax.faces.render.RenderKitFactory;
import javax.faces.view.ViewDeclarationLanguageFactory;
import javax.faces.view.facelets.TagHandlerDelegateFactory;

/**
 * see Javadoc of JSF Specification
 * 
 * @author Manfred Geiler (latest modification by $Author: lu4242 $)
 * @version $Revision: 1088858 $ $Date: 2011-04-04 21:36:35 -0500 (Mon, 04 Apr 2011) $
 */
public final class FactoryFinder
{
    public static final String APPLICATION_FACTORY = "javax.faces.application.ApplicationFactory";
    public static final String EXCEPTION_HANDLER_FACTORY = "javax.faces.context.ExceptionHandlerFactory";
    public static final String EXTERNAL_CONTEXT_FACTORY = "javax.faces.context.ExternalContextFactory";
    public static final String FACES_CONTEXT_FACTORY = "javax.faces.context.FacesContextFactory";
    public static final String LIFECYCLE_FACTORY = "javax.faces.lifecycle.LifecycleFactory";
    public static final String PARTIAL_VIEW_CONTEXT_FACTORY = "javax.faces.context.PartialViewContextFactory";
    public static final String RENDER_KIT_FACTORY = "javax.faces.render.RenderKitFactory";
    public static final String TAG_HANDLER_DELEGATE_FACTORY = "javax.faces.view.facelets.TagHandlerDelegateFactory";
    public static final String VIEW_DECLARATION_LANGUAGE_FACTORY = "javax.faces.view.ViewDeclarationLanguageFactory";
    public static final String VISIT_CONTEXT_FACTORY = "javax.faces.component.visit.VisitContextFactory";

    /**
     * used as a monitor for itself and _factories. Maps in this map are used as monitors for themselves and the
     * corresponding maps in _factories.
     */
    private static Map>> _registeredFactoryNames = new HashMap>>();

    /**
     * Maps from classLoader to another map, the container (i.e. Tomcat) will create a class loader for each web app
     * that it controls (typically anyway) and that class loader is used as the key.
     * 
     * The secondary map maps the factory name (i.e. FactoryFinder.APPLICATION_FACTORY) to actual instances that are
     * created via getFactory. The instances will be of the class specified in the setFactory method for the factory
     * name, i.e. FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY, MyFactory.class).
     */
    private static Map> _factories = new HashMap>();

    private static final Set VALID_FACTORY_NAMES = new HashSet();
    private static final Map> ABSTRACT_FACTORY_CLASSES = new HashMap>();
    private static final ClassLoader myFacesClassLoader;

    static
    {
        VALID_FACTORY_NAMES.add(APPLICATION_FACTORY);
        VALID_FACTORY_NAMES.add(EXCEPTION_HANDLER_FACTORY);
        VALID_FACTORY_NAMES.add(EXTERNAL_CONTEXT_FACTORY);
        VALID_FACTORY_NAMES.add(FACES_CONTEXT_FACTORY);
        VALID_FACTORY_NAMES.add(LIFECYCLE_FACTORY);
        VALID_FACTORY_NAMES.add(PARTIAL_VIEW_CONTEXT_FACTORY);
        VALID_FACTORY_NAMES.add(RENDER_KIT_FACTORY);
        VALID_FACTORY_NAMES.add(TAG_HANDLER_DELEGATE_FACTORY);
        VALID_FACTORY_NAMES.add(VIEW_DECLARATION_LANGUAGE_FACTORY);
        VALID_FACTORY_NAMES.add(VISIT_CONTEXT_FACTORY);
        
        ABSTRACT_FACTORY_CLASSES.put(APPLICATION_FACTORY, ApplicationFactory.class);
        ABSTRACT_FACTORY_CLASSES.put(EXCEPTION_HANDLER_FACTORY, ExceptionHandlerFactory.class);
        ABSTRACT_FACTORY_CLASSES.put(EXTERNAL_CONTEXT_FACTORY, ExternalContextFactory.class);
        ABSTRACT_FACTORY_CLASSES.put(FACES_CONTEXT_FACTORY, FacesContextFactory.class);
        ABSTRACT_FACTORY_CLASSES.put(LIFECYCLE_FACTORY, LifecycleFactory.class);
        ABSTRACT_FACTORY_CLASSES.put(PARTIAL_VIEW_CONTEXT_FACTORY, PartialViewContextFactory.class);
        ABSTRACT_FACTORY_CLASSES.put(RENDER_KIT_FACTORY, RenderKitFactory.class);
        ABSTRACT_FACTORY_CLASSES.put(TAG_HANDLER_DELEGATE_FACTORY, TagHandlerDelegateFactory.class);
        ABSTRACT_FACTORY_CLASSES.put(VIEW_DECLARATION_LANGUAGE_FACTORY, ViewDeclarationLanguageFactory.class);
        ABSTRACT_FACTORY_CLASSES.put(VISIT_CONTEXT_FACTORY, VisitContextFactory.class);
        try
        {
            ClassLoader classLoader;
            if (System.getSecurityManager() != null) {
                classLoader = (ClassLoader) AccessController.doPrivileged(new java.security.PrivilegedExceptionAction() {
                    public Object run() {
                        return FactoryFinder.class.getClassLoader();
                    }
                });
            }
            else {
                classLoader = FactoryFinder.class.getClassLoader();
            }

            if (classLoader == null)
            {
                throw new FacesException("jsf api class loader cannot be identified", null);
            }
            myFacesClassLoader = classLoader;
        }
        catch (Exception e)
        {
            throw new FacesException("jsf api class loader cannot be identified", e);
        }
    }

    // ~ Start FactoryFinderProvider Support ------------------------------------------------------------------------------------
    
    private static Object _factoryFinderProviderFactoryInstance;
    
    private static volatile boolean _initialized = false;
    
    private static void initializeFactoryFinderProviderFactory()
    {
        if (!_initialized)
        {
            _factoryFinderProviderFactoryInstance = _FactoryFinderProviderFactory.getInstance();
            _initialized = true;
        }
    }

    // ~ End FactoryFinderProvider Support ------------------------------------------------------------------------------------

    // avoid instantiation
    FactoryFinder()
    {
    }

    /**
     * 

* Create (if necessary) and return a per-web-application instance of the appropriate implementation class for the * specified JavaServer Faces factory class, based on the discovery algorithm described in the class description. *

* *

* The standard factories and wrappers in JSF all implement the interface {@link FacesWrapper}. If the returned * Object is an implementation of one of the standard factories, it must be legal to cast it to an * instance of FacesWrapper and call {@link FacesWrapper#getWrapped()} on the instance. *

* * @param factoryName * Fully qualified name of the JavaServer Faces factory for which an implementation instance is requested * * @return A per-web-application instance of the appropriate implementation class for the specified JavaServer Faces * factory class * * @throws FacesException * if the web application class loader cannot be identified * @throws FacesException * if an instance of the configured factory implementation class cannot be loaded * @throws FacesException * if an instance of the configured factory implementation class cannot be instantiated * @throws IllegalArgumentException * if factoryname does not identify a standard JavaServer Faces factory name * @throws IllegalStateException * if there is no configured factory implementation class for the specified factory name * @throws NullPointerException * if factoryname is null */ public static Object getFactory(String factoryName) throws FacesException { initializeFactoryFinderProviderFactory(); if (_factoryFinderProviderFactoryInstance == null) { // Do the typical stuff return _getFactory(factoryName); } else { try { //Obtain the FactoryFinderProvider instance for this context. Object ffp = _FactoryFinderProviderFactory.FACTORY_FINDER_PROVIDER_FACTORY_GET_FACTORY_FINDER_METHOD.invoke( _factoryFinderProviderFactoryInstance, null); //Call getFactory method and pass the params return _FactoryFinderProviderFactory.FACTORY_FINDER_PROVIDER_GET_FACTORY_METHOD.invoke(ffp, factoryName); } catch (Exception e) { //No Op throw new FacesException(e); } } } private static Object _getFactory(String factoryName) throws FacesException { if (factoryName == null) { throw new NullPointerException("factoryName may not be null"); } ClassLoader classLoader = getClassLoader(); // This code must be synchronized because this could cause a problem when // using update feature each time of myfaces (org.apache.myfaces.CONFIG_REFRESH_PERIOD) // In this moment, a concurrency problem could happen Map> factoryClassNames = null; Map factoryMap = null; synchronized (_registeredFactoryNames) { factoryClassNames = _registeredFactoryNames.get(classLoader); if (factoryClassNames == null) { String message = "No Factories configured for this Application. This happens if the faces-initialization " + "does not work at all - make sure that you properly include all configuration settings necessary for a basic faces application " + "and that all the necessary libs are included. Also check the logging output of your web application and your container for any exceptions!" + "\nIf you did that and find nothing, the mistake might be due to the fact that you use some special web-containers which " + "do not support registering context-listeners via TLD files and " + "a context listener is not setup in your web.xml.\n" + "A typical config looks like this;\n\n" + " org.apache.myfaces.webapp.StartupServletContextListener\n" + "\n"; throw new IllegalStateException(message); } if (!factoryClassNames.containsKey(factoryName)) { throw new IllegalArgumentException("no factory " + factoryName + " configured for this application."); } factoryMap = _factories.get(classLoader); if (factoryMap == null) { factoryMap = new HashMap(); _factories.put(classLoader, factoryMap); } } List classNames; Object factory; synchronized (factoryClassNames) { factory = factoryMap.get(factoryName); if (factory != null) { return factory; } classNames = factoryClassNames.get(factoryName); } // release lock while calling out factory = newFactoryInstance(ABSTRACT_FACTORY_CLASSES.get(factoryName), classNames.iterator(), classLoader); synchronized (factoryClassNames) { // check if someone else already installed the factory if (factoryMap.get(factoryName) == null) { factoryMap.put(factoryName, factory); } } return factory; } private static Object newFactoryInstance(Class interfaceClass, Iterator classNamesIterator, ClassLoader classLoader) { try { Object current = null; while (classNamesIterator.hasNext()) { String implClassName = classNamesIterator.next(); Class implClass = null; try { implClass = classLoader.loadClass(implClassName); } catch (ClassNotFoundException e) { implClass = myFacesClassLoader.loadClass(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 = implClass.newInstance(); } else { // let's check if class supports the decorator pattern try { Constructor 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) { throw new FacesException(e); } catch (IllegalAccessException e) { throw new FacesException(e); } catch (InvocationTargetException e) { throw new FacesException(e); } } catch (NoSuchMethodException e) { // no decorator pattern support current = implClass.newInstance(); } } } return current; } catch (ClassNotFoundException e) { throw new FacesException(e); } catch (InstantiationException e) { throw new FacesException(e); } catch (IllegalAccessException e) { throw new FacesException(e); } } public static void setFactory(String factoryName, String implName) { initializeFactoryFinderProviderFactory(); if (_factoryFinderProviderFactoryInstance == null) { // Do the typical stuff _setFactory(factoryName, implName); } else { try { //Obtain the FactoryFinderProvider instance for this context. Object ffp = _FactoryFinderProviderFactory.FACTORY_FINDER_PROVIDER_FACTORY_GET_FACTORY_FINDER_METHOD.invoke( _factoryFinderProviderFactoryInstance,null); //Call getFactory method and pass the params _FactoryFinderProviderFactory.FACTORY_FINDER_PROVIDER_SET_FACTORY_METHOD.invoke(ffp, factoryName, implName); } catch (Exception e) { //No Op throw new FacesException(e); } } } private static void _setFactory(String factoryName, String implName) { checkFactoryName(factoryName); ClassLoader classLoader = getClassLoader(); Map> factoryClassNames = null; synchronized (_registeredFactoryNames) { Map factories = _factories.get(classLoader); if (factories != null && factories.containsKey(factoryName)) { // Javadoc says ... This method has no effect if getFactory() has already been // called looking for a factory for this factoryName. return; } factoryClassNames = _registeredFactoryNames.get(classLoader); if (factoryClassNames == null) { factoryClassNames = new HashMap>(); _registeredFactoryNames.put(classLoader, factoryClassNames); } } synchronized (factoryClassNames) { List classNameList = factoryClassNames.get(factoryName); if (classNameList == null) { classNameList = new ArrayList(); factoryClassNames.put(factoryName, classNameList); } classNameList.add(implName); } } public static void releaseFactories() throws FacesException { initializeFactoryFinderProviderFactory(); if (_factoryFinderProviderFactoryInstance == null) { // Do the typical stuff _releaseFactories(); } else { try { //Obtain the FactoryFinderProvider instance for this context. Object ffp = _FactoryFinderProviderFactory.FACTORY_FINDER_PROVIDER_FACTORY_GET_FACTORY_FINDER_METHOD.invoke( _factoryFinderProviderFactoryInstance, null); //Call getFactory method and pass the params _FactoryFinderProviderFactory.FACTORY_FINDER_PROVIDER_RELEASE_FACTORIES_METHOD.invoke(ffp, null); } catch (Exception e) { //No Op throw new FacesException(e); } } } private static void _releaseFactories() throws FacesException { ClassLoader classLoader = getClassLoader(); // This code must be synchronized synchronized (_registeredFactoryNames) { _factories.remove(classLoader); // _registeredFactoryNames has as value type Map and this must // be cleaned before release (for gc). Map> factoryClassNames = _registeredFactoryNames.get(classLoader); if (factoryClassNames != null) { factoryClassNames.clear(); } _registeredFactoryNames.remove(classLoader); } } private static void checkFactoryName(String factoryName) { if (!VALID_FACTORY_NAMES.contains(factoryName)) { throw new IllegalArgumentException("factoryName '" + factoryName + "'"); } } private static ClassLoader getClassLoader() { try { ClassLoader classLoader = null; if (System.getSecurityManager() != null) { classLoader = (ClassLoader) AccessController.doPrivileged(new java.security.PrivilegedExceptionAction() { public Object run() { return Thread.currentThread().getContextClassLoader(); } }); } else { classLoader = Thread.currentThread().getContextClassLoader(); } if (classLoader == null) { throw new FacesException("web application class loader cannot be identified", null); } return classLoader; } catch (Exception e) { throw new FacesException("web application class loader cannot be identified", e); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy