How to create a custom WorkItem Handler in jBPM

In this second tutorial about jBPM WorkItemHandler we will discuss how to create a custom WorkItemHandler which can be used to plug into your BPMN process some complex Java logic.

A WorkItemHandler is a class that implements the org.kie.runtime.instance.WorkItemHandler interface. There are several built-in WorkItemHandler available in jBPM, for example, in this tutorial we have covered how to use  the built-in REST WorkItemHandler: How to use a REST WorkItem Handler in jBPM

Creating a custom WorkItemHandler

In order to add a custom WorkItemHandler you need to perform the following steps:

  1. Add a Work Item Definition (WID)
  2. Map the WIP with the actual Handler class in the kie-deployment-descriptor.xml
  3. Code the WorkItemHandler class

Let’s start from the first step.

The WID file is a mapping between user interactions with jBPM and the data that is passed to the work item handler.

jBPM tries to locate a *.wid file in two locations by default:

  • Within the project’s top-level global/ directory using the default name WorkDefinitions.wid file
  • Within the project’s src/main/resources/ directory.

As an example, we will add to a KJAR project a file CustomWorkDefinitions.wid under src/main/resources/ directory:

import org.drools.core.process.core.datatype.impl.type.StringDataType;

[
 [
 "name" : "HelloWIH",
 "parameters" : [
 "Message" : new StringDataType(),
 ],
 "displayName" : "HelloWIH",
 "icon" : "icon-info.gif"
 ]
]

Next, let’s define which Handler maps the “HelloWIH” in the kie-deployment-descriptor.xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<deployment-descriptor xsi:schemaLocation="http://www.jboss.org/jbpm deployment-descriptor.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <persistence-unit>org.jbpm.domain</persistence-unit>
  <audit-persistence-unit>org.jbpm.domain</audit-persistence-unit>
  <audit-mode>JPA</audit-mode>
  <persistence-mode>JPA</persistence-mode>
  <runtime-strategy>PER_PROCESS_INSTANCE</runtime-strategy>
  <marshalling-strategies/>
  <event-listeners/>
  <task-event-listeners/>
  <globals/>
  <work-item-handlers>
    <work-item-handler>
      <resolver>mvel</resolver>
      <identifier>new com.company.service.HelloItemHandler()</identifier>
      <parameters/>
      <name>HelloWIH</name>
    </work-item-handler>
  </work-item-handlers>
  <environment-entries/>
  <configurations/>
  <required-roles/>
  <remoteable-classes/>
  <limit-serialization-classes>true</limit-serialization-classes>
</deployment-descriptor>

Great, now if you check the Eclipse BPM palette, you will see that the HelloWIH Task is included in the Custom Tasks panel:

jbpm custom WorkItemHandler tutorial

Let’s add this Custom Task to our Driving License BPM process, so that we will notify to our Handler when the Process starts, passing as argument the “name” process variable:

jbpm custom WorkItemHandler tutorial

Within the I/O Settings of the Custom Task, we will set the Task name and we also include “name” as input and output:

jbpm custom WorkItemHandler tutorial

Great, we are done with our Custom Handler configuration. Lets’s code it.

Coding the WorkItemHandler

We will now switch to our Web application. In addition to the Spring Boot application class, we will include the following WorkItemHandler:

package com.company.service;

import org.drools.core.process.instance.WorkItemHandler;
import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemManager;
public class HelloItemHandler implements WorkItemHandler {

	@Override
	public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {
	    manager.abortWorkItem(workItem.getId());
	}

	@Override
	public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
	    
	    Object name = workItem.getParameter("name");
	    System.out.println("Hi " + name);

	    manager.completeWorkItem(workItem.getId(), null);
	}
}

The WorkItemHandler does nothing fancy, it just prints the value of the “name” parameter that has been passed by the process.

This process variable will be added during the start up of the process instance, as you can check from the Spring Boot Application class:

@SpringBootApplication
@RestController
public class Application  {

    @Autowired
    private ProcessService processService;
    @Autowired
    private RuntimeDataService runtimeDataService;
    @Autowired
    private UserTaskService userTaskService;
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @GetMapping("/hello")
    public ResponseEntity<String> sayHello(@RequestParam Integer age) throws Exception {


        // Provided as an example. Not actually needed by our process.
        Map<String, Object> vars = new HashMap<>();
        vars.put("name", "John Smith");

        Long processInstanceId = processService.startProcess("business-application-kjar-1_0-SNAPSHOT", "com.mastertheboss.LicenseDemo", vars);

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("age", age);

        List<TaskSummary> taskSummaries = runtimeDataService.getTasksAssignedAsPotentialOwner("john", new QueryFilter());

        taskSummaries.forEach(s->{
            Status status = taskSummaries.get(0).getStatus();
            if ( status == Status.Ready )
                userTaskService.claim(s.getId(), "john");
            userTaskService.start(s.getId(), "john");
            userTaskService.complete(s.getId(), "john", params);
        });

        return ResponseEntity.status(HttpStatus.CREATED).body("Task completed!");
    }

}

Depoying and running the custom WorkItemHandler

Start by installing on your local Maven repository the kjar project

$ cd business-application-kjar
$ mvn clean install

Then build, install and run the Spring Boot application service:

$ cd business-application-service
$ mvn clean install spring-boot:run

The application will start. You can now trigger the REST endpoint with a value for “age”, as required by the process:

$ curl http://localhost:8090/hello?age=14

You will see from your application logs that the process has started, the Custom Handler has been triggered and the Task has been completed:

Welcome to license check 
Hi John Smith
Enter you age John Smith
Thanks
Rejected

The source code for this example is availabe here: https://github.com/fmarchioni/mastertheboss/tree/master/jbpm/custom-wih