07-20-2017 05:36 AM
I would like to create a list inside an activiti expression like in the following example:
<serviceTask activiti:class="com.example.workflow.servicetask.Foo" activiti:exclusive="true" id="foo" >
<extensionElements>
<activiti:field expression="${listf(host1, host2, host3)}" name="hosts"/>
</extensionElements>
</serviceTask>
This seems to be not supported by default, but JUEL (the unified expression language implementation used by Activiti) provides some methods for adding custom functions.
In the debugger I was able to come up with some code that could evaluate a list expression:
org.activiti.engine.impl.juel.SimpleContext c = new org.activiti.engine.impl.juel.SimpleContext();
c.setFunction("list", "of", Arrays.class.getMethod("asList", Object[].class));
Context.getProcessEngineConfiguration().getExpressionManager()
.expressionFactory
.createValueExpression(c, "${listf(host1, host2)}", Object.class)
.getValue(((ExecutionEntity) activityExecution).cachedElContext)
How can I configure Activiti to use custom functions like this?
07-20-2017 08:07 AM
Since then I managed to make this work by extending the ExpressionManager and overriding a few things. But this is a bit brittle, I afraid a API change will break this. Hopefully there is a better way to do this.
public class ExpressionManagerWithPredefinedFunctions extends ExpressionManager {
private final SimpleContext context = new SimpleContext();
public ExpressionManagerWithPredefinedFunctions() {
try {
context.setFunction("list", "of", Arrays.class.getMethod("asList",Object[].class));
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
@Override
public Expression createExpression(String expression) {
ValueExpression valueExpression = expressionFactory.createValueExpression(context, expression.trim(), Object.class);
return new JuelExpression(valueExpression, expression);
}
}
private ProcessEngine processEngine() {
return new StandaloneProcessEngineConfiguration()
.setExpressionManager(new ExpressionManagerWithPredefinedFunctions())
.setAsyncExecutorEnabled(true)
.setJdbcUrl("jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000")
.setJdbcUsername("sa")
.setJdbcPassword("")
.setJdbcDriver("org.h2.Driver")
.setDatabaseSchemaUpdate(DB_SCHEMA_UPDATE_TRUE)
.buildProcessEngine();
}
07-20-2017 08:07 AM
Since then I managed to make this work by extending the ExpressionManager and overriding a few things. But this is a bit brittle, I afraid a API change will break this. Hopefully there is a better way to do this.
public class ExpressionManagerWithPredefinedFunctions extends ExpressionManager {
private final SimpleContext context = new SimpleContext();
public ExpressionManagerWithPredefinedFunctions() {
try {
context.setFunction("list", "of", Arrays.class.getMethod("asList",Object[].class));
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
@Override
public Expression createExpression(String expression) {
ValueExpression valueExpression = expressionFactory.createValueExpression(context, expression.trim(), Object.class);
return new JuelExpression(valueExpression, expression);
}
}
private ProcessEngine processEngine() {
return new StandaloneProcessEngineConfiguration()
.setExpressionManager(new ExpressionManagerWithPredefinedFunctions())
.setAsyncExecutorEnabled(true)
.setJdbcUrl("jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000")
.setJdbcUsername("sa")
.setJdbcPassword("")
.setJdbcDriver("org.h2.Driver")
.setDatabaseSchemaUpdate(DB_SCHEMA_UPDATE_TRUE)
.buildProcessEngine();
}
Explore our Alfresco products with the links below. Use labels to filter content by product module.