8 Replies Latest reply on Dec 21, 2007 6:20 AM by David Roberts

    Re-routing Tokens

    David Roberts Apprentice

      I would like to be able to re-route a token. For example, it moves along a flow, and you realise that a task on a previous node was completed incorrectly or there was an unexpected error, and now you want to send it back to that node to continue the flow from there again. What is the best way to re-route the token?

      There is the method 'token.setNode(Node)', would this do the job properly? Is it as simple as calling that method, or are there reprocutions I need to know about?
      I found an idea searching the forums that you could perhaps create a temporary transition etc, but I don't like that idea for our system.

      I would think that if I used token.setNode(Node), any task instances on that node would still remain, so I would probably have to delete those as well?

      Anyone done anything similair to what I am looking for, or have any ideas on the best method to re-route a token properly?

        • 1. Re: Re-routing Tokens
          Ronald van Kuijk Master

          There is no realy 'best method' since all have (dis)advantages like you already mention and other things like actionhandlers have already done things etc... so it is not that easy (not only in jBPM but in all workflow systems). Best is to model them in the process.

          • 2. Re: Re-routing Tokens
            David Roberts Apprentice

            Thanks Ronald for the quick reply.
            Okay I have done the following, and it seems to reroute to the new node okay.

            //remove current incomplete task instances---------------------------------------------------
             log.info("Removing task instances found at token with ID '"+tokenId+"'");
             List deleteTaskInstanceList = new ArrayList();
             //create a seperate list of those task instances to delete. If deleting them
             //straight from iterator, a ConcurrentModificationException will occur when calling it.next();
             for(Iterator it = processInstance.getTaskMgmtInstance().getTaskInstances().iterator();it.hasNext();) {
             TaskInstance taskInstance = (TaskInstance)it.next();
             if(tokenId.equals(taskInstance.getToken().getId()+"")) {
             if (taskInstance.getEnd() == null) { //not complete task
             deleteTaskInstanceList.add(taskInstance);
             }
             }
             }
             for (int x = 0; x < deleteTaskInstanceList.size(); x++) {
             TaskInstance taskInstance = (TaskInstance)deleteTaskInstanceList.get(x);
             log.info("Removing task instance with ID '"+taskInstance.getId()+"'");
             processInstance.getTaskMgmtInstance().removeTaskInstance(taskInstance);
             }
            //----------------------------------------------------------------------------------------------
            
             //enter new node
             Node newNode = processInstance.getProcessDefinition().getNode(nodeName);
             newNode.enter(new ExecutionContext(token));


            It seems to have the desired effect. You obviously have to keep in mind that you may break something, depending on what your actions etc do, but if you understand how your flow works, you can use this method appropriatly. Can anyone see anything that may cause problems here?

            The only thing that isn't working at the moment is the code
            processInstance.getTaskMgmtInstance().removeTaskInstance(taskInstance);

            The task instance doesn't actually get deleted. Any ideas why?

            • 3. Re: Re-routing Tokens
              Ronald van Kuijk Master

              You are right that if you understand your flow, actions etc very well, this is a way to do it.

              I have no idea why the removeTaskInstance() does not work. Can you make a minimal unittest that demonstrates the problem

              • 4. Re: Re-routing Tokens
                David Roberts Apprentice

                I see there has already been discussion about removing task instances not working, and a test case is provided there as well to show the issue. I think it is more apt to continue the removeTaskInstance problem discussion on that thread.

                Here's the link: http://www.jboss.com/index.html?module=bb&op=viewtopic&t=99354&postdays=0&postorder=asc&start=0

                Another link to a quick one entry thread: http://www.jboss.com/index.html?module=bb&op=viewtopic&t=99527

                • 5. Re: Re-routing Tokens
                  Olivier Debels Newbie

                  We also use re-routing in our workflows:

                  * Firstly we use it when we want to split/merge tokens. The idea here is that we can gradually move in a process instance from a situation where we have:
                  - a single token with a reference to a collection of domain objects
                  - as much tokens as we have domain objects.
                  For example a single report can be made about several domain cases, or the user can opt to split it and make different reports for domain cases which belong together. The user can also opt to merge other domain cases into the current token. Splitting actually creates new subtokens, merging adds domain cases to the current token and can remove other process instances which were created. When a user decides to merge a re-route can happen to a certain node in the workflow (is configurable in custom addition in jbpm designer). Re-routing is done by calling node.leave()

                  * Secondly we allow the user to reopen task instances under certain circumstances. For example when having a process with 2 task nodes, making of a report followed by approving the report, and the user has complete the making of a report task but realized he forgot something, he can reopen this task. In that case the approving of the report task will be removed and the token will be re-routed. This is actually your case.

                  * Thirdly when a user did some changes in a process instance with a start task but wants to undo those changes (and he triggered the creation of the process instance), this process instance and task will be removed. This is not re-routing but simply removing task and processes.

                  For removing processes and task instances we just make sure they don't appear in the client task lists any more.
                  - We created methods to end processinstances, subprocessinstances, the tokens and taskinstances they contain. Clients won 't notice these any more but they still remain in the database.
                  - The circumstances in which a user can undo/reopen etc... are really specific. For example your implementation will not work if you have subprocesses or if you fork and have subtokens.

                  Hope this helps a bit (and is a bit understandeable),

                  feel free the comment

                  Olivier.

                  • 6. Re: Re-routing Tokens
                    David Roberts Apprentice

                    Thanks Olivier for the detailed reply.

                    Instead of re-routing by calling node.leave(), I will use node.enter() on the new node instead. I don't want any leave node actions to be called when leaving the old node, because most of them are reliant on entering info on the task instance, which wouldn't neccessarily of happened yet. Also, calling node.enter() on my new node creates all the task instances and timers for that node.

                    I like your idea of simply ending the task instances from the old node, and not displaying them in the users list. I am now using a similair approach, seeing that we dont seem able to remove a task instance. I end the task instance and set the actor id to something arb, so it wont be displayed in anyones completed tasks list. I also set signalling to false before ending. I don't want the node to be signalled, for the same reason as not using node.leave() above.
                    Eg:

                    taskInstance.setActorId("rerouted");
                    taskInstance.setSignalling(false);
                    taskInstance.end();
                    


                    • 7. Re: Re-routing Tokens
                      Olivier Debels Newbie

                      Choosing between node.leave() or node.enter() is in our approach configurable (the implementation class which determines how to re-route the token is interchangeable).

                      Completed task instances aren't deleted too, which is ok since they can be used for logging and auditing purposes. We use the same code as you do (and also set canceled flag) (but also check if any tokens, super processes etc need to be ended). We also add the reason why they were ended (can be used for auditing purposes and to filter them out).

                      If needed we can always write a purge method which removes/backups any old completed task instance / process instance in the database (taking in account any logging records etc that need to be removed too).

                      Be aware when ending task instances like this and having fork/join with a task node in between. This could result in a never ending process instances.

                      • 8. Re: Re-routing Tokens
                        David Roberts Apprentice

                        Thank you for the advice.