package com.github.overengineer.scope.conversation.expression.eval;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import com.github.overengineer.scope.conversation.ConversationAdapter;
import com.github.overengineer.scope.conversation.ConversationUtil;
import com.github.overengineer.scope.conversation.expression.exceptions.ExpressionEvaluationException;
/**
* convenient, simple, statically-accessible singleton for evaluating SPEL expressions
*
* @author reesbyars
*/
public class Spel implements Eval {
private static final Logger LOG = LoggerFactory.getLogger(Spel.class);
private static Method CONVERSATION_ACCESSOR;
private static Method CONVERSATION_INITIATOR;
private static Method CONVERSATION_TERMINATOR;
private static Method CONVERSATION_CONTINUATOR;
static {
try {
CONVERSATION_ACCESSOR = ConversationUtil.class.getDeclaredMethod("getContextUsingSimpleName", new Class[]{String.class});
CONVERSATION_INITIATOR = ConversationUtil.class.getDeclaredMethod("beginUsingSimpleName", new Class[]{String.class, long.class, int.class});
CONVERSATION_TERMINATOR = ConversationUtil.class.getDeclaredMethod("endUsingSimpleName", new Class[]{String.class});
CONVERSATION_CONTINUATOR = ConversationUtil.class.getDeclaredMethod("persistUsingSimpleName", new Class[]{String.class});
} catch (SecurityException e) {
LOG.error("Could not instantiate Conversation Resolver properly. Message: " + e.getMessage());
} catch (NoSuchMethodException e) {
LOG.error("Could not instantiate Conversation Resolver properly. Message: " + e.getMessage());
}
}
private final SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
private final Map<String, Expression> expressionCache = new ConcurrentHashMap<String, Expression>();
private ParserContext parserContext = new ParserContext() {
@Override
public boolean isTemplate() {
return true;
}
@Override
public String getExpressionPrefix() {
return "${";
}
@Override
public String getExpressionSuffix() {
return "}";
}
};
/**
* {@inheritDoc}
*/
public Object evaluate(String expression, Map<String, Object> evaluationContext, Object root) throws ExpressionEvaluationException {
try {
Expression parsedExpression = this.expressionCache.get(expression);
if (parsedExpression == null) {
parsedExpression = parser.parseExpression(expression, this.parserContext);
expressionCache.put(expression, parsedExpression);
}
StandardEvaluationContext context = new StandardEvaluationContext(root);
context.setVariables(evaluationContext);
context.registerFunction("cGet", CONVERSATION_ACCESSOR);
context.registerFunction("cBeg", CONVERSATION_INITIATOR);
context.registerFunction("cEnd", CONVERSATION_TERMINATOR);
context.registerFunction("cCon", CONVERSATION_CONTINUATOR);
return parsedExpression.getValue(context);
} catch (Exception e) {
throw new ExpressionEvaluationException(expression, e);
}
}
/**
* {@inheritDoc}
*/
public Object evaluate(String expression) throws ExpressionEvaluationException {
try {
return this.evaluate(expression, ConversationAdapter.getAdapter().getActionContext(), ConversationAdapter.getAdapter().getAction());
} catch (Exception e) {
throw new ExpressionEvaluationException(expression, e);
}
}
public void setExpressionPrefix(final String prefix) {
this.parserContext = new ParserContext() {
String pre = prefix + "{";
@Override
public boolean isTemplate() {
return true;
}
@Override
public String getExpressionPrefix() {
return pre;
}
@Override
public String getExpressionSuffix() {
return "}";
}
};
}
}