/**
* Copyright (c) 2000-2017 Liferay, Inc. All rights reserved.
*
* Licensed 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 com.liferay.faces.util.factory.internal;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import com.liferay.faces.util.config.ConfiguredElement;
import com.liferay.faces.util.factory.FactoryExtensionFinder;
import com.liferay.faces.util.logging.Logger;
import com.liferay.faces.util.logging.LoggerFactory;
/**
* @author Neil Griffin
*/
public class FactoryExtensionFinderImpl extends FactoryExtensionFinder {
// Logger
private static final Logger logger = LoggerFactory.getLogger(FactoryExtensionFinderImpl.class);
// Private Constants
private static final String FACTORY_EXTENSION_CACHE = FactoryExtensionFinderImpl.class.getName();
@Override
@Deprecated
public Object getFactoryInstance(Class<?> factoryClass) {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
return getFactoryInstance(externalContext, factoryClass);
}
@Override
public Object getFactoryInstance(ExternalContext externalContext, Class<?> factoryClass) {
Object factory = null;
if (factoryClass != null) {
Map<Class<?>, Object> factoryExtensionCache = getFactoryExtensionCache(externalContext);
factory = factoryExtensionCache.get(factoryClass);
}
return factory;
}
@Override
public void registerFactory(ConfiguredElement configuredFactoryExtension) {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
registerFactory(externalContext, configuredFactoryExtension);
}
@Override
@SuppressWarnings("unchecked")
public void registerFactory(ExternalContext externalContext, ConfiguredElement configuredFactoryExtension) {
if (configuredFactoryExtension != null) {
String factoryClassFQCN = configuredFactoryExtension.getValue();
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?> factoryExtensionClass = classLoader.loadClass(factoryClassFQCN);
Class<?> baseFactoryExtensionClass = getBaseFactoryExtensionClass(factoryExtensionClass);
Object existingFactoryInstance = getFactoryInstance(externalContext, baseFactoryExtensionClass);
Object factoryInstance = newFactoryInstance(classLoader, factoryExtensionClass,
baseFactoryExtensionClass, existingFactoryInstance);
Map<Class<?>, Object> factoryExtensionCache = getFactoryExtensionCache(externalContext);
factoryExtensionCache.put(baseFactoryExtensionClass, factoryInstance);
}
catch (Exception e) {
logger.error(e);
}
}
}
@Override
@SuppressWarnings("unchecked")
public void releaseFactories(ExternalContext externalContext) {
Map<String, Object> applicationMap = externalContext.getApplicationMap();
Map<Class<?>, Object> factoryExtensionCache = (Map<Class<?>, Object>) applicationMap.get(
FACTORY_EXTENSION_CACHE);
if (factoryExtensionCache != null) {
factoryExtensionCache.clear();
applicationMap.remove(FACTORY_EXTENSION_CACHE);
}
}
@SuppressWarnings("unchecked")
private Class<?> getBaseFactoryExtensionClass(Class<?> factoryClass) {
Class<?> baseFactoryExtensionClass = factoryClass;
Class<?> factorySuperclass = factoryClass.getSuperclass();
if (!Object.class.getName().equals(factorySuperclass.getName())) {
baseFactoryExtensionClass = getBaseFactoryExtensionClass(factorySuperclass);
}
return baseFactoryExtensionClass;
}
@SuppressWarnings("unchecked")
private Map<Class<?>, Object> getFactoryExtensionCache(ExternalContext externalContext) {
Map<String, Object> applicationMap = externalContext.getApplicationMap();
Map<Class<?>, Object> factoryExtensionCache = (Map<Class<?>, Object>) applicationMap.get(
FACTORY_EXTENSION_CACHE);
if (factoryExtensionCache == null) {
factoryExtensionCache = new HashMap<Class<?>, Object>();
applicationMap.put(FACTORY_EXTENSION_CACHE, factoryExtensionCache);
}
return factoryExtensionCache;
}
private Object newFactoryInstance(ClassLoader classLoader, Class<?> factoryExtensionClass,
Class<?> baseFactoryExtensionClass, Object wrappedFactory) throws ClassNotFoundException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Object classInstance = null;
if (classLoader != null) {
if (factoryExtensionClass != null) {
Constructor<?> wrapperConstructor = null;
Constructor<?>[] constructors = factoryExtensionClass.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
Class<?>[] parameterTypes = constructor.getParameterTypes();
if ((parameterTypes != null) && (parameterTypes.length == 1) &&
(parameterTypes[0].getName().equals(baseFactoryExtensionClass.getName()))) {
wrapperConstructor = constructor;
}
}
if (wrapperConstructor == null) {
logger.debug("Creating instance with zero-arg constructor since wrapperConstructor=null");
try {
classInstance = factoryExtensionClass.newInstance();
}
catch (InstantiationException e) {
logger.error("Unable to create an instance of [{0}] with zero-arg constructor.",
factoryExtensionClass.getName());
throw e;
}
catch (IllegalAccessException e) {
logger.error("Unable to create an instance of [{0}] with zero-arg constructor.",
factoryExtensionClass.getName());
throw e;
}
}
else {
logger.debug("Creating instance with one-arg constructor since wrapperConstructor=[{0}]",
wrapperConstructor);
try {
classInstance = wrapperConstructor.newInstance(wrappedFactory);
}
catch (InstantiationException e) {
logger.error("Unable to create an instance of [{0}] with one-arg constructor.",
factoryExtensionClass.getName());
throw e;
}
catch (IllegalAccessException e) {
logger.error("Unable to create an instance of [{0}] with one-arg constructor.",
factoryExtensionClass.getName());
throw e;
}
catch (IllegalArgumentException e) {
logger.error("Unable to create an instance of [{0}] with one-arg constructor.",
factoryExtensionClass.getName());
throw e;
}
catch (InvocationTargetException e) {
logger.error("Unable to create an instance of [{0}] with one-arg constructor.",
factoryExtensionClass.getName());
throw e;
}
}
}
}
return classInstance;
}
}