Custom tasks
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:
The expanded 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.
Decorators
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 WorkItemHandler
interface.
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
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 execute
and abort
phase of the
handler and wraps the exception into a
WorkItemHandlerRuntimeException
.
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 SignallingTaskHandlerDecorator
or
LoggingTaskHandlerDecorator
. Set the HandlerDecoratorDefinition
in
the class
property and the decorator implementation in the
implementationClass
property in your configuration.
Asynchronous execution
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.
Implementation
In your implementer class, extend AsyncWorkItemHandler
and implement
the abstract methods that take care of creating Quartz related objects
such as Trigger
and JobDetail
. See
Quartz documentation for
details. (Magnolia currently bundles Quartz 1.8)
info.magnolia.module.workflow.jbpm.workitem.handler.AsyncWorkItemHandler
public abstract class AsyncWorkItemHandler implements WorkItemHandler {
@Inject
public AsyncWorkItemHandler(...) {
...
}
protected abstract String getJobName(WorkItem workItem);
protected abstract String getHandlerName();
protected abstract JobDetail createJobDetail(String jobName, WorkItem workItem);
protected abstract Trigger createTrigger(String jobName, WorkItem workItem);
}
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.
Tutorial
We have put together a step-by-step tutorial on how to model, implement and load custom work item handlers.