
org.apache.geronimo.myfaces.GeronimoFactoryFinderProvider Maven / Gradle / Ivy
/**
* 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.geronimo.myfaces;
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.FacesException;
import javax.faces.FactoryFinder;
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;
import org.apache.geronimo.web.WebApplicationName;
import org.apache.myfaces.spi.FactoryFinderProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* GeronimoFactoryFinderProvider is forked from javax.faces.FactoryFinder in MyFaces package, including the changes below :
* a. Use WebApplicationIdentity as key to hold different map for each web application
* b. Remove the codes of FactoryFinderProviderFactory
* @version $Rev$ $Date$
*/
public class GeronimoFactoryFinderProvider implements FactoryFinderProvider {
private static final Logger logger = LoggerFactory.getLogger(GeronimoFactoryFinderProvider.class);
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 Map>> _registeredFactoryNames = new HashMap>>();
private 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);
}
}
public 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;
String webApplicationName = WebApplicationName.getName();
if(webApplicationName == null) {
throw new IllegalStateException("No web identity is attached to current request thread " + Thread.currentThread().getName());
}
synchronized (_registeredFactoryNames) {
factoryClassNames = _registeredFactoryNames.get(webApplicationName);
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(webApplicationName);
if (factoryMap == null) {
factoryMap = new HashMap();
_factories.put(webApplicationName, 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 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 void setFactory(String factoryName, String implName) {
if (logger.isDebugEnabled()) {
logger.debug("Enter setFactory " + factoryName + " = " + implName);
}
checkFactoryName(factoryName);
String webApplicationIdentity = WebApplicationName.getName();
if(webApplicationIdentity == null) {
throw new IllegalStateException("No web identity is attached to current request thread " + Thread.currentThread().getName());
}
Map> factoryClassNames = null;
synchronized (_registeredFactoryNames) {
Map factories = _factories.get(webApplicationIdentity);
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(webApplicationIdentity);
if (factoryClassNames == null) {
factoryClassNames = new HashMap>();
_registeredFactoryNames.put(webApplicationIdentity, factoryClassNames);
}
}
synchronized (factoryClassNames) {
List classNameList = factoryClassNames.get(factoryName);
if (classNameList == null) {
classNameList = new ArrayList();
factoryClassNames.put(factoryName, classNameList);
}
classNameList.add(implName);
if (logger.isDebugEnabled()) {
logger.debug("Factory map of web application [" + webApplicationIdentity + "] is " + factoryClassNames);
}
}
}
public void releaseFactories() throws FacesException {
String webApplicationIdentity = WebApplicationName.getName();
if(webApplicationIdentity == null) {
throw new IllegalStateException("No web identity is attached to current request thread " + Thread.currentThread().getName());
}
// This code must be synchronized
synchronized (_registeredFactoryNames) {
_factories.remove(webApplicationIdentity);
// _registeredFactoryNames has as value type Map and this must
// be cleaned before release (for gc).
Map> factoryClassNames = _registeredFactoryNames.get(webApplicationIdentity);
if(logger.isDebugEnabled()) {
logger.debug("Web application [" + webApplicationIdentity + "] releases the factory map " + factoryClassNames);
}
if (factoryClassNames != null) {
factoryClassNames.clear();
}
_registeredFactoryNames.remove(webApplicationIdentity);
}
}
private void checkFactoryName(String factoryName) {
if (!VALID_FACTORY_NAMES.contains(factoryName)) {
throw new IllegalArgumentException("factoryName '" + factoryName + "'");
}
}
private 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