4 Replies Latest reply on Jan 6, 2006 11:43 PM by Elmo

    Interception a signal event

    Brian Bulthuis Newbie

      Hello,

      I am trying to figure out how to intercept a signal event so that when a token leaves a node, if certain conditions are met the token will be reassigned to an arbitrary node somewhere in the process definition, but not necessarily a node with a defined transition from the current node.

      For example:

      |node 1| -- tr1 -- |node 2|


      |node 3|

      My token is in node 1, I signal it, and if conditions are met I want to send it to node 3 (or 5 or 7 or 28) instead of node 2.

      I was thinking of using an ActionHandler class linked to the node leave event (Event.EVENTTYPE_NODE_LEAVE) to check for the conditions and then use the Token.setNode(nodeIWant) method, but doesn't work because the Transition.take(...) still runs _after_ my code reassigns the Node of the Token.

      Looking at the source, I don't see an obvious way to do what I want without making my own modification to the jBPM code, which I'd rather not do because of the versioning issues. The crux of my problem seems to be that the Transition.take(...) method is called once a Token is signalled, no matter what happens on any graph events that are triggered. It looks like it would work for me to attach my arbitrary assignment code to the "After Signal" (Event.EVENTTYPE_AFTER_SIGNAL) event of Token, but it looks to me like this would reassign the token to my arbitrary node _after_ it had already entered the node that the default transition points to, which is not what I want.

      Does anyone have any ideas on how I could accomplish this logic using jBPM properly/without modifying the source?

      Thanks a lot!

      -Brian

        • 1. Re: Interception a signal event
          Elmo Novice

          Hi Brian,

          Have you checked out the decision node? You don't need to create an ActionHandler class, you just specify a condition and script for evaluation to a certain transition path.

          Regards,

          Elmo

          • 2. Re: Interception a signal event
            Brian Bulthuis Newbie

            Thanks, Elmo.

            I was tending away from using decision nodes, because that would require that I put a decision node after every state that requires the "transition filter" code. I'd rather be able to execute some code on the leave node event that would somehow cancel the signal event that's already in progress.

            Good thought, though. I'm using decision nodes for many instances of less-ubiquitous decision logic in my processes.

            -Brian

            • 3. Re: Interception a signal event
              Brian Bulthuis Newbie

              Here's what I did - it's a bit of a hack, but it seems to be working okay with many concurrent instances running.

              Each node has node-leave event code that checks for certain conditions that may indicate assignment to an arbitrary node in the process instance is desired. If these conditions are found, a transient variable is set in the context instance with a reference to the current (proper) toNode of the transition that's about to execute (nothing happens in Node.leave(...) between the line where the node-leave event code is triggered and transition.take() is called except logging and the setting of the transitionSource). After the transient variable is set, I get a reference to the transition about to execute from executionContext.getTransition(), and set the 'to' of the transition to the node indicated by the triggering conditions. I now allow the transition code to run, sending the token to the desired node.

              Each node also has node-enter event code that sets the 'to' of the transition back to what it's supposed to be (otherwise the temporary 'to' will be persisted when the transaction is committed and tokens following the normal workflow will be routed incorrectly). This code simply checks for a transient variable in the current ContextInstance with the appropriate name, and if it's there, it sets the 'to' of the ExecutionContext's transition to the original (proper) node.

              Here's the code for the node-leave:

              Node n = executionContext.getProcessDefinition().getNode(nodeToGoTo);
              Transition transition = executionContext.getTransition();
              executionContext.getContextInstance().setTransientVariable(ORIGINAL_TO_NODE, transition.getTo());
              transition.setTo(n);


              And here's the code for the node-enter:

              Node n = (Node)executionContext.getContextInstance().getTransientVariable(ORIGINAL_TO_NODE);
              if (n != null){
               executionContext.getTransition().setTo(n);
               executionContext.getContextInstance().deleteTransientVariable(ORIGINAL_TO_NODE);
              }


              Of course I have a lot more validation and other stuff in my production code, but this is the part that does the work.

              Putting this code at the node-enter and node-leave events of every one of my nodes allows me more flexibility for routing an individual token at runtime, without specifying all possible paths in a workflow graph. So, for example, I can allow an end user to specify that after task "X" has been completed, whether that's two days or two months from now, and no matter where it has gone in that time, the token should come back to them and assign them a "Y" task, even though "Y" is never done after "X" normally.

              I don't know if this is a reasonable way to accomplish my aim, or if this will ever make sense to or help anyone, but I thought I'd post my solution anyway! If there is a 'proper' way to do this (outside of adding many decisions and/or transitions to graphs), and someone wants to post how, that would be cool.

              -Brian

              • 4. Re: Interception a signal event
                Elmo Novice

                Hi Brian,

                Yes your code will work fine but I would probably do things differently. My personal rule of thumb is "always leave each node via transition". If you make a visual graph, there should be a connection for each node, and that connection is the transistion. If you just "look up" a node, then there won't be that transition, and it will look like a hack. If your project gets bigger, you wont be able to see the relationship of each node and it might be difficult to maintain. To illustrate, you can also probably define it this way ,I have not tested this code, but maybe you can get the idea:

                 <state name="s">
                 <event type="node-enter">
                 <script>
                 /*validation script that results some_condition*/
                 token.signal( some_condition );
                 </script>
                 </event>
                 <transition name="cond1" to="node1"/>
                 <transition name="cond2" to="node2"/>
                 <transition name="cond3" to="node3"/>
                 </state>
                


                First, this node should be a wait state. Second, validation code is done at node-enter. The validation code returns the name of the next transition. I have not program anything in node-leave, there is nothing you can do once it leaves a node. Just my 2 cents

                Regards,

                Elmo