JavaBeat

  • Home
  • Java
    • Java 7
    • Java 8
    • Java EE
    • Servlets
  • Spring Framework
    • Spring Tutorials
    • Spring 4 Tutorials
    • Spring Boot
  • JSF Tutorials
  • Most Popular
    • Binary Search Tree Traversal
    • Spring Batch Tutorial
    • AngularJS + Spring MVC
    • Spring Data JPA Tutorial
    • Packaging and Deploying Node.js
  • About Us
    • Join Us (JBC)
  • Privacy

Developing the Business Logic in Activiti

July 31, 2011 by Krishna Srinivasan Leave a Comment

This article is based on Activiti in Action , to be published on Fall 2011. It is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) eBooks and pBooks. MEAPs are sold exclusively through Manning.com. All pBook purchases include free PDF, mobi and epub. When mobile formats become available all customers will be contacted and upgraded. Visit Manning.com for more information. [ Use promotional code ‘java40beat’ and get 40% discount on eBooks and pBooks ]

also read:

  • Java Tutorials
  • Java EE Tutorials
  • Design Patterns Tutorials
  • Java File IO Tutorials

Developing the Business Logic

Introduction

In this article, we will focus on the business logic tasks that need to be implemented in a loan request process. The part of the loan request process we will cover in this article can be seen in figure 1.

First, we take a look at the script task and, then, we implement the Java service tasks. Finally, at the end of this section, we show the BPMN 2.0 XML we created so far and test the process with Eclipse.

Implementing a script task

The first task we encounter when we look at the loan request process is the script task. We will use it to implement the credit check.

Understanding script tasks in BPMN 2.0

The script task is an official BPMN 2.0 construct. In figure 1, you can see the symbol that BPMN 2.0 prescribes for the script task. It has the same rectangular shape as a regular service task. The little graphical marker in the upper left corner indicates that the task is a script task. The script that is defined in the task will be executed by the process engine—in our case, the Activiti engine. An analyst will define the task in the model and a developer has to implement the script with a language the engine can interpret. When execution of the script is completed, the script task itself will also complete, and the engine moves toward the next execution.

Important BPMN 2.0 attributes of the script task construct are scriptFormat and script. The scriptFormat attribute defines the format of the script and is mandatory. The optional script attribute contains the actual script that needs to be executed. If no script is defined, the task will just complete without doing anything.

Working with Script tasks in Activiti

For the Activiti engine to execute the coded script, the scriptFormat attribute must have a value that is compatible with the JSR-223, Scripting for the Java platform. The scripting languages that come with engines that conform to the JSR are numerous. We will name a just a few of the languages that are supported: Groovy, Jaskell, AWK, Python, JavaScript, and PHP. For more information, you can check out the JSR-223 specification at http://jcp.org/en/jsr/detail?id=223.

Because, by default, the Groovy jar is shipped with the Activiti distribution, we will use Groovy as the script language in the Check Credit task. If you want to use another JSR-223-compatible scripting engine, it is sufficient to add the corresponding jar file to the classpath and use the appropriate name in the script task configuration.

All the process variables are standard accessible in the script, because the script has access to the execution that arrives in the task. You can, for example, use the process variable inputArray, an array of integers, as shown below.
[code lang=”html”]<script>
Sum = 0;
for ( i in inputArray ) {
sum += i
}
</script>[/code]
That’s great stuff isn’t it? Besides reading variables, it is also possible to set process variables in a script by using an assignment statement. In the example above, the sum variable will be stored as a process variable after the script has been executed. If you want to avoid this default behavior, script-local variables can be used as well. In Groovy, the keyword def must be used so def sum = 0. In that case, the sum variable is not stored as a process variable.

An alternative way to set process variables is done by explicitly using the execution variable that is available in the script task.
[code lang=”html”]
<script>
def bookVar = "BPMN 2.0 with Activiti"
execution.setVariable("bookName", bookVar);
</script>[/code]
As a final remark on some limitations while coding script, it is worth mentioning that some keywords cannot be used as variable names—out, out:print, lang:import, context, and elcontext—because these are reserved keywords within Activiti and Groovy. Back to our process—back to the Check Credit script task.

Implementing the credit check script task

The implementation of the Check Credit task is pretty straightforward. The Loan Sharks Company agrees to let a customer pass the credit check when his or her income is bigger than the requested loan amount. Check out listing 1 to see the BPMN 2.0 XML fragment that defines the script task.

Listing 1 Script task BPMN fragment
[code lang=”html”]<scriptTask id="checkCredit" scriptFormat="groovy"> #A
<script>
out:print "Checking credit for " + name + "\n"; #1
creditCheckOk = false; #2
if(income > loanAmount){
creditCheckOk = true;
}
out:print "Credit checked for " + name + "\n";
</script>
</scriptTask>
#A The Groovy script language declaration
#1 Using the process variable ‘name’
#2 Defining a new process variable[/code]
In the script, we use the name variable (#1) to print some logging on the console. Then, we create a new process variable (#2) that will hold the information about the credit check in a Boolean. As long as our loan requestor’s income is bigger than the requested loan amount, the credit check will pass (#3).

Using script tasks on the Activiti Engine

To use the Groovy scripting engine on the standard Tomcat distribution that is installed with the Activiti installation, it’s necessary to copy the Groovy groovy-all-version.jar to the tomcat/lib directory. You can find the Groovy jar in the examples/activiti-engine-examples/libs-runtime directory of your Activiti distribution.

We have our first script task in the process under control—moving on to the java service tasks.

Defining Java service tasks

Now, we are going to implement the Check Risk task and the Create Application task. The Check Risk task will return a Boolean indicating whether the risk of lending money to a certain customer is too high or not. The Create Application task gathers all the information produced so far in a LoanApplication Java bean and puts this bean on the process as a variable so we have easy access to it in the subsequent steps of the process.

Implementing the risk check Java service task

The Check Risk task is implemented with a Java service task. Typically, these kinds of checks contain valuable logic for the business and change frequently. To give more control to the business in maintaining this kind of logic and enable possible reuse for other applications, business rule engines are often used. Now, we’ll use the Java service task to implement the check.

To illustrate how the risk check behaves, see listing 2.

Listing 2 Implementation of the Check Risk service task
[code lang=”java”]public class RiskChecker implements JavaDelegation { #A
public void execute(DelegateExecution execution) {
String name = (String) execution.getVariable("name");
System.out.println("Checking loan risk for : " + name);
boolean riskCheckOk = false;
if(!name.equalsIgnoreCase("Evil Harry")) { #1
riskCheckOk = true;
}
execution.setVariable("riskCheckOk", riskCheckOk); #2
}
}
#A Java service task standard interface
#1 Checking the name process variable
#2 Setting riskCheckOk variable on execution[/code]
In the execute method of the RiskChecker class, we check if the name of our loan applicant is Evil Harry (#1). We have to do this because the Loan Sharks Company knows Harry well enough to be sure that, whenever money is lent to him, nobody ever sees it back again. Harry will not pass the risk check! Don’t forget to set the riskCheckOk variable on the execution (#2) so we can use it later.

Implementing the create application Java service task

The Create Application service task gathers all the data that was produced in the previous steps in one object instance and puts that instance in the process as a process variable. Code listing 3 displays the service task implementation.

Listing 3 The Create Application service task implementation
[code lang=”java”]public class ApplicationCreator implements JavaDelegation {
public void execute(DelegateExecution execution) {
LoanApplication la = new LoanApplication(); #1
la.setCreditCheckOk((Boolean) execution
.getVariable("creditCheckOk")); #2
la.setRiskCheckOk((Boolean)
execution.getVariable("riskCheckOk"));
la.setCustomerName((String)
execution.getVariable("name"));
la.setRequestedAmount((Integer)
execution.getVariable("loanAmount"));
la.setEmailAddres((String)
execution.getVariable("emailAddress"));
execution.setVariable("loanApplication", la); #3
}
}
#1 Creating the LoanApplication bean
#2 Retrieving process variable to populate the bean
#3 Setting the LoanApplication instance on the process[/code]
In the execute method of the ApplicationCreator Java service task class, we create the LoanApplication instance (#1). Remember that this object has to implement the Serializable interface; otherwise, the Activiti engine will not be able to store its state in the process database. The values with which we populate the object (#2) are retrieved, on one hand, from the start form we will build and, on the other, the ones that have been set by the two checks we implemented in the earlier tasks. At the end, don’t forget to store the variable in the execution (#3).

We saw that the Check Credit script task and the Check Risk service task can be executed in parallel so we take a look at that the parallel gateway BPMN construct.

Explaining the parallel gateway

The parallel gateway is used in the loan request process model to indicate that the check tasks can be executed independently and in parallel. The parallel gateway concept in BPMN is used to model concurrency in a process. It allows the execution path of a process to fork into multiple paths of execution or join multiple incoming paths together to a single point. The functionality of the parallel gateway is based on the incoming and outgoing sequence flow.

  • join—All concurrent executions arriving at the parallel gateway wait in the gateway until an execution has arrived for each incoming sequence flow. Then the process continues past the joining gateway.
  • fork—All outgoing sequence flows are followed in parallel, creating one concurrent execution for each sequence flow.

An important difference with, for example, the exclusive gateway is that the parallel gateway does not evaluate conditions.

Now that we have our business logic together and have talked about the control flow surrounding it, we will take a look at the resulting BPMN 2.0 XML.

Creating the BPMN 2.0 XML file

To be able to test this part of the loan request process, we are going to build a BPMN 2.0 XML file with all the tasks covered so far. We saw in the BPMN 2.0 model that the Check Credit task and the Check Risk task should be executed in parallel. The construct that is used in BPMN to realize this kind of behavior is the parallel gateway.

Take a look at code listing 4 to see how our loan request process looks like so far.

Listing 4 BPMN 2.0 XML for the partly finished loan request process
[code lang=”xml”]<process id="loanrequest" name="Process to handle a loan request">
<startEvent id=’theStart’ />
<sequenceFlow id=’flow1′ sourceRef=’theStart’
targetRef=’fork’ />
<parallelGateway id="fork" /> #1
<sequenceFlow id=’flow2′ sourceRef="fork"
targetRef="checkCredit" />
<sequenceFlow id=’flow3′ sourceRef="fork" #2
targetRef="checkRisk" />
<scriptTask id="checkCredit" scriptFormat="groovy">
<script>
out:print "Checking credit for " + name + "\n";
creditCheckOk = false;
if(income < loanAmount){
creditCheckOk = true;
}
out:print "Credit checked for " + name + "\n";
</script>
</scriptTask>
<sequenceFlow id=’flow4′ sourceRef="checkCredit" #3
targetRef="join" />
<serviceTask id="checkRisk"
activiti:class="org.bpmnwithactiviti.chapter4.RiskChecker">
</serviceTask>
<sequenceFlow id=’flow5′ sourceRef="checkRisk"
targetRef="join" />
<parallelGateway id="join" /> #4
<sequenceFlow id=’flow6′ sourceRef="join"
targetRef="createApplication" />
<serviceTask id="createApplication"
activiti:class="org.bpmnwithactiviti.
[CA]chapter4.ApplicationCreator">
</serviceTask>
<sequenceFlow id=’flow7′ sourceRef="createApplication"
targetRef="wait" />
<userTask id=’wait’ /> #5
<sequenceFlow id=’flow8′ sourceRef="wait"
targetRef="theEnd" />
<endEvent id=’theEnd’ />
</process>
#1 Declaration of the parallel gateway fork
#2 One execution flow forking to a task
#3 After the task is finished join again
#4 Declaration of the parallel gateway join
#5 User task for testing purposes[/code]
After the start of the process, execution is brought to the parallel gateway (#1) by the first sequence flow. Execution forks and the checkCredit script task and checkRisk Java service task are executed concurrently (#2). After both these tasks have finished, the process is guided by the outgoing sequence flows of the tasks (#3) toward the join (#4). After that, the process continues normally with the createApplication task. The user task that is defined at the bottom of the xml (#5) is purely there for testing purposes. Without it, the process ends after the createApplication task and we cannot query it anymore to see the value of the process variables.

NOTE In listing 4, we didn’t use the definitions element. We just leave it out to be brief but remember that it is needed when we want to execute the BPMN 2.0 XML, whether we use it standalone in a unit test or on Activiti engine after a deployment.

All the constructs used in the process so far can be easily tested in a unit test in Eclipse. It is good practice to test as early as possible. We want to get rid of possible bugs in the BPMN before we are deploying on Activiti engine, so let’s give our process a spin!

Testing the process with Eclipse

We will use the ActivitiRule class to get the RuntimeService and use the @Deployment annotation to deploy our process. Take a look at the code in code listing 5 to see how it is done.

Listing 5 Testing the loan request process tasks
[code lang=”java”]public class LoanRequestTest {
@Rule
public ActivitiRule activitiRule =
new ActivitiRule("activiti.cfg-mem.xml"); #A
@Test
@Deployment(resources={"chapter4/loanrequest_firstpart.bpmn20.xml"})
public void creditCheckTrue() {
Map<String, Object> processVariables = #1
ProcessInstance pi = activitiRule.getRuntimeService()
.startProcessInstanceByKey(
"loanrequest", processVariables);
processVariables = activitiRule.getRuntimeService()
.getVariables(pi.getId());
LoanApplication la = (LoanApplication) #2
processVariables.get("loanApplication"); #2
assertEquals(true, la.isCreditCheckOk());
assertEquals(true, la.isRiskCheckOk()); #3
}
}
#A Configures Activiti to use the in-memory database
#1 Starts the process with a variables map
#2 Retrieves the LoanApplication process variable
#3 Tests the process variable[/code]
As you can see, we don’t use the default activiti.cfg.xml but take a configuration file that uses the in-memory H2 database. We deploy the loan request BPMN 2.0 XML that we defined in listing 4 to do some early testing. Since we didn’t implement a start form for the process yet, we have to start the process with some programmatically defined variables (#1). If we don’t do this the service tasks will run into NullPointerExceptions.

Let’s start a loan request for Miss Piggy. As you can see Miss Piggy earns more money than she wants to borrow so passing the checks shouldn’t be any problem. You can see as well that she has an email address; this address can be used later to implement the email service task. After the process is started, we get the loanApplication variable out of the process (#2). This variable is set by the CreateApplication task. If the tests (#3) succeed, it means that all the tasks have run successfully.

Summary

You have seen how script tasks and Java service tasks can perform the logic that is needed to handle a loan request. We have seen how to implement a bit of business logic and test it with a simple unit test. We also covered two kinds of gateway that BPMN 2.0 provides, to control the paths of execution in a process, the exclusive gateway and the parallel gateway.

Filed Under: Java Tagged With: Activiti

Adding More Logic with the Email Task in Activiti

June 17, 2011 by Krishna Srinivasan Leave a Comment

This article is based on Activiti in Action , to be published on Fall 2011. It is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) eBooks and pBooks. MEAPs are sold exclusively through Manning.com. All pBook purchases include free PDF, mobi and epub. When mobile formats become available all customers will be contacted and upgraded. Visit Manning.com for more information. [ Use promotional code ‘java40beat’ and get 40% discount on eBooks and pBooks ]

also read:

  • Java Tutorials
  • Java EE Tutorials
  • Design Patterns Tutorials
  • Java File IO Tutorials

Introduction

When the employees of the Loan Shark Company decide not to approve of a loan request, the customer is informed by email. The email task is the last step of the loan approval process, as we can see in figure 1.

After this task is completed the process will finish.

NOTE The email task is not an official task of the BPMN 2.0 specification. It, therefore, doesn’t have a dedicated icon and is shown as a regular service task. Activiti uses the email task to enhance business processes that send emails to one or more recipients, including support for cc, bcc, and html content. It’s a bonus!

Before we can implement the email task in BPMN 2.0 XML and test it in Eclipse or run it later on Activiti engine for that matter, we need to set up a mail server first. We will use the Apache James project to do that. When our server is running, we will make a tiny process to test the email task and send Miss Piggy a message. This way, you can see how the email task works and make sure that the James environment is configured correctly.

Getting up and running with Apache James Mail server

Download Apache James from http://james.apache.org and unzip the file in a directory of choice. We are not going to do anything very secure in our loan request example, so we’ll just use the default setup. You can start the server by executing the run.sh or run.bat file in the james_install_dir/bin directory.

After the server is up and running smoothly in the background we need to add a user account so we have somebody to mail to from the process. Start a telnet session with localhost on port 4555; you can login with the preconfigured root user, password root. Then add a user with the following command:

adduser miss.piggy piggy

A user called miss.piggy is added with the email address miss.piggy@localhost and the password piggy. To check if Miss Piggy’s account is actually added, you can execute the listusers command to verify. Figure 2 gives a view on the telnet session to summarize things.

That’s all there is to it. The James mail server is configured correctly and waiting to receive mails on port 25. Back to Activiti!

Defining the email task

Now that our mail server is up and running smoothly, we are ready to define an email task in the BPMN 2.0 XML file. For detailed information concerning different configuration options for the email task within Activiti, you can check out the Activiti user guide. We will stick to the basics for the moment and create a simple standalone process that sends an email to the customer to test the mail server configuration. Let’s take a look at the BPMN 2.0 XML in listing 1.

Listing 1 Simple email task process to test the James configuration
[code lang=”xml”]<process id="simpleEmailProcess" >
<startEvent id="theStart" />
<sequenceFlow sourceRef="theStart" targetRef="sendMail" />
<serviceTask id="sendMail" activiti:type="mail"> #1
<extensionElements>
<activiti:field name="to">
<activiti:string>miss.piggy@localhost</activiti:string> #2
</activiti:field>
<activiti:field name="subject"> #3
<activiti:string>Hello ${name}!</activiti:string>
</activiti:field>
<activiti:field name="html"> #4
<expression>
<![CDATA[
<html>
<body>
Hello ${name},<br/><br/> #5
Your loan request has been denied.<br/><br/>
Kind regards,<br/>
The Loan Sharks Company.
</body>
</html>
]]>
</expression>
</activiti:field>
</extensionElements>
</serviceTask>
<sequenceFlow sourceRef="sendMail" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
#1 Defining the mail service task
#2 Declaring the recipient field
#3 Declaring a subject
#4 This mail has html content
#5 Using the process variable[/code]
The mail service task is defined by adding an Activiti-specific attribute to a regular service task (#1). The email address is defined in the to field (#2) and the subject is defined with the subject attribute (#3). The email address that we send in this example is hardcoded in the BPMN 2.0 XML. In a loan request, we want this property to be flexible because it depends on who is filing for a loan, so we use the expression attribute to define the address:

[code lang=”xml”]<activiti:field name="to" expression="${loanApplication.customerName}" />[/code]

The mail we use has html content (#4). You also can see that, in the email task, you have access to process variables; in this case, we use the name process variable to make the email personal (#5).

You can now run the process within Eclipse, but we need a mail server so we can test the email service task. Listing 2 shows an elegant way of writing a unit test for this.

Listing 2 Testing a process definition with a email service task
[code lang=”java”]public class MailTaskTest {
@Rule
public ActivitiRule activitiRule =
new ActivitiRule("activiti.cfg-mem-mail.xml"); #1
@Test
@Deployment(resources={"chapter4/testSimpleTextMail.bpmn20.xml"})
public void bookAvalaible() throws Exception {
Wiser wiser = new Wiser(); #2
wiser.setPort(25);
wiser.start();
activitiRule.getRuntimeService()
.startProcessInstanceByKey("simpleEmailProcess");
List messages = wiser.getMessages();
assertEquals(1, messages.size()); #3
WiserMessage message = messages.get(0);
MimeMessage mimeMessage = message.getMimeMessage();
assertEquals("Hello Miss Piggy!",
mimeMessage.getHeader("Subject", null));
wiser.stop();
}
}
#1 Starts engine with mail client
#2 Starts a test mail server
#3 Did we receive 1 email?
[/code]
Make sure that the mail server port in the activiti.cfg-mem-mail.xml file (#1) is configured for port 25. By default, Activiti expects the mail server to run on 5025, so we have to override the port by defining the following mail server.

<mail server=”localhost” port=”25″ />

The Activiti examples use a mail server that’s really great for unit testing and is called SubEtha SMTP (http://code.google.com/p/subethasmtp/). This mail server project provides a class named Wiser (#2), which can be used to start a mail server with just a few lines of code. And, when you want to check if an email has been sent to the mail server, you can use the getMessages method (#3). In this unit test, we validate if the subject of the email is the one we defined in the process definition of listing 1.

In addition to writing a unit test using the SubEtha mail server project, we can, of course, also use Apache James like we want to do for our loan request business process. You can use a similar unit test like the one we showed in code listing 2 but, instead of using SubEtha, you should start Apache James. To view the email, you can install an email client like, for example, Mozilla Thunderbird. James is using the default ports in the standard setup, so you only have to configure a Miss Piggy account running on localhost with port 25. The example email is shown in figure 3.

NOTE When you want to use the email task on the Tomcat distribution that Activiti ships with, you need to deploy two jars in the tomcat/lib directory; the mail.jar and the commons-mail.jar. Both the jars are available in the examples/activiti-engine-examples/libs-runtime directory of the Activiti distribution. Another important thing to remember is to set the port correctly in the activiti-cfg.xml file since, by default, it is listening on port 5025. You can find the Activiti configuration file that Tomcat uses in the tomcat/lib directory packaged in the activiti-cfg.jar.

What Activiti did with supplying the email task is demonstrate a showcase implementation of a custom and, therefore, not an official BPMN 2.0 task.

Summary

When the employees of the Loan Shark Company decide to not approve the loan request, an email is sent to inform the customer that the request has been denied.

Filed Under: Java Tagged With: Activiti

Creating an Activiti Development Environment

June 17, 2011 by Krishna Srinivasan Leave a Comment

This article is based on Activiti in Action , to be published on Fall 2011. It is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) eBooks and pBooks. MEAPs are sold exclusively through Manning.com. All pBook purchases include free PDF, mobi and epub. When mobile formats become available all customers will be contacted and upgraded. Visit Manning.com for more information. [ Use promotional code ‘java40beat’ and get 40% discount on eBooks and pBooks ]

also read:

  • Java Tutorials
  • Java EE Tutorials
  • Design Patterns Tutorials
  • Java File IO Tutorials

Introduction

In this article, you will be introduced into the different Activiti libraries you can use and setting up a Maven project structure.

Logging is an important vehicle to understand what’s going on in a complex framework as a process engine. We’ll see how we can tune the log levels for our needs. At the end, we’ll look at a couple of options you have to run the Activiti engine. But, first, it’s time to find out a little bit more about the Activiti library structure.

Getting familiar with the Activiti libraries

The Activiti distribution consists of several modules, including Activiti Modeler, Cycle, Probe, and Explorer. Each of these modules has its dependency and project structure. We’ll only focus on the Activiti Engine module, which provides the core component of the project.

But the Activiti engine also consists of at least two layers. The first layer, which provides core process engine logic, is the process virtual machine. The second layer is the engine, which provides the engine interfaces and implements the BPMN 2.0 specification. The engine and the process virtual machine are implemented in the same archive file, which can be found in the lib directory of the Activiti installation. In early versions of Activiti, the engine and process virtual machine layers were separated in different JARs but, for convenience reasons, the two layers were merged in one JAR in the current release.

An optional layer is the Spring container integration for the Activiti engine. This layer makes the Activiti engine available for use inside a Spring container and provides functionality to invoke Spring beans directly from service tasks. This layer is provided with the activiti-spring archive that is also available in the lib directory of the Activiti distribution. The 3 layers for the Activiti engine are shown in figure 1.

As you can see in figure 1, each layer of the Activiti engine adds a specific set of functionalities. Obviously, most of the process engine functionalities are provided by the Engine layer. The process virtual machine can be considered the foundational level of the Activiti engine, which provides a simple state or activity and transition model. The Spring layer adds the capability of running Activiti inside the Spring container with support for using Spring beans within service tasks and expressions.

Before we can use the Activiti engine in the development environment, the dependent libraries must also be available. Next, we show you a Maven-based project structure, which will provide you with the necessary dependencies. But you can also reference the library dependencies from the Activiti installation directory. Notice that you then have to run the setup first, because the setup script puts the libraries in right places of the workspace directory.

In the workspace directory, there are several projects created for the Engine, Spring, and other component examples. The runtime libraries can be found in the libs-runtime directory and the libraries necessary to test the examples are provided in the libs-test directory of every example project. If you don’t want to use Maven for your project you can retrieve the necessary libraries from here. But next up, we’ll see that a Maven project structure makes life a bit easier.

Mavenizing your Activiti project

Apache Maven can be considered the default choice for dependency management and project build management in general. And Activiti makes it very easy to set up your project with Maven. The examples in the Activiti distribution have a Maven structure and a pom.xml. But, let’s first create a Maven project for our example code with the following command.
[code lang=”java”]mvn archetype:generate -DgroupId=org.bpmnwithactiviti -DartifactId=bpmn-examples –
DinteractiveMode=false[/code]
This will create a standard Maven project layout with a base directory of bpmn-examples. A standard App Java class and an AppTest unit test are also generated but, since we won’t need those, you can delete them right away. The generated pom.xml in the root of the bpmn-examples directory needs some work because we have to add the Activiti dependencies. The full Maven pom.xml is shown in listing 1.

Listing 1 A standard Maven configuration for an Activiti project
[code lang=”java”]<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.bpmnwithactiviti</groupId>
<artifactId>bpmn-examples</artifactId>
<version>1.0 </version>
<packaging>jar</packaging>
<name>BPMN 2.0 with Activiti – Examples</name>
<properties>
<activiti-version>5.0</activiti-version>
</properties>
<dependencies>
<dependency>
<groupId>org.activiti</groupId> #1
<artifactId>activiti-engine</artifactId> #1
<version>${activiti-version}</version> #1
</dependency>
<dependency>
<groupId>com.h2database</groupId> #2
<artifactId>h2</artifactId> #2
<version>1.2.132</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>Activiti</id> #3
<url>http://maven.alfresco.com/nexus/content/
[CA]repositories/activiti</url>
</repository>
</repositories>
</project>
#1 Gets the Engine and PVM archives
#2 H2 database driver
#3 Alfresco Maven repository for Activiti[/code]
The Maven namespace declarations are left out of the listing to make the configuration more readable. To include the Activiti engine and PVM libraries we only have to include the activiti-engine dependency (#1). This dependency will also get all the third-party libraries which are necessary to run the Activiti engine. Notice that in this Maven configuration we didn’t include the Activiti Spring module.

To be able to test with an in-memory H2 database, we must also add the H2 database dependency (#2). The H2 database dependency also provides the database driver to connect to both the standalone H2 database provided with the Activiti distribution as well as the in-memory H2 database.

Because the Activiti Engine dependency is not yet available from a central Maven repository, we also need to add the Alfresco Maven repository for the Activiti project (#3). If you are using the Eclipse development tool, you can now run the mvn eclipse:eclipse command, which will create the necessary Eclipse project and classpath files. But, of course, similar Maven archetypes are available for IntelliJ IDEA and other IDEs.

Now all the Java libraries needed to run the Activiti Engine are available inside the IDE. Now let’s discuss how we can tune logging in the Activiti Engine.

Logging in the Activiti Engine

Logging statements can help a lot when you are debugging but are also essential for getting good error descriptions from a production system. When you are using multiple open-source frameworks in one project, you may run into different logging systems. And that’s exactly the case with Activiti and Spring.

Activiti uses the standard Java java.util.logging API, also known as JDK 1.4 logging, and Spring uses Apache commons logging. This means that, by default, it’s not possible to have one logging configuration file. Luckily there’s the SLF4J (Simple Logging Façade for Java—www.slf4j.org) framework, which can translate logging statements from different frameworks into the logging statement of your choice.

We use Log4J (http://logging.apache.org/log4j/1.2) as the logging system of choice, but you can easily change this to, for example, Apache Commons Logging if you would like to. SLF4J provides support for Log4J as well as Apache Commons Logging. For the JDK 1.4 logging statements to be translated by SLF4J to Log4J, we have to do some coding.

We’ll be using a lot of unit tests to work with the Activiti BPM platform and, therefore, the next code snippet shows the AbstractTest class we’ll be extending from in a unit test to initialize our logging framework.
[code lang=”java”]public abstract class AbstractTest {
@BeforeClass
public static void routeLoggingToSlf4j() {
LogUtil.readJavaUtilLoggingConfigFromClasspath();
java.util.logging.Logger rootLogger =
LogManager.getLogManager().getLogger("");
Handler[] handlers = rootLogger.getHandlers();
for (int i = 0; i < handlers.length; i++) {
rootLogger.removeHandler(handlers[i]);
}
SLF4JBridgeHandler.install();
}
}[/code]
This abstract unit test class ensures that the logging.properties for the JDK 1.4 logging of the Activiti Engine are read from the classpath. By default the JDK 1.4 logging reads the log configuration of your JAVA_HOME/lib/logging.properties and that’s not what we want. In our logging.properties the log level is set to FINEST to get all logging information out of the Activiti Engine when we want to.

Next in the code snippet, the log handlers are removed from the java.util.logging.Logger class because, otherwise, the JDK 1.4 logging framework would still perform the logging. At the end, we can invoke the SLF4J bridge, which will direct all JDK 1.4 logging output to SLF4J. And, since we have the SLF4J Log4J library on the classpath, we can now define the log level of the Activiti Engine, the Spring framework, and other external frameworks in a standard log4j.xml file.

This means we can define a log level of DEBUG when we want to do some debugging, and we can set the level to ERROR when we don’t want extra information logged in our unit tests. With our logging configuration in place, let’s discuss the options we have to run the Activiti Engine.

Developing and testing with the Activiti Engine

The primary component you have to deal with when designing and developing BPMN 2.0 processes with Activiti is the Activiti Engine. The engine is your entry point to, for example, deploy new process definitions, start new process instances, and query for user tasks. But what are our options to run the Activiti Engine during development? In the following subsections we discuss the following 3 options:

  1. Runing the Activiti Engine in the JVM with an in-memory database (H2).
  2. Runing the Activiti Engine in the JVM with a standalone database (H2).
  3. Runing the Activiti Engine on an application server (Apache Tomcat) with a standalone database (H2).

Running the Activiti Engine with an in-memory database

A good way to test a BPMN 2.0 process is to run the Activiti Engine inside the Java Virtual Machine with an in-memory database. In this deployment scenario, the unit tests can also be run within a continuous build environment without the need for external server components. The whole process engine environment runs from within the JVM and the unit test. Figure 2 shows this way of deployment in a graphical overview.

This deployment alternative is used because it’s the easiest to use from within an IDE. Next up, we look at another option, which is to use a standalone database.

Running the Activiti Engine with a standalone database

If you want to work with process definitions or instances that are deployed and running on a standalone environment, another deployment alternative is needed. You must be able to run the Activiti Engine connected to a standalone database. This enables possibilities to, for example, query the standalone database for specific running process instances. In a schematic way this type of deployment looks like figure 3.

An Activiti Engine can be created from within a unit test and the H2 database that installed and started as part of the Activiti installation setup used as the process engine database. This type of setup is not very suitable for unit testing but can be handy for integration testing where you also want to use the Activiti Explorer and Probe together in a process you create from your local development environment.

Running the Activiti Engine on Apache Tomcat with a standalone database

The previous deployment options are very useful for unit and integration testing. But, eventually, we’ll want to deploy our business processes on a production-like environment and do some basic testing there also. This means that we can’t start an Activiti Engine from within a unit test because it runs on a separate application server environment.

What we can do is use the REST API provided with the Activiti Engine to interact with the process engine. And the deployment of a new process definition must then be done via Activiti Probe or an Ant script by deploying a Business ARchive (BAR) file. Let’s have a look at this alternative in figure 4.

In an environment like the one shown in figure 4, the need for unit tests is typically low, because the deployment alternatives we discussed earlier are more likely to be used for unit and integration testing. But there will still be a need to communicate with the process engine when tools like the Activiti Explorer or Probe don’t provide all the information you need or in cases where you want to communicate with the process engine from other applications. The REST API provides a great way to implement the communication necessary.

Summary

The Activiti Engine provides a service task that invokes a Java class, and we looked at how to use this BPMN construct within a BPMN 2.0 process definition. This provides a powerful feature if there’s a need for process logic inside your business process.

Filed Under: Java Tagged With: Activiti

Follow Us

  • Facebook
  • Pinterest

As a participant in the Amazon Services LLC Associates Program, this site may earn from qualifying purchases. We may also earn commissions on purchases from other retail websites.

JavaBeat

FEATURED TUTORIALS

Answered: Using Java to Convert Int to String

What is new in Java 6.0 Collections API?

The Java 6.0 Compiler API

Copyright © by JavaBeat · All rights reserved