jbpm5 jbpm tutorial human task managementIn this tutorial we will continue our journey through jBPM5 exploring the Human Task  which is based on the WS-HumanTask specification

 


Many end-to-end business processes require human interactions with the process. For example, humans may be needed for approvals, exception management, or performing activities required to advance the business process.  jBPM supports a special human task node inside processes for modeling this interaction with human users.

In order to use human tasks inside your processes you need three components:

1) A Human task node
2) A Human Task Server (to be precise a task management component)
3) A Human Task Client


Release comparison: In jBPM 3 Task nodes are just a special kind of wait state node that lives in the same JVM as the process. In jBPM 5, you need a Task Server where task are registered and a Task Client which is used to interact with tasks.

It will be more clear with an example. Start a new jBPM project choosing to add a default example which includes Human Tasks management.
jbpm 5 tutorial human tasks
In this very simple example, we have two Human Task nodes.

jbpm 5 tutorial human tasks

By clicking on its properties we can see that the Tasks are assigned to the user John an Mary
jbpm 5 tutorial human tasks jbpm5
Looking at the code source, we have the minimal requirement to start the process.

package com.sample;

import org.drools.KnowledgeBase;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.runtime.StatefulKnowledgeSession;
import org.jbpm.test.JBPMHelper;

public class ProcessMain {

    public static final void main(String[] args) throws Exception {
        startUp();
        // load up the knowledge base
        KnowledgeBase kbase = readKnowledgeBase();
        StatefulKnowledgeSession ksession = JBPMHelper.newStatefulKnowledgeSession(kbase);
        // start a new process instance
        ksession.startProcess("com.sample.bpmn.hello");
        System.out.println("Process started ...");
    }

    private static KnowledgeBase readKnowledgeBase() throws Exception {
        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add(ResourceFactory.newClassPathResource("sample.bpmn"), ResourceType.BPMN2);
        return kbuilder.newKnowledgeBase();
    }
    
    private static void startUp() {
        JBPMHelper.startH2Server();
        JBPMHelper.setupDataSource();
        // please comment this line if you already have the task service running,
        // for example when running the jbpm-installer
        JBPMHelper.startTaskService();
    }
    
}

As you can see, this example project uses the jBPMHelper class. The jBPMHelper class can be used to getting started quickly with jBPM5. Let’s see in detail what these method provide:

This method starts the H2 in memory database where all process instances will be stored.

JBPMHelper.startH2Server();

This methods is used to set up a local datasource bound in the JNDI namespace jdbc/jbpm-ds
Inside the META-INF/persistence.xml you can find two persistence units named org.jbpm.persistence.jpa and org.jbpm.task which will be used to persist the process data
 JBPMHelper.setupDataSource();

Finally, this method is used to start a generic Task Service where all Task will be registered.

JBPMHelper.startTaskService();


In real world application you would rather create your own TaskService and adapt it to your process. Here’s a sample code which can be used to start a Task Service:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.jbpm.task");

TaskService taskService = new TaskService(emf, SystemEventListenerFactory.getSystemEventListener());

MinaTaskServer server = new MinaTaskServer( taskService );

Thread thread = new Thread( server );

thread.start();

Testing the process

 

Ok, now run the application. The process will be started and the first task will be assigned to user “john”. In order to interact with Tasks, switch to the Human Tasks View (Windows | Show view | Others | Drools tasks | Human Tasks View)

Enter user “john” and hit “Refresh”:

jbpm 5 tutorial human tasks jbpm5
The Task has been reserved to user John. In order to proceed, choose “Start” so that the Task will move to “In Progress” state, until the user has completed the Human Task.
When the user has finally completed the Task, choose “Complete”.
jbpm 5 tutorial human tasks jbpm5
At this point, the process execution will move to the next Human Task node which has been assigned to Mary as you can see from the following picture.

jbpm 5 tutorial human tasks jbpm5
Once you complete also this Task the process will reach the end state.

Please note that the life cycle explained above is the normal life cycle. The service also allows a lot of other life cycle methods. (See http://docs.jboss.org/jbpm/v5.2/userguide/ch.Human_Tasks.html#d0e3854) For example  the user can also indicate this using a fault response (possibly with fault data associated), in which case the status is changed to "Failed".


Understanding Human Task states

The human task itself usually has a complete life cycle itself as well. We will now shortly introduce this life cycle, as shown in the figure below. For more details, check out the WS-HumanTask specification.
jbpm 5 human task tutorial
Whenever a task is created, it starts in the "Created" stage. It usually automatically transfers to the "Ready" state, at which point the task will show up on the task list of all the actors that are allowed to execute the task.
If you have already assigned the task to one user (as in our example) then the Task will transition to the "Reserved" phase.
If you have not assigned the task to one actor, then the Task will stay in the "Ready" phase until an actor has claimed for it and then it will transition to the Reserved phase.


Once in the Reserved phase, the user can then at some point decide to start executing the task, in which case the task status is changed to "InProgress".

Finally, once the task has been performed, the user must complete the task (and can specify the result data related to the task), in which case the status is changed to "Completed"


 

Interacting with the Task programmatically

 

In real world applications you will probably require to interact with your Task programmatically, by creating your own Task client interfaces.

 

Connecting to the TaskService


The TaskClient api is not too complex. The first thing you will require is connecting to the TaskService

 TaskClient client = new TaskClient(new MinaTaskClientConnector("client 1", 
                new  MinaTaskClientHandler(SystemEventListenerFactory.getSystemEventListener())));
            client.connect("127.0.0.1", 9123);

What are MinaServer and MinaClient ? Apache MINA is a network application framework which helps users develop high performance and high scalability network applications easily.

Adjust the IP address to the machine where you have started the TaskService, which by default is bound on port 9123.


Browsing the TaskList

 
Once you have the TaskClient instance available, you can browse the Task assigned to a particular client. For example if we want to browse all Task assigned to user “john” using the en-UK format:

BlockingTaskSummaryResponseHandler taskSummaryResponseHandler =
               new BlockingTaskSummaryResponseHandler();

client.getTasksAssignedAsPotentialOwner("john", "en-UK", taskSummaryResponseHandler);

List<TaskSummary> tasks = taskSummaryResponseHandler.getResults();

 

for (TaskSummary task: tasks) {
      System.out.println(task.getId() + " " + task.getName() + " " + task.getStatus());
}



The method client.getTasksAssignedAsPotentialOwner will return all tasks which have a potential owner. If you want to retrieve all tasks (including also which are complete) you can use the following method:
client.getTasksOwned("john", "en-UK", taskSummaryResponseHandler);


Starting a Task

In order to start a specific taskid for the user john you would need to use the method start of the TaskClient:

BlockingTaskOperationResponseHandler responseHandler =

   new BlockingTaskOperationResponseHandler();

client.start( taskId, "john", responseHandler );

responseHandler.waitTillDone(1000); 

Completing a Task

In order to complete a specific taskid for the user john you would need to use the method complete of the TaskClient:

responseHandler = new BlockingTaskOperationResponseHandler();

client.complete( taskId, "john", null, responseHandler );

responseHandler.waitTillDone(1000);


Querying the Tasks

The methods getTasksAssignedAsPotentialOwner and getTasksOwned can be used to perform basic searches of the Tasks which are in charge for one particular user. Should you need a more complex search over the Task List you can use the query method of the TaskClient Api.

 

When using the query method of the TaskClient, you can issue queries using the Hibernate QL on the mapped entities

 

Using the query method requires a few parameters

 

public void query(String qlString,
     Integer size,
     Integer offset,
     QueryGenericResponseHandler responseHandler)

 

The qlString parameter is the Hibernate query

The size contains the total size of the elements retrieved

The offset is the initial offset (which can be used for paginating the data)

The responseHandler will hold the Resultset retrieved by the query.

 

Here's an example which returns all the Tasks whose name is "task1":


BlockingQueryGenericResponseHandler  responseHandler =
                new BlockingQueryGenericResponseHandler(); 

client.query("select count(t) from Task t left join t.names as name where name.text = 'Task1'",
                Integer.MAX_VALUE, 0,responseHandler);
           
List  tasks = responseHandler.getResults();

Here's another which returns a collection of Tasks, which are created by user "john" and are in status "Ready" or "Reserved":


BlockingQueryGenericResponseHandler  responseHandler =
                 new BlockingQueryGenericResponseHandler();

client.query(" from Task t where t.taskData.createdBy.id = 'john' and t.taskData.status in ('Ready', 'Reserved')",
            Integer.MAX_VALUE, 0,responseHandler);

List  tasks = responseHandler.getResults();

If you want to check the other properties of the org.jbpm.task.Task class you can have a look at GitHub repository:

0
0
0
s2smodern