此内容没有您所选择的语言版本。
Chapter 66. Core engine API for the process engine
The process engine executes business processes. To define the processes, you create business assets, including process definitions and custom tasks.
You can use the Core Engine API to load, execute, and manage processes in the process engine.
Several levels of control are available:
- At the lowest level, you can directly create a KIE base and a KIE session. A KIE base represents all the assets in a business process. A KIE session is an entity in the process engine that runs instances of a business process. This level provides fine-grained control, but requires explicit declaration and configuration of process instances, task handlers, event handlers, and other process engine entities in your code.
-
You can use the RuntimeManager class to manage sessions and processes. This class provides sessions for required process instances using a configurable strategy. It automatically configures the interaction between the KIE session and task services. It disposes of process engine entities that are no longer necessary, ensuring optimal use of resources. You can use a fluent API to instantiate
RuntimeManager
with the necessary business assets and to configure its environment. You can use the Services API to manage the execution of processes. For example, the deployment service deploys business assets into the engine, forming a deployment unit. The process service runs a process from this deployment unit.
If you want to embed the process engine in your application, the Services API is the most convenient option, because it hides the internal details of configuring and managing the engine.
Finally, you can deploy a KIE Server that loads business assets from KJAR files and runs processes. The KIE Server provides a REST API for loading and managing the processes. You can also use Business Central to manage a KIE Server.
If you use a KIE Server, you do not need to use the Core Engine API. For information about deploying and managing processes on a KIE Server, see Packaging and deploying a Red Hat Process Automation Manager project.
For the full reference information for all public process engine API calls, see the Java documentation. Other API classes also exist in the code, but they are internal APIs that can be changed in later versions. Use public APIs in applications that you develop and maintain.
66.1. KIE base and KIE session 复制链接链接已复制到粘贴板!
A KIE base contains a reference to all process definitions and other assets relevant for a process. The engine uses this KIE base to look up all information for the process, or for several processes, whenever necessary.
You can load assets into a KIE base from various sources, such as a class path, file system, or process repository. Creating a KIE base is a resource-heavy operation, as it involves loading and parsing assets from various sources. You can dynamically modify the KIE base to add or remove process definitions and other assets at run time.
After you create a KIE base, you can instantiate a KIE session based on this KIE base. Use this KIE session to run processes based on the definitions in the KIE base.
When you use the KIE session to start a process, a new process instance is created. This instance maintains a specific process state. Different instances in the same KIE session can use the same process definition but have different states.
Figure 66.1. KIE base and KIE session in the process engine
For example, if you develop an application to process sales orders, you can create one or more process definitions that determine how an order should be processed. When starting the application, you first need to create a KIE base that contains those process definitions. You can then create a session based on this KIE base. When a new sales order comes in, start a new process instance for the order. This process instance contains the state of the process for the specific sales request.
You can create many KIE sessions for the same KIE base and you can create many instances of the process within the same KIE session. Creating a KIE session, and also creating a process instance within the KIE session, uses far fewer resources than creating a KIE base. If you modify a KIE base, all the KIE sessions that use it can use the modifications automatically.
In most simple use cases, you can use a single KIE session to execute all processes. You can also use several sessions if needed. For example, if you want order processing for different customers to be completely independent, you can create a KIE session for each customer. You can also use multiple sessions for scalability reasons.
In typical applications you do not need to create a KIE base or KIE session directly. However, when you use other levels of the process engine API, you can interact with elements of the API that this level defines.
66.1.1. KIE base 复制链接链接已复制到粘贴板!
The KIE base includes all process definitions and other assets that your application might need to execute a business process.
To create a KIE base, use a KieHelper
instance to load processes from various resources, such as the class path or the file system, and to create a new KIE base.
The following code snippet shows how to create a KIE base consisting of only one process definition, which is loaded from the class path.
Creating a KIE base containing one process definition
KieHelper kieHelper = new KieHelper(); KieBase kieBase = kieHelper .addResource(ResourceFactory.newClassPathResource("MyProcess.bpmn")) .build();
KieHelper kieHelper = new KieHelper();
KieBase kieBase = kieHelper
.addResource(ResourceFactory.newClassPathResource("MyProcess.bpmn"))
.build();
The ResourceFactory
class has similar methods to load resources from a file, a URL, an InputStream, a Reader, and other sources.
This "manual" process of creating a KIE base is simpler than other alternatives, but can make an application hard to maintain. Use other methods of creating a KIE base, such as the RuntimeManager
class or the Services API, for applications that you expect to develop and maintain over long periods of time.
66.1.2. KIE session 复制链接链接已复制到粘贴板!
After creating and loading the KIE base, you can create a KIE session to interact with the process engine. You can use this session to start and manage processes and to signal events.
The following code snippet creates a session based on the KIE base that you created previously and then starts a process instance, referencing the ID in the process definition.
Creating a KIE session and starting a process instance
KieSession ksession = kbase.newKieSession(); ProcessInstance processInstance = ksession.startProcess("com.sample.MyProcess");
KieSession ksession = kbase.newKieSession();
ProcessInstance processInstance = ksession.startProcess("com.sample.MyProcess");
66.1.3. ProcessRuntime interface 复制链接链接已复制到粘贴板!
The KieSession
class exposes the ProcessRuntime
interface, which defines all the session methods for interacting with processes, as the following definition shows.
Definition of the ProcessRuntime
interface
66.1.4. Correlation Keys 复制链接链接已复制到粘贴板!
When working with processes, you might need to assign a business identifier to a process instance and then use the identifier to reference the instance without storing the generated instance ID.
To provide such capabilities, the process engine uses the CorrelationKey
interface, which can define CorrelationProperties
. A class that implements CorrelationKey
can have either a single property describing it or a multi-property set. The value of the property or a combination of values of several properties refers to a unique instance.
The KieSession
class implements the CorrelationAwareProcessRuntime
interface to support correlation capabilities. This interface exposes the following methods:
Methods of the CorrelationAwareProcessRuntime
interface
Correlation is usually used with long-running processes. You must enable persistence if you want to store correlation information permanently.
66.2. Runtime manager 复制链接链接已复制到粘贴板!
The RuntimeManager
class provides a layer in the process engine API that simplifies and empowers its usage. This class encapsulates and manages the KIE base and KIE session, as well as the task service that provides handlers for all tasks in the process. The KIE session and the task service within the runtime manager are already configured to work with each other and you do not need to provide such configuration. For example, you do not need to register a human task handler and to ensure that it is connected to the required service.
The runtime manager manages the KIE session according to a predefined strategy. The following strategies are available:
-
Singleton: The runtime manager maintains a single
KieSession
and uses it for all the requested processes. -
Per Request: The runtime manager creates a new
KieSession
for every request. -
Per Process Instance: The runtime manager maintains mapping between process instance and
KieSession
and always provides the sameKieSession
whenever working with a given process instance.
Regardless of the strategy, the RuntimeManager
class ensures the same capabilities in initialization and configuration of the process engine components:
-
KieSession
instances are loaded with the same factories (either in memory or JPA based). -
Work item handlers are registered on every
KieSession
instance (either loaded from the database or newly created). -
Event listeners (
Process
,Agenda
,WorkingMemory
) are registered on every KIE session, whether the session is loaded from the database or newly created. The task service is configured with the following required components:
- The JTA transaction manager
-
The same entity manager factory as the one used for
KieSession
instances -
The
UserGroupCallback
instance that can be configured in the environment
The runtime manager also enables disposing the process engine cleanly. It provides dedicated methods to dispose a RuntimeEngine
instance when it is no longer needed, releasing any resources it might have acquired.
The following code shows the definition of the RuntimeManager
interface:
Definition of the RuntimeManager
interface
The RuntimeManager
class also provides the RuntimeEngine
class, which includes methods to get access to underlying process engine components:
Definition of the RuntimeEngine
interface
An identifier of the RuntimeManager
class is used as deploymentId
during runtime execution. For example, the identifier is persisted as deploymentId
of a Task
when the Task
is persisted. The deploymentID
of a Task
associates it with the RuntimeManager
when the Task
is completed and the process instance is resumed.
The same deploymentId
is also persisted as externalId
in history log tables.
If you don’t specify an identifier when creating a RuntimeManager
instance, a default value is applied, depending on the strategy (for example, default-per-pinstance
for PerProcessInstanceRuntimeManager
). That means your application uses the same deployment of the RuntimeManager
class in its entire lifecycle.
If you maintain multiple runtime managers in your application, you must specify a unique identifier for every RuntimeManager
instance.
For example, the deployment service maintains multiple runtime managers and uses the GAV value of the KJAR file as an identifier. The same logic is used in Business Central and in KIE Server, because they depend on the deployment service.
When you need to interact with the process engine or task service from within a handler or a listener, you can use the RuntimeManager
interface to retrieve the RuntimeEngine
instance for the given process instance, and then use the RuntimeEngine
instance to retrieve the KieSession
or TaskService
instance. This approach ensures that the proper state of the engine, managed according to the selected strategy, is preserved.
66.2.1. Runtime manager strategies 复制链接链接已复制到粘贴板!
The RuntimeManager
class supports the following strategies for managing KIE sessions.
- Singleton strategy
This strategy instructs the runtime manager to maintain a single
RuntimeEngine
instance (and in turn singleKieSession
andTaskService
instances). Access to the runtime engine is synchronized and, therefore, thread safe, although it comes with a performance penalty due to synchronization.Use this strategy for simple use cases.
This strategy has the following characteristics:
- It has a small memory footprint, with single instances of the runtime engine and the task service.
- It is simple and compact in design and usage.
- It is a good fit for low-to-medium load on the process engine because of synchronized access.
-
In this strategy, because of the single
KieSession
instance, all state objects (such as facts) are directly visible to all process instances and vice versa. -
The strategy is not contextual. When you retrieve instances of
RuntimeEngine
from a singletonRuntimeManager
, you do not need to take theContext
instance into account. Usually, you can useEmptyContext.get()
as the context, although a null argument is acceptable as well. In this strategy, the runtime manager keeps track of the ID of the
KieSession
, so that the same session remains in use after aRuntimeManager
restart. The ID is stored as a serialized file in a temporary location in the file system that, depending on the environment, can be one of the following directories:-
The value of the
jbpm.data.dir
system property -
The value of the
jboss.server.data.dir
system property -
The value of the
java.io.tmpdir
system property
-
The value of the
WarningA combination of the Singleton strategy and the EJB Timer Scheduler might raise Hibernate issues under load. Do not use this combination in production applications. The EJB Timer Scheduler is the default scheduler in the KIE Server.
- Per request strategy
This strategy instructs the runtime manager to provide a new instance of
RuntimeEngine
for every request. One or more invocations of the process engine within a single transaction are considered a single request.The same instance of
RuntimeEngine
must be used within a single transaction to ensure correctness of state. Otherwise, an operation completed in one call would not be visible in the next call.This strategy is stateless, as process state is preserved only within the request. When a request is completed, the
RuntimeEngine
instance is permanently destroyed. If persistence is used, information related to the KIE session is removed from the persistence database as well.This strategy has the following characteristics:
- It provides completely isolated process engine and task service operations for every request.
- It is completely stateless, because facts are stored only for the duration of the request.
- It is a good fit for high-load, stateless processes, where no facts or timers must be preserved between requests.
- In this strategy, the KIE session is only available during the life of a request and is destroyed at the end of the request.
-
The strategy is not contextual. When you retrieve instances of
RuntimeEngine
from a per-requestRuntimeManager
, you do not need to take theContext
instance into account. Usually, you can useEmptyContext.get()
as the context, although a null argument is acceptable as well.
- Per process instance strategy
This strategy instructs
RuntimeManager
to maintain a strict relationship between a KIE session and a process instance. EachKieSession
is available as long as theProcessInstance
to which it belongs is active.This strategy provides the most flexible approach for using advanced capabilities of the process engine, such as rule evaluation and isolation between process instances. It maximizes performance and reduces potential bottlenecks introduced by synchronization. At the same time, unlike the request strategy, it reduces the number of KIE sessions to the actual number of process instances, rather than the total number of requests.
This strategy has the following characteristics:
- It provides isolation for every process instance.
-
It maintains a strict relationship between
KieSession
andProcessInstance
to ensure that it always delivers the sameKieSession
for a givenProcessInstance
. -
It merges the lifecycle of
KieSession
withProcessInstance
, and both are disposed when the process instance completes or aborts. - It enables maintenance of data, such as facts and timers, in the scope of the process instance. Only the process instance has access to the data.
-
It introduces some overhead because of the need to look up and load the
KieSession
for the process instance. -
It validates every usage of a
KieSession
so it cannot be used for other process instances. An exception is thrown if another process instance uses the sameKieSession
. The strategy is contextual and accepts the following context instances:
-
EmptyContext
or null: Used when starting a process instance because no process instance ID is available yet -
ProcessInstanceIdContext
: Used after the process instance is created -
CorrelationKeyContext
: Used as an alternative toProcessInstanceIdContext
to use a custom (business) key instead of the process instance ID
-
66.2.2. Typical usage scenario for the runtime manager 复制链接链接已复制到粘贴板!
The typical usage scenario for the runtime manager consists of the following stages:
At application startup time, complete the following stage:
-
Build a
RuntimeManager
instance and keep it for the entire lifetime of the application, as it is thread-safe and can be accessed concurrently.
-
Build a
At request time, complete the following stages:
-
Get
RuntimeEngine
from theRuntimeManager
, using the proper context instance as determined by the strategy that you configured for theRuntimeManager
class. -
Get the
KieSession
andTaskService
objects from theRuntimeEngine
. -
Use the
KieSession
andTaskService
objects for operations such asstartProcess
orcompleteTask
. -
After completing processing, dispose
RuntimeEngine
using theRuntimeManager.disposeRuntimeEngine
method.
-
Get
At application shutdown time, complete the following stage:
-
Close the
RuntimeManager
instance.
-
Close the
When RuntimeEngine
is obtained from RuntimeManager
within an active JTA transaction, you do not need to dispose RuntimeEngine
at the end, as RuntimeManager
automatically disposes the RuntimeEngine
on transaction completion (regardless of the completion status: commit or rollback).
The following example shows how you can build a RuntimeManager
instance and get a RuntimeEngine
instance (that encapsulates KieSession
and TaskService
classes) from it:
Building a RuntimeManager
instance and then getting RuntimeEngine
and KieSession
This example provides the simplest, or minimal, way of using RuntimeManager
and RuntimeEngine
classes. It has the following characteristics:
-
The
KieSession
instance is created in memory, using thenewDefaultInMemoryBuilder
builder. - A single process, which is added as an asset, is available for execution.
-
The
TaskService
class is configured and attached to theKieSession
instance through theLocalHTWorkItemHandler
interface to support user task capabilities within processes.
66.2.3. Runtime environment configuration object 复制链接链接已复制到粘贴板!
The RuntimeManager
class encapsulates internal process engine complexity, such as creating, disposing, and registering handlers.
It also provides fine-grained control over process engine configuration. To set this configuration, you must create a RuntimeEnvironment
object and then use it to create the RuntimeManager
object.
The following definition shows the methods available in the RuntimeEnvironment
interface:
Methods in the RuntimeEnvironment
interface
66.2.4. Runtime environment builder 复制链接链接已复制到粘贴板!
To create an instance of RuntimeEnvironment
that contains the required data, use the RuntimeEnvironmentBuilder
class. This class provides a fluent API to configure a RuntimeEnvironment
instance with predefined settings.
The following definition shows the methods in the RuntimeEnvironmentBuilder
interface:
Methods in the RuntimeEnvironmentBuilder
interface
Use the RuntimeEnvironmentBuilderFactory
class to obtain instances of RuntimeEnvironmentBuilder
. Along with empty instances with no settings, you can get builders with several preconfigured sets of configuration options for the runtime manager.
The following definition shows the methods in the RuntimeEnvironmentBuilderFactory
interface:
Methods in the RuntimeEnvironmentBuilderFactory
interface
The runtime manager also provides access to a TaskService
object as an integrated component of a RuntimeEngine
object, configured to communicate with the KIE session. If you use one of the default builders, the following configuration settings for the task service are present:
-
The persistence unit name is set to
org.jbpm.persistence.jpa
(for both process engine and task service). - The human task handler is registered on the KIE session.
- The JPA-based history log event listener is registered on the KIE session.
-
An event listener to trigger rule task evaluation (
fireAllRules
) is registered on the KIE session.
If you use the runtime manager API, the runtime engine object represents the process engine.
To extend runtime engines with your own handlers or listeners, you can implement the RegisterableItemsFactory
interface and then include it in the runtime environment using the RuntimeEnvironmentBuilder.registerableItemsFactory()
method. Then the runtime manager automatically adds the handlers or listeners to every runtime engine it creates.
The following definition shows the methods in the RegisterableItemsFactory
interface:
Methods in the RegisterableItemsFactory
interface
The process engine provides default implementations of RegisterableItemsFactory
. You can extend these implementations to define custom handlers and listeners.
The following available implementations might be useful:
-
org.jbpm.runtime.manager.impl.SimpleRegisterableItemsFactory
: The simplest possible implementation. It does not have any predefined content and uses reflection to produce instances of handlers and listeners based on given class names. -
org.jbpm.runtime.manager.impl.DefaultRegisterableItemsFactory
: An extension of the Simple implementation that introduces the same defaults as the default runtime environment builder and still provides the same capabilities as the Simple implementation. -
org.jbpm.runtime.manager.impl.cdi.InjectableRegisterableItemsFactory
: An extension of the Default implementation that is tailored for CDI environments and provides a CDI style approach to finding handlers and listeners using producers.
66.2.5.1. Registering work item handlers using a file 复制链接链接已复制到粘贴板!
You can register simple work item handlers, which are stateless or rely on the KieSession
state, by defining them in the CustomWorkItem.conf
file and placing the file on the class path.
Procedure
-
Create a file named
drools.session.conf
in theMETA-INF
subdirectory of the root of the class path. For web applications the directory isWEB-INF/classes/META-INF
. Add the following line to the
drools.session.conf
file:drools.workItemHandlers = CustomWorkItemHandlers.conf
drools.workItemHandlers = CustomWorkItemHandlers.conf
Copy to Clipboard Copied! Toggle word wrap Toggle overflow -
Create a file named
CustomWorkItemHandlers.conf
in the same directory. In the
CustomWorkItemHandlers.conf
file, define custom work item handlers using the MVEL style, similar to the following example:Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Result
The work item handlers that you listed are registered for any KIE session created by the application, regardless of whether the application uses the runtime manager API.
If your application uses the runtime manager API and runs in a CDI environment, your classes can implement the dedicated producer interfaces to provide custom work item handlers and event listeners to all runtime engines.
To create a work item handler, you must implement the WorkItemHandlerProducer
interface.
Definition of the WorkItemHandlerProducer
interface
To create an event listener, you must implement the EventListenerProducer
interface. Annotate the event listener producer with the proper qualifier to indicate the type of listeners that it provides. Use one of the following annotations:
-
@Process
forProcessEventListener
-
@Agenda
forAgendaEventListener
-
@WorkingMemory
forWorkingMemoryEventListener
Definition of the EventListenerProducer
interface
Package your implementations of these interfaces as a bean archive by including beans.xml
in the META-INF
subdirectory. Place the bean archive on the application class path, for example, in WEB-INF/lib
for a web application. The CDI-based runtime manager discovers the packages and registers the work item handlers and event listeners in every KieSession
that it creates or loads from the data store.
The process engine provides certain parameters to the producers to enable stateful and advanced operation. For example, the handlers or listeners can use the parameters to signal the process engine or the process instance in case of an error. The process engine provides the following components as parameters:
-
KieSession
-
TaskService
-
RuntimeManager
In addition, the identifier of the RuntimeManager
class instance is provided as a parameter. You can apply filtering to the identifier to decide whether this RuntimeManager
instance receives the handlers and listeners.
66.3. Services in the process engine 复制链接链接已复制到粘贴板!
The process engine provides a set of high-level services, running on top of the runtime manager API.
The services provide the most convenient way to embed the process engine in your application. The KIE Server also uses these services internally.
When you use services, you do not need to implement your own handling of the runtime manager, runtime engines, sessions, and other process engine entities. However, you can access the underlying RuntimeManager
objects through the services when necessary.
If you use the EJB remote client for the services API, the RuntimeManager
objects are not available, because they would not operate correctly on the client side after serialization.
66.3.1. Modules for process engine services 复制链接链接已复制到粘贴板!
The process engine services are provided as a set of modules. These modules are grouped by their framework dependencies. You can choose the suitable modules and use only these modules, without making your application dependent on the frameworks that other modules use.
The following modules are available:
-
jbpm-services-api
: Only API classes and interfaces -
jbpm-kie-services
: A code implementation of the services API in pure Java without any framework dependencies -
jbpm-services-cdi
: A CDI wrapper on top of the core services implementation -
jbpm-services-ejb-api
: An extension of the services API to support EJB requirements -
jbpm-services-ejb-impl
: EJB wrappers on top of the core services implementation -
jbpm-services-ejb-timer
: A scheduler service based on the EJB timer service to support time-based operations, such as timer events and deadlines -
jbpm-services-ejb-client
: An EJB remote client implementation, currently supporting only Red Hat JBoss EAP
66.3.2. Deployment service 复制链接链接已复制到粘贴板!
The deployment service deploys and undeploys units in the process engine.
A deployment unit represents the contents of a KJAR file. A deployment unit includes business assets, such as process definitions, rules, forms, and data models. After deploying the unit you can execute the processes it defines. You can also query the available deployment units.
Every deployment unit has a unique identifier string, deploymentId
, also known as deploymentUnitId
. You can use this identifier to apply any service actions to the deployment unit.
In a typical use case for this service, you can load and unload multiple KJARs at the same time and, when necessary, execute processes simultaneously.
The following code sample shows simple use of the deployment service.
Using the deployment service
The following definition shows the complete DeploymentService
interface:
Definition of the DeploymentService
interface
66.3.3. Definition service 复制链接链接已复制到粘贴板!
When you deploy a process definition using the deployment service, the definition service automatically scans the definition, parses the process, and extracts the information that the process engine requires.
You can use the definition service API to retrieve information about the process definition. The service extracts this information directly from the BPMN2 process definition. The following information is available:
- Process definition such as ID, name, and description
- Process variables including the name and type of every variable
- Reusable sub-processes used in the process (if any)
- Service tasks that represent domain-specific activities
- User tasks including assignment information
- Task data with input and output information
The following code sample shows simple use of the definition service. The processID
must correspond to the ID of a process definition in a KJAR file that you already deployed using the deployment service.
Using the definition service
You can also use the definition service to scan a definition that you provide as BPMN2-compliant XML content, without the use of a KJAR file. The buildProcessDefinition
method provides this capability.
The following definition shows the complete DefinitionService
interface:
Definition of the DefinitionService
interface
66.3.4. Process service 复制链接链接已复制到粘贴板!
The deployment and definition services prepare process data in the process engine. To execute processes based on this data, use the process service. The process service supports interaction with the process engine execution environment, including the following actions:
- Starting a new process instance
- Running a process as a single transaction
- Working with an existing process instance, for example, signalling events, getting information details, and setting values of variables
- Working with work items
The process service is also a command executor. You can use it to execute commands on the KIE session to extend its capabilities.
The process service is optimized for runtime operations. Use it when you need to run a process or to alter a process instance, for example, signal events or change variables. For read operations, for example, showing available process instances, use the runtime data service.
The following code sample shows deploying and running a process:
Deploying and runing a process using the deployment and process services
The startProcess
method expects deploymentId
as the first argument. Using this argument, you can start processes in a certain deployment when your application might have multiple deployments.
For example, you might deploy different versions of the same process from different KJAR files. You can then start the required version using the correct deploymentId
.
The following definition shows the complete ProcessService
interface:
Definition of the ProcessService
interface
66.3.5. Runtime Data Service 复制链接链接已复制到粘贴板!
You can use the runtime data service to retrieve all runtime information about processes, such as started process instances and executed node instances.
For example, you can build a list-based UI to show process definitions, process instances, tasks for a given user, and other data, based on information provided by the runtime data service.
This service is optimized to be as efficient as possible while providing all required information.
The following examples show various usage of this service.
Retrieving all process definitions
Collection definitions = runtimeDataService.getProcesses(new QueryContext());
Collection definitions = runtimeDataService.getProcesses(new QueryContext());
Retrieving active process instances
Collection<processinstancedesc> instances = runtimeDataService.getProcessInstances(new QueryContext());
Collection<processinstancedesc> instances = runtimeDataService.getProcessInstances(new QueryContext());
Retrieving active nodes for a particular process instance
Collection<nodeinstancedesc> instances = runtimeDataService.getProcessInstanceHistoryActive(processInstanceId, new QueryContext());
Collection<nodeinstancedesc> instances = runtimeDataService.getProcessInstanceHistoryActive(processInstanceId, new QueryContext());
Retrieving tasks assigned to the user john
List<tasksummary> taskSummaries = runtimeDataService.getTasksAssignedAsPotentialOwner("john", new QueryFilter(0, 10));
List<tasksummary> taskSummaries = runtimeDataService.getTasksAssignedAsPotentialOwner("john", new QueryFilter(0, 10));
The runtime data service methods support two important parameters, QueryContext
and QueryFilter
. QueryFilter
is an extension of QueryContext
. You can use these parameters to manage the result set, providing pagination, sorting, and ordering. You can also use them to apply additional filtering when searching for user tasks.
The following definition shows the methods of the RuntimeDataService
interface:
Definition of the RuntimeDataService
interface
66.3.6. User Task Service 复制链接链接已复制到粘贴板!
The user task service covers the complete lifecycle of an individual task, and you can use the service to manage a user task from start to end.
Task queries are not a part of the user task service. Use the runtime data service to query for tasks. Use the user task service for scoped operations on one task, including the following actions:
- Modification of selected properties
- Access to task variables
- Access to task attachments
- Access to task comments
The user task service is also a command executor. You can use it to execute custom task commands.
The following example shows starting a process and interacting with a task in the process:
Starting a process and interacting with a user task in this process
66.3.7. Quartz-based timer service 复制链接链接已复制到粘贴板!
The process engine provides a cluster-ready timer service using Quartz. You can use the service to dispose or load your KIE session at any time. The service can manage how long a KIE session is active in order to fire each timer appropriately.
The following example shows a basic Quartz configuration file for a clustered environment:
Quartz configuration file for a clustered environment
You must modify the previous example to fit your environment.
66.3.8. Query service 复制链接链接已复制到粘贴板!
The query service provides advanced search capabilities that are based on Dashbuilder data sets.
With this approach, you can control how to retrieve data from underlying data store. You can use complex JOIN
statements with external tables such as JPA entities tables or custom systems database tables.
The query service is built around the following two sets of operations:
Management operations:
- Register a query definition
- Replace a query definition
- Unregister (remove) a query definition
- Get a query definition
- Get all registered query definitions
Runtime operations:
-
Simple query based on
QueryParam
as the filter provider -
Advanced query based on
QueryParamBuilder
as the filter provider
-
Simple query based on
Dashbuilder data sets provide support for multiple data sources, such as CSV, SQL, and Elastic Search. However, the process engine uses a RDBMS-based backend and focuses on SQL-based data sets.
Therefore, the process engine query service is a subset of Dashbuilder data set capabilities that enables efficient queries with a simple API.
66.3.8.1. Key classes of the query service 复制链接链接已复制到粘贴板!
The query service relies on the following key classes:
-
QueryDefinition
: Represents the definition of a data set. The definition consists of a unique name, an SQL expression (the query) and the source, the JNDI name of the data source to use when performing queries. -
QueryParam
: The basic structure that represents an individual query parameter or condition. This structure consists of the column name, operator, and expected values. -
QueryResultMapper
: The class that maps raw dataset data (rows and columns) to an object representation. -
QueryParamBuilder
: The class that builds query filters that are applied to the query definition to invoke the query.
QueryResultMapper
QueryResultMapper
maps data taken from a database (dataset) to an object representation. It is similar to ORM providers such as hibernate
, which map tables to entities.
Many object types can be used for representing dataset results. Therefore, existing mappers might not always suit your needs. Mappers in QueryResultMapper
are pluggable and you can provide your own mapper when necessary, in order to transform dataset data into any type you need.
The process engine supplies the following mappers:
-
org.jbpm.kie.services.impl.query.mapper.ProcessInstanceQueryMapper
, registered with the nameProcessInstances
-
org.jbpm.kie.services.impl.query.mapper.ProcessInstanceWithVarsQueryMapper
, registered with the nameProcessInstancesWithVariables
-
org.jbpm.kie.services.impl.query.mapper.ProcessInstanceWithCustomVarsQueryMapper
, registered with the nameProcessInstancesWithCustomVariables
-
org.jbpm.kie.services.impl.query.mapper.UserTaskInstanceQueryMapper
, registered with the nameUserTasks
-
org.jbpm.kie.services.impl.query.mapper.UserTaskInstanceWithVarsQueryMapper
, registered with the nameUserTasksWithVariables
-
org.jbpm.kie.services.impl.query.mapper.UserTaskInstanceWithCustomVarsQueryMapper
, registered with nameUserTasksWithCustomVariables
-
org.jbpm.kie.services.impl.query.mapper.TaskSummaryQueryMapper
, registered with the nameTaskSummaries
-
org.jbpm.kie.services.impl.query.mapper.RawListQueryMapper
, registered with the nameRawList
Each QueryResultMapper
is registered with a unique string name. You can look up mappers by this name instead of referencing the full class name. This feature is especially important when using EJB remote invocation of services, because it avoids relying on a particular implementation on the client side.
To reference a QueryResultMapper
by the string name, use NamedQueryMapper
, which is a part of the jbpm-services-api
module. This class acts as a delegate (lazy delegate) and looks up the actual mapper when the query is performed.
Using NamedQueryMapper
queryService.query("my query def", new NamedQueryMapper<Collection<ProcessInstanceDesc>>("ProcessInstances"), new QueryContext());
queryService.query("my query def", new NamedQueryMapper<Collection<ProcessInstanceDesc>>("ProcessInstances"), new QueryContext());
QueryParamBuilder
QueryParamBuilder
provides an advanced way of building filters for data sets.
By default, when you use a query method of QueryService
that accepts zero or more QueryParam
instances, all of these parameters are joined with an AND
operator, so a data entry must match all of them.
However, sometimes more complicated relationships between parameters are required. You can use QueryParamBuilder
to build custom builders that provide filters at the time the query is issued.
One existing implementation of QueryParamBuilder
is available in the process engine. It covers default QueryParams
that are based on the core functions.
These core functions are SQL-based conditions, including the following conditions:
-
IS_NULL
-
NOT_NULL
-
EQUALS_TO
-
NOT_EQUALS_TO
-
LIKE_TO
-
GREATER_THAN
-
GREATER_OR_EQUALS_TO
-
LOWER_THAN
-
LOWER_OR_EQUALS_TO
-
BETWEEN
-
IN
-
NOT_IN
Before invoking a query, the process engine invokes the build method of the QueryParamBuilder
interface as many times as necessary while the method returns a non-null value. Because of this approach, you can build up complex filter options that could not be expressed by a simple list of QueryParams
.
The following example shows a basic implementation of QueryParamBuilder
. It relies on the DashBuilder Dataset API.
Basic implementation of QueryParamBuilder
After implementing the builder, you can use an instance of this class when performing a query with the QueryService
service, as shown in the following example:
Running a query with the QueryService
service
queryService.query("my query def", ProcessInstanceQueryMapper.get(), new QueryContext(), paramBuilder);
queryService.query("my query def", ProcessInstanceQueryMapper.get(), new QueryContext(), paramBuilder);
66.3.8.2. Using the query service in a typical scenario 复制链接链接已复制到粘贴板!
The following procedure outlines the typical way in which your code might use the query service.
Procedure
Define the data set, which is a view of the data you want to use. Use the
QueryDefinition
class in the services API to complete this operation:Defining the data set
SqlQueryDefinition query = new SqlQueryDefinition("getAllProcessInstances", "java:jboss/datasources/ExampleDS"); query.setExpression("select * from processinstancelog");
SqlQueryDefinition query = new SqlQueryDefinition("getAllProcessInstances", "java:jboss/datasources/ExampleDS"); query.setExpression("select * from processinstancelog");
Copy to Clipboard Copied! Toggle word wrap Toggle overflow This example represents the simplest possible query definition.
The constructor requires the following parameters:
- A unique name that identifies the query at run time
A JNDI data source name to use for performing queries with this definition
The parameter of the
setExpression()
method is the SQL statement that builds up the data set view. Queries in the query service use data from this view and filter this data as necessary.
Register the query:
Registering a query
queryService.registerQuery(query);
queryService.registerQuery(query);
Copy to Clipboard Copied! Toggle word wrap Toggle overflow If required, collect all the data from the dataset, without any filtering:
Collecting all the data from the dataset
Collection<ProcessInstanceDesc> instances = queryService.query("getAllProcessInstances", ProcessInstanceQueryMapper.get(), new QueryContext());
Collection<ProcessInstanceDesc> instances = queryService.query("getAllProcessInstances", ProcessInstanceQueryMapper.get(), new QueryContext());
Copy to Clipboard Copied! Toggle word wrap Toggle overflow This simple query uses defaults from
QueryContext
for paging and sorting.If required, use a
QueryContext
object that changes the defaults of the paging and sorting:Changing defaults using a
QueryContext
objectQueryContext ctx = new QueryContext(0, 100, "start_date", true); Collection<ProcessInstanceDesc> instances = queryService.query("getAllProcessInstances", ProcessInstanceQueryMapper.get(), ctx);
QueryContext ctx = new QueryContext(0, 100, "start_date", true); Collection<ProcessInstanceDesc> instances = queryService.query("getAllProcessInstances", ProcessInstanceQueryMapper.get(), ctx);
Copy to Clipboard Copied! Toggle word wrap Toggle overflow If required, use the query to filter data:
Using a query to filter data
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
With the query service, you can define what data to fetch and how to filter it. Limitation of the JPA provider or other similar limitations do not apply. You can tailor database queries to your environment to increase performance.
66.3.9. Advanced query service 复制链接链接已复制到粘贴板!
The advanced query service provides capabilities to search for processes and tasks, based on process and task attributes, process variables, and internal variables of user tasks. The search automatically covers all existing processes in the process engine.
The names and required values of attributes and variables are defined in QueryParam
objects.
Process attributes include process instance ID, correlation key, process definition ID, and deployment ID. Task attributes include task name, owner, and status.
The following search methods are available:
-
queryProcessByVariables
: Search for process instances based on a list of process attributes and process variable values. To be included in the result, a process instance must have the listed attributes and the listed values in its process variables. -
queryProcessByVariablesAndTask
: Search for process instances based on a list of process attributes, process variable values, and task variable values. To be included in the result, a process instance must have the listed attributes and the listed values in its process variables. It also must include a task with the listed values in its task variables. -
queryUserTasksByVariables
: Search for user tasks based on a list of task attributes, task variable values, and process variable values. To be included in the result, a task must have the listed attributes and listed values in its task variables. It also must be included in a process with the listed values in its process variables.
The service is provided by the AdvanceRuntimeDataService
class. The interface for this class also defines predefined task and process attribute names.
Definition of the AdvanceRuntimeDataService
interface
66.3.10. Process instance migration service 复制链接链接已复制到粘贴板!
The process instance migration service is a utility for migrating process instances from one deployment to another. Process or task variables are not affected by the migration. However, the new deployment can use a different process definition.
When migrating a process, the process instance migration service also automatically migrates all the subprocesses of the process, the subprocesses of those subprocesses, and so on. If you attempt to migrate a subprocess without migrating the parent process, the migration fails.
For the simplest approach to process migration, let active process instances finish and start new process instances in the new deployment. If this approach is not suitable for your needs, consider the following issues before starting process instance migration:
- Backward compatibility
- Data change
- Need for node mapping
Whenever possible, create backward-compatible processes by extending process definitions. For example, removing nodes from the process definition breaks compatibility. If you make such changes, you must provide node mapping. Process instance migration uses node mapping if an active process instance is in a node that has been removed.
A node map contains source node IDs from the old process definition mapped to target node IDs in the new process definition. You can map nodes of the same type only, such as a user task to a user task.
Red Hat Process Automation Manager offers several implementations of the migration service:
Methods in the ProcessInstanceMigrationService
interface that implement the migration service
To migrate process instances on a KIE Server, use the following implementations. These methods are similar to the methods in the ProcessInstanceMigrationService
interface, providing the same migration implementations for KIE Server deployments.
Methods in the ProcessAdminServicesClient
interface that implement the migration service for KIE Server deployments
You can migrate a single process instance or multiple process instances at once. If you migrate multiple process instances, each instance is migrated in a separate transaction to ensure that the migrations do not affect each other.
After migration is completed, the migrate
method returns a MigrationReport
object that contains the following information:
- The start and end dates of the migration.
- The migration outcome (success or failure).
-
A log entry of the
INFO
,WARN
, orERROR
type. TheERROR
message terminates the migration.
The following example shows a process instance migration:
Migrating a process instance in a KIE Server deployment
Known limitations of process instance migration
The following situations can cause a failure of the migration or incorrect migration:
- A new or modified task requires inputs that are not available in the migrated process instance.
- You modify the tasks prior to the active task where the changes have an impact on further processing.
- You remove a human task that is currently active. To replace a human task, you must map it to another human task.
-
You add a new task parallel to the single active task. As all branches in an
AND
gateway are not activated, the process gets stuck. - You remove active timer events (these events are not changed in the database).
- You fix or update inputs and outputs in an active task (the task data is not migrated).
If you apply mapping to a task node, only the task node name and description are mapped. Other task fields, including the TaskName
variable, are not mapped to the new task.
66.3.11. Deployments and different process versions 复制链接链接已复制到粘贴板!
The deployment service puts business assets into an execution environment. However, in some cases additional management is required to make the assets available in the correct context. Notably, if you deploy several versions of the same process, you must ensure that process instances use the correct version.
Activation and Deactivation of deployments
In some cases, a number of process instances are running on a deployment, and then you add a new version of the same process to the runtime environment.
You might decide that new instances of this process definition must use the new version while the existing active instances should continue with the previous version.
To enable this scenario, use the following methods of the deployment service:
-
activate
: Activates a deployment so it can be available for interaction. You can list its process definitions and start new process instances for this deployment. -
deactivate
: Deactivates a deployment. Disables the option to list process definitions and to start new process instances of processes in the deployment. However, you can continue working with the process instances that are already active, for example, signal events and interact with user tasks.
You can use this feature for smooth transition between project versions without the need for process instance migration.
Invocation of the latest version of a process
If you need to use the latest version of the project’s process, you can use the latest
keyword to interact with several operations in services. This approach is supported only when the process identifier remains the same in all versions.
The following example explains the feature.
The initial deployment unit is org.jbpm:HR:1.0
. It contains the first version of a hiring process.
After several weeks, you develop a new version and deploy it to the execution server as org.jbpm:HR.2.0
. It includes version 2 of the hiring process.
If you want to call the process and ensure that you use the latest version, you can use the following deployment ID:
org.jbpm.HR:latest
org.jbpm.HR:latest
If you use this deployment ID, the process engine finds the latest available version of the project. It uses the following identifiers:
-
groupId
:org.jbpm
-
artifactId
:HR
The version numbers are compared by Maven rules to find the latest version.
The following code example shows deployment of multiple versions and interacting with the latest version:
Deploying multiple versions of a process and interacting with the latest version
This feature is also available in the KIE Server REST API. When sending a request with a deployment ID, you can use LATEST
as the version identifier.
Additional resources
66.3.12. Deployment synchronization 复制链接链接已复制到粘贴板!
Process engine services include a deployment synchronizer that stores available deployments into a database, including the deployment descriptor for every deployment.
The synchronizer also monitors this table to keep it in sync with other installations that might be using the same data source. This functionality is especially important when running in a cluster or when Business Central and a custom application must operate on the same artifacts.
By default, when running core services, you must configure synchronization. For EJB and CDI extensions, synchronization is enabled automatically.
The following code sample configures synchronization:
Configuring synchronization
With this configuration, deployments are synchronized every three seconds with an initial delay of two seconds.
66.4. Threads in the process engine 复制链接链接已复制到粘贴板!
We can refer to two types of multi-threading: logical and technical. Technical multi-threading involves multiple threads or processes that are started, for example, by a Java or C program. Logical multi-threading happens in a BPM process, for example, after the process reaches a parallel gateway. In execution logic, the original process splits into two processes that run in a parallel fashion.
Process engine code implements logical multi-threading using one technical thread.
The reason for this design choice is that multiple (technical) threads must be able to communicate state information to each other if they are working on the same process. This requirement brings a number of complications. The extra logic required for safe communication between threads, as well as the extra overhead required to avoid race conditions and deadlocks, can negate any performance benefit of using such threads.
In general, the process engine executes actions in series. For example, when the process engine encounters a script task in a process, it executes the script synchronously and waits for it to complete before continuing execution. In the same way, if a process encounters a parallel gateway, the process engine sequentially triggers each of the outgoing branches, one after the other.
This is possible because execution is almost always instantaneous, meaning that it is extremely fast and produces almost no overhead. As a result, sequential execution does not create any effects that a user can notice.
Any code in a process that you supply is also executed synchronously and the process engine waits for it to finish before continuing the process. For example, if you use a Thread.sleep(…)
as part of a custom script, the process engine thread is blocked during the sleep period.
When a process reaches a service task, the process engine also invokes the handler for the task synchronously and waits for the completeWorkItem(…)
method to return before continuing execution. If your service handler is not instantaneous, implement the asynchronous execution independently in your code.
For example, your service task might invoke an external service. The delay in invoking this service remotely and waiting for the results might be significant. Therefore, invoke this service asynchronously. Your handler must only invoke the service and then return from the method, then notify the process engine later when the results are available. In the meantime, the process engine can continue execution of the process.
Human tasks are a typical example of a service that needs to be invoked asynchronously. A human task requires a human actor to respond to a request, and the process engine must not wait for this response.
When a human task node is triggered, the human task handler only creates a new task on the task list of the assigned actor. The process engine is then able to continue execution on the rest of the process, if necessary. The handler notifies the process engine asynchronously when the user has completed the task.
66.5. Event Listeners in the process engine 复制链接链接已复制到粘贴板!
You can develop a class that implements the ProcessEventListener
interface. This class can listen to process-related events, such as starting or completing a process or entering and leaving a node.
The process engine passes an event object to this class. The object provides access to related information, like the process instance and node instance linked to the event.
The following list shows the different methods of the ProcessEventListener
interface:
Methods of the ProcessEventListener
interface
The before
and after
event calls typically act like a stack. If event A directly causes event B, the following sequence of calls happens:
- Before A
- Before B
- After B
- After A
For example, if leaving node X triggers node Y, all event calls related to triggering node Y occur between the beforeNodeLeft
and afterNodeLeft
calls for node X.
In the same way, if starting a process directly causes some nodes to start, all nodeTriggered
and nodeLeft
event calls occur between the beforeProcessStarted
and afterProcessStarted
calls.
This approach reflects cause and effect relationships between events. However, the timing and order of after
event calls are not always intuitive. For example, an afterProcessStarted
call can happen after the afterNodeLeft
calls for some nodes in the process.
In general, to be notified when a particular event occurs, use the before
call for the event. Use an after
call only if you want to make sure that all processing related to this event has ended, for example, when you want to be notified when all steps associated with starting a particular process instance have been completed.
Depending on the type of node, some nodes might only generate nodeLeft
calls and others might only generate nodeTriggered
calls. For example, catch intermediate event nodes do not generate nodeTriggered
calls, because they are not triggered by another process node. Similarly, throw intermediate event nodes do not generate nodeLeft
calls, as these nodes do not have an outgoing connection to another node.
The KieSession
class implements the RuleRuntimeEventManager
interface that provides methods for registering, removing, and listing event listeners, as shown in the following list.
Methods of the RuleRuntimeEventManager
interface
However, in a typical case, do not use these methods.
If you are using the RuntimeManager
interface, you can use the RuntimeEnvironment
class to register event listeners.
If you are using the Services API, you can add fully qualified class names of event listeners to the META-INF/services/org.jbpm.services.task.deadlines.NotificationListener
file in your project. The Services API also registers some default listeners, including org.jbpm.services.task.deadlines.notifications.impl.email.EmailNotificationListener
, which can send email notifications for events.
To exclude a default listener, you can add the fully qualified name of the listener to the org.kie.jbpm.notification_listeners.exclude
JVM system property.
66.5.1. KieRuntimeLogger event listener 复制链接链接已复制到粘贴板!
The KieServices
package contains the KieRuntimeLogger
event listener that you can add to your KIE session. You can use this listener to create an audit log. This log contains all the different events that occurred at runtime.
These loggers are intended for debugging purposes. They might be too detailed for business-level process analysis.
The listener implements the following logger types:
-
Console logger: This logger writes out all the events to the console. The fully qualified class name for this logger is
org.drools.core.audit.WorkingMemoryConsoleLogger
. File logger: This logger writes out all the events to a file using an XML representation. You can use the log file in an IDE to generate a tree-based visualization of the events that occurred during execution. The fully qualified class name for this logger is
org.drools.core.audit.WorkingMemoryFileLogger
.The file logger writes the events to disk only when closing the logger or when the number of events in the logger reaches a predefined level. Therefore, it is not suitable for debugging processes at runtime.
-
Threaded file logger: This logger writes the events to a file after a specified time interval. You can use this logger to visualize the progress in real time while debugging processes. The fully qualified class name for this logger is
org.drools.core.audit.ThreadedWorkingMemoryFileLogger
.
When creating a logger, you must pass the KIE session as an argument. The file loggers also require the name of the log file to be created. The threaded file logger requires the interval in milliseconds after which the events are saved.
Always close the logger at the end of your application.
The following example shows the use of the file logger.
Using the file logger
The log file that is created by the file-based loggers contains an XML-based overview of all the events that occurred during the runtime of the process.
66.6. Process engine configuration 复制链接链接已复制到粘贴板!
You can use several control parameters available to alter the process engine default behavior to suit the requirements of your environment.
Set these parameters as JVM system properties, usually with the -D
option when starting a program such as an application server.
Name | Possible values | Default value | Description |
---|---|---|---|
| String |
Alternative JNDI name to be used when there is no access to the default name ( NOTE: The name must be valid for the given runtime environment. Do not use this variable if there is no access to the default user transaction JNDI name. | |
|
|
| Enable multiple incoming and outgoing sequence flows support for activities |
| String |
/ | Alternative class path location of the business calendar configuration file |
| Long | 2000 | Specifies the delay for overdue timers to allow proper initialization, in milliseconds |
| String |
Alternative comparator class to enable starting a process by name, by default the | |
|
|
| Enable or disable loop iteration tracking for advanced loop support when using XOR gateways |
| String |
| Alternative JNDI name for the mail session used by Task Deadlines |
| String |
/ | Alternative class path location for a user group callback implementation (LDAP, DB) |
| String |
|
Alternative location of the |
| String |
/ |
Alternative class path location of the user info configuration (used by |
| String |
| Alternative separator of actors and groups for user tasks |
| String | Location of the Quartz configuration file to activate the Quartz-based timer service | |
| String |
| Location to store data files produced by the process engine |
| Integer |
| Thread pool size for the process engine executor |
| Integer | 3 | Number of retries attempted by the process engine executor in case of an error |
| Integer | 0 |
Frequency used to check for pending jobs by the process engine executor, in seconds. If the value is |
|
|
| Disable the process engine executor |
| String |
|
Fully qualified name of the class that implements |
| String |
Fully qualified names of event listeners that must be excluded even if they would otherwise be used. Separate multiple names with commas. For example, you can add | |
| String | Fully qualified names of event listeners that must be included. Separate multiple names with commas. If you set this property, only the listeners in this property are included and all other listeners are excluded. |