5 Replies Latest reply on Dec 28, 2005 9:11 PM by enazareno

    how to design multiple sub-processes

    enazareno

      Hello to all,

      How do we best handle multiple sub-processes? For example, a recruitment process starts with the submission of a job order or a request. At the state when it is ready (i.e. approved) for accepting candidates, I would want to create a sub-process each for managing each candidate (from interview-accept or fail, etc). The job order can proceed when it has been fulfilled (right number of candidates accepted) or it can be forced to close and signal all pending sub processes to abort themselves firing the necessary events.

      Since the most logical approach is to do this programatically and triggered by a user, do we still need to declare this as a subprocess in the definition or should it be designed as a fork instead or as task-nodes? Is there a way to control from the process definition that the candidate-process can only be created or started if I am on the approved state?

      I have a few ideas on how to do this, but I would really appreciate it if somebody could share some of their design expertise on how best to do this. I would be happy to discuss this. Thanks a lot.

      Regards,

      Elmo

        • 1. Re: how to design multiple sub-processes
          brittm

          Sounds like a subprocess is exactly what you need. Your user interface related to a particular state/task could provide a button, and each time the user clicks it, a new "candidate" sub process is started. When ending the parent process, you would likely have to provide code that would terminate each sub process according to your needs, and then terminate the parent.

          Is there a way to control from the process definition that the candidate-process can only be created or started if I am on the approved state?
          I"m pretty sure that the answer to this is 'no'. You will have to construct your UI in such a way that the option is only available when you intend it to be.

          -Britt

          • 2. Re: how to design multiple sub-processes
            enazareno

            Hi Britt,

            Thanks for your reply. It seems the 3.01 version has no support yet for tracking multiple sub processes. The subprocess only works for 1, but not many. I tried to look at some facilties in the code but the super process in the sub process instance refers only to one parent. I also tried looking at the module instances, but it seems I don't know how to use it. Please check my code below, there are some i did a somebit of a hack, not pretty though but it seems to work.

            <process-definition name="hire-process">
            
             <start-state name="start-hire">
             <transition to="hire-state"/>
             </start-state>
            
             <state name="hire-state">
             <transition name="dummy" to="hire-state"/>
             <transition name="close" to="stop-hiring"/>
             <transition name="add-candidate" to="add-candidates"/>
             </state>
            
             <node name="add-candidates">
             <event type="node-enter">
             <action name="create-candidate-process" class="org.jbpm.CreateSubProcess">
             <subprocessname>candidate-process</subprocessname>
             </action>
             </event>
             <transition to="hire-state"/>
             </node>
            
             <process-state name="candidate-process">
             <sub-process name="candidate-process"/>
             </process-state>
            
             <node name="stop-hiring">
             <event type="node-enter">
             <action name="kill-subprocess" class="org.jbpm.SubProcessKiller" />
             </event>
             <transition to="end-process"/>
             </node>
            
             <end-state name="end-process"/>
            
            </process-definition>


            The purpose of the dummy transition is to avoid accidental signalling of this state. I need to specify the transition in this state whether close or add another candidate. So I just get a process, add an "add-candidate" transition and off it goes creating the sub process.

            I cant use the normal subprocess definition bec. it only continues when i have finished the process. so I did a little bit of hack here, i dont think this is the recommended way to use a subprocess.

            public class CreateSubProcess implements ActionHandler {
            
             String subprocessname;
            
             public void execute(ExecutionContext executionContext) throws Exception {
             ProcessState node = (ProcessState)executionContext.getProcessDefinition().findNode( subprocessname );
             if( node == null )
             throw new Exception(subprocessname + " does not exist! ");
             ProcessInstance subProcess = node.getSubProcessDefinition().createProcessInstance();
             ModuleInstance module = new ModuleInstance();
             module.setProcessInstance( subProcess );
             executionContext.getProcessInstance().addInstance( module );
             subProcess.signal();
             System.out.println("EXITING THE PROCESS NOW...");
             }
            
            }


            Tried to use the module instance. But it seems it does not work as I thought it would, maybe I'm not using it correctly. In the code below the process instance in the module referred to the parent process instance not the sub process.

            public class SubProcessKiller implements ActionHandler {
            
             public void execute(ExecutionContext executionContext) throws Exception {
             System.out.println( "START THE STOPPING PROCESS...");
             int i = 0;
             Map m = executionContext.getProcessInstance().getInstances();
             Iterator iter = m.values().iterator();
             while( iter.hasNext() ) {
             System.out.println( "looping token->");
             ModuleInstance mod = (ModuleInstance)iter.next();
             ProcessInstance sb = mod.getProcessInstance();
             sb.end();
             System.out.println( "proc name " + sb.getProcessDefinition().getName() );
             System.out.println( "proc id is " + sb.getId() );
             System.out.println("has ended? " + sb.hasEnded() );
             System.out.println(sb.getRootToken().getNode().getName());
             i++;
             }
             ProcessInstance p;
            
             System.out.println( "SUBPROCESSES CLEANED UP. NO. OF PROCESS CLOSED " + i );
             }
            
            }
            


            Anyway, everything seemed to work EXCEPT for the module instance. How do I track sub processes wihtout going to extraordinary means? Any suggestions? Thanks again.

            Regards,

            Elmo

            • 3. Re: how to design multiple sub-processes
              enazareno

              sorry, not 3.01 but I meant 3.1 version

              Regards,

              Elmo

              • 4. Re: how to design multiple sub-processes
                brittm

                Hmm...perhaps you can simply not use sub processes at all. Rather that think of the 'candidate' process as a sub process, just consider it as a stand-alone process. Start as many as necessary like you are now, with an ActionHandler, and set a process variable to link it back to your 'parent' process--perhaps a variable called "parentProcessInstanceId". You would have to write a Hibernate query to return all 'candidate' processes with a given parentProcessInstanceId process variable, and then you could iterate through them, canceling (and ending) each one as appropriate.

                The nice thing about jBPM is that its so open that there always seems to be a way to solve a problem. :)

                -Britt

                • 5. Re: how to design multiple sub-processes
                  enazareno

                  Hi Britt,


                  Hmm...perhaps you can simply not use sub processes at all


                  I seem to like your first suggestion that each candidate should be a subprocess. Anyway, I was thinking long about it last night and I thought the key for it to work was to make child tokens to bind to the subprocess or probably create task instances to bind the subprocess.

                  I looked up the posts regarding how to create child tokens but it seems the wiki custom fork was already very outdated. I also checked the manual on leaving transitions (decision) also it was outdated. Last resort was to dig up the code and do trial and error. I seem to come up with a better solution. The new solution has much natural design bec. it has the proper connections and transitions unlike the first. Workarounds are very hard to remember but quite easy to forget. ;)

                  Here is my new process defintion. The fork-join is quite important so that the sub processes will know where they will meet when they end.

                  <process-definition name="hire-process">
                  
                   <start-state name="start-hire">
                   <transition to="fork"/>
                   </start-state>
                  
                   <fork name="fork">
                   <transition to="approved-state"/>
                   </fork>
                  
                   <state name="approved-state">
                   <transition name="default" to="approved-state"/>
                   <transition name="close" to="stop-hiring"/>
                   <transition name="add-candidate" to="approved-state">
                   <action name="create-child-token" class="org.jbpm.CreateNewToken">
                   <leavename>candidate-process</leavename>
                   </action>
                   </transition>
                   <transition name="candidate-process" to="candidate-process"/>
                   </state>
                  
                   <process-state name="candidate-process">
                   <event type="subprocess-created">
                   <script>print( "ENTERING SUBPROCESS ... TOKEN: " + token.getName() );</script>
                   </event>
                   <event type="subprocess-end">
                   <script>print( "ENDING SUBPROCESS ... TOKEN: " + token.getName() );</script>
                   </event>
                   <sub-process name="candidate-process"/>
                   <transition to="join"/>
                   </process-state>
                  
                   <node name="stop-hiring">
                   <event type="node-enter">
                   <action name="kill-subprocess" class="org.jbpm.SubProcessKiller" />
                   </event>
                   <transition to="join"/>
                   </node>
                  
                   <join name="join">
                   <transition to="end-process"/>
                   </join>
                  
                   <end-state name="end-process"/>
                  
                  </process-definition>


                  Here are the custom actions. I don't know if I've done this correctly.

                  public class CreateNewToken implements ActionHandler {
                  
                   String leavename;
                  
                   public void execute(ExecutionContext executionContext) throws Exception {
                   Token childToken = new Token( executionContext.getToken(), "TK" + (new UID()) );
                   ExecutionContext newctx = new ExecutionContext(childToken);
                   executionContext.getTransitionSource().leave(newctx, leavename );
                   }
                  
                  }
                  


                  In order for it to work, you must provide a token name. I found about it the hard way. I think we can use the id here of the candidate, the name must be unique.

                  Here is the sub process clean up.

                  public class SubProcessKiller implements ActionHandler {
                  
                   public void execute(ExecutionContext executionContext) throws Exception {
                   System.out.println( "START THE STOPPING PROCESS...");
                   int i = 0;
                   Map m = executionContext.getProcessInstance().getRootToken().getActiveChildren();
                   System.out.println( "NO. OF ACTIVE CHILDREN " + m.size() );
                   Iterator iter = m.values().iterator();
                   while( iter.hasNext() ) {
                   Token t = (Token)iter.next();
                   System.out.println( "end token name " + t.getName() );
                   if( t.getSubProcessInstance()!=null) {
                   System.out.println( "ending subprocess");
                   t.getSubProcessInstance().end();
                   i++;
                   }
                   }
                   System.out.println( "SUBPROCESSES CLEANED UP. NO. OF SUBPROCESS CLOSED " + i );
                   }
                  
                  }
                  


                  Anyway all seems to work this time and my design requirements are satisfied. I seem to prefer declarative programming as much as possible. Its self-documenting and we do not have to dig up code to remember things.

                  If you or anybody has a much better design regarding handling of multiple subprocesses, I'd very much like to hear it. Thanks a lot for your help and have a happy new year. :)

                  Regards,

                  Elmo