package org.jboss.seam.bpm;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.el.CompositeELResolver;
import javax.el.ELContext;
import javax.el.MethodExpression;
import javax.el.MethodNotFoundException;
import javax.el.PropertyNotFoundException;
import javax.el.ValueExpression;
import org.jboss.seam.el.EL;
import org.jboss.seam.el.SeamFunctionMapper;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.jbpm.jpdl.el.ELException;
import org.jbpm.jpdl.el.Expression;
import org.jbpm.jpdl.el.ExpressionEvaluator;
import org.jbpm.jpdl.el.FunctionMapper;
import org.jbpm.jpdl.el.VariableResolver;
/**
* Plugs the JBoss EL expression language and Seam
* EL resolvers into jBPM. Note that this current
* implementation does not allow jBPM to see stuff
* defined only by the JSF ELResolvers.
*
* @author Gavin King
* @author Pete Muir
*
*/
public class SeamExpressionEvaluator
extends ExpressionEvaluator
{
private static LogProvider log = Logging.getLogProvider(SeamExpressionEvaluator.class);
@Override
public Object evaluate(String expression, Class returnType, final VariableResolver resolver, FunctionMapper mapper)
throws ELException
{
return createExpression(expression, returnType, mapper).evaluate(resolver);
}
@Override
public Expression parseExpression(final String expression, final Class returnType, FunctionMapper mapper)
throws ELException
{
return createExpression(expression, returnType, mapper);
}
private static Expression createExpression(final String expression, final Class returnType, final FunctionMapper mapper)
{
return new Expression()
{
private ELContext elContext = EL.createELContext();
private MethodExpression me;
private ValueExpression ve;
private void initMethodExpression()
{
if (me == null || ve == null)
{
me = EL.EXPRESSION_FACTORY.createMethodExpression(elContext, expression, returnType, new Class[0]);
}
}
private void initValueExpression()
{
if (me == null || ve == null)
{
ve = EL.EXPRESSION_FACTORY.createValueExpression(elContext, expression, returnType);
}
}
@Override
public Object evaluate(VariableResolver resolver) throws ELException
{
List<javax.el.ELException> exceptions = new ArrayList<javax.el.ELException>();
try
{
initMethodExpression();
if (me != null)
{
try
{
return me.invoke(createELContext(resolver, mapper), new Object[0]);
}
catch (MethodNotFoundException e)
{
exceptions.add(e);
}
}
}
catch (javax.el.ELException e)
{
exceptions.add(e);
}
try
{
initValueExpression();
if (ve != null)
{
try
{
return ve.getValue(createELContext(resolver, mapper));
}
catch (PropertyNotFoundException e)
{
exceptions.add(e);
}
}
}
catch (javax.el.ELException e)
{
exceptions.add(e);
}
if (exceptions.size() == 1)
{
throw new ELException("Error evaluating " + expression, exceptions.get(0));
}
else if (exceptions.size() > 1)
{
log.debug("Exceptions occurred when parsing " + expression);
for (javax.el.ELException e : exceptions)
{
log.debug("Possible cause", e);
}
}
if (me == null && ve == null)
{
log.debug("Error parsing " + expression);
throw new ELException("Error parsing " + expression + "; not a valid EL expression");
}
throw new ELException("Error evaluating " + expression + "; possible causes are logged at debug level");
}
};
}
private static javax.el.FunctionMapper decorateFunctionMapper(final FunctionMapper functionMapper)
{
return new SeamFunctionMapper( new javax.el.FunctionMapper()
{
@Override
public Method resolveFunction(String prefix, String localName)
{
return functionMapper.resolveFunction(prefix, localName);
}
});
}
private static ELContext createELContext(VariableResolver resolver, FunctionMapper functionMapper)
{
CompositeELResolver composite = new CompositeELResolver();
composite.add(EL.EL_RESOLVER);
composite.add( new JbpmELResolver(resolver) );
return EL.createELContext(composite, decorateFunctionMapper(functionMapper));
}
}