From jBPM documentation:
jBPM provides the ability to create and use domain-specific task nodes in your business processes. This simplifies development when you're creating business processes that contain tasks dealing with other technical systems.
When using jBPM, we call these domain-specific task nodes "custom work items" or (custom) "service nodes". There are two separate aspects to creating and using custom work items:
- Adding a node with a custom work item to a process definition using the Eclipse editor or jBPM designer.
- Creating a custom work item handler that the jBPM engine will use when executing the custom work item in a running process.
Custom tasks are also called as domain specific tasks. The technical term is work item and its work item handler.
A work item is an XML node inside your process definition. The respective work item handler is a Java class that implements the
org.kie.api.runtime.process.WorkItemHandler interface. This document explains how to integrate and configure a work item handler and how to use the handler to execute a work item.
Work item handler registry
The mapping between a work item and its handler is based on the work item name. The name has to be added to the jBPM Environment when starting the engine. In Magnolia we use an observed registry for work item handlers. The registry is under the
workItemHandlers node in module configuration. Custom handlers can be configured in any module using YAML or JCR.
Here are the default work item handlers registered in Magnolia:
rejectNotification handler shows the properties needed to register a handler:
class: The definition class of a work item is similar to any other definition class in Magnolia. The fields you make accessible using getters and setters on the definition are accessible to the implementation by injecting the definition into it. This is one possibility to access data from within your handler in the process. Another option is passing a parameter map when launching the process.
implementationClass: An implementation class executes the work item.
Do not re-implement similar mechanisms over and over again. Introduce decorators for your handlers when you need some common functionality in handlers. A decorator allows you to wrap an existing work item handler implementation into another handler. Both handlers must implement the same
Decorator configuration is similar to handler configuration. A decorator needs a definition and an implementation configured. When the handler is loaded into Magnolia during system startup, it looks for a
decorator node in the configuration. If the node is found the original handler is wrapped into the decorator by passing the original handler as parameter. Also passed are the decorator definition and any other objects accessible through injection.
Error handling is an example of decoration. A technical error during execution throws an exception:
Error handling in process execution is not a trivial topic. Start implementing error handling the moment you start modeling your process. You have to know what can go wrong and you need to decide what to do in case of errors. As a rule of thumb, exception and error handling should be handled inside your process and be isolated from the rest of the system.
Error handling using a decorator
As described in jBPM Technical Exceptions, you can use decorators for handling errors in custom tasks where an error is an exception thrown during the execution of a task.
ThrowExceptionHandlerDecorator is a sample implementation of a decorator for wrapping any kind of task. The decorator catches any kind of exception thrown during
abort phase of the handler and wraps the exception into a
The exception can then be caught as part of the process using an Error Boundary Event, letting the process take care of error handling. The advantage of this approach is that you clearly see where errors can happen and the associated handling is evident at process level. You can re-use the pattern for other custom tasks that may fail.
Apart from using Magnolia's own exception decorator you can also use the decorators provided by jBPM such as
LoggingTaskHandlerDecorator. Set the
HandlerDecoratorDefinition in the
class property and the decorator implementation in the
implementationClass property in your configuration.
Error handler decorator configuration
implementationClass: The actual implementation of the decorator
log: Whether the caught exception should be logged. Default is
Modeling an error
Define the error at the process level in the BPMN2 editor:
Reference the error from the Error Boundary Event:
In jBPM 6 there are some technical restrictions in using Error Boundary Events which should be solved in upcoming releases:
- The exception is not mapped to the Target. You cannot retrieve the exception later on in the process.
- In theory you should not have to use the FQN of the exception, but rather define a human readable name of the error.
As process execution runs synchronously you will run into problems executing long-running tasks as part of the process. There are different solutions to approach this problem. See jBPM: Concurrency and asynchronous execution before proceeding.
Executing your work item handler asynchronously
Instead of spawning a thread manually inside your work item handler as outlined in jBPM: Asynchronous execution, you can extend Magnolia's
AsyncWorkItemHandler which takes advantage of the asynchronous Quartz scheduler for launching long running tasks. The benefit of extending this abstract handler is that you can model the error handling the same way as in Modeling an error using an Error Boundary Event.
In your implementer class, extend
AsyncWorkItemHandler and implement the abstract methods that take care of creating Quartz related objects such as
JobDetail. See Quartz documentation for details. (Magnolia currently bundles Quartz 1.8)
Error handling in asynchronous execution
Error handling during asynchronous execution is done by registering a Quartz
JobListener to the scheduler. The listener handles a failed job in the same way an error decorator handles errors. In case you need to change the default behavior, override the
AsyncWorkItemHandler#getListener(String jobName) method in your implementation.
We have put together a step-by-step tutorial on how to model, implement and load custom work item handlers.