Chapter 5. Advanced Process modeling

5.1. Process modeling options

You can create Processes in multiple ways:
Using one of the graphical editors
You can use two delivered graphical editors. Process Designer is available through Business Central and Eclipse Process Designer. See Red Hat JBoss BPM Suite User Guide for more information on how to use the editors.
Using an XML editor
You can use any XML or text editor to create a process specification using the BPMN2 XML schema.
Using the Process API
You can use the JBoss BPM Suite core API directly. The most important process model elements are defined in the packages org.jbpm.workflow.core and org.jbpm.workflow.core.node.

5.1.1. Process modeling using XML

The BPMN2 file must meet the BPMN2 schema. The file content comprises the following parts:
XML prolog
The XML prolog consists of the XML declaration and DTD declaration.
The process element
The process element defines process attributes and contains definitions of the process elements (nodes and connections).
BPMN diagram definition
The BPMNDiagram element contains definitions for visualization of the Process elements in the Process Diagram.

Example 5.1. BPMN2 example file

<?xml version="1.0" encoding="UTF-8"?>
<definitions id="Definition"
             targetNamespace="http://www.jboss.org/drools"
             typeLanguage="http://www.java.com/javaTypes"
             expressionLanguage="http://www.mvel.org/2.0"
             xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"Rule Task
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd"
             xmlns:g="http://www.jboss.org/drools/flow/gpd"
             xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
             xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
             xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
             xmlns:tns="http://www.jboss.org/drools">
  <process processType="Private" isExecutable="true" id="com.sample.hello" name="Hello Process" >

    <!-- nodes -->
    <startEvent id="_1" name="Start" />
    <scriptTask id="_2" name="Hello" >
      <script>System.out.println("Hello World");</script>
    </scriptTask>
    <endEvent id="_3" name="End" >
        <terminateEventDefinition/>
    </endEvent>

    <!-- connections -->
    <sequenceFlow id="_1-_2" sourceRef="_1" targetRef="_2" />
    <sequenceFlow id="_2-_3" sourceRef="_2" targetRef="_3" />
  </process>

  <bpmndi:BPMNDiagram>
    <bpmndi:BPMNPlane bpmnElement="com.sample.hello" >
      <bpmndi:BPMNShape bpmnElement="_1" >
        <dc:Bounds x="16" y="16" width="48" height="48" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_2" >
        <dc:Bounds x="96" y="16" width="80" height="48" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_3" >
        <dc:Bounds x="208" y="16" width="48" height="48" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_1-_2" >
        <di:waypoint x="40" y="40" />
        <di:waypoint x="136" y="40" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_2-_3" >
        <di:waypoint x="136" y="40" />
        <di:waypoint x="232" y="40" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

5.1.2. Process modeling using API

To be able to execute processes from within your application, you need to perform the following in your code:
  1. Create a Runtime Manager in your Execution Server.
    • Singleton: allows sequential execution of multiple instances in the one session
    • PerProcessInstance: allows you to create multiple process instances; every instance is created within its own session.
    • PerRequestSession: every external interaction with a process instances causes that the process session finishes and the process instance is re-created in a new session.
  2. Get a runtime context and create a session in it.
  3. Start a Process from the underlying Knowledge Base.
  4. Close the Runtime Manager.

Example 5.2. Process instantiation in a session of Per Process Instance Runtime Manager

import org.kie.api.runtime.manager.RuntimeManager;
import org.kie.api.runtime.manager.RuntimeManagerFactory.Factory;
import org.kie.api.runtime.manager.RuntimeEngine;
import org.kie.api.runtime.KieSession;
...
RuntimeManager manager =
    RuntimeManagerFactory.Factory.get()
        .newPerProcessInstanceRuntimeManager(environment);

RuntimeEngine runtime =
    manager.getRuntimeEngine(
        ProcessInstanceIdContext.get());

KieSession ksession = runtime.getKieSession();
// do something here, e.g.
ksession.startProcess(“org.jbpm.hello”);

manager.disposeRuntimeEngine(engine);
manager.close();

5.1.3. Process update

5.1.3.1. Process update

When updating a Process definition, the new Process definition must define an increased version number and an update policy: the update policy defines how to handle the running Process instances of the older Process definition. You can decide to apply on them one of the following strategies:
  • Abort: any running Process instances are aborted. If necessary, you can have the Process instance restarted using the new Process definition.
  • Transfer: any running Process instances are migrated to the new process definition: once the instance has been migrated successfully, it will continue its execution based on the updated process logic. For further information refer to Section 5.1.3.3, “Migrating a Process instance”.
Note that the older version of the Process definition remains in the repository as well as in the respective sessions. Therefore, the new process should have a different ID, though the name can remain the same, and you can use the version parameter to show when a Process is updated (the version parameter is just a String and is not validated).

Example 5.3. Process abort update

import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieSessionConfiguration;

// build kbase with the replace-version-1.bpmn process
        KieBase kbase = KieServices.Factory.get().newKieSessionConfiguration();
        kbase.addKnowledgePackages(getProcessPackages("replace-version-1.bpmn"));

        KieSession ksession = kbase.newStatefulKnowledgeSession();
        try {
            // start a replace-version-1.bpmn process instance
            ksession.startProcess("com.sample.process", Collections.<String, Object>singletonMap("name", "process1"));

            // add the replace-version-2.bpmn process and start its instance
            kbase.addKnowledgePackages(getProcessPackages("replace-version-2.bpmn"));
            ksession.startProcess("com.sample.process", Collections.<String, Object>singletonMap("name", "process2"));

            // signal all processes in the session to continue (both instances finish)
            ksession.signalEvent("continue", null);
        } finally {
            ksession.dispose();
        }

5.1.3.2. Process instance migration

Every Process instance contains complete runtime information that are relevant for the Process instance so that it can continue its execution after interruption. This information includes all data linked to the Process instance, such as variables, the current state in the Process diagram, information on the instance of the Element that is active.
A Process instance does not contain information that is not runtime relevant; The runtime data and state are linked to a particular Process using ID references, that represent the process logic that needs to be followed when executing the Process instance. This separation of Process definition and runtime state allows reuse of the Process definition across multiple Process instances and minimizes the size of the runtime state. Consequently, updating a running Process instance to an updated Process definition is a matter of changing the referenced Process ID to the new ID.
However, this does not take into account that the state of the Process instance (the variable instances and the node instances) might need to be migrated as well. In cases where the Process is only extended and all existing wait states are kept, this is pretty straightforward, the runtime state of the process instance does not need to change at all. However, it is also possible that a more sophisticated mapping is necessary. For example, when an existing wait state is removed, or split into multiple wait states, an existing process instance that is waiting in that state cannot simply be updated. Or when a new process variable is introduced, that variable might need to be initiated correctly so it can be used in the remainder of the (updated) process.

5.1.3.3. Migrating a Process instance

The WorkflowProcessInstanceUpgrader can be used to upgrade a workflow process instance to a newer process instance. Of course, you need to provide the process instance and the new process id. By default, jBPM will automatically map old node instances to new node instances with the same id. But you can provide a mapping of the old (unique) node id to the new node id. The unique node id is the node id, preceded by the node ids of its parents (with a colon in between), to uniquely identify a node when composite nodes are used (as a node id is only unique within its node container. The new node id is simply the new node id in the node container (so no unique node id here, simply the new node id). The following code snippet shows a simple example.

Example 5.4. Process transfer with custom active Element mapping

import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.process.ProcessInstance;
import org.kie.api.runtime.process.WorkflowProcessInstance;

// build kbase with the replace-version-1.bpmn process
        KieBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
        kbase.addKnowledgePackages(getProcessPackages("replace-version-1.bpmn"));

        KieSession ksession = kbase.newStatefulKnowledgeSession();
        try {
            // start two instances of the replace-version-1.bpmn process
            ProcessInstance pi = ksession.startProcess("com.sample.process", Collections.<String, Object>singletonMap("name", "process1"));
            ProcessInstance pi2 = ksession.startProcess("com.sample.process", Collections.<String, Object>singletonMap("name", "process2"));

            // add the replace-version-3.bpmn process to the kbase and start its instance
            kbase.addKnowledgePackages(getProcessPackages("replace-version-3.bpmn"));
            ksession.startProcess("com.sample.process2", Collections.<String, Object>singletonMap("name", "process3"));

            // upgrade: active nodes from the replace-version-1.bpmn process are mapped to the same nodes in the  process
            WorkflowProcessInstanceUpgrader.upgradeProcessInstance(ksession, pi.getId(), "com.sample.process2", null);

            // upgrade the process using custom mapping
            Map<String, Long> mapping = new HashMap<String, Long>();
            mapping.put("3", 8L);
            mapping.put("2", 7L);
            WorkflowProcessInstanceUpgrader.upgradeProcessInstance(ksession, pi2.getId(), "com.sample.process2", mapping);
            ksession.fireAllRules();

            // signal all processes they may continue (all of them finish)
            ksession.signalEvent("continue", null);

        } finally {
            ksession.dispose();
        }
If this kind of mapping is still insufficient, you can still describe your own custom mappers for specific situations. Be sure to first disconnect the process instance, change the state accordingly and then reconnect the process instance, similar to how the WorkflowProcessinstanceUpgrader does it.

5.1.4. Multi-threading

Technical multi-threading is what happens when multiple threads or processes are started on a computer, for example by a Java or C program. Logical multi-threading is what we see in a BPM process after the process reaches a parallel gateway, for example. From a functional standpoint, the original process splits in two processes that are executed in a parallel fashion.
The Process engine supports logical multi-threading; for example, in Processes that include a parallel Gateway. The logical multi-threading is implemented using one technical thread: A Process that includes logical multi-threading is executed in one technical thread. Avoiding technical multi-threadng prevents further implementation complexity as multiple technical threads of one Process instance need to communicate their state information to each other. While it might seem that technical multi-threading would bring significant performance benefits, the extra logic needed to make sure the threads can work together well may cancel out these benefits.
In general, the execution engine also executes actions in serial. For example, when the engine encounters a Script Task, it synchronously executes the script and waits for it to complete before continuing execution. Similarly, when a Process encounters a Parallel Gateway, it sequentially triggers each of the outgoing Flows. This is possible since execution is almost always instantaneous. Similarly, action scripts in a Process are also executed synchronously, and the engine waits for them to finish before continuing execution. That means, that if the execution needs to wait, for example, a Thread.sleep() call is being execution, the engine does not continue any execution — it remains blocked during the wait period.

5.1.4.1. Asynchronous execution

If a work item execution of a Task does not execute instantaneously, but needs to wait, for example, to receive a response from an external system, the service handler must handle your service asynchronously. The asynchronous handler only invokes the service and notifies the engine once the results are available. In the mean time, the process engine continues the execution of the process.
A typical example of a service that requires asynchronous invocation is a Human Task: The engine is not to wait until a human actor responds to the request but continue and process the result of the Task when it becomes available. The human task handler creates a new task on the task list of the assigned actor and the engine is then allowed to continue the execution: The handler notifies the engine asynchronously when the user completes the task.
To implement an asynchronous service handler, implement the actual service in a new thread using the executeWorkItem() method in the work item handler that allows the Process instance to continue its execution.

Example 5.5. Example of asynchronous service handling in Java

import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemHandler;
import org.kie.api.runtime.process.WorkItemManager;

public class MyServiceTaskHandler implements WorkItemHandler {

        

  public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {

    new Thread(new Runnable() {

      public void run() {

        // The main thread with the parent element execution
        }
    }).start();
  }

  public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {

  }
}
It is recommended to have your handler contact a service that executes the business operation, instead of performing the task, as failure of the business operation will not affect your process. This approach also provides greater flexibility when developing and reusing services.
For example, your human task handler can invoke the human task service to add a task to the service. To implement an asynchronous handler, you usually have to do an asynchronous invocation of the handler. This usually depends on the technology you use to do the communication and might be an asynchronous invocation of a web service, or sending a JMS message to the external service.
The Red Hat JBoss BPM Suite Job Executor
Red Hat JBoss BPM Suite, from 6.1 version, implements a special component, the Job Executor, to accommodate asynchronous execution. The Executor provides an environment independent from the process runtime environment for instantiation of asynchronous executions defined in a Command object.
In particular, the JBoss BPM Suite Job Executor provides advanced handling of common asynchronous execution operations, like error handling, retry, cancellation and history logging. You can continue to delegate work to a separate thread, as described above, in a custom implementation of WorkItemHandler and use the JBoss BPM Suite Job Executor to handle these operations for you.
The JBoss BPM Suite Job Executor works on instances of the Command interface. This interface implements a single method execute() that accepts the CommandContext data transfer object with serializable data. The Command instance should only contain the business logic to be executed and have no reference to the underlying process engine or runtime related data. At the minimum, the CommandContext should provide the businessKey - the unique identifier of the caller and callback - the fully qualified classname (FQCN) of the CommandCallback instance to be called on command completion. Of course, when executed as part of a process (WorkItemHandler), you will need to provide additional data like the workItem, processInstanceId and deploymentId.
The result for the execution is returned via an instance of the ExecutionResults class. As with the input data, the data provided by this class must also be serializable.
Business Central provides a way for you to view the current jobs within the system; to schedule them, cancel them, or view their history. Go to DeployJobs to access this screen. You can even create a new job by clicking on the New Job button.
The Asynchronous WorkItemHandler
Red Hat JBoss BPM Suite 6.1 provides an out of the box asynchronous WorkItemHandler that is backed by the JBoss BPM Suite Job Executor. All the features that the JBoss BPM Suite Executor delivers are available for background execution within a process instance. There are two ways to configure this AsyncWorkItemHandler class:
  1. As a generic handler where you provide the command name as part of the work item parameters. In Business Central while modeling a process, if you need to execute some work item asynchronously: specify async as the value for the TaskName property, create a data input called CommandClass and assign the FQCN of this CommandClass as the data input.
  2. As a specific handler which is created to handle a given type of work item, thus allowing you to register different instances of AsyncWorkItemHandler for different work items. Commands are most likely to be dedicated to a particular work item, which allows you to specify the CommandClass at registration time instead of requiring it at design time, as with the first approach. But this means that an additional CDI bean that implements WorkItemHandlerProducer interface needs to be provided and placed on the application classpath so that the CDI container can find it. When you are ready to model your process, set the value of the TaskName property to the one provided at registration time.
Configuring the JBoss BPM Suite Executor
The JBoss BPM Suite executor can be configured to allow fine tunning of its environment via the following system properties:
  1. org.kie.executor.disabled: true OR false - enable/disable the executor.
  2. org.kie.executor.pool.size: Integer. Specify the thread pool size for the executor, which by default is 1.
  3. org.kie.executor.retry.count: Integer. Specifies the default number of retries in case of an error executing a job. The default value is 3.
  4. org.kie.executor.interval: Integer. Specifies the time to wait between checking for waiting jobs. The default value is 3 seconds.
  5. org.kie.executor.timeunit: NANOSECONDS OR MICROSECONDS OR MILLISECONDS OR SECONDS OR MINUTES OR HOURS OR DAYS. Specifies the unit for the interval property. The default is SECONDS.

5.1.4.2. Multiple Sessions and persistence

The simplest way to run multiple Process instances is to run them in one knowledge session. However, it is possible to run multiple Process instances in different knowledge sessions or in different technical threads.
When using multiple knowledge session with multiple processes and adding persistence, use a database that allows row-level as well as table-level locks: There could be a situation when there are 2 or more threads running, each within its own knowledge session instance. On each thread, a Processs is being started using the local knowledge session instance. In this use case, a race condition exists in which both thread A and thread B have coincidentally simultaneously finished a Process instance. At this point, both thread A and B are commiting changes to the database. If row-level locks are not possible, then the following situation can occur:
  • Thread A has a lock on the ProcessInstanceInfo table, having just committed a change to that table.
  • Thread A wants a lock on the SessionInfo table in order to commit a change.
  • Thread B has the opposite situation: It has a lock on the SessionInfo table, having just committed a change.
  • Thread B wants a lock on the ProcessInstanceInfo table, even though Thread A already has a lock on it.
This is a deadlock situation which the database and application are not be able to solve, unless row-level locks are posible and enabled in the database and tables used.

5.1.5. Technical exceptions

Technical exceptions occur when a technical component of a Process acts in an unexpected way. When using Java-based systems, this often results in a Java Exception. As these exceptions cannot be handled using BPMN2, it is important to handle them in expected ways.
The following types of code might throw exceptions:
  • Code present directly in the process definition
  • Code that is not part of the product executed during a Process
  • Code that interacts with a technical component outside of the Process Engine
This includes the following:
  • Code in Element properties, such as the Script property of a Script Task element or in the definitions of the interception actions, that is, the onEntry and onExit properties
  • Code in WorkItemHandlers associated with task and task-type nodes

Code in Element properties

Exceptions thrown by code defined in Element properties can cause the Process instance to fail in an unrecoverable way. Often, it is the code that starts the Process that will end up throwing the exception generated by a Process without returning a reference to the Process instance. Such code includes for example the onEntry and onExit properties, Script defined for the Script Task, etc.
Therefore, it is important to limit the scope of the code in these Elements so that is operates only over Process variables. Using a scriptTask to interact with a different technical component, such as a database or web service has significant risks because any exceptions thrown will corrupt or abort the Process instance.
To interact with other systems, use task Elements, serviceTask Elements and other task-type Elements. Do not use the scriptTask nodes for these purposes.

Note

If the script defined in a scriptTask causes the problem, the Process Engine usually throws the WorkflowRuntimeException with information on the Process (refer to Section 5.1.5.1.5, “Extracting information from WorkflowRuntimeException”).

Code in WorkItemHandlers

WorkItemHandlers are used when your Process interacts with other technical systems (for more information on WorkItemHandlers refer to Section 4.14.1, “Work item definition”).
You can either build exception handling into your own WorkItemhandler implementations or wrap your implementation into the handler decorator classes (for examples and detailed information refer to Section 5.1.5.1.2, “Exception handling classes”). These classes include the logic that is executed when an exception is thrown during the execution or abortion of a work item:
SignallingTaskHandlerDecorator
catches the exception and signals it to the Process instance using a configurable event type when the executeWorkItem() or abortWorkItem methods of the original WorkItemHandler instance throw an exception. The exception thrown is passed as part of the event. This functionality can be also used to signal to an Event SubProcess defined in the Process definition.
LoggingTaskHandlerDecorator
logs error about any exceptions thrown by the executeWorkItem() and abortWorkItem() methods. It also saves any exceptions thrown to an internal list so that they can be retrieved later for inspection or further logging. The content and format of the message logged are configurable.
While the classes described above covers most cases involving exception handling as it catches any throwable objects, you might still want to write a custom WorkItemHandler that includes exception handling logic. In such a case, consider the following:
  • Does the implementation catch all exceptions the code could return?
  • Does the implementation complete or abort the work item after an exception has been caught or uses a mechanisms to retry the process later (in some cases, incomplete process instances might be acceptable)?
  • Does the implementation define any other actions that need to be taken when an exception is caught? Would it be beneficial to interact with other technical systems? Should a Sub-Process be triggered to handle the exception?

Important

If WorkItemManager to signals that the work item has been completed or aborted, make sure the signal is sent after any signals to the Process instance were sent. Depending on how your Process definition, calling WorkItemManager.completeWorkItem() or WorkItemManager.abortWorkItem() triggers the completion of the Process instance as these methods trigger further execution of the Process execution flow.

5.1.5.1. Technical exception examples

5.1.5.1.1. Service Task handlers
The example involves a Throwing Error Intermediate Event caught by an Error Event Sub-Process.
When the Throwing Error Intermediate Event throws the Error, the Process instance is interrupted:
  1. Execution of the Process instance stops: no other parts of the Process are executed.
  2. The Process instance finishes as ABORTED.
The Process starts with the Start event and continues to the Throw Exception Service Task. The Task produces an Exception, which is propagated as a Signal object through the Process instance and caught by the subStart event in the Exception Handler Event Sub-Process. The workflow continues to the Handle Exception Service Task and the Process instance finishes with the subEnd event.

Figure 5.1. Process with an exception handling Event Sub-Process

Parts of the BPMN2 definition of the example Process relevant for exception handling
 <itemDefinition id="_stringItem" structureRef="java.lang.String"/>                                                  1
<message id="_message" itemRef="_stringItem"/>                                                                       2

<interface id="_serviceInterface" name="org.jbpm.examples.exceptions.service.ExceptionService">
<operation id="_serviceOperation" name="throwException">
<inMessageRef>_message</inMessageRef>                                                                                2
</operation>
</interface>

<error id="_exception" errorCode="code" structureRef="_exceptionItem"/>                                              3

<itemDefinition id="_exceptionItem" structureRef="org.kie.api.runtime.process.WorkItem"/>                            4
<message id="_exceptionMessage" itemRef="_exceptionItem"/>                                                           4

<interface id="_handlingServiceInterface" name="org.jbpm.examples.exceptions.service.ExceptionService">
<operation id="_handlingServiceOperation" name="handleException">
<inMessageRef>_exceptionMessage</inMessageRef>                                                                       4
</operation>
</interface>

<process id="ProcessWithExceptionHandlingError" name="Service Process" isExecutable="true" processType="Private">
<!-- properties -->
<property id="serviceInputItem" itemSubjectRef="_stringItem"/>                                                       1
<property id="exceptionInputItem" itemSubjectRef="_exceptionItem"/>                                                  4

<!-- main process -->
<startEvent id="_1" name="Start" />
<serviceTask id="_2" name="Throw Exception" implementation="Other" operationRef="_serviceOperation">

<!-- rest of the serviceTask element and process definition... -->

<subProcess id="_X" name="Exception Handler" triggeredByEvent="true" >
<startEvent id="_X-1" name="subStart">
<dataOutput id="_X-1_Output" name="event"/>
<dataOutputAssociation>
<sourceRef>_X-1_Output</sourceRef>
<targetRef>exceptionInputItem</targetRef>                                                                            4
</dataOutputAssociation>
<errorEventDefinition id="_X-1_ED_1" errorRef="_exception" />                                                        3
</startEvent>

<!-- rest of the subprocess definition... -->

</subProcess>

</process>

1

The itemDefinition element defines a data structure used in the serviceInputItem property of the Process.

2

The message element (1st reference) defines a message that contains the String defined by the itemDefinition element on the line above. The interface element below then refers to the itemDefinition element (2nd reference) in order to define what type of content the service (defined by the interface) expects.

3

The error element (1st reference) defines an error that is used to trigger the Event SubProcess of the Process. The content of the error is defined by the itemDefintion element defined below the error element.

4

This itemDefinition element (1st reference) defines an item that contains a WorkItem instance. The message element (2nd reference) then defines a message that uses this item definition to define its content. The interface element below that refers to the message definition (3rd reference) in order to define the type of content that the service expects.
In the Process element itself, a property element (4th reference) that contains the initial itemDefinition. This allows the Event SubProcess to store the error it receives in that property (5th reference).
5.1.5.1.2. Exception handling classes
The serviceTask tasks use the org.jbpm.bpmn2.handler.ServiceTaskHandler class as its task handler class unless the serviceTask defines a custom WorkItemHandler implementation.
To catch and handle any technical exceptions a WorkItemHandler of a task might throw, wrap or decorate the handler class with a SignallingTaskHandlerDecorator instance.

Important

When sending a signal of an event to the Process Engine, consider the rules for signaling process events:
  • Error events are signaled by sending an Error-errorCode attribute value value to the session.
  • Signal events are signaled by sending the name of the signal to the session.
  • If you wanted to send an error event to a Boundary Catch Error Event, the error type should be of the format: "Error-" + $AttachedNodeID + "-" + $ERROR_CODE. For example, Error-SubProcess_1-888 would be a valid error type.
    However, this is NOT a recommended practice because sending the signal this way bypasses parts of the boundary error event functionality and it relies on internal implementation details that might be changed in the future. For a way to programmatically trigger a boundary error event when an Exception is thrown in WorkItemHandler see this KnowledgeBase article.

Example 5.6. Using SignallingTaskHandlerDecorator

The ServiceTaskHandler calls the ExceptionService.throwException() method to throw an exception (refer to the _handlingServiceInterface interface element in the BPMN2).
The SignallingTaskHandlerDecorator that wraps the ServiceTaskHandler sends to the Process instance the error with the set error code.
import java.util.HashMap;
import java.util.Map;

import org.jbpm.bpmn2.handler.ServiceTaskHandler;
import org.jbpm.bpmn2.handler.SignallingTaskHandlerDecorator;
import org.jbpm.examples.exceptions.service.ExceptionService;
import org.kie.api.KieBase;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.process.ProcessInstance;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.io.ResourceFactory;

public class ExceptionHandlingErrorExample {

public static final void main(String[] args) {
runExample();
}

public static ProcessInstance runExample() {
KieSession ksession = createKieSession();

String eventType = "Error-code";                                                                                          1
SignallingTaskHandlerDecorator signallingTaskWrapper                                                                      1
= new SignallingTaskHandlerDecorator(ServiceTaskHandler.class, eventType);
signallingTaskWrapper.setWorkItemExceptionParameterName(ExceptionService.exceptionParameterName);                         1
ksession.getWorkItemManager().registerWorkItemHandler("Service Task", signallingTaskWrapper);

Map<String, Object> params = new HashMap<String, Object>();
params.put("serviceInputItem", "Input to Original Service");
ProcessInstance processInstance = ksession.startProcess("ProcessWithExceptionHandlingError", params);
return processInstance;
}

private static KieSession createKieSession() {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("exceptions/ExceptionHandlingWithError.bpmn2"), ResourceType.BPMN2);
KieBase kbase = kbuilder.newKnowledgeBase();
return kbase.newKieSession();
}

1

Definition of the Error-code event to be sent to the process instance when the wrapped WorkItemHandler implementation throws an exception

1

Construction of the SignallingTaskHandlerDecorator class instance with the WorkItemHandler implementation and eventType as parameters
Note that a SignallingTaskHandlerDecorator class constructor that takes an instance of a WorkItemHandler implementation as its parameter is also available. This constructor is useful if the WorkItemHandler implementation does not allow a no-argument constructor.

1

Registering the WorItemHandler with the session
When an exception is thrown by the wrapped WorkItemHandler, the SignallingTaskHandlerDecorator saves it as a parameter in the WorkItem instance with a parameter name configured in the SignallingTaskHandlerDecorator (see the code below for the ExceptionService).
5.1.5.1.3. Exception service
In Section 5.1.5.1.1, “Service Task handlers” the BPMN2 process definition defines the exception service using the ExceptionService class as follows:
<interface id="_handlingServiceInterface" name="org.jbpm.examples.exceptions.service.ExceptionService">
<operation id="_handlingServiceOperation" name="handleException">
The exception service uses the ExceptionService class to provide the exception handling abilities. The class is implemented as follows:
import org.kie.api.runtime.process.WorkItem;
...	
public class ExceptionService {
public static String exceptionParameterName = "my.exception.parameter.name";
public void handleException(WorkItem workItem) {
System.out.println( "Handling exception caused by work item '" + workItem.getName() + "' (id: " + workItem.getId() + ")");
Map<String, Object> params = workItem.getParameters();
Throwable throwable = (Throwable) params.get(exceptionParameterName);
throwable.printStackTrace();
}
public String throwException(String message) {
throw new RuntimeException("Service failed with input: " + message );
}
public static void setExceptionParameterName(String exceptionParam) {
exceptionParameterName = exceptionParam;
}

}
You can specify any Java class with the default or another no-argument constructor as the class to provide the exception service so that it is executed as part of a serviceTask.
5.1.5.1.4. Handling errors with Signals
In the example in Section 5.1.5.1.1, “Service Task handlers”, an Error event occurs during Process execution and the execution is interrupted immediately: no other Flows or Activities are executed.
However, you might want to complete the execution. In such case you can use a Signal event as the Process execution continues after the Signal is processed (that is, after the Signal Event SubProcess or another Activities that the Signal triggered, finish their execution). Also, the Process execution finished successfully, not in an aborted state, which is the case if an Error is used.
In the example process, we define the error element which is then used to throw the Error:
 <error id="_exception" errorCode="code" structureRef="_exceptionItem"/>
To use a Signal instead, do the following:
  1. Remove the line defining the error element and define a <signal> element:
     <signal id="exception-signal" structureRef="_exceptionItem"/>
  2. Make sure to change all references from the "_exception" <error> to the "exception-signal" <signal>.
    Change the <errorEventDefinition> element in the <startEvent>,
     <errorEventDefinition id="_X-1_ED_1" errorRef="_exception" />
    to a <signalEventDefinition>:
     <signalEventDefinition id="_X-1_ED_1" signalRef="exception-signal"/>
5.1.5.1.5. Extracting information from WorkflowRuntimeException
If a scripts in your Process definition may throw or threw an exception, you need to retrieve more information about the exception and related information.
If it is a scriptTask element that causes an exception, you can extract the information from the WorkflowRuntimeException as it is the wrapper of the scriptTask.
The WorkflowRuntimeException instance stores the information outlined in Table 5.1, “Information in WorkflowRuntimeException instances”. Values of all fields listed can be obtained using the standard get* methods.

Table 5.1. Information in WorkflowRuntimeException instances

Field name Type Description
processInstanceId long
The id of the ProcessInstance instance in which the exception occurred
Note that the ProcessInstance may not exist anymore or be available in the database if using persistence.
processId String The id of the process definition that was used to start the process (that is, "ExceptionScriptTask" in
ksession.startProcess("ExceptionScriptTask");
)
nodeId long The value of the (BPMN2) id attribute of the node that threw the exception
nodeName String The value of the (BPMN2) name attribute of the node that threw the exception
variables Map<String, Object> The map containing the variables in the process instance (experimental)
message String The short message with information on the exception
cause Throwable The original exception that was thrown
The following code illustrates how to extract extra information from a process instance that throws a WorkflowRuntimeException exception instance.
import org.jbpm.workflow.instance.WorkflowRuntimeException;
import org.kie.api.KieBase;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.process.ProcessInstance;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.io.ResourceFactory;

public class ScriptTaskExceptionExample {

public static final void main(String[] args) {
runExample();
}

public static void runExample() {
KieSession ksession = createKieSession();
Map<String, Object> params = new HashMap<String, Object>();
String varName = "var1";
params.put( varName , "valueOne" );
try {
ProcessInstance processInstance = ksession.startProcess("ExceptionScriptTask", params);
} catch( WorkflowRuntimeException wfre ) {
String msg = "An exception happened in "
+ "process instance [" + wfre.getProcessInstanceId()
+ "] of process [" + wfre.getProcessId()
+ "] in node [id: " + wfre.getNodeId()
+ ", name: " + wfre.getNodeName()
+ "] and variable " + varName + " had the value [" + wfre.getVariables().get(varName)
+ "]";
System.out.println(msg);
}
}
private static KieSession createKieSession() {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("exceptions/ScriptTaskException.bpmn2"), ResourceType.BPMN2);
KieBase kbase = kbuilder.newKnowledgeBase();
return kbase.newKieSession();
}
}