1 2 Previous Next 20 Replies Latest reply on Feb 25, 2008 12:20 PM by pojomonkey

    Token.signal() ---> 2 tokens?

    qpool.char

      Hello, could you please give me a short answer to this understanding problem?

      The example situation:

      TaskNode A ------> Fork

      Fork ------> TaskNode B
      Fork ------> TaskNode C

      Lets assume, i have a token in TaskNode A. Now i call token.signal().
      The token moves to Fork. Now again token.signal().

      Do i result in 2 tokens, one for TaskNode B, one for TaskNode C?
      Or do i only have one token for both TaskNodes?

      I have this situation in my code, and dont know how to get all active TaskInstances after leaving a fork....

      thx in advance

        • 1. Re: Token.signal() ---> 2 tokens?
          qpool.char

          I mean, i move my token to the fork.

          Then again token.signal()

          Then i check with

          Collection c = jbpmContext.getTaskMgmtSession().findTaskInstancesByToken(token.getId());
          log.info("************ Number of TaskInstances for Token: " + c.size());
          


          the number of available TaskInstances for this token, and the number is 1.

          But i m expecting 2.....

          thx in advance

          • 2. Re: Token.signal() ---> 2 tokens?
            kukeltje

            Don't 'expect', be sure. So probably there is more than one token. Look at the unit tests in cvs to see how the internals of jbpm work for forks. Unit tests are so great...

            • 3. Re: Token.signal() ---> 2 tokens?
              kukeltje

              I should not have kept you in the dark.... there are 2 tokens...

              • 4. Re: Token.signal() ---> 2 tokens?
                qpool.char

                thx :)

                • 5. Re: Token.signal() ---> 2 tokens?

                  In a similar scenario, I find that following the fork, two new tokens proceed along each of the (2) transitions leaving the fork to their respective nodes - however, the 'root' token then 'follows' one of the other tokens and also enters the same node, and generates a node-enter event.

                  Generally, I could track the progress of the root token to see the progress along the execution path - but following the fork, it then looks like there are 2 executions of the path.

                  I can't figure how I can determine which token is the 'active' one on an execution path, and which one is isn't. (Because I would not expect both tokens on that same execution path to be 'active'.)

                  • 6. Re: Token.signal() ---> 2 tokens?
                    kukeltje

                    please make a unit test so we can see the problem and what you specifically do.

                    • 7. Re: Token.signal() ---> 2 tokens?

                      Process definition:

                      <?xml version="1.0" encoding="UTF-8"?>
                      
                      <process-definition xmlns="" name="ForkTest">
                      
                       <start-state name="startstate">
                       <task name="NewProcess">
                       <controller>
                       <variable access="read,write,required" name="choice"></variable>
                       </controller>
                       </task>
                       <transition to="decisonnode" name="ok"></transition>
                       </start-state>
                      
                      
                       <decision name="decisonnode">
                       <transition to="optiona" name="choose a">
                       <condition>#{choice == "OptionA"}</condition>
                       </transition>
                       <transition to="optionb" name="choose b">
                       <condition>#{choice == "OptionB"}</condition>
                       </transition>
                       </decision>
                      
                       <fork name="fork1">
                       <transition to="track" name="t10"></transition>
                       <transition to="proceed" name="t20"></transition>
                       </fork>
                      
                       <fork name="fork2" async="true">
                       <transition to="monitor" name="t1"></transition>
                       <transition to="step1" name="t2"></transition>
                       </fork>
                      
                       <join name="join1">
                       <transition to="join2"></transition>
                       </join>
                      
                       <join name="join2">
                       <transition to="complete"></transition>
                       </join>
                      
                       <state name="optiona">
                       <transition to="nextstate" name="ok"></transition>
                       </state>
                      
                       <state name="nextstate">
                       <transition to="fork1" name="ok"></transition>
                       </state>
                      
                       <state name="optionb">
                       <transition to="nextstate" name="ok"></transition>
                       </state>
                      
                       <state name="proceed" async="true">
                       <transition to="fork2" name="ok"></transition>
                       </state>
                      
                       <state name="track" async="true">
                       <transition to="join2" name="ok"></transition>
                       </state>
                      
                       <state name="monitor" async="true">
                       <transition to="join1" name="ok"></transition>
                       </state>
                      
                       <state name="step1" async="true">
                       <transition to="step2" name="ok"></transition>
                       </state>
                      
                       <state name="step2" async="true">
                       <transition to="step3" name="ok"></transition>
                       </state>
                      
                       <state name="complete">
                       <transition to="end" name="ok"></transition>
                       </state>
                      
                       <state async="true" name="step3">
                       <transition to="join1" name="ok"></transition>
                       </state>
                      
                      
                       <end-state name="end"></end-state>
                      
                      
                       <action name="EnterNode" class="taskmanager.EnterStateHandler"></action>
                      
                       <action name="LeaveNode" class="taskmanager.ExitStateHandler"></action>
                      
                      
                       <event type="node-enter">
                       <action class="taskmanager.EnterStateHandler" ref-name="EnterNode"></action>
                       </event>
                      
                       <event type="node-leave">
                       <action ref-name="LeaveNode"></action>
                       </event>
                      
                      
                      </process-definition>


                      Unit test:
                      package forktest;
                      
                      import java.util.Map;
                      
                      import junit.framework.TestCase;
                      
                      import org.jbpm.JbpmConfiguration;
                      import org.jbpm.JbpmContext;
                      import org.jbpm.context.exe.ContextInstance;
                      import org.jbpm.graph.def.Node;
                      import org.jbpm.graph.def.ProcessDefinition;
                      import org.jbpm.graph.exe.ProcessInstance;
                      import org.jbpm.graph.exe.Token;
                      import org.jbpm.persistence.db.DbPersistenceServiceFactory;
                      import org.jbpm.svc.Services;
                      import org.jbpm.taskmgmt.exe.TaskInstance;
                      
                      public class ForkUnitTest extends TestCase
                      {
                       /**
                       * Some helpers
                       */
                       JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
                       DbPersistenceServiceFactory dbPersistenceServiceFactory = (DbPersistenceServiceFactory) jbpmConfiguration.getServiceFactory(Services.SERVICENAME_PERSISTENCE);
                      
                       JbpmContext jbpmContext;
                      
                       private ProcessInstance processInstance;
                      
                       private long processInstanceId;
                       private ContextInstance contextInstance;
                      // private TaskMgmtInstance taskMgmtInstance;
                      
                       public ForkUnitTest()
                       {
                       }
                      
                       /**
                       * Set up the basic in-memory DB, deploy the process description and
                       * set up a jBPM context.
                       * @see jBPM docs wrt jbpm configuration file
                       */
                       protected void setUp() throws Exception
                       {
                       super.setUp();
                       dbPersistenceServiceFactory.createSchema();
                       deployProcess();
                       jbpmConfiguration.startJobExecutor();
                       jbpmContext = jbpmConfiguration.createJbpmContext();
                       }
                      
                       /**
                       * Tidy up.
                       */
                       protected void tearDown() throws Exception
                       {
                       super.tearDown();
                       jbpmContext.close();
                       dbPersistenceServiceFactory.dropSchema();
                       jbpmContext = null;
                       }
                      
                       /**
                       *
                       */
                       public void newTransaction()
                       {
                       jbpmContext.close();
                       jbpmContext = jbpmConfiguration.createJbpmContext();
                       processInstance = jbpmContext.loadProcessInstanceForUpdate(processInstanceId);
                      // processInstanceId = processInstance.getId();
                       }
                      
                       /**
                       * Get the process description file, parse it and deploy the
                       * process definition.
                       */
                       private void deployProcess()
                       {
                       JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
                       try
                       {
                       ProcessDefinition processDefinition =
                       ProcessDefinition.parseXmlResource("ForkProcess/processdefinition.xml");
                       jbpmContext.deployProcessDefinition(processDefinition);
                       } finally
                       {
                       jbpmContext.close();
                       }
                       }
                      
                       /**
                       * Each subsequent test will need a new process instance
                       * @return a TaskInstance, or null if there is no start task defined.
                       */
                       private TaskInstance createNewProcessInstance()
                       {
                       processInstance = jbpmContext.newProcessInstanceForUpdate("ForkTest");
                       processInstanceId = processInstance.getId();
                       contextInstance = processInstance.getContextInstance();
                      // taskMgmtInstance = processInstance.getTaskMgmtInstance();
                       return processInstance.getTaskMgmtInstance().createStartTaskInstance();
                       }
                      
                       public void testFork()
                       {
                       TaskInstance taskInstance = createNewProcessInstance();
                       contextInstance.setVariable("choice", "OptionB");
                       assertEquals("startstate", processInstance.getRootToken().getNode().getName());
                       processInstance.signal();
                       jbpmContext.save(processInstance);
                      
                       newTransaction();
                      
                       assertEquals("optionb", processInstance.getRootToken().getNode().getName());
                       processInstance.signal("ok");
                       jbpmContext.save(processInstance);
                      
                       newTransaction();
                      
                       assertEquals("nextstate", processInstance.getRootToken().getNode().getName());
                       processInstance.signal("ok");
                       jbpmContext.save(processInstance);
                      
                       newTransaction();
                      
                       Token root = processInstance.getRootToken();
                       root.signal();
                       Map map = root.getChildren();
                       assertEquals(2, map.size());
                      
                       Token tk_t10 = (Token) map.get("t10");
                       assertEquals("t10", tk_t10.getName());
                      
                       ProcessInstance pi = tk_t10.getProcessInstance();
                       assertEquals(processInstanceId, pi.getId());
                       Node node = tk_t10.getNode();
                       assertEquals("track", node.getName());
                       tk_t10.signal("ok");
                       jbpmContext.save(processInstance);
                      
                       newTransaction();
                      
                       root = processInstance.getRootToken();
                       map = root.getChildren();
                       assertEquals(2, map.size());
                      
                       tk_t10 = (Token) map.get("t10");
                       assertEquals("t10", tk_t10.getName());
                      
                       Token tk_t20 = (Token) map.get("t20");
                       assertEquals("t20", tk_t20.getName());
                      
                       pi = tk_t20.getProcessInstance();
                       assertEquals(processInstanceId, pi.getId());
                       node = tk_t20.getNode();
                       assertEquals("proceed", node.getName());
                      
                       tk_t20.signal();
                       assertEquals("fork2", processInstance.getRootToken().getNode().getName());
                       }
                      
                      }
                      


                      And the two handlers:
                      /**
                       *
                       */
                      package forktest;
                      
                      import org.jbpm.graph.def.ActionHandler;
                      import org.jbpm.graph.def.Node;
                      import org.jbpm.graph.exe.ExecutionContext;
                      import org.jbpm.graph.exe.Token;
                      import org.jbpm.graph.node.State;
                      
                      /**
                       * @author pauls
                       *
                       */
                      public class EnterStateHandler implements ActionHandler
                      {
                      
                       /**
                       *
                       */
                       private static final long serialVersionUID = 7209848070013962714L;
                      
                       /* (non-Javadoc)
                       * @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
                       */
                       public void execute(ExecutionContext executionContext) throws Exception
                       {
                       Node node = executionContext.getNode();
                       Token token = executionContext.getToken();
                       String tok_name = (token.getName() == null ? "root" : token.getName());
                      
                       if (token.isLocked())
                       {
                       System.out.println("Token: " + tok_name + " is locked");
                       }
                      
                       if (token.isSuspended())
                       {
                       System.out.println("Token: " + tok_name + " is suspended");
                       }
                      
                       if (node instanceof State)
                       {
                       System.out.println("Token: " + tok_name + " entering node: " + node.getName());
                       }
                       else
                       {
                       System.out.println("Node is: " + node.getName());
                       }
                       }
                      
                      }
                      
                      
                      /**
                       *
                       */
                      package forktest;
                      
                      import org.jbpm.graph.def.ActionHandler;
                      import org.jbpm.graph.def.Node;
                      import org.jbpm.graph.exe.ExecutionContext;
                      import org.jbpm.graph.exe.Token;
                      import org.jbpm.graph.node.State;
                      
                      /**
                       * @author pauls
                       *
                       */
                      public class ExitStateHandler implements ActionHandler
                      {
                      
                       /**
                       *
                       */
                       private static final long serialVersionUID = 7209848070013962714L;
                      
                       /* (non-Javadoc)
                       * @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)
                       */
                       public void execute(ExecutionContext executionContext) throws Exception
                       {
                       Node node = executionContext.getNode();
                       Token token = executionContext.getToken();
                       String tok_name = (token.getName() == null ? "root" : token.getName());
                      
                       if (node instanceof State)
                       {
                       System.out.println("Token: " + tok_name + " leaving node: " + node.getName());
                       }
                       else
                       {
                       System.out.println("Node was: " + node.getName());
                       }
                       }
                      
                      }
                      
                      [/CODE]
                      
                      And on the console the output from the handlers:
                      Node was: startstate
                      Token: root is locked
                      Node is: decisonnode
                      Node was: decisonnode
                      Token: root is locked
                      Token: root entering node: optionb
                      Token: root leaving node: optionb
                      Token: root is locked
                      Token: root entering node: nextstate
                      Token: root leaving node: nextstate
                      Token: root is locked
                      Node is: fork1
                      Node was: fork1
                      Token: t10 is locked
                      Token: t10 entering node: track
                      Node was: fork1
                      Token: t20 is locked
                      Token: t20 entering node: proceed
                      Node was: fork1
                      Token: root is locked
                      Token: root entering node: track
                      
                      


                      And it's that last line that's bugging me.

                      • 8. Re: Token.signal() ---> 2 tokens?
                        • 9. Re: Token.signal() ---> 2 tokens?

                          Correction. In the process defintion the actions should be defined as follows:

                          <action name="EnterNode" class="forktest.EnterStateHandler"></action>
                          
                          <action name="LeaveNode" class="forktest.ExitStateHandler"></action>


                          • 10. Re: Token.signal() ---> 2 tokens?
                            kukeltje

                            I do not see strange things in here. The only thing that surprises me is that token.getName() is null for the root token....

                            What version of jBPM are you using? I'll try to reproduce tonight... btw

                            • 11. Re: Token.signal() ---> 2 tokens?

                               

                              "kukeltje" wrote:
                              I do not see strange things in here.
                              There may be nothing 'strange', but I wasn't expecting multiple tokens to pass through any node.

                              I'm looking to use 'client base assignment' (see http://www.jboss.com/products/jbpm/docs/jpdl) and use jBPM as the execution engine. Since I then want to hang actions off the node-enter/leave events, I need to know which token is the 'active' execution path.

                              In the example supplied, the root token that 'follows' the 't10' token is - in effect - creating a second execution path through the same node, unless there is some way to distinguish when the root token is the active token on the execution path and when it is not. (I am assuming that following the 'fork' that the root token - being the parent of the other 2 - is no longer the 'active' token'?)

                              "kukeltje" wrote:
                              The only thing that surprises me is that token.getName() is null for the root token....

                              Yeah, that threw me too.

                              "kukeltje" wrote:
                              What version of jBPM are you using? I'll try to reproduce tonight... btw

                              I downloaded jbpm-jpdl-suite-3.2.2.zip

                              • 12. Re: Token.signal() ---> 2 tokens?
                                mputz

                                IMO, you shouldn't signal the root token once it has arrived in the fork:

                                 Token root = processInstance.getRootToken();
                                 // root token is already on the fork, signal children instead
                                 // root.signal();
                                


                                I've found a (rejected) feature request to prevent the root token from being signaled on a fork node: http://jira.jboss.com/jira/browse/JBPM-642

                                • 13. Re: Token.signal() ---> 2 tokens?

                                   

                                  "mputz" wrote:
                                  IMO, you shouldn't signal the root token once it has arrived in the fork:

                                   Token root = processInstance.getRootToken();
                                   // root token is already on the fork, signal children instead
                                   // root.signal();
                                  

                                  OK, but how should the root token progress to the matching join? And what about the example I've given where on of the execuation paths forks again?

                                  What is the logic to determine when I can signal which tokens? In my test - see below - from fork1, I would expect to be signalling token t20 - but when that arrives at fork2, should I cease signalling t20? Then how is it to join finally?

                                  "mputz" wrote:
                                  I've found a (rejected) feature request to prevent the root token from being signaled on a fork node: http://jira.jboss.com/jira/browse/JBPM-642

                                  I'll be reading that shortly...

                                  It may explain why I can get the root token to the last state in the process when it's children haven't all joined yet. Seems to me that the join is operating like a discriminator..
                                  package forktest;
                                  
                                  import java.util.Map;
                                  
                                  import junit.framework.TestCase;
                                  
                                  import org.jbpm.JbpmConfiguration;
                                  import org.jbpm.JbpmContext;
                                  import org.jbpm.context.exe.ContextInstance;
                                  import org.jbpm.graph.def.Node;
                                  import org.jbpm.graph.def.ProcessDefinition;
                                  import org.jbpm.graph.exe.ProcessInstance;
                                  import org.jbpm.graph.exe.Token;
                                  import org.jbpm.persistence.db.DbPersistenceServiceFactory;
                                  import org.jbpm.svc.Services;
                                  import org.jbpm.taskmgmt.exe.TaskInstance;
                                  
                                  public class ForkUnitTest extends TestCase
                                  {
                                   /**
                                   * Some helpers
                                   */
                                   JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
                                   DbPersistenceServiceFactory dbPersistenceServiceFactory = (DbPersistenceServiceFactory) jbpmConfiguration.getServiceFactory(Services.SERVICENAME_PERSISTENCE);
                                  
                                   JbpmContext jbpmContext;
                                  
                                   private ProcessInstance processInstance;
                                  
                                   private long processInstanceId;
                                   private ContextInstance contextInstance;
                                  // private TaskMgmtInstance taskMgmtInstance;
                                  
                                   public ForkUnitTest()
                                   {
                                   }
                                  
                                   /**
                                   * Set up the basic in-memory DB, deploy the process description and
                                   * set up a jBPM context.
                                   * @see jBPM docs wrt jbpm configuration file
                                   */
                                   protected void setUp() throws Exception
                                   {
                                   super.setUp();
                                   dbPersistenceServiceFactory.createSchema();
                                   deployProcess();
                                   jbpmConfiguration.startJobExecutor();
                                   jbpmContext = jbpmConfiguration.createJbpmContext();
                                   }
                                  
                                   /**
                                   * Tidy up.
                                   */
                                   protected void tearDown() throws Exception
                                   {
                                   super.tearDown();
                                   jbpmContext.close();
                                   dbPersistenceServiceFactory.dropSchema();
                                   jbpmContext = null;
                                   }
                                  
                                   /**
                                   *
                                   */
                                   public void newTransaction()
                                   {
                                   jbpmContext.close();
                                   jbpmContext = jbpmConfiguration.createJbpmContext();
                                   processInstance = jbpmContext.loadProcessInstanceForUpdate(processInstanceId);
                                  // processInstanceId = processInstance.getId();
                                   }
                                  
                                   /**
                                   * Get the process description file, parse it and deploy the
                                   * process definition.
                                   */
                                   private void deployProcess()
                                   {
                                   JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
                                   try
                                   {
                                   ProcessDefinition processDefinition =
                                   ProcessDefinition.parseXmlResource("ForkProcess/processdefinition.xml");
                                   jbpmContext.deployProcessDefinition(processDefinition);
                                   } finally
                                   {
                                   jbpmContext.close();
                                   }
                                   }
                                  
                                   /**
                                   * Each subsequent test will need a new process instance
                                   * @return a TaskInstance, or null if there is no start task defined.
                                   */
                                   private TaskInstance createNewProcessInstance()
                                   {
                                   processInstance = jbpmContext.newProcessInstanceForUpdate("ForkTest");
                                   processInstanceId = processInstance.getId();
                                   contextInstance = processInstance.getContextInstance();
                                  // taskMgmtInstance = processInstance.getTaskMgmtInstance();
                                   return processInstance.getTaskMgmtInstance().createStartTaskInstance();
                                   }
                                  
                                   public void testFork()
                                   {
                                   TaskInstance taskInstance = createNewProcessInstance();
                                   contextInstance.setVariable("choice", "OptionB");
                                   assertEquals("startstate", processInstance.getRootToken().getNode().getName());
                                   processInstance.signal();
                                   jbpmContext.save(processInstance);
                                  
                                   newTransaction();
                                  
                                   assertEquals("optionb", processInstance.getRootToken().getNode().getName());
                                   processInstance.signal("ok");
                                   jbpmContext.save(processInstance);
                                  
                                   newTransaction();
                                  
                                   assertEquals("nextstate", processInstance.getRootToken().getNode().getName());
                                   processInstance.signal("ok");
                                   jbpmContext.save(processInstance);
                                  
                                   newTransaction();
                                  
                                   Token root = processInstance.getRootToken();
                                   root.signal();
                                  
                                   jbpmContext.save(processInstance);
                                  
                                   newTransaction();
                                  
                                   root = processInstance.getRootToken();
                                   Map map = root.getChildren();
                                   assertEquals(2, map.size());
                                  
                                   Token tk_t10 = (Token) map.get("t10");
                                   assertEquals("t10", tk_t10.getName());
                                  
                                   ProcessInstance pi = tk_t10.getProcessInstance();
                                   assertEquals(processInstanceId, pi.getId());
                                   Node node = tk_t10.getNode();
                                   assertEquals("track", node.getName());
                                  // tk_t10.signal("ok");
                                   jbpmContext.save(processInstance);
                                  
                                   newTransaction();
                                  
                                   root = processInstance.getRootToken();
                                   map = root.getChildren();
                                   assertEquals(2, map.size());
                                  
                                   tk_t10 = (Token) map.get("t10");
                                   assertEquals("t10", tk_t10.getName());
                                  
                                   Token tk_t20 = (Token) map.get("t20");
                                   assertEquals("t20", tk_t20.getName());
                                  
                                   pi = tk_t20.getProcessInstance();
                                   assertEquals(processInstanceId, pi.getId());
                                   node = tk_t20.getNode();
                                   assertEquals("proceed", node.getName());
                                   tk_t20.signal();
                                   node = tk_t20.getNode();
                                   assertEquals("fork2", node.getName());
                                  
                                   map = tk_t20.getChildren();
                                   assertEquals(2, map.size());
                                  
                                   assertEquals("track", processInstance.getRootToken().getNode().getName());
                                  
                                   node = tk_t10.getNode();
                                   assertEquals("track", node.getName());
                                   tk_t10.signal("ok");
                                   node = tk_t10.getNode();
                                   assertEquals("join2", node.getName());
                                   jbpmContext.save(processInstance);
                                  
                                   newTransaction();
                                  
                                   root = processInstance.getRootToken();
                                   root.signal();
                                   assertEquals("join2", processInstance.getRootToken().getNode().getName());
                                  
                                   root.signal();
                                   // FAILS on the next assert as root token is now on state 'complete'
                                   // but shouldn't be as token t20 is still at fork2!!!
                                   assertEquals("join2", processInstance.getRootToken().getNode().getName());
                                   }
                                  
                                  }
                                  


                                  • 14. Re: Token.signal() ---> 2 tokens?

                                     

                                    "mputz" wrote:
                                    I've found a (rejected) feature request to prevent the root token from being signaled on a fork node: http://jira.jboss.com/jira/browse/JBPM-642

                                    That seems to be exactly what I've found.

                                    So if this behaviour is 'normal', how is it possibly to use jBPM as the execution engine in the 'client based assignment' mode as described in the documentation?

                                    If the code that's signalling the tokens has to actually be 'aware' of the process definition, then that goes out of the window completely!

                                    Having looked at some of the unit tests in the jBPM source repository, I think that some of those 'ignore' this behaviour (or avoid dealing with it!)

                                    1 2 Previous Next