5 Replies Latest reply on Sep 12, 2008 10:43 AM by Ronald van Kuijk

    forking tasks

    Gergely Nagy Newbie


      We have a workflow with a fork, and need to track tasks in each branch. A simplified use case follows:

      / \
      Task11 Task21
      | |
      Task12 |
      \ /

      We have a seam ui that uses PooledTaskInstanceList. We use swim lanes too, however the fork is within a single swim lane, so i guess it should not matter.

      So we have a page with the pooled task instances. Initially Task0 should be displayed. When the user completes it, 2 tasks should appear: Task11, Task21. Then, if the user completes e.g. Task11, then the following should appear: Task 12, Task21. Etc. The join should continue only if both branches are done.

      However, currently only 1 task is shown from either branch, seemingly randomly, e.g. after Task0 the user has only the option to complete Task11, then Task12, then Task21, the end.

      I read thought the docs and this forum, and the thing people seem to get hung upon is to perform things concurrently. But we don't really need that, just that the forked tasks appear multiple times in the pooled instance list (or some other list??), so the user can choose what to do next. I tried putting async=true on the fork to no avail.

      Any suggestions?


        • 1. Re: forking tasks
          Ronald van Kuijk Master

          hmmm... it should work as expected. No reason why task11 and task21 should not be visible at the same time. What could be the case is that you run into 'caching'. Meaning that the tasklist is loaded when the transition to one task is taken from the fork but not the otherone yet. Refreshing this could clear things up. But if this is the case then I'd expect the first task after the first transition from the fork to be always visible, not randomly one or the other (unless it is non-determenistic which transition is taken first.

          Async=true should not be needed here.

          I'll try to make a unittest without seam to see if I can reproduce. Or if you already have one that would be great. btw, how are transactions configured?

          • 2. Re: forking tasks
            Ronald van Kuijk Master

            wait... task21 is not even visible when task11 is already performed? that is reaaal strange...???

            • 3. Re: forking tasks
              Ronald van Kuijk Master

              Ok, basic trial without Seam and no special transaction stuff works

              package net.vankuijk.jbpm;
              import java.util.ArrayList;
              import java.util.Arrays;
              import java.util.HashSet;
              import java.util.Iterator;
              import java.util.List;
              import java.util.Set;
              import org.apache.commons.logging.Log;
              import org.apache.commons.logging.LogFactory;
              import org.jbpm.JbpmContext;
              import org.jbpm.db.AbstractDbTestCase;
              import org.jbpm.graph.def.ProcessDefinition;
              import org.jbpm.graph.exe.ExecutionContext;
              import org.jbpm.graph.exe.ProcessInstance;
              import org.jbpm.taskmgmt.def.AssignmentHandler;
              import org.jbpm.taskmgmt.exe.Assignable;
              import org.jbpm.taskmgmt.exe.TaskAssignmentDbTest;
              import org.jbpm.taskmgmt.exe.TaskInstance;
              import org.jbpm.taskmgmt.exe.TaskMgmtInstance;
              import junit.framework.TestCase;
              public class ForkedTaskTest extends AbstractDbTestCase {
               void deployProcessDefinition(String xml) {
               ProcessDefinition processDefinition = ProcessDefinition
               public void testStartStateSwimlaneInitialization() {
               deployProcessDefinition("<process-definition name='testForkedTasks'>"
               + " <swimlane name='gertsGroupSwimlane'>"
               + " <assignment pooled-actors='gertsGroup' />"
               + " </swimlane>"
               + " <start-state>"
               + " <transition name='to_0' to='0' />"
               + " </start-state>"
               + " <task-node name='0'>"
               + " <task name='task 0' swimlane='gertsGroupSwimlane' />"
               + " <transition name='to_fork1' to='fork1' />"
               + " </task-node>"
               + " <fork name='fork1'>"
               + " <transition name='to_11' to='11' />"
               + " <transition name='to_21' to='21' />"
               + " </fork>"
               + " <task-node name='11'>"
               + " <task name='task 11' swimlane='gertsGroupSwimlane' />"
               + " <transition name='to_12' to='12' />"
               + " </task-node>"
               + " <task-node name='12'>"
               + " <task name='task 12' swimlane='gertsGroupSwimlane' />"
               + " <transition name='to_join' to='join1' />"
               + " </task-node>"
               + " <task-node name='21'>"
               + " <task name='task 21' swimlane='gertsGroupSwimlane' />"
               + " <transition name='to_join' to='join1' />"
               + " </task-node>"
               + " <join name='join1'>"
               + " <transition name='end' to='end' />"
               + " </join>"
               + " <end-state name='end' />"
               + "</process-definition>");
               ProcessInstance processInstance = jbpmContext.newProcessInstanceForUpdate("testForkedTasks");
               processInstance = saveAndReload(processInstance);
               ArrayList actorIDs = new ArrayList();
               List tasks = jbpmContext.getGroupTaskList(actorIDs);
               assertEquals(1, tasks.size());
               assertEquals(false, ((TaskInstance) tasks.get(0)).isStartTaskInstance());
               TaskInstance task0 = (TaskInstance) tasks.iterator().next();
               assertEquals("task 0", task0.getName());
               processInstance = saveAndReload(processInstance);
               tasks = jbpmContext.getGroupTaskList(actorIDs);
               assertEquals(2, tasks.size());
               ArrayList taskNames = new ArrayList();
               taskNames.add(((TaskInstance) tasks.get(0)).getName());
               taskNames.add(((TaskInstance) tasks.get(1)).getName());
               assertTrue(taskNames.contains("task 11"));
               assertTrue(taskNames.contains("task 21"));
               assertFalse(taskNames.contains("task 12"));
               TaskInstance task11 = (TaskInstance) tasks.get(0); //gamble it is the first
               if (!task11.getName().equals("task 11")) {
               task11 = (TaskInstance) tasks.get(1); // ok, it's the second
               processInstance = saveAndReload(processInstance);
               tasks = jbpmContext.getGroupTaskList(actorIDs);
               assertEquals(2, tasks.size());
               taskNames = new ArrayList();
               taskNames.add(((TaskInstance) tasks.get(0)).getName());
               taskNames.add(((TaskInstance) tasks.get(1)).getName());
               assertFalse(taskNames.contains("task 11")); //ended
               assertTrue(taskNames.contains("task 21"));
               assertTrue(taskNames.contains("task 12"));
               private static final Log log = LogFactory

              So it I have no clue what is going wrong in your case. Transactions? What if you try to retrieve the tasklist by using the jBPM api directly?

              • 4. Re: forking tasks
                Gergely Nagy Newbie

                Hi Ronald,

                Thanks a lot for your help! I don't really know what caused the problem, but now everything works correctly. The test case you wrote was very useful, I could adapt it to set up unit tests for our work flow, and I just kept tweaking the process definition and code until things worked.


                • 5. Re: forking tasks
                  Ronald van Kuijk Master

                  That's what TTD is for :-)