Keep informed?
Subscribe for our newsletter now!

Build your own activiti task explorer with CDI and JSF 2

Outdated!

Please note that this blog post is outdated, since we forked Activiti in March 2013 and started a new Open Source BPM project called camunda BPM (www.camunda.org). You will find this topic and loads of more best practices, blueprints etc. there, so you should just have a look :-)


A couple of days ago, I promised that I would unveil “first class activiti support in Java EE 6”. Today I will give you a first taste. But keep in mind: what I am showing below is cool, but: it is by far not the coolest thing we have currently lined up. So stay tuned.

Many of our customers embed Activiti in their own applications, in many instances to support task or case management. In such a situation we do not use activiti explorer but implement task management ourselves, tightly integrated in our application. Today I want to show how we can use the activiti-cdi module to implement human task management. The activiti-cdi module is an activiti contribution by camunda (I am the module lead) and we have made huge progress over the last months. In this article I showcase some of the features of the current trunk, which will be released with activiti 5.8 (released on October 1st). We will see that in order to create JSF task forms, in simple cases we do not even have to write Java code. At the same time, we have the full power of Java EE 6 at our fingertips, if we need more. So today, we are going to build JSF based task management in under an hour!

Let’s start with an example

So without further introduction, let’s just jump right into it. We start by creating a simple BPMN 2.0 process:

So a very basic twitter quality assurance process, I submit a tweet (which starts the process), my manager has a look at it, if he decides that the tweet is in compliance with company policy, it is published, if not, it is rejected.

Project setup and activiti configuration

Now let’s start implementing this with activiti and Java EE 6. First step: create a maven project. I need activiti-cdi and a couple of other dependencies:

<dependencies>
	<dependency>
		<groupId>org.activiti</groupId>
		<artifactId>activiti-cdi</artifactId>
		<version>5.8-SNAPSHOT</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
		<version>3.0.3.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>javax</groupId>
		<artifactId>javaee-api</artifactId>
		<version>6.0</version>
		<scope>provided</scope>
	</dependency>
</dependencies>

Activiti-cdi transitively pulls in activiti-engine and spring-beans. spring-context is required because we want to configure the process engine using spring and want to look up container (Jboss AS 7) managed resources in JNDI:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- activiti configuration for jboss AS 7 -->

	<!-- lookup the JTA-Transaction manager -->
	<bean id="transactionManager" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiName" value="java:jboss/TransactionManager"></property>
		<property name="resourceRef" value="true" />
	</bean>

	<!-- process engine configuration -->
	<bean id="processEngineConfiguration" class="org.activiti.cdi.CdiJtaProcessEngineConfiguration">
		<property name="dataSourceJndiName" value="java:jboss/datasources/ExampleDS" />
		<property name="databaseType" value="h2" />
		<property name="transactionManager" ref="transactionManager" />
		<property name="transactionsExternallyManaged" value="true" />
		<property name="databaseSchemaUpdate" value="true" />
	</bean>

</beans>

We could also configure activiti differently, for example programmatically or using seam3-config. In that case we would not need spring. But hey, why not use spring for configuration – we have to give them something, right?

At startup activiti-cdi will try to boot the process engine. To accomplish this it will lookup a bean implementing the “ProcessEngineLookup” interface. We provide one, extending LocalProcessEngine lookup, which will create a spring-configured process engine:

public class ProcessEngineConfiguration extends LocalProcessEngineLookup {
}

So if I do not want to use Spring I could initialize a process engine programmatically here. Finally, we create a file called processes.xml where we list the processes we want to deploy:

<?xml version="1.0" encoding="utf-8" ?>
<!-- list the processes to be deployed -->
<processes>
	<process resource="diagrams/twitterProcess.bpmn20.xml" /> 
</processes>

Ok, now setup is complete and we are good to go!

Displaying a list of deployed processes:

To start off, we want to display a list of processes which are deployed, which could look like this:

Ok, so admittedly we could improve the layout :) but that can be delegated to any UI expert who is familiar with HTML and CSS.
Activiti cdi makes the repository service available for injection, so implementing this is easy:

public class ProcessList {

  @Inject
  private RepositoryService repositoryService;

  @Produces
  @Named("processDefinitionList")
  public List getProcessDefinitionList() {
    return repositoryService.createProcessDefinitionQuery()
            .list();
  }
}

To display the list, we create a simple jsf page:

<h:dataTable value="#{processDefinitionList}" var="v_process">
	<h:column>
		<f:facet name="header">Key</f:facet>
		#{v_process.key} 
	</h:column>
	<h:column>
		<f:facet name="header">Name</f:facet>
		#{v_process.name}
	</h:column>
	<h:column>
		<f:facet name="header">Version</f:facet>
		#{v_process.version}
	</h:column>
	<h:column>
		<f:facet name="header">Action</f:facet>
		<h:outputLink value="#{formService.getStartFormData(v_process.id).formKey}">
			Start
			<f:param name="processDefinitionKey" value="#{v_process.key}"></f:param>
		</h:outputLink>
	</h:column>
</h:dataTable>

The last column is the most interesting; let’s look at it in more detail. We are generating a link. We retrieve the activiti:formKey specified on the start event:

<startEvent id="startevent1" name="Start" 
                           activiti:formKey="taskForm_newTweet.jsf” />

And add a GET parameter, in this case the key of the process definition. So this will generate the following link:

taskForm_newTweet.jsf?processDefinitionKey=tweetProcess

Starting the process

Ok, now we have to create the form which starts the process. The code looks like this:

<f:metadata>
<!-- bind the key of the process to be started -->
	<f:viewParam name="processDefinitionKey" />
</f:metadata>

<h1>New Tweet</h1>
<h:form>
	<table>
		<tr>
			<td>Your twitter account:</td>
			<td><h:inputText value="#{processVariables['twitterAccount']}" />					</td>
		</tr>
		<tr>
			<td>Tweet content:</td>
			<td><h:inputText value="#{processVariables['tweetContent']}" />
			</td>
		</tr>
		<tr>
			<td></td>
			<td><h:commandButton value="Submit"
							action="#{businessProcess.startProcessByKey(processDefinitionKey)}" />
			</td>
		</tr>
	</table>
</h:form>

In the f:metadata section, we „bind“ the GET parameter, we added to the link. This allows us to reference the value provided in the URL. We do this when starting the process using the commandButton in the last line:

#{businessProcess.startProcessByKey(processDefinitionKey)}

I am referencing a bean named businessProcess here. This bean is the “heart piece” of activiti-cdi and is built for simplifying the implementation of user tasks (for a deeper discussion, see the last section of this post). For now, it is enough to understand that the difference between businessProcess.startProcessByKey(String) and  runtimeService.startProcessByKey(String) is that in addition to starting the referenced process, the business process bean flushes any process variables I have created in the current unit of work, either by setting them explicitly through businessProcess.setVariable(‘key’, value) or using the processVariables bean which is a java.util.Map<String,Object>. This is exactly what we do in the above case, using #{processVariables['twitterAccount']}.

What is cool here is that

  • we are not required to write a backing bean which collects the process variables and starts the process,
  • it is very simple to access additional (domain) data,
  • we could use a sequence of forms as a Java EE 6 conversation (e.g. a Wizard), in that case activiti cdi would cache the process variables in the conversation,
  • the f:metadata and submit part of the form are completely generic, so it is easy to write a facelets template which makes this reusable!

Creating a tasklist

Creating a tasklist is very similar to displaying a list of process instances. Again we start with the backing beans.

public class TaskList {

  @Inject
  private CurrentUser currentUser;

  @Inject
  private TaskService taskService;

  @Produces
  @Named("personalTaskList")
  public List getPersonalTaskList() {
     return taskService.createTaskQuery()
           .taskAssignee(currentUser.getUsername())
           .list();
  }

}

Where the current user is another simple bean:

@Named
@SessionScoped
public class CurrentUser implements Serializable {

  private String username = "kermit";

  public void setUsername(String username) { this.username = username; }
  public String getUsername() { return username; }

}

The current user could be populated at login, in this case, we add an input field above the tasklist to be able to display tasks for arbitrary users:

<h1>List of assigned Tasks</h1>
<h:form>
	<p>
		Tasks for user: 
		<h:inputText value="#{currentUser.username}"> 
			<f:ajax render="taskList" event="keyup" />
		</h:inputText>
	</p>			
	<h:dataTable value="#{personalTaskList}" var="v_task" id="taskList">
		<h:column>
			<f:facet name="header">Task Name</f:facet>
			#{v_task.name}
		</h:column>
		<h:column>
			<f:facet name="header">Description</f:facet>
			#{v_task.description}
		</h:column>
		<h:column>
			<f:facet name="header">Action</f:facet>
			<h:outputLink
				value="#{formService.getTaskFormData(v_task.id).formKey}">
				Complete
				<f:param name="taskId" value="#{v_task.id}"></f:param>
			</h:outputLink>
		</h:column>
	</h:dataTable>
</h:form>

The “complete” link is implemented in the same fashion as the “start” link in the start process list. This brings us to the last step, implementing task forms.

Implement task forms with JSF 2


Again, we reference the jsf form in the process:

<userTask id="reviewTweet" name="Review Tweet" 
                         activiti:assignee="kermit" activiti:formKey="taskForm_reviewTweet.jsf"></userTask>

The following is a jsf task form. Notice again how everything but the form fields themselves is completely generic and could be made reusable using templates:

<f:metadata>
	<f:viewParam name="taskId" />
	<!-- start working on the usertask and starting a conversation -->
	<f:event type="preRenderView" listener="#{businessProcess.startTask(taskId, true)}" />
</f:metadata>

<h1>#{task.name}</h1>
<p><em>#{task.description}</em></p>

<h:form>
<table>
		<tr>
			<td>Twitter Account:</td>
			<td><h:outputText value="#{processVariables['twitterAccount']}" /></td>
		</tr>
		<tr>
			<td>Tweet content:</td>
			<td><h:outputText value="#{processVariables['tweetContent']}" />
			</td>
		</tr>
		<tr>
			<td>Approve?</td>
			<td><h:selectBooleanCheckbox value="#{processVariables['approved']}" /></td>			</tr>				
		<tr>
			<td>Comment:</td>
			<td><h:inputTextarea value="#{processVariables['comment']}" /></td>
		</tr>
		<tr>
			<td></td>
			<td>
				<h:commandButton value="Submit" action=#{businessProcess.completeTask(true)}" />
			</td>
		</tr>
	</table>
</h:form>

Let’s look at the f:metadata section in more detail. We are calling businessProcess.startTask(taskId, true), passing in the id of the task retrieved from the view parameters. By calling this method we are basically saying to the businessProcess bean “We are now working on the task with id 10”. As we do not like to repeat ourselves, we say that we also want to start a conversation (if none is already active). So the businessProcess bean will “remember” that we are working on that task for the lifetime of the current conversation. That means that while this conversation lasts, we are able to retrieve process variables which are resolved in the execution of the current task. As I wrote earlier, a conversation spans multiple HTTP requests, so this is particularly useful if we use AJAX requests or have a sequence of multiple forms representing a single usertask.

In this case we are ending the task / conversation using the submit button: businessProcess.completeTask(true). (true=end conversation) This also flushes the process variables we have changed to the execution. So behind the scenes taskService.completeTask(id, variables) is called, with the difference that activiti-cdi “knows” which task to complete and which process variables to flush, so that we do not have to do that ourselves, for each task we implement.

And that’s it! Now we have activiti usertasks in JSF! You can check out the complete project from our camunda fox SVN:
https://svn.camunda.com/fox/trunk/demo/activiti5-cdi-jsf-task-management/

The Deal with the “businessProcess” Bean

Now that we have seen an example of how to use activiti-cdi to be implement usertasks, I want to add a few more details about the “businessProcess” bean we used. The general concept is outlined in the following graphic:

The business process bean can be in two states: “associated” or not “associated”. If it is not associated, we can use it to create transient process variables, which are cached. If we call startProcess() later the process variables are flushed to the new process instance. If the business process bean is associated with a task or an execution, we can use it to retrieve process variables located in that execution. If we change the value of the process variables, the changes are not immediately flushed to the execution; on the contrary, only if we successfully complete the current unit of work, either through completeTask() or signalExecution(), the variables are flushed. So in a sense the businessProcess bean behaves like a JPA entity manager.

This allows us to scope the business process bean to a logical unit of work in our application. By default it will associate with the CDI conversation context. If the conversation context is not available i.e. during the invocation of a MDB or during the processing of a JAX-RS request, it will associate with the CDI request context. If no such context is available i.e. when the activiti job executor makes the call, it associates with the current Thread.

So to sum this up, the business process bean allows us to manage two items of “state”, (1) we can  use it to remember which task / execution we are working on and (2) which process variables we have modified. Whenever we implement something like a usertask, we have to think about how to manage that state, so I hope that activiti-cdi provides a usable generic solution to this.

These are some of the concepts we treat in our new training Java Enterprise Applications & Activiti.

The next blog will be about how you can skip the part named “Project setup and activiti configuration” above. That is possible on camunda fox – our brand new enterprise bpm platform based on Activiti.

Daniel Meyer

About Daniel Meyer, camunda BPM Project Lead

Daniel Meyer is project lead for camunda BPM. He is passionate about BPM with a particular focus on process automation and process engines. His mission is to deliver the best possible experience to developers who want to use BPM technology in their applications. He is a Java EE 6 aficionado and believes in polyglot technology stacks based on open standards.

Already read?

New Whitepaper: The Zero-Code BPM Myth

Zalando process orders in camunda BPM

18 Responses

Leave a reply

Powered by WP Hashcash