/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.ajax4jsf.util;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.context.FacesContext;
import org.ajax4jsf.el.ELContextWrapper;
import org.ajax4jsf.util.GenericsIntrospectionCache.GenericsCacheEntry;
/**
* @author asmirnov
*
*/
public class ELUtils {
private ELUtils() {
// Utility class with static methods only - do not instantiate.
}
/**
* Get EL-enabled value. Return same string, if not el-expression.
* Otherthise, return parsed and evaluated expression.
*
* @param context -
* current Faces Context.
* @param value -
* string to parse.
* @return - interpreted el or unmodified value.
*/
public static boolean isValueReference(String value) {
if (value == null)
return false;
int start = value.indexOf("#{");
if (start >= 0) {
int end = value.lastIndexOf('}');
if (end >= 0 && start < end) {
return true;
}
}
return false;
}
private static Class<?> resolveType(Type type) {
Class<?> result = Object.class;
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] types = parameterizedType.getActualTypeArguments();
if (types != null && types.length != 0) {
Type actualType = types[0];
if (actualType instanceof Class) {
result = (Class<?>) actualType;
}
}
}
return result;
}
private static BeanInfo getBeanInfo(Class<?> beanClass, GenericsCacheEntry entry) {
BeanInfo beanInfo = null;
SoftReference<BeanInfo> beanInfoReference = entry.beanInfoReference;
if (beanInfoReference != null) {
beanInfo = beanInfoReference.get();
}
if (beanInfo == null) {
try {
beanInfo = Introspector.getBeanInfo(beanClass);
entry.beanInfoReference = new SoftReference<BeanInfo>(beanInfo);
} catch (IntrospectionException e) {
throw new FacesException(e.getMessage(), e);
}
}
return beanInfo;
}
private static Class<?> getGenericCollectionType(FacesContext context, Object base, String propertyName) {
Class<?> genericPropertyClass = null;
if (base != null && propertyName != null) {
Class<? extends Object> beanClass = base.getClass();
//Map and ResourceBundle have special resolvers that we doesn't support
if (!Map.class.isAssignableFrom(beanClass) && !ResourceBundle.class.isAssignableFrom(beanClass)) {
GenericsIntrospectionCache introspectionCache = GenericsIntrospectionCache.getInstance(context);
synchronized (introspectionCache) {
GenericsCacheEntry cacheEntry = introspectionCache.getGenericCacheEntry(beanClass);
if (cacheEntry.genericPropertiesClasses == null) {
cacheEntry.genericPropertiesClasses = new HashMap<String, Class<?>>();
} else {
genericPropertyClass = cacheEntry.genericPropertiesClasses.get(propertyName);
}
if (genericPropertyClass == null) {
if (!cacheEntry.genericPropertiesClasses.containsKey(propertyName)) {
BeanInfo beanInfo = getBeanInfo(beanClass, cacheEntry);
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : descriptors) {
if (propertyName.equals(pd.getName())) {
Method readMethod = pd.getReadMethod();
genericPropertyClass = resolveType(readMethod.getGenericReturnType());
break;
}
}
cacheEntry.genericPropertiesClasses.put(propertyName, genericPropertyClass);
} else {
//property Class has been already resolved as null
}
}
}
}
}
return genericPropertyClass;
}
public static Class<?> getContainerClass(FacesContext facesContext, ValueExpression expression) {
ELContext initialELContext = facesContext.getELContext();
CapturingELResolver capturingELResolver = new CapturingELResolver(initialELContext.getELResolver());
Class<?> type = expression.getType(new ELContextWrapper(initialELContext, capturingELResolver));
Class<?> containerType = type.getComponentType();
if (containerType == null && type != null) {
if (Collection.class.isAssignableFrom(type)) {
Object base = capturingELResolver.getBase();
Object property = capturingELResolver.getProperty();
if (base != null && property != null) {
containerType = getGenericCollectionType(facesContext, base, property.toString());
}
}
}
return containerType;
}
}