Tijs has posted 3 posts at DZone. View Full User Profile

Tutorial From Devoxx: Activiti, BPMN 2.0 in Action

11.18.2010
| 33832 views |
  • submit to reddit
A little while ago BonitaSoft mentioned in an interview posted on DZone that 'BonitaSoft is the only true open source BPM option available in today's market'. Well it’s not anymore; meet the Apache licensed Activiti project.

If you haven't been fortunate enough to see the Activiti in Action session of Tom Baeyens and Joram Barrez at Devoxx last Thursday, this article will get you up to speed with this first full-blown open source business process management suite. Before we dive in the technical details of developing processes with the Activiti engine we will first give a little bit of background about BPMN 2.0 and Activiti. Finally, after you have seen the API in practice, we present the tools completing the Activiti stack briefly and give you some references to get more background information to check out.

                                                          

The road to BPMN 2.0 and Activiti
Already back in 2004 the first version of the Business Process Modeling Notation, BPMN 1.0, was finalized. This language enables analysts to model their business. From a developer's point of view, to run these processes the industry standard was of course WS-BPEL 2.0. Besides the fact that you needed two different languages to get from a process model to an executable process, some important constructs like human task or workflow support and cyclic control flow, where lacking. BPMN 2.0 overcomes these issues and defines one language for modeling a business process and execute it on a process engine, so now analysts and developers speak with the same vocabulary and share models without the need of conversion.

While traditional vendors were (and still are!) busy to migrate their BPEL engines and BPMN 1.x modeling tools to BPMN 2.0, Tom Baeyens and Joram Barrez started the Activiti project to create a rock solid BPMN 2.0 process engine. These former leaders of jBPM were planning on implementing the BPMN 2.0 specification on the jBPM engine, when Alfresco was looking for a more liberal licensed process engine for the workflow functionality in their document management system. The two parties met and the Activiti project was born!

Now, half a year later, on the first of December, the first GA release Activiti 5.0 is coming out. To quote the guys concerning the odd version number for a first release: 'we are not building experimental stuff here'. Build with the knowledge and experience of developing jBPM versions 1 to 4, Activiti is lightweight and has a very clean and open API.

Giving the Activiti engine a spin
To try out the example we will show you can get Activiti at http://www.activiti.org/. Setting up your environment is pretty straightforward and will be explained later on. Now let’s get into the details of developing business processes with Activiti. Note that we’ll focus on the Activiti engine in this article, but we’ll provide more articles about Activiti where we discuss other parts of the project such as the Activiti Modeler and the Activiti Designer. We’ve talked about the new BPMN 2.0 specification a bit but to really understand the technical basics of this upcoming open standard, we’ll start with a very simple process with only a start and an end event with a script task in between.
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn"
targetNamespace="http://www.bpmnwithactiviti.org/pizzaorder">

<process id="pizzaorder" name="Order a pizza">
<startEvent id="theStart"/>
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="validateOrder" />
<scriptTask id="validateOrder" scriptFormat="groovy">
<script>
out:print "Validating pizza order for " + customerName + "\n";
if(amount > 10){
rejectReason = "That is a little bit too much for us " + amount + " pizzas";
pizzaOrderToOven = false;
} else {
pizzaOrderToOven = true;
}
out:print "Pizza order was validated with outcome " + pizzaOrderToOven + "\n";
if(pizzaOrderToOven == false) {
out:print "Reject reason is " + rejectReason + "\n";
} else {
out:print amount + " " + pizza + " pizzas going to the oven\n";
}
</script>
</scriptTask>
<sequenceFlow id="flow2" sourceRef="validateOrder" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
</definitions>
This simple example shows the basic structure of a BPMN 2.0 XML process definition with a definitions root element. In the process definition we see that most of the process consists of the script task code. If we had printed a text like "Hello world" the XML would have been pretty compact. However it’s good to have a bit more meat inside this process definition, as we’ll see in a bit. You can see that the start and end event and the script task are connected via sequence flows. The sequence flows define the process flow of this simple process flow, so after the start event the script task is executed and finally the end event.

In the script code a logging line is printed with the out:print keyword. In the log line we use the customerName variable, which is a process variable that has to be passed as an input variable to the process instance. You can directly use process variables in the scripting logic. The amount variable is another example of a process variable. If the amount of ordered pizza’s is more than 10, a new process variable pizzaOrderToOven will be created and set to false. Else, if the amount is less or equal to 10 the pizzaOrderToOven process variable is set to true. So now we’ve defined our first little process, but what’s the next step? Well, a good practice would be to test this process using the powerful unit testing functionality of Activiti.
public class PizzaScriptTaskTest {
@Rule
public ActivitiRule rule = new ActivitiRule("activiti.cfg-mem.xml");

@Test
@Deployment(resources={"pizzaOrderSimple.bpmn20.xml"})
public void submitPizzaOrderNotValid() {
Map<String, Object> variableMap = new HashMap<String, Object>();
variableMap.put("customerName", "JohnDoe");
variableMap.put("address", "1st Street 7623");
variableMap.put("pizza", "Margherita");
variableMap.put("amount", 11);
RuntimeService runtimeService = rule.getProcessEngine().getRuntimeService();
String processID = runtimeService.startProcessInstanceByKey("pizzaorder", variableMap).getId();
assertNotNull(processID);
}
}
The unit test is very compact, but does actually quite a lot of things, let’s walk through them. First the ActivitiRule class is a JUnit 4 TestWatchman subclass where the Activiti engine is started and ended automatically for you. The only thing the ActivitiRule needs to do this is a configuration file where the Activiti database is defined and a couple of optional additions like a job scheduler and a mail server. The configuration for our unit test uses an in-memory H2 database and looks like this.
<?xml version="1.0" encoding="UTF-8"?>
<activiti-cfg>
<database type="h2" schema-strategy="create-if-necessary">
<jdbc url="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000"
driver="org.h2.Driver"
username="sa"
password="" />
</database>
<job-executor activate="off" />
</activiti-cfg>
The configuration file defines the JDBC connection to the Activiti engine database; in this case a H2 database. As you can see the database schema is created automatically the first time with the create-if-necessary schema strategy. The job scheduler is turned off because we don’t need it yet. In our larger example later on, we’ll do use a job.

So the Activiti engine is started with a single line in our unit test. Then we see an @Deployment annotation above our unit test method. This makes sure the BPMN 2.0 process definition we created earlier is deployed to the process engine before the unit test method is executed. In the script task of our simple pizza order process we use a couple of process variables like customerName and amount, so in the unit test we create a Map of process variables that are used to start the new process instance. To start a new process instance we need to get hold of a RuntimeService instance, which can be obtained via the ActiviRule instance. With the startProcessInstanceByKey method you can then start a new process instance of our pizza order process definition with the Map of variables. When you’ve imported the source code pizza-order project in your IDE (for example Eclipse after you used Maven to configure the project with mvn eclipse:eclipse), you can execute this unit test right away and see that the Activiti engine is started very quickly and the process definition is deployed and started within the second. Powerful stuff right?

Implementing a full pizza order process with Activiti
The simple pizza order process example provides a good overview of the basic functionality Activiti provides to deploy and start new process instances. But to get even more information about Activiti it’s good to look at a larger example. We’ll implement a more complex  pizza order process, which looks like the following process model created with Activiti Modeler.



As you can see we’ll still use our validate order script task, but we’ll enhance the rest of the process definition with Java service tasks, an exclusive gateway, user tasks and a boundary timer event. We’ll make nobody happy with showing the full BPMN 2.0 XML for this example, but we’ll walk through every part of the process step-by-step. The full XML implementation is of course available in the source code of this article. To prevent yourself from working with the raw BPMN 2.0 XML you can use the Activiti Designer to design and generate this for you.

The first enhancement we see in the process model is an exclusive gateway. An exclusive gateway can be used to implement conditional logic to decide which sequence flow must be taken in the process flow. In this example, if the pizza order amount is more than 10 the pizzaOrderToOven process variable is set to false and the process must be ended. The BPMN 2.0 XML for this exclusive gateway looks like this.
<exclusiveGateway id="validateGateway" />
<sequenceFlow id="flow3" sourceRef="validateGateway" targetRef="calculatePrice">
<conditionExpression xsi:type="tFormalExpression">${pizzaOrderToOven == true}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow4" sourceRef="validateGateway" targetRef="theEnd">
<conditionExpression xsi:type="tFormalExpression">${pizzaOrderToOven == false}</conditionExpression>
</sequenceFlow>
As you can see, if the pizzaOrderToOven process variable is true, the next step will be the calculate price task, otherwise the process will be ended. In addition to the great scripting functionality, it’s also very easy to add Java logic to the process via a Java service task. To calculate the price of the pizza order we’ll use a Java service task. As this is no standard BPMN 2.0 construct, Activiti provides this functionality as an extension to the BPMN specification. In XML this looks like the following snippet.
<serviceTask id="calculatePrice"
activiti:class="org.bpmnwithactiviti.dzone.pizzaorder.CalculatePriceService" />
That’s not difficult, is it? Just a fully qualified class name that includes the package name. To implement the CalculatePriceService it’s not complex either, because with the JavaDelegation interface of the Activiti framework we only have to implement an execute method. For our pizza order example the price calculation is implemented as follows.
public class CalculatePriceService implements JavaDelegation {
@Override
public void execute(DelegateExecution execution) throws Exception {
String pizzaName = (String) execution.getVariable("pizza");
int amount = (Integer) execution.getVariable("amount");
System.out.println("Calculating price for " + amount + " " + pizzaName + " pizzas");
int price = 0;
if("margherita".equalsIgnoreCase(pizzaName)) {
price = amount * 6;
} else {
price = amount * 8;
}
System.out.println("Price will be " + price);
execution.setVariable("price", price);
}
}
The input parameter of the execute method is a DelegateExecution instance, where you retrieve information from the running process instance. A typical usage of the DelegateExecution is to retrieve and set process variables in the process instance. In this example we retrieve the pizza and amount process variables to calculate a price and set this result as a new process variable in the process instance.

Quickly on to the next step of the process, baking the pizza’s, which is represented as an user task in the process definition. A user task is assigned to a specific user or a list or group of candidate users. The user has to claim and complete the user task before the process will progress to the next state. With the Activiti Explorer you can claim and complete user tasks via a web interface, as we’ll see later on when we’ve complete the process. An additional function of Activiti is the form implementation. You can define a form with simple HTML tags and configure it on a user task. Then when a user wants to complete that user task in the Activiti Explorer that form is shown to the user. In our pizza order example we’ll use two forms, one to start the process and one to implement the bake pizza user tasks. The forms look like the following figures in the Activiti Explorer.

                                                                        

                                                                

Now let’s look at how we can implement the second form where we have to enter the expected delivery time and see how easy this is.
<h1>Get the pizza to the oven</h1>
<p>
${customerName} would like to get ${amount} ${pizza} pizzas.
</p>
<p>
Total price : ${price}
</p>
<table>
<tr>
<td>
<label>
Expected delivery time:<br/>
<input type="text" name="delivery" value="" />
<input type="hidden" name="delivery_required" value="true" />
</label><br/>
</td>
</tr>
</table>
You only have to define simple HTML elements to implement the form. We can use process variables directly in the user task form like we do with the ${customerName} variable. And to define an input field we use the standard HTML input element. The delivery field value will automatically be available as a process variable when the user task form is completed. By specifying an additional hidden input element you can make the input field required. Now let’s look at how we use this task form in the BPMN 2.0 XML of our pizza order process.
<userTask id="bakePizzas" name="Bake the pizza" 
activiti:formKey="pizzaBake.form"
activiti:assignee="fozzie"/>
The user task is assigned to fozzie, one of the default users when you install Activiti. The pizzaBake.form user task form is the one we defined in the previous code snippet. So this is all we have to do to assign an user task with a form to a specific user.

We are approaching the end of our pizza order example process, but we have to look into two more parts of the process definition. First the boundary timer. A boundary timer can be used to define a specific time period on a task and when that time period has passed, a boundary timer event will fire. In the pizza order example we have defined a boundary timer of 1 minute on the bake pizza user task of fozzie. When fozzie doesn’t complete its user task within 1 minute, the user task is deleted and a task in the management group is inserted. The management group is also a default group defined when you install Activiti and kermit is the only user, which is part of that group. So Kermit can claim and complete the user task after the boundary timer of 1 minute is fired. In BPMN 2.0 XML it looks like this.
<boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="bakePizzas">
<timerEventDefinition>
<timeDuration>PT1M</timeDuration>
</timerEventDefinition>
</boundaryEvent>
<sequenceFlow id="flow6" sourceRef="escalationTimer" targetRef="bakePizzasByManager" />
<userTask id="bakePizzasByManager" name="Fozzie is sleeping?"
activiti:formKey="pizzaBake.form"
activiti:candidateGroups="management" />
The boundary timer event is attached to the bakePizzas user task we defined in the previous code snippet. So after 1 minute the timer event is fired and the bakePizzas user task is cancelled e.g. deleted. To attach another task to a boundary timer event you just use a sequence flow. In this case we defined another user task that reuses the same user task form and has the management group configured as its candidate group.

One more part to explain and that is the twitter service task. Just like the calculate price service task we have implemented a twitter task with a Java service task. We already know how to implement a Java service task in BPMN 2.0 XML, so we’ll just take a look at the Java class implementation.
public class TwitterService implements JavaDelegation {
@Override
public void execute(DelegateExecution execution) throws Exception {
String customerName = (String) execution.getVariable("customerName");
int amount = (Integer) execution.getVariable("amount");
String pizza = (String) execution.getVariable("pizza");
int price = (Integer) execution.getVariable("price");
String delivery = (String) execution.getVariable("delivery");
AccessToken accessToken = new AccessToken("YOUR TOKEN", "YOUR TOKEN SECRET");
Twitter twitter = new TwitterFactory().getOAuthAuthorizedInstance(
"RclhVMQOSyapUD4sFtyTfg",
"t7fI6QjDDhb13dxiOG2MIJY5KGBJKZfxkBEl2bAOc8", accessToken);
twitter.updateStatus("#Activiti engine created pizza order: " +
customerName + " ordered " + amount + " " + pizza + " pizza's for DZone article");
twitter.updateStatus("Oh yes the " + pizza + " pizza's will cost: " +
price + " euro and will be delivered around " + delivery);
}
}
This service implementation uses the Twitter4J framework to communicate with your Twitter account. It takes a couple of process variables and twitters two messages on to your account about the pizza order. Notice that you still have to overwrite the access token and access token secret keys. In the Twitter4J examples this OAuth authentication method is explained.

To make it easy for you to generate these tokens the source code of this article contains a CreateTwitterAccess unit test. This unit test generates a Twitter URL you must open in your web browser. After you’ve received a PIN code, you have to enter this PIN code in the console of the unit test. Then the unit test will generate your access tokens, which you can copy to the TwitterService implementation.

We’ve covered the whole pizza order process and talked about script, Java service, and user tasks, the exclusive gateway, the boundary timer and the user task forms. So now it’s time to deploy and demo our example process. To have everything running you must execute the following steps:

  1. Download Activiti RC1 from http://activiti.org.
  2. Run the installation script by running the ant command in the setup directory of the Activiti distribution. This will install and startup Activiti.
  3. Stop the Tomcat server that’s started as part of the installation script.
  4. Run the default target deploy.pizzaorder of the build.xml that’s available in the root of the source code package of this article. This will deploy the process definition to the Activiti engine.
  5. Copy the groovy-all jar from the examples/activity-engine-examples/libs-runtime directory of the Activiti distribution to the app/apache-tomcat-6.0.29/lib directory. This is needed because the Groovy scripting engine is not installed in Tomcat by default.
  6. Copy the twitter4j-core jar from your Maven repository (by default USER_HOME/.m2) to the Tomcat lib directory. The twitter jar is available in the Maven repo in the org/twitter4j/twitter4j-core/2.1.6 directory. This makes sure that the Twitter4J library is available on the classpath.
  7. Copy the pizzaorder.jar from the source code dist directory to the app/apache-tomcat-6.0.29/lib directory. This is needed because the service task classes used in the pizza order process must be on the classpath of Tomcat.
  8. Start the Tomcat server again by running the Ant command ant tomcat.start from the setup directory of your Activiti distribution.


When you are done with these steps you can go to the Activiti Explorer – http://localhost:8080/activiti-explorer - and login with for example fozzie, fozzie. Because we also need the fozzie user for our first user task this is handy later on. Then click on the processes tab and click on the start form link you can find with the pizza order process. There you can fill-in the start form and click for OK. Then go back to the task tab and you should see a screen similar to the next figure.



This means that the pizza order process has successfully created a user task for fozzie. If you look in the Tomcat console you’ll see the logging lines we added to the tasks. Now you can choose if you want fozzie to complete the task or you can wait a minute and the task must be completed by kermit.  When the task is completed, the 2 messages are tweeted about the pizza order process that look like this.



Activiti, a full-blown BPMS
Now that you have seen Activiti Engine in action, just a few words about the tools surrounding the engine that make Activiti a full-blown BPMS.



The business process life cycle starts with Activiti Modeler, the Web 2.0 based modeling tool which allows you to drag and drop BPMN 2.0 constructs on a modeling pane to create your process model in your favorite browser.

Next tool down the line is Activiti designer, an Eclipse based development tool to add technical detail to the model, like for example binding a Java class to a service activity. It provides unit test functionality to run the BPMN 2.0 process you are working on, on the Activiti engine as well as support to export business archive files to run on the engine when you are all done.

When processes finally run on there you need Activiti Probe. Probe provides administrating capabilities by providing a view on the process engine environment at any given moment, showing the status of the engine from a technical standpoint.

For the end users of the business process application there is Activiti Explorer as you have seen in the pizza order example. With Explorer workflow is implemented. Users get to see the list of tasks they can work on and processes they are allowed to start.

The last tool in the Activiti stack is Cycle. Activiti Cycle facilitates the collaboration between business folks and IT in a way that fits with how people work in practice. It is basically a tool that focuses on the big picture. This means that all aspects of business related content, software development and software deployment are taken into account. With Cycle, Activiti created a glue "layer" between the different tools and repositories that are used in business process modeling projects as you can see in the tool overview picture.

All these tools of Activiti deserve an article for themselves to demonstrate the functionality they provide to support the business process lifecycle. As mentioned before, we will publish a few of these articles in the coming weeks/months, so check them out if Activiti impresses you as much as it impresses us and until that time order some pizzas!

About the Authors

Tijs Rademakers

Tijs works as a software architect for Atos Origin and is the lead developer of the Activiti Designer project. His focus is on BPM and open source Java development. Tijs is the author of the Open Source ESBs in Action book and is a frequent speaker on Java conferences

Twitter

Ron van Liempd

As a software architect at Atos Origin Ron focuses on translating the business needs into IT realizations. His focus is on business rules management systems and BPM and works on the Activiti Designer project.

Twitter

Tijs and Ron are currently writing the Manning book 'Activiti in Action' and blog about it on http://bpmn20inaction.blogspot.com/.

References

•    Find out more about BPMN 2.0 at http://www.bpmn.org/
•    Detailed information about working with Activiti: http://www.activiti.org/userguide/index.html
•    On Activiti Designer: http://docs.codehaus.org/display/ACT/Activiti+BPMN+2.0+Eclipse+Plugin
•    Good intro on Activiti Cycle: http://www.bpm-guide.de/2010/08/27/activiti-cycle-explained/
•    Cool demo of Activiti Explorer on the iPad: http://www.youtube.com/user/BPMmobile2010?feature=mhum

And Activiti Modeler on the iPad as well: http://www.signavio.com/en/company/blog/128-bpmn-process-modeling-on-the-ipad.html

AttachmentSize
pizza-order.zip10.29 KB
Published at DZone with permission of its author, Tijs Rademakers.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Claude Lalyre replied on Mon, 2010/11/22 - 5:06am

I think that SCXML (statechat definition) does the same thing....

Tijs Rademakers replied on Tue, 2010/11/23 - 9:25am

SCXML is a state machine and Activiti is in its foundation also a state machine, however Activiti provides the following things on top: 1. BPMN 2.0 compliancy (a language where business people also know to model in) 2. Workflow or human task support 3. Out-of-the-box Spring integration 4. Web service support 5 Support for sending mails 6. A full-blown tool stack with a modeler, designer, admin and collaboration tool. So I think there are a couple of differences ;-) Tijs

Fadi Al-katout replied on Wed, 2011/10/26 - 2:43pm

Great article, but I have a question about the users and groups in activity, is it possible to make activity work with my own users and groups that I already have in my application? 

 Thanks in advance 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.