JBoss.org Community Documentation

- Prev
- Next

## Chapter 12. Human Tasks

An important aspect of business processes is human task management. While some of the work performed in a process can be executed automatically, some tasks need to be executed by human actors. jBPM supports a special human task node inside processes for modeling this interaction with human users. This human task node allows process designers to define the properties related to the task that the human actor needs to execute, like for example the type of task, the actor(s), the data associated with the task, etc. jBPM also includes a so-called human task service, a back-end service that manages the life cycle of these tasks at runtime. This implementation is based on the WS-HumanTask specification. Note however that this implementation is fully pluggable, meaning that users can integrate their own human task solution if necessary.

To have human actors participate in your processes, you first need to (1) include human task nodes inside your process to model the interaction with human actors, (2) integrate a task management component (like for example the WS-HumanTask based implementation provided by jBPM) and (3) have end users interact with a human task client to request their task list and claim and complete the tasks assigned to them. Each of these three elements will be discussed in more detail in the next sections.

## 12.1. Human tasks inside processes

jBPM supports the use of human tasks inside processes using a special user task node (as shown in the figure above). A user task node represents an atomic task that needs to be executed by a human actor. [Although jBPM has a special user task node for including human tasks inside a process, human tasks are considered the same as any other kind of external service that needs to be invoked and are therefore simply implemented as a domain-specific service. Check out the chapter on domain-specific services to learn more about how to register your own domain-specific services.]

A user task node contains the following properties:

- Id: The id of the node (which is unique within one node container).

- Name: The display name of the node.

- TaskName: The name of the human task.

- Priority: An integer indicating the priority of the human task.

- Comment: A comment associated with the human task.

- ActorId: The actor id that is responsible for executing the human task. A list of actor id's can be specified using a comma (',') as separator.

- GroupId: The group id that is responsible for executing the human task. A list of group id's can be specified using a comma (',') as separator.

- Skippable: Specifies whether the human task can be skipped, i.e., whether the actor may decide not to execute the task.

- Content: The data associated with this task.

- Swimlane: The swimlane this human task node is part of. Swimlanes make it easy to assign multiple human tasks to the same actor. See the human tasks chapter for more detail on how to use swimlanes.

- On entry and on exit actions: Action scripts that are executed upon entry and exit of this node, respectively.

- Parameter mapping: Allows copying the value of process variables to parameters of the human task. Upon creation of the human tasks, the values will be copied.

- Result mapping: Allows copying the value of result parameters of the human task to a process variable. Upon completion of the human task, the values will be copied. A human task has a result variable "Result" that contains the data returned by the human actor. The variable "ActorId" contains the id of the actor that actually executed the task.

You can edit these variables in the properties view (see below) when selecting the user task node, or the most important properties can also be edited by double-clicking the user task node, after which a custom user task node editor is opened, as shown below as well.

In many cases, the parameters of a user task (like for example the task name, actorId, priority, etc.) can be defined when creating the process. You simply fill in value of these properties in the property editor. It is however likely that some of the properties of the human task are dependent on some data related to the process instance this task is being requested in. For example, if a business process is used to model how to handle incoming sales requests, tasks that are assigned to a sales representative could include information related to that specific sales request, like its unique id, the name of the customer that requested it, etc. You can make your human task properties dynamic in two ways:

- #{expression}: Task parameters of type String can use #{expression} to embed the value of the given expression in the String. For example, the comment related to a task might be "Please review this request from user #{user}", where user is a variable in the process. At runtime, #{user} will be replaced by the actual user name for that specific process instance. The value of #{expression} will be resolved when creating human task and the #{...} will be replaced by the toString() value of the value it resolves to. The expression could simply be the name of a variable (in which case it will be resolved to the value of the variable), but more advanced MVEL expressions are possible as well, like for example #{person.name.firstname}. Note that this approach can only be used for String parameters. Other parameters should use parameter mapping to map a value to that parameter.
- Parameter mapping: You can map the value of a process variable (or a value derived from a variable) to a task parameter. For example, if you need to assign a task to a user whose id is a variable in your process, you can do so by mapping that variable to the parameter ActorId, as shown in the following screenshot. [Note that, for parameters of type String, this would be identical to specifying the ActorId using #{userVariable}, so it would probably be easier to use #{expression} in this case, but parameter mapping also allow you to assign a value to properties that are not of type String.]

### 12.1.1. User and group assignment

Tasks can be assigned to one specific user. In that case, the task will show up on the task list of that specific user only. If a task is assigned to more than one user, any of those users can claim and execute this task.

Tasks can also be assigned to one or more groups. This means that any user that is part of the group can claim and execute the task. For more information on how user and group management is handled in the default human task service, check out the user and group assignment.

### 12.1.2. Data mapping

Human tasks typically present some data related to the task that needs to be performed to the actor that is executing the task and usually also request the actor to provide some result data related to the execution of the task. Task forms are typically used to present this data to the actor and request results.

#### 12.1.2.1. Task parameters

Data that needs to be displayed in a task form should be passed to the task, using parameter mapping. Parameter mapping allows you to copy the value of a process variable to a task parameter (as described above). This could for example be the customer name that needs to be displayed in the task form, the actual request, etc. To copy data to the task, simply map the variable to a task parameter. This parameter will then be accessible in the task form (as shown later, when describing how to create task forms).

For example, the following human task (as part of the humantask example in jbpm-examples) is assigned to a sales representative that needs to decide whether to accept or reject a request from a customer. Therefore, it copies the following process variables to the task as task parameters: the userId (of the customer doing the request), the description (of the request), and the date (of the request).

#### 12.1.2.2. Task results

Data that needs to be returned to the process should be mapped from the task back into process variables, using result mapping. Result mapping allows you to copy the value of a task result to a process variable (as described above). This could for example be some data that the actor filled in. To copy a task result to a process variable, simply map the task result parameter to the variable in the result mapping. The value of the task result will then be copied after completion of the task so it can be used in the remainder of the process.

For example, the following human task (as part of the humantask example in jbpm-examples) is assigned to a sales representative that needs to decide whether to accept or reject a request from a customer. Therefore, it copies the following task results back to the process: the outcome (the decision that the sales representative has made regarding this request, in this case "Accept" or "Reject") and the comment (the justification why).

### 12.1.3. Swimlanes

User tasks can be used in combination with swimlanes to assign multiple human tasks to the same actor. Whenever the first task in a swimlane is created, and that task has an actorId specified, that actorId will be assigned to (all other tasks of) that swimlane as well. Note that this would override the actorId of subsequent tasks in that swimlane (if specified), so only the actorId of the first human task in a swimlane will be taken into account, all others will then take the actorId as assigned in the first one.

Whenever a human task that is part of a swimlane is completed, the actorId of that swimlane is set to the actorId that executed that human task. This allows for example to assign a human task to a group of users, and to assign future tasks of that swimlame to the user that claimed the first task. This will also automatically change the assignment of tasks if at some point one of the tasks is reassigned to another user.

To add a human task to a swimlane, simply specify the name of the swimlane as the value of the "Swimlane" parameter of the user task node. A process must also define all the swimlanes that it contains. To do so, open the process properties by clicking on the background of the process and click on the "Swimlanes" property. You can add new swimlanes there.

The new BPMN2 Eclipse editor will support a visual representation of swimlanes (as horizontal lanes), so that it will be possible to define a human task as part of a swimlane simply by dropping the task in that lane on the process model.

### 12.1.4. Examples

The jbpm-examples module has some examples that show human tasks in action, like the evaluation example and the humantask example. These examples show some of the more advanced features in action, like for example group assignment, data passing in and out of human tasks, swimlanes, etc. Be sure to take a look at them for more details and a working example.

## 12.2. Human task service

As far as the jBPM engine is concerned, human tasks are similar to any other external service that needs to be invoked and are implemented as a domain-specific service. Check out the chapter on domain-specific services for more detail on how to include a domain- specific service in your process. Because a human task is an example of such a domain- specific service, the process itself contains a high-level, abstract description of the human task that need to be executed, and a work item handler is responsible for binding this abstract tasks to a specific implementation. Using our pluggable work item handler approach, users can plug in the human task service that is provided by jBPM, as descrived below, or they may register their own implementation.

The jBPM project provide a default implementation of a human task service based on the WS-HumanTask specification. If you do not have the requirement to integrate an existing human task service, you can use this service. It manages the life cycle of the tasks (creation, claiming, completion, etc.) and stores the state of all the tasks, task lists, etc. It also supports features like internationalization, calendar integration, different types of assignments, delegation, deadlines, etc. It is implemented as part of the jbpm-human-task module.

The task service implementation is based on the WS-HumanTask (WS-HT) specification. This specification defines (in detail) the model of the tasks, the life cycle, and a lot of other features as the ones mentioned above. It is pretty comprehensive and can be found here.

### 12.2.1. Task life cycle

Looking from the perspective of the process, whenever a user task node is triggered during the execution of a process instance, a human task is created. The process will only leave that node when that human task has been completed or aborted.

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.

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. There, it is waiting for one of these actors to claim the task, indicating that he or she will be executing the task. Once a user has claimed a task, the status is changed to "Reserved". Note that a task that only has one potential actor will automatically be assigned to that actor upon creation of that task. After claiming the task, that 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". If the task could not be completed, the user can also indicate this using a fault response (possibly with fault data associated), in which case the status is changed to "Failed".

The life cycle explained above is the normal life cycle. The service also allows a lot of other life cycle methods, like:

- Delegating or forwarding a task, in which case it is assigned to another actor
- Revoking a task, so it is no longer claimed by one specific actor but reappears on the task list of all potential actors
- Temporarly suspending and resuming a task
- Stopping a task in progress
- Skipping a task (if the task has been marked as skippable), in which case the task will not be executed

### 12.2.2. Linking the human task service to the jBPM engine

The human task service needs to be integrated with the jBPM engine just like any other external service, by registering a work item handler that is responsible for translating the abstract work item (in this case a human task) to a specific invocation of a service. We have implemented this work item handler (org.jbpm.process.workitem.wsht.WSHumanTaskHandler in the jbpm-human-task module), so you can register this work item handler like this:

    StatefulKnowledgeSession ksession = ...;

    ksession.getWorkItemManager().registerWorkItemHandler("Human Task", new WSHumanTaskHandler());

If you are using persistence, you should use the CommandBasedWSHumanTaskHandler instead (org.jbpm.process.workitem.wsht.CommandBasedWSHumanTaskHandler in the jbpm-human-task module), like this:

    StatefulKnowledgeSession ksession = ...;

    ksession.getWorkItemManager().registerWorkItemHandler("Human Task", new CommandBasedWSHumanTaskHandler());

By default, this handler will connect to the human task service on the local machine on port 9123. You can easily change the address and port of the human task service that should be used by by invoking the setConnection(ipAddress, port) method on the WSHumanTaskHandler.

The communication between the human task service and the process engine, or any task client, is done using messages being sent between the client and the server. The implementation allows different transport mechanisms being plugged in, but by default, Mina (http://mina.apache.org/) is used for client/server communication. An alternative implementation using HornetQ is also available.

### 12.2.3. Interacting with the human task service

The human task service exposes various methods to manage the life cycle of the tasks through a Java API. This allows clients to integrate (at a low level) with the human task service. Note that end users should probably will not interact with this low-level API directly but rather use one of the more user-friendly task clients (see below) that offer a graphical user interface to request task lists, claim and complete tasks, etc. These task clients internally interact with the human task service using this API as well. But the low-level API is also available for developers to interact with the human task service directly.

A task client (class org.jbpm.task.service.TaskClient) offers the following methods for managing the life cycle of human tasks:

    public void start( long taskId, String userId, TaskOperationResponseHandler responseHandler )

    public void stop( long taskId, String userId, TaskOperationResponseHandler responseHandler )

    public void release( long taskId, String userId, TaskOperationResponseHandler responseHandler )

    public void suspend( long taskId, String userId, TaskOperationResponseHandler responseHandler )

    public void resume( long taskId, String userId, TaskOperationResponseHandler responseHandler )

    public void skip( long taskId, String userId, TaskOperationResponseHandler responseHandler )

    public void delegate( long taskId, String userId, String targetUserId,

                          TaskOperationResponseHandler responseHandler )

    public void complete( long taskId, String userId, ContentData outputData,

                          TaskOperationResponseHandler responseHandler )

    ...

If you take a look a the method signatures you will notice that almost all of these methods take the following arguments:

- taskId: The id of the task that we are working with. This is usually extracted from the currently selected task in the user task list in the user interface.

- userId: The id of the user that is executing the action. This is usually the id of the user that is logged in into the application.

- responseHandler: Communication with the task service is asynchronous, so you should use a response handler that will be notified when the results are available.

When you invoke a message on the TaskClient, a message is created that will be sent to the server, and the server will execute the logic that implements the correct action.

The following code sample shows how to create a task client and interact with the task service to create, start and complete a task.

    TaskClient client = new TaskClient(new MinaTaskClientConnector("client 1",

        new MinaTaskClientHandler(SystemEventListenerFactory.getSystemEventListener())));

    client.connect("127.0.0.1", 9123);

    // adding a task

    BlockingAddTaskResponseHandler addTaskResponseHandler = new BlockingAddTaskResponseHandler();

    Task task = ...;

    client.addTask( task, null, addTaskResponseHandler );

    long taskId = addTaskResponseHandler.getTaskId();

    // getting tasks for user "bobba"

    BlockingTaskSummaryResponseHandler taskSummaryResponseHandler =

        new BlockingTaskSummaryResponseHandler();

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

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

    // starting a task

    BlockingTaskOperationResponseHandler responseHandler =

        new BlockingTaskOperationResponseHandler();

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

    responseHandler.waitTillDone(1000);

    // completing a task

    responseHandler = new BlockingTaskOperationResponseHandler();

    client.complete( taskId, "bobba".getId(), null, responseHandler );

    responseHandler.waitTillDone(1000);

### 12.2.4. User and group assignment

Tasks can be assigned to one specific user. In that case, the task will show up on the task list of that specific user only. If a task is assigned to more than one user, any of those users can claim and execute this task. Tasks can also be assigned to one or more groups. This means that any user that is part of the group can claim and execute the task.

The human task service needs to know what all the possible valid user and group ids are (to make sure tasks are assigned to existing users and/or groups to avoid errors and tasks that end up assigned to non-existing users). You need to make sure to register all users and groups before tasks can be assigned to them. This can be done dynamically.

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

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

    TaskServiceSession taskSession = taskService.createSession();

    // now register new users and groups

    taskSession.addUser(new User("krisv"));

    taskSession.addGroup(new Group("developers"));

The human task service itself does not maintain the relationship between users and groups. This is considered outside the scope of the human task service, as in general businesses already have existing services that contain this information (like for example an LDAP service). Therefore, the human task service also offers you to specify the list of groups that a user is part of, so this information can also be taken into account when for example requesting the task list or claiming a task.

For example, if a task is assigned to the group "sales" and the user "sales-rep" that is part of that group wants to claim that task, he should pass the fact that he is part of that group when requesting the list of tasks that he is assigned to as potential owner:

    List<String> groups = new ArrayList<String>();

    groups.add("sales");

    taskClient.getTasksAssignedAsPotentialOwner("sales-rep", groups, "en-UK", taskSummaryHandler);

The WS-HumanTask specification also introduces the role of an administrator. An administrator can manipulate the life cycle of the task, even though he might not be assigned as a potential owner of that task. By default, jBPM registers a special user with userId "Administrator" as the administrator of each task. You should therefor make sure that you always define at least a user "Adminstrator" when registering the list of valid users at the task service.

Future versions of jBPM will provide a callback interface that will simplify the user and group management. This interface will allow you to validate users and groups without having to register them all at the task service, and provide a method that you can implement to dynamically resolve the groups a user is part of (for example by contacting an existing service like LDAP). Users will then be able to simply register their implementation of this callback interface without having to provide the list of groupIds the user is part of for all relevent method invocations.

### 12.2.5. Starting the human task service

The human task service is a completely independent service that the process engine communicates with. We therefore recommend to start it as a separate service as well. The installer contains a command to start the task server (in this case using Mina as transport protocol), or you can use the following code fragment:

    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();

The task management component uses the Java Persistence API (JPA) to store all task information in a persistent manner. To configure the persistence, you need to modify the persistence.xml configuration file accordingly. We refer to the JPA documentation on how to do that. The following fragment shows for example how to use the task management component with hibernate and an in-memory H2 database:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>

    <persistence

        version="1.0"

        xsi:schemaLocation=

          "http://java.sun.com/xml/ns/persistence

           http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd

           http://java.sun.com/xml/ns/persistence/orm

           http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"

        xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xmlns="http://java.sun.com/xml/ns/persistence">

      <persistence-unit name="org.jbpm.task">

        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <class>org.jbpm.task.Attachment</class>

        <class>org.jbpm.task.Content</class>

        <class>org.jbpm.task.BooleanExpression</class>

        <class>org.jbpm.task.Comment</class>

        <class>org.jbpm.task.Deadline</class>

        <class>org.jbpm.task.Comment</class>

        <class>org.jbpm.task.Deadline</class>

        <class>org.jbpm.task.Delegation</class>

        <class>org.jbpm.task.Escalation</class>

        <class>org.jbpm.task.Group</class>

        <class>org.jbpm.task.I18NText</class>

        <class>org.jbpm.task.Notification</class>

        <class>org.jbpm.task.EmailNotification</class>

        <class>org.jbpm.task.EmailNotificationHeader</class>

        <class>org.jbpm.task.PeopleAssignments</class>

        <class>org.jbpm.task.Reassignment</class>

        <class>org.jbpm.task.Status</class>

        <class>org.jbpm.task.Task</class>

        <class>org.jbpm.task.TaskData</class>

        <class>org.jbpm.task.SubTasksStrategy</class>

        <class>org.jbpm.task.OnParentAbortAllSubTasksEndStrategy</class>

        <class>org.jbpm.task.OnAllSubTasksEndParentEndStrategy</class>

        <class>org.jbpm.task.User</class>

        <properties>

          <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>

          <property name="hibernate.connection.driver_class" value="org.h2.Driver"/>

          <property name="hibernate.connection.url" value="jdbc:h2:mem:mydb" />

          <property name="hibernate.connection.username" value="sa"/>

          <property name="hibernate.connection.password" value="sasa"/>

          <property name="hibernate.connection.autocommit" value="false" />

          <property name="hibernate.max_fetch_depth" value="3"/>

          <property name="hibernate.hbm2ddl.auto" value="create" />

          <property name="hibernate.show_sql" value="true" />

        </properties>

      </persistence-unit>

    </persistence>

The first time you start the task management component, you need to make sure that all the necessary users and groups are added to the database. Our implementation requires all users and groups to be predefined before trying to assign a task to that user or group. So you need to make sure you add the necessary users and group to the database using the taskSession.addUser(user) and taskSession.addGroup(group) methods. Note that you at least need an "Administrator" user as all tasks are automatically assigned to this user as the administrator role.

The jbpm-human-task module contains a org.jbpm.task.RunTaskService class in the src/test/java source folder that can be used to start a task server. It automatically adds users and groups as defined in LoadUsers.mvel and LoadGroups.mvel configuration files.

The jBPM installer automatically starts a human task service (using an in-memory H2 database) as a separate Java application. This task service is defined in the task-service directory in the jbpm-installer folder. You can register new users and task by modifying the LoadUsers.mvel and LoadGroups.mvel scripts in the resources directory.

## 12.3. Human task clients

### 12.3.1. Eclipse demo task client

The Drools IDE contains a org.drools.eclipse.task plugin that allows you to test and/or debug processes using human tasks. In contains a Human Task View that can connect to a running task management component, request the relevant tasks for a particular user (i.e. the tasks where the user is either a potential owner or the tasks that the user already claimed and is executing). The life cycle of these tasks can then be executed, i.e. claiming or releasing a task, starting or stopping the execution of a task, completing a task, etc. A screenshot of this Human Task View is shown below. You can configure which task management component to connect to in the Drools Task preference page (select Window -> Preferences and select Drools Task). Here you can specify the url and port (default = 127.0.0.1:9123).

Notice that this task client only supports a (small) sub-set of the features provided the human task service. But in general this is sufficient to do some initial testing and debugging or demoing inside the Eclipse IDE.

### 12.3.2. Web-based task client in jBPM Console

The jBPM console also contains a task view for looking up task lists and managing the life cycle of tasks, task forms to complete the tasks, etc. See the chapter on the jBPM console for more information.

- PrevChapter 11. Console
- Top of page
- Front page
- NextChapter 13. Domain-specific processes