In another installment of the JBoss BPM Suite Tips & Tricks series we will be helping understand how you can access or change a process context variable from inside a rule in your BPM project.
We will be using a simple demo project that can be found in our demo collections on github, which will allow you to view and experiment with the final working example in a JBoss BPM Suite installation.
The JBoss BPM Suite installation you will have to set up yourself, but you can leverage our JBoss BPM Suite installation project we have to save you some trouble.
The goal
The basic goal of this article and demo project is to show you exactly how to design a process that uses a rule that if it fires will then access and modify one of the process variables. This communication between a process and a rule is an often asked question.The setup
Start by unzipping the demo project repository and copy it into the JBoss BPM Suite installation projects directory.# Start by cloning project at # https://github.com/eschabell/demo-collections. # $ git clone git@github.com:eschabell/demo-collections.git $ cd demo-collections $ unzip niogit-rule-procvar.zip # Follow instructions and install JBoss BPM Suite # via https://github.com/eschabell/bpms-install-demo. # # Then copy the demo repository into the JBoss BPM Suite server. # $ cp -rv .niogit bpms-install-demo/target/jboss-eap-6.1/bin # Start the JBoss BPM Suite server. # $ ./bpms-install-demo/target/jboss-eap-6.1/bin/standalone.sh # Login with user 'erics' and password 'bpmsuite' to get started.
Now we can take a look at the process, how it is configured to be deployed by default, what the rule is, what we have to do to modify a process variable, and look at the output.
The initial output
Our process consists of a simple run through that prints a log statement at the first node, then runs a rule (which we want to modify a process variable), then a gateway where we decide if the rule fired or not, and then the path where the rule fired (we log that) or the path where the rule did not fire (we log that too).Test process for rule modifying a process variable. |
On our initial attempt we had a process that only had the first two nodes, then ended. We expected to see something like this in the logs if we ran three instances of the process:
17:29:46,315 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Execute Java Step 17:29:46,330 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Tested Rule 17:29:46,315 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Execute Java Step 17:29:46,330 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Tested Rule 17:29:46,315 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Execute Java Step 17:29:46,330 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Tested Rule
What we ended up with was this:
17:29:46,315 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Execute Java Step 17:29:46,330 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Tested Rule 17:29:46,315 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Execute Java Step 17:29:46,315 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Execute Java Step
At this point we modified the process you see above, adding two debug nodes that report if the rule fired or not, making the outcome clearer. We expected to see something like this in the logs if we ran three instances of the process:
20:51:22,491 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Execute Java Step 20:51:22,494 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Tested Rule 20:51:22,497 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Rule fired! 20:51:35,615 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Execute Java Step 20:51:35,618 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Tested Rule 20:51:35,621 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Rule fired! 20:51:43,312 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Execute Java Step 20:51:43,316 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Tested Rule 20:51:43,320 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Rule fired!
What we ended up with was this:
20:51:22,491 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Execute Java Step 20:51:22,494 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Tested Rule 20:51:22,497 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Rule fired! 20:51:35,615 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Execute Java Step 20:51:35,618 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Rule did not fire... 20:51:43,312 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Execute Java Step 20:51:43,316 INFO [stdout] (http-localhost/127.0.0.1:8080-2) Rule did not fire...
What happened to the rule firing the second and third time? Not only that, the rule never even triggers in the second and third time through, why?
To find out we need to look at the session strategy that is applied by default.
The deployment
Taking a closer look at how this process is deployed, we see that it makes use of the default session strategy SINGLETON which means it will run all process instances in a single ksession.Deployment by default is using SINGLETON runtime strategy |
The second (and all consecutive) time through the working memory was not being modified so the rule is never evaluated, it just passes over it.
To fix this we need to make the process clearer, so we added a process variable to be updated when the rule fired, a gateway to check the process variable, and if set to log that the rules had fired. Remember, the rule firing sets the process variable.
Let's see how that looks.
The rule
We took our initial stab at the rule by setting it up to always match the condition so that the action would fire:rule "update-procvar" ruleflow-group "fire-always" when eval(true) then System.out.println("Tested Rule"); endRemember with the single ksession the first time through it fired, but after that it never gets evaluated again. To fix this we will need to make sure that some form of object or fact is added into the working memory each time this process instance is run.
Luckily this is provided for in a rule task, where you can create Data Assignments and map your DataInputSets. This is done by selecting the rule task and expanding the Properties sidebar to show you that we have created a fired variable and assigned it the value null, then we are inserting it into the working memory as our DataInputSet.
Mapping the fired variable into the working memory every time. |
import org.kie.api.runtime.process.WorkflowProcessInstance; rule "update-procvar" ruleflow-group "fire-always" when $pi: WorkflowProcessInstance() String() then $pi.setVariable("fired", "true"); endWhat we have done here in the rule is add an import to give us access to the process instance we are running in, then assign it to the local variable $pi so we can work with it to access our process variable, then we have a check that will always succeed if there is a new String object in working memory. Remember we insert a fired object every time we enter this rule task node?
This should cause the rule to evaluate and then using the process instance we can set the process variable fired to true, which is exactly the check that is done at the following gateway node.
Let's run it a few times and see what happens?
The Output
This is what you will see when you run three instances of the demo process:
21:06:32,767 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Execute Java Step 21:06:32,774 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Tested Rule 21:06:32,777 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Rule fired! 21:06:41,646 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Execute Java Step 21:06:41,654 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Tested Rule 21:06:41,656 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Rule fired! 21:06:47,559 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Execute Java Step 21:06:47,565 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Tested Rule 21:06:47,567 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Rule fired!
We hope you now understand how a process is deployed using a rule, how to access and update a process variable from a rule in your project, and can put this knowledge to use in your own projects.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.