9 Replies Latest reply on Jun 9, 2008 8:43 AM by kukeltje

    replication of task at runtime

    waltertaus

      Hello,

      I want to replicate one task in my process n times. However, the number n is only known at runtime. At the end all n tasks should be synchronized and only when all tasks have been completed further process navigation should take place.

      Ideally it would be:
      1) fork
      2) n times the same task
      3) join

      Furthermore, I must not modify the process definition as for the next instance of this process the number n will be different. I.e. I really want to replicate the tasks only for the current process instance.

      I would be grateful to get your ideas how to solve this scenario.

      Walter

        • 1. Re: replication of task at runtime
          csplrj1

          Does it involves different actors or same actors? I am just asking as I have a same problem. but i require that the task to be associated with different actors

          Thanks in advance

          CSJakharia

          • 2. Re: replication of task at runtime
            kukeltje

            look in the wiki... there is a 'dynamic fork' example

            • 3. Re: replication of task at runtime
              waltertaus

              Hi,
              in my example the same actors are involved.
              I looked in Wiki and found a MultiChoiceForkAH and a ForEachForkAh. Is this what you are referring to as "Dynamic Fork" ?

              Thanks,
              Walter

              • 4. Re: replication of task at runtime
                kukeltje

                yes

                • 5. Re: replication of task at runtime
                  waltertaus

                  Hi,

                  I have now implemented this ForEachForkHandler and it works. However, I have now come up with an extended scenario.
                  In my ForEachForkHandler I create 4 tasks. However, in specific situations I want already to continue when the first two tasks are completed. Therefore, I have tried to implement a kind of housekeeping handler which I call from the join to get rid of the "unnecessary" tasks.

                  My process consists of
                  1) fork
                  2) 4 activities which have been generated by the ForEachForkHandler
                  3) join

                  When entering the join I call setNOutOfM with an appropriate value. Secondly I invoke the handler listed below:

                  ublic class MultiinstanceHouseKeepingHandler implements ActionHandler {
                  
                   @Override
                   public void execute(ExecutionContext ctx) throws Exception {
                   // TODO Auto-generated method stub
                   Token t = ctx.getToken();
                   Collection til = ctx.getTaskMgmtInstance().getTaskInstances();
                   Map childTokenList = t.getParent().getChildren();
                   Set ks = childTokenList.keySet();
                   Iterator it = ks.iterator();
                   while (it.hasNext()) {
                   Token ct = (Token)childTokenList.get(it.next());
                   if (ct == t)
                   continue;
                   Iterator itil = til.iterator();
                   while (itil.hasNext()) {
                   TaskInstance ti = (TaskInstance)itil.next();
                   if (ti.getToken() == ct) {
                   ti.cancel();
                   ct.end();
                   break;
                   }
                   }
                   }
                   }
                  }
                  

                  The process continues correctly with the task following the join. However, I cannot get rid of the other unwanted tasks and they stay forever on my worklist.
                  What am I doing wrong here?

                  Thanks,
                  Walter

                  • 6. Re: replication of task at runtime
                    kukeltje

                    you mean the ti.cancel() and ct.end() do not get called because the 'itil' is is empty or do they get called but do not work?

                    • 7. Re: replication of task at runtime
                      waltertaus

                      Hi,

                      I was not aware that the call to ti.cancel also invokes my MultiinstanceHouseKeepingHandler. ANd in this second (i.e. nested) call to my Handler it blew up and hence did not eliminate anything from my worklist. I am now setting an indication that I am within a nested call so that my handler knows what to do.
                      Thanks,
                      Walter

                      • 8. Re: replication of task at runtime
                        waltertaus

                        Hi,
                        for the sake of completeness, here is now my complete code.

                        public class MultiinstanceLoopForkHandler implements ActionHandler {
                         private String loopMaxValue;
                         private String loopId;
                         private int loopType;
                        
                         @Override
                         public void execute(ExecutionContext ctx) throws Exception {
                         // TODO Auto-generated method stub
                        
                         Token token = ctx.getToken();
                         Fork fork = (Fork)ctx.getNode();
                         int i;
                         try {
                         i = Integer.parseInt(loopMaxValue);
                         }
                         catch (Exception e) {
                         try {
                         if (ctx.getVariable(loopMaxValue) != null)
                         i = (Integer)ctx.getVariable(loopMaxValue);
                         else
                         i = 1;
                         }
                         catch(Exception e1) {
                         e1.printStackTrace();
                         i = 1;
                         }
                         }
                         if (loopType == 1)
                         ctx.setVariable(loopId + "MaxCount", 1);
                         else
                         ctx.setVariable(loopId + "MaxCount", i);
                         Transition leavingTrans = (Transition)fork.getLeavingTransitions().get(0);
                         for (int j = 1; j<i; j++) {
                         String newTokenName = loopId + j;
                         String transitionName = leavingTrans.getName();
                         Token newToken = new Token(token, newTokenName);
                         ctx.getJbpmContext().getSession().save(newToken);
                         fork.leave(new ExecutionContext(newToken), transitionName);
                         }
                         }
                        
                        }
                        


                        public class MultiinstanceLoopJoinHandler implements ActionHandler {
                         private String loopId;
                         @Override
                         public void execute(ExecutionContext ctx) throws Exception {
                         // TODO Auto-generated method stub
                         if (ctx.getVariable(loopId + "Housekeeping") != null)
                         return;
                         ctx.setVariable(loopId + "Housekeeping", 1);
                         Token t = ctx.getToken();
                         Collection til = ctx.getTaskMgmtInstance().getTaskInstances();
                         Map childTokenList = t.getParent().getChildren();
                         Set ks = childTokenList.keySet();
                         Iterator it = ks.iterator();
                         while (it.hasNext()) {
                         Token ct = (Token)childTokenList.get(it.next());
                         if (ct.getName().equals(t.getName()) && ct.getId() == t.getId())
                         continue;
                         if (ct.getName() != null && !ct.getName().startsWith(loopId))
                         continue;
                         Iterator itil = til.iterator();
                         while (itil.hasNext()) {
                         TaskInstance ti = (TaskInstance)itil.next();
                         if (ti.getToken() == ct) {
                         ti.cancel();
                         ct.end();
                         break;
                         }
                         }
                         }
                         }
                        
                        }
                        
                        


                        And here is an example process.
                        <fork name="ForkOne">
                        <event type="node-enter">
                        <action class="com.pi.bpm.workflow.jbpm.MultiinstanceLoopForkHandler">
                        <loopMaxValue>3</loopMaxValue>
                        <loopId>MultinstanceOne</loopId>
                        <loopType>1</loopType>
                        </action>
                        </event>
                        <transition name="MultinstanceOne" to="MultinstanceOne"></transition>
                        </fork>
                        <task-node name="MultinstanceOne">
                        <transition name="ToJoinOne" to="JoinOne"></transition>
                        <task name="MultinstanceOne"></task>
                        </task-node>
                        <join name="JoinOne">
                        <event type="node-enter">
                        <script><expression>
                        if (executionContext.getVariable("MultinstanceOneMaxCount") > 1) executionContext.getNode().setNOutOfM(executionContext.getVariable("MultinstanceOneMaxCount"));
                        else executionContext.getNode().setDiscriminator(true);
                        </expression></script>
                        <action class="com.pi.bpm.workflow.jbpm.MultiinstanceLoopJoinHandler">
                        <loopId>MultinstanceOne</loopId>
                        </action>
                        </event>
                        <transition name="To_cF5fADE6Ed2C6L5mprqn1w" to="../UserTask5/UserTask5">
                        </transition>
                        </join>
                        </super-state>
                        


                        BTW with this sequence I can handle the BPMN constructs of Multiinstance Loop All and Multiinstance Loop One.

                        ANy suggestions and improvements are highly welcome.

                        Walter


                        • 9. Re: replication of task at runtime
                          kukeltje

                          nice, congratulations... on a sidenote, could you make a wiki page for this. I'm sure others are interested.