Jbpm woes
cbensemann Aug 14, 2010 11:37 PMHi All,
Have been using seam 2.2.1.CR2 + jbpm-jpdl 3.2.6.SP1. I have defined a business process whereby a user can create tasks
and assign them to other users. To achieve this I have used the ForEachForkActionHandler which is described on the jbpm site. At first glance this appears to do what I want (i.e. if you create two tasks on the screen then two jbpm tasks are created and once those are completed the whole business process joins and continues on to the next step). What happens however is that both tasks get initialized with the same variables (should become clearer once I post code below). That is to say that both tasks end up being assigned to the same user with the same descriptions etc.
"Executive Summary"
For those that might get lost in my code/comments below. Simply put when two different tasks are created inside the ForEachForkActionHandler and then transitioned to the next step in the business proccess each task gets assigned to the same one user and given the same description when I would expect that each one be assigned to different users (if the tasked were created for different people) and have their own descriptions.
Lots of words and details below.
the relevant part of my business process
<node name="corrective_actions"> <action class="nz.co.softwarefactory.esafensound.util.ForEachForkActionHandler" config-type="bean"> <listVariable>correctiveActions</listVariable> <as>action</as> </action> <transition to="complete_corrective_action" /> </node> <task-node name="complete_corrective_action" > <task notify="true" duedate="1 business week" description="#{action.summary}" > <assignment actor-id="#{action.owner.email}" /> </task> <transition to="corrective_actions_join" /> </task-node> <join name="corrective_actions_join"> <transition to="signoff" /> </join>
the ForEachForkActionHandler
public class ForEachForkActionHandler implements ActionHandler { protected List<?> list; protected String as; private String listVariable; protected static final String FOREACH_PREFIX = "foreach."; /** * Create a new child token for each item in list. * * @param executionContext * @throws Exception */ public void execute(final ExecutionContext executionContext) throws Exception { initializeList(executionContext); final Token rootToken = executionContext.getToken(); final Node node = executionContext.getNode(); final List<Object[]> argSets = new LinkedList<Object[]>(); // // First, create a new token and execution context for each item in // list. // for (int i = 0; i < node.getLeavingTransitions().size(); i++) { final Transition transition = (Transition) node.getLeavingTransitions().get(i); for (int j = 0; list != null && j < list.size(); j++) { final Object item = list.get(j); final Token newToken = new Token(rootToken, ForEachForkActionHandler.FOREACH_PREFIX + node.getId() + "." + j); newToken.setTerminationImplicit(true); executionContext.getJbpmContext().getSession().save(newToken); final ExecutionContext newExecutionContext = new ExecutionContext(newToken); newExecutionContext.getContextInstance().createVariable(as, item, newToken); argSets.add(new Object[] { newExecutionContext, transition }); } } // // Now, let each new token leave the node. // for (int i = 0; i < argSets.size(); i++) { final Object[] args = argSets.get(i); node.leave((ExecutionContext) args[0], (Transition) args[1]); } } public List<?> getList() { return list; } public void setList(final List<?> list) { this.list = list; } public String getAs() { return as; } public void setAs(final String as) { this.as = as; } public String getListVariable() { return listVariable; } public void setListVariable(final String listVariable) { this.listVariable = listVariable; } protected void initializeList(final ExecutionContext executionContext) { if (list == null && listVariable != null) { list = (List<?>) executionContext.getContextInstance().getVariable(listVariable); } } }
My understanding of the ForEachForkActionHandler is that the variables in list will be iterated over and for each one a new task is created and the then a locally scoped variable created to store the item. Then when the node is transistioned to the next state the actor should be assigned to #{action.owner.email} and the description to #{action.summary} and both of these variables should come from the varaibles scoped to that task instance
I have spent quite a bit of time trying to understand how all of this works and debugging through the code and you can see that two tasks are created and two copies of action
are persisted in the jbpm database and both have different values. I could be on the wrong track as I did get a little confused but think the problem comes when the SeamExpressionEvaluator tries to evaluate the expressions. It always returns one value. At this point I stopped debugging as I have spent far too much time on this and hope someone else can shed some light on the problem.