jBPM for Developers: Part 2

Exclusive offer: get 50% off this eBook here
jBPM Developer Guide

jBPM Developer Guide — Save 50%

A Java developer's guide to the jBOSS Business Process Management software

$35.99    $18.00
by Mauricio Salatino | December 2009 | JBoss MySQL Java PHP

Read Part One of jBPM for Developers here.

Process execution

At this point, where our definitions are ready, we can create an execution of our defined processes. This can be achieved by creating a class where each instance represents one execution of our process definition—bringing our processes to life and guiding the company with their daily activities; letting us see how our processes are moving from one node to the next one. With this concept of execution, we will gain the power of interaction and influence the process execution by using the methods proposed by this class.

We are going to add all of the methods that we need to represent the executional stage of the process, adding all the data and behavior needed to execute our process definitions.

This process execution will only have a pointer to the current node in the process execution. This will let us query the process status when we want.

jBPM Developer Guide

An important question about this comes to our minds: why do we need to interact with our processes? Why doesn't the process flow until the end when we start it?

And the answer to these important questions is: it depends. The important thing here is to notice that there will be two main types of nodes:

  • One that runs without external interaction (we can say that is an automatic node). These type of nodes will represent automatic procedures that will run without external interactions.
  • The second type of node is commonly named wait state or event wait. The activity that they represent needs to wait for a human or a system interaction to complete it. This means that the system or the human needs to create/fire an event when the activity is finished, in order to inform the process that it can continue to the next node.

Wait states versus automatic nodes

The difference between them is basically the activity nature. We need to recognize this nature in order to model our processes in the right way. As we have seen before, a "wait state" or an "event wait" situation could occur when we need to wait for some event to take place from the point of view of the process. These events are classified into two wide groups—Asynchronous System Interactions and Human tasks.

Asynchronous System Interactions

This means the situation when the process needs to interact with some other system, but the operation will be executed in some asynchronous way.

For non-advanced developers, the word "asynchronous" could sound ambiguous or without meaning. In this context, we can say that an asynchronous execution will take place when two systems communicate with each other without blocking calls. This is not the common way of execution in our Java applications. When we call a method in Java, the current thread of execution will be blocked while the method code is executed inside the same thread. See the following example:

jBPM Developer Guide

The doBackup() method will block until the backup is finished. When this happens, the call stack will continue with the next line in the main class. This blocking call is commonly named as a synchronous call.

On the other hand, we got the non-blocking calls, where the method is called but we (the application) are not going to wait for the execution to finish, the execution will continue to the next line in the main class without waiting.

In order to achieve this behavior, we need to use another mechanism. One of the most common mechanisms used for this are messages.

Let's see this concept in the following image:

jBPM Developer Guide

In this case, by using messages for asynchronous executions, the doBackup() method will be transformed into a message that will be taken by another thread (probably an external system) in charge of the real execution of the doBackup() code. The main class here will continue with the next line in the code. It's important for you to notice that the main thread can end before the external system finishes doing the backup. That's the expected behavior, because we are delegating the responsibility to execute the backup code in the external system. But wait a minute, how do we know if the doBackup() method execution finished successfully? In such cases, the main thread or any other thread should query the status of the backup to know whether it is ready or not.

Human tasks

Human tasks are also asynchronous, we can see exactly the same behavior that we saw before. However, in this case, the executing thread will be a human being and the message will be represented as a task in the person's task list.

jBPM Developer Guide

As we can see in this image, a task is created when the Main thread's execution reaches the doBackup() method. This task goes directly to the corresponding user in the task list. When the user has time or is able to do that task, he/she completes it. In this case, the "Do Backup" activity is a manual task that needs to be performed by a human being.

In both the situations, we have the same asynchronous behavior, but the parties that interact change and this causes the need for different solutions.

For system-to-system interaction, probably, we need to focus on the protocols that the systems use for communication.

In human tasks, on the other hand, the main concern will probably be the user interface that handles the human interaction.

How do we know if a node is a wait state node or an automatic node?
First of all, by the name. If the node represents an activity that is done by humans, it will always wait. In system interactions, it is a little more difficult to deduce this by the name (but, if we see an automatic activity that we know takes a lot of time, that will probably be an asynchronous activity which will behave as a wait state). A common example could be a backup to tape, where the backup action is scheduled in an external system. If we are not sure about the activity nature we need to ask about the activity nature to our stakeholder.

We need to understand these two behaviors in order to know how to implement each node's executional behavior, which will be related with the specific node functionality.

Creating the execution concept in Java

With this class, we will represent each execution of our process, which means that we could have a lot of instances at the same time running with the same definition. Inside the package called org.jbpm.examples.chapter02.simpleGOP.execution (provided at www.packtpub.com/files/code/5685_Code.zip), we will find the following class:

public class Execution {
private Definition definition;
private Node currentNode;

public Execution(Definition definition) {
this.definition = definition;
//Setting the first Node as the current Node
this.currentNode = definition.getNodes().get(0);
}

public void start(){
// Here we start the flow leaving the currentNode.
currentNode.leave(this);
}
... (Getters and Setters methods)
}

As we can see, this class contains a Definition and a Node, the idea here is to have a currentNode that represents the node inside the definition to which this execution is currently "pointing". We can say that the currentNode is a pointer to the current node inside a specific definition.

The real magic occurs inside each node. Now each node has the responsibility of deciding whether it must continue the execution to the next node or not. In order to achieve this, we need to add some methods (enter(), execute(), leave()) that will define the internal executional behavior for each node. We do this in the Node class to be sure that all the subclasses of the Node class will inherit the generic way of execution. Of course, we can change this behavior by overwriting the enter(), execute(), and leave() methods.

We can define the Node.java class (which is also found in the chapter02.simpleGOPExecution project in the code bundle) as follows:

...
public void enter(Execution execution){
execution.setCurrentNode(this);
System.out.println("Entering "+this.getName());
execute(execution);
}
public void execute(Execution execution){
System.out.println("Executing "+this.getName());
if(actions.size() > 0){
Collection<Action> actionsToExecute = actions.values();
Iterator<Action> it = actionsToExecute.iterator();
while(it.hasNext()){
it.next().execute();
}
leave(execution);
}else{
leave(execution);
}
}
public void leave(Execution execution){
System.out.println("Leaving "+this.getName());
Collection<Transition> transitions =
getLeavingTransitions().values();
Iterator<Transition> it = transitions.iterator();
if(it.hasNext()){
it.next().take(execution);
}
}
...

As you can see in the Node class, which is the most basic and generic implementation, three methods are defined to specify the executional behavior of one of these nodes in our processes. If you carefully look at these three methods, you will notice that they are chained, meaning that the enter() method will be the first to be called. And at the end, it will call the execute() method, which will call the leave() method depending on the situation. The idea behind these chained methods is to demarcate different phases inside the execution of the node.

All of the subclasses of the Node class will inherit these methods, and with that the executional behavior. Also, all the subclasses could add other phases to demarcate a more complex lifecycle inside each node's execution.

The next image shows how these phases are executed inside each node.

jBPM Developer Guide

As you can see in the image, the three methods are executed when the execution points to a specific node. Also, it is important to note that transitions also have the Take phase, which will be executed to jump from one node to the next.

All these phases inside the nodes and in the transition will let us hook custom blocks of code to be executed.

One example for what we could use these hooks for is auditing processes. We could add in the enter() method, that is the first method called in each node, a call to an audit system that takes the current timestamp and measures the time that the node uses until it finishes the execution when the leave() method is called.

jBPM Developer Guide

Another important thing to notice in the Node class is the code inside the execute() method. A new concept appears. The Action interface that we see in that loop, represents a pluggable way to include custom specific logic inside a node without changing the node class. This allows us to extend the node functionality without modifying the business process graph. This means that we can add a huge amount of technical details without increasing the complexity of the graph. For example, imagine that in our business process each time we change node, we need to store the data collected from each node in a database. In most of the cases, this requirement is purely technical, and the business users don't need to know about that. With these actions, we achieve exactly the above. We only need to create a class with the custom logic that implements the Action interface and then adds it to the node in which we want to execute the custom logic.

jBPM Developer Guide

The best way to understand how the execution works is by playing with the code. In the chapter02.simpleGOPExecution maven project, we have another test that shows us the behavior of the execution class. This test is called TestExecution and contains two basic tests to show how the execution works.

If you don't know how to use maven, there is a quick start guide at the end of this article. You will need to read it in order to compile and run these tests.

public void testSimpleProcessExecution(){
Definition definition = new Definition("myFirstProcess");
System.out.println("########################################");
System.out.println(" Executing PROCESS:
"+definition.getName()+" ");
System.out.println("########################################");
Node firstNode = new Node("First Node");
Node secondNode = new Node("Second Node");
Node thirdNode = new Node("Third Node");
firstNode.addTransition("to second node", secondNode);
secondNode.addTransition("to third node", thirdNode);
//Add an action in the second node.
CustomAction implements Action
secondNode.addAction(new CustomAction("First"));
definition.addNode(firstNode);
definition.addNode(secondNode);
definition.addNode(thirdNode);
//We can graph it if we want.
//definition.graph();
Execution execution = new Execution (definition);
execution.start();
//The execution leave the third node
assertEquals("Third Node", execution.getCurrentNode().getName());
}

If you run this first test, it creates a process definition as in the definition tests, and then using the definition, it creates a new execution. This execution lets us interact with the process. As this is a simple implementation, we only have the start() method that starts the execution of our process, executing the logic inside each node. In this case, each node is responsible for continuing the execution to the next node. This means that there are no wait state nodes inside the example process. In case we have a wait state, our process will stop the execution in the first wait state. So, we need to interact with the process again in order to continue the execution.

Feel free to debug this test to see how this works. Analyze the code and follow the execution step by step. Try to add new actions to the nodes and analyze how all of the classes in the project behave.

When you get the idea, the framework internals will be easy to digest.

jBPM Developer Guide A Java developer's guide to the jBOSS Business Process Management software
Published: December 2009
eBook Price: $35.99
Book Price: $59.99
See more
Select your format and quantity:

Homework

We are ready to create our first simple GOP language, the idea here is to get hands-on code and try to implement your own solution. Following and using the guidelines proposed in this article with minimal functionality, but with the full paradigm implemented, will represent and execute our first process. We could try to implement our example about "Recycling Thing Co.", but we will start with something easier. So, you can debug it and play with it until you get the main points of functionality. In the following sections, I will give you all the information that you need in order to implement the new words of our language and the behavior that the process will have. This is quite a lot of homework, but trust me, this is really worth it. The idea of finishing this homework is to feel comfortable with the code and the behavior of our defined processes. You will also see how the methods are chained together in order to move the process from one node to the next.

Creating a simple language

Our language will be composed with subclasses from our previous node class. Each of these subclasses will be a word in our new language. Take a look at the ActivityNode proposed in the chapter02.simpleGOPExecution project, inside the org.jbpm.examples.chapter02.simpleGOP.definition.more.expressive.power package. And when we try to represent processes with this language, we will have some kind of sentence or paragraph expressed in our business process language. As in all languages, these sentences and each word will have restrictions and correct ways of use. We will see these restrictions in the Nodes description section of the article.

So, here we must implement four basic words to our simple language. These words will be start, action, human decision, and end to model processes like this one:

 

jBPM Developer Guide

Actually, we can have any combination that we want of different types of nodes mixed in our processes. Always follow the rules/restrictions of the language that we implement. These restrictions are always related to the words' meanings. For example, if we have the word "start" (that will be a subclass of node) represented with the node: StartNode, this node implementation could not have arriving transitions. This is because the node will start the process and none of the rest of the nodes could be connected to the start node. Also, we could see a similar restriction with the end node, represented in the implementation with the EndNode class, because it is the last node in our processes and it could not have any leaving transitions. With each kind of node, we are going to see that they have different functionality and a set of restrictions that we need to respect when we are using these words in sentences defining our business processes. These restrictions could be implemented as 'not supported operation' and expressed with: throw new UnsupportedOperationException("Some message here");. Take a look at the EndNode class, you will see that the addTransition() method was being overridden to achieve that.

Nodes description

In this section, we will see the functionality of each node. You can take this functionality and follow it in order to implement each node. Also, you could think of some other restrictions that you could apply to each node. Analyze the behavior of each method and decide, for each specific node type, whether the method behavior needs to be maintained as it is in the super class or whether it needs to be overwritten.

  • StartNode: This will be our first node in all our processes. For this functionality, this node will behave as a wait state, waiting for an external event/signal/trigger that starts the process execution. When we create a new instance of process execution, this node is selected from the process description and set as the current node in the current execution. The start() method in the execution class will represent the event that moves the process from the first node to the second, starting the flow of the process.
  • EndNode: It will be our last node in all our processes. This node will end the life of our process execution instance. As you can imagine, this node will restrict the possibility of adding leaving transitions to this node.
  • ActionNode: This node will contain a reference to some technical code that executes custom actions that we need for fulfilling the process goal. This is a very generic node where we can add any kind of procedure. This node will behave as an automatic activity, execute all of these actions, and then leave the node.
  • HumanDecisionNode: This is a very simple node that gives a human being some information in order to decide which path of the process the execution will continue through. This node, which needs human interaction, will behave as a wait state node waiting for a human to decide which transition the node must take (this means that the node behaves as an OR decision, because with this node, we cannot take two or more paths at the same time).

One last thing before you start with the real implementation of these nodes. We will need to understand what the expected results are in the execution stage of our processes. The following images will show you how the resultant process must behave in the execution stage. The whole execution of the process (from the start node to the end node) will be presented in these three stages.

Stage one

The following image represents the first stage of execution of the process. In this image, you will see the common concepts that appear in the execution stage. Every time we create a new process execution, we will start with the first node, waiting for an external signal that will move the process to the next node.

jBPM Developer Guide

  1. An execution is created using our process definition instance in order to know which activities the process will have.
  2. The start node is selected from the process definition and placed inside the current node reference in the execution instance. This is represented by the black arrow pointing to the Start node.
  3. As the StartNode behaves as a wait state, it will wait and externally trigger to start the process execution. We need to know this, because may, we can think that if we create an instance of execution, it will automatically begin the execution.

Stage two

The second stage of the execution of the process is represented by the following image:

jBPM Developer Guide

  • We can start the execution by calling the start() method inside the execution class. This will generate an event that will tell the process to start flowing through the nodes.
  • The process starts taking the first transition that the start node has, to the first action node. This node will only have an action hooked, so it will execute this action and then take the transition to the next node. This is represented with the dashed line pointing to the Action node. This node will continue the execution and will not behave as a wait state—updating the current node pointer, which has the execution, to this node.
  • The Human Decision node is reached, this means that some user must decide which path the process will continue through. Also, this means that the process must wait for a human being to be ready to decide. Obviously, the node will behave as a wait state, updating the current node pointer to this node.

But wait a second, another thing happens here, the process will return the execution control to the main method. What exactly does this mean?

Until here, the execution goes from one wait state (the start node) to another wait state (the human decision node) inside the method called start, enclosing all the automatic nodes' functionality and leaving the process in a wait state. Let's analyze the method call stack trace:

jBPM Developer Guide

When the process reaches the HumanDecisionNode.execute(), it doesn't need to do anything more. It returns to the main() method and continues with the next line after the Execution.start()call.

Stage three

The following image represents the third stage of execution of the process:

jBPM Developer Guide

  1. Now we are waiting for a human to make a decision, but wait a second, if the thread that calls the start() method on the instance of the execution dies, we lose all the information about the current execution, and we cannot get it back later. This means that we cannot restore this execution to continue from the human decision node. On the other hand, we can just sleep the thread waiting for the human to be ready to make the decision with something like Thread.currentThread().sleep(X). Where X is expressed in milliseconds. But we really don't know how much time we must wait until the decision is taken. So, sleeping the thread is not a good option. We will need some kind of mechanism that lets us persist the execution information and allows us to restore this status when the user makes the decision. For this simple example, we just suppose that the decision occurs just after the start() method returns. So, we get the execution object, the current node (this will be the human decision node), and execute the decide() method with the name of the transition that we want to take as argument.
  2. Let's run ((HumanDecisionNode)execution.getCurrentNode()). decide("transition to action three", execution). This is an ugly way to make the decision, because we are accessing the current node from the execution. We could create a method in the execution class that wraps this ugly call. However, for this example, it is okay. You only need to understand that the call to the decide() method is how the user interacts with the process.
  3. When we make this decision, the next action node is an automatic node like the action one, and the process will flow until the EndNode, which is ending the execution instance, because this is the last wait state, but any action could be made to continue. As you can see, the wait states will need some kind of persistent solution in order to actually be able to wait for human or asynchronous system interactions. That is why you need to continue your testing of the execution with ((HumanDecisionNode)execution.getCurrentNode()).decide("transition to action three",execution), simulating the human interaction before the current thread dies.

Quick start guide to building Maven projects

A quick start guide for building Maven projects is follows:

  • Download and install Maven 2.x (http://maven.apache.org/)
  • Append maven binaries in the PATH system variable
  • Open a terminal/console
  • Go to the appropriate directory and look for a file called pom.xml
  • Type mvn clean install into the console, this will compile the code, run the tests, and package the project
  • If you are using Netbeans, you can just open your project (having the maven plugin activated)
  • If you are using Eclipse, you need to run the project in the mvn eclipse: eclipse project directory, in order to generate the files needed for the project. Then you can just import the project into your workspace

Summary

In this article, we learnt the main points that you will need in order to understand how the framework works internally.

We have analyzed why we need the Graph Oriented Programming approach to represent and execute our business processes.

jBPM Developer Guide A Java developer's guide to the jBOSS Business Process Management software
Published: December 2009
eBook Price: $35.99
Book Price: $59.99
See more
Select your format and quantity:

About the Author :


Mauricio Salatino

Mauricio Salatino (a.k.a. Salaboy) has been an active part of the Java and open source software community for more than eight years. He got heavily involved in the JBoss jBPM and Drools projects as a community contributor five years ago. After publishing his first book about jBPM for Packt Publishing, he was recognized as a valuable member of both projects at the JBoss Community Awards 2011.

During the last three years, Mauricio has being teaching and consulting on jBPM and Drools in America and Europe. In 2010, he co-founded Plugtree (www.plugtree.com), which is a company that provides consultancy and training around the world. Since then, he has participated in international conferences such as Java One, Rules Fest, Jazoon, JBoss In Bossa, and RuleML, as the main speaker. He is now a Drools and jBPM Senior Software Developer at Red Hat / JBoss, fully dedicated to moving these projects forward.

Books From Packt

WordPress 2.8 Theme Design
WordPress 2.8 Theme Design

jQuery UI 1.7: The User Interface Library for jQuery
jQuery UI 1.7: The User Interface Library for jQuery

Spring Persistence with Hibernate
Spring Persistence with Hibernate

Apache Roller 4.0 – Beginner's Guide
Apache Roller 4.0 – Beginner's Guide

Oracle SQL Developer 2.1
Oracle SQL Developer 2.1

JBoss Drools Business Rules
JBoss Drools Business Rules

Drools JBoss Rules 5.0 Developer's Guide
Drools JBoss Rules 5.0 Developer's Guide

JBoss AS 5 Development
JBoss AS 5 Development

No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
v
P
5
e
K
v
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software