package com.idega.util.expression;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.application.Application;
import javax.faces.context.FacesContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import bsh.Interpreter;
import com.idega.business.SpringBeanName;
import com.idega.util.CoreConstants;
/**
* @author <a href="mailto:civilis@idega.com">Vytautas Čivilis</a>
* @version $Revision: 1.9 $
*
* Last modified: $Date: 2009/05/15 07:22:30 $ by $Author: valdas $
*
*/
@Service
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class ELUtil implements ApplicationContextAware {
private ApplicationContext applicationcontext;
private static ELUtil me;
private static Logger LOGGER = Logger.getLogger(ELUtil.class.getName());
public static final String EXPRESSION_BEGIN = "#{",
EXPRESSION_END = "}";
private Interpreter interpreter;
public static ELUtil getInstance() {
return me;
}
public ELUtil() {
//should be created by spring, so no need to synchronize
if(ELUtil.me == null) {
ELUtil.me = this;
}
else {
LOGGER.warning("Tried to repeatedly create singleton instance");
}
}
public <T>T getBean(String expression) throws BeanCreationException {
if (expression.contains(CoreConstants.DOT)) {
FacesContext fctx = FacesContext.getCurrentInstance();
if (fctx != null) {
if (!expression.startsWith(EXPRESSION_BEGIN)) {
expression = EXPRESSION_BEGIN + expression;
}
if (!expression.endsWith(EXPRESSION_END)) {
expression += EXPRESSION_END;
}
ValueExpression ve = fctx.getApplication().getExpressionFactory().createValueExpression(fctx.getELContext(), expression, Object.class);
@SuppressWarnings("unchecked")
T bean = (T) ve.getValue(fctx.getELContext());
return bean;
} else
throw new UnsupportedOperationException("Method binding without faces context not supported yet");
}
expression = cleanupExp(expression);
ApplicationContext ac = getApplicationContext();
@SuppressWarnings("unchecked")
T val = (T) ac.getBean(expression);
return val;
}
public void autowire(Object obj) {
ApplicationContext ac = getApplicationContext();
ac.getAutowireCapableBeanFactory().autowireBean(obj);
}
public static String cleanupExp(String exp) {
if (exp.startsWith(EXPRESSION_BEGIN)) {
exp = exp.substring(EXPRESSION_BEGIN.length());
}
if (exp.endsWith(EXPRESSION_END)) {
exp = exp.substring(0, exp.length()-EXPRESSION_END.length());
}
return exp;
}
public ApplicationContext getApplicationContext() {
return applicationcontext;
}
@Override
public void setApplicationContext(ApplicationContext applicationcontext) throws BeansException {
this.applicationcontext = applicationcontext;
}
public void publishEvent(ApplicationEvent event) {
if (event != null) {
ApplicationContext ac = getApplicationContext();
ac.publishEvent(event);
}
}
public <T>T getBean(Class<T> clazz) throws BeanCreationException {
if(!clazz.isAnnotationPresent(SpringBeanName.class)) {
throw new RuntimeException("Interface is not annotated with "+SpringBeanName.class.getName()+" annotation");
}
SpringBeanName bname = clazz.getAnnotation(SpringBeanName.class);
@SuppressWarnings("unchecked")
T bean = (T) getBean(bname.value());
return bean;
}
/**
* Evaluates expression
*
* @param exp
* @return
* @throws Exception
*/
public Object evaluateExpression(String exp) throws Exception{
//TODO: use unified EL resolvers???
String beanName = getBeanName(exp);
String methodName = getMethodName(exp);
List<String> argsList = getArgs(exp);
Class<?>[] classParams = new Class[argsList.size()];
Object[] strParams = new String[argsList.size()];
for(int i = 0;i<argsList.size();i++){
classParams[i] = String.class;
strParams[i] = argsList.get(i);
}
Object obj = ELUtil.getInstance().getBean(beanName);
Object returnedObj = null;
try {
Method method = obj.getClass().getMethod(methodName, classParams);
returnedObj = method.invoke(obj, strParams);
} catch (Exception e) {
throw new Exception("Exeption accured while trying to invoke method " + methodName, e);
}
returnedObj = getPostConditionValue(exp, returnedObj, "==");
returnedObj = getPostConditionValue(exp, returnedObj, "!=");
return returnedObj;
}
private Object getPostConditionValue(String exp, Object returnedObj, String condition) {
if (exp == null || returnedObj == null) {
return returnedObj;
}
int conditionIndex = exp.indexOf(condition);
if (conditionIndex == -1) {
return returnedObj;
}
String conditionParameter = exp.substring(conditionIndex + condition.length());
conditionParameter = cleanupExp(conditionParameter);
String expression = null;
if (returnedObj instanceof Boolean || returnedObj instanceof Number) {
expression = String.valueOf(returnedObj).concat(condition).concat(conditionParameter);
} // More expressions can be added here
if (expression == null) {
return returnedObj;
}
try {
returnedObj = getInterpreter().eval(expression);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Error evaluating expression: " + expression, e);
return returnedObj;
}
return returnedObj;
}
private String getBeanName(String exp){
String beanName = cleanupExp(exp);
while(true){
beanName = beanName.substring(0, beanName.lastIndexOf(CoreConstants.DOT));
if (beanName.matches("[a-zA-Z0-9.]+") || beanName.indexOf(CoreConstants.DOT) == -1) {
break;
}
}
return beanName;
}
private String getMethodName(String exp){
String beanName = getBeanName(exp);
String methodName = cleanupExp(exp);
int index = methodName.indexOf("(");
if(index >= 0){
methodName = methodName.substring(beanName.length()+1, index);
} else {
methodName = methodName.substring(beanName.length()+1);
methodName = "get"+Character.toUpperCase(methodName.charAt(0))+methodName.substring(1);
}
return methodName;
}
private List<String> getArgs(String exp){
List<String> returnArray = new ArrayList<String>();
int pre = exp.indexOf("(");
if(pre >= 0){
String argsList = exp.substring( pre+1, exp.lastIndexOf(")"));
String removedApo = argsList.replaceAll("'", "");
StringTokenizer tokenizer = new StringTokenizer(removedApo,",");
while(tokenizer.hasMoreTokens()){
String token = tokenizer.nextToken();
returnArray.add(token.trim());
}
}
return returnArray;
}
private Interpreter getInterpreter() {
if (interpreter == null) {
interpreter = new Interpreter();
}
return interpreter;
}
public static boolean isExpression(String expression) {
if(expression == null){
return false;
}
int open = expression.indexOf("#{");
if(open >= 0){
int close = expression.indexOf("}",open);
return (close >= 0);
}
return false;
}
public static ValueExpression createValueExpression(FacesContext fContext, String expression, Class<?> expectedReturnType) {
// get application from faces context
Application app = fContext.getApplication();
ExpressionFactory exprFactory = app.getExpressionFactory();
// getting the ELContext from faces context
ELContext elContext = fContext.getELContext();
// creating value expression with the help of the expression factory and the ELContext
return exprFactory.createValueExpression(elContext, expression, expectedReturnType);
}
public static MethodExpression createMethodExpression(FacesContext context, String expression, Class<?> expectedReturnType,
Class<?>[] expectedParamTypes) {
Application app = context.getApplication();
ExpressionFactory exprFactory = app.getExpressionFactory();
ELContext elContext = context.getELContext();
return exprFactory.createMethodExpression(elContext, expression, expectedReturnType, expectedParamTypes);
}
}