jBPMLogo

Getting Started

Introduction and getting started with jBPM

1. Overview

1.1. What is jBPM?

jBPM is a flexible Business Process Management (BPM) Suite. It is light-weight, fully open-source (distributed under Apache License 2.0) and written in Java. It allows you to model, execute, and monitor business processes and cases throughout their life cycle.

Process

A business process allows you to model your business goals by describing the steps that need to be executed to achieve those goals, and the order of those goals is depicted using a flow chart. This process greatly improves the visibility and agility of your business logic. jBPM focuses on executable business processes, which are business processes that contain enough detail so they can actually be executed on a BPM jBPM engine. Executable business processes bridge the gap between business users and developers as they are higher-level and use domain-specific concepts that are understood by business users but can also be executed directly.

Business processes need to be supported throughout their entire life cycle: authoring, deployment, process management and task lists, and dashboards and reporting.

The core of jBPM is a light-weight, extensible workflow engine written in pure Java that allows you to execute business processes using the latest BPMN 2.0 specification. It can run in any Java environment, embedded in your application or as a service.

On top of the jBPM engine, a lot of features and tools are offered to support business processes throughout their entire life cycle:

  • Pluggable human task service based on WS-HumanTask for including tasks that need to be performed by human actors.

  • Pluggable persistence and transactions (based on JPA / JTA).

  • Case management capabilities added to the jBPM engine to support more adaptive and flexible use cases

  • Web-based process designer to support the graphical creation and simulation of your business processes (drag and drop).

  • Web-based data modeler and form modeler to support the creation of data models and task forms

  • Web-based, customizable dashboards and reporting

  • All combined in one web-based Business Central application, supporting the complete BPM life cycle:

    • Modeling and deployment - author your processes, rules, data models, forms and other assets

    • Execution - execute processes, tasks, rules and events on the core runtime engine

    • Runtime Management - work on assigned task, manage process instances, etc

    • Reporting - keep track of the execution using Business Activity Monitoring capabilities

kie wb after login
  • Eclipse-based developer tools to support the modeling, testing and debugging of processes

  • Remote API to jBPM engine as a service (REST, JMS, Remote Java API)

  • Integration with Maven, Spring, OSGi, etc.

BPM creates the bridge between business analysts, developers and end users by offering process management features and tools in a way that both business users and developers like. Domain-specific nodes can be plugged into the palette, making the processes more easily understood by business users.

jBPM supports case management by offering more advanced features to support adaptive and dynamic processes that require flexibility to model complex, real-life situations that cannot easily be described using a rigid process. We bring control back to the end users by allowing them to control which parts of the process should be executed; this allows dynamic deviation from the process.

jBPM is not just an isolated jBPM engine. Complex business logic can be modeled as a combination of business processes with business rules and complex event processing. jBPM can be combined with the Drools project to support one unified environment that integrates these paradigms where you model your business logic as a combination of processes, rules and events.

1.2. Overview of jBPM

Overview

This figure gives an overview of the different components of the jBPM project.

  • The core engine is the heart of the project and allows you to execute business processes in a flexible manner. It is a pure Java component that you can choose to embed as part of your application or deploy it as a service and connect to it through the web-based UI or remote APIs.

    • An optional core service is the human task service that will take care of the human task life cycle if human actors participate in the process.

    • Another optional core service is runtime persistence; this will persist the state of all your process instances and log audit information about everything that is happening at runtime.

    • Applications can connect to the core engine through its Java API or as a set of CDI services, but also remotely through a REST and JMS API.

  • Web-based tools allow you to model, simulate and deploy your processes and other related artifacts (like data models, forms, rules, etc.):

    • The process designer allows business users to design and simulate business processes in a web-based environment.

    • The data modeler allows non-technical users to view, modify and create data models for use in your processes.

    • A web-based form modeler also allows you to create, generate or edit forms related to your processes (to start the process or to complete one of the user tasks).

    • Rule authoring allows you to specify different types of business rules (decision tables, guided rules, etc.) for combination with your processes.

    • All assets are stored and managed by the Guvnor repository (exposed through Git) and can be managed (versioning), built and deployed.

  • The web-based management console allows business users to manage their runtime (manage business processes like start new processes, inspect running instances, etc.), to manage their task list and to perform Business Activity Monitoring (BAM) and see reports.

  • The Eclipse-based developer tools are an extension to the Eclipse IDE, targeted towards developers, and allows you to create business processes using drag and drop, test and debug your processes, etc.

Each of the component is described in more detail below.

1.3. jBPM engine in jBPM

The jBPM engine implements the Business Process Management (BPM) paradigm in jBPM. BPM is a business methodology that enables modeling, measuring, and optimizing processes within an enterprise.

In BPM, a repeatable business process is represented as a workflow diagram. The Business Process Model and Notation (BPMN) specification defines the available elements of this diagram. The jBPM engine implements a large subset of the BPMN 2.0 specification.

With the jBPM engine, business analysts can develop the diagram itself. Developers can implement the business logic of every element of the flow in code, making an executable business process. Users can execute the business process and interact with it as necessary. Analysts can generate metrics that reflect the efficiency of the process.

The workflow diagram consists of a number of nodes. The BPMN specification defines many kinds of nodes, including the following principal types:

  • Event: Nodes representing something happening in the process or outside of the process. Typical events are the start and the end of a process. An event can throw messages to other processes and catch such messages. Circles on the diagram represent events.

  • Activity: Nodes representing an action that must be taken (whether automatically or with user involvement). Typical events are a task, which represents an action taken within the process, and a call to a subprocess. Rounded rectangles on the diagram represent activities.

  • Gateway: A branching or merging node. A typical gateway evaluates an expression and, depending on the result, continues to one of several execution paths. Diamond shapes on the diagram represent gateways.

When a user starts the process, a process instance is created. The process instance contains a set of data, or context, stored in process variables. The state of a process instance includes all the context data and also the current active node (or, in some cases, several active nodes).

Some of these variables can be initialized when a user starts the process. An activity can read from process variables and write to process variables. A gateway can evaluate process variables to determine the execution path.

For example, a purchase process in a shop can be a business process. The content of the user’s cart can be the initial process context. At the end of execution, the process context can contain the payment confirmation and shipment tracking details.

Optionally, you can use the BPMN data modeler in Business Central to design the model for the data in process variables.

The workflow diagram is represented in code by an XML business process definition. The logic of events, gateways, and subprocess calls are defined within the business process definition.

Some task types (for example, script tasks and the standard decision engine rule task) are implemented in the engine. For other task types, including all custom tasks, when the task must be executed the jBPM engine executes a call using the Work Item Handler API. Code external to the engine can implement this API, providing a flexible mechanism for implementing various tasks.

The jBPM engine includes a number of predefined types of tasks. These types include a script task that runs user Java code, a service task that calls a Java method or a Web Service, a decision task that calls a decision engine service, and other custom tasks (for example, REST and database calls).

Another predefined type of task is a user task, which includes interaction with a user. User tasks in the process can be assigned to users and groups.

The jBPM engine uses the KIE API to interact with other software components. You can run business processes as services on a KIE Server and interact with them using a REST implementation of the KIE API. Alternatively, you can embed business processes in your application and interact with them using KIE API Java calls. In this case, you can run the jBPM engine in any Java environment.

Business Central includes a user interface for users executing human tasks and a form modeler for creating the web forms for human tasks. However, you can also implement a custom user interface that interacts with the jBPM engine using the KIE API.

The jBPM engine supports the following additional features:

  • Support for persistence of the process information using the JPA standard. Persistence preserves the state and context (data in process variables) of every process instance, so that they are not lost in case any components are restarted or taken offline for some time. You can use an SQL database engine to store the persistence information.

  • Pluggable support for transactional execution of process elements using the JTA standard. If you use a JTA transaction manager, every element of the business process starts as a transaction. If the element does not complete, the context of the process instance is restored to the state in which it was before the element started.

  • Support for custom extension code, including new node types and other process languages.

  • Support for custom listener classes that are notified about various events.

  • Support for migrating running process instances to a new version of their process definition

The jBPM engine can also be integrated with other independent core services:

  • The human task service can manage user tasks when human actors need to participate in the process. It is fully pluggable and the default implementation is based on the WS-HumanTask specification. The human task service manages the lifecycle of the tasks, task lists, task forms, and some more advanced features like escalation, delegation, and rule-based assignments.

  • The history log can store all information about the execution of all the processes in the jBPM engine. While runtime persistence stores the current state of all active process instances, you need the history log to ensure access to historic information. The history log contains all current and historic states of all active and completed process instances. You can use the log to query for any information related to the execution of process instances for monitoring and analysis.

1.4. Business Central

The Business Central web-based application covers the complete life cycle of BPM projects starting at authoring phase, going through implementation, execution and monitoring. It combines a series web-based tools into one configurable solution to manage all assets and runtime data needed for the business solution.

It supports the following:

  • A repository service to store your business processes and related artifacts, using a Git repository, which supports versioning, remote Git access (as a file system) and access via REST.

  • A web-based user interface to manage your business processes, targeted towards business users; it also supports the visualization (and editing) of your artifacts (the web-based editors like designer, data and form modeler are integrated here), but also categorisation, build and deployment, etc..

  • Collaboration features which enable multiple actors (for example business users and developers) to work together on the same project.

kie wb after login
Figure 1. Business Central application

1.4.1. Process Designer

The web-based jBPM Designer allows you to model your business processes in a web-based environment. It is targeted towards business users and offers a graphical editor for viewing and editing your business processes (using drag and drop), similar to the Eclipse plugin. It supports round-tripping between the Eclipse editor and the web-based designer. It also supports simulation of processes.

Designer
Figure 2. Web-based designer for creating BPMN2 processes

1.4.2. Data Modeler

Processes almost always have some kind of data to work with. The data modeler allows non-technical users to view, edit or create these data models.

Typically, a business process analyst or data analyst will capture the requirements for a process or application and turn these into a formal set of interrelated data structures. The new Data Modeler tool provides an easy, straightforward and visual aid for building both logical and physical data models, without the need for advanced development skills or explicit coding. The data modeler is transparently integrated into Business Central. Its main goals are to make data models first class citizens in the process improvement cycle and allow for full process automation through the integrated use of data structures (and the forms that will be used to interact with them).

1.4.3. Process Management

Business processes and all its related runtime information can be managed through Business Central. It is targeted towards process administrators users and its main features include:

  • Process definitions management: view the entire list of process currently deployed into a Kie Server and its details.

  • Process instances management: the ability to start new process instances, get a filtered list of process instances, visually inspect the state of a specific process instances.

  • Human tasks management: being able to get a list of all tasks, view details such as current assignees, comments, activity logs as well as send reminders and forward tasks to different users and more.

  • Execution Errors management: allows administrators to view any execution error reported in the Kie Server instance, inspect its details including stacktrace and perform the error acknowledgement.

  • Jobs management: possibility to view currently scheduled and schedule new Jobs to run in the Kie Server instance.

ProcessInstanceDiagram
Figure 3. Managing your process instances

For more details around the entire management section please read the process management chapter.

1.4.4. Task Inbox

As often part of any process execution, human involvement is needed to review, approve or provide extra information. Business Central provides a Task Inbox section where any user potentially involved with these task can manage its workload. In there, users are able to get a list of all tasks, complete tasks using customizable task forms, collaborate using comments and more.

TaskInbox
Figure 4. Task Inbox

1.4.5. Business Activity Monitoring

As of version 6.0, jBPM comes with a full-featured BAM tooling which allows non-technical users to visually compose business dashboards. With this brand new module, to develop business activity monitoring and reporting solutions on top of jBPM has never been so easy!

BAM
Figure 5. Business Activity Monitoring

Key features:

  • Visual configuration of dashboards (Drag’n’drop).

  • Graphical representation of KPIs (Key Performance Indicators).

  • Configuration of interactive report tables.

  • Data export to Excel and CSV format.

  • Filtering and search, both in-memory or SQL based.

  • Data extraction from external systems, through different protocols.

  • Granular access control for different user profiles.

  • Look’n’feel customization tools.

  • Pluggable chart library architecture.

Target users:

  • Managers / Business owners. Consumer of dashboards and reports.

  • IT / System architects. Connectivity and data extraction.

  • Analysts / Developers. Dashboard composition & configuration.

To get further information about the new and noteworthy BAM capabilities of jBPM please read the chapter Business Activity Monitoring.

1.5. Eclipse Developer Tools

The Eclipse-based tools are a set of plugins to the Eclipse IDE and allow you to integrate your business processes in your development environment. It is targeted towards developers and has some wizards to get started, a graphical editor for creating your business processes (using drag and drop) and a lot of advanced testing and debugging capabilities.

EclipseFlow
Figure 6. Eclipse editor for creating BPMN2 processes

It includes the following features:

  • Wizard for creating a new jBPM project

  • A graphical editor for BPMN 2.0 processes

  • The ability to plug in your own domain-specific nodes

  • Validation

  • Runtime support (so you can select which version of jBPM you would like to use)

  • Graphical debugging to see all running process instances of a selected session, to visualize the current state of one specific process instance, etc.

2. Getting Started

We recommend taking a look at our Getting Start page as a starting point for getting a full environment up and running with all the components you need in order to design, deploy, run and monitor a process. Alternatively, you can also take a quick tutorial that will guide you through most of the components using a simple example available in the Installer Chapter. This will teach you how to download and use the installer to create a demo setup, including most of the components. It uses a simple example to guide you through the most important features. Screencasts are available to help you out as well.

If you like to read more information first, the following chapters first focus on the core jBPM engine (API, BPMN 2.0, etc.). Further chapters will then describe the other components and other more complex topics like domain-specific processes, flexible processes, etc. After reading the core chapters, you should be able to jump to other chapters that you might find interesting.

You can also start playing around with some examples that are offered in a separate download. Check out the Examples chapter to see how to start playing with these.

After reading through these chapters, you should be ready to start creating your own processes and integrate the jBPM engine with your application. These processes can be started from the installer or be started from scratch.

2.1. Downloads

Latest releases can be downloaded from jBPM.org. Just pick the artifact you want:

  • server: single zip distribution with jBPM server (including WildFly, Business Central, jBPM case management showcase and service repository)

  • bin: all the jBPM binaries (JARs) and their transitive dependencies

  • src: the sources of the core components

  • docs: the documentation

  • examples: some jBPM examples, can be imported into Eclipse

  • installer: the jBPM Installer, downloads and installs a demo setup of jBPM

  • installer-full: full jBPM Installer, downloads and installs a demo setup of jBPM, already contains a number of dependencies prepackaged (so they don’t need to be downloaded separately)

Older releases are archived at http://downloads.jboss.org/jbpm/release/.

Alternatively, you can also use one of the many Docker images available for use at the Download section.

2.2. Community

Here are a lot of useful links part of the jBPM community:

Please feel free to join us in our IRC channel at chat.freenode.net#jbpm. This is where most of the real-time discussion about the project takes place and where you can find most of the developers most of their time as well. Don’t have an IRC client installed? Simply go to http://webchat.freenode.net/, input your desired nickname, and specify #jbpm. Then click login to join the fun.

2.3. Sources

2.3.1. License

The jBPM code itself is using the Apache License v2.0.

Some other components we integrate with have their own license:

  • The new Eclipse BPMN2 plugin is Eclipse Public License (EPL) v1.0.

  • The legacy web-based designer is based on Oryx/Wapama and is MIT License

  • The Drools project is Apache License v2.0.

2.3.2. Source code

jBPM now uses git for its source code version control system. The sources of the jBPM project can be found here (including all releases starting from jBPM 5.0-CR1):

The source of some of the other components can be found here:

2.3.3. Building from source

If you’re interested in building the source code, contributing, releasing, etc. make sure to read this README.

2.4. Getting Involved

We are often asked "How do I get involved". Luckily the answer is simple, just write some code and submit it :) There are no hoops you have to jump through or secret handshakes. We have a very minimal "overhead" that we do request to allow for scalable project development. Below we provide a general overview of the tools and "workflow" we request, along with some general advice.

If you contribute some good work, don’t forget to blog about it :)

2.4.1. Sign up to jboss.org

Signing to jboss.org will give you access to the JBoss wiki, forums and JIRA. Go to https://www.jboss.org/ and click "Register".

sign jbossorg

2.4.2. Sign the Contributor Agreement

The only form you need to sign is the contributor agreement, which is fully automated via the web. As the image below says "This establishes the terms and conditions for your contributions and ensures that source code can be licensed appropriately"

sign contributor

2.4.3. Submitting issues via JIRA

To be able to interact with the core development team you will need to use JIRA, the issue tracker. This ensures that all requests are logged and allocated to a release schedule and all discussions captured in one place. Bug reports, bug fixes, feature requests and feature submissions should all go here. General questions should be undertaken at the mailing lists.

Minor code submissions, like format or documentation fixes do not need an associated JIRA issue created.

submit jira

2.4.4. Fork GitHub

With the contributor agreement signed and your requests submitted to JIRA you should now be ready to code :) Create a GitHub account and fork any of the Drools, jBPM or Guvnor repositories. The fork will create a copy in your own GitHub space which you can work on at your own pace. If you make a mistake, don’t worry blow it away and fork again. Note each GitHub repository provides you the clone (checkout) URL, GitHub will provide you URLs specific to your fork.

fork github

2.4.5. Writing Tests

When writing tests, try and keep them minimal and self contained. We prefer to keep the DRL fragments within the test, as it makes for quicker reviewing. If there are a large number of rules then using a String is not practical so then by all means place them in separate DRL files instead to be loaded from the classpath. If your tests need to use a model, please try to use those that already exist for other unit tests; such as Person, Cheese or Order. If no classes exist that have the fields you need, try and update fields of existing classes before adding a new class.

There are a vast number of tests to look over to get an idea, MiscTest is a good place to start.

unit test

2.4.6. Commit with Correct Conventions

When you commit, make sure you use the correct conventions. The commit must start with the JIRA issue id, such as DROOLS-1946. This ensures the commits are cross referenced via JIRA, so we can see all commits for a given issue in the same place. After the id the title of the issue should come next. Then use a newline, indented with a dash, to provide additional information related to this commit. Use an additional new line and dash for each separate point you wish to make. You may add additional JIRA cross references to the same commit, if it’s appropriate. In general try to avoid combining unrelated issues in the same commit.

Don’t forget to rebase your local fork from the original master and then push your commits back to your fork.

jira crossreferenced

2.4.7. Submit Pull Requests

With your code rebased from original master and pushed to your personal GitHub area, you can now submit your work as a pull request. If you look at the top of the page in GitHub for your work area there will be a "Pull Request" button. Selecting this will then provide a gui to automate the submission of your pull request.

The pull request then goes into a queue for everyone to see and comment on. Below you can see a typical pull request. The pull requests allow for discussions and it shows all associated commits and the diffs for each commit. The discussions typically involve code reviews which provide helpful suggestions for improvements, and allows for us to leave inline comments on specific parts of the code. Don’t be disheartened if we don’t merge straight away, it can often take several revisions before we accept a pull request. Luckily GitHub makes it very trivial to go back to your code, do some more commits and then update your pull request to your latest and greatest.

It can take time for us to get round to responding to pull requests, so please be patient. Submitted tests that come with a fix will generally be applied quite quickly, where as just tests will often way until we get time to also submit that with a fix. Don’t forget to rebase and resubmit your request from time to time, otherwise over time it will have merge conflicts and core developers will general ignore those.

submit pull request

2.5. What to do if I encounter problems or have questions?

You can always contact the jBPM community for assistance.

IRC: #jbpm at chat.freenode.net

jBPM Setup Google Group - Installation, configuration, setup and administration discussions for Business Central, Eclipse, runtime environments and general enterprise architectures.

jBPM Usage Google Group - Authoring, executing and managing processes with jBPM. Any questions regarding the use of jBPM. General API help and best practices in building BPM systems.

Visit our website for more options on how to get help.

Legacy jBPM User Forum - serves as an archive; post new questions to one of the Google Groups above

3. Business applications

3.1. Overview

Business application can be defined as an automated solution, built with selected frameworks and capabilities that implements business functions and/or business problems. Capabilities can be (among others):

  • persistence

  • messaging

  • transactions

  • business processes, business rules

  • planning solutions

Business application is more of a logical grouping of individual services that represent certain business capabilities. Usually they are deployed separately and can also be versioned individually. Overall goal is that the complete business application will allow particular domain to achieve their business goals e.g. order management, accommodation management, etc.

Business application is
  • Build on any runtime (most popular options)

    • SpringBoot

    • WildFly

    • Thorntail

  • deployable to cloud with just single command

    • OpenShift

    • Kubernetes

    • Docker

  • UI agnostic

    • Doesn’t enforce any UI frameworks and let users to make their own choice

  • Configurable database profiles

    • to allow smooth transition from one database to another with just single parameter/switch

  • Generated

    • makes it really easy to start for developers so they don’t get upset with initial failures usually related to configuration

Business application consists of
  • Many project

    • data model project - shared data model between business assets and service

    • business assets (kjar) project - easily importable into Business Central

    • service project - actual service with various capabilities

  • Configuration for

    • maven repository - settings.xml

    • database profiles

    • deployment setup

      • local

      • docker

      • OpenShift

Service project is the one that is deployable but will in most of the cases include business assets and data model projects. Data model project represents the common data structures that will be shared between service implementation and business assets. That enables proper encapsulation and promotes reuse and at the same time reduces shortcuts to make data model classes something more than they are - include too much of implementation into data models.

Business applications you build are not restricted to having only one of each project types. In order to build the solutions you need your business app can:

  • Have multiple data model projects - each service project can expose its own public data model

  • Have multiple business assets (kjar) projects - in case there is a business need for it

  • Have multiple service projects - to split services into smaller components for better manageability

  • Have UI modules - either per service (embedded in the service project) or a federated one (separate project for UI only)

  • Service projects can communicate with each other either directly or via business processes

Following diagram represents the sample business application

Business application diagram

3.2. Create your business application

Business application can be created in multiple ways, depending on the project types you need.

3.2.1. Generate business application

The fastest and recommended way to quickly generate your business application is by using the jBPM online service: start.jbpm.org

Generate application at start.jbpm.org

With the online service you can:

  • generate your business app using a default (most commonly used) configuration

  • configure your business application to include specific features that you need

The generated application will be delivered as a zip archive will following structure

generated application

To provide more information about individual steps, let’s review different options that user can choose from

3.2.1.1. Capabilities

Capabilities essentially define the features that your business application will be equipped with. Available options are:

  • Business automation covers features for process management, case management, decision management and optimisation. These will be by default configured in the service project of your business application. Although you can turn them off via configuration.

  • Decision management covers mainly decision and rules related features (backed by Drools project)

  • Business optimisation covers planning problems and solutions related features (backed by OptaPlanner project)

3.2.1.2. Application information

General information about the application that is

  • name - the name that will be used for the projects generated

  • package - valid Java package name that will be created in the projects and used as group of maven projects

  • version - selected version of jBPM/KIE that should be used for service project

3.2.1.3. Project types

Selection of project types to be included in the business application

  • data model - basic maven/jar project to keep the data structures

  • business assets - kjar project that can be easily imported into Business Central for development

  • service - service project that will include chosen capabilities with all bits configured

3.2.2. Manually create business application

In case you can’t use jBPM online service to generate the application you can manually create individual projects. jBPM provides maven archetypes that can be easily used to generate the application. In fact jBPM online service uses these archetypes behind the scenes to generate business application.

Business assets project archetype

org.kie:kie-kjar-archetype:7.44.0.Final

Service project archetype

org.kie:kie-service-spring-boot-archetype:7.44.0.Final

Data model archetype

org.apache.maven.archetypes:maven-archetype-quickstart:1.3

Example that allows to generate all three types of projects

mvn archetype:generate -B -DarchetypeGroupId=org.kie -DarchetypeArtifactId=kie-model-archetype -DarchetypeVersion=7.44.0.Final -DgroupId=com.company -DartifactId=test-model -Dversion=1.0-SNAPSHOT -Dpackage=com.company.model

mvn archetype:generate -B -DarchetypeGroupId=org.kie -DarchetypeArtifactId=kie-kjar-archetype -DarchetypeVersion=7.44.0.Final -DgroupId=com.company -DartifactId=test-kjar -Dversion=1.0-SNAPSHOT -Dpackage=com.company

mvn archetype:generate -B -DarchetypeGroupId=org.kie -DarchetypeArtifactId=kie-service-spring-boot-archetype -DarchetypeVersion=7.44.0.Final -DgroupId=com.company -DartifactId=test-service -Dversion=1.0-SNAPSHOT -Dpackage=com.company.service -DappType=bpm

When generating projects from the archetypes in same directory you should end up with exactly the same structure as generated by jBPM online service.

3.3. Run your business application

Once your business application is created, the next step is to actually run it.

3.3.1. Launch application

By default business application has a single runnable project - that is the service project. The service project is equipped with two scripts (both for linux and windows)

  • launch.sh/launch.bat

  • launch-dev.sh/launch-dev.bat

the main difference between these two scripts is the target execution

  • launch.sh/bat is dedicated to start application in standalone mode, without additional requirements.

  • launch-dev.sh/bat is dedicated to start application in sort of development mode (in other words managed mode) so it will require Business Central to be available as jBPM controller.

Development mode is meant to allow people to work on the business assets projects and dynamically deploy changes to the business application without the need to restart it. At the same time it provides a complete monitoring environment over business automation capabilities (process instances, tasks, jobs, etc).

To launch your application just go into service project ({your business application name}-service) and invoke

./launch.sh clean install for Linux/Unix

./launch.bat clean install for Windows

the clean install part of the command is to tell maven how to build. It will then build projects in following order

  • Data model

  • Business assets

  • Service

the first time it might take a while as it will download all dependencies of the project. At the end of the build it will start the application and after few seconds you should see output similar to following..,

INFO  o.k.s.s.a.KieServerAutoConfiguration     : KieServer (id business-application-service (name business-application-service)) started initialization process
INFO  o.k.server.services.impl.KieServerImpl   : Server Default Extension has been successfully registered as server extension
INFO  o.k.server.services.impl.KieServerImpl   : Drools KIE Server extension has been successfully registered as server extension
INFO  o.k.server.services.impl.KieServerImpl   : DMN KIE Server extension has been successfully registered as server extension
INFO  o.k.s.api.marshalling.MarshallerFactory  : Marshaller extensions init
INFO  o.k.server.services.impl.KieServerImpl   : jBPM KIE Server extension has been successfully registered as server extension
INFO  o.k.server.services.impl.KieServerImpl   : Case-Mgmt KIE Server extension has been successfully registered as server extension
INFO  o.k.server.services.impl.KieServerImpl   : jBPM-UI KIE Server extension has been successfully registered as server extension
INFO  o.k.s.s.impl.policy.PolicyManager        : Registered KeepLatestContainerOnlyPolicy{interval=0 ms} policy under name KeepLatestOnly
INFO  o.k.s.s.impl.policy.PolicyManager        : Policy manager started successfully, activated policies are []
INFO  o.k.server.services.impl.KieServerImpl   : Selected startup strategy ControllerBasedStartupStrategy - deploys kie containers given by controller ignoring locally defined
INFO  o.k.s.services.impl.ContainerManager     : About to install containers '[]' on kie server 'KieServer{id='business-application-service'name='business-application-service'version='7.9.0.Final'location='http://localhost:8090/rest/server'}'
INFO  o.k.server.services.impl.KieServerImpl   : KieServer business-application-service is ready to receive requests
INFO  o.k.s.s.a.KieServerAutoConfiguration     : KieServer (id business-application-service) started successfully
INFO  o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
INFO  s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8090 (http)
INFO  c.c.b.service.Application                : Started Application in 14.534 seconds (JVM running for 15.193)

and you should be able to access your business application at http://localhost:8090/

Business application landing page

3.3.2. Launch application in development mode

Development mode requires Business Central to be available, by default at http://localhost:8080/business-central. The easiest way to get that up and running is to use jBPM single distribution that can be downloaded at jbpm.org Look at the Getting Started guide to get yourself familiar with Business Central.

Make sure you have Business Central up and running before launching your business application in development mode.

3.3.3. Import your business assets project into Business Central

Business assets projects that was just created can be easily imported into Business Central as soon as it’s a valid git repository. To make it as such

  • Go into business assets project - {your business application name}-kjar

  • Execute git init

  • Execute git add -A

  • Execute git commit -m "Initial project structure"

  • Log in to Business Central and go to projects

  • Select import project and enter the following URL file:///{path to your business application}/{your business application name}-kjar

  • Click import and confirm project to be imported

3.3.3.1. Work on your business assets

Once the business assets project is imported into Business Central you can start working on it. Just go to the project and add assets such as business process, rules, decision tables etc.

3.3.3.2. Launch business application in development mode

To launch your application just go into service project ({your business application name}-service) and invoke

./launch-dev.sh clean install for Linux/Unix

./launch-dev.bat clean install for Windows

this should print the first entry after the build as follows

Launching the application in development mode - requires connection to controller (Business Central)

and similar as to launching in the standalone more after couple of seconds should be able to access your business application at http://localhost:8090/

Once the application started, it should be successfully connect to jBPM controller and by that be visible in the servers perspective of Business Central.

Connected business application
3.3.3.3. Deploy business assets project into running business application

After adding assets to your project in Business Central you can just deploy it to a running server instance. Click the Deploy button on your project and in few seconds you should see the project deployed on your business application.

Connected business application with deployed project

You can use Process Definitions and Process Instance perspectives of Business Central to interact with your newly deployed business assets such as processes or user tasks.

3.4. Configure business application

There are several components that can be configured in the business application. Depending on selected capabilities during application generation, a number of components can differ.

Entire configuration of the business application (service project) is done via application.properties file that is a standard way to configure SpringBoot applications. It is located under the src/main/resources directory of {your business application}-service folder.

3.4.1. Configuring core components

3.4.1.1. Configuring server

One of the most important configuration is actually the server itself. That is the host, port and path for the REST endpoints.

# used for server binding
server.address=localhost
server.port=8090

# used to define path for REST apis
cxf.path=/rest
3.4.1.2. Configure authentication and authorization

Business application is secured by default by protecting all REST endpoints (URL pattern /rest/*).

Authentication is enabled for single test user named user with password user. Additionally there is a default kieserver user that allows to easily connect to Business Central in development mode.

Both authentication and authorization is based on Spring Security and can be configured in DefaultWebSecurityConfig.java that is included in the generated service project (src/main/java/com/company/service/DefaultWebSecurityConfig.java)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;


@Configuration("kieServerSecurity")
@EnableWebSecurity
public class DefaultWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .csrf().disable()
        .authorizeRequests()
        .antMatchers("/rest/*").authenticated()
        .and()
        .httpBasic();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("user").password("user").roles("kie-server");
        auth.inMemoryAuthentication().withUser("kieserver").password("kieserver1!").roles("kie-server");
    }
}
This security configuration is just starting point and should be altered for all business applications going to production like setup.
Use Keycloak as authentication provider

Configuring business applications to use Keycloak as authentication and authorisation requires few steps

  • Install Keycloak - follow official documentation at keycloak.org

  • Configure Keycloak once started

    • Use default master realm or create new one

    • Create client named springboot-app and set its AccessType to public

    • Set Valid redirect URI and Web Origin according to your local setup - with default setup they should be set to

    • Valid Redirect URIs: http://localhost:8090/*

    • Web Origins: http://localhost:8090

    • Create realm roles that are used in the application

    • Create users used in the application and assign roles to them

  • Configure dependencies in service project pom.xml

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.keycloak.bom</groupId>
      <artifactId>keycloak-adapter-bom</artifactId>
      <version>${version.org.keycloak}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

  ....

<dependency>
  <groupId>org.keycloak</groupId>
  <artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>

Business application includes jBPM (KIE) execution server that can be configured to be better identified

kieserver.serverId=business-application-service
kieserver.serverName=business-application-service
kieserver.location=http://localhost:8090/rest/server
kieserver.controllers=http://localhost:8080/business-central/rest/controller
  • Configure application.properties

# keycloak security setup
keycloak.auth-server-url=http://localhost:8100/auth
keycloak.realm=master
keycloak.resource=springboot-app
keycloak.public-client=true
keycloak.principal-attribute=preferred_username
keycloak.enable-basic-auth=true
  • Modify DefaultWebSecurityConfig.java to ensure that Spring Security will work correctly with Keycloak

import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;

@Configuration("kieServerSecurity")
@EnableWebSecurity
public class DefaultWebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http
        .csrf().disable()
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .httpBasic();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
        SimpleAuthorityMapper mapper = new SimpleAuthorityMapper();
        mapper.setPrefix("");
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(mapper);
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Bean
    public KeycloakConfigResolver KeycloakConfigResolver() {
       return new KeycloakSpringBootConfigResolver();
    }

    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }
}

These are the steps to configure you business application to use Keycloak as authentication and authorisation service.

3.4.1.3. Configuring execution server

server id and server name refer to how the business application will be identified when connecting to the jBPM controller (Business Central) and thus should provide as meaningful information as possible.

location is used to inform other components that might interact with REST api where the execution server is accessible. It should not be the exact same location as defined by server.address and server.port especially when running in containers (Docker/OpenShift).

controllers allows to specify a (comma separated) list of URLs.

3.4.1.4. Configuring capabilities

In case your business application selected 'Business Automation' as the capability then there you can control which of them should actually be turned on on runtime.

# used for decision management
kieserver.drools.enabled=true
kieserver.dmn.enabled=true

# used for business processes and cases
kieserver.jbpm.enabled=true
kieserver.jbpmui.enabled=true
kieserver.casemgmt.enabled=true

# used for planning
kieserver.optaplanner.enabled=true
3.4.1.5. Configuring data source
Data source configuration is only required for business automation (meaning when jBPM is used)
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.url=jdbc:h2:./target/spring-boot-jbpm;MVCC=true
spring.datasource.driver-class-name=org.h2.Driver

Above configures shows the basic data source settings, next section will deal with connection pooling for efficient data access.

Depending on the driver class selected, make sure your application adds correct dependency that include the JDBC driver class or data source class.
narayana.dbcp.enabled=true
narayana.dbcp.maxTotal=20

this configuration enables the data source connection pool (that is based on commons-dbcp2 project) and a complete list of parameters can be found on configuration page. All parameters from the configuration page must be prefixed with narayana.dbcp.

3.4.1.6. Configuring JPA

jBPM uses Hibernate as the database access layer and thus needs to be properly configured

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
JPA configuration is completely based on SpringBoot so all options for both hibernate and JPA can be found as SpringBoot configuration page

Application with business automation capability creates entity manager factory based on persistence.xml that comes with jBPM. In case there are more entities that should be added to this entity manager factory (e.g. custom entities for the business application) they can easily be added by specifying a comma separated list of packages to scan

spring.jpa.properties.entity-scan-packages=org.jbpm.springboot.samples.entities

All entities found in that package will be automatically added to entity manager factory and thus used in the same manner as any other JPA entity in the application.

3.4.1.7. Configuring jBPM executor

jBPM executor is the backbone for asynchronous execution in jBPM. By default it is disabled, but can easily be turned on by configuration parameters.

jbpm.executor.enabled=true
jbpm.executor.retries=5
jbpm.executor.interval=0
jbpm.executor.threadPoolSize=1
jbpm.executor.timeUnit=SECONDS
  • jbpm.executor.enabled = true|false - allows to completely disable executor component

  • jbpm.executor.threadPoolSize = Integer - allows to specify thread pool size where default is 1

  • jbpm.executor.retries = Integer - allows to specify number of retries in case of errors while running a job

  • jbpm.executor.interval = Integer - allows to specify interval (by default in seconds) that executor will use to synchronize with database - default is 0 seconds which means it is disabled

  • jbpm.executor.timeUnit = String - allows to specify timer unit used for calculating interval, value must be a valid constant of java.util.concurrent.TimeUnit, by default it’s SECONDS.

3.4.1.8. Configuring distributed timers - Quartz

In case you plan to run your application in a cluster (multiple instances of it at the same time) then you need to take into account the timer service setup. Since the business application is running on top of Tomcat web container the only option for timer service for distributed setup is Quartz based.

jbpm.quartz.enabled=true
jbpm.quartz.configuration=quartz.properties

Above are two mandatory parameters and the configuration file that need to be either on the classpath or on the file system (if the path is given).

For distributed timers database storage should be used and properly configured via quartz.properties file.

#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = SpringBootScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.skipUpdateCheck=true
org.quartz.scheduler.idleWaitTime=1000
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreCMT
org.quartz.jobStore.driverDelegateClass=org.jbpm.process.core.timer.impl.quartz.DeploymentsAwareStdJDBCDelegate
org.quartz.jobStore.useProperties=false
org.quartz.jobStore.dataSource=myDS
org.quartz.jobStore.nonManagedTXDataSource=notManagedDS
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval = 5000
#============================================================================
# Configure Datasources
#============================================================================
org.quartz.dataSource.myDS.connectionProvider.class=org.jbpm.springboot.quartz.SpringConnectionProvider
org.quartz.dataSource.myDS.dataSourceName=quartzDataSource
org.quartz.dataSource.notManagedDS.connectionProvider.class=org.jbpm.springboot.quartz.SpringConnectionProvider
org.quartz.dataSource.notManagedDS.dataSourceName=quartzNotManagedDataSource
Data source names in quartz configuration file refer to Spring beans. Additionally connection provider needs to be set to org.jbpm.springboot.quartz.SpringConnectionProvider to allow integration with Spring based data sources.

By default Quartz requires two data sources:

  • managed data source so it can participate in transaction of the jBPM engine

  • not managed data source so it can look up for timers to trigger without any transaction handling

jBPM based business application assumes that quartz database (schema) will be collocated with jBPM tables and by that produces data source used for transactional operations for Quartz.

The other (non transactional) data source needs to be configured but it should point to the same database as the main data source.

# enable to use database as storage
jbpm.quartz.db=true

quartz.datasource.name=quartz
quartz.datasource.username=sa
quartz.datasource.password=sa
quartz.datasource.url=jdbc:h2:./target/spring-boot-jbpm;MVCC=true
quartz.datasource.driver-class-name=org.h2.Driver

# used to configure connection pool
quartz.datasource.dbcp2.maxTotal=15

# used to initialize quartz schema
quartz.datasource.initialization=true
spring.datasource.schema=classpath*:quartz_tables_h2.sql
spring.datasource.initialization-mode=always

The last three lines of the above configuration is responsible for initialising database schema automatically. When configured it should point to a proper DDL script.

3.4.1.9. Configuring different databases

Business application is generated with default H2 database - just to get started quickly and without any extra requirements. Since this default setup may not valid for production use the generated business applications come with configuration dedicated to:

  • MySQL

  • PostgreSQL

There are dedicated profiles - both Maven and Spring to get you started really fast without much work. The only thing you need to do is to alight the configuration with your databases.

MySQL configuration

spring.datasource.username=jbpm
spring.datasource.password=jbpm
spring.datasource.url=jdbc:mysql://localhost:3306/jbpm
spring.datasource.driver-class-name=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource

#hibernate configuration
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

PostgreSQL configuration

spring.datasource.username=jbpm
spring.datasource.password=jbpm
spring.datasource.url=jdbc:postgresql://localhost:5432/jbpm
spring.datasource.driver-class-name=org.postgresql.xa.PGXADataSource

#hibernate configuration
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

Once the updates to the configuration are done you can launch your application via

./launch.sh clean install -Pmysql for MySQL on Linux/Unix

./launch.bat clean install -Pmysql for MySQL on Windows

./launch.sh clean install -Ppostgres for MySQL on Linux/Unix

./launch.bat clean install -Ppostgres for MySQL on Windows

3.4.1.10. Configuring user group providers

Business automation capability supports human centric activities to be managed, to provide integration with user and group repositories there is a built in mechanism in jBPM. There are two entry points

  • UserGroupCallback - responsible for verification if user/group exists and for collecting groups for given user

  • UserInfo - responsible for collecting additional information about user/group such as email address, preferred language, etc

Both of these can be configured by providing alternative implementation - either one of the provided out of the box or custom developed.

When it comes to UserGroupCallback it is recommended to stick to the default one as it is based on the security context of the application. That means whatever backend store is used for authentication and authorisation (e.g. Keycloak) it will be used as source information for collecting user/group information.

UserInfo requires more advanced information to be collected and thus is a separate component. Not all user/group repositories will provide expect data especially those that are purely used for authentication and authorisation.

Following code is needed to provide alternative implementation of UserGroupCallback

@Bean(name = "userGroupCallback")
public UserGroupCallback userGroupCallback(IdentityProvider identityProvider) throws IOException {
    return new MyCustomUserGroupCallback(identityProvider);
}

Following code is needed to provide alternative implementation of UserInfo

@Bean(name = "userInfo")
public UserInfo userInfo() throws IOException {
    return new MyCustomUserInfo();
}
3.4.1.11. Enable Swagger documentation

Business application can easily enable Swagger based documentation for all endpoints available in the service project.

Add required dependencies to service project pom.xml
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-rs-service-description-swagger</artifactId>
  <version>3.1.11</version>
</dependency>
<dependency>
  <groupId>io.swagger</groupId>
  <artifactId>swagger-jaxrs</artifactId>
  <version>1.5.15</version>
  <exclusions>
    <exclusion>
      <groupId>javax.ws.rs</groupId>
      <artifactId>jsr311-api</artifactId>
    </exclusion>
  </exclusions>
</dependency>
Enable Swagger support in application.properties
kieserver.swagger.enabled=true

Swagger document can be found at http://localhost:8090/rest/swagger.json

Enable Swagger UI

To enable Swagger UI add following dependency to pom.xml of the service project.

<dependency>
  <groupId>org.webjars</groupId>
  <artifactId>swagger-ui</artifactId>
  <version>2.2.10</version>
</dependency>

Once the Swagger UI is enabled and server is started, complete set of endpoints can be found at http://localhost:8090/rest/api-docs/?url=http://localhost:8090/rest/swagger.json

3.5. Develop your business application

Developing custom logic in business application strictly depends on your specific requirements. In this guide we will provide some common steps that developers might need to get started.

3.5.1. Data model

The data model project in your generated business application promotes the idea (and best practice in fact) of designing data models with reuse in mind. At the same time it avoids putting too much in the model (which usually happens when model is colocated with the service itself).

Data model project should be seen as the API of the business application or one of its services. In case of application that is composed of several services it’s recommended that each service exposes its own data model (API).

That API then can be used by both service project and the business assets project.

Generated application model is not added as dependency to service nor business assets projects.

3.5.2. Business assets development

Business assets are usually developed in Business Central, where developers can create different assets types such as

  • Business processes

  • Case definitions

  • Rules

  • Decision tables

  • Data objects

  • Forms

  • Others

Before these assets can be created the business assets project needs to be imported into Business Central as described in Import your business assets project into Business Central

Whenever working with business assets you can easily try them out in your business application by running the application in development mode. That allows developer to build and deploy the assets project directly to a running application. Moreover Business Central can also be used to quickly interact with processes, tasks and cases. To learn more see Launch application in development mode

Once the work on business assets is finished it should be fetch back to your business application source.

  • go into business assets project - {your business application name}-kjar

  • execute git fetch origin

  • execute git rebase origin/master

With this your business assets are now part of the business application source tree and can be launched in standalone mode - without Business Central as jBPM controller.

To launch your application just go into service project ({your business application name}-service) and invoke

./launch.sh clean install for Linux/Unix

./launch.bat clean install for Windows

In case the version of your business assets project changes you will have to update that information in the service project. Locate the configuration file that is used for standalone mode {your business application name}-service.xml Edit it and update the version for the specific container.

Business assets project has two special files

  • pom.xml

  • src/main/resources/META-INF/kie-deployment-descriptor.xml

The first one is Apache Maven project file and is managed via Project Settings in Business Central. It allows to define project information (group id, artifact id, version, name, description). In addition it allows to define dependencies the project will have e.g. data model project.

Whenever dependencies are added from the following group ids they should be marked as scope provided

  • org.kie

  • org.drools

  • org.jbpm

  • org.optaplanner

Deployment descriptor allows to configure various components of the business automation capability such as

  • Persistence for jBPM

  • Runtime strategy

  • Event listeners

  • Work item handlers

  • Marshalling strategies

  • And more

for complete description of the deployment descriptor see Deployment descriptor

3.5.3. Work Item Handlers

Business processes can take advantage of so-called domain specific services which are implemented as work items and their actual execution is carried out by work item handlers. Work items defined in the process or case definition are linked by name with work item handler (the implementation).

Work item handlers can be registered in three ways

  • via deployment descriptor - use this approach if you want to decouple life cycle of the handler from your business application

  • via auto registration of Spring Components - use this when you have your handlers implemented as Spring beans (components) that are bound to the life cycle of the application

  • via manual registration of any work handler implementation - use this when the handler is not implemented by you and thus there is no way to use the Spring Component approach or it has advanced initialisation logic that does not fit the deployment descriptor approach

3.5.3.1. Register Work Item Handler via deployment descriptor

Registration in deployment descriptor can be done directly in Business Central via Project settings → Deployments

Add the work item handler mapped to the name of the work item

deployment descriptor work item handler

this will result in following source code of the deployment descriptor

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<deployment-descriptor xsi:schemaLocation="http://www.jboss.org/jbpm deployment-descriptor.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <persistence-unit>org.jbpm.domain</persistence-unit>
    <audit-persistence-unit>org.jbpm.domain</audit-persistence-unit>
    <audit-mode>JPA</audit-mode>
    <persistence-mode>JPA</persistence-mode>
    <runtime-strategy>SINGLETON</runtime-strategy>
    <marshalling-strategies/>
    <event-listeners/>
    <task-event-listeners/>
    <globals/>
    <work-item-handlers>
        <work-item-handler>
            <resolver>mvel</resolver>
            <identifier>new org.jbpm.process.workitem.rest.RESTWorkItemHandler("user", "password", classLoader)</identifier>
            <parameters/>
            <name>Rest</name>
        </work-item-handler>
    </work-item-handlers>
    <environment-entries/>
    <configurations/>
    <required-roles/>
    <remoteable-classes/>
    <limit-serialization-classes>true</limit-serialization-classes>
</deployment-descriptor>
3.5.3.2. Register Work Item Handler via auto registration of Spring Components

The easiest way to register work item handlers is to rely on Spring discovery and configuration of beans. It’s enough to annotate your work item handler class with @Component("WorkItemName") and that bean will be automatically registered in jBPM.

import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemHandler;
import org.kie.api.runtime.process.WorkItemManager;
import org.springframework.stereotype.Component;

@Component("Custom")
public class CustomWorkItemHandler implements WorkItemHandler {

    @Override
    public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {

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

    @Override
    public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {

    }

}

This will register CustomWorkItemHandler under Custom name so every work item named Custom will use that handler to execute it’s logic.

The name attribute of @Component annotations is mandatory for registration to happen. In case the name is missing work item handler won’t be registered and warning will be logged.
3.5.3.3. Register Work Item Handler programmatically

Last resort option is to get hold of DeploymentService and register handlers programmatically

@Autowire
private SpringKModuleDeploymentService deploymentService;

...

@PostConstruct
public void configure() {

    deploymentService.registerWorkItemHandler("Custom", new CustomWorkItemHandler());
}

3.5.4. Event listeners

jBPM allows to register various event listeners that will be invoked upon various events triggered by the jBPM engine. Supported event listener types are

  • ProcessEventListener

  • AgendaEventListener

  • RuleRuntimeEventListener

  • TaskLifeCycleEventListener

  • CaseEventListener

Similar to work item handlers, event listeners can be registered in three ways

  • via deployment descriptor - use this approach if you want to decouple life cycle of the listener from your business application

  • via auto registration of Spring Components - use this when you have your listeners implemented as Spring beans (components) that are bound to the life cycle of the application

  • via manual registration of any work handler implementation - use this when the listener is not implemented by you and thus there is no way to use the Spring Component approach or it has advanced initialisation logic that does not fit the deployment descriptor approach

3.5.4.1. Register event listener via deployment descriptor

Registration in deployment descriptor can be done directly in Business Central via Project settings → Deployments

deployment descriptor event listener

this will result in following source code of the deployment descriptor

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<deployment-descriptor xsi:schemaLocation="http://www.jboss.org/jbpm deployment-descriptor.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <persistence-unit>org.jbpm.domain</persistence-unit>
    <audit-persistence-unit>org.jbpm.domain</audit-persistence-unit>
    <audit-mode>JPA</audit-mode>
    <persistence-mode>JPA</persistence-mode>
    <runtime-strategy>SINGLETON</runtime-strategy>
    <marshalling-strategies/>
    <event-listeners>
        <event-listener>
            <resolver>mvel</resolver>
            <identifier>new org.jbpm.listeners.CustomProcessEventListener</identifier>
            <parameters/>
        </event-listener>
    </event-listeners>
    <task-event-listeners/>
    <globals/>
    <work-item-handlers/>
    <environment-entries/>
    <configurations/>
    <required-roles/>
    <remoteable-classes/>
    <limit-serialization-classes>true</limit-serialization-classes>
</deployment-descriptor>
3.5.4.2. Register event listener via auto registration of Spring Components

The easiest way to register event listeners is to rely on Spring discovery and configuration of beans. It’s enough to annotate your event listener implementation class with @Component() and that bean will be automatically registered in jBPM.

import org.kie.api.event.process.ProcessCompletedEvent;
import org.kie.api.event.process.ProcessEventListener;
import org.kie.api.event.process.ProcessNodeLeftEvent;
import org.kie.api.event.process.ProcessNodeTriggeredEvent;
import org.kie.api.event.process.ProcessStartedEvent;
import org.kie.api.event.process.ProcessVariableChangedEvent;
import org.springframework.stereotype.Component;

@Component
public class CustomProcessEventListener implements ProcessEventListener {

    @Override
    public void beforeProcessStarted(ProcessStartedEvent event) {

    }

    ...

}
Event listener can extend default implementation of given event listener to avoid implementing all methods e.g. org.kie.api.event.process.DefaultProcessEventListener

Type of the event listeners is determined by the interface (or super class) it implements.

3.5.4.3. Register event listener programmatically

Last resort option is to get hold of DeploymentService and register handlers programmatically

@Autowire
private SpringKModuleDeploymentService deploymentService;

...

@PostConstruct
public void configure() {

    deploymentService.registerProcessEventListener(new CustomProcessEventListener());
}

3.5.5. Custom REST endpoints

In many (if not all) cases there will be a need to expose additional REST endpoints for your business application (in your service project). This can be easily achieved by creating a JAX-RS compatible class (with JAX-RS annotations). It will automatically be registered with the running service when the following scanning option is configured in your apps application.properties config file:

cxf.jaxrs.classes-scan=true
cxf.jaxrs.classes-scan-packages=org.kie.server.springboot.samples.rest

The endpoint will be bound to the global REST api path defined in the cxf.path property.

An example of a custom endpoint can be found below

package org.kie.server.springboot.samples.rest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("extra")
public class AdditionalEndpoint {

    @GET
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Response listContainers() {

        return Response.ok().build();
    }
}

3.6. Deploy business application

Business applications are designed to run in pretty much any environment but for production the usual target is cloud-based runtimes that allow scalability and operational efficiency.

Business application deployable components are composed of services. Every application consists of one or more services that are deployed in isolation and in many cases will follow different release cycle.

3.6.1. OpenShift deployment

Business applications can be easily deployed to OpenShift Container Platform. It’s as easy as starting the application locally, meaning by using launch.sh/bat scripts.

You need to have OpenShift installed (good choice for local installation is minishift) or remote installation that can be accessed over network.

So first of all login to OpenShift Cluster

oc login -u system:admin

once successfully logged in following output (or similar) should be displayed

Logged into "https://192.168.64.2:8443" as "system:admin" using existing credentials.

You have access to the following projects and can switch between them with 'oc project <projectname>':

    default
    kube-public
    kube-system
  * myproject
    openshift
    openshift-infra
    openshift-node
    openshift-web-console

Using project "myproject".

To deploy your application as to OpenShift Container Platform just go into service project ({your business application name}-service) and invoke

./launch.sh clean install -Popenshift,h2 for Linux/Unix

./launch.bat clean install -Popenshift,h2 for Windows

The launch script will perform the build with openshift profile (see pom.xml in the business assets project and service project for details). The significant difference that is done for openshift is that the business assets project will generate an offline maven repository with the project itself and all its dependencies. Next this maven repository will be included in the image itself and maven (used by business automation capability) will work in offline mode - meaning no access to internet will be attempted.

Launching the application on OpenShift...
--> Found image ef440f7 (15 seconds old) in image stream "myproject/business-application-service" under tag "1.0-SNAPSHOT" for "business-application-service:1.0-SNAPSHOT"

    * This image will be deployed in deployment config "business-application-service"
    * Ports 8090/tcp, 8778/tcp, 9779/tcp will be load balanced by service "business-application-service"
      * Other containers can access this service through the hostname "business-application-service"

--> Creating resources ...
    deploymentconfig "business-application-service" created
    service "business-application-service" created
--> Success
    Application is not exposed. You can expose services to the outside world by executing one or more of the commands below:
     'oc expose svc/business-application-service'
    Run 'oc status' to view your app.
route "business-application-service" exposed

You can then go to OpenShift Web Console and look at the Overview of your project (myproject by default)

Business application on OpenShift

By clicking on the route url (in this case http://business-application-service-myproject.192.168.64.2.nip.io) you can go to the application already deployed and running.

3.6.2. Docker deployment

Business applications are by default configured with option to deploy service as docker container.

This is done in very similar way as launching the service locally - via launch.sh/bat script.

You must have Docker installed on your machine to make this work!

To deploy your application as docker container just go into service project ({your business application name}-service) and invoke

./launch.sh clean install -Pdocker,h2 for Linux/Unix

./launch.bat clean install -Pdocker,h2 for Windows

When building with docker proper database profile needs to be selected as well - this is done via -Pdocker,{db} so the image and the application gets proper JDBC driver selected.

The launch script will perform the build with docker profile (see pom.xml in the business assets project and service project for details). The significant difference that is done for docker container is that the business assets project will generate an offline maven repository with the project itself and all its dependencies. Next this maven repository will be included in the docker image itself and maven (used by business automation capability) will work in offline mode - meaning no access to internet will be attempted.

Once the build is complete launch script will directly create container and start it, this should be done once the following line is printed to console

Launching the application as docker container...
d40e4cdb662d3b1d9ddee27c5a843be31cb6e7dc4936b0fc1937ce8e48f440ae

the second line is the container id that can be later on used to interact with the container, for instance to follow the logs

docker logs -f d40e4cdb662d3b1d9ddee27c5a843be31cb6e7dc4936b0fc1937ce8e48f440ae

the business application will be accessible at the same port as configured by default that is 8090, simply go to http://localhost:8090 to see your application running as docker container.

3.6.3. Using external database

Currently business applications that require an external database need to provide the database in advance - before the application is launched and properly configured within the application configuration files.

Further releases will improve this by relying on docker compose/OpenShift templates.

3.7. Tutorials

3.7.1. My First Business Application

3.7.1.1. What will you do

You will build a simple but fully functional business application. Once you build it you will explore basic services exposed by the application.

3.7.1.2. What do you need
  • About 10 minutes of your time

  • Java (JDK) 8 or later

  • Maven 3.5.x

  • Access to the Internet

3.7.1.3. What should I do

To get started with business applications the easiest way is to generate the,. Go to start.jbpm.org and click button Generate default business application.

This will generate and download a business-application.zip file that will consists of three projects

  • business-application-model

  • business-application-kjar

  • business-application-service

Unzip the business-application.zip file into desired location and go into business-application-service directory. There you will find launch scripts (for both linux/unix and windows).

./launch.sh clean install for Linux/Unix

./launch.bat clean install for Windows

Execute one applicable to your operating system and wait for it to finish.

It might take quite some time (depending on your network) as it will download bunch of dependencies required to execute both build and application itself.
3.7.1.4. Results

Once the build and launch is complete you can open your browser http://localhost:8090 to see your first business application up and running.

It presents with a welcome screen that is mainly for verification purpose to illustrate that application started successfully.

You can point the browser to http://localhost:8090/rest/server to see the actual Business Automation capability services

By default all REST endpoints (url pattern /rest/*) are secured and require authentication. Default user that can be used to logon is user with password user

Business Automation service supports three types of data format

  • XML (JAXB based)

  • JSON

  • XML (XStream based)

To display Business Automation capability service details in different format set HTTP headers

  • Accept: application/json for JSON format

  • Accept: application/xml for XML (JAXB based) format

  • X-KIE-ContentType: XSTREAM for XML (XStream based) format

3.7.1.5. Summary

Congratulations! you have just built and started your first business application.

3.7.1.6. Source code of the tutorial

Here is the complete source code of the tutorial.

3.7.2. Business Application with Business Assets

3.7.2.1. What will you do

You will enhance your business application with some business assets

  • business process (BPMN2)

and execute this business assets

  • via REST api of your business application

  • via Business Central UI

3.7.2.2. What do you need
  • About 15 minutes of your time

  • Java (JDK) 8 or later

  • Maven 3.5.x

  • Access to the Internet

  • Business Central deployed - see single distribution for instructions

3.7.2.3. What should I do

If you haven’t done it already, complete tutorial My First Business Application.

Start Business Central (if not already started) and open your browser at http://localhost:8080/business-central and logon as user wbadmin with password wbadmin

Import your business assets project into Business Central
  • Go into business assets project - business-application-kjar

  • Execute git init

  • Execute git add -A

  • Execute git commit -m "my business assets project"

  • Log in to Business Central and go to projects

  • Select import project and enter the following URL file:///{path to your business application}/business-application-kjar

  • Click import and confirm project to be imported

Create Business Process

In browser where you logged into Business Central go to Projects. You will see your newly imported project named business-application-kjar, go into that project.

  • go into business-application-kjar project

  • click Add asset button

  • select Business Process asset

  • provide name for this asset

  • create your business process

Sample business process could be a single user task that will be assigned to user wbadmin.

Business process - sample
Pull back your business assets to business application source code
  • Go to business-application-kjar

  • Execute git remote add origin ssh://wbadmin@localhost:8001/MySpace/business-application-kjar

  • Execute git pull origin master - when prompted enter wbadmin as password

Go to business-application-service directory and launch the application

./launch.sh clean install for Linux/Unix

./launch.bat clean install for Windows

3.7.2.4. Results

Once the build and launch is complete you can open your browser http://localhost:8090

Next, point the browser to http://localhost:8090/rest/server/containers to see that your business assets project has been properly deployed and is running.

By default all REST endpoints (url pattern /rest/*) are secured and require authentication. Default user that can be used to logon is wbadmin with password wbadmin

Next, point the browser to http://localhost:8090/rest/server/containers/business-application-kjar/processes to see business processes available for execution.

Execute business process

You can execute business process via REST api exposed by your business application (in fact by Business Automation capability).

Optionally HTTP headers can be set to change the format of data returned

  • Accept: application/json for JSON format

  • Accept: application/xml for XML (JAXB based) format

  • X-KIE-ContentType: XSTREAM for XML (XStream based) format

{processid} needs to be replaced with actual process id that is returned from the endpoint http://localhost:8090/rest/server/containers/business-application-kjar/processes

Remember that endpoints are protected so make sure you provide user name and password when making the request.

In response to this request, a process instance id should be returned.

<long-type>
    <value>1</value>
</long-type>

You can examine details of that process instance by pointing your browser to http://localhost:8090/rest/server/containers/business-application-kjar/processes/instances/1

<process-instance>
  <process-instance-id>1</process-instance-id>
  <process-id>business-application-kjar.process</process-id>
  <process-name>process</process-name>
  <process-version>1.0</process-version>
  <process-instance-state>1</process-instance-state>
  <container-id>business-application-kjar-1_0-SNAPSHOT</container-id>
  <initiator>wbadmin</initiator>
  <start-date>2018-09-14T11:39:39.622+02:00</start-date>
  <process-instance-desc>process</process-instance-desc>
  <correlation-key>1</correlation-key>
  <parent-instance-id>-1</parent-instance-id>
  <sla-compliance>0</sla-compliance>
  <active-user-tasks>
    <task-summary>
      <task-id>1</task-id>
      <task-name>Task</task-name>
      <task-description/>
      <task-status>Reserved</task-status>
      <task-priority>0</task-priority>
      <task-actual-owner>wbadmin</task-actual-owner>
      <task-created-by>wbadmin</task-created-by>
      <task-created-on>2018-09-14T11:39:39.661+02:00</task-created-on>
      <task-activation-time>2018-09-14T11:39:39.661+02:00</task-activation-time>
      <task-proc-inst-id>1</task-proc-inst-id>
      <task-proc-def-id>business-application-kjar.process</task-proc-def-id>
      <task-container-id>business-application-kjar-1_0-SNAPSHOT</task-container-id>
    </task-summary>
  </active-user-tasks>
</process-instance>
Execute business process from Business Central UI

Stop the application if it’s running.

Go to business-application-service directory and launch the application in development mode

./launch-dev.sh clean install for Linux/Unix

./launch-dev.bat clean install for Windows

this will connect your business application to Business Central so can be administered from within its UI.

Go to Business Central in the browser and navigate to servers (from the home screen).

tutorial 2 empty server

As you can see the business-application-service Dev is there and connected. Although it does not have any kjars deployed. This is because it’s now running in managed mode meaning it’s Business Central that decides what kjars it should run.

So let’s deploy the business-application-kjar to our running application.

  • Go to projects from home screen of Business Central

  • Go into business-application-kjar project

  • Click Deploy button

  • Make sure that Server configuration is set to business-application-service-dev and click ok

The project should be successfully deployed and you can examine that state by going back to servers from home screen.

Next, go to process definitions (in Manage section of the Home screen) and select server configuration (top right corner) - again it should be business-application-service-dev the list of available process definition will be loaded and you should see your single process definition from the project business-application-kjar.

tutorial 2 process def

Examine details of that process definition by clicking on the row in the table. Switch to Diagram tab to see the visual representation of your process definition.

Start new instance of the business process by clicking on New instance button. This will bring up form (depending on your process definition) it might or might not have any fields. Just click on Submit button to start process instance.

Once started process instance details will be opened, you can examine different sections to learn more about your active process instance

tutorial 2 process instance
  • Instance details - base information about process instance

  • Process variables - latest values for process variables

  • Documents - list of documents managed by the process

  • Logs - detailed logs about what has been done within the process instance

  • Diagram - annotated diagram with completed (greyed out) and active (red borders) nodes

To look at user tasks, go to task inbox (in Track section of the Home screen). List of available tasks will be presented. This time there is no need to select server configuration because Business Central keeps track of recently selected configuration on different screens.

tutorial 2 task list
3.7.2.5. Summary

Congratulations! you have enhanced your business application to actually do something - execute business processes. At the same time you have created your first business process and made successful integration between your business application and Business Central.

3.7.2.6. Source code of the tutorial

Here is the complete source code of the tutorial.

3.7.3. Business Application with custom work item handlers and event listeners

3.7.3.1. What will you do

You will enhance your business application with business assets that execute custom business logic and monitors execution via event listeners.

  • business process (BPMN2) with custom service task (aka work item)

  • develop work item handler for the custom service task

  • develop process event listener that will receive events from the jBPM engine

and execute this business assets

  • via REST api of your business application

  • via Business Central UI

3.7.3.2. What do you need
  • About 20 minutes of your time

  • Java (JDK) 8 or later

  • Maven 3.5.x

  • IDE of your choice

  • Access to the Internet

  • Business Central deployed - see single distribution for instructions

3.7.3.3. What should I do

If you haven’t done it already, complete tutorial Business Application with Business Assets.

If you would like directly start with this tutorial you can get complete source of the Business Application with Business Assets tutorial from here

Start Business Central (if not already started) and open your browser at http://localhost:8080/business-central and logon as user wbadmin with password wbadmin

Import your business assets project into Business Central

if not already imported proceed with points below to import business asset project

  • Go into business assets project - business-application-kjar

  • Execute git init

  • Execute git add -A

  • Execute git commit -m "my business assets project"

  • Log in to Business Central and go to projects

  • Select import project and enter the following URL file:///{path to your business application}/business-application-kjar

  • Click import and confirm project to be imported

Create custom service task in Business Central
  • Go to Projects → business-application-kjar project

  • Click Add asset and select WorkItem Definition

  • Give it a name CustomTask

It should look like the following snippet

[
  [
    "name" : "MyTask",
    "parameters" : [
        "MyFirstParam" : new StringDataType(),
        "MySecondParam" : new StringDataType(),
        "MyThirdParam" : new ObjectDataType()
    ],
    "results" : [
        "Result" : new ObjectDataType("java.util.Map")
    ],
    "displayName" : "My Task",
    "icon" : ""
  ]
]
  • Save and close the editor

Create new process with service task (MyTask)
  • Click Add Asset button and select Business Process

  • Give it a name CustomTaskProcess

  • Open Service Tasks on the palette (cogs icon)

  • Drag and Drop the MyTask service task into the canvas

  • Connect it with start event and finish it with end event

It should look like this

tutorial 3 process with custom task
  • Save and close the editor

Implement custom work item handler
  • Import business-application-service project into IDE of your choice

  • Create new class MyTaskWorkItemHandler that implements org.kie.api.runtime.process.WorkItemHandler

  • Implement the executeWorkItemHandler by simply printing out work item and complete the work item

@Override
public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
    System.out.println("Work item being executed " + workItem);
    manager.completeWorkItem(workItem.getId(), null);
}
  • annotate the class with @Component annotation with name that matches the work item defined in Business Central

Complete class of the handler should look like this

package com.company.service.handlers;

import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemHandler;
import org.kie.api.runtime.process.WorkItemManager;
import org.springframework.stereotype.Component;

@Component("MyTask")
public class MyTaskWorkItemHandler implements WorkItemHandler {

    @Override
    public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
        System.out.println("Work item being executed " + workItem);
        manager.completeWorkItem(workItem.getId(), null);
    }

    @Override
    public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {

    }

}
Implement custom event listener

To be able to monitor execution of our business assets such as business process an event listener can be implemented. In this tutorial we focus on ProcessEventListener but there are other types such as:

  • TaskLifeCycleEventListener

  • CaseEventListener

  • RuleRuntimeEventListener

  • AgendaEventListener

Go back to IDE where the business-application-service is imported

  • Create class MyProcessEventListener that implements org.kie.api.event.process.ProcessEventListener

  • Implement methods with simple print outs

  • Annotate the class with Component - in this case the name is not relevant

Complete class of the event listener should look like this

package com.company.service.listeners;

import org.kie.api.event.process.ProcessCompletedEvent;
import org.kie.api.event.process.ProcessEventListener;
import org.kie.api.event.process.ProcessNodeLeftEvent;
import org.kie.api.event.process.ProcessNodeTriggeredEvent;
import org.kie.api.event.process.ProcessStartedEvent;
import org.kie.api.event.process.ProcessVariableChangedEvent;
import org.springframework.stereotype.Component;

@Component
public class MyProcessEventListener implements ProcessEventListener {

    @Override
    public void beforeProcessStarted(ProcessStartedEvent event) {
        System.out.println("beforeProcessStarted " + event);
    }

    @Override
    public void afterProcessStarted(ProcessStartedEvent event) {
        System.out.println("afterProcessStarted " + event);
    }

    @Override
    public void beforeProcessCompleted(ProcessCompletedEvent event) {
        System.out.println("beforeProcessCompleted " + event);
    }

    @Override
    public void afterProcessCompleted(ProcessCompletedEvent event) {
        System.out.println("afterProcessCompleted " + event);
    }

    @Override
    public void beforeNodeTriggered(ProcessNodeTriggeredEvent event) {
        System.out.println("beforeNodeTriggered " + event);
    }

    @Override
    public void afterNodeTriggered(ProcessNodeTriggeredEvent event) {
        System.out.println("afterNodeTriggered " + event);
    }

    @Override
    public void beforeNodeLeft(ProcessNodeLeftEvent event) {
        System.out.println("beforeNodeLeft " + event);
    }

    @Override
    public void afterNodeLeft(ProcessNodeLeftEvent event) {
        System.out.println("afterNodeLeft " + event);
    }

    @Override
    public void beforeVariableChanged(ProcessVariableChangedEvent event) {
        System.out.println("beforeVariableChanged " + event);
    }

    @Override
    public void afterVariableChanged(ProcessVariableChangedEvent event) {
        System.out.println("afterVariableChanged " + event);
    }

}
Run the application

At this point all development effort is done, the last remaining thing is to pull back the business assets project into the business-application-kjar project

  • Go to business-application-kjar

  • Execute git remote add origin ssh://wbadmin@localhost:8001/MySpace/business-application-kjar (if not already added)

  • Execute git pull origin master - when prompted enter wbadmin as password

Go to business-application-service directory and launch the application

./launch.sh clean install for Linux/Unix

./launch.bat clean install for Windows

3.7.3.4. Results

Once the build and launch is complete you can open your browser http://localhost:8090

Next, point the browser to http://localhost:8090/rest/server/containers to see that your business assets project has been properly deployed and is running.

By default all REST endpoints (url pattern /rest/*) are secured and require authentication. Default user that can be used to logon is wbadmin with password wbadmin

Next, point the browser to http://localhost:8090/rest/server/containers/business-application-kjar/processes to see business processes available for execution. You should see two of them.

Execute business process

You can execute business process via REST api exposed by your business application (in fact by Business Automation capability).

Optionally HTTP headers can be set to change the format of data returned

  • Accept: application/json for JSON format

  • Accept: application/xml for XML (JAXB based) format

  • X-KIE-ContentType: XSTREAM for XML (XStream based) format

{processid} needs to be replaced with actual process id that is returned from the endpoint http://localhost:8090/rest/server/containers/business-application-kjar/processes

Remember that endpoints are protected so make sure you provide user name and password when making the request.

In response to this request, a process instance id should be returned.

<long-type>
    <value>1</value>
</long-type>

You can examine details of that process instance by pointing your browser to http://localhost:8090/rest/server/containers/business-application-kjar/processes/instances/1

<process-instance>
  <process-instance-id>1</process-instance-id>
  <process-id>business-application-kjar.CustomTaskProcess</process-id>
  <process-name>CustomTaskProcess</process-name>
  <process-version>1.0</process-version>
  <process-instance-state>2</process-instance-state>
  <container-id>business-application-kjar-1_0-SNAPSHOT</container-id>
  <initiator>wbadmin</initiator>
  <start-date>2018-10-11T13:29:55.807+02:00</start-date>
  <process-instance-desc>CustomTaskProcess</process-instance-desc>
  <correlation-key>1</correlation-key>
  <parent-instance-id>-1</parent-instance-id>
  <sla-compliance>0</sla-compliance>
</process-instance>

Looking into the application logs (console) you should see that both the handler has been executed and event listener was notified about various events

beforeVariableChanged ==>[ProcessVariableChanged(id=initiator; instanceId=initiator; oldValue=null; newValue=wbadmin; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
afterVariableChanged ==>[ProcessVariableChanged(id=initiator; instanceId=initiator; oldValue=null; newValue=wbadmin; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
beforeProcessStarted ==>[ProcessStarted(name=CustomTaskProcess; id=business-application-kjar.CustomTaskProcess)]
beforeNodeTriggered ==>[ProcessNodeTriggered(nodeId=3; id=0; nodeName=null; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
beforeNodeLeft ==>[ProcessNodeLeft(nodeId=3; id=0; nodeName=null; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
beforeNodeTriggered ==>[ProcessNodeTriggered(nodeId=1; id=1; nodeName=My Task; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]

Work item being executed WorkItem 1 [name=MyTask, state=0, processInstanceId=1, parameters{}]

beforeNodeLeft ==>[ProcessNodeLeft(nodeId=1; id=1; nodeName=My Task; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
beforeNodeTriggered ==>[ProcessNodeTriggered(nodeId=2; id=2; nodeName=null; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
beforeNodeLeft ==>[ProcessNodeLeft(nodeId=2; id=2; nodeName=null; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
beforeProcessCompleted ==>[ProcessCompleted(name=CustomTaskProcess; id=business-application-kjar.CustomTaskProcess)]
afterProcessCompleted ==>[ProcessCompleted(name=CustomTaskProcess; id=business-application-kjar.CustomTaskProcess)]
afterNodeLeft ==>[ProcessNodeLeft(nodeId=2; id=2; nodeName=null; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
afterNodeTriggered ==>[ProcessNodeTriggered(nodeId=2; id=2; nodeName=null; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
afterNodeLeft ==>[ProcessNodeLeft(nodeId=1; id=1; nodeName=My Task; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
afterNodeTriggered ==>[ProcessNodeTriggered(nodeId=1; id=1; nodeName=My Task; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
afterNodeLeft ==>[ProcessNodeLeft(nodeId=3; id=0; nodeName=null; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
afterNodeTriggered ==>[ProcessNodeTriggered(nodeId=3; id=0; nodeName=null; processName=CustomTaskProcess; processId=business-application-kjar.CustomTaskProcess)]
afterProcessStarted ==>[ProcessStarted(name=CustomTaskProcess; id=business-application-kjar.CustomTaskProcess)]
3.7.3.5. Summary

Congratulations! you have enhanced your business application to take advantage of custom service tasks and you learned how to keep an eye on what is actually being executed by your business application. With this knowledge you can start doing more advanced service tasks that will integrate your application with the outside world.

3.7.3.6. Source code of the tutorial

Here is the complete source code of the tutorial.

3.7.4. Business Application with JPA entity

3.7.4.1. What will you do

You will enhance your business application with JPA entity that will be used both by your business application service and business assets.

  • develop JPA entity as part of your business-application-model project

  • business process (BPMN2) with user task that will display JPA entity

and execute this business assets

  • via REST api of your business application

  • via Business Central UI

3.7.4.2. What do you need
  • About 20 minutes of your time

  • Java (JDK) 8 or later

  • Maven 3.5.x

  • IDE of your choice

  • Access to the Internet

  • Business Central deployed - see single distribution for instructions

3.7.4.3. What should I do

If you haven’t done it already, complete tutorial Business Application with Business Assets.

If you would like directly start with this tutorial you can get complete source of the Business Application with Business Assets tutorial from here

Start Business Central (if not already started) and open your browser at http://localhost:8080/business-central and logon as user wbadmin with password wbadmin

Import your business assets project into Business Central

if not already imported proceed with points below to import business asset project

  • Go into business assets project - business-application-kjar

  • Execute git init

  • Execute git add -A

  • Execute git commit -m "my business assets project"

  • Log in to Business Central and go to projects

  • Select import project and enter the following URL file:///{path to your business application}/business-application-kjar

  • Click import and confirm project to be imported

Implement JPA entity
  • Import business-application-model project into IDE of your choice

  • Add to pom.xml of the model project dependency to JPA api (in scope provided)

<dependencies>
  <dependency>
    <groupId>org.hibernate.javax.persistence</groupId>
    <artifactId>hibernate-jpa-2.1-api</artifactId>
    <version>1.0.0.Final</version>
    <scope>provided</scope>
  </dependency>
</dependencies>
  • Implement class as JPA Entity Person

  • Create three fields in the class

    • id (of type Long)

    • firstName (of type String)

    • lastName (of type String)

  • Annotate the class with @Entity

  • Annotate the id field with @Id and @GeneratedValue(strategy = GenerationType.AUTO)

Complete class of the entity should look like this

package com.company.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String firstName;

    private String lastName;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "Person [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + "]";
    }

}
Configure service project to use the JPA entity
  • Import business-application-service project into IDE of your choice

  • Add dependency to the business-application-model in your service pom.xml

<dependency>
  <groupId>com.company</groupId>
  <artifactId>business-application-model</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>
  • Edit application.properties file (that is located in src/main/resources)

  • Add spring.jpa.properties.entity-scan-packages=com.company.model into the file

Adjust the package if you did not use the default com.company.model package
  • Add the same entry into application-dev.properties file

Create new process that use JPA entity
  • Log in to Business Central

  • Go to Projects → business-application-kjar project

  • Go to Settings tab

  • Go to Dependencies

  • Add dependency to business-application-model - make sure it is in provided scope

  • Go to Deployment → Marshalling strategy

  • Add new marshalling strategy with following value new org.drools.persistence.jpa.marshaller.JPAPlaceholderResolverStrategy(entityManagerFactory)

  • Go back to assets

  • Click Add Asset button and select Business Process

  • Give it a name JPAProcess

  • Open Tasks on the palette

  • Drag and Drop the User Task into the canvas

  • Connect it with start event and finish it with end event

  • Create variable named person with type (custom) com.company.model.Person

It should look like this

tutorial 4 process with jpa user task
  • Map the variable as input and output of user task - use same name for input and output variable

tutorial 4 process with jpa user task vars
  • Save and close the editor

Run the application

At this point all development effort is done, the last remaining thing is to pull back the business assets project into the business-application-kjar project

  • Go to business-application-kjar

  • Execute git remote add origin ssh://wbadmin@localhost:8001/MySpace/business-application-kjar (if not already added)

  • Execute git pull origin master - when prompted enter wbadmin as password

Go to business-application-service directory and launch the application

./launch.sh clean install for Linux/Unix

./launch.bat clean install for Windows

3.7.4.4. Results

Once the build and launch is complete you can open your browser http://localhost:8090

Next, point the browser to http://localhost:8090/rest/server/containers to see that your business assets project has been properly deployed and is running.

By default all REST endpoints (url pattern /rest/*) are secured and require authentication. Default user that can be used to logon is wbadmin with password wbadmin

Next, point the browser to http://localhost:8090/rest/server/containers/business-application-kjar/processes to see business processes available for execution. You should see two of them.

Execute business process

You can execute business process via REST api exposed by your business application (in fact by Business Automation capability).

HTTP method: POST

HTTP headers:

  • Accept: application/json

  • Content-Type: application/json

Body:

{
  "person" : {
    "Person" : {
      "firstName":"WB",
      "lastName":"Admin"
    }
  }
}

{processid} needs to be replaced with actual process id that is returned from the endpoint http://localhost:8090/rest/server/containers/business-application-kjar/processes

Remember that endpoints are protected so make sure you provide user name and password when making the request.

In response to this request, a process instance id should be returned.

1

You can examine details of that process instance by pointing your browser to http://localhost:8090/rest/server/containers/business-application-kjar/processes/instances/1?withVars=true

<process-instance>
  <process-instance-id>1</process-instance-id>
  <process-id>business-application-kjar.JPAProcess</process-id>
  <process-name>JPAProcess</process-name>
  <process-version>1.0</process-version>
  <process-instance-state>1</process-instance-state>
  <container-id>business-application-kjar-1_0-SNAPSHOT</container-id>
  <initiator>wbadmin</initiator>
  <start-date>2018-10-11T14:42:23.053+02:00</start-date>
  <process-instance-desc>JPAProcess</process-instance-desc>
  <correlation-key>1</correlation-key>
  <parent-instance-id>-1</parent-instance-id>
  <sla-compliance>0</sla-compliance>
  <active-user-tasks>
    <task-summary>
      <task-id>1</task-id>
      <task-name>Task</task-name>
      <task-description/>
      <task-status>Reserved</task-status>
      <task-priority>0</task-priority>
      <task-actual-owner>wbadmin</task-actual-owner>
      <task-created-by>wbadmin</task-created-by>
      <task-created-on>2018-10-11T14:42:23.058+02:00</task-created-on>
      <task-activation-time>2018-10-11T14:42:23.058+02:00</task-activation-time>
      <task-proc-inst-id>2</task-proc-inst-id>
      <task-proc-def-id>business-application-kjar.JPAProcess</task-proc-def-id>
      <task-container-id>business-application-kjar-1_0-SNAPSHOT</task-container-id>
    </task-summary>
  </active-user-tasks>
  <variables>
    <entry>
      <key>person</key>
      <value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="person">
        <firstName>WB</firstName>
        <id>1</id>
        <lastName>Admin</lastName>
      </value>
    </entry>
    <entry>
      <key>initiator</key>
      <value xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">wbadmin</value>
    </entry>
  </variables>
</process-instance>

This illustrates that an instance has been created, it has one user task assigned (the owner is wbadmin) and it has two process variables

  • initiator - set to the user who initiated the request

  • person - our JPA entity that was created based on the payload - but note that the id was generated automatically by the database

You can also examine user task by opening following URL in your browser http://localhost:8090/rest/server/containers/business-application-kjar/tasks/1?withInputData=true

<task-instance>
  <task-id>1</task-id>
  <task-priority>0</task-priority>
  <task-name>Task</task-name>
  <task-subject/>
  <task-description/>
  <task-form>Task</task-form>
  <task-status>Reserved</task-status>
  <task-actual-owner>wbadmin</task-actual-owner>
  <task-created-by>wbadmin</task-created-by>
  <task-created-on>2018-10-11T14:42:23.058+02:00</task-created-on>
  <task-activation-time>2018-10-11T14:42:23.058+02:00</task-activation-time>
  <task-skippable>false</task-skippable>
  <task-workitem-id>1</task-workitem-id>
  <task-process-instance-id>1</task-process-instance-id>
  <task-parent-id>-1</task-parent-id>
  <task-process-id>business-application-kjar.JPAProcess</task-process-id>
  <task-container-id>business-application-kjar-1_0-SNAPSHOT</task-container-id>
  <inputData>
    <entry>
      <key>TaskName</key>
      <value xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Task</value>
    </entry>
    <entry>
      <key>NodeName</key>
      <value xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Task</value>
    </entry>
    <entry>
      <key>person</key>
      <value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="person">
        <firstName>WB</firstName>
        <id>1</id>
        <lastName>Admin</lastName>
      </value>
    </entry>
    <entry>
      <key>Skippable</key>
      <value xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">false</value>
    </entry>
    <entry>
      <key>ActorId</key>
      <value xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">wbadmin</value>
    </entry>
  </inputData>
</task-instance>

Same person JPA entity is available on the task assigned to wbadmin

3.7.4.5. Summary

Congratulations! you have enhanced your business application to take advantage of a JPA entity as shared model between your business assets and service projects. With the power of business automation and JPA you learned how to externalise data managed by automated by business processes.

3.7.4.6. Source code of the tutorial

Here is the complete source code of the tutorial.

3.7.5. Business Application with ElasticSearch

3.7.5.1. What will you do

You will build business application that pushes out information about your business automation (processes, cases, tasks) directly to an ElasticSearch server. You can then use ElasticSearch REST api to perform advanced queries on top of your business data.

3.7.5.2. What do you need
  • About 20 minutes of your time

  • Java (JDK) 8 or later

  • Maven 3.5.x

  • IDE of your choice

  • Access to the Internet

  • Business Central deployed - see single distribution for instructions

3.7.5.3. What should I do
Install ElasticSearch

To get quickly up and running with ElasticSearch, make use of docker images provided by ElasticSearch.

docker pull docker.elastic.co/elasticsearch/elasticsearch:6.4.2

Once pulled, start it with basic settings recommended for development and test.

docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.4.2

Wait a bit and your ElasticSearch will be up and running, to verify if it is working as expected, open you browser at http://localhost:9200 and you should see similar content

{
  "name" : "IKXT4Z_",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "G7q7D2zgQy6JzLZBCzbtTQ",
  "version" : {
    "number" : "6.4.2",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "04711c2",
    "build_date" : "2018-09-26T13:34:09.098244Z",
    "build_snapshot" : false,
    "lucene_version" : "7.4.0",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}
when prompted for user name and password use elastic/changeme
Build business application

To get started with business applications the easiest way is to generate it. Go to start.jbpm.org and click button Generate default business application.

This will generate and download a business-application.zip file that will consists of three projects

  • business-application-model

  • business-application-kjar

  • business-application-service

Unzip the business-application.zip file into desired location and go into business-application-service directory. There you will find launch scripts (for both linux/unix and windows).

Start Business Central (if not already started) and open your browser at http://localhost:8080/business-central and logon as user wbadmin with password wbadmin

Import your business assets project into Business Central

if not already imported proceed with points below to import business asset project

  • Go into business assets project - business-application-kjar

  • Execute git init

  • Execute git add -A

  • Execute git commit -m "my business assets project"

  • Log in to Business Central and go to projects

  • Select import project and enter the following URL file:///{path to your business application}/business-application-kjar

  • Click import and confirm project to be imported

Create Business Process

In browser where you logged into Business Central go to Projects. You will see your newly imported project named business-application-kjar, go into that project.

  • go into business-application-kjar project

  • click Add asset button

  • select Business Process asset

  • provide name for this asset

  • create your business process

Sample business process could be a single user task that will be assigned to user wbadmin.

Business process - sample
Configure service project to use the ElasticSearch
  • Import business-application-service project into IDE of your choice

  • Add dependency to the jbpm-event-emitters-elasticsearch in your service pom.xml

<dependency>
  <groupId>org.jbpm</groupId>
  <artifactId>jbpm-event-emitters-elasticsearch</artifactId>
  <version>${version.org.kie}</version>
</dependency>

There are several configuration parameters that define how business application will connect to ElasticSearch server

  • jbpm.addons.event.emitters.elasticsearch.url - location of the ElasticSearch server, defaults to http://localhost:9200

  • jbpm.addons.event.emitters.elasticsearch.date_format - date format to be used for dates defaults to yyyy-MM-dd’T’hh:mm:ss.SSSZ

  • jbpm.addons.event.emitters.elasticsearch.user - optional user name to be used to authenticate in ElasticSearch server

  • jbpm.addons.event.emitters.elasticsearch.password - optional password to be used to authenticate in ElasticSearch server

If the defaults fit your ElasticSearch setup then you don’t need to set any properties in application.properties.

For the default setup we use in this tutorial, user and password need to be set

  • Edit application.properties file (that is located in src/main/resources)

  • Add jbpm.addons.event.emitters.elasticsearch.user=elastic into the file

  • Add jbpm.addons.event.emitters.elasticsearch.password=changeme into the file

Add the same entry into application-dev.properties file
Run the application

At this point all development effort is done, the last remaining thing is to pull back the business assets project into the business-application-kjar project

  • Go to business-application-kjar

  • Execute git remote add origin ssh://wbadmin@localhost:8001/MySpace/business-application-kjar (if not already added)

  • Execute git pull origin master - when prompted enter wbadmin as password

Go to business-application-service directory and launch the application

./launch.sh clean install for Linux/Unix

./launch.bat clean install for Windows

3.7.5.4. Results

Once the build and launch is complete you can open your browser http://localhost:8090 to see your business application up and running.

It presents with a welcome screen that is mainly for verification purpose to illustrate that application started successfully.

You can point the browser to http://localhost:8090/rest/server to see the actual Business Automation capability services

By default all REST endpoints (url pattern /rest/*) are secured and require authentication. Default user that can be used to logon is wbadmin with password wbadmin

Next, point the browser to http://localhost:8090/rest/server/containers/business-application-kjar/processes to see business processes available for execution. You should see just one.

Execute business process

You can execute business process via REST api exposed by your business application (in fact by Business Automation capability).

HTTP method: POST

HTTP headers:

  • Accept: application/json

  • Content-Type: application/json

Body:

{
  "name":"wbadmin",
  "age":25
}

{processid} needs to be replaced with actual process id that is returned from the endpoint http://localhost:8090/rest/server/containers/business-application-kjar/processes

Remember that endpoints are protected so make sure you provide user name and password when making the request.

Once executed you can verify the integration with ElasticSearch simply by pointing your browser to http://localhost:9200/processes/_search?pretty=true and the result should be as follows

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "processes",
        "_type" : "process",
        "_id" : "business-application-service-dev_1",
        "_score" : 1.0,
        "_source" : {
          "compositeId" : "business-application-service-dev_1",
          "id" : 1,
          "processId" : "usertaskprocess",
          "processName" : "usertaskprocess",
          "processVersion" : "1.0",
          "state" : 1,
          "containerId" : "business-application-kjar_1.0-SNAPSHOT",
          "initiator" : "wbadmin",
          "date" : "2018-10-25T02:41:55.205+0200",
          "processInstanceDescription" : "usertaskprocess",
          "correlationKey" : "1",
          "parentId" : -1,
          "variables" : {
            "initiator" : "wbadmin",
            "name" : "wbadmin",
            "age" : 25
          }
        }
      }
    ]
  }
}

and to see user tasks stored in ElasticSearch point your browser to http://localhost:9200/tasks/_search?pretty=true

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "tasks",
        "_type" : "task",
        "_id" : "business-application-service-dev_1",
        "_score" : 1.0,
        "_source" : {
          "compositeId" : "business-application-service-dev_1",
          "id" : 1,
          "priority" : 8,
          "name" : "Complete me",
          "subject" : "TaskSubject",
          "description" : "Here is a task for wbadmin",
          "taskType" : null,
          "formName" : "CompleteMe",
          "status" : "Reserved",
          "actualOwner" : "wbadmin",
          "createdBy" : "wbadmin",
          "createdOn" : "2018-10-25T02:41:54.942+0200",
          "activationTime" : "2018-10-25T02:41:54.942+0200",
          "expirationDate" : null,
          "skipable" : false,
          "workItemId" : 1,
          "processInstanceId" : 1,
          "parentId" : -1,
          "processId" : "usertaskprocess",
          "containerId" : "business-application-kjar_1.0-SNAPSHOT",
          "potentialOwners" : [
            "wbadmin"
          ],
          "excludedOwners" : [ ],
          "businessAdmins" : [
            "Administrator",
            "Administrators"
          ],
          "inputData" : {
            "Comment" : "TaskSubject",
            "Description" : "Here is a task for wbadmin",
            "TaskName" : "CompleteMe",
            "NodeName" : "Complete me",
            "Priority" : "8",
            "name" : "wbadmin",
            "Skippable" : "false",
            "ActorId" : "wbadmin",
            "age" : 25
          },
          "outputData" : null
        }
      }
    ]
  }
}

When you complete a task or abort a process instance data in ElasticSearch will be immediately updated.

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "processes",
        "_type" : "process",
        "_id" : "business-application-service-dev_2",
        "_score" : 1.0,
        "_source" : {
          "compositeId" : "business-application-service-dev_2",
          "id" : 2,
          "processId" : "usertaskprocess",
          "processName" : "usertaskprocess",
          "processVersion" : "1.0",
          "state" : 3,
          "containerId" : "business-application-kjar_1.0-SNAPSHOT",
          "initiator" : "wbadmin",
          "date" : "2018-10-25T03:01:02.557+0200",
          "processInstanceDescription" : "usertaskprocess",
          "correlationKey" : "2",
          "parentId" : -1,
          "variables" : {
            "initiator" : "wbadmin",
            "name" : "bartek",
            "age" : 5
          }
        }
      }
    ]
  }
}
3.7.5.5. Summary

Congratulations! you have integrated your business application with ElasticSearch. Now you can take advantage of all the good things ElasticSearch provides you with such as full text search by process variables, task assignees, case participants and more.

3.7.5.6. Source code of the tutorial

Here is the complete source code of the tutorial.

3.7.6. Business Application with JMS

3.7.6.1. What will you do

You will build business application that uses JMS to send information between your business processes. It combines process logic and messaging to provide comprehensive solution to common problems such as - how to notify other participants of particular event.

3.7.6.2. What do you need
  • About 20 minutes of your time

  • Java (JDK) 8 or later

  • Maven 3.5.x

  • IDE of your choice

  • Access to the Internet

  • Business Central deployed - see single distribution for instructions

3.7.6.3. What should I do
Install Apache Artemis

Download and unzip Apache Artemis distribution. Refer to the location where you unzip it as ${ARTEMIS_HOME}.

Once downloaded, navigate to the location where you want to store your broker data and create new broker

${ARTEMIS_HOME}/bin/artemis create business-app-broker

You will be prompted for some required information during creation, that should look like this

Creating ActiveMQ Artemis instance at: /.../business-app-broker

--user: is a mandatory property!
Please provide the default username:
admin

--password: is mandatory with this configuration:
Please provide the default password:


--allow-anonymous | --require-login: is a mandatory property!
Allow anonymous access?, valid values are Y,N,True,False
Y

Next, start the broker instance, go to business-app-broker/bin and issue following command

./artemis run

Open your browser at http://localhost:8161/console to logon to management console of Apache Artemis with user name and password provided at the time you created the broker.

For more detailed instruction on how to configure Apache Artemis visit its website

Last step in configuring JMS service is to create a queue (or an address as it’s called in Apache Artemis).

Once logged into Management Console

  • Go to Artemis in the menu

  • Expand the tree view and click addresses

  • On right hand side click Create

  • Create new address with name ExternalSignalQueue

  • Select Anycast

All steps are done for installing and configuring Apache Artemis for this tutorial.

Build business application

To get started with business applications the easiest way is to generate it. Go to start.jbpm.org and click button Generate default business application.

This will generate and download a business-application.zip file that will consists of three projects

  • business-application-model

  • business-application-kjar

  • business-application-service

Unzip the business-application.zip file into desired location and go into business-application-service directory. There you will find launch scripts (for both linux/unix and windows).

Start Business Central (if not already started) and open your browser at http://localhost:8080/business-central and logon as user wbadmin with password wbadmin

Import your business assets project into Business Central

if not already imported proceed with points below to import business asset project

  • Go into business assets project - business-application-kjar

  • Execute git init

  • Execute git add -A

  • Execute git commit -m "my business assets project"

  • Log in to Business Central and go to projects

  • Select import project and enter the following URL file:///{path to your business application}/business-application-kjar

  • Click import and confirm project to be imported

Create Business Processes

In browser where you logged into Business Central go to Projects. You will see your newly imported project named business-application-kjar, go into that project.

  • go into business-application-kjar project

  • click Add asset button

  • select Business Process asset

  • provide name for this asset (throwsignalprocess)

  • create your business process

Sample business process should be a single script task and end signal event. Signal event should use external scope and define a signal IamDone

Business process - sample

Process should define single process variable input that is then mapped as data output of the end event.

Business process - sample

Next create another business process that will receive that signal.

  • go into business-application-kjar project

  • click Add asset button

  • select Business Process asset

  • provide name for this asset (catchsignalprocess)

  • create your business process

Sample business process should be a signal catch event and single user task assigned to wbadmin. The catch signal event should use the signal same as throwing one and that is IamDone

Business process - sample

Process should define single process variable data that is then mapped as data input of the catch event.

Business process - sample
Configure service project to use the Apache Artemis
  • Import business-application-service project into IDE of your choice

  • Add dependency to the spring-boot-starter-artemis in your service pom.xml

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
  • Add dependency to the jbpm-workitems-jms in your service pom.xml

<dependency>
  <groupId>org.jbpm</groupId>
  <artifactId>jbpm-workitems-jms</artifactId>
  <version>${version.org.kie}</version>
</dependency>

There are several configuration parameters that define how business application will connect to Apache Artemis

  • Edit application.properties file (that is located in src/main/resources)

spring.artemis.mode=native
spring.artemis.host=localhost
spring.artemis.port=61616
spring.artemis.user=admin
spring.artemis.password=admin
Use the user credentials you provided when creating the broker in the configuration
Add the same entry into application-dev.properties file
Develop JMS components of your Business Application

First of all, you need to enable jms on the service level.

  • Open Application class (located in src/main/java/com/company/service directory)

  • Add @EnableJms on the class level (next to @SpringBootApplication)

Then create a new class that will be responsible for sending signals over JMS. This will be really small extension to out of the box JMS work item handler. ConfiguredJMSSendTaskWorkItemHandler needs to extend org.jbpm.process.workitem.jms.JMSSendTaskWorkItemHandler and this is where the most of the logic comes from.

This class needs to autowire

  • ConnectionFactory - used to connect to Apache Artemis

  • JmsTemplate - used to send messages

Overload executeWorkItem method to take advantage of JmsTemplate instead of direct JMS API.

Last but not least, annotate the class with @Component annotation so it will be automatically registered as work item handler. Below is the complete source code of the handler implementation.

package com.company.service.jms;

import javax.jms.ConnectionFactory;

import org.jbpm.process.workitem.jms.JMSSendTaskWorkItemHandler;
import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemManager;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;

@Component("External Send Task")
public class ConfiguredJMSSendTaskWorkItemHandler extends JMSSendTaskWorkItemHandler {

    private JmsTemplate jmsTemplate;

    public ConfiguredJMSSendTaskWorkItemHandler(ConnectionFactory connectionFactory, JmsTemplate jmsTemplate) {
        super(connectionFactory, null);
        this.jmsTemplate = jmsTemplate;
    }

    @Override
    public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
        try {
            jmsTemplate.send("ExternalSignalQueue", (session) -> createMessage(workItem, session));
            manager.completeWorkItem(workItem.getId(), null);
        } catch (Exception e) {
            handleException(e);
        }
    }
}

Last development activity is to create the message receiver. This is even easier than sender as there is out of the box receiver from jBPM - org.jbpm.process.workitem.jms.JMSSignalReceiver

package com.company.service.jms;

import javax.jms.BytesMessage;

import org.jbpm.process.workitem.jms.JMSSignalReceiver;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class ReceiveJMSEvents extends JMSSignalReceiver {

    @JmsListener(destination = "ExternalSignalQueue")
    public void processMessage(BytesMessage content) {
        super.onMessage(content);
    }

}

And that’s it, you’re all set to communicate between business processes via JMS.

Run the application

At this point all development effort is done, the last remaining thing is to pull back the business assets project into the business-application-kjar project

  • Go to business-application-kjar

  • Execute git remote add origin ssh://wbadmin@localhost:8001/MySpace/business-application-kjar (if not already added)

  • Execute git pull origin master - when prompted enter wbadmin as password

Go to business-application-service directory and launch the application

./launch.sh clean install for Linux/Unix

./launch.bat clean install for Windows

3.7.6.4. Results

Once the build and launch is complete you can open your browser http://localhost:8090 to see your business application up and running.

It presents with a welcome screen that is mainly for verification purpose to illustrate that application started successfully.

You can point the browser to http://localhost:8090/rest/server to see the actual Business Automation capability services

By default all REST endpoints (url pattern /rest/*) are secured and require authentication. Default user that can be used to logon is wbadmin with password wbadmin

Next, point the browser to http://localhost:8090/rest/server/containers/business-application-kjar/processes to see business processes available for execution. You should see two processes:

  • catchsignalprocess

  • throwsignalprocess

Execute business process

You can execute business process via REST api exposed by your business application (in fact by Business Automation capability).

First start process instance that will wait for a signal

HTTP method: POST

HTTP headers:

  • Accept: application/json

  • Content-Type: application/json

And then start process instance that will throw (send) signal via JMS

HTTP method: POST

HTTP headers:

  • Accept: application/json

  • Content-Type: application/json

Body:

{
  "input":"hello"
}
Remember that endpoints are protected so make sure you provide user name and password when making the request.

Verify that there is a user task assigned to wbadmin user with information coming from second process instance - hello

Execute business process from Business Central UI

Stop the application if it’s running.

Go to business-application-service directory and launch the application in development mode

./launch-dev.sh clean install for Linux/Unix

./launch-dev.bat clean install for Windows

this will connect your business application to Business Central so can be administered from within its UI.

Go to Business Central in the browser and navigate to servers (from the home screen).

Let’s deploy the business-application-kjar to our running application.

  • Go to projects from home screen of Business Central

  • Go into business-application-kjar project

  • Click Deploy button

  • Make sure that Server configuration is set to business-application-service-dev and click ok

The project should be successfully deployed and you can examine that state by going back to servers from home screen.

Next, go to process definitions (in Manage section of the Home screen) and select server configuration (top right corner) - again it should be business-application-service-dev the list of available process definition will be loaded and you should see your single process definitions from the project business-application-kjar.

First start process instance that will wait for a signal (catchsignalprocess), then start process instance that will throw (send) signal via JMS (throwsignalprocess). When starting second process specify the input you want to send together with signal.

Go to Task inbox from home screen to see that task is created with input provided on the second process instance.

3.7.6.5. Summary

Congratulations! you have integrated your business application with JMS. Moreover, you made business processes to talk to each other (over signals). This allows you to build more advanced interactions based on your business logic.

3.7.6.6. Source code of the tutorial

Here is the complete source code of the tutorial.

3.7.7. Business Application with Dynamic Assets

3.7.7.1. What will you do

You will enhance your business application with some dynamic assets that allow more adaptive approach to business logic compared with structured business processes.

Next execute these dynamic assets

  • via REST api of your business application

  • via jBPM Case Management showcase

3.7.7.2. What do you need
  • About 15 minutes of your time

  • Java (JDK) 8 or later

  • Maven 3.5.x

  • Access to the Internet

  • Business Central deployed - see single distribution for instructions

3.7.7.3. What should I do

To get started with business applications the easiest way is to generate it. Go to start.jbpm.org and click button Configure your business application.

Business process - sample
  • First step: Select Business Automation (selected by default)

  • Second step: Provide details for your business application

  • Third step: Select Dynamic Assets, Data Model and Service projects

  • Click Generate business application button

Start Business Central (if not already started) and open your browser at http://localhost:8080/business-central and logon as user wbadmin with password wbadmin

Import your business assets project into Business Central
  • Go into business assets project - business-application-kjar

  • Execute git init

  • Execute git add -A

  • Execute git commit -m "my business assets project"

  • Log in to Business Central and go to projects

  • Select import project and enter the following URL file:///{path to your business application}/business-application-kjar

  • Click import and confirm project to be imported

Create Dynamic Asset - Case definition

In browser where you logged into Business Central go to Projects. You will see your newly imported project named business-application-kjar.

  • go into business-application-kjar project

  • click Add asset button

  • select Case definition asset

  • provide name for this asset e.g. myfirstcase

  • optionally you can provide prefix for case ids - if not given it will default to CASE-XXX where XXX is generated number

  • create your case definition

Case definition is designed in the so-called legacy process designer.

You can now create your dynamic case definition that does not have to have connected process activities.

Sample case definition could be a two user tasks that will be assigned to user wbadmin and not connected to anything else.

Case definition - sample

This sample case definition consists of two user tasks

  • Dynamic User Task

  • Another task that is started automatically

Both of them are assigned to wbadmin user although only one (second) will be created automatically when case instance is created. This is because it is marked as autostart and thus will be directly created.

The first one can be dynamically created on ad hoc basis.

Pull back your business assets to business application source code
  • Go to business-application-kjar

  • Execute git remote add origin ssh://wbadmin@localhost:8001/MySpace/business-application-kjar

  • Execute git pull origin master - when prompted enter wbadmin as password

Go to business-application-service directory and launch the application

./launch.sh clean install for Linux/Unix

./launch.bat clean install for Windows

3.7.7.4. Results

Once the build and launch is complete you can open your browser http://localhost:8090

Next, point the browser to http://localhost:8090/rest/server/containers to see that your business assets project has been properly deployed and is running.

By default all REST endpoints (url pattern /rest/*) are secured and require authentication. Default user that can be used to logon is wbadmin with password wbadmin

Next, point the browser to http://localhost:8090/rest/server/containers/business-application-kjar/cases/definitions to see dynamic assets (cases) available for execution.

Execute business process

You can execute business process via REST api exposed by your business application (in fact by Business Automation capability).

HTTP headers can be set to change the format of data returned

  • Accept: application/json for JSON format

  • Accept: application/xml for XML (JAXB based) format

  • X-KIE-ContentType: XSTREAM for XML (XStream based) format

{casedefid} needs to be replaced with actual case definition id that is returned from the endpoint http://localhost:8090/rest/server/containers/business-application-kjar/cases/definitions

Remember that endpoints are protected so make sure you provide user name and password when making the request.

In response to this request, a case instance id should be returned.

<string-type>
    <value>CASE-0000000001</value>
</string-type>

You can examine details of that case instance by pointing your browser to http://localhost:8090/rest/server/containers/business-application-kjar/cases/instances/CASE-0000000001

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<case-instance>
    <case-id>CASE-0000000001</case-id>
    <case-description>myfirstcase</case-description>
    <case-owner>wbadmin</case-owner>
    <case-status>1</case-status>
    <case-definition-id>myfirstcase</case-definition-id>
    <container-id>business-application-kjar-1_0-SNAPSHOT</container-id>
    <case-started-at>2018-10-30T09:54:45.747+01:00</case-started-at>
    <case-completion-msg></case-completion-msg>
    <case-sla-compliance>0</case-sla-compliance>
</case-instance>

Load tasks for given case instance that are assigned to wbadmin user

you should see second task from case definition

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<task-summary-list>
    <task-summary>
        <task-id>1</task-id>
        <task-name>Another task that is started automatically</task-name>
        <task-subject></task-subject>
        <task-description></task-description>
        <task-status>Reserved</task-status>
        <task-priority>0</task-priority>
        <task-is-skipable>true</task-is-skipable>
        <task-actual-owner>wbadmin</task-actual-owner>
        <task-created-by>wbadmin</task-created-by>
        <task-created-on>2018-10-30T09:54:45.790+01:00</task-created-on>
        <task-activation-time>2018-10-30T09:54:45.790+01:00</task-activation-time>
        <task-proc-inst-id>1</task-proc-inst-id>
        <task-proc-def-id>myfirstcase</task-proc-def-id>
        <task-container-id>business-application-kjar-1_0-SNAPSHOT</task-container-id>
        <task-parent-id>-1</task-parent-id>
    </task-summary>
</task-summary-list>

You can trigger dynamically the other user task by issuing request to

Optionally you can send data as payload of the request.

Load tasks again for given case instance that are assigned to wbadmin user

you should see both tasks from case definition

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<task-summary-list>
    <task-summary>
        <task-id>1</task-id>
        <task-name>Another task that is started automatically</task-name>
        <task-subject></task-subject>
        <task-description></task-description>
        <task-status>Reserved</task-status>
        <task-priority>0</task-priority>
        <task-is-skipable>true</task-is-skipable>
        <task-actual-owner>wbadmin</task-actual-owner>
        <task-created-by>wbadmin</task-created-by>
        <task-created-on>2018-10-30T09:54:45.790+01:00</task-created-on>
        <task-activation-time>2018-10-30T09:54:45.790+01:00</task-activation-time>
        <task-proc-inst-id>1</task-proc-inst-id>
        <task-proc-def-id>myfirstcase</task-proc-def-id>
        <task-container-id>business-application-kjar-1_0-SNAPSHOT</task-container-id>
        <task-parent-id>-1</task-parent-id>
    </task-summary>
    <task-summary>
        <task-id>3</task-id>
        <task-name>Dynamic User Task</task-name>
        <task-subject></task-subject>
        <task-description></task-description>
        <task-status>Reserved</task-status>
        <task-priority>0</task-priority>
        <task-is-skipable>true</task-is-skipable>
        <task-actual-owner>wbadmin</task-actual-owner>
        <task-created-by>wbadmin</task-created-by>
        <task-created-on>2018-10-30T10:08:01.257+01:00</task-created-on>
        <task-activation-time>2018-10-30T10:08:01.257+01:00</task-activation-time>
        <task-proc-inst-id>1</task-proc-inst-id>
        <task-proc-def-id>myfirstcase</task-proc-def-id>
        <task-container-id>business-application-kjar-1_0-SNAPSHOT</task-container-id>
        <task-parent-id>-1</task-parent-id>
    </task-summary>
</task-summary-list>
Execute business process from jBPM Case Management Showcase

There is a need to repoint the jBPM Case Management Showcase application to use business application instead of the KIE Server bundled with single zip distribution of jBPM. To do so, edit standalone.xml file of jbpm server (JBPM_SERVER/standalone/configuration) and change the value of org.kie.server.location system property

<property name="org.kie.server.location" value="http://localhost:8090/rest/server"/>

Once done, restart jBPM server.

Stop the application if it’s running.

Go to business-application-service directory and launch the application in development mode

./launch-dev.sh clean install for Linux/Unix

./launch-dev.bat clean install for Windows

this will connect your business application to Business Central so can be administered from within its UI.

Go to Business Central in the browser and navigate to servers (from the home screen).

tutorial 7 empty server

As you can see the business-application-service Dev is there and connected. Although it does not have any kjars deployed. This is because it’s now running in managed mode meaning it’s Business Central that decides what kjars it should run.

So let’s deploy the business-application-kjar to our running application.

  • Go to projects from home screen of Business Central

  • Go into business-application-kjar project

  • Click Deploy button

  • Make sure that Server configuration is set to business-application-service-dev and click ok

The project should be successfully deployed and you can examine that state by going back to servers from home screen.

Next, go to process definitions (in Manage section of the Home screen) and select server configuration (top right corner) - again it should be business-application-service-dev the list of available process definition will be loaded and you should see your single case definition from the project business-application-kjar.

tutorial 7 process defs

Examine details of that case definition by clicking on the row in the table. Switch to Diagram tab to see the visual representation of your case definition.

Business Central does not allow to start case instances and thus you need to switch to Case Management showcase application. It is accessible from the Apps launcher icon (top right corner) next to logout button.

Launch the application and login with wbadmin. Once logged in you can start a new case instance.

tutorial 7 case app

Go into newly started case instance by clicking on the row of the active cases list.

tutorial 7 case instance

From there you can start a new instance of Dynamic User Task as the other one is already there.

3.7.7.5. Summary

Congratulations! you have enhanced your business application to take advantage of dynamic and adaptive business assets that allow to do much more than structured processes. You could see how easy it is to add additional user tasks and that’s just the beginning.

3.7.7.6. Source code of the tutorial

Here is the complete source code of the tutorial.

4. jBPM Installer

4.1. Prerequisites

This script assumes you have Java JDK 1.8+ (set as JAVA_HOME), and Ant 1.9+ installed. If you don’t, use the following links to download and install them:

To check whether Java and Ant are installed correctly, type the following commands inside a command prompt:

java -version

ant -version

This should return information about which version of Java and Ant you are currently using.

4.2. Downloading the Installer

First of all, you need to download the installer and unzip it on your local file system. There are two versions

  • full installer - already contains a lot of the dependencies that are necessary during the installation

  • minimal installer - contains only the installer and will download all required dependencies on the fly

In general, it is probably best to download the full installer: jBPM-7.46.0.Final-installer-full.zip

You can also download the latest build (only for the minimal installer).

4.3. Demo Setup

The easiest way to get started is to simply run the installation script to install the demo setup. The demo install will setup all the web tooling (on top of WildFly) and Eclipse tooling in a pre-configured setup. Go into the jbpm-installer folder where you unzipped the installer and (from a command prompt) run:

ant install.demo

This will:

  • Download WildFly application server

  • Configure and deploy a process execution server

  • Configure and deploy Business Central

  • Configure and deploy the case management application

  • Download Eclipse

  • Install the Drools and jBPM Eclipse plugin

  • Install the Eclipse BPMN 2.0 Modeler

Running this command could take a while (REALLY, not kidding, we are for example downloading an Eclipse installation, even if you downloaded the full installer, specifically for your operating system).

The script always shows which file it is downloading (you could for example check whether it is still downloading by checking whether the size of the file in question in the jbpm-installer/lib folder is still increasing). If you want to avoid downloading specific components (because you will not be using them or you already have them installed somewhere else), check below for running only specific parts of the demo or directing the installer to an already installed component.

Once the demo setup has finished, you can start playing with the various components by starting the demo setup:

ant start.demo

This will:

  • Start H2 database server

  • Start WildFly application server

  • Start Eclipse

Now wait until the process management console comes up:

The case management UI will be available on:

It could take a minute to start up the application server and web application. If the web page doesn’t show up after a while, make sure you don’t have a firewall blocking that port, or another application already using the port 8080. You can always take a look at the server log {jbpm-installer-folder}/wildfly-{version}/standalone/log/server.log

Once everything is started, you can start playing with the Eclipse and web tooling, as explained in the following sections.

If you only want to try out the web tooling and do not wish to download and install the Eclipse tooling, you can use these alternative commands:

ant install.demo.noeclipse
ant start.demo.noeclipse

Similarly, if you only want to try out the Eclipse tooling and do not wish to download and install the web tooling, you can use these alternative commands:

ant install.demo.eclipse
ant start.demo.eclipse

Now continue with the 10-minute tutorials. Once you’re done playing and you want to shut down the demo setup, you can use:

ant stop.demo

If at any point in time would like to start over with a clean demo setup - meaning all changes you did inside the web tooling and/or saved in the database will be lost, you can run the following command (after which you can run the installer again from scratch, note that this cannot be undone):

ant clean.demo

4.4. 10-Minute Tutorial using Business Central

Open up the process management console:

It could take a minute to start up the application server and web application. If the web page doesn’t show up after a while, make sure you don’t have a firewall blocking that port, or another application already using the port 8080. You can always take a look at the server log {jbpm-installer-folder}/wildfly-{version}/standalone/log/server.log

Log in, using krisv / krisv as user name / password.

Using a prebuilt Evaluation example, the following screencast gives an overview of how to manage your process instances. It shows you:

  • How to log in to Business Central

  • How to import an existing example project and build and deploy it

  • How to start a new process instance

  • How to look up the current status of a running process instance

  • How to look up your tasks

  • How to complete a task

  • How to look at reports to monitor your process execution

    ScreencastConsole

Business Central supports the entire life cycle of your business processes: authoring, deployment, process management, tasks and dashboards.

  • The project authoring page allows you to look at existing repositories, where each project can contain business processes (but also business rules, data models, forms, etc.). It allows you to create your own project, or you could import an existing example to take a look at.

    • In this screencast, we start by importing the Evaluation project

  • The project explorer shows all available artifacts:

    • evaluation: business process describing the evaluation process as a sequence of tasks

    • evaluation-taskform: process form to start the evaluation process

    • PerformanceEvaluation-taskform: task form to perform the evaluation tasks

  • To make a process available for execution, you need to successfully build and deploy it first. To do so, open the selected project (in the project authoring page) and click Build & Deploy (top right corner).

  • To manage your process definitions and instances, click the "Process Management" menu option at the top menu bar and select one of the available options depending on you interest:

    • Process Definitions - lists all available process definitions

    • Process Instances - lists all active process instances (allows to show completed, aborted as well by changing filter criteria)

  • The process definitions view allows you to start a new process instance by clicking on the Start button. The process form (as defined in the project) will be shown, where you need to fill in the necessary information to start the process. In this case, you need to fill the user you want to start an evaluation for (for example use "krisv") and a reason for the request, after which you can complete the form. Some details about the process instance that was just started will be shown in the process instance details panel. From there you can access additional details:

    • Process model - to visualize the current state of the process

    • Process variables - to see current values of process variables

    • Documents - documents related to the process instance

    • Logs - overview of all process events for that instance

    The process instance that you just started is first requiring a self-evaluation of the user and is waiting until the user has completed this task.

  • To see the tasks that have been assigned to you, choose the "Tasks" menu option on the top bar. By default, it will show all active tasks, and a "Performance Evaluation" (that was created by the process instance you just started) should be available for you. When you click a task, the task details will be shown, including the task form related to this task. After starting the task, you can fill in the necessary information and complete the task. After completing the task, you could check the "Process Instances" once more to check the progress of your process instance. You should be able to see that the process is now waiting for your HR manager and project manager to also perform an evaluation. You could log in as "john" / "john" and "mary" / "mary" to complete these tasks.

  • After starting and/or completing a few process instances and human tasks, you can generate a report of what has happened so far. Under "Dashboards", select "Process & Task Dashboard". This is a set of predefined charts that allow users to spot what is going on in the system. Charts can be fully customized as well, as explained in the Business Activity Monitoring chapter.

4.5. 10-Minute Tutorial using Eclipse

The following screencast gives an overview of how to use the Eclipse tooling. It shows you:

  • How to import and execute the evaluation sample project

    • Import the evaluation project (included in the jbpm-installer)

    • Open the Evaluation.bpmn process

    • Open the com.sample.ProcessTest Java class

    • Execute the ProcessTest class to run the process

  • How to create a new jBPM project (including sample process and JUnit test)

    ScreencastEclipse

You can import the evaluation project - a sample included in the jbpm-installer - by selecting "File → Import …​", select "Existing Projects into Workspace" and browse to the jbpm-installer/sample/evaluation folder and click "Finish". You can open up the evaluation process and the ProcessTest class. To execute the class, right-click it and select "Run as …​ - Java Application". The console should show how the process was started and how the different actors in the process completed the tasks assigned to them, to complete the process instance.

You could also create a new project using the jBPM project wizard. The sample projects contain a process and an associated Java file to start the process. Select "File - New …​ - Project …​" and under the "jBPM" category and select "jBPM project". Select to create a project with some example files to get you started quickly and click next. Give the project a name. You can choose from a simple HelloWorld example or a slightly more advanced example using persistence and human tasks. If you select the latter and click Finish, you should see a new project containing a "sample.bpmn" process and a "com.sample.ProcessTest" JUnit test class. You can open the BPMN2 process by double-clicking it. To execute the process, right-click ProcessTest.java and select "Run As - Java Application".

4.6. Configuration

4.6.1. Business Central Authentication

The Business Central web application is using the pre-installed other security domain for authenticating and authorizing users (as specified in the WEB-INF/jboss-web.xml inside the WARs).

The application server uses by default property files based realms - Please note that this configuration is intended only for demo purposes (users, roles and passwords are stored in simple property files on the filesystem).

Authentication is configured in the standalone.xml file as follows:

<security-domain name="other" cache-type="default">
    <authentication>
        <login-module code="Remoting" flag="optional">
            <module-option name="password-stacking" value="useFirstPass"/>
        </login-module>
        <login-module code="RealmDirect" flag="required">
            <module-option name="password-stacking" value="useFirstPass"/>
        </login-module>
        <login-module code="org.kie.security.jaas.KieLoginModule" flag="optional" module="deployment.jbpm-console.war"/>
    </authentication>
</security-domain>
<security-realm name="ApplicationRealm">
    <authentication>
        <local default-user="$local" allowed-users="*" skip-group-loading="true"/>
        <properties path="users.properties" relative-to="jboss.server.config.dir"/>
    </authentication>
    <authorization>
        <properties path="roles.properties" relative-to="jboss.server.config.dir"/>
    </authorization>
</security-realm>

These are the default users:

Table 1. Default users
Name Password Business Central roles Task roles

admin

admin

admin,analyst,kiemgmt,rest-all,kie-server

krisv

krisv

admin,analyst,rest-all,kie-server

john

john

analyst,kie-server

Accounting,PM

mary

mary

analyst,kie-server

HR

sales-rep

sales-rep

analyst,kie-server

sales

jack

jack

analyst,kie-server

IT

katy

katy

analyst,kie-server

HR

salaboy

salaboy

admin,analyst,rest-all,kie-server

IT,HR,Accounting

kieserver

kieserver1!

kie-server

Authentication can be customized by using any of the following options:

  • The users and groups management screens on the Business Central web application.

Navigate into the Business Central web application and click the menu HomeAdmin and selecting Users.

  • The add-user script that comes by default on Wildfly/EAP.

Example for Linux platforms - run the following command and follow the script instructions:

/bin/sh $JBOSS_HOME/bin/add-user.sh
  --user-properties $JBOSS_HOME/standalone/configuration/users.properties
  --group-properties $JBOSS_HOME/standalone/configuration/roles.properties
  --realm ApplicationRealm

4.6.2. Using your own database with the jBPM installer

4.6.2.1. Introduction

jBPM uses the Java Persistence API specification (v2) to allow users to configure whatever datasource they want to use to persist runtime data. As a result, the instructions below describe how you should configure a datasource when using JPA on JBoss application server (e.g. EAP7 or Wildfly10) using a persistence.xml file and configuring your datasource and driver in your application server’s standalone.xml , similar to how you would configure any other application using JPA on the application server. The installer automates some of this (like copying the right files to the right location after installation).

By default, the jbpm-installer uses an H2 database for persisting runtime data. In this section we will:

  1. modify the persistence settings for runtime persistence of process instance state

  2. test the startup with our new settings!

You will need a local instance of a database, in this case we will use MySQL.

4.6.2.2. Database setup

In the MySQL database used in this quickstart, create a single user:

  • user/schema "jbpm" with password "jbpm" (which will be used to persist all entities)

If you end up using different names for your user/schemas, please make a note of where we insert "jbpm" in the configuration files.

If you want to try this quickstart with another database, a section at the end of this quickstart describes what you may need to modify.

4.6.2.3. Configuration

The following files define the persistence settings for the jbpm-installer demo:

  • jbpm-installer/db/jbpm-persistence-JPA2.xml

  • Application server configuration

    • standalone-*.xml

There are multiple standalone.xml files available (depending on whether you are using JBoss EAP or Wildfly and whether you are running the normal or full profile). The full profile is required to use the JMS component for remote integration, so will be used by default by the installer. Best practice is to update all standalone.xml files to have consistent setup but most important is to have standalone-full-wildfly-{version}.xml properly configured as this is used by default by the installer.

Do the following:

  • Disable H2 default database and enable MySQL database in build.properties

    # default is H2
    # H2.version=1.3.168
    # db.name=h2
    # db.driver.jar.name=${db.name}.jar
    # db.driver.download.url=http://repo1.maven.org/maven2/com/h2database/h2/${H2.version}/h2-${H2.version}.jar
    #mysql
    db.name=mysql
    db.driver.module.prefix=com/mysql
    db.driver.jar.name=mysql-connector-java-5.1.18.jar
    db.driver.download.url=https://repository.jboss.org/nexus/service/local/repositories/central/content/mysql/mysql-connector-java/5.1.18/mysql-connector-java-5.1.18.jar
    org.kie.server.persistence.dialect=org.hibernate.dialect.MySQLDialect

    You might want to update the db driver jar name and download url to whatever version of the jar matches your installation. Look to also update the dialect to what matches your installation if needed (for example change to MySQL5Dialect for MySQL 5.x specific features).

  • db/jbpm-persistence-JPA2.xml :

    This is the JPA persistence file that defines the persistence settings used by jBPM for the jBPM engine information, the logging/BAM information, and task service.

    In this file, you will have to change the name of the hibernate dialect used for your database.

    The original line is:

    <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>

    In the case of a MySQL database, you need to change it to:

    <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>

    For those of you who decided to use another database, a list of the available hibernate dialect classes can be found here.

  • standalone-full-wildfly-{version}.xml :

    Standalone.xml and standalone-full.xml are the configuration for the standalone JBoss application server. When the installer installs the demo, it copies these files to the standalone/configuration directory in the JBoss server directory. Since the installer uses Wildfly by default as application server, you probably need to change standalone-full-wildfly-{version}.xml .

    We need to change the datasource configuration in standalone-full.xml so that the jBPM engine can use our MySQL database. The original file contains (something very similar to) the following lines:

    <datasource jta="true" jndi-name="java:jboss/datasources/jbpmDS" pool-name="H2DS" enabled="true" use-java-context="true" use-ccm="true">
        <connection-url>jdbc:h2:tcp://localhost/~/jbpm-db;MVCC=TRUE</connection-url>
        <driver>h2</driver>
        <security>
           <user-name>sa</user-name>
        </security>
    </datasource>
    <drivers>
        <driver name="h2" module="com.h2database.h2">
            <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
        </driver>
    </drivers>

    Change the lines to the following:

    <datasource jta="true" jndi-name="java:jboss/datasources/jbpmDS" pool-name="MySQLDS" enabled="true" use-java-context="true" use-ccm="true">
        <connection-url>jdbc:mysql://localhost:3306/jbpm</connection-url>
        <driver>mysql</driver>
        <security>
           <user-name>jbpm</user-name>
           <password>jbpm</password>
        </security>
    </datasource>

    and add an additional driver configuration:

    <driver name="mysql" module="com.mysql">
        <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
    </driver>
  • To install driver jars in JBoss application server (Wildfly, EAP, etc.), it is recommended to install the driver jar as a module. The installer already takes care of this mostly: it will copy the driver jar (you specified in the build.properties ) to the right folder inside the modules directory of your server and put a matching module.xml next to it. For MySQL, this file is called db/mysql_module.xml . Open this file and make sure that the file name of the driver jar listed there is identical the driver jar name you specified in the build.properties (including the version). Note that, even if you simply uncommented the default MySQL configuration, you will still need to add the right version here.

  • Starting the demo

    We’ve modified all the necessary files at this point. Now would be a good time to make sure your database is started up as well!

    The installer script copies this file into the jbpm-console WAR before the WAR is installed on the server. If you have already run the installer, it is recommended to stop the installer and clean it first using

    ant stop.demo

    and

    ant clean.demo

    before continuing.

    Run

    ant install.demo

    to (re)install the wars and copy the necessary configuration files. Once you’ve done that, (re)start the demo using

    ant start.demo
  • Problems?

    If this isn’t working for you, please try the following:

    • Please double check the files you’ve modified: I wrote this, but still made mistakes when changing files!

    • Please make sure that you don’t secretly have another (unmodified) instance of JBoss AS running.

    • If neither of those work (and you’re using MySQL), then please do let us know.

4.6.2.4. Using a different database

If you decide to use a different database with this demo, you need to remember the following when going through the steps above:

  • Configuring the jBPM datasource in standalone.xml:

    • After locating the java:jboss/datasources/jbpmDS datasource, you need to provide the following properties specific to your database:

      • Change the url of your database

      • Change the user-name and password

      • Change the name of the driver (which you’ll create next)

        For example:

        <datasource jta="true" jndi-name="java:jboss/datasources/jbpmDS" pool-name="PostgreSQLDS" enabled="true" use-java-context="true" use-ccm="true">
            <connection-url>jdbc:postgresql://localhost:5432/jbpm</connection-url>
            <driver>postgresql</driver>
            <security>
                <user-name>jbpm</user-name>
                <password>jbpm</password>
            </security>
        </datasource>
    • Add an additional driver configuration:

      • Change the name of the driver to match the name you specified when configuring the datasource in the previous step

      • Change the module of the driver: the database driver jar should be installed as a module (see below) and here you should reference the unique name of the module. Since the installer can take care of automatically generating this module for you (see below), this should match the db.driver.module.prefix property in build.properties (where forward slashes are replaced by a point). In the example below, I used org/postgresql as db.driver.module.prefix which means that I should then use org.postgresql as module name for the driver.

      • Fill in the correct name of the XA datasource class to use.

    For example:

    +

    <driver name="postgresql" module="org.postgresql">
        <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
    </driver>
  • You need to change the dialect in persistence.xml to the dialect for your database, for example:

    <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
  • In order to make sure your driver will be correctly installed in the JBoss application server, there are typically multiple options, like install as a module or as a deployment. It is recommended to install the driver as a module for EAP and Wildfly.

    • Install the driver JAR as a module, which is what the install script does.

    • Otherwise, you can modify and install the downloaded JAR as a deployment. In this case you will have to copy the JAR yourself to the standalone/deployments directory.

    If you choose to install driver as JBoss module (recommended), please do the following:

    • In build.properties, disable the default H2 driver properties

      # default is H2
      # H2.version=1.3.168
      # db.name=h2
      # db.driver.jar.name=h2-${H2.version}.jar
      # db.driver.download.url=http://repo1.maven.org/maven2/com/h2database/h2/${H2.version}/h2-${H2.version}.jar
    • Uncomment one of the other example configs (mysql or postgresql) or create your own:

      #postgresql
      db.name=postgresql
      db.driver.module.prefix=org/postgresql
      db.driver.jar.name=postgresql-9.1-902.jdbc4.jar
      db.driver.download.url=https://repository.jboss.org/nexus/content/repositories/thirdparty-uploads/postgresql/postgresql/9.1-902.jdbc4/postgresql-9.1-902.jdbc4.jar
      • Change the db.name property in build.properties to a name for your database.

      • Change the db.driver.module.prefix property to a name for the module of your driver. Note that this should match the module property when configuring the driver in standalone.xml (where forward slashes in the prefix here are replaced by a point). In the example above, I used org/postgresql as db.driver.module.prefix which means that I should then use org.postgresql as module name for the driver.

      • Change the db.driver.jar.name property to the name of the jar that contains your database driver.

      • Change the db.driver.download.url property to where the driver jar can be downloaded. Alternatively, you could manually download the jar yourself, and place it in the db/drivers folder, using the same name as you specified in the db.driver.jar.name property.

    • Lastly, you’ll have to create the db/${db.name}_module.xml file. As an example you can use db/mysql_module.xml, so just make a copy of it and:

      • Change the name of the module to match the driver module name above

      • Change the name of the module resource path to the name of the db.driver.jar.name property.

    • For example, the top of the file would look like:

<module xmlns="urn:jboss:module:1.0" name="org.postgresql">
   <resources>
     <resource-root path="postgresql-9.1-902.jdbc4.jar"/>
   </resources>

4.6.3. jBPM database schema scripts (DDL scripts)

By default the demo setup makes use of Hibernate auto DDL generation capabilities to build up the complete database schema, including all tables, sequences, etc. This might not always be welcomed (by your database administrator), and thus the installer provides DDL scripts for most popular databases.

Table 2. DDL scripts
Database name Location

db2

jbpm-installer/db/ddl-scripts/db2

derby

jbpm-installer/db/ddl-scripts/derby

h2

jbpm-installer/db/ddl-scripts/h2

hsqldb

jbpm-installer/db/ddl-scripts/hsqldb

mysql5

jbpm-installer/db/ddl-scripts/mysql5

mysqlinnodb

jbpm-installer/db/ddl-scripts/mysqlinnodb

oracle

jbpm-installer/db/ddl-scripts/oracle

postgresql

jbpm-installer/db/ddl-scripts/postgresql

sqlserver

jbpm-installer/db/ddl-scripts/sqlserver

sqlserver2008

jbpm-installer/db/ddl-scripts/sqlserver2008

sybase

jbpm-installer/db/ddl-scripts/sybase

DDL scripts are provided for both jBPM and Quartz schemas although Quartz schema DDL script is only required when the timer service should be configured with Quartz database job store. See the section on timers for additional details.

This can be used to initially create the database schema, but it can also serve as the basis for any\ optimization that needs to be applied - such as indexes, etc.

If you use MySQL 5.7 or earlier (MariaDB 10.2.3 or earlier), you also need to run jbpm-installer/db/ddl-scripts/mysql5/mysql-jbpm-amend-auto-increment-procedure.sql

This script creates a procedure for jBPM tables (ProcessInstanceInfo/WorkItemInfo/Task) to protect AUTO_INCREMENT counter. Without the procedure, ID values of those tables could be reset on MySQL/MariaDB restart (https://dev.mysql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html#innodb-auto-increment-initialization). It would introduce further side effects.

In addition to creating the procedure, you have to call the procedure on MySQL/MariaDB restart. For example,

/etc/my.cnf

init-file=/path/to/mysql-jbpm-amend-auto-increment-call.sql

Write mysql-jbpm-amend-auto-increment-call.sql

call mydatabase.JbpmAmendAutoIncrement;

If you use PostgreSQL with jBPM, you also need to run jbpm-installer/db/ddl-scripts/postgresql/postgresql-jbpm-lo-trigger-clob.sql

This script creates triggers for jBPM tables to protect CLOB references of large objects. Without the triggers, vacuumlo tool (https://www.postgresql.org/docs/9.4/static/vacuumlo.html) deletes active large objects so causes an issue to jBPM. If you are already running jBPM without the triggers, you also need to run the following SQLs after applying the triggers to protect existing CLOB.

insert into jbpm_active_clob ( loid ) select cast(expression as oid) from booleanexpression where expression is not null;
insert into jbpm_active_clob ( loid ) select cast(body as oid) from email_header where body is not null;
insert into jbpm_active_clob ( loid ) select cast(text as oid) from i18ntext where text is not null;
insert into jbpm_active_clob ( loid ) select cast(text as oid) from task_comment where text is not null;
insert into jbpm_active_clob ( loid ) select cast(qexpression as oid) from querydefinitionstore where qexpression is not null;
insert into jbpm_active_clob ( loid ) select cast(deploymentunit as oid) from deploymentstore where deploymentunit is not null;

4.6.4. jBPM installer script

jBPM installer ant script performs most of the work automatically and usually does not require additional attention but in case it does, here is a list of available targets that might be needed to perform some of the steps manually.

Table 3. jBPM installer available targets
Target Description

clean.db

cleans up database used by jBPM demo (applies only to H2 database)

clean.demo

cleans up entire installation so new installation can be performed

clean.demo.noeclipse

same as clean.demo but does not remove Eclipse

clean.eclipse

removes Eclipse and its workspace

clean.generated.ddl

removes DDL scripts generated if any

clean.jboss

removes application server with all its deployments

clean.jboss.repository

removes repository content for demo setup (guvnor Maven repo, niogit, etc)

download.db.driver

downloads DB driver configured in build.properties

download.ddl.dependencies

downloads all dependencies required to run DDL script generation tool

download.droolsjbpm.eclipse

downloads Drools and jBPM Eclipse plugin

download.eclipse

downloads Eclipse distribution

download.eclipse.gef

downloads Eclipse GEF feature

download.jboss

downloads JBoss Application Server

download.jBPM.bin

downloads jBPM binary distribution (jBPM libs and its dependencies)

download.jBPM.casemgmt

downloads jBPM case management console

download.jBPM.console

downloads jBPM process management console

download.kie.server

downloads jBPM process execution server

install.db.files

installs DB driver as JBoss module

install.demo

installs complete demo environment

install.demo.eclipse

installs Eclipse with all jBPM plugins, no server installation

install.demo.noeclipse

similar to install.demo but skips Eclipse installation

install.droolsjbpm-eclipse.into.eclipse

installs droolsjbpm Eclipse plugin into Eclipse

install.eclipse

install Eclipse IDE

install.jboss

installs JBoss AS

install.jBPM-casemgmt.into.jboss

installs jBPM case management application

install.jBPM-console.into.jboss

installs jBPM process management console

install.kie-server.into.jboss

installs jBPM process execution server

4.7. Frequently Asked Questions

Some common issues are explained below.

  1. What if the installer complains it cannot download component X?

    Are you connected to the Internet? Do you have a firewall turned on? Do you require a proxy? It might be possible that one of the locations we’re downloading the components from is temporarily offline. Try downloading the components manually (possibly from alternate locations) and put them in the jbpm-installer/lib folder.

  2. What if the installer complains it cannot extract / unzip a certain JAR/WAR/zip?

    If your download failed while downloading a component, it is possible that the installer is trying to use an incomplete file. Try deleting the component in question from the jbpm-installer/lib folder and reinstall, so it will be downloaded again.

  3. What if I have been changing my installation (and it no longer works) and I want to start over again with a clean installation?

    You can use ant clean.demo to remove all the installed components, so you end up with a fresh installation again.

  4. I sometimes see exceptions when trying to stop or restart certain services, what should I do?

    If you see errors during shutdown, are you sure the services were still running? If you see exceptions during restart, are you sure the service you started earlier was successfully shutdown? Maybe try killing the services manually if necessary.

  5. Something seems to be going wrong when running Eclipse but I have no idea what. What can I do?

    Always check the consoles for output like error messages or stack traces. You can also check the Eclipse Error Log for exceptions. Try adding an audit logger to your session to figure out what’s happening at runtime, or try debugging your application.

  6. Something seems to be going wrong when running the web-based application like the jbpm-console. What can I do?

    You can check the server log for possible exceptions: jbpm-installer/jboss-as-{version}/standalone/log/server.log (for JBoss AS7).

For all other questions, try contacting the jBPM community as described in the Getting Started chapter.

5. Examples

5.1. Introduction

Business Central provides various sample projects that will help you in getting started with automating business processes. These are bundled together with the application and you can easily try them out by navigating to Design  Projects and clicking on Try Samples.

This section shows the different examples that can be found in the jbpm-playground repository. All these examples are high level and business oriented.

If you want to contribute with these examples please get in touch with any member of the jBPM/Drools Team.

5.2. Importing Projects through Git

To import the Human Resources example, as well as other examples, follow these steps:

  1. Logging in to Business Central

    1. On the command line, change into the $SERVER_HOME/bin/ directory and execute the following command:

      • for Unix environment:

        ./standalone.sh
      • for Windows environment:

        ./standalone.bat
    2. Once your server is up and running, open the following address in a web browser:

      http://localhost:8080/business-central

      This opens the login page.

    3. Log in to Business Central with the user credentials created during installation.

  2. Importing Projects Through Git

    1. Click Design  Projects.

    2. Click Import Project.

      1. If your current space contains at least one project, the Import Project option is available under the dropdown menu in the space menu bar.

    3. In the Import Project dialogue, enter the following information:

      • Repository URL : enter the Git URL you want to import, for example: https://github.com/kiegroup/jbpm-playground.

      • Authentication Options: If the target git repository requires authentication, you can specify the user name and password using the expanded dialog option.

    4. Click Import.

project import

This will import a number of examples into your instance of jBPM.

5.3. Human Resources Example

The Human Resource Example’s use case can be described as follows: A company wants to hire new developers. In this process, three departments (that is the Human resources, IT, and Accounting) are involved. These departments are represented by three users: Katy, Jack, and John respectively.

human resources high level
Business process designed for the Human Resource Example's use caseBusiness Process

Note that only four out of the six defined activities within the business process are User Tasks. User Tasks require human interaction. The other two tasks are Service Tasks, which are automated and connected to other systems.

Each instance of the process will follow certain actions:

  • The human resources team performs the initial interview with the candidate.

  • The IT department team performs the technical interview.

  • Based on the output from the previous two steps, the accounting team creates a job proposal.

  • When the proposal has been drafted, it is automatically sent to the candidate via email.

  • If the candidate accepts the proposal, a new meeting to sign the contract is scheduled.

  • Finally, if the candidate accepts the proposal, the system posts a message about the new hire using Twitter service connector.

Note, that Jack, John, and Katy represent any employee within the company with appropriate role assigned.

5.3.1. The Kie Project: human-resources

To start exploring the project:

  1. Click Design  Projects.

  2. Click Human Resources Kjar Example  hiring.

The asset list page contains the hiring.bpmn2 process and a set of forms for each human task. Click these assets to explore. Notice that different editors open for different types of assets.

human resources hiring bpmn

5.3.2. Building the Human Resources Example

To build the Project:

  1. Click Design  Projects.

  2. Click Human Resources Kjar Example.

  3. Click Deploy.

Deploy creates a new JAR artifact that is deployed to the runtime environment as a new deployment unit.

human resources build and deploy

After successfully building and deploying your project, you can verify its presence in the Execution Servers tab. Click Deploy  Execution Servers to do so.

human resources deployment screen
Figure 7. Deployment Units

When you Deploy a project from the Project Editor, it is deployed using the default configuration which means using the Singleton strategy, the default Kie Base and the default Kie session.

If you want to change these settings, you can make the necessary adjustments on the Settings tab for the specific project. Then, you will be able to set a different strategy, or use a non-default Kie Base or Kie Session. Once you saved your settings you can redeploy the project as a new Deployment Unit.

human resources settings screen
Figure 8. Project Settings

Once your artifact that contains the process definition is deployed, the Process Definition will become available in Manage  Process Definitions.

5.3.3. Create a new Process Instance

To create new process instances:

Click Manage  Process Definitions.

Start your instance:

human resources process definitions
Figure 9. Starting Process Instances

The Process Definitions section contains all the available process definitions in the runtime environment. In order to add new process definitions, build and deploy a new project.

Most processes require additional information to create a new process instance. This is done through forms. For this project, fill in the name of the candidate that is to be interviewed.

When you click Submit, you create a new process instance. This creates the first task, that is available for the Human Resources team. To see the task, you need to logout and log in as a user with the appropriate role assigned, that is someone from the Human Resources.

When you start the process, you can interact with the human tasks. To do so, click Track  Task Inbox.

Note that in order to see the tasks in the task list, you need to belong to specific user groups, for which the task is designed. For example, the HR Interview task is visible only for the members of the HR group, and the Tech Interview Task is visible only to the members of the IT group.

5.4. Examples zip

A zip file of examples can also be downloaded from the downloads page, containing various examples that can be opened in the Eclipse-based Developers Tools. Simply download and unzip the examples artefact and import into your Eclipse workspace.

6. jBPM Version Migration Guide

6.1. Deprecated in jBPM 7

Table 4. Deprecated properties
Property Description jBPM 7 Behavior

jbpm.v5.id.strategy

This property is responsible for how the id value of NodeInstance instances was generated. Setting this property to true meant that the same strategy used in jBPM 5 was still used, even though this (jBPM 5) strategy meant that NodeInstance ids were not unique.

In jBPM 7, this is no longer possible: all NodeInstance id’s are unique.

6.2. Changed in jBPM 7

Table 5. Migration information
Jira Description What to do

https://issues.jboss.org/browse/JBPM-7693

Value of constant DAYS_PER_WEEK in class org.jbpm.process.core.timer.BusinessCalendarImpl was updated to business.days.per.week to correctly reflect its meaning.

Update your code to reflect this change - from old value business.hours.per.week to new value business.days.per.week.

jBPM Core

Using the jBPM Core Engine

7. Core Engine API

7.1. Core engine API for the jBPM engine

The jBPM 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 jBPM 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 jBPM 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 jBPM 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 jBPM 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 jBPM 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 the full reference information for all public jBPM 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.

7.2. 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.

KnowledgeBaseAndSession
Figure 10. KIE base and KIE session in the jBPM 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 jBPM engine API, you can interact with elements of the API that this level defines.

7.2.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 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();

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.

7.2.2. KIE session

After creating and loading the KIE base, you can create a KIE session to interact with the jBPM 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");

7.2.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
  /**
	 * Start a new process instance.  Use the process (definition) that
	 * is referenced by the given process ID.
	 *
	 * @param processId  The ID of the process to start
	 * @return the ProcessInstance that represents the instance of the process that was started
	 */
    ProcessInstance startProcess(String processId);

    /**
	 * Start a new process instance.  Use the process (definition) that
	 * is referenced by the given process ID.  You can pass parameters
	 * to the process instance as name-value pairs, and these parameters set
	 * variables of the process instance.
   *
	 * @param processId  the ID of the process to start
   * @param parameters  the process variables to set when starting the process instance
	 * @return the ProcessInstance that represents the instance of the process that was started
     */
    ProcessInstance startProcess(String processId,
                                 Map<String, Object> parameters);

    /**
     * Signals the jBPM engine that an event has occurred. The type parameter defines
     * the type of event and the event parameter can contain additional information
     * related to the event.  All process instances that are listening to this type
     * of (external) event will be notified.  For performance reasons, use this type of
     * event signaling only if one process instance must be able to notify
     * other process instances. For internal events within one process instance, use the
     * signalEvent method that also include the processInstanceId of the process instance
     * in question.
     *
     * @param type the type of event
     * @param event the data associated with this event
     */
    void signalEvent(String type,
                     Object event);

    /**
     * Signals the process instance that an event has occurred. The type parameter defines
     * the type of event and the event parameter can contain additional information
     * related to the event.  All node instances inside the given process instance that
     * are listening to this type of (internal) event will be notified.  Note that the event
     * will only be processed inside the given process instance.  All other process instances
     * waiting for this type of event will not be notified.
     *
     * @param type the type of event
     * @param event the data associated with this event
     * @param processInstanceId the id of the process instance that should be signaled
     */
    void signalEvent(String type,
                     Object event,
                     long processInstanceId);

    /**
     * Returns a collection of currently active process instances.  Note that only process
     * instances that are currently loaded and active inside the jBPM engine are returned.
     * When using persistence, it is likely not all running process instances are loaded
     * as their state is stored persistently.  It is best practice not to use this
     * method to collect information about the state of your process instances but to use
     * a history log for that purpose.
     *
     * @return a collection of process instances currently active in the session
     */
    Collection<ProcessInstance> getProcessInstances();

    /**
     * Returns the process instance with the given ID.  Note that only active process instances
     * are returned. If a process instance has been completed already, this method returns
     * null.
     *
     * @param id the ID of the process instance
     * @return the process instance with the given ID, or null if it cannot be found
     */
    ProcessInstance getProcessInstance(long processInstanceId);

    /**
     * Aborts the process instance with the given ID. If the process instance has been completed
     * (or aborted), or if the process instance cannot be found, this method will throw an
     * IllegalArgumentException.
     *
     * @param id the ID of the process instance
     */
    void abortProcessInstance(long processInstanceId);

    /**
     * Returns the WorkItemManager related to this session. This object can be used to
     * register new WorkItemHandlers or to complete (or abort) WorkItems.
     *
     * @return the WorkItemManager related to this session
     */
    WorkItemManager getWorkItemManager();

7.2.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 jBPM 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
      /**
      * Start a new process instance.  Use the process (definition) that
      * is referenced by the given process ID.  You can pass parameters
      * to the process instance (as name-value pairs), and these parameters set
      * variables of the process instance.
      *
      * @param processId  the ID of the process to start
      * @param correlationKey custom correlation key that can be used to identify the process instance
      * @param parameters  the process variables to set when starting the process instance
      * @return the ProcessInstance that represents the instance of the process that was started
      */
      ProcessInstance startProcess(String processId, CorrelationKey correlationKey, Map<String, Object> parameters);

      /**
      * Create a new process instance (but do not yet start it).  Use the process
      * (definition) that is referenced by the given process ID.
      * You can pass to the process instance (as name-value pairs),
      * and these parameters set variables of the process instance.
      * Use this method if you need a reference to the process instance before actually
      * starting it.  Otherwise, use startProcess.
      *
      * @param processId  the ID of the process to start
      * @param correlationKey custom correlation key that can be used to identify the process instance
      * @param parameters  the process variables to set when creating the process instance
      * @return the ProcessInstance that represents the instance of the process that was created (but not yet started)
      */
      ProcessInstance createProcessInstance(String processId, CorrelationKey correlationKey, Map<String, Object> parameters);

      /**
      * Returns the process instance with the given correlationKey.  Note that only active process instances
      * are returned.  If a process instance has been completed already, this method will return
      * null.
      *
      * @param correlationKey the custom correlation key assigned when the process instance was created
      * @return the process instance identified by the key or null if it cannot be found
      */
      ProcessInstance getProcessInstance(CorrelationKey correlationKey);

Correlation is usually used with long-running processes. You must enable persistence if you want to store correlation information permanently.

7.3. Runtime manager

The RuntimeManager class provides a layer in the jBPM 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 same KieSession whenever working with a given process instance.

Regardless of the strategy, the RuntimeManager class ensures the same capabilities in initialization and configuration of the jBPM 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 jBPM 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
public interface RuntimeManager {

	/**
	 * Returns a <code>RuntimeEngine</code> instance that is fully initialized:
	 * <ul>
	 * 	<li>KieSession is created or loaded depending on the strategy</li>
	 * 	<li>TaskService is initialized and attached to the KIE session (through a listener)</li>
	 * 	<li>WorkItemHandlers are initialized and registered on the KIE session</li>
	 * 	<li>EventListeners (process, agenda, working memory) are initialized and added to the KIE session</li>
	 * </ul>
	 * @param context the concrete implementation of the context that is supported by given <code>RuntimeManager</code>
	 * @return instance of the <code>RuntimeEngine</code>
	 */
    RuntimeEngine getRuntimeEngine(Context<?> context);

    /**
     * Unique identifier of the <code>RuntimeManager</code>
     * @return
     */
    String getIdentifier();

    /**
     * Disposes <code>RuntimeEngine</code> and notifies all listeners about that fact.
     * This method should always be used to dispose <code>RuntimeEngine</code> that is not needed
     * anymore. <br/>
     * Do not use KieSession.dispose() used with RuntimeManager as it will break the internal
     * mechanisms of the manager responsible for clear and efficient disposal.<br/>
     * Disposing is not needed if <code>RuntimeEngine</code> was obtained within an active JTA transaction,
     * if the getRuntimeEngine method was invoked during active JTA transaction, then disposing of
     * the runtime engine will happen automatically on transaction completion.
     * @param runtime
     */
    void disposeRuntimeEngine(RuntimeEngine runtime);

    /**
     * Closes <code>RuntimeManager</code> and releases its resources. Call this method when
     * a runtime manager is not needed anymore. Otherwise it will still be active and operational.
     */
    void close();

}

The RuntimeManager class also provides the RuntimeEngine class, which includes methods to get access to underlying jBPM engine components:

Definition of the RuntimeEngine interface
public interface RuntimeEngine {

	/**
	 * Returns the <code>KieSession</code> configured for this <code>RuntimeEngine</code>
	 * @return
	 */
    KieSession getKieSession();

    /**
	 * Returns the <code>TaskService</code> configured for this <code>RuntimeEngine</code>
	 * @return
	 */
    TaskService getTaskService();
}

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 jBPM 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.

7.3.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 single KieSession and TaskService instances). Access to the runtime engine is synchronized and, therefore, thread safe, although it comes with a performance penalty due to synchronization.

This strategy is similar to what was available by default in jBPM version 5.x. 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 jBPM 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 singleton RuntimeManager, you do not need to take the Context instance into account. Usually, you can use EmptyContext.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 a RuntimeManager 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

A 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 jBPM 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 jBPM 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-request RuntimeManager, you do not need to take the Context instance into account. Usually, you can use EmptyContext.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. Each KieSession is available as long as the ProcessInstance to which it belongs is active.

This strategy provides the most flexible approach for using advanced capabilities of the jBPM 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 and ProcessInstance to ensure that it always delivers the same KieSession for a given ProcessInstance.

  • It merges the lifecycle of KieSession with ProcessInstance, 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 same KieSession.

  • 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 to ProcessInstanceIdContext to use a custom (business) key instead of the process instance ID

7.3.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.

  • At request time, complete the following stages:

    • Get RuntimeEngine from the RuntimeManager, using the proper context instance as determined by the strategy that you configured for the RuntimeManager class.

    • Get the KieSession and TaskService objects from the RuntimeEngine.

    • Use the KieSession and TaskService objects for operations such as startProcess or completeTask.

    • After completing processing, dispose RuntimeEngine using the RuntimeManager.disposeRuntimeEngine method.

  • At application shutdown time, complete the following stage:

    • Close the RuntimeManager instance.

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
    // First, configure the environment to be used by RuntimeManager
    RuntimeEnvironment environment = RuntimeEnvironmentBuilder.Factory.get()
    .newDefaultInMemoryBuilder()
    .addAsset(ResourceFactory.newClassPathResource("BPMN2-ScriptTask.bpmn2"), ResourceType.BPMN2)
    .get();

    // Next, create the RuntimeManager - in this case the singleton strategy is chosen
    RuntimeManager manager = RuntimeManagerFactory.Factory.get().newSingletonRuntimeManager(environment);

    // Then get RuntimeEngine from the runtime manager, using an empty context because singleton does not keep track
    // of runtime engine as there is only one
    RuntimeEngine runtime = manager.getRuntimeEngine(EmptyContext.get());

    // Get the KieSession from the RuntimeEngine - already initialized with all handlers, listeners, and other requirements
    // configured on the environment
    KieSession ksession = runtimeEngine.getKieSession();

    // Add invocations of the jBPM engine here,
    // for example, ksession.startProcess(processId);

    // Finally, dispose the runtime engine
    manager.disposeRuntimeEngine(runtimeEngine);

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 the newDefaultInMemoryBuilder builder.

  • A single process, which is added as an asset, is available for execution.

  • The TaskService class is configured and attached to the KieSession instance through the LocalHTWorkItemHandler interface to support user task capabilities within processes.

7.3.3. Runtime environment configuration object

The RuntimeManager class encapsulates internal jBPM engine complexity, such as creating, disposing, and registering handlers.

It also provides fine-grained control over jBPM 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
  public interface RuntimeEnvironment {

	/**
	 * Returns <code>KieBase</code> that is to be used by the manager
	 * @return
	 */
    KieBase getKieBase();

    /**
     * KieSession environment that is to be used to create instances of <code>KieSession</code>
     * @return
     */
    Environment getEnvironment();

    /**
     * KieSession configuration that is to be used to create instances of <code>KieSession</code>
     * @return
     */
    KieSessionConfiguration getConfiguration();

    /**
     * Indicates if persistence is to be used for the KieSession instances
     * @return
     */
    boolean usePersistence();

    /**
     * Delivers a concrete implementation of <code>RegisterableItemsFactory</code> to obtain handlers and listeners
     * that is to be registered on instances of <code>KieSession</code>
     * @return
     */
    RegisterableItemsFactory getRegisterableItemsFactory();

    /**
     * Delivers a concrete implementation of <code>UserGroupCallback</code> that is to be registered on instances
     * of <code>TaskService</code> for managing users and groups.
     * @return
     */
    UserGroupCallback getUserGroupCallback();

    /**
     * Delivers a custom class loader that is to be used by the jBPM engine and task service instances
     * @return
     */
    ClassLoader getClassLoader();

    /**
     * Closes the environment, permitting closing of all dependent components such as ksession factories
     */
    void close();

7.3.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
public interface RuntimeEnvironmentBuilder {

	public RuntimeEnvironmentBuilder persistence(boolean persistenceEnabled);

	public RuntimeEnvironmentBuilder entityManagerFactory(Object emf);

	public RuntimeEnvironmentBuilder addAsset(Resource asset, ResourceType type);

	public RuntimeEnvironmentBuilder addEnvironmentEntry(String name, Object value);

	public RuntimeEnvironmentBuilder addConfiguration(String name, String value);

	public RuntimeEnvironmentBuilder knowledgeBase(KieBase kbase);

	public RuntimeEnvironmentBuilder userGroupCallback(UserGroupCallback callback);

	public RuntimeEnvironmentBuilder registerableItemsFactory(RegisterableItemsFactory factory);

	public RuntimeEnvironment get();

	public RuntimeEnvironmentBuilder classLoader(ClassLoader cl);

	public RuntimeEnvironmentBuilder schedulerService(Object globalScheduler);

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
public interface RuntimeEnvironmentBuilderFactory {

	/**
     * Provides a completely empty <code>RuntimeEnvironmentBuilder</code> instance to manually
     * set all required components instead of relying on any defaults.
     * @return new instance of <code>RuntimeEnvironmentBuilder</code>
     */
    public RuntimeEnvironmentBuilder newEmptyBuilder();

    /**
     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:
     * <ul>
     * 	<li>DefaultRuntimeEnvironment</li>
     * </ul>
     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults
     *
     * @see DefaultRuntimeEnvironment
     */
    public RuntimeEnvironmentBuilder newDefaultBuilder();

    /**
     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:
     * <ul>
     * 	<li>DefaultRuntimeEnvironment</li>
     * </ul>
     * but does not have persistence for the jBPM engine configured so it will only store process instances in memory
     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults
     *
     * @see DefaultRuntimeEnvironment
     */
    public RuntimeEnvironmentBuilder newDefaultInMemoryBuilder();

    /**
     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:
     * <ul>
     * 	<li>DefaultRuntimeEnvironment</li>
     * </ul>
     * This method is tailored to work smoothly with KJAR files
     * @param groupId group id of kjar
     * @param artifactId artifact id of kjar
     * @param version version number of kjar
     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults
     *
     * @see DefaultRuntimeEnvironment
     */
    public RuntimeEnvironmentBuilder newDefaultBuilder(String groupId, String artifactId, String version);

    /**
     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:
     * <ul>
     * 	<li>DefaultRuntimeEnvironment</li>
     * </ul>
     * This method is tailored to work smoothly with KJAR files and use the kbase and ksession settings in the KJAR
     * @param groupId group id of kjar
     * @param artifactId artifact id of kjar
     * @param version version number of kjar
     * @param kbaseName name of the kbase defined in kmodule.xml stored in kjar
     * @param ksessionName name of the ksession define in kmodule.xml stored in kjar
     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults
     *
     * @see DefaultRuntimeEnvironment
     */
    public RuntimeEnvironmentBuilder newDefaultBuilder(String groupId, String artifactId, String version, String kbaseName, String ksessionName);

    /**
     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:
     * <ul>
     * 	<li>DefaultRuntimeEnvironment</li>
     * </ul>
     * This method is tailored to work smoothly with KJAR files and use the release ID defined in the KJAR
     * @param releaseId <code>ReleaseId</code> that described the kjar
     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults
     *
     * @see DefaultRuntimeEnvironment
     */
    public RuntimeEnvironmentBuilder newDefaultBuilder(ReleaseId releaseId);

    /**
     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:
     * <ul>
     * 	<li>DefaultRuntimeEnvironment</li>
     * </ul>
		 * This method is tailored to work smoothly with KJAR files and use the kbase, ksession, and release ID settings in the KJAR
     * @param releaseId <code>ReleaseId</code> that described the kjar
     * @param kbaseName name of the kbase defined in kmodule.xml stored in kjar
     * @param ksessionName name of the ksession define in kmodule.xml stored in kjar
     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults
     *
     * @see DefaultRuntimeEnvironment
     */
    public RuntimeEnvironmentBuilder newDefaultBuilder(ReleaseId releaseId, String kbaseName, String ksessionName);

    /**
     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:
     * <ul>
     * 	<li>DefaultRuntimeEnvironment</li>
     * </ul>
     * It relies on KieClasspathContainer that requires the presence of kmodule.xml in the META-INF folder which
     * defines the kjar itself.
     * Expects to use default kbase and ksession from kmodule.
     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults
     *
     * @see DefaultRuntimeEnvironment
     */
    public RuntimeEnvironmentBuilder newClasspathKmoduleDefaultBuilder();

    /**
     * Provides default configuration of <code>RuntimeEnvironmentBuilder</code> that is based on:
     * <ul>
     * 	<li>DefaultRuntimeEnvironment</li>
     * </ul>
		 * It relies on KieClasspathContainer that requires the presence of kmodule.xml in the META-INF folder which
     * defines the kjar itself.
     * @param kbaseName name of the kbase defined in kmodule.xml
     * @param ksessionName name of the ksession define in kmodule.xml
     * @return new instance of <code>RuntimeEnvironmentBuilder</code> that is already preconfigured with defaults
     *
     * @see DefaultRuntimeEnvironment
     */
    public RuntimeEnvironmentBuilder newClasspathKmoduleDefaultBuilder(String kbaseName, String ksessionName);

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 jBPM 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.

7.3.5. Registration of handlers and listeners for runtime engines

If you use the runtime manager API, the runtime engine object represents the jBPM 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
	/**
	 * Returns new instances of <code>WorkItemHandler</code> that will be registered on <code>RuntimeEngine</code>
	 * @param runtime provides <code>RuntimeEngine</code> in case handler need to make use of it internally
	 * @return map of handlers to be registered - in case of no handlers empty map shall be returned.
	 */
    Map<String, WorkItemHandler> getWorkItemHandlers(RuntimeEngine runtime);

    /**
	 * Returns new instances of <code>ProcessEventListener</code> that will be registered on <code>RuntimeEngine</code>
	 * @param runtime provides <code>RuntimeEngine</code> in case listeners need to make use of it internally
	 * @return list of listeners to be registered - in case of no listeners empty list shall be returned.
	 */
    List<ProcessEventListener> getProcessEventListeners(RuntimeEngine runtime);

    /**
	 * Returns new instances of <code>AgendaEventListener</code> that will be registered on <code>RuntimeEngine</code>
	 * @param runtime provides <code>RuntimeEngine</code> in case listeners need to make use of it internally
	 * @return list of listeners to be registered - in case of no listeners empty list shall be returned.
	 */
    List<AgendaEventListener> getAgendaEventListeners(RuntimeEngine runtime);

    /**
	 * Returns new instances of <code>WorkingMemoryEventListener</code> that will be registered on <code>RuntimeEngine</code>
	 * @param runtime provides <code>RuntimeEngine</code> in case listeners need to make use of it internally
	 * @return list of listeners to be registered - in case of no listeners empty list shall be returned.
	 */
    List<WorkingMemoryEventListener> getWorkingMemoryEventListeners(RuntimeEngine runtime);

The jBPM 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.

7.3.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
  1. Create a file named drools.session.conf in the META-INF subdirectory of the root of the class path. For web applications the directory is WEB-INF/classes/META-INF.

  2. Add the following line to the drools.session.conf file:

    drools.workItemHandlers = CustomWorkItemHandlers.conf
  3. Create a file named CustomWorkItemHandlers.conf in the same directory.

  4. In the CustomWorkItemHandlers.conf file, define custom work item handlers using the MVEL style, similar to the following example:

    [
      "Log": new org.jbpm.process.instance.impl.demo.SystemOutWorkItemHandler(),
      "WebService": new org.jbpm.process.workitem.webservice.WebServiceWorkItemHandler(ksession),
      "Rest": new org.jbpm.process.workitem.rest.RESTWorkItemHandler(),
      "Service Task" : new org.jbpm.process.workitem.bpmn2.ServiceTaskHandler(ksession)
    ]
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.

7.3.5.2. Registration of handlers and listeners in a CDI environment

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
public interface WorkItemHandlerProducer {

    /**
     * Returns a map of work items (key = work item name, value=  work item handler instance)
     * to be registered on the KieSession
     * <br/>
     * The following parameters are accepted:
     * <ul>
     *  <li>ksession</li>
     *  <li>taskService</li>
     *  <li>runtimeManager</li>
     * </ul>
     *
     * @param identifier - identifier of the owner - usually RuntimeManager that allows the producer to filter out
     * and provide valid instances for given owner
     * @param params - the owner might provide some parameters, usually KieSession, TaskService, RuntimeManager instances
     * @return map of work item handler instances (recommendation is to always return new instances when this method is invoked)
     */
    Map<String, WorkItemHandler> getWorkItemHandlers(String identifier, Map<String, Object> params);
}

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 for ProcessEventListener

  • @Agenda for AgendaEventListener

  • @WorkingMemory for WorkingMemoryEventListener

Definition of the EventListenerProducer interface
public interface EventListenerProducer<T> {

    /**
     * Returns a list of instances for given (T) type of listeners
     * <br/>
     * The following parameters are accepted:
     * <ul>
     *  <li>ksession</li>
     *  <li>taskService</li>
     *  <li>runtimeManager</li>
     * </ul>
     * @param identifier - identifier of the owner - usually RuntimeManager that allows the producer to filter out
     * and provide valid instances for given owner
     * @param params - the owner might provide some parameters, usually KieSession, TaskService, RuntimeManager instances
     * @return list of listener instances (recommendation is to always return new instances when this method is invoked)
     */
    List<T> getEventListeners(String identifier, Map<String, Object>  params);
}

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 jBPM 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 jBPM engine or the process instance in case of an error. The jBPM 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.

7.4. Services in the jBPM engine

The jBPM engine provides a set of high-level services, running on top of the runtime manager API. This API is available since jBPM version 6.2.

The services provide the most convenient way to embed the jBPM 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 jBPM 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.

7.4.1. Modules for jBPM engine services

The jBPM 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

7.4.2. Deployment service

The deployment service deploys and undeploys units in the jBPM 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
// Create deployment unit by providing the GAV of the KJAR
DeploymentUnit deploymentUnit = new KModuleDeploymentUnit(GROUP_ID, ARTIFACT_ID, VERSION);
// Get the deploymentId for the deployed unit
String deploymentId = deploymentUnit.getIdentifier();
// Deploy the unit
deploymentService.deploy(deploymentUnit);
// Retrieve the deployed unit
DeployedUnit deployed = deploymentService.getDeployedUnit(deploymentId);
// Get the runtime manager
RuntimeManager manager = deployed.getRuntimeManager();

The following definition shows the complete DeploymentService interface:

Definition of the DeploymentService interface
public interface DeploymentService {

    void deploy(DeploymentUnit unit);

    void undeploy(DeploymentUnit unit);

    RuntimeManager getRuntimeManager(String deploymentUnitId);

    DeployedUnit getDeployedUnit(String deploymentUnitId);

    Collection<DeployedUnit> getDeployedUnits();

    void activate(String deploymentId);

    void deactivate(String deploymentId);

    boolean isDeployed(String deploymentUnitId);
}

7.4.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 jBPM 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 subprocesses 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
String processId = "org.jbpm.writedocument";

Collection<UserTaskDefinition> processTasks =
bpmn2Service.getTasksDefinitions(deploymentUnit.getIdentifier(), processId);

Map<String, String> processData =
bpmn2Service.getProcessVariables(deploymentUnit.getIdentifier(), processId);

Map<String, String> taskInputMappings =
bpmn2Service.getTaskInputMappings(deploymentUnit.getIdentifier(), processId, "Write a Document" );

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
public interface DefinitionService {

    ProcessDefinition buildProcessDefinition(String deploymentId, String bpmn2Content, ClassLoader classLoader, boolean cache) throws IllegalArgumentException;

    ProcessDefinition getProcessDefinition(String deploymentId, String processId);

    Collection<String> getReusableSubProcesses(String deploymentId, String processId);

    Map<String, String> getProcessVariables(String deploymentId, String processId);

    Map<String, String> getServiceTasks(String deploymentId, String processId);

    Map<String, Collection<String>> getAssociatedEntities(String deploymentId, String processId);

    Collection<UserTaskDefinition> getTasksDefinitions(String deploymentId, String processId);

    Map<String, String> getTaskInputMappings(String deploymentId, String processId, String taskName);

    Map<String, String> getTaskOutputMappings(String deploymentId, String processId, String taskName);

}

7.4.4. Process service

The deployment and definition services prepare process data in the jBPM engine. To execute processes based on this data, use the process service. The process service supports interaction with the jBPM engine execution environment, including the following actions:

  • Starting a new process instance

  • 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 alter the 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
KModuleDeploymentUnit deploymentUnit = new KModuleDeploymentUnit(GROUP_ID, ARTIFACT_ID, VERSION);

deploymentService.deploy(deploymentUnit);

long processInstanceId = processService.startProcess(deploymentUnit.getIdentifier(), "customtask");

ProcessInstance pi = processService.getProcessInstance(processInstanceId);

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
public interface ProcessService {

	/**
	 * Starts a process with no variables
	 *
	 * @param deploymentId deployment identifier
	 * @param processId process identifier
	 * @return process instance IDentifier
	 * @throws RuntimeException in case of encountered errors
	 * @throws DeploymentNotFoundException in case a deployment with the given deployment identifier does not exist
	 * @throws DeploymentNotActiveException in case the deployment with the given deployment identifier is not active
	 */
	Long startProcess(String deploymentId, String processId);

	/**
	 * Starts a process and sets variables
	 *
	 * @param deploymentId deployment identifier
	 * @param processId process identifier
	 * @param params process variables
	 * @return process instance IDentifier
	 * @throws RuntimeException in case of encountered errors
	 * @throws DeploymentNotFoundException in case a deployment with the given deployment identifier does not exist
	 * @throws DeploymentNotActiveException in case the deployment with the given deployment identifier is not active
	 */
    Long startProcess(String deploymentId, String processId, Map<String, Object> params);

	/**
	 * Starts a process with no variables and assigns a correlation key
	 *
	 * @param deploymentId deployment identifier
	 * @param processId process identifier
	 * @param correlationKey correlation key to be assigned to the process instance - must be unique
	 * @return process instance IDentifier
	 * @throws RuntimeException in case of encountered errors
	 * @throws DeploymentNotFoundException in case a deployment with the given deployment identifier does not exist
     * @throws DeploymentNotActiveException in case the deployment with the given deployment identifier is not active
	 */
	Long startProcess(String deploymentId, String processId, CorrelationKey correlationKey);

	/**
	 * Starts a process, sets variables, and assigns a correlation key
	 *
	 * @param deploymentId deployment identifier
	 * @param processId process identifier
	 * @param correlationKey correlation key to be assigned to the process instance - must be unique
	 * @param params process variables
	 * @return process instance IDentifier
	 * @throws RuntimeException in case of encountered errors
	 * @throws DeploymentNotFoundException in case a deployment with the given deployment identifier does not exist
     * @throws DeploymentNotActiveException in case the deployment with the given deployment identifier is not active
	 */
    Long startProcess(String deploymentId, String processId, CorrelationKey correlationKey, Map<String, Object> params);

    /**
     * Starts a process at the listed nodes, instead of the normal starting point.
     * This method can be used for restarting a process that was aborted. However,
     * it does not restore the context of a previous process instance. You must
     * supply all necessary variables when calling this method.
     * This method does not guarantee that the process is started in a valid state.
     *
     * @param deploymentId deployment identifier
     * @param processId process identifier
     * @param params process variables
     * @param nodeIds list of BPMN node identifiers where the process must start
     * @return process instance IDentifier
     * @throws RuntimeException in case of encountered errors
     * @throws DeploymentNotFoundException in case a deployment with the given deployment identifier does not exist
     * @throws DeploymentNotActiveException in case the deployment with the given deployment identifier is not active
     */
    Long startProcessFromNodeIds(String deploymentId, String processId, Map<String, Object> params, String... nodeIds);

    /**
    * Starts a process at the listed nodes, instead of the normal starting point,
    * and assigns a correlation key.
    * This method can be used for restarting a process that was aborted. However,
    * it does not restore the context of a previous process instance. You must
    * supply all necessary variables when calling this method.
    * This method does not guarantee that the process is started in a valid state.
     *
     * @param deploymentId deployment identifier
     * @param processId process identifier
     * @param key correlation key (must be unique)
     * @param params process variables
     * @param nodeIds list of BPMN node identifiers where the process must start.
     * @return process instance IDentifier
     * @throws RuntimeException in case of encountered errors
     * @throws DeploymentNotFoundException in case a deployment with the given deployment identifier does not exist
     * @throws DeploymentNotActiveException in case the deployment with the given deployment identifier is not active
     */
    Long startProcessFromNodeIds(String deploymentId, String processId, CorrelationKey key, Map<String, Object> params, String... nodeIds);

    /**
     * Aborts the specified process
     *
     * @param processInstanceId process instance unique identifier
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
     */
    void abortProcessInstance(Long processInstanceId);

    /**
     * Aborts the specified process
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId process instance unique identifier
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
     */
    void abortProcessInstance(String deploymentId, Long processInstanceId);

    /**
	 * Aborts all specified processes
	 *
	 * @param processInstanceIds list of process instance unique identifiers
	 * @throws DeploymentNotFoundException in case the deployment unit was not found
	 * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
	 */
    void abortProcessInstances(List<Long> processInstanceIds);

    /**
     * Aborts all specified processes
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceIds list of process instance unique identifiers
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
     */
    void abortProcessInstances(String deploymentId, List<Long> processInstanceIds);

    /**
	 * Signals an event to a single process instance
	 *
	 * @param processInstanceId the process instance unique identifier
	 * @param signalName the ID of the signal in the process
	 * @param event the event object to be passed with the event
	 * @throws DeploymentNotFoundException in case the deployment unit was not found
	 * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
	 */
    void signalProcessInstance(Long processInstanceId, String signalName, Object event);

    /**
     * Signals an event to a single process instance
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId the process instance unique identifier
     * @param signalName the ID of the signal in the process
     * @param event the event object to be passed with the event
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
     */
    void signalProcessInstance(String deploymentId, Long processInstanceId, String signalName, Object event);

    /**
	 * Signal an event to a list of process instances
	 *
	 * @param processInstanceIds list of process instance unique identifiers
	 * @param signalName the ID of the signal in the process
	 * @param event the event object to be passed with the event
	 * @throws DeploymentNotFoundException in case the deployment unit was not found
	 * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
	 */
    void signalProcessInstances(List<Long> processInstanceIds, String signalName, Object event);

    /**
     * Signal an event to a list of process instances
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceIds list of process instance unique identifiers
     * @param signalName the ID of the signal in the process
     * @param event the event object to be passed with the event
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
     */
    void signalProcessInstances(String deploymentId, List<Long> processInstanceIds, String signalName, Object event);

    /**
     * Signal an event to a any process instance that listens to a given signal and belongs to a given deployment
     *
     * @param deployment identifier of the deployment
     * @param signalName the ID of the signal in the process
     * @param event the event object to be passed with the event
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     */
    void signalEvent(String deployment, String signalName, Object event);

    /**
	 * Returns process instance information. Will return null if no
	 * active process with the ID is found
	 *
	 * @param processInstanceId The process instance unique identifier
	 * @return Process instance information
	 * @throws DeploymentNotFoundException in case the deployment unit was not found
	 */
    ProcessInstance getProcessInstance(Long processInstanceId);

    /**
     * Returns process instance information. Will return null if no
     * active process with the ID is found
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId The process instance unique identifier
     * @return Process instance information
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     */
    ProcessInstance getProcessInstance(String deploymentId, Long processInstanceId);

    /**
	 * Returns process instance information. Will return null if no
	 * active process with that correlation key is found
	 *
	 * @param correlationKey correlation key assigned to the process instance
	 * @return Process instance information
	 * @throws DeploymentNotFoundException in case the deployment unit was not found
	 */
    ProcessInstance getProcessInstance(CorrelationKey correlationKey);

    /**
     * Returns process instance information. Will return null if no
     * active process with that correlation key is found
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param correlationKey correlation key assigned to the process instance
     * @return Process instance information
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     */
    ProcessInstance getProcessInstance(String deploymentId, CorrelationKey correlationKey);

    /**
	 * Sets a process variable.
	 * @param processInstanceId The process instance unique identifier
	 * @param variableId The variable ID to set
	 * @param value The variable value
	 * @throws DeploymentNotFoundException in case the deployment unit was not found
	 * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
	 */
    void setProcessVariable(Long processInstanceId, String variableId, Object value);

    /**
     * Sets a process variable.
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId The process instance unique identifier
     * @param variableId The variable id to set.
     * @param value The variable value.
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
     */
    void setProcessVariable(String deploymentId, Long processInstanceId, String variableId, Object value);

    /**
	 * Sets process variables.
	 *
	 * @param processInstanceId The process instance unique identifier
	 * @param variables map of process variables (key = variable name, value = variable value)
	 * @throws DeploymentNotFoundException in case the deployment unit was not found
	 * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
	 */
    void setProcessVariables(Long processInstanceId, Map<String, Object> variables);

    /**
     * Sets process variables.
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId The process instance unique identifier
     * @param variables map of process variables (key = variable name, value = variable value)
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
     */
    void setProcessVariables(String deploymentId, Long processInstanceId, Map<String, Object> variables);

    /**
	 * Gets a process instance variable.
	 *
	 * @param processInstanceId the process instance unique identifier
	 * @param variableName the variable name to get from the process
	 * @throws DeploymentNotFoundException in case the deployment unit was not found
	 * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
	*/
    Object getProcessInstanceVariable(Long processInstanceId, String variableName);

    /**
     * Gets a process instance variable.
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId the process instance unique identifier
     * @param variableName the variable name to get from the process
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
    */
    Object getProcessInstanceVariable(String deploymentId, Long processInstanceId, String variableName);

	/**
	 * Gets a process instance variable values.
	 *
	 * @param processInstanceId The process instance unique identifier
	 * @throws DeploymentNotFoundException in case the deployment unit was not found
	 * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
	*/
	Map<String, Object> getProcessInstanceVariables(Long processInstanceId);

	/**
     * Gets a process instance variable values.
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId The process instance unique identifier
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
    */
    Map<String, Object> getProcessInstanceVariables(String deploymentId, Long processInstanceId);

	/**
	 * Returns all signals available in current state of given process instance
	 *
	 * @param processInstanceId process instance ID
	 * @return list of available signals or empty list if no signals are available
	 */
    Collection<String> getAvailableSignals(Long processInstanceId);

    /**
     * Returns all signals available in current state of given process instance
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId process instance ID
     * @return list of available signals or empty list if no signals are available
     */
    Collection<String> getAvailableSignals(String deploymentId, Long processInstanceId);

	/**
	 * Completes the specified WorkItem with the given results
	 *
	 * @param id workItem ID
	 * @param results results of the workItem
	 * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws WorkItemNotFoundException in case a work item with the given ID was not found
	 */
    void completeWorkItem(Long id, Map<String, Object> results);

    /**
     * Completes the specified WorkItem with the given results
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId process instance ID to which the work item belongs
     * @param id workItem ID
     * @param results results of the workItem
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws WorkItemNotFoundException in case a work item with the given ID was not found
     */
    void completeWorkItem(String deploymentId, Long processInstanceId, Long id, Map<String, Object> results);

    /**
     * Abort the specified workItem
     *
     * @param id workItem ID
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws WorkItemNotFoundException in case a work item with the given ID was not found
     */
    void abortWorkItem(Long id);

    /**
     * Abort the specified workItem
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId process instance ID to which the work item belongs
     * @param id workItem ID
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws WorkItemNotFoundException in case a work item with the given ID was not found
     */
    void abortWorkItem(String deploymentId, Long processInstanceId, Long id);

    /**
     * Returns the specified workItem
     *
     * @param id workItem ID
     * @return The specified workItem
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws WorkItemNotFoundException in case a work item with the given ID was not found
     */
    WorkItem getWorkItem(Long id);

    /**
     * Returns the specified workItem
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId process instance ID to which the work item belongs
     * @param id workItem ID
     * @return The specified workItem
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws WorkItemNotFoundException in case a work item with the given ID was not found
     */
    WorkItem getWorkItem(String deploymentId, Long processInstanceId, Long id);

    /**
     * Returns active work items by process instance ID.
     *
     * @param processInstanceId process instance ID
     * @return The list of active workItems for the process instance
     * @throws DeploymentNotFoundException in case the deployment unit was not found
	 * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
     */
    List<WorkItem> getWorkItemByProcessInstance(Long processInstanceId);

    /**
     * Returns active work items by process instance ID.
     *
     * @param deploymentId deployment to which the process instance belongs
     * @param processInstanceId process instance ID
     * @return The list of active workItems for the process instance
     * @throws DeploymentNotFoundException in case the deployment unit was not found
     * @throws ProcessInstanceNotFoundException in case a process instance with the given ID was not found
     */
    List<WorkItem> getWorkItemByProcessInstance(String deploymentId, Long processInstanceId);


    /**
     * Executes the provided command on the underlying command executor (usually KieSession)
     * @param deploymentId deployment identifier
     * @param command actual command for execution
     * @return results of the command execution
     * @throws DeploymentNotFoundException in case a deployment with the given deployment identifier does not exist
     * @throws DeploymentNotActiveException in case the deployment with the given deployment identifier is not active for restricted commands (for example, start process)
     */
    public <T> T execute(String deploymentId, Command<T> command);

    /**
     * Executes the provided command on the underlying command executor (usually KieSession)
     * @param deploymentId deployment identifier
     * @param context context implementation to be used to get the runtime engine
     * @param command actual command for execution
     * @return results of the command execution
     * @throws DeploymentNotFoundException in case a deployment with the given deployment identifier does not exist
     * @throws DeploymentNotActiveException in case the deployment with the given deployment identifier is not active for restricted commands (for example, start process)
     */
    public <T> T execute(String deploymentId, Context<?> context, Command<T> command);

}
7.4.4.1. 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());
Retrieving active process instances
Collection<processinstancedesc> instances = runtimeDataService.getProcessInstances(new QueryContext());
Retrieving active nodes for a particular process instance
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));

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 complete RuntimeDataService interface:

Definition of the RuntimeDataService interface
public interface RuntimeDataService {

    // Process instance information

    Collection<ProcessInstanceDesc> getProcessInstances(QueryContext queryContext);

    Collection<ProcessInstanceDesc> getProcessInstances(List<Integer> states, String initiator, QueryContext queryContext);

    Collection<ProcessInstanceDesc> getProcessInstancesByProcessId(List<Integer> states, String processId, String initiator, QueryContext queryContext);

    Collection<ProcessInstanceDesc> getProcessInstancesByProcessName(List<Integer> states, String processName, String initiator, QueryContext queryContext);

    Collection<ProcessInstanceDesc> getProcessInstancesByDeploymentId(String deploymentId, List<Integer> states, QueryContext queryContext);

    ProcessInstanceDesc getProcessInstanceById(long processInstanceId);

    Collection<ProcessInstanceDesc> getProcessInstancesByProcessDefinition(String processDefId, QueryContext queryContext);

    Collection<ProcessInstanceDesc> getProcessInstancesByProcessDefinition(String processDefId, List<Integer> states, QueryContext queryContext);


    // Node and Variable instance information

    NodeInstanceDesc getNodeInstanceForWorkItem(Long workItemId);

    Collection<NodeInstanceDesc> getProcessInstanceHistoryActive(long processInstanceId, QueryContext queryContext);

    Collection<NodeInstanceDesc> getProcessInstanceHistoryCompleted(long processInstanceId, QueryContext queryContext);

    Collection<NodeInstanceDesc> getProcessInstanceFullHistory(long processInstanceId, QueryContext queryContext);

    Collection<NodeInstanceDesc> getProcessInstanceFullHistoryByType(long processInstanceId, EntryType type, QueryContext queryContext);

    Collection<VariableDesc> getVariablesCurrentState(long processInstanceId);

    Collection<VariableDesc> getVariableHistory(long processInstanceId, String variableId, QueryContext queryContext);


    // Process information

    Collection<ProcessDefinition> getProcessesByDeploymentId(String deploymentId, QueryContext queryContext);

    Collection<ProcessDefinition> getProcessesByFilter(String filter, QueryContext queryContext);

    Collection<ProcessDefinition> getProcesses(QueryContext queryContext);

    Collection<String> getProcessIds(String deploymentId, QueryContext queryContext);

    ProcessDefinition getProcessById(String processId);

    ProcessDefinition getProcessesByDeploymentIdProcessId(String deploymentId, String processId);

	// user task query operations

    UserTaskInstanceDesc getTaskByWorkItemId(Long workItemId);

    UserTaskInstanceDesc getTaskById(Long taskId);

    List<TaskSummary> getTasksAssignedAsBusinessAdministrator(String userId, QueryFilter filter);

    List<TaskSummary> getTasksAssignedAsBusinessAdministratorByStatus(String userId, List<Status> statuses, QueryFilter filter);

    List<TaskSummary> getTasksAssignedAsPotentialOwner(String userId, QueryFilter filter);

    List<TaskSummary> getTasksAssignedAsPotentialOwner(String userId, List<String> groupIds, QueryFilter filter);

    List<TaskSummary> getTasksAssignedAsPotentialOwnerByStatus(String userId, List<Status> status, QueryFilter filter);

    List<TaskSummary> getTasksAssignedAsPotentialOwner(String userId, List<String> groupIds, List<Status> status, QueryFilter filter);

    List<TaskSummary> getTasksAssignedAsPotentialOwnerByExpirationDateOptional(String userId, List<Status> status, Date from, QueryFilter filter);

    List<TaskSummary> getTasksOwnedByExpirationDateOptional(String userId, List<Status> strStatuses, Date from, QueryFilter filter);

    List<TaskSummary> getTasksOwned(String userId, QueryFilter filter);

    List<TaskSummary> getTasksOwnedByStatus(String userId, List<Status> status, QueryFilter filter);

    List<Long> getTasksByProcessInstanceId(Long processInstanceId);

    List<TaskSummary> getTasksByStatusByProcessInstanceId(Long processInstanceId, List<Status> status, QueryFilter filter);

    List<AuditTask> getAllAuditTask(String userId, QueryFilter filter);

}
7.4.4.2. 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
long processInstanceId =
processService.startProcess(deployUnit.getIdentifier(), "org.jbpm.writedocument");

List<Long> taskIds =
runtimeDataService.getTasksByProcessInstanceId(processInstanceId);

Long taskId = taskIds.get(0);

userTaskService.start(taskId, "john");
UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId);

Map<String, Object> results = new HashMap<String, Object>();
results.put("Result", "some document data");
userTaskService.complete(taskId, "john", results);

7.4.5. Quartz-based timer service

The jBPM 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
#============================================================================
# Configure Main Scheduler Properties
#============================================================================

org.quartz.scheduler.instanceName = jBPMClusteredScheduler
org.quartz.scheduler.instanceId = AUTO

#============================================================================
# Configure ThreadPool
#============================================================================

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 5

#============================================================================
# Configure JobStore
#============================================================================

org.quartz.jobStore.misfireThreshold = 60000

org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreCMT
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties=false
org.quartz.jobStore.dataSource=managedDS
org.quartz.jobStore.nonManagedTXDataSource=nonManagedDS
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval = 20000

#=========================================================================
# Configure Datasources
#=========================================================================
org.quartz.dataSource.managedDS.jndiURL=jboss/datasources/psbpmsDS
org.quartz.dataSource.nonManagedDS.jndiURL=jboss/datasources/quartzNonManagedDS

You must modify the previous example to fit your environment.

For more information about configuring a Quartz scheduler, see the documentation for the Quartz 1.8.5 distribution archive.

7.4.6. 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

Dashbuilder data sets provide support for multiple data sources, such as CSV, SQL, and Elastic Search. However, the jBPM engine uses a RDBMS-based backend and focuses on SQL-based data sets.

Therefore, the jBPM engine query service is a subset of Dashbuilder data set capabilities that enables efficient queries with a simple API.

7.4.6.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 jBPM engine supplies the following mappers:

  • org.jbpm.kie.services.impl.query.mapper.ProcessInstanceQueryMapper, registered with the name ProcessInstances

  • org.jbpm.kie.services.impl.query.mapper.ProcessInstanceWithVarsQueryMapper, registered with the name ProcessInstancesWithVariables

  • org.jbpm.kie.services.impl.query.mapper.ProcessInstanceWithCustomVarsQueryMapper, registered with the name ProcessInstancesWithCustomVariables

  • org.jbpm.kie.services.impl.query.mapper.UserTaskInstanceQueryMapper, registered with the name UserTasks

  • org.jbpm.kie.services.impl.query.mapper.UserTaskInstanceWithVarsQueryMapper, registered with the name UserTasksWithVariables

  • org.jbpm.kie.services.impl.query.mapper.UserTaskInstanceWithCustomVarsQueryMapper, registered with name UserTasksWithCustomVariables

  • org.jbpm.kie.services.impl.query.mapper.TaskSummaryQueryMapper, registered with the name TaskSummaries

  • org.jbpm.kie.services.impl.query.mapper.RawListQueryMapper, registered with the name RawList

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());
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 jBPM 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 jBPM 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
public class TestQueryParamBuilder implements QueryParamBuilder<ColumnFilter> {

    private Map<String, Object> parameters;
    private boolean built = false;
    public TestQueryParamBuilder(Map<String, Object> parameters) {
        this.parameters = parameters;
    }

    @Override
    public ColumnFilter build() {
        // return null if it was already invoked
        if (built) {
            return null;
        }

        String columnName = "processInstanceId";

        ColumnFilter filter = FilterFactory.OR(
                FilterFactory.greaterOrEqualsTo((Long)parameters.get("min")),
                FilterFactory.lowerOrEqualsTo((Long)parameters.get("max")));
        filter.setColumnId(columnName);

        built = true;
        return filter;
    }

}

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);
7.4.6.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
  1. 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");

    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.

  2. Register the query:

    Registering a query
    queryService.registerQuery(query);
  3. 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());

    This simple query uses defaults from QueryContext for paging and sorting.

  4. If required, use a QueryContext object that changes the defaults of the paging and sorting:

    Changing defaults using a QueryContext object
    QueryContext ctx = new QueryContext(0, 100, "start_date", true);
             
    Collection<ProcessInstanceDesc> instances = queryService.query("getAllProcessInstances", ProcessInstanceQueryMapper.get(), ctx);
  5. If required, use the query to filter data:

    Using a query to filter data
    // single filter param
    Collection<ProcessInstanceDesc> instances = queryService.query("getAllProcessInstances", ProcessInstanceQueryMapper.get(), new QueryContext(), QueryParam.likeTo(COLUMN_PROCESSID, true, "org.jbpm%"));
     
    // multiple filter params (AND)
    Collection<ProcessInstanceDesc> instances = queryService.query("getAllProcessInstances", ProcessInstanceQueryMapper.get(), new QueryContext(),
     QueryParam.likeTo(COLUMN_PROCESSID, true, "org.jbpm%"),
     QueryParam.in(COLUMN_STATUS, 1, 3));

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.

Further examples can be found here.

7.4.7. 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 jBPM 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
public interface AdvanceRuntimeDataService {

    String TASK_ATTR_NAME = "TASK_NAME";
    String TASK_ATTR_OWNER = "TASK_OWNER";
    String TASK_ATTR_STATUS = "TASK_STATUS";
    String PROCESS_ATTR_INSTANCE_ID = "PROCESS_INSTANCE_ID";
    String PROCESS_ATTR_CORRELATION_KEY = "PROCESS_CORRELATION_KEY";
    String PROCESS_ATTR_DEFINITION_ID = "PROCESS_DEFINITION_ID";
    String PROCESS_ATTR_DEPLOYMENT_ID = "PROCESS_DEPLOYMENT_ID";

    List<ProcessInstanceWithVarsDesc> queryProcessByVariables(List<QueryParam> attributes,
      List<QueryParam> processVariables, QueryContext queryContext);

    List<ProcessInstanceWithVarsDesc> queryProcessByVariablesAndTask(List<QueryParam> attributes,
       List<QueryParam> processVariables, List<QueryParam> taskVariables,
       List<String> potentialOwners, QueryContext queryContext);

    List<UserTaskInstanceWithPotOwnerDesc> queryUserTasksByVariables(List<QueryParam> attributes,
       List<QueryParam> taskVariables, List<QueryParam> processVariables,
       List<String> potentialOwners, QueryContext queryContext);
}

7.4.8. 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.

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 to 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.

jBPM offers several implementations of the migration service:

Methods in the ProcessInstanceMigrationService interface that implement the migration service
public interface ProcessInstanceMigrationService {
 /**
 * Migrates a given process instance that belongs to the source deployment into the target process ID that belongs to the target deployment.
 * The following rules are enforced:
 * <ul>
 * <li>the source deployment ID must point to an existing deployment</li>
 * <li>the process instance ID must point to an existing and active process instance</li>
 * <li>the target deployment must exist</li>
 * <li>the target process ID must exist in the target deployment</li>
 * </ul>
 * Returns a migration report regardless of migration being successful or not; examine the report for the outcome of the migration.
 * @param sourceDeploymentId deployment to which the process instance to be migrated belongs
 * @param processInstanceId ID of the process instance to be migrated
 * @param targetDeploymentId ID of the deployment to which the target process belongs
 * @param targetProcessId ID of the process to which the process instance should be migrated
 * @return returns complete migration report
 */
 MigrationReport migrate(String sourceDeploymentId, Long processInstanceId, String targetDeploymentId, String targetProcessId);
 /**
 * Migrates a given process instance (with node mapping) that belongs to source deployment into the target process ID that belongs to the target deployment.
 * The following rules are enforced:
 * <ul>
 * <li>the source deployment ID must point to an existing deployment</li>
 * <li>the process instance ID must point to an existing and active process instance</li>
 * <li>the target deployment must exist</li>
 * <li>the target process ID must exist in the target deployment</li>
 * </ul>
 * Returns a migration report regardless of migration being successful or not; examine the report for the outcome of the migration.
 * @param sourceDeploymentId deployment to which the process instance to be migrated belongs
 * @param processInstanceId ID of the process instance to be migrated
 * @param targetDeploymentId ID of the deployment to which the target process belongs
 * @param targetProcessId ID of the process to which the process instance should be migrated
 * @param nodeMapping node mapping - source and target unique IDs of nodes to be mapped - from process instance active nodes to new process nodes
 * @return returns complete migration report
 */
 MigrationReport migrate(String sourceDeploymentId, Long processInstanceId, String targetDeploymentId, String targetProcessId, Map<String, String> nodeMapping);
 /**
 * Migrates given process instances that belong to the source deployment into a target process ID that belongs to the target deployment.
 * The following rules are enforced:
 * <ul>
 * <li>the source deployment ID must point to an existing deployment</li>
 * <li>the process instance ID must point to an existing and active process instance</li>
 * <li>the target deployment must exist</li>
 * <li>the target process ID must exist in the target deployment</li>
 * </ul>
 * Returns a migration report regardless of migration being successful or not; examine the report for the outcome of the migration.
 * @param sourceDeploymentId deployment to which the process instances to be migrated belong
 * @param processInstanceIds list of process instance IDs to be migrated
 * @param targetDeploymentId ID of the deployment to which the target process belongs
 * @param targetProcessId ID of the process to which the process instances should be migrated
 * @return returns complete migration report
 */
 List<MigrationReport> migrate(String sourceDeploymentId, List<Long> processInstanceIds, String targetDeploymentId, String targetProcessId);
 /**
 * Migrates given process instances (with node mapping) that belong to the source deployment into a target process ID that belongs to the target deployment.
 * The following rules are enforced:
 * <ul>
 * <li>the source deployment ID must point to an existing deployment</li>
 * <li>the process instance ID must point to an existing and active process instance</li>
 * <li>the target deployment must exist</li>
 * <li>the target process ID must exist in the target deployment</li>
 * </ul>
 * Returns a migration report regardless of migration being successful or not; examine the report for the outcome of the migration.
 * @param sourceDeploymentId deployment to which the process instances to be migrated belong
 * @param processInstanceIds list of process instance ID to be migrated
 * @param targetDeploymentId ID of the deployment to which the target process belongs
 * @param targetProcessId ID of the process to which the process instances should be migrated
 * @param nodeMapping node mapping - source and target unique IDs of nodes to be mapped - from process instance active nodes to new process nodes
 * @return returns list of migration reports one per each process instance
 */
 List<MigrationReport> migrate(String sourceDeploymentId, List<Long> processInstanceIds, String targetDeploymentId, String targetProcessId, Map<String, String> nodeMapping);
}

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
public interface ProcessAdminServicesClient {

    MigrationReportInstance migrateProcessInstance(String containerId, Long processInstanceId, String targetContainerId, String targetProcessId);

    MigrationReportInstance migrateProcessInstance(String containerId, Long processInstanceId, String targetContainerId, String targetProcessId, Map<String, String> nodeMapping);

    List<MigrationReportInstance> migrateProcessInstances(String containerId, List<Long> processInstancesId, String targetContainerId, String targetProcessId);

    List<MigrationReportInstance> migrateProcessInstances(String containerId, List<Long> processInstancesId, String targetContainerId, String targetProcessId, Map<String, String> nodeMapping);
}

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, or ERROR type. The ERROR message terminates the migration.

The following example shows a process instance migration:

Migrating a process instance in a KIE Server deployment
import org.kie.server.api.model.admin.MigrationReportInstance;
import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.client.KieServicesClient;
import org.kie.server.client.KieServicesConfiguration;

public class ProcessInstanceMigrationTest{

	private static final String SOURCE_CONTAINER = "com.redhat:MigrateMe:1.0";
  private static final String SOURCE_PROCESS_ID = "MigrateMe.MigrateMev1";
	private static final String TARGET_CONTAINER = "com.redhat:MigrateMe:2";
  private static final String TARGET_PROCESS_ID = "MigrateMe.MigrateMeV2";

	public static void main(String[] args) {

		KieServicesConfiguration config = KieServicesFactory.newRestConfiguration("http://HOST:PORT/kie-server/services/rest/server", "USERNAME", "PASSWORD");
		config.setMarshallingFormat(MarshallingFormat.JSON);
		KieServicesClient client = KieServicesFactory.newKieServicesClient(config);

		long sourcePid = client.getProcessClient().startProcess(SOURCE_CONTAINER, SOURCE_PROCESS_ID);

    // Use the 'report' object to return migration results.
		MigrationReportInstance report = client.getAdminClient().migrateProcessInstance(SOURCE_CONTAINER, sourcePid,TARGET_CONTAINER, TARGET_PROCESS_ID);

		System.out.println("Was migration successful:" + report.isSuccessful());

		client.getProcessClient().abortProcessInstance(TARGET_CONTAINER, sourcePid);

	}
}
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.

7.4.9. 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

If you use this deployment ID, the jBPM 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
KModuleDeploymentUnit deploymentUnitV1 = new KModuleDeploymentUnit("org.jbpm", "HR", "1.0");
deploymentService.deploy(deploymentUnitV1);

long processInstanceId = processService.startProcess("org.jbpm:HR:LATEST", "customtask");
ProcessInstanceDesc piDesc = runtimeDataService.getProcessInstanceById(processInstanceId);

// We have started a process with the project version 1
assertEquals(deploymentUnitV1.getIdentifier(), piDesc.getDeploymentId());

// Next we deploy version 2
KModuleDeploymentUnit deploymentUnitV2 = new KModuleDeploymentUnit("org.jbpm", "HR", "2.0");
deploymentService.deploy(deploymentUnitV2);

processInstanceId = processService.startProcess("org.jbpm:HR:LATEST", "customtask");
piDesc = runtimeDataService.getProcessInstanceById(processInstanceId);

// This time we have started a process with the project version 2
assertEquals(deploymentUnitV2.getIdentifier(), piDesc.getDeploymentId());

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.

7.4.10. Deployment synchronization

Prior to jBPM 6.2, jBPM services did not have a deployment store by default. When embedded in jbpm-console/kie-wb, they utilized the sistem.git VFS repository to preserve deployed units across server restarts. While that approach works, it causes some drawbacks:

  • It is not available for custom systems that use services

  • It requires a complex setup process in a cluster deployment, involving zookeeper and helix

Since version 6.2, jBPM services include a deployment synchronizer that stores available deployments into a database, including the deployment descriptor for every deployment.

The synhronizer 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
TransactionalCommandService commandService = new TransactionalCommandService(emf);

DeploymentStore store = new DeploymentStore();
store.setCommandService(commandService);

DeploymentSynchronizer sync = new DeploymentSynchronizer();
sync.setDeploymentService(deploymentService);
sync.setDeploymentStore(store);

DeploymentSyncInvoker invoker = new DeploymentSyncInvoker(sync, 2L, 3L, TimeUnit.SECONDS);
invoker.start();
....
invoker.stop();

With this configuration, deployments are synchronized every three seconds with an initial delay of two seconds.

7.5. Threads in the jBPM 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.

jBPM 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 jBPM engine executes actions in series. For example, when the jBPM 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 jBPM 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 jBPM 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 jBPM engine thread is blocked during thre sleep period.

When a process reaches a service task, the jBPM 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 jBPM engine later when the results are available. In the meantime, the jBPM 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 jBPM 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 jBPM engine is then able to continue execution on the rest of the process, if necessary. The handler notifies the jBPM engine asynchronously when the user has completed the task.

7.6. Event Listeners in the jBPM 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 jBPM 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
public interface ProcessEventListener {

  void beforeProcessStarted( ProcessStartedEvent event );
  void afterProcessStarted( ProcessStartedEvent event );
  void beforeProcessCompleted( ProcessCompletedEvent event );
  void afterProcessCompleted( ProcessCompletedEvent event );
  void beforeNodeTriggered( ProcessNodeTriggeredEvent event );
  void afterNodeTriggered( ProcessNodeTriggeredEvent event );
  void beforeNodeLeft( ProcessNodeLeftEvent event );
  void afterNodeLeft( ProcessNodeLeftEvent event );
  void beforeVariableChanged(ProcessVariableChangedEvent event);
  void afterVariableChanged(ProcessVariableChangedEvent event);

}

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
    void addEventListener(AgendaEventListener listener);
    void addEventListener(RuleRuntimeEventListener listener);
    void removeEventListener(AgendaEventListener listener);
    void removeEventListener(RuleRuntimeEventListener listener);
    Collection<AgendaEventListener>	getAgendaEventListeners();
    Collection<RuleRuntimeEventListener> getRuleRintimeEventListeners();

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.

7.6.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
  import org.kie.api.KieServices;
  import org.kie.api.logger.KieRuntimeLogger;
  ...
  KieRuntimeLogger logger = KieServices.Factory.get().getLoggers().newFileLogger(ksession, "test");
  // add invocations to the jBPM engine here,
  // e.g. ksession.startProcess(processId);
  ...
  logger.close();

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. You can use the Audit View in the Drools Eclipse plugin to open the file and visualize the events as a tree. Events that occur between the before and after calls of an event are shown as children of that event.

The following screenshot shows a simple example. A process is started, resulting in the activation of the Start node, an Action node, and an End node, after which the process is completed.

AuditView
Figure 11. Audit view of a jBPM engine runtime log

7.7. jBPM engine configuration

You can use several control parameters available to alter the jBPM 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.

Table 6. Control parameters
Name Possible values Default value Description

jbpm.ut.jndi.lookup

String

Alternative JNDI name to be used when there is no access to the default name (java:comp/UserTransaction).

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.

jbpm.enable.multi.con

true|false

false

Enable multiple incoming and outgoing sequence flows support for activities

jbpm.business.calendar.properties

String

/jbpm.business.calendar.properties

Alternative class path location of the business calendar configuration file

jbpm.overdue.timer.delay

Long

2000

Specifies the delay for overdue timers to allow proper initialization, in milliseconds

jbpm.process.name.comparator

String

Alternative comparator class to enable starting a process by name, by default the NumberVersionComparator comparator is used

jbpm.loop.level.disabled

true|false

true

Enable or disable loop iteration tracking for advanced loop support when using XOR gateways

org.kie.mail.session

String

mail/jbpmMailSession

Alternative JNDI name for the mail session used by Task Deadlines

jbpm.usergroup.callback.properties

String

/jbpm.usergroup.callback.properties

Alternative class path location for a user group callback implementation (LDAP, DB)

jbpm.user.group.mapping

String

${jboss.server.config.dir}/roles.properties

Alternative location of the roles.properties file for JBossUserGroupCallbackImpl

jbpm.user.info.properties

String

/jbpm.user.info.properties

Alternative class path location of the user info configuration (used by LDAPUserInfoImpl)

org.jbpm.ht.user.separator

String

,

Alternative separator of actors and groups for user tasks

org.quartz.properties

String

Location of the Quartz configiration file to activate the Quartz-based timer service

jbpm.data.dir

String

${jboss.server.data.dir} if available, otherwise ${java.io.tmpdir}

Location to store data files produced by the jBPM engine

org.kie.executor.pool.size

Integer

1

Thread pool size for the jBPM engine executor

org.kie.executor.retry.count

Integer

3

Number of retries attempted by the jBPM engine executor in case of an error

org.kie.executor.interval

Integer

0

Frequency used to check for pending jobs by the jBPM engine executor, in seconds. If the value is 0, the check is run once, during the startup of the executor.

org.kie.executor.disabled

true|false

true

Disable the jBPM engine executor

org.kie.store.services.class

String

org.drools.persistence.jpa.KnowledgeStoreServiceImpl

Fully qualified name of the class that implements KieStoreServices that is responsible for bootstrapping KieSession instances

org.kie.jbpm.notification_listeners.exclude

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 org.jbpm.services.task.deadlines.notifications.impl.email.EmailNotificationListener to exclude the default email notification listener.

org.kie.jbpm.notification_listeners.include

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.

8. Processes

8.1. What is BPMN 2.0

"The primary goal of BPMN is to provide a notation that is readily understandable by all business users, from the business analysts that create the initial drafts of the processes, to the technical developers responsible for implementing the technology that will perform those processes, and finally, to the business people who will manage and monitor those processes."

The Business Process Model and Notation (BPMN) 2.0 specification is an OMG specification that not only defines a standard on how to graphically represent a business process (like BPMN 1.x), but now also includes execution semantics for the elements defined, and an XML format on how to store (and share) process definitions.

jBPM6 allows you to execute processes defined using the BPMN 2.0 XML format. That means that you can use all the different jBPM6 tooling to model, execute, manage and monitor your business processes using the BPMN 2.0 format for specifying your executable business processes. Actually, the full BPMN 2.0 specification also includes details on how to represent things like choreographies and collaboration. The jBPM project however focuses on that part of the specification that can be used to specify executable processes.

Executable processes in BPMN consist of different types of nodes being connected to each other using sequence flows. The BPMN 2.0 specification defines three main types of nodes:

  • Events: They are used to model the occurrence of a particular event. This could be a start event (that is used to indicate the start of the process), end events (that define the end of the process, or of that subflow) and intermediate events (that indicate events that might occur during the execution of the process).

  • Activities: These define the different actions that need to be performed during the execution of the process. Different types of tasks exist, depending on the type of activity you are trying to model (e.g. human task, service task, etc.) and activities could also be nested (using different types of sub-processes).

  • Gateways: Can be used to define multiple paths in the process. Depending on the type of gateway, these might indicate parallel execution, choice, etc.

jBPM6 does not implement all elements and attributes as defined in the BPMN 2.0 specification. We do however support a significant subset, including the most common node types that can be used inside executable processes. This includes (almost) all elements and attributes as defined in the "Common Executable" subclass of the BPMN 2.0 specification, extended with some additional elements and attributes we believe are valuable in that context as well. The full set of elements and attributes that are supported can be found below, but it includes elements like:

  • Flow objects

    • Events

      • Start Event (None, Conditional, Signal, Message, Timer)

      • End Event (None, Terminate, Error, Escalation, Signal, Message, Compensation)

      • Intermediate Catch Event (Signal, Timer, Conditional, Message)

      • Intermediate Throw Event (None, Signal, Escalation, Message, Compensation)

      • Non-interrupting Boundary Event (Escalation, Signal, Timer, Conditional, Message)

      • Interrupting Boundary Event (Escalation, Error, Signal, Timer, Conditional, Message, Compensation)

    • Activities

      • Script Task

      • Task

      • Service Task

      • User Task

      • Business Rule Task

      • Manual Task

      • Send Task

      • Receive Task

      • Reusable Sub-Process (Call Activity)

      • Embedded Sub-Process

      • Event Sub-Process

      • Ad-Hoc Sub-Process

      • Data-Object

    • Gateways

      • Diverging

        • Exclusive

        • Inclusive

        • Parallel

        • Event-Based

      • Converging

        • Exclusive

        • Inclusive

        • Parallel

    • Lanes

  • Data

    • Java type language

    • Process properties

    • Embedded Sub-Process properties

    • Activity properties

  • Connecting objects

    • Sequence flow

For example, consider the following "Hello World" BPMN 2.0 process, which does nothing more than writing out a "Hello World" statement when the process is started.

HelloWorld

An executable version of this process expressed using BPMN 2.0 XML would look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<definitions id="Definition"
             targetNamespace="http://www.example.org/MinimalExample"
             typeLanguage="http://www.java.com/javaTypes"
             expressionLanguage="http://www.mvel.org/2.0"
             xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
             xs:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd"
             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.HelloWorld" name="Hello World" >

    <!-- nodes -->
    <startEvent id="_1" name="StartProcess" />
    <scriptTask id="_2" name="Hello" >
      <script>System.out.println("Hello World");</script>
    </scriptTask>
    <endEvent id="_3" name="EndProcess" >
        <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="Minimal" >
      <bpmndi:BPMNShape bpmnElement="_1" >
        <dc:Bounds x="15" y="91" width="48" height="48" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_2" >
        <dc:Bounds x="95" y="88" width="83" height="48" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_3" >
        <dc:Bounds x="258" y="86" width="48" height="48" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_1-_2" >
        <di:waypoint x="39" y="115" />
        <di:waypoint x="75" y="46" />
        <di:waypoint x="136" y="112" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_2-_3" >
        <di:waypoint x="136" y="112" />
        <di:waypoint x="240" y="240" />
        <di:waypoint x="282" y="110" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>

</definitions>

To create your own process using BPMN 2.0 format, you can

  • The jBPM Designer is an open-source web-based editor that supports the BPMN 2.0 format. We have embedded it into Business Central for BPMN 2.0 process visualization and editing. You could use the Designer (either standalone or integrated) to create / edit BPMN 2.0 processes and then export them to BPMN 2.0 format or save them into repository and import them so they can be executed.

  • A new BPMN2 Eclipse plugin is being created to support the full BPMN2 specification.

  • You can always manually create your BPMN 2.0 process files by writing the XML directly. You can validate the syntax of your processes against the BPMN 2.0 XSD, or use the validator in the Eclipse plugin to check both syntax and completeness of your model.

  • Drools Eclipse Process editor has been deprecated in favor of BPMN2 Modeler for process modeling. It can still be used for limited number of supported elements but should be faced out as it is not being developed any more.

    Create a new Process file using the Drools Eclipse plugin wizard and in the last page of the wizard, make sure you select Drools 5.1 code compatibility. This will create a new process using the BPMN 2.0 XML format. Note however that this is not exactly a BPMN 2.0 editor, as it still uses different attributes names etc. It does however save the process using valid BPMN 2.0 syntax. Also note that the editor does not support all node types and attributes that are already supported in the jBPM engine.

The following code fragment shows you how to load a BPMN2 process into your KIE base …​

private static KnowledgeBase createKnowledgeBase() throws Exception {
    KieHelper kieHelper = new KieHelper();
    KieBase kieBase = kieHelper
    .addResource(ResourceFactory.newClassPathResource("sample.bpmn2"))
    .build();

    return kieBase;
}

... and how to execute this process …​

KieBase kbase = createKnowledgeBase();
KieSession ksession = kbase.newKieSession();
ksession.startProcess("com.sample.HelloWorld");

For more detail, check out the chapter on the API and the basics.

8.2. Business processes

A business process is a diagram that describes the order for a series of steps that must be executed and consists of predefined nodes and connections. Each node represents one step in the process while the connections specify how to transition from one node to another.

A typical business process consists of the following components:

  • The header section that comprises global elements such as the name of the process, imports, and variables

  • The nodes section that contains all the different nodes that are part of the process

  • The connections section that links these nodes to each other to create a flow chart

This image shows the steps of "self evaluation" through the project manager and HR manager.
Figure 12. Business process

jBPM contains the legacy process designer and the new process designer for creating business process diagrams. The new process designer has an improved layout and feature set and continues to be developed. Until all features of the legacy process designer are completely implemented in the new process designer, both designers are available in Business Central for you to use.

8.2.1. Creating a business process in Business Central

The process designer is the jBPM process modeler. The output of the modeler is a BPMN 2.0 process definition file. The definition is used as input for the jBPM jBPM engine, which creates a process instance based on the definition.

The procedures in this section provide a general overview of how to create a simple business process.

Prerequisites
  • You have created or imported a jBPM project.

  • You have created the required users. User privileges and settings are controlled by the roles assigned to a user and the groups that a user belongs to.

Procedure
  1. In Business Central, go to MenuDesignProjects.

  2. Click the project name to open the project’s asset list.

  3. Click Add Asset → Business Process.

  4. In the Create new Business Process wizard, enter the following values:

    • Business Process: New business process name

    • Package: Package location for your new business process, for example com.myspace.myProject

  5. Click Ok to open the process designer.

  6. In the upper-right corner, click the Properties diagram properties icon and add your business process property information, such as process data and variables:

    1. Scroll down and expand Process Data.

    2. Click btn plus next to Process Variables and define the process variables that you want to use in your business process.

    Table 7. General process properties
    Label Description

    Name

    Enter the name of the process.

    Documentation

    Describes the process. The text in this field is included in the process documentation, if applicable.

    ID

    Enter an identifier for this process, such as orderItems.

    Package

    Enter the package location for this process in your jBPM project, such as org.acme.

    ProcessType

    Specify whether the process is public or private (or null, if not applicable).

    Version

    Enter the artifact version for the process.

    Ad hoc

    Select this option if this process is an ad hoc subprocess.

    Process Instance Description

    Enter a description of the purpose of the process.

    Imports

    Click to open the Imports window and add any data object classes required for your process.

    Executable

    Select this option to make the process executable part of your jBPM project.

    SLA Due Date

    Enter the service level agreement (SLA) expiration date.

    Process Variables

    Add any process variables for the process. Process variables are visible within the specific process instance. Process variables are initialized at process creation and destroyed on process completion. Variable Tags provide greater control over variable behavior, for example whether the variable is required or readonly. For more information about variable tags, see [variables-con_business-processes].

    Metadata Attributes

    Add any custom metadata attribute name and value that you want to use for custom event listeners, such as a listener to implement some action when a metadata attribute is present.

    Global Variables

    Add any global variables for the process. Global variables are visible to all process instances and assets in a project. Global variables are typically used by business rules and constraints, and are created dynamically by the rules or constraints.

    The Metadata Attributes entries are similar to Process Variables tags in that they enable new metaData extensions to BPMN diagrams. However, process variable tags modify the behavior of specific process variables, such as whether a certain variable is required or readonly, whereas metadata attributes are key-value definitions that modify the behavior of the overall process.

    For example, the following custom metadata attribute riskLevel and value low in a BPMN process correspond to a custom event listener for starting the process:

    Image of custom metadata attribute and value
    Figure 13. Example metadata attribute and value in the BPMN modeler
    Example metadata attribute and value in the BPMN file
    <bpmn2:process id="approvals" name="approvals" isExecutable="true" processType="Public">
      <bpmn2:extensionElements>
        <tns:metaData name="riskLevel">
          <tns:metaValue><![CDATA[low]]></tns:metaValue>
        </tns:metaData>
      </bpmn2:extensionElements>
    Example event listener with metadata value
    public class MyListener implements ProcessEventListener {
        ...
        @Override
        public void beforeProcessStarted(ProcessStartedEvent event) {
            Map < String, Object > metadata = event.getProcessInstance().getProcess().getMetaData();
            if (metadata.containsKey("low")) {
                // Implement some action for that metadata attribute
            }
        }
    }
  7. In the process designer canvas, use the left toolbar to drag and drop BPMN components to define your business process logic, connections, events, tasks, or other elements.

    A task and event in jBPM expect one incoming and one outgoing flow. If you want to design a business process with multiple incoming and multiple outgoing flows, then consider redesigning the business process using gateways. Using gateways makes the logic apparent, which a sequence flow is executing. Therefore, gateways are considered as a best practice for multiple connections.

    However, if it is a must to use multiple connections for a task or an event, then you must set the JVM (Java virtual machine) system property jbpm.enable.multi.con to true. When Business Central and KIE Server run on different servers, then ensure that both of them contains the jbpm.enable.multi.con system property as enabled otherwise, the jBPM engine throws an exception.

  8. After you add and define all components of the business process, click Save to save the completed business process.

8.2.1.1. Creating business rules tasks

Business rules tasks are used to make decisions through a Decision Model and Notation (DMN) model or rule flow group.

Procedure
  1. Create a business process.

  2. In the process designer, select the Activities tool from the tool palette.

  3. Select Business Rule.

  4. Click a blank area of the process designer canvas.

  5. If necessary, in the upper-right corner of the screen, click the Properties icon.

  6. Add or define the task information listed in the following table as required.

    Table 8. Business rule task parameters
    Label Description

    Name

    The name of the business rule task. You can also double-click the business rule task shape to edit the name.

    Rule Language

    The output language for the task. Select Decision Model and Notation (DMN) or Drools (DRL).

    Rule Flow Group

    The rule flow group associated with this business task. Select a rule flow group from the list or specify a new rule flow group.

    On Entry Action

    A Java, JavaScript, or MVEL script that specifies an action at the start of the task.

    On Exit Action

    A Java, JavaScript, or MVEL script that specifies an action at the end of the task.

    Is Async

    Select if this task should be invoked asynchronously. Make tasks asynchronous if they cannot be executed instantaneously, for example a task performed by an outside service.

    AdHoc Autostart

    Select if this is an ad hoc task that should be started automatically. AdHoc Autostart enables the task to automatically start when the process or case instance is created instead of being starting by a start task. It is often used in case management.

    SLA Due Date

    The date that the service level agreement (SLA) expires.

    Assignments

    Click to add local variables.

  7. Click Save.

8.2.1.2. Creating script tasks

Script tasks are used to execute a piece of code written in Java, JavaScript, or MVEL. They contain code snippets that specify the action of the script task. You can include global and process variables in your scripts.

Note that MVEL accepts any valid Java code and additionally provides support for nested access of parameters. For example, the MVEL equivalent of the Java call person.getName() is person.name. MVEL also provides other improvements over Java and MVEL expressions are generally more convenient for business users.

Procedure
  1. Create a business process.

  2. In the process designer, select the Activities tool from the tool palette.

  3. Select Script.

  4. Click a blank area of the process designer canvas.

  5. If necessary, in the upper-right corner of the screen, click the Properties icon.

  6. Add or define the task information listed in the following table as required.

    Table 9. Script task parameters
    Label Description

    Name

    The name of the script task. You can also double-click the script task shape to edit the name.

    Documentation

    Enter a description of the task. The text in this field is included in the process documentation. Click the Documentation tab in the upper-left side of the process designer canvas to view the process documentation.

    Script

    Enter a script in Java, JavaScript, or MVEL to be excuted by the task, and select the script type.

    Is Async

    Select if this task should be invoked asynchronously. Make tasks asynchronous if they cannot be executed instantaneously, for example a task performed by an outside service.

    AdHoc Autostart

    Select if this is an ad hoc task that should be started automatically. AdHoc Autostart enables the task to automatically start when the process or case instance is created instead of being starting by a start task. It is often used in case management.

  7. Click Save.

8.2.1.3. Creating service tasks

A service task is a task that executes an action based on a web service call or in a Java class method. Examples of service tasks include sending an email and logging a message when these tasks are performed by systems. You can define the parameters (input) and results (output) that are associated with a service task. A Service Task should have one incoming connection and one outgoing connection.

Procedure
  1. In Business Central, select the Admin icon in the top-right corner of the screen and select Artifacts.

  2. Click Upload to open the Artifact upload window.

  3. Choose the .jar file and click upload button.

    The .jar file contains data types (data objects) and Java classes for web service and Java service tasks respectively.

  4. Create a project you want to use.

  5. Go to your project Settings → Dependencies.

  6. Click Add from repository, locate the uploaded .jar file, and click Select.

  7. Open your project Settings → Work Item Handler.

  8. Enter the following values in the given fields:

    • Name - Service Task

    • Value - new org.jbpm.process.workitem.bpmn2.ServiceTaskHandler(ksession, classLoader)

  9. Save the project.

    Example of creating web service task

    The default implementation of a service task in the BPMN2 specification is a web service. The web service support is based on the Apache CXF dynamic client, which provides a dedicated service task handler that implements the WorkItemHandler interface:

    org.jbpm.process.workitem.bpmn2.ServiceTaskHandler

    To create a service task using web service, you must configure the web service:

    1. Create a business process.

    2. If necessary, in the upper-right corner of the screen, click the Properties icon.

    3. Click import property icon in the Imports property to open the Imports window.

    4. Click +Add next to the WSDL Imports to import the required WSDL (Web Services Description Language) values. For example:

    5. In the process designer, select the Activities tool from the tool palette.

    6. Select Service Task.

    7. Click a blank area of the process designer canvas.

    8. Add or define the task information listed in the following table as required.

      Table 10. Web service task parameters
      Label Description

      Name

      The name of the service task. You can also double-click the service task shape to edit the name.

      Documentation

      Enter a description of the task. The text in this field is included in the process documentation. Click the Documentation tab in the upper-left side of the process designer canvas to view the process documentation.

      Implementation

      Specify a web service.

      Interface

      The service used to implement the script, such as CountriesPortService.

      Operation

      The operation that is called by the interface, such as getCountry.

      Assignments

      Click to add local variables.

      AdHoc Autostart

      Select if this is an ad hoc task that should be started automatically. AdHoc Autostart enables the task to automatically start when the process or case instance is created instead of being starting by a start task. It is often used in case management.

      Is Async

      Select if this task should be invoked asynchronously. Make tasks asynchronous if they cannot be executed instantaneously, for example a task performed by an outside service.

      Is Multiple Instance

      Select if this task has multiple instances.

      MI Execution mode

      Select if the multiple instances execute in parallel or sequentially.

      MI Collection input

      Specify a variable that represents a collection of elements for which new instances are created, such as inputCountryNames.

      MI Data Input

      Specify the input data assignment that is transferred to a web service, such as Parameter.

      MI Collection output

      The array list in which values returned from the web service task is stored, such as outputCountries.

      MI Data Output

      Specify the output data assignment for the web service task, which stores the result of class execution on the server, such as Result.

      MI Completion Condition (mvel)

      Specify the MVEL expression that is evaluated on each completed instance to check if the specified multiple instance node can complete.

      On Entry Action

      A Java, JavaScript, or MVEL script that specifies an action at the start of the task.

      On Exit Action

      A Java, JavaScript, or MVEL script that specifies an action at the end of the task.

      SLA Due Date

      The date that the service level agreement (SLA) expires.

    Example of creating Java service task

    When you create a service task using Java method, then the method can only contain one parameter and returns a single value. To create a service task using a Java method, you must add the Java class to the dependencies of the project:

    1. Create a business process.

    2. In the process designer, select the Activities tool from the tool palette.

    3. Select Service Task.

    4. Click a blank area of the process designer canvas.

    5. If necessary, in the upper-right corner of the screen, click the Properties icon.

    6. Add or define the task information listed in the following table as required.

      Table 11. Java service task parameters
      Label Description

      Name

      The name of the service task. You can also double-click the service task shape to edit the name.

      Documentation

      Enter a description of the task. The text in this field is included in the process documentation. Click the Documentation tab in the upper-left side of the process designer canvas to view the process documentation.

      Implementation

      Specify the task is implemented in Java.

      Interface

      The class used to implement the script, such as org.xyz.HelloWorld.

      Operation

      The method that is called by the interface, such as sayHello.

      Assignments

      Click to add local variables.

      AdHoc Autostart

      Select if this is an ad hoc task that should be started automatically. AdHoc Autostart enables the task to automatically start when the process or case instance is created instead of being starting by a start task. It is often used in case management.

      Is Async

      Select if this task should be invoked asynchronously. Make tasks asynchronous if they cannot be executed instantaneously, for example a task performed by an outside service.

      Is Multiple Instance

      Select if this task has multiple instances.

      MI Execution mode

      Select if the multiple instances execute in parallel or sequentially.

      MI Collection input

      Specify a variable that represents a collection of elements for which new instances are created, such as InputCollection.

      MI Data Input

      Specify the input data assignment that is transferred to a Java class. For example, you can set the input data assignments as Parameter and ParameterType. ParameterType represents the type of Parameter and sends arguments to the execution of Java method.

      MI Collection output

      The array list in which values returned from the Java class is stored, such as OutputCollection.

      MI Data Output

      Specify the output data assignment for Java service task, which stores the result of class execution on the server, such as Result.

      MI Completion Condition (mvel)

      Specify the MVEL expression that is evaluated on each completed instance to check if the specified multiple instance node can complete. For example, OutputCollection.size() == 3 indicates more than three people are not addressed.

      On Entry Action

      A Java, JavaScript, or MVEL script that specifies an action at the start of the task.

      On Exit Action

      A Java, JavaScript, or MVEL script that specifies an action at the end of the task.

      SLA Due Date

      The date that the service level agreement (SLA) expires.

  10. Click Save.

8.2.1.4. Creating user tasks

User tasks are used to include human actions as input to the business process.

Procedure
  1. Create a business process.

  2. In the process designer, select the Activities tool from the tool palette.

  3. Select User.

  4. Either drag and drop a user task onto the process designer canvas or click a blank area of the canvas.

  5. If necessary, in the upper-right corner of the screen, click the Properties icon.

  6. Add or define the task information listed in the following table as required.

    Table 12. User task parameters
    Label Description

    Name

    The name of the user task. You can also double-click the user task shape to edit the name.

    Documentation

    Enter a description of the task. The text in this field is included in the process documentation. Click the Documentation tab in the upper-left side of the process designer canvas to view the process documentation.

    Task Name

    The name of the human task.

    Subject

    Enter a subject for the task.

    Actors

    The actors responsible for executing the human task. Click Add to add a row then select an actor from the list or click New to add a new actor.

    Groups

    The groups responsible for executing the human task. Click Add to add a row then select a group from the list or click New to add a new group.

    Assignments

    Local variables for this task. Click to open the Task Data I/O window then add data inputs and outputs as required.

    Reassignments

    Specify a different actor to complete this task.

    Notifications

    Click to specify notifications associated with the task.

    Is Async

    Select if this task should be invoked asynchronously. Make tasks asynchronous if they cannot be executed instantaneously, for example a task performed by an outside service.

    Skippable

    Select if this task is not mandatory.

    Priority

    Specify a priority for the task.

    Description

    Enter a description for the human task.

    Created By

    The user that created this task.

    AdHoc Autostart

    Select if this is an ad hoc task that should be started automatically. AdHoc Autostart enables the task to automatically start when the process or case instance is created instead of being starting by a start task. It is often used in case management.

    Multiple Instance

    Select if this task has multiple instances.

    On Entry Action

    A Java, JavaScript, or MVEL script that specifies an action at the start of the task.

    On Exit Action

    A Java, JavaScript, or MVEL script that specifies an action at the end of the task.

    Content

    The content of the script.

    SLA Due Date

    The date that the service level agreement (SLA) expires.

  7. Click Save.

8.2.1.5. Copying elements from one business process to another business process

You can copy individual elements from one business process to another business process in Business Central.

Procedure
  1. In the business process designer canvas, click and drag the cursor to select the elements that you want to copy.

  2. Click 3417 in the upper-right toolbar to copy your selection.

  3. Switch into the second business process where you want to add the copied elements.

  4. In the second business process, create any process variables that are used in the business process that you want to copy. The variable Name and Type parameters must be identical in order to preserve variable mapping.

  5. Click 3418 to paste your selection.

  6. Click Save to save the updated business process.

8.2.1.6. Making a copy of a business process

You can make a copy of a business process in Business Central and modify the copied process as needed.

Procedure
  1. In the business process designer, click Copy in the upper-right toolbar.

  2. In the Make a Copy window, enter a new name for the copied business process, select the target package, and optionally add a comment.

  3. Click Make a Copy.

  4. Modify the copied business process as needed and click Save to save the updated business process.

8.2.1.7. Resizing elements and using the zoom function to view business processes

You can resize individual elements in a business process and zoom in or out to modify the view of your business process.

Procedure
  1. In the business process designer, select the element and click the red dot in the lower-right corner of the element.

  2. Drag the red dot to resize the element.

    Resizing an element
    Figure 14. Resize an element
  3. To zoom in or out to view the entire diagram, click the plus or minus sign on the lower-right side of the canvas.

    Zooming to view the entire diagram
    Figure 15. Enlarge or shrink a business process

8.2.2. Deploying a business process in Business Central

After you design your business process in Business Central, you can build and deploy your project in Business Central to make the process available to KIE Server.

Prerequisites
  • KIE Server is deployed and connected to Business Central.

Procedure
  1. In Business Central, go to MenuDesignProjects.

  2. Click the project that you want to deploy.

  3. Click Deploy.

    You can also select the Build & Install option to build the project and publish the KJAR file to the configured Maven repository without deploying to a KIE Server. In a development environment, you can click Deploy to deploy the built KJAR file to a KIE Server without stopping any running instances (if applicable), or click Redeploy to deploy the built KJAR file and replace all instances. The next time you deploy or redeploy the built KJAR, the previous deployment unit (KIE container) is automatically updated in the same target KIE Server. In a production environment, the Redeploy option is disabled and you can click Deploy only to deploy the built KJAR file to a new deployment unit (KIE container) on a KIE Server.

    To configure the KIE Server environment mode, set the org.kie.server.mode system property to org.kie.server.mode=development or org.kie.server.mode=production. To configure the deployment behavior for a corresponding project in Business Central, go to project SettingsGeneral SettingsVersion and toggle the Development Mode option. By default, KIE Server and all new projects in Business Central are in development mode. You cannot deploy a project with Development Mode turned on or with a manually added SNAPSHOT version suffix to a KIE Server that is in production mode.

    To review project deployment details, click View deployment details in the deployment banner at the top of the screen or in the Deploy drop-down menu. This option directs you to the MenuDeployExecution Servers page.

8.2.3. Executing a business process in Business Central

After you build and deploy the project that contains your business process, you can execute the defined functionality for the business process.

As an example, this procedure uses the Mortgage_Process sample project in Business Central. In this scenario, you input data into a mortgage application form acting as the mortgage broker. The MortgageApprovalProcess business process runs and determines whether or not the applicant has offered an acceptable down payment based on the decision rules defined in the project. The business process either ends the rule testing or requests that the applicant increase the down payment to proceed. If the application passes the business rule testing, the bank approver reviews the application and either approves or denies the loan.

Prerequisites
  • KIE Server is deployed and connected to Business Central.

Procedure
  1. In Business Central, go to MenuProjects and select a space. The default space is MySpace.

  2. In the upper-right corner of the window, click the arrow next to Add Project and select Try Samples.

  3. Select the Mortgage_Process sample and click Ok.

  4. On the project page, select Mortgage_Process.

  5. On the Mortgage_Process page, click Build.

  6. After the project has built, click Deploy.

  7. Go to MenuManageProcess Definitions.

  8. Click anywhere in the MortgageApprovalProcess row to view the process details.

  9. Click the Diagram tab to view the business process diagram in the editor.

  10. Click New Process Instance to open the Application form and input the following values into the form fields:

    • Down Payment: 30000

    • Years of amortization: 10

    • Name: Ivo

    • Annual Income: 60000

    • SSN: 123456789

    • Age of property: 8

    • Address of property: Brno

    • Locale: Rural

    • Property Sale Price: 50000

  11. Click Submit to start a new process instance. After starting the process instance, the Instance Details view opens.

  12. Click the Diagram tab to view the process flow within the process diagram. The state of the process is highlighted as it moves through each task.

  13. Click MenuManageTasks.

    For this example, the user or users working on the corresponding tasks are members of the following groups:

    • approver: For the Qualify task

    • broker: For the Correct Data and Increase Down Payment tasks

    • manager: For the Final Approval task

  14. As the approver, review the Qualify task information, click Claim and then Start to start the task, and then select Is mortgage application in limit? and click Complete to complete the task flow.

  15. In the Tasks page, click anywhere in the Final Approval row to open the Final Approval task.

  16. Click Claim to claim responsibility for the task, and click Complete to finalize the loan approval process.

The Save and Release buttons are only used to either pause the approval process and save the instance if you are waiting on a field value, or to release the task for another user to modify.

8.2.4. Process definitions and process instances in Business Central

A process definition is a Business Process Model and Notation (BPMN) 2.0 file that serves as a container for a process and its BPMN diagram. The process definition shows all of the available information about the business process, such as any associated subprocesses or the number of users and groups that are participating in the selected definition.

A process definition also defines the import entry for imported processes that the process definition uses, and the relationship entries.

BPMN2 source of a process definition
<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>
      PROCESS
    </process>

    <bpmndi:BPMNDiagram>
     BPMN DIAGRAM DEFINITION
    </bpmndi:BPMNDiagram>

    </definitions>

After you have created, configured, and deployed your project that includes your business processes, you can view the list of all the process definitions in Business Central MenuManageProcess Definitions. You can refresh the list of deployed process definitions at any time by clicking the refresh button in the upper-right corner.

The process definition list shows all the available process definitions that are deployed into the platform. Click any of the process definitions listed to show the corresponding process definition details. This displays information about the process definition, such as if there is a sub-process associated with it, or how many users and groups exist in the process definition. The Diagram tab in the process definition details page contains the BPMN2-based diagram of the process definition.

Within each selected process definition, you can start a new process instance for the process definition by clicking the New Process Instance button in the upper-right corner. Process instances that you start from the available process definitions are listed in MenuManageProcess Instances.

You can also define the default pagination option for all users under the Manage drop-down menu (Process Definition, Process Instances, Tasks, Jobs, and Execution Errors) and in MenuTrackTask Inbox.

8.2.4.1. Process definitions in XML

You can create processes directly in XML format using the BPMN 2.0 specifications. The syntax of these XML processes is defined using the BPMN 2.0 XML Schema Definition.

A process XML file consists of the following core sections:

  • process: This is the top part of the process XML that contains the definition of the different nodes and their properties. The process XML file consists of exactly one <process> element. This element contains parameters related to the process (its type, name, ID, and package name), and consists of three subsections: a header section where process-level information such as variables, globals, imports, and lanes are defined, a nodes section that defines each of the nodes in the process, and a connections section that contains the connections between all the nodes in the process.

  • BPMNDiagram: This is the lower part of the process XML file that contains all graphical information, such as the location of the nodes. The nodes section contains a specific element for each node and defines the various parameters and any sub-elements for that node type.

The following process XML file fragment shows a simple process that contains a sequence of a start event, a script task that prints "Hello World" to the console, and an end event:

<?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"
  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>

8.2.5. Invoking a Decision Model and Notation (DMN) service in a business process

You can use Decision Model and Notation (DMN) to model a decision service graphically in a decision requirements diagram (DRD) in Business Central and then invoke that DMN service as part of a business process in Business Central. Business processes interact with DMN services by identifying the DMN service and mapping business data between DMN inputs and the business process properties.

As an illustration, this procedure uses an example TrainStation project that defines train routing logic. This example project contains the following data object and DMN components designed in Business Central for the routing decision logic:

Example Train object
public class Train {

     private String departureStation;

     private String destinationStation;

     private BigDecimal railNumber;

     // Getters and setters
}
dmn execution graph
Figure 16. Example Compute Rail DMN model
dmn execution expression
Figure 17. Example Rail DMN decision table
dmn execution data type
Figure 18. Example tTrain DMN data type

For more information about creating DMN models in Business Central, see Decision Model and Notation (DMN) in the Drools documentation.

Prerequisites
  • All required data objects and DMN model components are defined in the project.

Procedure
  1. In Business Central, go to MenuDesignProjects and click the project name.

  2. Select or create the business process asset in which you want to invoke the DMN service.

  3. In the process designer, use the left toolbar to drag and drop BPMN components as usual to define your overall business process logic, connections, events, tasks, or other elements.

  4. To incorporate a DMN service in the business process, add a Business Rule task from the left toolbar or from the start-node options and insert the task in the relevant location in the process flow.

    For this example, the following Accept Train business process incorporates the DMN service in the Route To Rail node:

    dmn execution business process
    Figure 19. Example Accept Train business process with a DMN service
  5. Select the business rule task node that you want to use for the DMN service, click Properties in the upper-right corner of the process designer, and under Implementation/Execution, define the following fields:

    • Rule Language: Select DMN.

    • Namespace: Enter the unique namespace from the DMN model file. Example: https://www.drools.org/kie-dmn

    • Decision Name: Enter the name of the DMN decision node that you want to invoke in the selected process node. Example: Rail

    • DMN Model Name: Enter the DMN model name. Example: Compute Rail

      When you explore the root node, ensure that the Namespace and DMN Model Name fields consist of the same value in BPMN as DMN diagram.
  6. Under Data AssignmentsAssignments, click the Edit icon and add the DMN input and output data to define the mapping between the DMN service and the process data.

    For the Route To Rail DMN service node in this example, you add an input assignment for Train that corresponds to the input node in the DMN model, and add an output assignment for Rail that corresponds to the decision node in the DMN model. The Data Type must match the type that you set for that node in the DMN model, and the Source and Target definition is the relevant variable or field for the specified object.

    dmn execution io mapping
    Figure 20. Example input and output mapping for the Route To Rail DMN service node
  7. Click Save to save the data input and output data.

  8. Define the remainder of your business process according to how you want the completed DMN service to be handled.

    For this example, the PropertiesImplementation/ExecutionOn Exit Action value is set to the following code to store the rail number after the Route To Rail DMN service is complete:

    Example code for On Exit Action
    train.setRailNumber(rail);

    If the rail number is not computed, the process reaches a No Appropriate Rail end error node that is defined with the following condition expression:

    dmn execution negative condition
    Figure 21. Example condition for No Appropriate Rail end error node

    If the rail number is computed, the process reaches an Accept Train script task that is defined with the following condition expression:

    dmn execution positive condition
    Figure 22. Example condition for Accept Train script task node

    The Accept Train script task also uses the following script in PropertiesImplementation/ExecutionScript to print a message about the train route and current rail:

    com.myspace.trainstation.Train t =
        (com.myspace.trainstation.Train) kcontext.getVariable("train");
    System.out.println("Train from: " + t.getDepartureStation() +
                       ", to: " + t.getDestinationStation() +
                       ",  is on rail: " + t.getRailNumber());
  9. After you define your business process with the incorporated DMN service, save your process in the process designer, deploy the project, and run the corresponding process definition to invoke the DMN service.

    For this example, when you deploy the TrainStation project and run the corresponding process definition, you open the process instance form for the Accept Train process definition and set the departure station and destination station fields to test the execution:

    dmn execution process instance form
    Figure 23. Example process instance form for the Accept Train process definition

    After the process is executed, a message appears in the server log with the train route that you specified:

    Example server log output for the Accept Train process
    Train from: Zagreb, to: Belgrade,  is on rail: 1

8.3. Activities

8.3.1. Script task

ScriptTask
Figure 24. Script task

Represents a script that should be executed in this process. A Script Task should have one incoming connection and one outgoing connection. The associated action specifies what should be executed, the dialect used for coding the action (i.e., Java, JavaScript or MVEL), and the actual action code. This code can access any variables and globals. There is also a predefined variable kcontext that references the ProcessContext object (which can, for example, be used to access the current ProcessInstance or NodeInstance, and to get and set variables, or get access to the ksession using kcontext.getKieRuntime()). When a Script Task is reached in the process, it will execute the action and then continue with the next node. It contains the following properties:

  • Id: The id of the node (which is unique within one node container).

  • Name: The display name of the node.

  • Action: The action script associated with this action node.

Note that you can write any valid Java code inside a script node. This basically allows you to do anything inside such a script node. There are some caveats however:

  • When trying to create a higher-level business process, that should also be understood by business users, it is probably wise to avoid low-level implementation details inside the process, including inside these script tasks. A Script Task could still be used to quickly manipulate variables etc. but other concepts like a Service Task could be used to model more complex behaviour in a higher-level manner.

  • Scripts should be immediate. They are using the jBPM engine thread to execute the script. Scripts that could take some time to execute should probably be modeled as an asynchronous Service Task.

  • You should try to avoid contacting external services through a script node. Not only does this usually violate the first two caveats, it is also interacting with external services without the knowledge of the jBPM engine, which can be problematic, especially when using persistence and transactions. In general, it is probably wiser to model communication with an external service using a service task.

  • Scripts should not throw exceptions. Runtime exceptions should be caught and for example managed inside the script or transformed into signals or errors that can then be handled inside the process.

8.3.2. Service task

ServiceTask
Figure 25. Service task

Represents an (abstract) unit of work that should be executed in this process. All work that is executed outside the jBPM engine should be represented (in a declarative way) using a Service Task. Different types of services are predefined, e.g., sending an email, logging a message, etc. Users can define domain-specific services or work items, using a unique name and by defining the parameters (input) and results (output) that are associated with this type of work. Check the chapter on domain-specific processes for a detailed explanation and illustrative examples of how to define and use work items in your processes. When a Service Task is reached in the process, the associated work is executed. A Service Task should have one incoming connection and one outgoing connection.

  • Id: The id of the node (which is unique within one node container).

  • Name: The display name of the node.

  • Parameter mapping: Allows copying the value of process variables to parameters of the work item. Upon creation of the work item, the values will be copied.

  • Result mapping: Allows copying the value of result parameters of the work item to a process variable. Each type of work can define result parameters that will (potentially) be returned after the work item has been completed. A result mapping can be used to copy the value of the given result parameter to the given variable in this process. For example, the "FileFinder" work item returns a list of files that match the given search criteria within the result parameter Files. This list of files can then be bound to a process variable for use within the process. Upon completion of the work item, the values will be copied.

  • On-entry and on-exit actions: Actions that are executed upon entry or exit of this node, respectively.

  • Additional parameters: Each type of work item can define additional parameters that are relevant for that type of work. For example, the "Email" work item defines additional parameters such as From, To, Subject and Body. The user can either provide values for these parameters directly, or define a parameter mapping that will copy the value of the given variable in this process to the given parameter; if both are specified, the mapping will have precedence. Parameters of type String can use #{expression} to embed a value in the string. The value will be retrieved when creating the work item, and the substitution expression will be replaced by the result of calling toString() on the variable. The expression could simply be the name of a variable (in which case it resolves to the value of the variable), but more advanced MVEL expressions are possible as well, e.g., \#{person.name.firstname}.

8.3.3. User task

UserTask
Figure 26. User task

Processes can also involve tasks that need to be executed by human actors. A User Task represents an atomic task to be executed by a human actor. It should have one incoming connection and one outgoing connection. User Tasks can be used in combination with Swimlanes to assign multiple human tasks to similar actors. Refer to the chapter on human tasks for more details. A User Task is actually nothing more than a specific type of service node (of type "Human Task"). A User Task contains the following properties:

  • Id: The id of the node (which is unique within one node container).

  • Name: The display name of the node.

  • TaskName: The name of the human task.

  • Priority: An integer indicating the priority of the human task.

  • Comment: A comment associated with the human task.

  • ActorId: The actor id that is responsible for executing the human task. A list of actor id’s can be specified using a comma (',') as separator.

  • GroupId: The group id that is responsible for executing the human task. A list of group id’s can be specified using a comma (',') as separator.

  • Skippable: Specifies whether the human task can be skipped, i.e., whether the actor may decide not to execute the task.

  • Content: The data associated with this task.

  • Swimlane: The swimlane this human task node is part of. Swimlanes make it easy to assign multiple human tasks to the same actor. See the human tasks chapter for more detail on how to use swimlanes.

  • On entry and on exit actions: Action scripts that are executed upon entry and exit of this node, respectively.

  • Parameter mapping: Allows copying the value of process variables to parameters of the human task. Upon creation of the human tasks, the values will be copied.

  • Result mapping: Allows copying the value of result parameters of the human task to a process variable. Upon completion of the human task, the values will be copied. A human task has a result variable "Result" that contains the data returned by the human actor. The variable "ActorId" contains the id of the actor that actually executed the task.

A user task should define the type of task that needs to be executed (using properties like TaskName, Comment, etc.) and who needs to perform it (using either actorId or groupId). Note that if there is data related to this specific process instance that the end user needs when performing the task, this data should be passed as the content of the task. The task for example does not have access to process variables. Check out the chapter on human tasks to get more detail on how to pass data between human tasks and the process instance.

8.3.4. Reusable sub-process

ReusableSubProcess
Figure 27. Reusable sub-process - Call activity

Represents the invocation of another process from within this process. A sub-process node should have one incoming connection and one outgoing connection. When a Reusable Sub-Process node is reached in the process, the jBPM engine will start the process with the given id. It contains the following properties:

  • Id: The id of the node (which is unique within one node container).

  • Name: The display name of the node.

  • ProcessId: The id of the process that should be executed.

  • Wait for completion (by default true): If this property is true, this sub-process node will only continue if the child process that was started has terminated its execution (completed or aborted); otherwise it will continue immediately after starting the subprocess (so it will not wait for its completion).

  • Independent (by default true): If this property is true, the child process is started as an independent process, which means that the child process will not be terminated if this parent process is completed (or this sub-process node is canceled for some other reason); otherwise the active sub-process will be canceled on termination of the parent process (or cancellation of the sub-process node). Note that you can only set independent to "false" only when "Wait for completion" is set to true.

  • On-entry and on-exit actions: Actions that are executed upon entry or exit of this node, respectively.

  • Parameter in/out mapping: A sub-process node can also define in- and out-mappings for variables. The variables given in the "in" mapping will be used as parameters (with the associated parameter name) when starting the process. The variables of the child process that are defined for the "out" mappings will be copied to the variables of this process when the child process has been completed. Note that you can use "out" mappings only when "Wait for completion" is set to true.

8.3.5. Business rule task

BusinessRuleTask
Figure 28. Business rule task

A Business Rule Task Represents a set of rules that need to be evaluated. The rules are evaluated when the node is reached. A Rule Task should have one incoming connection and one outgoing connection. Rules are defined in separate files using the Drools rule format. Rules can become part of a specific ruleflow group using the ruleflow-group attribute in the header of the rule.

When a Rule Task is reached in the process, the jBPM engine will start executing rules that are part of the corresponding ruleflow-group (if any). Execution will automatically continue to the next node if there are no more active rules in this ruleflow group. As a result, during the execution of a ruleflow group, new activations belonging to the currently active ruleflow group can be added to the Agenda due to changes made to the facts by the other rules. Note that the process will immediately continue with the next node if it encounters a ruleflow group where there are no active rules at that time.

If the ruleflow group was already active, the ruleflow group will remain active and execution will only continue if all active rules of the ruleflow group has been completed. It contains the following properties:

  • Id: The id of the node (which is unique within one node container).

  • Name: The display name of the node.

  • RuleFlowGroup: The name of the ruleflow group that represents the set of rules of this RuleFlowGroup node.

8.3.6. Embedded sub-process

EmbeddedSubProcess
Figure 29. Embedded sub-process

A Sub-Process is a node that can contain other nodes so that it acts as a node container. This allows not only the embedding of a part of the process within such a sub-process node, but also the definition of additional variables that are accessible for all nodes inside this container. A sub-process should have one incoming connection and one outgoing connection. It should also contain one start node that defines where to start (inside the Sub-Process) when you reach the sub-process. It should also contain one or more end events. Note that, if you use a terminating event node inside a sub-process, you are terminating just that sub-process. A sub-process ends when there are no more active nodes inside the sub-process. It contains the following properties:

  • Id: The id of the node (which is unique within one node container).

  • Name: The display name of the node.

  • Variables: Additional variables can be defined to store data during the execution of this node.

8.3.7. Multi-instance sub-process

MultipleInstances
Figure 30. Multi-instance sub-process

A Multiple Instance sub-process is a special kind of sub-process that allows you to execute the contained process segment multiple times, once for each element in a collection. A multiple instance sub-process should have one incoming connection and one outgoing connection. It waits until the embedded process fragment is completed for each of the elements in the given collection before continuing. It contains the following properties:

  • Id: The id of the node (which is unique within one node container).

  • Name: The display name of the node.

  • CollectionExpression: The name of a variable that represents the collection of elements that should be iterated over. The collection variable should be an array or of type java.util.Collection. If the collection expression evaluates to null or an empty collection, the multiple instances sub-process will be completed immediately and follow its outgoing connection.

  • VariableName: The name of the variable to contain the current element from the collection. This gives nodes within the composite node access to the selected element.

  • CollectionOutput: The name of a variable that represents a collection of elements that will gather all output of the multi instance sub process

  • OutputVariableName: The name of the variable to contain the current output from the multi instance activity

  • CompletionCondition: MVEL expression that will be evaluated on each instance completion to check if given multi instance activity can already be completed. In case it evaluates to true all other remaining instances within multi instance activity will be canceled.

8.4. BPMN2 events in process designer

An event is something that happens to a business process. BPMN2 supports three categories of events:

  • Start

  • End

  • Intermediate

A start event catches an event trigger, an end event throws an event trigger, and an intermediate event can both catch and throw event triggers.

The following business process diagram shows examples of events: events

In this example, the following events occurred:

  • The ATM Card Inserted signal start event is triggered when the signal is received.

  • The timeout intermediate event is an interrupting event based on a timer trigger. This means that the Wait for PIN subprocess is canceled when the timer event is triggered.

  • Depending on the inputs to the process, either end event associated with the Validate User Pin task or the end event associated with the Inform User of Timeout task ends the process.

8.4.1. Start events

Use start events to indicate the start of a business process. A start event cannot have an incoming sequence flow and must have only one outgoing sequence flow. You can use none start events in top-level processes, embedded subprocess, callable subprocesses, and event subprocesses.

All start events, with the exception of the none start event, are catch events. For example, a signal start event starts the process only when the referenced signal (event trigger) is received. You can configure start events in event subprocesses to be interrupting or non-interrupting. An interrupting start event for an event subprocess stops or interrupts the execution of the containing or parent process. A non-interrupting start event does not stop or interrupt the execution of the containing or parent process.

Table 13. Start events
Start event type Top-level Subprocesses

Interrupt

Non-interrupt

None

bpmn start node

Conditional

bpmn conditional start

bpmn conditional start

bpmn conditional non interrupt

Compensation

bpmn compensation start

bpmn compensation start

Error

bpmn error start

Escalation

bpmn escalation start

bpmn escalation start

bpmn escalation non interrupt

Message

bpmn message node

bpmn message node

bpmn message non interrupt

Signal

bpmn signal start

bpmn signal start

bpmn signal non interrupt

Timer

bpmn timer start

bpmn timer start

bpmn timer non interrupt

None

The none start event is a start event without a trigger condition. A process or a subprocess can contain at most one none start event, which is triggered on process or subprocess start by default, and the outgoing flow is taken immediately.

When you use a none start event in a subprocess, the execution of the process flow is transferred from the parent process into the subprocess and the none start event is triggered. This means that the token (the current location within the process flow) is passed from the parent process into the subprocess activity and the none start event of the subprocess generates a token of its own.

Conditional

The conditional start event is a start event with a Boolean condition definition. The execution is triggered when the condition is first evaluated to false and then to true. The process execution starts only if the condition is evaluated to true after the start event has been instantiated.

A process can contain multiple conditional start events.

Compensation

A compensation start event is used to start a compensation event subprocess when using a subprocess as the target activity of a compensation intermediate event.

Error

A process or subprocess can contain multiple error start events, which are triggered when an error object with a particular ErrorRef property is received. The error object can be produced by an error end event. It indicates an incorrect process ending. The process instance with the error start event starts execution after it has received the respective error object. The error start event is executed immediately upon receiving the error object and its outgoing flow is taken.

Escalation

The escalation start event is a start event that is triggered by an escalation with a particular escalation code. Processes can contain multiple escalation start events. The process instance with an escalation start event starts its execution when it receives the defined escalation object. The process is instantiated and the escalation start event is executed immediately and its outgoing flow is taken.

Message

A process or an event subprocess can contain multiple message start events, which are triggered by a particular message. The process instance with a message start event only starts its execution from this event after it has received the respective message. After the message is received, the process is instantiated and its message start event is executed immediately (its outgoing flow is taken).

Because a message can be consumed by an arbitrary number of processes and process elements, including no elements, one message can trigger multiple message start events and therefore instantiate multiple processes.

Signal

The signal start event is triggered by a signal with a particular signal code. A process can contain multiple signal start events. The signal start event only starts its execution within the process instance after the instance has received the respective signal. Then, the signal start event is executed and its outgoing flow is taken.

Timer

The timer start event is a start event with a timing mechanism. A process can contain multiple timer start events, which are triggered at the start of the process, after which the timing mechanism is applied.

When you use a timer start event in a subprocess, execution of the process flow is transferred from the parent process into the subprocess and the timer start event is triggered. The token is taken from the parent subprocess activity and the timer start event of the subprocess is triggered and waits for the timer to trigger. After the time defined by the timing definition has been reached, the outgoing flow is taken.

8.4.2. Intermediate events

Intermediate events drive the flow of a business process. Intermediate events are used to either catch or throw an event during the execution of the business process. These events are placed between the start and end events and can also be used on the boundary of an activity, like a subprocess or a human task, as a catch event. The boundary catch events can be configured as interrupting or non-interrupting. An interrupting boundary catch event cancels the bound activity whereas a non-interrupting event does not.

An intermediate event handles a particular situation that occurs during process execution. The situation is a trigger for an intermediate event. In a process, intermediate events with one outgoing flow can be placed on an activity boundary.

If the event occurs while the activity is being executed, the event triggers its execution to the outgoing flow. One activity may have multiple boundary intermediate events. Note that depending on the behavior you require from the activity with the boundary intermediate event, you can use either of the following intermediate event types:

  • Interrupting: The activity execution is interrupted and the execution of the intermediate event is triggered.

  • Non-interrupting: The intermediate event is triggered and the activity execution continues.

Table 14. Intermediate events
Intermediate event type Catching Boundary Throwing

Interrupt

Non-interrupt

Message

bpmn intermediate message

bpmn intermediate message

bpmn message noninterrupt

bpmn message throwing

Timer

bpmn intermediate timer

bpmn intermediate timer

bpmn timer noninterrupt

Error

bpmn intermediate error

Signal

bpmn intermediate signal

bpmn intermediate signal

bpmn signal noninterrupt

bpmn signal throwing

Conditional

bpmn intermediate conditional

bpmn intermediate conditional

bpmn conditional noninterrupt

Compensation

bpmn intermediate catch

bpmn intermediate catch

bpmn intermediate compensation throwing

Escalation

bpmn intermediate escalation

bpmn intermediate escalation

bpmn intermediate escalation non interrupting

bpmn intermediate escalation throwing

Link

bpmn intermediate link

bpmn intermediate link throwing

Message

A message intermediate event is an intermediate event that enables you to manage a message object. Use one of the following events:

  • A throwing message intermediate event produces a message object based on the defined properties.

  • A catching message intermediate event listens for a message object with the defined properties.

Timer

A timer intermediate event enables you to delay workflow execution or to trigger the workflow execution periodically. It represents a timer that can trigger one or multiple times after a specified period of time. When the timer intermediate event is triggered, the timer condition, which is the defined time, is checked and the outgoing flow is taken. When the timer intermediate event is placed in the process workflow, it has one incoming flow and one outgoing flow. Its execution starts when the incoming flow transfers to the event. When a timer intermediate event is placed on an activity boundary, the execution is triggered at the same time as the activity execution.

The timer is canceled if the timer element is canceled, for example by completing or aborting the enclosing process instance.

Conditional

A conditional intermediate event is an intermediate event with a boolean condition as its trigger. The event triggers further workflow execution when the condition evaluates to true and its outgoing flow is taken.

The event must define the Expression property. When a conditional intermediate event is placed in the process workflow, it has one incoming flow, one outgoing flow, and its execution starts when the incoming flow transfers to the event. When a conditional intermediate event is placed on an activity boundary, the execution is triggered at the same time as the activity execution. Note that if the event is non-interrupting, the event triggers continuously while the condition is true.

Signal

A signal intermediate event enables you to produce or consume a signal object. Use either of the following options:

  • A throwing signal intermediate event produces a signal object based on the defined properties.

  • A catching signal intermediate event listens for a signal object with the defined properties.

Error

An error intermediate event is an intermediate event that can be used only on an activity boundary. It enables the process to react to an error end event in the respective activity. The activity must not be atomic. When the activity finishes with an error end event that produces an error object with the respective ErrorCode property, the error intermediate event catches the error object and execution continues to its outgoing flow.

Compensation

A compensation intermediate event is a boundary event attached to an activity in a transaction subprocess. It can finish with a compensation end event or a cancel end event. The compensation intermediate event must be associated with a flow, which is connected to the compensation activity.

The activity associated with the boundary compensation intermediate event is executed if the transaction subprocess finishes with the compensation end event. The execution continues with the respective flow.

Escalation

An escalation intermediate event is an intermediate event that enables you to produce or consume an escalation object. Depending on the action the event element should perform, you need to use either of the following options:

  • A throwing escalation intermediate event produces an escalation object based on the defined properties.

  • A catching escalation intermediate event listens for an escalation object with the defined properties.

Use either of the following options:

  • A throwing link intermediate event produces a link object based on the defined properties.

  • A catching link intermediate event listens for a link object with the defined properties.

8.4.3. End events

End events are used to end a business process and may not have any outgoing sequence flows. There may be multiple end events in a business process. All end events, with the exception of the none and terminate end events, are throw events.

End events indicate the completion of a business process. An end event is a node that ends a particular workflow. It has one or more incoming sequence flows and no outgoing flow.

A process must contain at least one end event.

During run time, an end event finishes the process workflow. The end event can finish only the workflow that reached it, or all workflows in the process instance, depending on the end event type.

Table 15. End events
End event Icon

None

bpmn end node

Message

bpmn end message

Signal

bpmn end signal

Error

bpmn end error

Compensation

bpmn end compensation

Escalation

bpmn end escalation

Terminate

bpmn end terminate

None

The none end event specifies that no other special behavior is associated with the end of the process.

Message

When a flow enters a message end event, the flow finishes and the end event produces a message as defined in its properties.

Signal

A throwing signal end event is used to finish a process or subprocess flow. When the execution flow enters the element, the execution flow finishes and produces a signal identified by its SignalRef property.

Error

The throwing error end event finishes the incoming workflow, which means consumes the incoming token, and produces an error object. Any other running workflows in the process or subprocess remain uninfluenced.

Compensation

A compensation end event is used to finish a transaction subprocess and trigger the compensation defined by the compensation intermediate event attached to the boundary of the subprocess activities.

Escalation

The escalation end event finishes the incoming workflow, which means consumes the incoming token, and produces an escalation signal as defined in its properties, triggering the escalation process.

Terminate

The terminate end event finishes all execution flows in the specified process instance. Activities being executed are canceled. The subprocess instance terminates if it reaches a terminate end event.

8.5. Gateways

8.5.1. Diverging gateway

DivergingGateway
Figure 31. Diverging gateway

Allows you to create branches in your process. A Diverging Gateway should have one incoming connection and two or more outgoing connections. There are three types of gateway nodes currently supported:

  • AND or parallel means that the control flow will continue in all outgoing connections simultaneously.

  • XOR or exclusive means that exactly one of the outgoing connections will be chosen. The decision is made by evaluating the constraints that are linked to each of the outgoing connections. The constraint with the lowest priority number that evaluates to true is selected. Constraints can be specified using different dialects. Note that you should always make sure that at least one of the outgoing connections will evaluate to true at runtime (the jBPM engine will throw an exception at runtime if it cannot find at least one outgoing connection).

  • OR or inclusive means that all outgoing connections whose condition evaluates to true are selected. Conditions are similar to the exclusive gateway, except that no priorities are taken into account. Note that you should make sure that at least one of the outgoing connections will evaluate to true at runtime because the jBPM engine will throw an exception at runtime if it cannot determine an outgoing connection.

It contains the following properties:

  • Id: The id of the node (which is unique within one node container).

  • Name: The display name of the node.

  • Type: The type of the split node, i.e., AND, XOR or OR (see above).

  • Constraints: The constraints linked to each of the outgoing connections (in case of an exclusive or inclusive gateway).

8.5.2. Converging gateway

ConvergingGateway
Figure 32. Converging gateway

Allows you to synchronize multiple branches. A Converging Gateway should have two or more incoming connections and one outgoing connection. There are three types of splits currently supported:

  • AND or parallel means that is will wait until all incoming branches are completed before continuing.

  • XOR or exclusive means that it continues as soon as one of its incoming branches has been completed. If it is triggered from more than one incoming connection, it will trigger the next node for each of those triggers.

  • OR or inclusive means that it continues as soon as all direct active paths of its incoming branches has been completed. This is a complex merge behaviour that is described in BPMN2 specification but in most cases it means that OR join will wait for all active flows that started in OR split. Some advanced cases (including other gateways in between or repeatable timers) will be causing different "direct active path" calculation.

It contains the following properties:

  • Id: The id of the node (which is unique within one node container).

  • Name: The display name of the node.

  • Type: The type of the Join node, i.e. AND, OR or XOR.

8.6. BPMN2 swimlanes in process designer

Swimlanes are process elements that visually group tasks related to one group or user. You can use user tasks in combination with swimlanes to assign multiple user tasks to the same actor, due to Autoclaim property of the swimlanes. When a potential owner of a group claims the first task in a swimlane, then other tasks are directly assigned to the same owner. Therefore, the claim for other tasks is not needed by the remaining owners of the group. The Autoclaim property enables the auto-assignment of the tasks that are related to a swimlane.

If the remaining user tasks in a swimlane contain multiple predefined ActorIds, then the user tasks are not assigned automatically.

In the following example, an analyst lane consists of two user tasks: swimlane

The Group field in the Update Customer Details and Resolve Customer Issue tasks contain the value analyst. When the process is started, and the Update Customer Details task is claimed, started, or completed by an analyst, and the Resolve Customer Issue task is claimed and assigned to the user who completed the first task. However, if only the Update Customer Details task contains the analyst group assigned, and the second task contains no user or group assignments, and the process stops after the first task completes.

You can disable the Autoclaim property of the swimlanes. If the Autoclaim property is disabled, then the tasks related to a swimlane are not assigned automatically. By default, the value of Autoclaim property is set as true. If needed, you can also change the default value for the Autoclaim property from project settings in Business Central or using the deployment descriptor file.

To change the default value of Autoclaim property of swimlanes in Business Central:

  1. Go to project Settings.

  2. Open Deployment → Environment entries.

  3. Enter the following values in the given fields:

    • Name - Autoclaim

    • Value - "false”

If you want to set the environment entry in the XML deployment descriptor, add the following code to the kie-deployment-descriptor.xml file:

<environment-entries>
  ..
    <environment-entry>
        <resolver>mvel</resolver>
        <identifier>new String ("false")</identifier>
        <parameters/>
        <name>Autoclaim</name>
    </environment-entry>
  ..
</environment-entries>

8.7. BPMN2 artifacts in process designer

Artifacts are used to provide additional information about a process. An artifact is any object depicted in the BPMN2 diagram that is not part of the process workflow. Artifacts have no incoming or outgoing flow objects.The purpose of artifacts is to provide additional information required to understand the diagram. The artifacts table lists the artifacts supported in the legacy process designer.

Table 16. Artifacts
Artifact type Description

Group

Organizes tasks or processes that have significance in the overall process. Group artifacts are not supported in the new process designer.

Text annotation

Provides additional textual information for the BPMN2 diagram.

Data object

Displays the data flowing through a process in the BPMN2 diagram.

8.7.1. Creating data object

Data objects represent, for example, documents used in a process in physical and digital form. Data objects appear as a page with a folded top right corner. The following procedure is a generic overview of creating a data object.

In jBPM 7.44.0, limited support for data objects is provided that excludes support for data inputs, data outputs, and associations.

Procedure
  1. Create a business process.

  2. In the process designer, select the Artifacts → Data Object from the tool palette.

  3. Either drag and drop a data object onto the process designer canvas or click a blank area of the canvas.

  4. If necessary, in the upper-right corner of the screen, click the Properties icon.

  5. Add or define the data object information listed in the following table as required.

    Table 17. Data object parameters
    Label Description

    Name

    The name of the data object. You can also double-click the data object shape to edit the name.

    Type

    Select a type of the data object.

  6. Click Save.

8.8. Others

8.8.1. Variables

While the flow chart focuses on specifying the control flow of the process, it is usually also necessary to look at the process from a data perspective. Throughout the execution of a process, data can be retrieved, stored, passed on and used.

For storing runtime data, during the execution of the process, process variables can be used. A variable is defined by a name and a data type. This could be a basic data type, such as boolean, int, or String, or any kind of Object subclass (it must implement Serializable interface). Variables can be defined inside a variable scope. The top-level scope is the variable scope of the process itself. Subscopes can be defined using a Sub-Process. Variables that are defined in a subscope are only accessible for nodes within that scope.

Whenever a variable is accessed, the process will search for the appropriate variable scope that defines the variable. Nesting of variable scopes is allowed. A node will always search for a variable in its parent container. If the variable cannot be found, it will look in that one’s parent container, and so on, until the process instance itself is reached. If the variable cannot be found, a read access yields null, and a write access produces an error message, with the process continuing its execution.

Variables can be used in various ways:

  • Process-level variables can be set when starting a process by providing a map of parameters to the invocation of the startProcess method. These parameters will be set as variables on the process scope.

  • Script actions can access variables directly, simply by using the name of the variable as a local parameter in their script. For example, if the process defines a variable of type "org.jbpm.Person" in the process, a script in the process could access this directly:

    // call method on the process variable "person"
    person.setAge(10);

    Changing the value of a variable in a script can be done through the knowledge context:

    kcontext.setVariable(variableName, value);
  • Service tasks (and reusable sub-processes) can pass the value of process variables to the outside world (or another process instance) by mapping the variable to an outgoing parameter. For example, the parameter mapping of a service task could define that the value of the process variable x should be mapped to a task parameter y right before the service is being invoked. You can also inject the value of process variable into a hard-coded parameter String using \#{expression}. For example, the description of a human task could be defined as You need to contact person #{person.getName()} (where person is a process variable), which will replace this expression by the actual name of the person when the service needs to be invoked. Similarly results of a service (or reusable sub-process) can also be copied back to a variable using a result mapping.

  • Various other nodes can also access data. Event nodes for example can store the data associated to the event in a variable, etc. Check the properties of the different node types for more information.

  • Process variables can be accessed also from the Java code of your application. It is done by casting of ProcessInstance to WorkflowProcessInstance. See the following example:

    variable = ((WorkflowProcessInstance) processInstance).getVariable("variableName");

    To list all the process variables see the following code snippet:

    org.jbpm.process.instance.ProcessInstance processInstance = ...;
    VariableScopeInstance variableScope = (VariableScopeInstance) processInstance.getContextInstance(VariableScope.VARIABLE_SCOPE);
    Map<String, Object> variables = variableScope.getVariables();

    Note that when you use persistence then you have to use a command based approach to get all process variables:

    Map<String, Object> variables = ksession.execute(new GenericCommand<Map<String, Object>>() {
        public Map<String, Object> execute(Context context) {
            KieSession ksession = ((KnowledgeCommandContext) context).getStatefulKnowledgesession();
            org.jbpm.process.instance.ProcessInstance processInstance = (org.jbpm.process.instance.ProcessInstance) ksession.getProcessInstance(piId);
            VariableScopeInstance variableScope = (VariableScopeInstance) processInstance.getContextInstance(VariableScope.VARIABLE_SCOPE);
            Map<String, Object> variables = variableScope.getVariables();
            return variables;
        }
    });

Finally, processes (and rules) all have access to globals, i.e. globally defined variables and data in the KIE session. Globals are directly accessible in actions just like variables. Globals need to be defined as part of the process before they can be used. You can for example define globals by clicking the globals button when specifying an action script in the Eclipse action property editor. You can also set the value of a global from the outside using ksession.setGlobal(name, value) or from inside process scripts using kcontext.getKieRuntime().setGlobal(name,value);.

8.8.2. Scripts

Action scripts can be used in different ways:

  • Within a Script Task,

  • As entry or exit actions, with a number of nodes.

Actions have access to globals and the variables that are defined for the process and the predefined variable kcontext. This variable is of type ProcessContext and can be used for several tasks:

  • Getting the current node instance (if applicable). The node instance could be queried for data, such as its name and type. You can also cancel the current node instance.

    NodeInstance node = kcontext.getNodeInstance();
    String name = node.getNodeName();
  • Getting the current process instance. A process instance can be queried for data (name, id, processId, etc.), aborted or signaled an internal event.

    ProcessInstance proc = kcontext.getProcessInstance();
    proc.signalEvent( type, eventObject );
  • Getting or setting the value of variables.

  • Accessing the Knowledge Runtime allows you do things like starting a process, signaling (external) events, inserting data, etc.

jBPM supports multiple dialects, like Java, JavaScript and MVEL. Java actions should be valid Java code, same for JavaScript. MVEL actions can use the business scripting language MVEL to express the action. MVEL accepts any valid Java code but additionally provides support for nested accesses of parameters (e.g., person.name instead of person.getName()), and many other scripting improvements. Thus, MVEL expressions are more convenient for the business user. For example, an action that prints out the name of the person in the "requester" variable of the process would look like this:

// Java dialect
System.out.println( person.getName() );

// JavaScript dialect
print(person.name + '\n);

//  MVEL dialect
System.out.println( person.name );

8.8.3. Timers

Timers wait for a predefined amount of time, before triggering, once or repeatedly. They can be used to trigger certain logic after a certain period, or to repeat some action at regular intervals.

8.8.3.1. Configure timer with delay and period

A Timer node is set up with a delay and a period. The delay specifies the amount of time to wait after node activation before triggering the timer the first time. The period defines the time between subsequent trigger activations. A period of 0 results in a one-shot timer.

The (period and delay) expression should be of the form [d][#h][#m][#s][[ms]]. You can specify the amount of days, hours, minutes, seconds and milliseconds (which is the default if you don’t specify anything). For example, the expression "1h" will wait one hour before triggering the timer (again).

8.8.3.2. Configure timer with CRON like expression

Timer events can be configured with CRON like expression when timeCycle is used as timer event definition. Important is that the language attribute of timeCycle definition must be set to cron. With that such cycle of a timer is controlled in the same way as CRON jobs. CRON like expression is supported for:

  • start event timers

  • intermediate event timers

  • boundary event timers

Following is an example of a definition of a boundary timer with CRON like expression

<bpmn2:boundaryEvent id="1" name="Send Update Timer" attachedToRef="_77A94B54-8B7C-4F8A-84EE-C1D310A343A6" cancelActivity="false">
   <bpmn2:outgoing>2</bpmn2:outgoing>
   <bpmn2:timerEventDefinition id="_erIyiJZ7EeSDh8PHobjSSA">
     <bpmn2:timeCycle xsi:type="bpmn2:tFormalExpression" id="_erIyiZZ7EeSDh8PHobjSSA" language="cron">0/1 * * * * ?</bpmn2:timeCycle>
   </bpmn2:timerEventDefinition>
</bpmn2:boundaryEvent>

This timer will fire every second and will continue until activity this boundary event is attached to is active.

8.8.3.3. Configure timer ISO-8601 date format

since version 6 timers can be configured with valid ISO8601 date format that supports both one shot timers and repeatable timers. Timers can be defined as date and time representation, time duration or repeating intervals

  • Date - 2013-12-24T20:00:00.000+02:00 - fires exactly at Christmas Eve at 8PM

  • Duration - PT1S - fires once after 1 second

  • Repeatable intervals - R/PT1S - fires every second, no limit, alternatively R5/PT1S will fire 5 times every second

8.8.3.4. Configure timer with process variables

The timer service is responsible for making sure that timers get triggered at the appropriate times. Timers can also be canceled, meaning that the timer will no longer be triggered.

Timers can be used in two ways inside a process:

  • A Timer Event may be added to the process flow. Its activation starts the timer, and when it triggers, once or repeatedly, it activates the Timer node’s successor. Subsequently, the outgoing connection of a timer with a positive period is triggered multiple times. Canceling a Timer node also cancels the associated timer, after which no more triggers will occur.

  • Timers can be associated with a Sub-Process or tasks as a boundary event.

8.8.3.5. Update timer within running process instance

In some cases timer that has been already scheduled should be rescheduled to accommodate new requirements (prolong or shorten timer expiration time, change delay, period or repeat limit).

As this involves several low level steps, jBPM comes with a dedicated command to perform these operations as an atomic operation to make sure all is done within the same transaction.

org.jbpm.process.instance.command.UpdateTimerCommand

Following timer events are supported to be updated:

  • boundary timer event

  • intermediate timer event

Timers can be rescheduled by providing the following information to the UpdateTimerCommand

  • processInstanceId - mandatory

  • timer node name - mandatory

Next one of following three parameters set needs to be used:

  • delay

  • period and repeatLimit

  • delay, period and repeatLimit

Example on how to updated timer event:

// first start process instance and record its id
long id = kieSession.startProcess(BOUNDARY_PROCESS_NAME).getId();

//set timer delay to 3s
kieSession.execute(new UpdateTimerCommand(id, BOUNDARY_TIMER_ATTACHED_TO_NAME, 3));

Important is that the update command is executed via ksession executor to ensure it’s done in transaction (when persistence is used).

8.8.4. Constraints

A constraint is a boolean expression that is evaluated when an element containing a constraint is executed. You can use constraints in various parts of your process, such as in a diverging gateway.

jBPM supports two types of constraints, including:

  • Code constraints: Constraints that are defined in Java, Javascript, Drools, or MVEL. Code constraints can access the data in the working memory, including the global and process variables. The following code constraint examples contain person as a variable in a process:

    Example Java code constraint
    return person.getAge() > 20;
    Example MVEL code constraint
    return person.age > 20;
    Example Javascript code constraint
    person.age > 20
  • Rule constraints: Constraints that are defined in the form of DRL rule conditions. Rule constraints can access the data in the working memory, including global variables. However, rule constraints cannot access the variables directly in a process but using a process instance. To retrieve the reference of the parent process instance, use the processInstance variable of the type WorkflowProcessInstance.

    You can insert a process instance into the session and update it if necessary, for example, using Java code or an on-entry, on-exit, or explicit action in your process.

    The following example shows a rule constraint, searching for a person with the same name as the value of the name variable in the process.

    Example rule constraint with process variable assignment
    processInstance : WorkflowProcessInstance()
    Person( name == ( processInstance.getVariable("name") ) )
    # add more constraints here ...

8.9. BPMN process fluent API for Business Central processes

jBPM provides a BPMN process fluent API that enables you to create business processes using factories. You can also manually validate the business process that you created using process fluent API. The process fluent API is defined in the org.kie.api.fluent package.

Therefore, instead of using BPMN2 XML standard, you can use the process fluent API to create business processes in a few lines of code.

8.9.1. Example requests with the BPMN process fluent API

The following example includes BPMN process fluent API requests for basic interactions with a business process. For more examples, see the process fluent API source in GitHub.

Creating and interacting with Business Central business processes

The following example shows basic business process with a script task, an exception handler, and a variable:

Example request to create and interact with a Business Central business process
Process process =
                // Create process builder
                factory.processBuilder(processId)
                       // package and name
                       .packageName("org.jbpm")
                       .name("My process")
                       // start node
                       .startNode(1).name("Start").done()
                       // Add variable of type string
                       .variable(var("pepe", String.class))
                       // Add exception handler
                       .exceptionHandler(IllegalArgumentException.class, Dialect.JAVA, "System.out.println(\"Exception\");")
                       // script node in Java language that prints "action"
                       .actionNode(2).name("Action")
                       .action(Dialect.JAVA,
                               "System.out.println(\"Action\");").done()
                       // end node
                       .endNode(3).name("End").done()
                       // connections
                       .connection(1,
                                   2)
                       .connection(2,
                                   3)
                       .build();

In this example, a ProcessBuilderFactory reference is obtained and then, using processBuilder(String processId) method, a ProcessBuilder instance is created, which is associated with the given process Id. The ProcessBuilder instance enables you to build a definition of the created process using the fluent API.

A business process consists of three components:

  • Header: The header section contains global elements such as the name of the process, imports, and variables.

    In the previous example, the header contains the name and version of the process and the package name.

  • Nodes: The nodes section contains all the different nodes that are part of the process.

    In the previous example, nodes are added to the process by calling the startNode(), actionNode(), and endNode() methods. These methods return a specific NodeBuilder that allows you to set the properties of that node. After the code finishes configuring that specific node, the done() method returns the NodeContainerBuilder to add more nodes, if necessary.

  • Connections: The connections section links the nodes to create a flow chart.

    In the previous example, once you add all the nodes, you must connect them by creating connections between them. You can call the connection() method, which links the nodes.

Finally, you can call the build() method and obtain the generated process definition. The build() method also validates the process definition and throws an exception if the process definition is not valid.

8.9.2. Example requests to execute a business process

Once you create a valid process definition instance, you can execute it using a combination of public and internal KIE APIs. To execute a process, create a Resource, which is used to create a KieBase. Using the KieBase, you can create a KieSession to execute the process.

The following example uses ProcessBuilderFactory.toBytes process to create a ByteArrayResource resource.

Example request to execute a process
// Build resource from Process
KieResources resources = ServiceRegistry.getInstance().get(KieResources.class);
Resource res = resources
                        .newByteArrayResource(factory.toBytes(process))
                        ​.setSourcePath("/tmp/processFactory.bpmn2"); // source path or target path must be set to be added into kbase
​// Build kie base from this resource using KIE API
​KieServices ks = KieServices.Factory.get();
​KieRepository kr = ks.getRepository();
​KieFileSystem kfs = ks.newKieFileSystem();
​kfs.write(res);
​KieBuilder kb = ks.newKieBuilder(kfs);
​kb.buildAll(); // kieModule is automatically deployed to KieRepository if successfully built.
​KieContainer kContainer = ks.newKieContainer(kr.getDefaultReleaseId());
​KieBase kbase = kContainer.getKieBase();
​// Create kie session using KieBase
​KieSessionConfiguration conf = ...;
​Environment env = ....;
​KieSession ksession = kbase.newKieSession(conf,env);
​// execute process using same process Id that is used to obtain ProcessBuilder instance
​ksession.startProcess(processId)

8.10. Testing a business process

A business process can be updated dynamically, which can cause errors, therefore testing a process business is also a part of the business process life cycle similar to any other development artifact.

The unit test for a business process ensures that the process behaves as expected in a specific use case. For example, you can test an output based on a particular input. To simplify unit testing, jBPM includes the org.jbpm.test.JbpmJUnitBaseTestCase class.

The JbpmJUnitBaseTestCase performs as a base test case class, which is used for jBPM related tests. The JbpmJUnitBaseTestCase provides the following usage areas:

  • JUnit life cycle methods

    Table 18. JUnit life cycle methods
    Method Description

    setUp

    This method is annotated as @Before. It configures a data source and EntityManagerFactory and deletes the session ID of a singleton.

    tearDown

    This method is annotated as @After. It removes history, closes EntityManagerFactory and a data source, and disposes RuntimeManager and RuntimeEngines.

  • Knowledge base and knowledge session management methods: To create a session, create RuntimeManager and RuntimeEngine. Use the following methods to create and dispose RuntimeManager:

    Table 19. RuntimeManager and RuntimeEngine management methods
    Method Description

    createRuntimeManager

    Creates RuntimeManager for a given set of assets and selected strategy.

    disposeRuntimeManager

    Disposes RuntimeManager that is active in the scope of the test.

    getRuntimeEngine

    Creates new RuntimeEngine for the given context.

  • Assertions: To test the state of assets, use the following methods:

    Table 20. RuntimeManager and RuntimeEngine Management Methods
    Assertion Description

    assertProcessInstanceActive(long processInstanceId, KieSession ksession)

    Verifies whether a process instance with the given processInstanceId is active.

    assertProcessInstanceCompleted(long processInstanceId)

    Verifies whether a process instance with the given processInstanceId is completed. You can use this method if session persistence is enabled, otherwise use assertProcessInstanceNotActive(long processInstanceId, KieSession ksession).

    assertProcessInstanceAborted(long processInstanceId)

    Verifies whether a process instance with the given processInstanceId is aborted. You can use this method if session persistence is enabled, otherwise use assertProcessInstanceNotActive(long processInstanceId, KieSession ksession).

    assertNodeExists(ProcessInstance process, String…​ nodeNames)

    Verifies whether the specified process contains the given nodes.

    assertNodeActive(long processInstanceId, KieSession ksession, String…​ name)

    Verifies whether a process instance with the given processInstanceId contains at least one active node with the specified node names.

    assertNodeTriggered(long processInstanceId, String…​ nodeNames)

    Verifies whether a node instance is triggered for each given node during the execution of the specified process instance.

    assertProcessVarExists(ProcessInstance process, String…​ processVarNames)

    Verifies whether the given process contains the specified process variables.

    assertProcessNameEquals(ProcessInstance process, String name)

    Verifies whether the given name matches the specified process name.

    assertVersionEquals(ProcessInstance process, String version)

    Verifies whether the given process version matches the specified process version.

  • Helper methods: Use following methods to create a new RuntimeManager and RuntimeEngine for a given set of processes with or without using persistence. For more information about persistence, see jBPM engine in jBPM.

    Table 21. RuntimeManager and RuntimeEngine Management Methods
    Method Description

    setupPoolingDataSource

    Configures a data source.

    getDs

    Returns the configured data source.

    getEmf

    Returns the configured EntityManagerFactory.

    getTestWorkItemHandler

    Returns a test work item handler that can be registered in addition to the default work item handler.

    clearHistory

    Clears the history log.

The following example contains a start event, a script task, and an end event. The example JUnit test creates a new session, starts the hello.bpmn process, and verifies whether the process instance is completed and the StartProcess, Hello, and EndProcess nodes are executed.

Example JUnit Test Process
Figure 33. Example JUnit Test of hello.bpmn Process
public class ProcessPersistenceTest extends JbpmJUnitBaseTestCase {

    public ProcessPersistenceTest() {
        super(true, true);
    }

    @Test
    public void testProcess() {

        createRuntimeManager("hello.bpmn");

        RuntimeEngine runtimeEngine = getRuntimeEngine();

        KieSession ksession = runtimeEngine.getKieSession();

        ProcessInstance processInstance = ksession.startProcess("com.sample.bpmn.hello");

        assertProcessInstanceNotActive(processInstance.getId(), ksession);

        assertNodeTriggered(processInstance.getId(), "StartProcess", "Hello", "EndProcess");
    }
}

JbpmJUnitBaseTestCase supports all predefined RuntimeManager strategies as part of the unit testing. Therefore, it is enough to specify the strategy that is used when you create a RuntimeManager as part of a single test. The following example shows the use of the PerProcessInstance strategy in a task service to manage user tasks:

public class ProcessHumanTaskTest extends JbpmJUnitBaseTestCase {

    private static final Logger logger = LoggerFactory.getLogger(ProcessHumanTaskTest.class);

    public ProcessHumanTaskTest() {
        super(true, false);
    }

    @Test
    public void testProcessProcessInstanceStrategy() {
        RuntimeManager manager = createRuntimeManager(Strategy.PROCESS_INSTANCE, "manager", "humantask.bpmn");
        RuntimeEngine runtimeEngine = getRuntimeEngine(ProcessInstanceIdContext.get());
        KieSession ksession = runtimeEngine.getKieSession();
        TaskService taskService = runtimeEngine.getTaskService();

        int ksessionID = ksession.getId();
        ProcessInstance processInstance = ksession.startProcess("com.sample.bpmn.hello");

        assertProcessInstanceActive(processInstance.getId(), ksession);
        assertNodeTriggered(processInstance.getId(), "Start", "Task 1");

        manager.disposeRuntimeEngine(runtimeEngine);
        runtimeEngine = getRuntimeEngine(ProcessInstanceIdContext.get(processInstance.getId()));

        ksession = runtimeEngine.getKieSession();
        taskService = runtimeEngine.getTaskService();

        assertEquals(ksessionID, ksession.getId());

        // let John execute Task 1
        List<TaskSummary> list = taskService.getTasksAssignedAsPotentialOwner("john", "en-UK");
        TaskSummary task = list.get(0);
        logger.info("John is executing task {}", task.getName());
        taskService.start(task.getId(), "john");
        taskService.complete(task.getId(), "john", null);

        assertNodeTriggered(processInstance.getId(), "Task 2");

        // let Mary execute Task 2
        list = taskService.getTasksAssignedAsPotentialOwner("mary", "en-UK");
        task = list.get(0);
        logger.info("Mary is executing task {}", task.getName());
        taskService.start(task.getId(), "mary");
        taskService.complete(task.getId(), "mary", null);

        assertNodeTriggered(processInstance.getId(), "End");
        assertProcessInstanceNotActive(processInstance.getId(), ksession);
    }
}

8.10.1. Testing integration with external services

Business processes often include the invocation of external services. Unit testing of a business process enables you to register test handlers that verify whether the specific services are requested correctly, and also provide test responses for the requested services.

To test the interaction with external services, use the default TestWorkItemHandler handler. You can register the TestWorkItemHandler to collect all the work items of a particular type. Also, TestWorkItemHandler contains data related to a task. A work item represents one unit of work, such as sending a specific email or invoking a specific service. The TestWorkItemHandler verifies whether a specific work item is requested during an execution of a process, and the associated data is correct.

The following example shows how to verify an email task and whether an exception is raised if the email is not sent. The unit test uses a test handler that is executed when an email is requested and enables you to test the data related to the email, such as the sender and recipient. Once the abortWorkItem() method notifies the engine about the email delivery failure, the unit test verifies that the process handles such case by generating an error and logging the action. In this case, the process instance is eventually aborted.

Example email process for testing
Figure 34. Example email process
public void testProcess2() {

    createRuntimeManager("sample-process.bpmn");

    RuntimeEngine runtimeEngine = getRuntimeEngine();

    KieSession ksession = runtimeEngine.getKieSession();

    TestWorkItemHandler testHandler = getTestWorkItemHandler();

    ksession.getWorkItemManager().registerWorkItemHandler("Email", testHandler);

    ProcessInstance processInstance = ksession.startProcess("com.sample.bpmn.hello2");

    assertProcessInstanceActive(processInstance.getId(), ksession);
    assertNodeTriggered(processInstance.getId(), "StartProcess", "Email");

    WorkItem workItem = testHandler.getWorkItem();
    assertNotNull(workItem);
    assertEquals("Email", workItem.getName());
    assertEquals("me@mail.com", workItem.getParameter("From"));
    assertEquals("you@mail.com", workItem.getParameter("To"));

    ksession.getWorkItemManager().abortWorkItem(workItem.getId());
    assertProcessInstanceNotActive(processInstance.getId(), ksession);
    assertNodeTriggered(processInstance.getId(), "Gateway", "Failed", "Error");

}

9. Human Tasks

9.1. Introduction

An important aspect of business processes is human task management. While some of the work performed in a process can be executed automatically, some tasks need to be executed by human actors.

jBPM supports a special human task node inside processes for modeling this interaction with human users. This human task node allows process designers to define the properties related to the task that the human actor needs to execute, like for example the type of task, the actor(s), or the data associated with the task.

jBPM also includes a so-called human task service, a back-end service that manages the life cycle of these tasks at runtime. The jBPM implementation is based on the WS-HumanTask specification. Note however that this implementation is fully pluggable, meaning that users can integrate their own human task solution if necessary.

In order to have human actors participate in your processes, you first need to (1) include human task nodes inside your process to model the interaction with human actors, (2) integrate a task management component (like for example the WS-HumanTask based implementation provided by jBPM) and (3) have end users interact with a human task client to request their task list and claim and complete the tasks assigned to them. Each of these three elements will be discussed in more detail in the next sections.

9.2. Using User Tasks in our Processes

jBPM supports the use of human tasks inside processes using a special User Task node defined by the BPMN2 Specification(as shown in the figure above). A User Task node represents an atomic task that needs to be executed by a human actor.

user task

[Although jBPM has a special user task node for including human tasks inside a process, human tasks are considered the same as any other kind of external service that needs to be invoked and are therefore simply implemented as a domain-specific service. See the chapter on domain-specific processes to learn more about this.]

A User Task node contains the following core properties:

  • Actors: The actors that are responsible for executing the human task. A list of actor id’s can be specified using a comma (',') as separator.

  • Group: The group id that is responsible for executing the human task. A list of group id’s can be specified using a comma (',') as separator.

  • Name: The display name of the node.

  • TaskName: The name of the human task. This name is used to link the task to a Form. It also represents the internal name of the Task that can be used for other purposes.

  • DataInputSet: all the input variables that the task will receive to work on. Usually you will be interested in copying variables from the scope of the process to the scope of the task. (Look at the data mappings section for an example)

  • DataOutputSet: all the output variables that will be generated by the execution of the task. Here you specify all the names of the variables in the context of the task that you are interested to copy to the context of the process. (Look at the data mappings section for an example)

  • Assignments: here you specify which process variable will be linked to each Data Input and Data Output mapping. (Look at the data mappings section for an example)

You can edit these variables in the properties view (see below) when selecting the User Task node.

properties panel

A User Task node also contains the following extra properties:

  • Comment: A comment associated with the human task. Here you can use expressions.

  • Content: The data associated with this task.

  • Priority: An integer indicating the priority of the human task.

  • Skippable: Specifies whether the human task can be skipped, i.e., whether the actor may decide not to execute the task.

  • On entry and on exit actions: Action scripts that are executed upon entry and exit of this node, respectively.

properties panel extra

9.2.1. Swimlanes

User tasks can be used in combination with swimlanes to assign multiple human tasks to the same actor. Whenever the first task in a swimlane is created, and that task has an actorId specified, that actorId will be assigned to (all other tasks of) that swimlane as well. Note that this would override the actorId of subsequent tasks in that swimlane (if specified), so only the actorId of the first human task in a swimlane will be taken into account, all others will then take the actorId as assigned in the first one.

ActorId assignment will work only when there is a single actor specified. Since ActorId field can contain multiple actors (john,mary,peter) auto assignment for the first task will not be performed when multiple values are found.

Whenever a human task that is part of a swimlane is completed, the actorId of that swimlane is set to the actorId that executed that human task. This allows for example to assign a human task to a group of users, and to assign future tasks of that swimlane to the user that claimed the first task. This will also automatically change the assignment of tasks if at some point one of the tasks is reassigned to another user.

Also exists the possibility to disable the autoclaim functionality of the swimlanes. In such case, the swimlane works like a visual element to group tasks in the process diagram, but the task which belong to any swimlane won’t be assigned automatically. The Autoclaim functionality is set to true by default. If you require the property Autoclaim set to false by default, set the following runtime environment entry in your deployment descriptor on a global or a project level:

  • Name: Autoclaim

  • Value: "false"

For example, if you want to set the entry in the XML deployment descriptor on the project level, add the following to the kie-deployment-descriptor.xml file:

<environment-entries>
  ..
    <environment-entry>
        <resolver>mvel</resolver>
        <identifier>new String ("false")</identifier>
        <parameters/>
        <name>Autoclaim</name>
    </environment-entry>
  ..
</environment-entries>

If you are setting the runtime environment property using the API, note that the value is a String, not a Boolean type.

For more information about deployment descriptors, see Deployment descriptors.

9.3. Task escalations and notifications

There are a number of situations that can raise the need for task escalation. For example, if a user is assigned to a task, but is unavailable, the task should be automatically reassigned to another user or group. Escalation can be defined for tasks that are in one of the following states:

  • not started (READY or RESERVED)

  • not completed (IN_PROGRESS)

Whenever an escalation is reached its associated users/groups will be assigned to the task as potential owners, replacing those that were previously set. In case the task had an actual owner assigned, it will be reset and the task will be placed in READY state.

9.3.1. Designing a task escalation

You must set the following attribute values when designing a task escalation in the BPMN2 editor:

editor reassignment
  • Users: Comma-separated list of user IDs that must be assigned to the task during escalation. Acceptable values are strings and expressions, such as #{user-id}.

  • Groups: Comma-separated list of group IDs that must be assigned to the task during escalation. Acceptable values are strings and expressions such as #{group-id}.

  • Expires At: Time or duration definition stating when the escalation should start. For a detailed description, see the Time and Duration definitions section.

  • Type: Identifies the type of task state that the escalation should start. For example, not-started or not-completed.

9.3.2. Email notifications

In addition to defining task escalation values, email notifications can be defined and sent for tasks that are in one of the following states:

  • not started (READY or RESERVED)

  • not completed (IN_PROGRESS)

9.3.3. Designing email notifications

The following attributes must be set when designing an email notification in the BPMN2 editor:

editor notification
  • Type: Identifies the type of task state that the escalation should start. For example, not-started or not-completed.

  • Task expiration definition: This definition states about the time or duration of escalation. For more information, see the Time and Duration definitions section.

  • From: (Optional) user or group ID. Acceptable values are strings and expressions.

  • To Users: Comma-separated list of user IDs that are the recipients of the notification.

  • To Groups: Comma-separated list of group IDs that are recipients of the notification.

  • Reply To: (Optional) user or group ID that will receive replies from the notification.

  • Subject: Subject of the notification. Acceptable values are strings and expressions.

  • Body: Body of the notification. Acceptable values are strings and expressions.

A Notification can reference process variables using the #{processVariable} expression and task variables using the ${taskVariable} expression. The process variables are resolved during task creation time and task variables are resolved at notification time. The following additional task variables can be defined for notifications:

  • taskId: Internal ID of a task instance

  • processInstanceId: Internal ID of a process instance that the task belongs to

  • workItemId: Internal ID of a work item that created this task

  • owners: List of users and groups that are potential owners of the task

  • doc: Map that contains regular task variables

The following illustration contains the body of a simple notification message and shows how the different variables can be accessed:

<html>
	<body>
		<b>${owners[0].id} you have been assigned to a task (task-id ${taskId})</b><br>
		You can access it in your task
		<a href="http://localhost:8080/business-central/app.html#errai_ToolSet_Tasks;Group_Tasks.3">inbox</a><br/>
		Important technical information that can be of use when working on it<br/>
		- process instance id - ${processInstanceId}<br/>
		- work item id - ${workItemId}<br/>

		<hr/>

		Here are some task variables available
		<ul>
			<li>ActorId = ${doc['ActorId']}</li>
			<li>GroupId = ${doc['GroupId']}</li>
			<li>Comment = ${doc['Comment']}</li>
		</ul>
		<hr/>
		Here are all potential owners for this task
		<ul>
		$foreach{orgEntity : owners}
			<li>Potential owner = ${orgEntity.id}</li>
		$end{}
		</ul>

		<i>Regards from jBPM team</i>
	</body>
</html>

9.3.4. Time and Duration definitions

With the ISO 8601 format addition, duration definition such as "2s" or "4h" became single time executions. In order to define repeatable executions you must now use the ISO 8601 repeatable format (see Repeatable execution below.)

Use the Task expiration definition attribute for both task escalations and notifications to define when the escalation or notification will occur. The Task expiration definition attribute can be set in several ways: as Time period, as Date/time and as Expression.

9.3.4.1. Time period

In default mode the Time period widget will generate One time execution (see One time execution below.), if needed, the Notification repeat switch allows to set Repeatable execution of two types: until Task state changes (like R/P1Y ) and until Repeat count reaches (like R4/P1Y) (see Repeatable execution below.)

9.3.4.2. Date/time

Notify after task expiration can be set by choosing the date and time in dateTime picker and by choosing the timezone. If needed, time zone can be switched from timezone offset to time zone naming and back. It is possible to set Notification repeat by switching on Notification repeat like it works for Time period and it is also possible to set how often notify will fire.

9.3.4.3. Expression

In other cases it is possible to set Task expiration as a string value or an expression. For example, #{expiresAt}. The following options are available to define your escalation or notification definitions:

9.3.4.4. One time execution

Can be defined with both time format, for example:

  • 2m - in two minutes

  • 4h - in four hours

  • 6d - in 6 days

or with ISO 8601 date and time format, for example:

  • PT2M - in two minutes

  • PT4H - in four hours

  • P6D - in six days

9.3.4.5. Repeatable execution

When using the ISO 8601 format, you can define the rescheduling of your task escalation or notification using one of the following options that follow the ISO 8601 repeating intervals specification:

  • R/duration - First triggers at current time, plus duration and repeats at each duration time interval. For example, "R5/PT4H" triggers four hours from now and repeats five times in four hour intervals. "R/PT2S" is an unbounded interval and triggers every two seconds until the task is no longer in the not-started or not-completed states.

  • R/startDate/duration - First triggers at the startDate with the repeat period using the set duration. For example "R2/2019-01-01T13:00:00Z/PT6H" is a trigger that first fires on January 1st 2019 at 1pm and re-fires two times six and twelve hours from the first fire.

  • R/duration/endDate - First triggers at endDate - duration with the repeat period using the set duration. For example "R2/PT6H/2019-01-01T13:00:00Z" is a trigger that first fires on January 1st 2019 at 7am and re-fires two times six and twelve hours from the first fire.

  • R/startDate/endDate - First triggers at the startDate and the duration set at endDate - startDate. For example: "R2/2019-01-01T13:00:00Z/2019-01-01T16:00:00Z" is a trigger that fires on January 1st 2019 at 1pm and re-fires two times three and six hours from the first fire.

You can use one unbounded or multiple bounded (non-ISO8601) definitions for each escalation or notification type (such as not-completed or not-started). You cannot mix unbounded and bounded notifications and escalations. For example, you cannot use R2/PT1S for a not-completed notification and R/PT2S for a not-completed escalation because both are of the not-completed type. However, you can use R2/PT1S for a not-started escalation and R/PT2S for a not-completed escalation. Whether a definition is an escalation or a notification is irrelevant, but the type distinction is important.

9.4. Data Mappings

Human tasks typically present some data related to the task that needs to be performed to the actor that is executing the task and usually also request the actor to provide some result data related to the execution of the task. Task forms are typically used to present this data to the actor and request results.

The data that will be used by the Task needs to be specified when we define the User Task in our Process. In order to do that we need to define which data will be copied from the process context to the task context. Notice that the data is copied, so it can be modified inside the Task context but it will not affect the process variables unless we decide to copy back the value from the task to the process context.

Most of the times Forms are used to display data to the end user. Allowing them to generate/create new data that will be propagated to the process context to be used by future activities. In order to decide how the information flow from the process to a particular task and from the task to the process we need to define which pieces of information will be automatically copied by the jBPM engine. The following section shows how to do these mappings by configuring the DataInputSet, DataOutputSet and the Assignments properties of a User Task.

Let’s start defining the Task DataInputSet:

data input

Both GroupId and Comment are automatically generated, so you don’t need to worry about that. In this case the only user defined Data Input is called: in_name. This means that the task will be receiving information from the process context and internally this variable will be called in_name. The type is also specified here.

In the Data Outputs represent the data that will be generated by the tasks. In this case we have two variables of type String called: out_name and out_mail and two Integer variables called: out_age and out_score are defined. This means that inside the task context we will need to set the value to these variables.

data output

Finally all the connections with the process context needs to be done in the Data Assignments. The main idea here is to define how Data Inputs and Data Outputs will be associated with process variables.

data assignments

As shown in the previous screenshot, the assignments between the process variables (in this case (name, age, mail and hr_score)) and the Data Inputs and Outputs are done in the Data Assignments screen. Notice that the example uses a convention that makes it easy to know which is an internal Task variables (Data Input/Output) using the "in_" and "out_" prefix to the variable names. Using this convention you can quickly understand the Assignments screen. The first row maps the process variable called name to the data input called in_name. The second row maps the data output called out_mail to the process variable called mail, and so on.

These mappings at runtime will automatically copy the variables content from one context (process and task) to the other automatically for us.

9.5. Task Lifecycle

From the perspective of a process, when a user task node is encountered during the execution, a human task is created. The process will then only leave the user task node when the associated human task has been completed or aborted.

The human task itself usually has a complete life cycle itself as well. For details beyond what is described below, please check out the WS-HumanTask specification. The following diagram is from the WS-HumanTask specification and describes the human task life cycle.

WSHT lifecycle

A newly created task starts in the "Created" stage. Usually, it will then automatically become "Ready", after which the task will show up on the task list of all the actors that are allowed to execute the task. The task will stay "Ready" until one of these actors claims the task, indicating that he or she will be executing it.

When a user then eventually claims the task, the status will change to "Reserved". Note that a task that only has one potential (specific) actor will automatically be assigned to that actor upon creation of the task. When the user who has claimed the task starts executing it, the task status will change from "Reserved" to "InProgress".

Lastly, once the user has performed and completed the task, the task status will change to "Completed". In this step, the user can optionally specify the result data related to the task. If the task could not be completed, the user could also indicate this by using a fault response, possibly including fault data, in which case the status would change to "Failed".

While the life cycle explained above is the normal life cycle, the specification also describes a number of other life cycle methods, including:

  • Delegating or forwarding a task, so that the task is assigned to another actor

  • Revoking a task, so that it is no longer claimed by one specific actor but is (re)available to all actors allowed to take it

  • Temporarily suspending and resuming a task

  • Stopping a task in progress

  • Skipping a task (if the task has been marked as skippable), in which case the task will not be executed

9.6. Task Permissions

Only users associated with a specific task are allowed to modify or retrieve information about the task. This allows users to create a jBPM workflow with multiple tasks and yet still be assured of both the confidentiality and integrity of the task status and information associated with a task.

Some task operations will end up throwing a org.jbpm.services.task.exception.PermissionDeniedException when used with information about an unauthorized user. For example, when a user is trying to directly modify the task (for example, by trying to claim or complete the task), the PermissionDeniedException will be thrown if that user does not have the correct role for that operation. Furthermore, a user will not be able to view or retrieve tasks that the user is not involved with, especially if this is via the Business Central application.

User 'Administrator' and group 'Administrators' are automatically added to each Human Task.

9.6.1. Task Permissions Matrix

The permissions matrix below summarizes the actions that specific user roles are allowed to do. On the left side, possible operations are listed while user roles are listed across the top of the matrix.

The cells of the permissions matrix contain one of three possible characters, each of which indicate the user role permissions for that operation:

  • a "+ indicates that the user role CAN do the specified operation

  • a “-” indicates that the user role MAY NOT do the specified operation

  • a “0” indicates that the user role MAY NOT do the specified operation, and that it is also not an operation that matches the user’s role ("not applicable")

Furthermore, the following words or abbreviations in the table header refer to the following roles:

Table 22. Task roles in the permissions table
Word Role Description

Initiator

Task Initiator

The user who creates the task instance

Stakeholder

Task Stakeholder

The user involved in the task: this user can influence the progress of a task, by performing administrative actions on the task instance

Potential

Potential Owner

The user who can claim the task before it has been claimed, or after it has been released or forward: only tasks that have the status "Ready" may be claimed; a potential owner becomes the actual owner of a task by claiming the task

Actual

Actual Owner

The user who has claimed the task and will progress the task to completion or failure

Administrator

Business Administrator

A "super user" who may modify the status or progress of a task at any point in a task’s lifecycle

User roles are assigned to users by the definition of the task in the jBPM (BPMN2) process definition.

Permissions Matrices

The following matrix describes the authorizations for all operations which modify a task:

Table 23. Main operations permissions matrix
Operation Role Initiator Stakeholder Potential Actual Administrator

activate

+

+

0

0

+

claim

-

+

+

0

+

complete

-

+

0

+

+

delegate

+

+

+

+

+

fail

-

+

0

+

+

forward

+

+

+

+

+

nominate

+

+

+

+

+

release

+

+

+

+

+

remove

-

0

0

0

+

resume

+

+

+

+

+

skip

+

+

+

+

+

start

-

+

+

+

+

stop

-

+

0

+

+

suspend

+

+

+

+

+

The matrix below describes the authorizations used when retrieving task information. In short, it says that all users which have any role with regards to the specific task, are allowed to see the task. This applies to all operations that are used to retrieve any type of information about the task.

Table 24. Retrieval operations permissions matrix
Operation Role Initiator Stakeholder Potential Actual Administrator

get

+

+

+

+

+

9.7. Task Service and The jBPM engine

As far as the jBPM engine is concerned, human tasks are similar to any other external service that needs to be invoked and are implemented as a domain-specific service. (For more on domain-specific services, see the chapter on them here.) Because a human task is an example of such a domain-specific service, the process itself only contains a high-level, abstract description of the human task to be executed and a work item handler that is responsible for binding this (abstract) task to a specific implementation.

Users can plug in any human task service implementation, such as the one that’s provided by jBPM, or they may register their own implementation. In the next paragraphs, we will describe the human task service implementation provided by jBPM.

The jBPM project provides a default implementation of a human task service based on the WS-HumanTask specification. If you do not need to integrate jBPM with another existing implementation of a human task service, you can use this service. The jBPM implementation manages the life cycle of the tasks (creation, claiming, completion, etc.) and stores the state of all the tasks, task lists, and other associated information. It also supports features like internationalization, calendar integration, different types of assignments, delegation, escalation and deadlines. The code for the implementation itself can be found in the jbpm-human-task module.

The jBPM task service implementation is based on the WS-HumanTask (WS-HT) specification. This specification defines (in detail) the model of the tasks, the life cycle, and many other features. It is very comprehensive and the first version can be found here.

9.8. Task Service API

The human task service exposes a Java API for managing the life cycle of tasks. This allows clients to integrate (at a low level) with the human task service. Note that end users should probably not interact with this low-level API directly, but use one of the more user-friendly task clients (see below) instead. These clients offer a graphical user interface to request task lists, claim and complete tasks, and manage tasks in general. The task clients listed below use the Java API to internally interact with the human task service. Of course, the low-level API is also available so that developers can use it in their code to interact with the human task service directly.

A task service (interface org.kie.api.task.TaskService) offers the following methods (among others) for managing the life cycle of human tasks:

              ...

              void start( long taskId, String userId );

              void stop( long taskId, String userId );

              void release( long taskId, String userId );

              void suspend( long taskId, String userId );

              void resume( long taskId, String userId );

              void skip( long taskId, String userId );

              void delegate(long taskId, String userId, String targetUserId);

              void complete( long taskId, String userId, Map<String, Object> results );

              ...

If you take a look at the method signatures you will notice that almost all of these methods take the following arguments:

  • taskId: The id of the task that we are working with. This is usually extracted from the currently selected task in the user task list in the user interface.

  • userId: The id of the user that is executing the action. This is usually the id of the user that is logged in into the application.

There is also an internal interface that you should check for more methods to interact with the Task Service, this interface is internal until it gets tested. Future version of the External (public) interface can include some of the methods proposed in the InternalTaskService interface. If you want to make use of the methods provided by this interface you need to manually cast to InternalTaskService. One method that can be useful from this interface is getTaskContent():

               Map<String, Object> getTaskContent( long taskId );

This method saves you from doing all the boiler plate of getting the ContentMarshallerContext to unmarshall the serialized version of the task content. If you only want to use the stable/public API’s you can just copy what this method does:

              Task taskById = taskQueryService.getTaskInstanceById(taskId);
              Content contentById = taskContentService.getContentById(taskById.getTaskData().getDocumentContentId());
              ContentMarshallerContext context = getMarshallerContext(taskById);
              Object unmarshalledObject = ContentMarshallerHelper.unmarshall(contentById.getContent(), context.getEnvironment(), context.getClassloader());
              if (!(unmarshalledObject instanceof Map)) {
                  throw new IllegalStateException(" The Task Content Needs to be a Map in order to use this method and it was: "+unmarshalledObject.getClass());

              }
              Map<String, Object> content = (Map<String, Object>) unmarshalledObject;
              return content;

Because the content of the Task can be any Object, the previous method assume that you are storing a Map of objects to work. If you are storing other than a Map you should do the correspondent checks.

9.8.1. Task event listener

Task service supports task listeners to be invoked upon various life cycle events happening on given task instance. In majority of cases task event listeners are used to intercept certain operation to perform additional logic - like storing task information in separate tables for business activity monitoring needs.

Task event listeners are pluggable and users can provide their own implementation of org.kie.api.task.TaskLifeCycleEventListener interface. There are beforeTask* and afterTask* methods that are invoked upon given event occurred on a task instance.

TaskEvent (org.kie.api.task.TaskEvent) is the only argument available to the listener that provides access to:

  • Task instance that the event correspond to

  • TaskContext that provides access to services for further processing needs such as TaskPersistenceContext

In many cases implementors of task event listener need to have access to task variables (either input or output or both) to perform required operations. It can be done as described above (using various services and content marshaller helper) though that in many cases leads to code duplication in multiple listeners thus an extended support was added in 6.5 to simply use TaskContext to obtain that information.

loadTaskVariables(Task task);

Method loadTaskVariables can be used to populate both input and output variables of a given task by simple and single method call. That method is "no op" in case task variables are already set on a task.

To improve performance task variables are automatically set when they are available - usually given by caller on task service:

  • when task is created it usually has input variables, these variables are then set on Task instance so there is no need to use loadTaskVariables method as only task input variables are available when task is being created - applies to beforeTaskAdded and afterTaskAdded events handling

  • when task is completed it usually has output variables, these variables are set on a task so there is no need to use loadTaskVariables method if only task output variables are required.

Other than that loadTaskVariables should be used to populate task variables.

It’s enough to call it once (like in beforeTask) method of the listener as they will be available to both beforeTask* and afterTask* methods then.

9.8.2. Data model of task service

Below is the database model used by task service with all tables and their relationship illustrated.

task schema

9.9. Interacting with the Task Service

In order to get access to the Task Service API it is recommended to let the Runtime Manager to make sure that everything is setup correctly. Look at the Runtime Manager section for more information. From the API perspective you should be doing something like this:

// ...

RuntimeEngine engine = runtimeManager.getRuntimeEngine(EmptyContext.get());
KieSession kieSession = engine.getKieSession();
// Start a process
kieSession.startProcess("CustomersRelationship.customers", params);
// Do Task Operations
TaskService taskService = engine.getTaskService();
List<TaskSummary> tasksAssignedAsPotentialOwner = taskService.getTasksAssignedAsPotentialOwner("mary", "en-UK");

// Claim Task
taskService.claim(taskSummary.getId(), "mary");
// Start Task
taskService.start(taskSummary.getId(), "mary");

// ...

If you use this approach, there is no need to register the Task Service with the jBPM engine. The Runtime Manager will do that for you automatically. If you don’t use the Runtime Manager, you will be responsible for setting the LocalHTWorkItemHandler in the session in order to get the Task Service notifying the jBPM engine when a task is completed, or the jBPM engine notifying that a task has been created.

In jBPM 6.x the Task Service runs locally to the jBPM engine and for that reason multiple light clients can be created for different jBPM engine instances. All the clients will be sharing the same database (backend storage for the tasks).

9.10. Experimental features

9.10.1. SubTasks

The "Subtasks" feature is an experimental feature in the task service. This feature allows one task to have sub-tasks in a parent-child relationship. The parent task can auto-complete depending on the state of its children (and the subtask strategy used).

You can use it by setting the parentId of a task, either when creating the task manually via the task service or otherwise by setting the ParentId parameter of the task definition in the BPMN2 process definition.

10. Persistence and Transactions

10.1. Persistence and transactions in the jBPM engine

The jBPM engine implements persistence for process states. The implementation uses the JPA framework with an SQL database backend. It can also store audit log information in the database.

The jBPM engine also enables transactional execution of processes using the JTA framework, relying on the persistence backend to support the transactions.

10.2. Persistence of process runtime states

The jBPM engine supports persistent storage of the runtime state of running process instances. Because it stores the runtime states, it can continue execution of a process instance if the jBPM engine stopped or encountered a problem at any point.

The jBPM engine also persistently stores the process definitions and the history logs of current and previous process states.

You can use the persistence.xml file, specified by the JPA framework, to configure persistence in an SQL database. You can plug in different persistence strategies. For more information about the persistence.xml file, see Configuration in the persistence.xml file.

By default, if you do not configure persistence in the jBPM engine, process information, including process instance states, is not made persistent.

When the jBPM engine starts a process, it creates a process instance, which represents the execution of the process in that specific context. For example, when executing a process that processes a sales order, one process instance is created for each sales request.

The process instance contains the current runtime state and context of a process, including current values of any process variables. However, it does not include information about the history of past states of the process, as this information is not required for ongoing execution of a process.

When the runtime state of process instances is made persistent, you can restore the state of execution of all running processes in case the jBPM engine fails or is stopped. You can also remove a particular process instance from memory and then restore it at a later time.

If you configure the jBPM engine to use persistence, it automatically stores the runtime state into the database. You do not need to trigger persistence in the code.

When you restore the state of the jBPM engine from a database, all instances are automatically restored to their last recorded state. Process instances automatically resume execution if they are triggered, for example, by an expired timer, the completion of a task that was requested by the process instance, or a signal being sent to the process instance. You do not need to load separate instances and trigger their execution manually.

The jBPM engine also automatically reloads process instances on demand.

10.2.1. Safe points for persistence

The jBPM engine saves the state of a process instance to persistent storage at safe points during the execution of the process.

When a process instance is started or resumes execution from a previous wait state, the jBPM engine continues the execution until no more actions can be performed. If no more actions can be performed, it means that the process has completed or else has reached a wait state. If the process contains several parallel paths, all the paths must reach a wait state.

This point in the execution of the process is considered a safe point. At this point, the jBPM engine stores the state of the process instance, and of any other process instances that were affected by the execution, to persistent storage.

10.2.2. Binary runtime persistence data model

The runtime persistence data is internal. As a general rule, do not access the database tables directly and, most importantly, do not modify it. Changing the runtime state information for process instances without using the jBPM engine might have unexpected consequences. Use a history log to analyze information about the current or past states of process instances.

In rare cases it might be useful to query internal database tables directly if you have a specific need to do so.

The jBPM engine uses a binary persistence mechanism, otherwise known as marshalling, which converts the state of the process instance into a binary dataset. The same mechanism is also applied to the session state and any work item states.

When the process instance state is persisted, the jBPM engine completes two steps:

  • First, it transforms the process instance information into a binary blob. For performance reasons, the jBPM engine uses a custom serialization mechanism and not standard Java serialization.

  • Next, it stores the blob alongside metadata about this process instance. This metadata includes the process instance ID, process ID, and process start date, as well as other data.

Apart from process instance states, the jBPM engine stores some state information for the session, including the state of timer jobs and the session data for evaluating business rules. The jBPM engine stores the session state as a separate binary blob, along with metadata that includes the ID of the session.

To restore the state of a session, reload the session with a particular ID using the ksession.getId() method.

Binary datasets that represent process instance states are usually relatively small, because they contain only the minimal execution state of the process instance. For a simple process instance, the state usually includes the nodes that are currently executing and any existing variable values.

jbpm schema doc
Figure 35. Data model for jBPM engine persistence

The sessioninfo entity contains the state of the knowledge session in which the process instance is running.

Table 25. SessionInfo
Field Description Nullable

id

The primary key

NOT NULL

lastmodificationdate

The last time that the entity was saved to the database

rulesbytearray

The binary dataset containing the state of the session

NOT NULL

startdate

The start time of the session

optlock

The version field that serves as its optimistic lock value

The processinstanceinfo entity contains the state of the process instance.

Table 26. ProcessInstanceInfo
Field Description Nullable

instanceid

The primary key

NOT NULL

lastmodificationdate

The last time that the entity was saved to the database

lastreaddate

The last time that the entity was retrieved (read) from the database

processid

The name (ID) of the process

processinstancebytearray

The binary dataset containing the state of the process instance

NOT NULL

startdate

The start time of the process

state

An integer representing the state of the process instance

NOT NULL

optlock

The version field that serves as its optimistic lock value

The eventtypes entity contains information about events that a process instance will undergo or has undergone.

Table 27. EventTypes
Field Description Nullable

instanceid

This column references the processinstanceinfo primary key. There is a foreign key constraint on this column.

NOT NULL

element

A text field related to an event that the process has undergone

The workiteminfo entity contains the state of a work item.

Table 28. WorkItemInfo
Field Description Nullable

workitemid

The primary key

NOT NULL

creationDate

The creation date of the work item

name

The name of the work item

processinstanceid

The (primary key) ID of the process. There is no foreign key constraint on this field.

NOT NULL

state

An integer representing the state of the work item

NOT NULL

optlock

The version field that serves as its optimistic lock value

workitembytearay

The binary dataset containing the state of the work item

NOT NULL

The CorrelationKeyInfo entity contains information about correlation keys assigned to the given process instance. The relationship is loose, because this table is optional, used only when correlation capabilities are required.

Table 29. CorrelationKeyInfo
Field Description Nullable

keyid

The primary key

NOT NULL

name

The assigned name of the correlation key

processinstanceid

The ID of the process instance which is assigned to this correlation key

NOT NULL

optlock

The version field that serves as its optimistic lock value

The CorrelationPropertyInfo entity contains information about correlation properties for the given correlation key that is assigned to the given process instance.

Table 30. CorrelationPropertyInfo
Field Description Nullable

propertyid

The primary key

NOT NULL

name

The name of the property

value

The value of the property

NOT NULL

optlock

The version field that serves as its optimistic lock value

correlationKey-keyid

Foreign key to map to the correlation key

NOT NULL

The ContextMappingInfo entity contains information about contextual information mapped to a ksession. This entity is an internal part of the RuntimeManager class and can be considered optional when RuntimeManager is not used.

Table 31. ContextMappingInfo
Field Description Nullable

mappingid

The primary key

NOT NULL

context_id

Identifier of the context

NOT NULL

ksession_id

Identifier of the ksession mapped to this context

NOT NULL

owner_id

Identifier of the runtime manager

NOT NULL

optlock

The version field that serves as its optimistic lock value

10.3. The persistent audit log

The jBPM engine can store information about the execution of process instances, including the successive historical states of the instances.

This information can be useful in many cases. For example, you might want to verify which actions have been executed for a particular process instance or to monitor and analyze the efficiency of a particular process.

However, storing history information in the runtime database would result in the database rapidly increasing in size and would also affect the performance of the persistence layer. Therefore, history log information is stored separately.

The jBPM engine creates a log based on events that it generates during execution of processes. It uses the event listener mechanism to receive events and extract the necessary information, then persists this information to a database. The jbpm-audit module contains an event listener that stores process-related information in a database using JPA.

You can use filters to limit the scope of the logged information.

10.3.1. The jBPM engine audit log data model

You can query jBPM engine audit log information to use it in different scenarios, for example, creating a history log for one specific process instance or analyzing the performance of all instances of a specific process.

The audit log data model is a default implementation. Depending on your use cases, you might also define your own data model for storing the information you require. You can use process event listeners to extract the information.

The data model contains three entities: one for process instance information, one for node instance information, and one for process variable instance information.

The ProcessInstanceLog table contains the basic log information about a process instance.

Table 32. ProcessInstanceLog table fields
Field Description Nullable

id

The primary key and ID of the log entity

NOT NULL

correlationKey

The correlation of this process instance

duration

Actual duration of this process instance since its start date

end_date

When applicable, the end date of the process instance

externalId

Optional external identifier used to correlate to some elements, for example, a deployment ID

user_identity

Optional identifier of the user who started the process instance

outcome

The outcome of the process instance. This field contains the error code if the process instance was finished with an error event.

parentProcessInstanceId

The process instance ID of the parent process instance, if applicable

processid

The ID of the process

processinstanceid

The process instance ID

NOT NULL

processname

The name of the process

processtype

The type of the instance (process or case)

processversion

The version of the process

sla_due_date

The due date of the process according to the service level agreement (SLA)

slaCompliance

The level of compliance with the SLA

start_date

The start date of the process instance

status

The status of the process instance that maps to the process instance state

The NodeInstanceLog table contains more information about which nodes were executed inside each process instance. Whenever a node instance is entered from one of its incoming connections or is exited through one of its outgoing connections, information about the event is stored in this table.

Table 33. NodeInstanceLog table fields
Field Description Nullable

id

The primary key and ID of the log entity

NOT NULL

connection

Actual identifier of the sequence flow that led to this node instance

log_date

The date of the event

externalId

Optional external identifier used to correlate to some elements, for example, a deployment ID

nodeid

The node ID of the corresponding node in the process definition

nodeinstanceid

The node instance ID

nodename

The name of the node

nodetype

The type of the node

processid

The ID of the process that the process instance is executing

processinstanceid

The process instance ID

NOT NULL

sla_due_date

The due date of the node according to the service level agreement (SLA)

slaCompliance

The level of compliance with the SLA

type

The type of the event (0 = enter, 1 = exit)

NOT NULL

workItemId

(Optional, only for certain node types) The identifier of the work item

nodeContainerId

The identifier of the container, if the node is inside an embedded sub-process node

referenceId

The reference identifier

The VariableInstanceLog table contains information about changes in variable instances. By default, the jBPM engine generates log entries after a variable changes its value. The jBPM engine can also log entries before the changes.

Table 34. VariableInstanceLog table fields
Field Description Nullable

id

The primary key and ID of the log entity

NOT NULL

externalId

Optional external identifier used to correlate to some elements, for example, a deployment ID

log_date

The date of the event

processid

The ID of the process that the process instance is executing

processinstanceid

The process instance ID

NOT NULL

oldvalue

The previous value of the variable at the time that the log is made

value

The value of the variable at the time that the log is made

variableid

The variable ID in the process definition

variableinstanceid

The ID of the variable instance

The AuditTaskImpl table contains information about user tasks.

Table 35. AuditTaskImpl table fields
Field Description Nullable

id

The primary key and ID of the task log entity

activationTime

Time when this task was activated

actualOwner

Actual owner assigned to this task. This value is set set only when the owner claims the task.

createdBy

User who created this task

createdOn

Date when the task was created

deploymentId

The ID of the deployment of which this task is a part

description

Description of the task

dueDate

Due date set on this task

name

Name of the task

parentId

Parent task ID

priority

Priority of the task

processId

Process definition ID to which this task belongs

processInstanceId

Process instance ID with which this task is associated

processSessionId

KIE session ID used to create this task

status

Current status of the task

taskId

Identifier of the task

workItemId

Identifier of the work item assigned on the process side to this task ID

lastModificationDate

The date and time when the process instance state was last recorded in the persistence database

The BAMTaskSummary table collects information about tasks that is used by the BAM engine to build charts and dashboards.

Table 36. BAMTaskSummary table fields
Field Description Nullable

pk

The primary key and ID of the log entity

NOT NULL

createdDate

Date when the task was created

duration

Duration since the task was created

endDate

Date when the task reached an end state (complete, exit, fail, skip)

processinstanceid

The process instance ID

startDate

Date when the task was started

status

Current status of the task

taskId

Identifier of the task

taskName

Name of the task

userId

User ID assigned to the task

optlock

The version field that serves as its optimistic lock value

The TaskVariableImpl table contains information about task variable instances.

Table 37. TaskVariableImpl table fields
Field Description Nullable

id

The primary key and ID of the log entity

NOT NULL

modificationDate

Date when the variable was modified most recently

name

Name of the task

processid

The ID of the process that the process instance is executing

processinstanceid

The process instance ID

taskId

Identifier of the task

type

Type of the variable: either input or output of the task

value

Variable value

The TaskEvent table contains information about changes in task instances. Operations such as claim, start, and stop are stored in this table to provide a timeline view of events that happened to the given task.

Table 38. TaskEvent table fields
Field Description Nullable

id

The primary key and ID of the log entity

NOT NULL

logTime

Date when this event was saved

message

Log event message

processinstanceid

The process instance ID

taskId

Identifier of the task

type

Type of the event. Types correspond to life cycle phases of the task

userId

User ID assigned to the task

workItemId

Identifier of the work item to which the task is assigned

optlock

The version field that serves as its optimistic lock value

correlationKey

Correlation key of the process instance

processType

Type of the process instance (process or case)

10.3.2. Configuration for storing the process events log in a database

To log process history information in a database with a default data model, you must register the logger on your session.

Registering the logger on your KIE session
KieSession ksession = ...;
ksession.addProcessEventListener(AuditLoggerFactory.newInstance(Type.JPA, ksession, null));

// invoke methods for your session here

To specify the database for storing the information, you must modify the persistence.xml file to include the audit log classes: ProcessInstanceLog, NodeInstanceLog, and VariableInstanceLog.

Modified persistence.xml file that includes the audit log classes
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<persistence
  version="2.0"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd
  http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
  xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <persistence-unit name="org.jbpm.persistence.jpa" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/jbpm-ds</jta-data-source>
    <mapping-file>META-INF/JBPMorm.xml</mapping-file>
    <class>org.drools.persistence.info.SessionInfo</class>
    <class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class>
    <class>org.drools.persistence.info.WorkItemInfo</class>
    <class>org.jbpm.persistence.correlation.CorrelationKeyInfo</class>
    <class>org.jbpm.persistence.correlation.CorrelationPropertyInfo</class>
    <class>org.jbpm.runtime.manager.impl.jpa.ContextMappingInfo</class>

    <class>org.jbpm.process.audit.ProcessInstanceLog</class>
    <class>org.jbpm.process.audit.NodeInstanceLog</class>
    <class>org.jbpm.process.audit.VariableInstanceLog</class>

    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
      <property name="hibernate.max_fetch_depth" value="3"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.connection.release_mode" value="after_transaction"/>
      <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform"/>
    </properties>
  </persistence-unit>
</persistence>

10.3.3. Configuration for sending the process events log to a JMS queue

When the jBPM engine stores events in the database with the default audit log implementation, the database operation is completed synchronously, within the same transaction as the actual execution of the process instance. This operation takes time, and on highly loaded systems it might have some impact on database performance, especially when both the history log and the runtime data are stored in the same database.

As an alternative, you can use the JMS-based logger that the jBPM engine provides. You can configure this logger to submit process log entries as messages to a JMS queue, instead of directly persisting them in the database.

You can configure the JMS logger to be transactional, in order to avoid data inconsistencies if a jBPM engine transaction is rolled back.

Using the JMS audit logger
ConnectionFactory factory = ...;
Queue queue = ...;
StatefulKnowledgeSession ksession = ...;
Map<String, Object> jmsProps = new HashMap<String, Object>();
jmsProps.put("jbpm.audit.jms.transacted", true);
jmsProps.put("jbpm.audit.jms.connection.factory", factory);
jmsProps.put("jbpm.audit.jms.queue", queue);
ksession.addProcessEventListener(AuditLoggerFactory.newInstance(Type.JMS, ksession, jmsProps));

// invoke methods one your session here

This is just one of the possible ways to configure JMS audit logger. You can use the AuditLoggerFactory class to set additional configuration parameters.

10.3.4. Auditing of variables

By default, values of process and task variables are stored in audit tables as string representations. To create string representations of non-string variable types, the jBPM engine calls the variable.toString() method. If you use a custom class for a variable, you can implement this method for the class. In many cases this representation is sufficient.

However, sometimes a string representation in the logs might not be sufficient, especially when there is a need for efficient queries by process or task variables. For example, a Person object, used as a value for a variable, might have the following structure:

Example Person object, used as a process or task variable value
public class Person implements Serializable {

    private static final long serialVersionUID = -5172443495317321032L;
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

The toString() method provides a human-readable format. However, it might not be sufficient for a search. A sample string value is Person [name="john", age="34"]. Searching through a large number of such strings to find people of age 34 would make a database query inefficient.

To enable more efficient searching, you can audit variables using VariableIndexer objects, which extract relevant parts of the variable for storage in the audit log.

Definition of the VariableIndexer interface
/**
 * Variable indexer that transforms a variable instance into another representation (usually string)
 * for use in log queries.
 *
 * @param <V> type of the object that will represent the indexed variable
 */
public interface VariableIndexer<V> {

    /**
     * Tests if this indexer can index a given variable
     *
     * NOTE: only one indexer can be used for a given variable
     *
     * @param variable variable to be indexed
     * @return true if the variable should be indexed with this indexer
     */
    boolean accept(Object variable);

    /**
     * Performs an index/transform operation on the variable. The result of this operation can be
     * either a single value or a list of values, to support complex type separation.
     * For example, when the variable is of the type Person that has name, address, and phone fields,
     * the indexer could build three entries out of it to represent individual fields:
     * person = person.name
     * address = person.address.street
     * phone = person.phone
     * this configuration allows advanced queries for finding relevant entries.
     * @param name name of the variable
     * @param variable actual variable value
     * @return
     */
    List<V> index(String name, Object variable);
}

The default indexer uses the toString() method to produce a single audit entry for a single variable. Other indexers can return a list of objects from indexing a single variable.

To enable efficient queries for the Person type, you can build a custom indexer that indexes a Person instance into separate audit entries, one representing the name and another representing the age.

Sample indexer for the Person type
public class PersonTaskVariablesIndexer implements TaskVariableIndexer {

    @Override
    public boolean accept(Object variable) {
        if (variable instanceof Person) {
            return true;
        }
        return false;
    }

    @Override
    public List<TaskVariable> index(String name, Object variable) {

        Person person = (Person) variable;
        List<TaskVariable> indexed = new ArrayList<TaskVariable>();

        TaskVariableImpl personNameVar = new TaskVariableImpl();
        personNameVar.setName("person.name");
        personNameVar.setValue(person.getName());

        indexed.add(personNameVar);

        TaskVariableImpl personAgeVar = new TaskVariableImpl();
        personAgeVar.setName("person.age");
        personAgeVar.setValue(person.getAge()+"");

        indexed.add(personAgeVar);

        return indexed;
    }

}

The jBPM engine can use this indexer to index values when they are of the Person type, while all other variables are indexed with the default toString() method. Now, to query for process instances or tasks that refer to a person with age 34, you can use the following query:

  • variable name: person.age

  • variable value: 34

As a LIKE type query is not used, the database server can optimize the query and make it efficient on a large set of data.

Custom indexers

The jBPM engine supports indexers for both process and task variables. However, it uses different interfaces for the indexers, because they must produce different types of objects that represent an audit view of the variable.

You must implement the following interfaces to build custom indexers:

  • For process variables: org.kie.internal.process.ProcessVariableIndexer

  • For task variables: org.kie.internal.task.api.TaskVariableIndexer

You must implement two methods for either of the interfaces:

  • accept: Indicates whether a type is handled by this indexer. The jBPM engine expects that only one indexer can index a given variable value, so it uses the first indexer that accepts the type.

  • index: Indexes a value, producing a object or list of objects (usually strings) for inclusion in the audit log.

After implementing the interface, you must package this implementation as a JAR file and list the implementation in one of the following files:

  • For process variables, the META-INF/services/org.kie.internal.process.ProcessVariableIndexer file, which lists fully qualified class names of process variable indexers (single class name per line)

  • For task variables, the META-INF/services/org.kie.internal.task.api.TaskVariableIndexer file, which lists fully qualified class names of task variable indexers (single class name per line)

The ServiceLoader mechanism discovers the indexers using these files. When indexing a process or task variable, the jBPM engine examines the registered indexers to find any indexer that accepts the value of the variable. If no other indexer accepts the value, the jBPM engine applies the default indexer that uses the toString() method.

10.4. Transactions in the jBPM engine

The jBPM engine supports Java Transaction API (JTA) transactions.

It also supports local transactions only when using Spring. For more information about using Spring to set up persistence, please see the Spring chapter in the Drools integration guide. The current version of the jBPM engine does not support pure local transactions.

If you do not provide transaction boundaries inside your application, the jBPM engine automatically executes each method invocation on the jBPM engine in a separate transaction.

Optionally, you can specify the transaction boundaries in the application code, for example, to combine multiple commands into one transaction.

10.4.1. Registration of a transaction manager

You must register a transaction manager in the environment to use user-defined transactions.

The following sample code registers the transaction manager and uses JTA calls to specify transaction boundaries.

Registering a transaction manager and using transactions
// Create the entity manager factory
EntityManagerFactory emf = EntityManagerFactoryManager.get().getOrCreate("org.jbpm.persistence.jpa");
TransactionManager tm = TransactionManagerServices.getTransactionManager();

// Set up the runtime environment
RuntimeEnvironment environment = RuntimeEnvironmentBuilder.Factory.get()
.newDefaultBuilder()
.addAsset(ResourceFactory.newClassPathResource("MyProcessDefinition.bpmn2"), ResourceType.BPMN2)
    .addEnvironmentEntry(EnvironmentName.TRANSACTION_MANAGER, tm)
    .get();

// Get the KIE session
RuntimeManager manager = RuntimeManagerFactory.Factory.get().newPerRequestRuntimeManager(environment);
RuntimeEngine runtime = manager.getRuntimeEngine(ProcessInstanceIdContext.get());
KieSession ksession = runtime.getKieSession();

// Start the transaction
UserTransaction ut = InitialContext.doLookup("java:comp/UserTransaction");
ut.begin();

// Perform multiple commands inside one transaction
ksession.insert( new Person( "John Doe" ) );
ksession.startProcess("MyProcess");

// Commit the transaction
ut.commit();

You must provide a jndi.properties file in you root class path to create a JNDI InitialContextFactory object, because transaction-related objects like UserTransaction, TransactionManager, and TransactionSynchronizationRegistry are registered in JNDI.

If your project includes the jbpm-test module, this file is already included by default.

Otherwise, you must create the jndi.properties file with the following content:

Content of the jndi.properties file
java.naming.factory.initial=org.jbpm.test.util.CloseSafeMemoryContextFactory
org.osjava.sj.root=target/test-classes/config
org.osjava.jndi.delimiter=/
org.osjava.sj.jndi.shared=true

This configuration assumes that the simple-jndi:simple-jndi artifact is present in the class path of your project. You can also use a different JNDI implementation.

By default, the Narayana JTA transaction manager is used. If you want to use a different JTA transaction manager, you can change the persistence.xml file to use the required transaction manager. For example, if your application runs on Red Hat JBoss EAP version 7 or later, you can use the JBoss transaction manager. In this case, change the transaction manager property in the persistence.xml file:

Transaction manager property in the persistence.xml file for the JBoss transaction manager
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />

Using the Singleton strategy of the RuntimeManager class with JTA transactions (UserTransaction or CMT) creates a race condition. This race condition can result in an IllegalStateException exception with a message similar to Process instance XXX is disconnected.

To avoid this race condition, explicitly synchronize around the KieSession instance when invoking the transaction in the user application code.

synchronized (ksession) {
    try {
        tx.begin();

        // use ksession
        // application logic

        tx.commit();
    } catch (Exception e) {
        //...
    }
}

10.4.2. Configuring container-managed transactions

If you embed the jBPM engine in an application that executes in container-managed transaction (CMT) mode, for example, EJB beans, you must complete additional configuration. This configuration is especially important if the application runs on an application server that does not allow a CMT application to access a UserTransaction instance from JNDI, for example, WebSphere Application Server.

The default transaction manager implementation in the jBPM engine relies on UserTransaction to query transaction status and then uses the status to determine whether to start a transaction. In environments that prevent access to a UserTransaction instance, this implementation fails.

To enable proper execution in CMT environments, the jBPM engine provides a dedicated transaction manager implementation: org.jbpm.persistence.jta.ContainerManagedTransactionManager. This transaction manager expects that the transaction is active and always returns ACTIVE when the getStatus() method is invoked. Operations such as begin, commit, and rollback are no-op methods, because the transaction manager cannot affect these operations in container-managed transaction mode.

During process execution your code must propagate any exceptions thrown by the engine to the container to ensure that the container rolls transactions back when necessary.

To configure this transaction manager, complete the steps in this procedure.

Procedure
  1. In your code, insert the transaction manager and persistence context manager into the environment before creating or loading a session:

    Inserting the transaction manager and persistence context manager into the environment
    Environment env = EnvironmentFactory.newEnvironment();
    env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
    env.set(EnvironmentName.TRANSACTION_MANAGER, new ContainerManagedTransactionManager());
    env.set(EnvironmentName.PERSISTENCE_CONTEXT_MANAGER, new JpaProcessPersistenceContextManager(env));
    env.set(EnvironmentName.TASK_PERSISTENCE_CONTEXT_MANAGER, new JPATaskPersistenceContextManager(env));
  2. In the persistence.xml file, configure the JPA provider. The following example uses hibernate and WebSphere Application Server.

    Configuring the JPA provider in the persistence.xml file
    <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.CMTTransactionFactory"/>
    <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.WebSphereJtaPlatform"/>
  3. To dispose a KIE session, do not dispose it directly. Instead, execute the org.jbpm.persistence.jta.ContainerManagedTransactionDisposeCommand command. This commands ensures that the session is disposed at the completion of the current transaction. In the following example, ksession is the KieSession object that you want to dispose.

    Disposing a KIE session using the ContainerManagedTransactionDisposeCommand command
    ksession.execute(new ContainerManagedTransactionDisposeCommand());

    Directly disposing the session causes an exception at the completion of the transaction, because the jBPM engine registers transaction synchronization to clean up the session state.

10.5. Configuration of persistence in the jBPM engine

If you use the jBPM engine without configuring any persistence, it does not save runtime data to any database; no in-memory database is available by default. You can use this mode if it is required for performance reasons or when you want to manage persistence yourself.

To use JPA persistence in the jBPM engine, you must configure it.

Configuration usually requires adding the necessary dependencies, configuring a data source, and creating the jBPM engine classes with persistence configured.

10.5.1. Configuration in the persistence.xml file

To use JPA persistence, you must add a persistence.xml persistence configuration to your class path to configure JPA to use Hibernate and the H2 database (or any other database that you prefer). Place this file in the META-INF directory of your project.

Sample persistence.xml file
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence
      version="2.0"
      xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd
      http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
      xmlns="http://java.sun.com/xml/ns/persistence"
      xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <persistence-unit name="org.jbpm.persistence.jpa" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/jbpm-ds</jta-data-source>
    <mapping-file>META-INF/JBPMorm.xml</mapping-file>
    <class>org.drools.persistence.info.SessionInfo</class>
    <class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class>
    <class>org.drools.persistence.info.WorkItemInfo</class>
    <class>org.jbpm.persistence.correlation.CorrelationKeyInfo</class>
    <class>org.jbpm.persistence.correlation.CorrelationPropertyInfo</class>
    <class>org.jbpm.runtime.manager.impl.jpa.ContextMappingInfo</class>

    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
      <property name="hibernate.max_fetch_depth" value="3"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.connection.release_mode" value="after_transaction"/>
            <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform"/>
    </properties>
  </persistence-unit>
</persistence>

The example refers to a jdbc/jbpm-ds data source. For instructions about configuring a data source, see Configuration of data sources for jBPM engine persistence.

10.5.2. Configuration of data sources for jBPM engine persistence

To configure JPA persistence in the jBPM engine, you must provide a data source, which represents a database backend.

If you run your application in an application server, such as Red Hat JBoss EAP, you can use the application server to set up data sources, for example, by adding a data source configuration file in the deploy directory. For instructions about creating data sources, see the documentaion for the application server.

If you deploy your application to Red Hat JBoss EAP, you can create a data source by creating a configuration file in the deploy directory:

Example data source configuration file for Red Hat JBoss EAP
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
  <local-tx-datasource>
    <jndi-name>jdbc/jbpm-ds</jndi-name>
    <connection-url>jdbc:h2:tcp://localhost/~/test</connection-url>
    <driver-class>org.h2.jdbcx.JdbcDataSource</driver-class>
    <user-name>sa</user-name>
    <password></password>
  </local-tx-datasource>
</datasources>

If your application runs in a plain Java environment, you can use Narayana and Tomcat DBCP by using the DataSourceFactory class from the kie-test-util module supplied by jBPM. See the following code fragment. This example uses the H2 in-memory database in combination with Narayana and Tomcat DBCP.

Example code configuring an H2 in-memory database data source
Properties driverProperties = new Properties();
driverProperties.put("user", "sa");
driverProperties.put("password", "sa");
driverProperties.put("url", "jdbc:h2:mem:jbpm-db;MVCC=true");
driverProperties.put("driverClassName", "org.h2.Driver");
driverProperties.put("className", "org.h2.jdbcx.JdbcDataSource");
PoolingDataSourceWrapper pdsw = DataSourceFactory.setupPoolingDataSource("jdbc/jbpm-ds", driverProperties);

10.5.3. Dependencies for persistence

Persistence requires certain JAR artifact dependencies.

The jbpm-persistence-jpa.jar file is always required. This file contains the code for saving the runtime state whenever necessary.

Depending on the persistence solution and database you are using, you might need additional dependencies. The default configuration combination includes the following components:

  • Hibernate as the JPA persistence provider

  • H2 in-memory database

  • Narayana for JTA-based transaction management

  • Tomcat DBCP for connection pooling capabilities

This configuration requires the following additional dependencies:

  • jbpm-persistence-jpa (org.jbpm)

  • drools-persistence-jpa (org.drools)

  • persistence-api (javax.persistence)

  • hibernate-entitymanager (org.hibernate)

  • hibernate-annotations (org.hibernate)

  • hibernate-commons-annotations (org.hibernate)

  • hibernate-core (org.hibernate)

  • commons-collections (commons-collections)

  • dom4j (org.dom4j)

  • jta (javax.transaction)

  • narayana-jta (org.jboss.narayana.jta)

  • tomcat-dbcp (org.apache.tomcat)

  • jboss-transaction-api_1.2_spec (org.jboss.spec.javax.transaction)

  • javassist (javassist)

  • slf4j-api (org.slf4j)

  • slf4j-jdk14 (org.slf4j)

  • simple-jndi (simple-jndi)

  • h2 (com.h2database)

  • jbpm-test (org.jbpm) only for testing, do not include this artifact in the production application

10.5.4. Creating a KIE session with persistence

If your code creates KIE sessions directly, you can use the JPAKnowledgeService class to create your KIE session. This approach provides full access to the underlying configuration.

Procedure
  1. Create a KIE session using the JPAKnowledgeService class, based on a KIE base, a KIE session configuration (if necessary), and an environment. The environment must contain a reference to the Entity Manager Factory that you use for persistence.

    Creating a KIE session with persistence
    // create the entity manager factory and register it in the environment
    EntityManagerFactory emf =
        Persistence.createEntityManagerFactory( "org.jbpm.persistence.jpa" );
    Environment env = KnowledgeBaseFactory.newEnvironment();
    env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, emf );
    
    // create a new KIE session that uses JPA to store the runtime state
    StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession( kbase, null, env );
    int sessionId = ksession.getId();
    
    // invoke methods on your method here
    ksession.startProcess( "MyProcess" );
    ksession.dispose();
  2. To re-create a session from the database based on a specific session ID, use the JPAKnowledgeService.loadStatefulKnowledgeSession() method:

    Re-creating a KIE session from the persistence database
    // re-create the session from database using the sessionId
    ksession = JPAKnowledgeService.loadStatefulKnowledgeSession(sessionId, kbase, null, env );

10.5.5. Persistence in the runtime manager

If your code uses the RuntimeManager class, use the RuntimeEnvironmentBuilder class to configure the environment for persistence. By default, the runtime manager searches for the org.jbpm.persistence.jpa persistence unit.

The following example creates a KieSession with an empty context.

Creating a KIE session with an empty context using the runtime manager
RuntimeEnvironmentBuilder builder = RuntimeEnvironmentBuilder.Factory.get()
        .newDefaultBuilder()
        .knowledgeBase(kbase);
RuntimeManager manager = RuntimeManagerFactory.Factory.get()
        .newSingletonRuntimeManager(builder.get(), "com.sample:example:1.0");
RuntimeEngine engine = manager.getRuntimeEngine(EmptyContext.get());
KieSession ksession = engine.getKieSession();

The prevous example requires a KIE base as the kbase parameter. You can use a kmodule.xml KJAR descriptor on the class path to buld the KIE base.

Building a KIE base from a kmodule.xml KJAR descriptor
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
KieBase kbase = kContainer.getKieBase("kbase");

A kmodule.xml descriptor file can include an attribute for resource packages to scan to find and deploy jBPM engine workflows.

Sample kmodule.xml descriptor file
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
  <kbase name="kbase" packages="com.sample"/>
</kmodule>

To control the persistence, you can use the RuntimeEnvironmentBuilder::entityManagerFactory methods.

Controlling configuration of persistence in the runtime manager
EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa");

RuntimeEnvironment runtimeEnv = RuntimeEnvironmentBuilder.Factory
        .get()
        .newDefaultBuilder()
        .entityManagerFactory(emf)
        .knowledgeBase(kbase)
        .get();

StatefulKnowledgeSession ksession = (StatefulKnowledgeSession) RuntimeManagerFactory.Factory.get()
        .newSingletonRuntimeManager(runtimeEnv)
        .getRuntimeEngine(EmptyContext.get())
        .getKieSession();

After creating the ksession KIE session in this example, you can call methods in ksession, for example, StartProcess(). The jBPM engine persists the runtime state in the configured data source.

You can restore a process instance from persistent storage by using the process instance ID. The runtime manager automatically re-creates the required session.

Re-creating a KIE session from the persistence database using a process instance ID
RuntimeEngine runtime = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId));

KieSession session = runtime.getKieSession();

10.6. Persisting process variables in a separate database schema in jBPM

When you create process variables to use within the processes that you define, jBPM stores those process variables as binary data in a default database schema. You can persist process variables in a separate database schema for greater flexibility in maintaining and implementing your process data.

For example, persisting your process variables in a separate database schema can help you perform the following tasks:

  • Maintain process variables in human-readable format

  • Make the variables available to services outside of jBPM

  • Clear the log of the default database tables in jBPM without losing process variable data

This procedure applies to process variables only. This procedure does not apply to case variables.
Prerequisites
  • You have defined processes in jBPM for which you want to implement variables.

  • If you want to persist variables in a database schema outside of jBPM, you have created a data source and the separate database schema that you want to use. For information about creating data sources, see Data Source Management.

Procedure
  1. In the data object file that you use as a process variable, add the following elements to configure variable persistence:

    Example Person.java object configured for variable persistence
    @javax.persistence.Entity  (1)
    @javax.persistence.Table(name = "Person")  (2)
    public class Person extends org.drools.persistence.jpa.marshaller.VariableEntity  (3)
    implements java.io.Serializable {  (4)
    
    	static final long serialVersionUID = 1L;
    
    	@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO, generator = "PERSON_ID_GENERATOR")
    	@javax.persistence.Id  (5)
    	@javax.persistence.SequenceGenerator(name = "PERSON_ID_GENERATOR", sequenceName = "PERSON_ID_SEQ")
    	private java.lang.Long id;
    
    	private java.lang.String name;
    
    	private java.lang.Integer age;
    
    	public Person() {
    	}
    
    	public java.lang.Long getId() {
    		return this.id;
    	}
    
    	public void setId(java.lang.Long id) {
    		this.id = id;
    	}
    
    	public java.lang.String getName() {
    		return this.name;
    	}
    
    	public void setName(java.lang.String name) {
    		this.name = name;
    	}
    
    	public java.lang.Integer getAge() {
    		return this.age;
    	}
    
    	public void setAge(java.lang.Integer age) {
    		this.age = age;
    	}
    
    	public Person(java.lang.Long id, java.lang.String name,
    			java.lang.Integer age) {
    		this.id = id;
    		this.name = name;
    		this.age = age;
    	}
    
    }
    1 Configures the data object as a persistence entity.
    2 Defines the database table name used for the data object.
    3 Creates a separate MappedVariable mapping table that maintains the relationship between this data object and the associated process instance. If you do not need this relationship maintained, you do not need to extend the VariableEntity class. Without this extension, the data object is still persisted, but contains no additional data.
    4 Configures the data object as a serializable object.
    5 Sets a persistence ID for the object.

    To make the data object persistable using Business Central, navigate to the data object file in your project, click the Persistence icon in the upper-right corner of the window, and configure the persistence behavior:

    persistence in central
    Figure 36. Persistence configuration in Business Central
  2. In the pom.xml file of your project, add the following dependency for persistence support. This dependency contains the VariableEntity class that you configured in your data object.

    Project dependency for persistence
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-persistence-jpa</artifactId>
      <version>${jbpm.version}</version>
      <scope>provided</scope>
    </dependency>
  3. In the ~/META-INF/kie-deployment-descriptor.xml file of your project, configure the JPA marshalling strategy and a persistence unit to be used with the marshaller. The JPA marshalling strategy and persistence unit are required for objects defined as entities.

    JPA marshaller and persistence unit configured in the kie-deployment-descriptor.xml file
    <marshalling-strategy>
      <resolver>mvel</resolver>
      <identifier>new org.drools.persistence.jpa.marshaller.JPAPlaceholderResolverStrategy("myPersistenceUnit", classLoader)</identifier>
      <parameters/>
    </marshalling-strategy>
  4. In the ~/META-INF directory of your project, create a persistence.xml file that specifies in which data source you want to persist the process variable:

    Example persistence.xml file with data source configuration
    <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">
        <persistence-unit name="myPersistenceUnit" transaction-type="JTA">
            <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
            <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>  (1)
            <class>org.space.example.Person</class>
            <exclude-unlisted-classes>true</exclude-unlisted-classes>
            <properties>
                <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
                <property name="hibernate.max_fetch_depth" value="3"/>
                <property name="hibernate.hbm2ddl.auto" value="update"/>
                <property name="hibernate.show_sql" value="true"/>
                <property name="hibernate.id.new_generator_mappings" value="false"/>
                <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/>
            </properties>
        </persistence-unit>
    </persistence>
    1 Sets the data source in which the process variable is persisted

    To configure the marshalling strategy, persistence unit, and data source using Business Central, navigate to project SettingsDeploymentsMarshalling Strategies and to project SettingsPersistence:

    jpa marhsalling strategy
    Figure 37. JPA marshaller configuration in Business Central
    persistence unit
    Figure 38. Persistence unit and data source configuration in Business Central

Business Central

How to use the web-based Business Central application

11. Business Central (General)

11.1. Installation

11.1.1. War installation

Use the war from the Business Central distribution zip that corresponds to your application server. The differences between these war files are mainly superficial. For example, some JARs might be excluded if the application server already supplies them.

  • eap7: tailored for Red Hat JBoss Enterprise Application Platform 7

  • wildfly14: tailored for Wildfly 14

11.1.2. Business Central data

Business Central stores its data, by default in the directory $WORKING_DIRECTORY/.niogit, for example wildfly-14.0.1.Final/bin/.niogit, but it can be overridden with the system property-Dorg.uberfire.nio.git.dir.

In production, make sure to back up the Business Central data directory.

11.1.3. Troubleshooting

11.1.3.1. Loading.. does not disappear and Business Central fails to show

There have been reports that Firewalls in between the server and the browser can interfere with Server Sent Events (SSE) used by Business Central.

The issue results in the "Loading…​" spinner remaining visible and Business Central failing to materialize.

The workaround is to disable the Business Central’s use of Server Sent Events by adding file /WEB-INF/classes/ErraiService.properties to the exploded WAR containing the value errai.bus.enable_sse_support=false. Re-package the WAR and re-deploy.

Some Users have also reported disabling Server Sent Events does not resolve the issue. The solution found to work is to configure the JVM to use a different Entropy Gathering Device on Linux for SecureRandom. This can be configured by setting System Property java.security.egd to file:/dev/./urandom. See this Stack Overflow post for details.

Please note however this affects the JVM’s random number generation and may present other challenges where strong cryptography is required. Configure with caution.

11.1.3.2. Not able to clone Business Central Git repository using ssh protocol.

Git clients using ssh to interact with the Git server that is bundled with Business Central are authenticated and authorized to perform git commands by the security API that is part of the Uberfire backend server. When using an LDAP security realm, some git clients were not being authorized as expected. This was due to the fact that for non-web clients such as Git via ssh, the principal (i.e., user or group) name assigned to a user by the application server’s user registry is the more complex DN associated to that principal by LDAP. The logic of the Uberfire backend server looked for on exact match of roles allowed with the principal name returned and therefore failed.

It is now possible to control the role-principal matching via the system property

org.uberfire.ldap.regex.role_mapper

which takes as its value a Regex pattern to be applied when matching LDAP principal to role names. The pattern must contain the literal word variable 'role'. During authorization the variable is replaced by each of the allow application roles. If the pattern is matched the role is added to the user.

For instance, if the DN for the admin group in LDAP is

DN: cn=admin,ou=groups,dc=example,dc=com

and its intended role is admin, then setting org.uberfire.ldap.regex.role_mapper with value

cn[\\ ]*=[\\ ]*role

will find a match on role 'admin'.

11.2. Business Central system properties

The Business Central system properties listed in this section are passed to standalone*.xml files.

Git directory

Use the following properties to set the location and name for the Business Central Git directory:

  • org.uberfire.nio.git.dir: Location of the Business Central Git directory.

  • org.uberfire.nio.git.dirname: Name of the Business Central Git directory. Default value: .niogit.

  • org.uberfire.nio.git.ketch: Enables or disables Git ketch.

  • org.uberfire.nio.git.hooks: Location of the Git hooks directory.

Git over HTTP

Use the following properties to configure access to the Git repository over HTTP:

  • org.uberfire.nio.git.proxy.ssh.over.http: Specifies whether SSH should use an HTTP proxy. Default value: false.

  • http.proxyHost: Defines the host name of the HTTP proxy. Default value: null.

  • http.proxyPort: Defines the host port (integer value) of the HTTP proxy. Default value: null.

  • http.proxyUser: Defines the user name of the HTTP proxy.

  • http.proxyPassword: Defines the user password of the HTTP proxy.

  • org.uberfire.nio.git.http.enabled: Enables or disables the HTTP daemon. Default value: true.

  • org.uberfire.nio.git.http.host: If the HTTP daemon is enabled, it uses this property as the host identifier. This is an informative property that is used to display how to access the Git repository over HTTP. The HTTP still relies on the servlet container. Default value: localhost.

  • org.uberfire.nio.git.http.hostname: If the HTTP daemon is enabled, it uses this property as the host name identifier. This is an informative property that is used to display how to access the Git repository over HTTP. The HTTP still relies on the servlet container. Default value: localhost.

  • org.uberfire.nio.git.http.port: If the HTTP daemon is enabled, it uses this property as the port number. This is an informative property that is used to display how to access the Git repository over HTTP. The HTTP still relies on the servlet container. Default value: 8080.

Git over HTTPS

Use the following properties to configure access to the Git repository over HTTPS:

  • org.uberfire.nio.git.proxy.ssh.over.https: Specifies whether SSH uses an HTTPS proxy. Default value: false.

  • https.proxyHost: Defines the host name of the HTTPS proxy. Default value: null.

  • https.proxyPort: Defines the host port (integer value) of the HTTPS proxy. Default value: null.

  • https.proxyUser: Defines the user name of the HTTPS proxy.

  • https.proxyPassword: Defines the user password of the HTTPS proxy.

  • user.dir: Location of the user directory.

  • org.uberfire.nio.git.https.enabled: Enables or disables the HTTPS daemon. Default value: false

  • org.uberfire.nio.git.https.host: If the HTTPS daemon is enabled, it uses this property as the host identifier. This is an informative property that is used to display how to access the Git repository over HTTPS. The HTTPS still relies on the servlet container. Default value: localhost.

  • org.uberfire.nio.git.https.hostname: If the HTTPS daemon is enabled, it uses this property as the host name identifier. This is an informative property that is used to display how to access the Git repository over HTTPS. The HTTPS still relies on the servlet container. Default value: localhost.

  • org.uberfire.nio.git.https.port: If the HTTPS daemon is enabled, it uses this property as the port number. This is an informative property that is used to display how to access the Git repository over HTTPS. The HTTPS still relies on the servlet container. Default value: 8080.

JGit
  • org.uberfire.nio.jgit.cache.instances: Defines the JGit cache size.

  • org.uberfire.nio.jgit.cache.overflow.cleanup.size: Defines the JGit cache overflow cleanup size.

  • org.uberfire.nio.jgit.remove.eldest.iterations: Enables or disables whether to remove eldest JGit iterations.

  • org.uberfire.nio.jgit.cache.evict.threshold.duration: Defines the JGit evict threshold duration.

  • org.uberfire.nio.jgit.cache.evict.threshold.time.unit: Defines the JGit evict threshold time unit.

Git daemon

Use the following properties to enable and configure the Git daemon:

  • org.uberfire.nio.git.daemon.enabled: Enables or disables the Git daemon. Default value: true.

  • org.uberfire.nio.git.daemon.host: If the Git daemon is enabled, it uses this property as the local host identifier. Default value: localhost.

  • org.uberfire.nio.git.daemon.hostname: If the Git daemon is enabled, it uses this property as the local host name identifier. Default value: localhost

  • org.uberfire.nio.git.daemon.port: If the Git daemon is enabled, it uses this property as the port number. Default value: 9418.

  • org.uberfire.nio.git.http.sslVerify: Enables or disables SSL certificate checking for Git repositories. Default value: true.

    If the default or assigned port is already in use, a new port is automatically selected. Ensure that the ports are available and check the log for more information.
Git SSH

Use the following properties to enable and configure the Git SSH daemon:

  • org.uberfire.nio.git.ssh.enabled: Enables or disables the SSH daemon. Default value: true.

  • org.uberfire.nio.git.ssh.host: If the SSH daemon enabled, it uses this property as the local host identifier. Default value: localhost.

  • org.uberfire.nio.git.ssh.hostname: If the SSH daemon is enabled, it uses this property as local host name identifier. Default value: localhost.

  • org.uberfire.nio.git.ssh.port: If the SSH daemon is enabled, it uses this property as the port number. Default value: 8001.

    If the default or assigned port is already in use, a new port is automatically selected. Ensure that the ports are available and check the log for more information.
  • org.uberfire.nio.git.ssh.cert.dir: Location of the .security directory where local certificates are stored. Default value: Working directory.

  • org.uberfire.nio.git.ssh.idle.timeout: Sets the SSH idle timeout.

  • org.uberfire.nio.git.ssh.passphrase: Pass phrase used to access the public key store of your operating system when cloning git repositories with SCP style URLs. Example: git@github.com:user/repository.git.

  • org.uberfire.nio.git.ssh.algorithm: Algorithm used by SSH. Default value: RSA.

  • org.uberfire.nio.git.gc.limit: Sets the GC limit.

  • org.uberfire.nio.git.ssh.ciphers: A comma-separated string of ciphers. The available ciphers are aes128-ctr, aes192-ctr, aes256-ctr, arcfour128, arcfour256, aes192-cbc, aes256-cbc. If the property is not used, all available ciphers are loaded.

  • org.uberfire.nio.git.ssh.macs: A comma-separated string of message authentication codes (MACs). The available MACs are hmac-md5, hmac-md5-96, hmac-sha1, hmac-sha1-96, hmac-sha2-256, hmac-sha2-512. If the property is not used, all available MACs are loaded.

    If you plan to use RSA or any algorithm other than DSA, make sure you set up your application server to use the Bouncy Castle JCE library.
KIE Server nodes and jBPM controller

Use the following properties to configure the connections with the KIE Server nodes from the jBPM controller:

  • org.kie.server.controller: The URL is used to connect to the jBPM controller. For example, ws://localhost:8080/business-central/websocket/controller.

  • org.kie.server.user: User name used to connect to the KIE Server nodes from the jBPM controller. This property is only required when using this Business Central installation as a jBPM controller.

  • org.kie.server.pwd: Password used to connect to the KIE Server nodes from the jBPM controller. This property is only required when using this Business Central installation as a jBPM controller.

Maven and miscellaneous

Use the following properties to configure Maven and other miscellaneous functions:

  • kie.maven.offline.force: Forces Maven to behave as if offline. If true, disables online dependency resolution. Default value: false.

    Use this property for Business Central only. If you share a runtime environment with any other component, isolate the configuration and apply it only to Business Central.
  • org.uberfire.gzip.enable: Enables or disables Gzip compression on the GzipFilter compression filter. Default value: true.

  • org.kie.workbench.profile: Selects the Business Central profile. Possible values are FULL or PLANNER_AND_RULES. A prefix FULL_ sets the profile and hides the profile preferences from the administrator preferences. Default value: FULL

  • org.appformer.m2repo.url: Business Central uses the default location of the Maven repository when looking for dependencies. It directs to the Maven repository inside Business Central, for example, http://localhost:8080/business-central/maven2. Set this property before starting Business Central. Default value: File path to the inner m2 repository.

  • appformer.ssh.keystore: Defines the custom SSH keystore to be used with Business Central by specifying a class name. If the property is not available, the default SSH keystore is used.

  • appformer.ssh.keys.storage.folder: When using the default SSH keystore, this property defines the storage folder for the user’s SSH public keys. If the property is not available, the keys are stored in the Business Central .security folder.

  • appformer.experimental.features: Enables the experimental features framework. Default value: false.

  • org.kie.demo: Enables an external clone of a demo application from GitHub.

  • org.uberfire.metadata.index.dir: Place where the Lucene .index directory is stored. Default value: Working directory.

  • org.uberfire.ldap.regex.role_mapper: Regex pattern used to map LDAP principal names to the application role name. Note that the variable role must be a part of the pattern as the application role name substitutes the variable role when matching a principle value and role name.

  • org.uberfire.sys.repo.monitor.disabled: Disables the configuration monitor. Do not disable unless you are sure. Default value: false.

  • org.uberfire.secure.key: Password used by password encryption. Default value: org.uberfire.admin.

  • org.uberfire.secure.alg: Crypto algorithm used by password encryption. Default value: PBEWithMD5AndDES.

  • org.uberfire.domain: Security-domain name used by uberfire. Default value: ApplicationRealm.

  • org.guvnor.m2repo.dir: Place where the Maven repository folder is stored. Default value: <working-directory>/repositories/kie.

  • org.guvnor.project.gav.check.disabled: Disables group ID, artifact ID, and version (GAV) checks. Default value: false.

  • org.kie.build.disable-project-explorer: Disables automatic build of a selected project in Project Explorer. Default value: false.

  • org.kie.builder.cache.size: Defines the cache size of the project builder. Default value: 20.

  • org.kie.verification.disable-dtable-realtime-verification: Disables the real-time validation and verification of decision tables. Default value: false.

jBPM controller

Use the following properties to configure how to connect to the jBPM controller:

  • org.kie.workbench.controller: The URL used to connect to the jBPM controller, for example, ws://localhost:8080/kie-server-controller/websocket/controller.

  • org.kie.workbench.controller.user: The jBPM controller user. Default value: kieserver.

  • org.kie.workbench.controller.pwd: The jBPM controller password. Default value: kieserver1!.

  • org.kie.workbench.controller.token: The token string used to connect to the jBPM controller.

    For more information about how to use token-based authentication, see Using token-based authentication.
Java Cryptography Extension KeyStore (JCEKS)

Use the following properties to configure JCEKS:

  • kie.keystore.keyStoreURL: The URL used to load a Java Cryptography Extension KeyStore (JCEKS). For example, file:///home/kie/keystores/keystore.jceks.

  • kie.keystore.keyStorePwd: The password used for the JCEKS.

  • kie.keystore.key.ctrl.alias: The alias of the key for the default REST jBPM controller.

  • kie.keystore.key.ctrl.pwd: The password of the alias for the default REST jBPM controller.

Rendering

Use the following properties to switch between Business Central and KIE Server rendered forms:

  • org.jbpm.wb.forms.renderer.ext: Switches the form rendering between Business Central and KIE Server. By default, the form rendering is performed by Business Central. Default value: false.

  • org.jbpm.wb.forms.renderer.name: Enables you to switch between Business Central and KIE Server rendered forms. Default value: workbench.

11.3. Quick Start

These steps help you get started with minimum of effort.

They should not be a substitute for reading the documentation in full.

11.3.1. Importing examples

Import Examples - Quick install examples

If Business Central is empty you are shown an empty Space page. Clicking "Try Samples" button below will show the examples that are available.

QuickStart example1

Once "Try Samples" page opens, you can select one or more examples and click "Ok".

QuickStart example2

If Business Central already contains Projects the examples can be imported with the "Try Samples" button found from the menu.

QuickStart import with pre existing projects

11.3.2. Add Project

Alternatively, to importing an example, a new empty project can be created from the Space page with "Add Project".

QuickStart example1
Figure 39. New Project button

Give the Project a name and optional description.

QuickStart new project wizard
Figure 40. Giving Project a name

11.3.3. Define Data Model

After a Project has been created you need to define Types to be used by your rules.

Select "Data Object" from the "Add Asset" menu.

You can also use types contained in existing JARs.

Please consult the full documentation for details.

QuickStart create a data model
Figure 41. Creating "Data Object"

Set the name and select a package for the new type.

QuickStart create data object popup
Figure 42. Creating a new type

Click "+ add field" button and set a field name and type and click "Create" to create a field for the type.

QuickStart create field
Figure 43. Click "Create" and add the field

Click "Save" to update the model.

QuickStart confirm save
Figure 44. Clicking "Save"

11.3.4. Define Rule

Select "DRL file" (for example) from the "Add Asset" menu.

QuickStart create drl file
Figure 45. Selecting "DRL file" from the "Add Asset" menu

Enter a file name for the new rule.

Make sure you select the same package as the rule had. It is possible to have rules and data models in different packages, but let’s keep things simple for demo purposes.

QuickStart new rule popup
Figure 46. Entering a file name for rule

Enter a definition for the rule.

The definition process differs from asset type to asset type.

The full documentation has details about the different editors.

QuickStart writing a rule
Figure 47. Defining a rule

Once the rule has been defined it will need to be saved in the same way we saved the model.

11.3.5. Build and Deploy

Once rules have been defined within a project; the project can be built and deployed to the Business Central’s Maven Artifact Repository.

To build a project select the "Build & Deploy" from the Project Authoring.

QuickStart build and deploy
Figure 48. Building a project

Click "Build & Deploy" to build the project and deploy it to the Business Central’s Maven Artifact Repository.

When you select Build & Deploy Business Central will deploy to any repositories defined in the Dependency Management section of the pom in your Business Central project. You can edit the pom.xml file associated with your Business Central project under the Repository View of the project explorer. Details on dependency management in maven can be found here : http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

If there are errors during the build process they will be reported in the "Messages" panel.

Now the project has been built and deployed; it can be referenced from your own projects as any other Maven Artifact.

The full documentation contains details about integrating projects with your own applications.

11.4. Configuration

11.4.1. Basic user management

Business Central authenticates its users against the application server’s authentication and authorization (JAAS).

On JBoss EAP and WildFly, add a user with the script $JBOSS_HOME/bin/add-user.sh (or .bat):

$ ./add-user.sh
// Type: Application User
// Realm: empty (defaults to ApplicationRealm)
// Role: admin

There is no need to restart the application server.

11.4.2. Roles

Business Central uses the following roles:

  • admin

  • analyst

  • developer

  • manager

  • user

11.4.2.1. Admin

Administrates the BPMS system.

  • Manages users

  • Manages VFS Repositories

  • Has full access to make any necessary changes

11.4.2.2. Developer

Developer can do almost everything admin can do, except clone repositories.

  • Manages rules, models, process flows, forms and dashboards

  • Manages the asset repository

  • Can create, build and deploy projects

  • Can use the JBDS connection to view processes

11.4.2.3. Analyst

Analyst is a weaker version of developer and does not have access to the asset repository or the ability to deploy projects.

11.4.2.4. Business user

Daily user of the system to take actions on business tasks that are required for the processes to continue forward. Works primarily with the task lists.

  • Does process management

  • Handles tasks and dashboards

11.4.2.5. Manager/Viewer-only User

Viewer of the system that is interested in statistics around the business processes and their performance, business indicators, and other reporting of the system and people who interact with the system.

  • Only has access to dashboards

11.5. Introduction

11.5.1. Log in and log out

Create a user with the role admin and log in with those credentials.

After successfully logging in, the account user name is displayed at the top right. Click it to review the roles of the current account.

11.5.2. Home screen

After logging in, the home screen shows. The actual content of the home screen depends on the Business Central variant (Drools, jBPM, …​).

home

11.5.3. Business Central overview

Business Central is structured with Spaces and Projects:

workbenchStructureOverview
11.5.3.1. Space

Spaces are useful to model departments and divisions.

A Space can hold multiple Projects.

Space
11.5.3.2. Project

Projects are the place where assets are stored and each project belongs to a single Space.

Projects are in fact a Virtual File System based storage, that by default uses GIT as backend. Such setup allows Business Central to work with multiple backends and, at the same time, take full advantage of backend specifics features like in GIT case versioning, branching and even external access.

A new Project can be created from scratch or cloned from an existing repository.

One of the biggest advantages of using GIT as backend is the ability to clone a repository from external and use your preferred tools to edit and build your assets.

Never clone your repositories directly from .niogit directory.

11.5.4. Business Central user interface concepts

Business Central consists of different logical entities:

  • Part

    A Part is a screen or editor with which the user can interact to perform operations.

    Example Parts are "Project Explorer", "Project Editor", "Guided Rule Editor" etc.

  • Page

    A perspective is a logical grouping of related Panels and Parts. A perspective is usually named as page, since it is a term far more familiar to end users whereas a perspective is more developer oriented. Notice however, Business Central supports both developer created pages and those created by end users from the page builder (aka Content Management) tooling but, generally speaking, page is used to refer to both of them.

    The user can switch between pages by clicking on one of the top-level menu items; such as "Home", "Authoring", "Deploy" etc.

11.6. Changing the layout

11.6.1. Resizing

Move the mouse pointer over the panel splitter (a grey horizontal or vertical line in between panels).

The cursor will by changing indicate it is positioned correctly over the splitter. Press and hold the left mouse button and drag the splitter to the required position; then release the left mouse button.

11.7. Authoring (General)

11.7.1. Artifact Repository

Projects often need external artifacts in their classpath in order to build, for example a domain model JARs. The artifact repository holds those artifacts.

The Artifact Repository is a full blown Maven repository. It follows the semantics of a Maven remote repository: all snapshots are timestamped. But it is often stored on the local hard drive.

By default the artifact repository is stored under $WORKING_DIRECTORY/repositories/kie, but it can be overridden with the system property-Dorg.guvnor.m2repo.dir. There is only 1 Maven repository per installation.

The Artifact Repository screen shows a list of the artifacts in the Maven repository:

mavenRepositoryExplorer

To add a new artifact to that Maven repository, either:

  • Use the upload button and select a JAR. If the JAR contains a POM file under META-INF/maven (which every JAR build by Maven has), no further information is needed. Otherwise, a groupId, artifactId and version need to be given too.

mavenRepositoryUpload
  • Using Maven, mvn deploy to that Maven repository. Refresh the list to make it show up.

This remote Maven repository is relatively simple. It does not support proxying, mirroring, …​ like Nexus or Archiva.

11.7.2. Asset Editor

The Asset Editor is the principle component of the Business Central user interface. It consists of two main views Editor and Overview.

  • The views

    AssetEditor edit
    Figure 49. The Asset Editor - Editor tab
    • A : The editing area - exactly what form the editor takes depends on the Asset type. An asset can only be edited by one user at a time to avoid conflicts. When a user begins to edit an asset, a lock will automatically be acquired. This is indicated by a lock symbol appearing on the asset title bar as well as in the project explorer view (see Project Explorer for details). If a user starts editing an already locked asset a pop-up notification will appear to inform the user that the asset can’t currently be edited, as it is being worked on by another user. Changes will be prevented until the editing user saves or closes the asset, or logs out of Business Central. Session timeouts will also cause locks to be released. Every user further has the option to force a lock release, if required (see the Metadata section below).

    • B : This menu bar contains various actions for the Asset; such as Save, Rename, Copy etc. Note that saving, renaming and deleting are deactivated if the asset is locked by a different user.

    • C : Different views for asset content or asset information.

      • Editor shows the main editor for the asset

      • Overview contains the metadata and conversation views for this editor. Explained in more detail below.

      • Source shows the asset in plain DRL. Note: This tab is only visible if the asset content can be generated into DRL.

      • Data Objects contains the model available for authoring. By default only Data Objects that reside within the same package as the asset are available for authoring. Data Objects outside of this package can be imported to become available for authoring the asset.

    AssetEditor dataobjects
    Figure 50. The Asset Editor - Data Objects tab
  • Overview

    • A : General information about the asset and the asset’s description.

      "Type:" The format name of the type of Asset.

      "Description:" Description for the asset.

      "Used in projects:" Names the projects where this rule is used.

      "Last Modified:" Who made the last change and when.

      "Created on:" Who created the asset and when.

    • B : Version history for the asset. Selecting a version loads the selected version into this editor.

    • C : Meta data (from the "Dublin Core" standard)

    • D : Comments regarding the development of the Asset can be recorded here.

Overview
Figure 51. The Asset Editor - Overview tab
  • Metadata

    • A : Meta data:-

      "Tags:" A tagging system for grouping the assets.

      "Note:" A comment made when the Asset was last updated (i.e. why a change was made)

      "URI:" URI to the asset inside the Git repository.

      "Subject/Type/External link/Source" : Other miscellaneous meta data for the Asset.

      "Lock status" : Shows the lock status of the asset and, if locked, allows to force unlocking the asset.

Metadata
Figure 52. The Metadata tab
  • Locking

    Business Central supports pessimistic locking of assets. When one User starts editing an asset it is locked to change by other Users. The lock is held until a period of inactivity lapses, the Editor is closed or the application stopped and restarted. Locks can also be forcibly removed on the MetaData section of the Overview tab.

    A "padlock" icon is shown in the Editor’s title bar and beside the asset in the Project Explorer when an asset is locked.

    AssetEditor locked
    Figure 53. The Asset Editor - Locked assets cannot be edited by other users

11.7.3. Tags Editor

Tags allow assets to be labelled with any number of tags that you define. These tags can be used to filter assets on the Project Explorer enabling "Tag filtering".

11.7.3.1. Creating Tags

To create tags you simply have to write them on the Tags input and press the "Add new Tag/s" button. The Tag Editor allows creating tags one by one or writing more than one separated with a white space.

CreatingTags
Figure 54. Creating Tags

Once you created new Tags they will appear over the Editor allowing you to remove them by pressing on them if you want.

ExistingTags
Figure 55. Existing Tags

11.7.4. Project Explorer

The Project Explorer provides the ability to browse files inside the current Project. The Project Explorer can be accessed from the left side when an Asset Editor is open.

11.7.4.1. Initial view

If a file is currently being edited by another user, a lock symbol will be displayed in front of the file name. The symbol is blue in case the lock is owned by the currently authenticated user, otherwise black. Moving the mouse pointer over the lock symbol will display a tooltip providing the name of the user who is currently editing the file (and therefore owning the lock). To learn more about locking see Asset Editor for details.

ProjectExplorer Project Expanded
Figure 56. Expanded asset group
11.7.4.2. Different views

Project Explorer supports multiple views.

  • Project View

    A simplified view of the underlying project structure. Certain system files are hidden from view.

  • Repository View

    A complete view of the underlying project structure including all files; either user-defined or system generated.

Views can be selected by clicking on the icon within the Project Explorer, as shown below.

Both Project and Repository Views can be further refined by selecting either "Show as Folders" or "Show as Links".

ProjectExplorer Switching View
Figure 57. Switching view
Repository View examples
ProjectExplorer Repository Folders
Figure 58. Repository View - Folders
ProjectExplorer Repository Links
Figure 59. Repository View - Links
11.7.4.3. Download Project or Repository

"Download Project" or "Download Repository" make it possible to download the project or the repository as a ZIP file.

ProjectExplorer Downloads
Figure 60. Repository and Project Downloads
11.7.4.4. Filtering by Tag

Viewing elements in packages that contain a lot of assets easily is now made possible by enabling the Tag filter, which allows you to filter assets by their tags.

To see how to add tags to an asset look at: Tags Editor

ProjectExplorer Tag Filter Enable
Figure 61. Enabling Filter by Tag
ProjectExplorer Tag Filter Show
Figure 62. Filter by Tag
ProjectExplorer Tag Filter Working
Figure 63. Filtering by Tag
11.7.4.5. Copy, Rename, Delete and Download Actions

Copy, rename and delete actions are available on Links mode, for packages in of Project View and for files and directories in the Repository View. Download action is available for directories. Download option downloads the selected the selected directory as a zip file.

  • A : Copy

  • B : Rename

  • C : Delete

  • D : Download

ProjectExplorer Project Links Copy Rename Delete
Figure 64. Project View - Package actions

Business Central roadmap includes a refactoring and an impact analysis tool, but currently doesn’t have it. Until both tools are provided make sure that your changes (copy/rename/delete) on packages, files or directories doesn’t have a major impact on your project.

In cases that your change had an unexpected impact, Business Central enables you to restore your repository using the Repository editor.

Files locked by other users as well as directories that contain such files cannot be renamed or deleted until the corresponding locks are released. If that is the case the rename and delete symbols will be deactivated. To learn more about locking see Asset Editor for details.

ProjectExplorer Delete NotAllowed

11.7.5. Project Editor

The Project Editor screen can be accessed from Project Explorer. Project Editor shows the settings for the currently active project.

Unlike most of the Business Central editors, project editor edits more than one file. Showing everything that is needed for configuring the KIE project in one place.

project editor menu
Figure 65. Project Screen and the different views
11.7.5.1. Build & Deploy

Build & Deploy builds the current project and deploys the KJAR into the Business Central internal Maven repository.

11.7.5.2. Project Settings

Project Settings edits the pom.xml file used by Maven.

Project General Settings

General settings provide tools for project name and GAV-data (Group, Artifact, Version). GAV values are used as identifiers to differentiate projects and versions of the same project.

general settings
Figure 66. Project Settings
Dependencies

The project may have any number of either internal or external dependencies. Dependency is a project that has been built and deployed to a Maven repository. Internal dependencies are projects built and deployed in the same Business Central as the project. External dependencies are retrieved from repositories outside of the current Business Central. Each dependency uses the GAV-values to specify the project name and version that is used by the project.

dependencies
Figure 67. Dependencies
Package Name White List

Classes and declared types in white listed packages show up as Data Objects that can be imported in assets. The full list is stored in package-name-white-list file that is stored in each project root.

Package white list has three modes:

  • All packages included: Every package defined in this jar is white listed.

  • Packages not included: None of the packages listed in this jar are white listed.

  • Some packages included: Only part of the packages in the jar are white listed.

Metadata

Metadata for the pom.xml file.

11.7.5.3. KIE base Settings

KIE base Settings edits the kmodule.xml file used by Drools.

kmodule
Figure 68. KIE base Settings

For more information about the KIE base properties, check the Drools Expert documentation for kmodule.xml.

KIE bases and sessions

KIE bases and sessions lists the KIE bases and the KIE sessions specified for the project.

KIE base list

Lists all the KIE bases by name. Only one KIE base can be set as default.

KIE base properties

KIE base can include other KIE bases. The models, rules and any other content in the included KIE base will be visible and usable by the currently selected KIE base.

Rules and models are stored in packages. The packages property specifies what packages are included into this KIE base.

Equals behavior is explained in the Drools Expert part of the documentation.

Event processing mode is explained in the Drools Fusion part of the documentation.

KIE sessions

The table lists all the KIE sessions in the selected KIE base. There can be only one default of each type. The types are stateless and stateful. Clicking the pen-icon opens a popup that shows more properties for the KIE session.

Metadata

Metadata for the kmodule.xml

11.7.5.4. Imports

Settings edits the project.imports file used by the Business Central editors.

ExternalDataObjects
Figure 69. Imports
External Data Objects

Data Objects provided by the Java Runtime environment may need to be registered to be available to rule authoring where such Data Objects are not implicitly available as part of an existing Data Object defined within the Business Central or a Project dependency. For example an Author may want to define a rule that checks for java.util.ArrayList in Working Memory. If a domain Data Object has a field of type java.util.ArrayList, then there is no need to create a registration.

Metadata

Metadata for the project.imports file.

11.7.5.5. Duplicate GAV detection

When performing any of the following operations a check is now made against all Maven Repositories, resolved for the Project, for whether the Project’s GroupId, ArtifactId and Version pre-exist. If a clash is found the operation is prevented; although this can be overridden by Users with the admin role.

The feature can be disabled by setting the System Property org.guvnor.project.gav.check.disabled to true.

Resolved repositories are those discovered in:-

  • The Project’s POM<repositories> section (or any parent POM).

  • The Project’s POM<distributionManagement> section.

  • Maven’s global settings.xml configuration file.

Affected operations:-

  • Creation of new Managed Repositories.

  • Saving a Project definition with the Project Editor.

  • Adding new Modules to a Managed Multi-Module Repository.

  • Saving the pom.xml file.

  • Build & installing a Project with the Project Editor.

  • Build & deploying a Project with the Project Editor.

  • Asset Management operations building, installing or deploying Projects.

  • REST operations creating, installing or deploying Projects.

Users with the Admin role can override the list of Repositories checked using the "Repositories" settings in the Project Editor.

validation menu item
Figure 70. Project Editor - Viewing resolved Repositories
MavenRepositories2
Figure 71. Project Editor - The list of resolved Repositories
MavenRepositories3
Figure 72. Duplicate GAV detected

11.7.6. Validation

Business Central provides a common and consistent service for users to understand whether files authored within the environment are valid.

11.7.6.1. Problem Panel

The Problems Panel shows real-time validation results of assets within a Project.

When a Project is selected from the Project Explorer the Problems Panel will refresh with validation results of the chosen Project.

When files are created, saved or deleted the Problems Panel content will update to show either new validation errors, or remove existing if a file was deleted.

workbench problems panel
Figure 73. The Problems Panel
11.7.6.2. On demand validation

It is not always desirable to save a file in order to determine whether it is in a valid state.

All of the file editors provide the ability to validate the content before it is saved.

Clicking on the 'Validate' button shows validation errors, if any.

workbench validation

11.7.7. Data Modeller

11.7.7.1. First steps to create a data model

By default, a data model is always constrained to the context of a project. For the purpose of this tutorial, we will assume that a correctly configured project already exists and the authoring page is open.

To start the creation of a data model inside a project, take the following steps:

  1. From the home panel, select the Design page and select the given project.

    authoring
    Figure 74. Go to authoring page and select a project
  2. Open the Data Modeller tool by clicking on a Data Object file, or using the "Add Asset → Data Object" menu option. Set Data Object name to "PurchaseOrder" and click Ok.

    open data model
    Figure 75. Click a Data Object

This will start up the Data Modeller tool, which has the following general aspect:

overview
Figure 76. Data modeller overview

The "Editor" tab is divided into the following sections:

  • The new field section is dedicated to the creation of new fields, and is opened when the "add field" button is pressed.

    create new field
    Figure 77. New field creation
  • The Data Object’s "field browser" section displays a list with the data object fields.

    data object field browser
    Figure 78. The Data Object’s field browser
  • The "Data Object / Field general properties" section. This is the rightmost section of the Data Modeller editor and visualizes the "Data Object" or "Field" general properties, depending on user selection.

    Data Object general properties can be selected by clicking on the Data Object Selector.

    data object selector
    Figure 79. Data Object selector
    data object general properties
    Figure 80. Data Object general properties

    Field general properties can be selected by clicking on a field.

field selector
Figure 81. Field selector
field general properties
Figure 82. Field general properties
  • On the right side of Business Central a new "Tool Bar" is provided that enables the selection of different context sensitive tool windows that will let the user do domain specific configurations. Currently four tool windows are provided for the following domains "Drools & jBPM", "OptaPlanner", "Persistence" and "Advanced" configurations.

    tool window selector
    Figure 83. Data modeller Tool Bar
    data object drools tool window
    Figure 84. Drools & jBPM tool window
    data object optaplanner tool window
    Figure 85. OptaPlanner tool window

    To see and use the OptaPlanner tool window, the user needs to have the role plannermgmt.

    data object persistence tool window
    Figure 86. Persistence tool window
    data object or field advanced tool window
    Figure 87. Advanced tool window

The "Source" tab shows an editor that allows the visualization and modification of the generated java code.

  • Round trip between the "Editor" and "Source" tabs is possible, and also source code preservation is provided. It means that no matter where the Java code was generated (e.g. Eclipse, Data modeller), the data modeller will only update the necessary code blocks to maintain the model updated.

    source editor tab
    Figure 88. Source editor

The "Overview" tab shows the standard metadata and version information as the other workbench editors.

11.7.7.2. Data Objects

A data model consists of data objects which are a logical representation of some real-world data. Such data objects have a fixed set of modeller (or application-owned) properties, such as its internal identifier, a label, description, package etc. Besides those, a data object also has a variable set of user-defined fields, which are an abstraction of a real-world property of the type of data that this logical data object represents.

Creating a data object can be achieved using the Business Central "New Item - Data Object" menu option.

create new data object
Figure 89. New Data Object menu option

Both resource name and location are mandatory parameters. When the "Ok" button is pressed a new Java file will be created and a new editor instance will be opened for the file edition. The optional "Persistable" attribute will add by default configurations on the data object in order to make it a JPA entity. Use this option if your jBPM project needs to store data object’s information in a database.

11.7.7.3. Properties & relationships

Once the data object has been created, it now has to be completed by adding user-defined properties to its definition. This can be achieved by pressing the "add field" button. The "New Field" dialog will be opened and the new field can be created by pressing the "Create" button. The "Create and continue" button will also add the new field to the Data Object, but won’t close the dialog. In this way multiple fields can be created avoiding the popup opening multiple times. The following fields can (or must) be filled out:

  • The field’s internal identifier (mandatory). The value of this field must be unique per data object, i.e. if the proposed identifier already exists within current data object, an error message will be displayed.

  • A label (optional): as with the data object definition, the user can define a user-friendly label for the data object field which is about to be created. This has no further implications on how fields from objects of this data object will be treated. If a label is defined, then this is how the field will be displayed throughout the data modeller tool.

  • A field type (mandatory): each data object field needs to be assigned with a type.

    This type can be either of the following:

    1. A 'primitive java object' type: these include most of the object equivalents of the standard Java primitive types, such as Boolean, Short, Float, etc, as well as String, Date, BigDecimal and BigInteger.

      create field with primitive type
      Figure 90. Primitive object field types
    2. A 'data object' type: any user defined data object automatically becomes a candidate to be defined as a field type of another data object, thus enabling the creation of relationships between them. A data object field can be created either in 'single' or in 'multiple' form, the latter implying that the field will be defined as a collection of this type, which will be indicated by selecting "List" checkbox.

types entity
Figure 91. Data object field types
  1. A 'primitive java' type: these include java primitive types byte, short, int, long, float, double, char and boolean.

types primitive
Figure 92. Primitive field types

When finished introducing the initial information for a new field, clicking the 'Create' button will add the newly created field to the end of the data object’s fields table below:

new field was created
Figure 93. New field has been created

The new field will also automatically be selected in the data object’s field list, and its properties will be shown in the Field general properties editor. Additionally the field properties will be loaded in the different tool windows, in this way the field will be ready for edition in whatever selected tool window.

At any time, any field (without restrictions) can be deleted from a data object definition by clicking on the corresponding 'x' icon in the data object’s fields table.

11.7.7.4. Additional options

As stated before, both Data Objects as well as Fields require some of their initial properties to be set upon creation. Additionally there are three domains of properties that can be configured for a given Data Object. A domain is basically a set of properties related to a given business area. Current available domains are, "Drools & jBPM", "Persistence" and the "Advanced" domain. To work on a given domain the user should select the corresponding "Tool window" (see below) on the right side toolbar. Every tool window usually provides two editors, the "Data Object" level editor and the "Field" level editor, that will be shown depending on the last selected item, the Data Object or the Field.

Drools & jBPM domain

The Drools & jBPM domain editors manages the set of Data Object or Field properties related to drools applications.

Drools & jBPM object editor

The Drools & jBPM object editor manages the object level drools properties

data object drools tool window
Figure 94. The data object’s properties
  • TypeSafe: this property allows to enable/disable the type safe behaviour for current type. By default all type declarations are compiled with type safety enabled. (See Drools for more information on this matter).

  • ClassReactive: this property allows to mark this type to be treated as "Class Reactive" by the Drools engine. (See Drools for more information on this matter).

  • PropertyReactive: this property allows to mark this type to be treated as "Property Reactive" by the Drools engine. (See Drools for more information on this matter).

  • Role: this property allows to configure how the Drools engine should handle instances of this type: either as regular facts or as events. By default all types are handled as a regular fact, so for the time being the only value that can be set is "Event" to declare that this type should be handled as an event. (See Drools Fusion for more information on this matter).

  • Timestamp: this property allows to configure the "timestamp" for an event, by selecting one of his attributes. If set the Drools engine will use the timestamp from the given attribute instead of reading it from the Session Clock. If not, the Drools engine will automatically assign a timestamp to the event. (See Drools Fusion for more information on this matter).

  • Duration: this property allows to configure the "duration" for an event, by selecting one of his attributes. If set the Drools engine will use the duration from the given attribute instead of using the default event duration = 0. (See Drools Fusion for more information on this matter).

  • Expires: this property allows to configure the "time offset" for an event expiration. If set, this value must be a temporal interval in the form: [d][#h][#m][#s][[ms]] Where [ ] means an optional parameter and # means a numeric value. e.g.: 1d2h, means one day and two hours. (See Drools Fusion for more information on this matter).

  • Remotable: If checked this property makes the Data Object available to be used with jBPM remote services as REST, JMS and WS. (See jBPM for more information on this matter).

Drools & jBPM field editor

The Drools & jBPM object editor manages the field level drools properties

field drools tool window
Figure 95. The data object’s field properties
  • Equals: checking this property for a Data Object field implies that it will be taken into account, at the code generation level, for the creation of both the equals() and hashCode() methods in the generated Java class. We will explain this in more detail in the following section.

  • Position: this field requires a zero or positive integer. When set, this field will be interpreted by the Drools engine as a positional argument (see the section below and also the Drools documentation for more information on this subject).

Persistence domain

The Persistence domain editors manages the set of Data Object or Field properties related to persistence.

Persistence domain object editor

Persistence domain object editor manages the object level persistence properties

data object persistence tool window
Figure 96. The data object’s properties
  • Persistable: this property allows to configure current Data Object as persistable.

  • Table name: this property allows to set a user defined database table name for current Data Object.

Persistence domain field editor

The persistence domain field editor manages the field level persistence properties and is divided into three sections.

field persistence tool window sections
Figure 97. Persistence domain field editor sections
Identifier:

A persistable Data Object should have one and only one field defined as the Data Object identifier. The identifier is typically a unique number that distinguishes a given Data Object instance from all other instances of the same class.

  • Is Identifier: marks current field as the Data Object identifier. A persistable Data Object should have one and only one field marked as identifier, and it should be a base java type, like String, Integer, Long, etc. A field that references a Data Object, or is a multiple field can not be marked as identifier. And also composite identifiers are not supported in this version. When a persistable Data Object is created an identifier field is created by default with the properly initializations, it’s strongly recommended to use this identifier.

  • Generation Strategy: the generation strategy establishes how the identifier values will be automatically generated when the Data Object instances are created and stored in a database. (e.g. by the forms associated to jBPM processes human tasks.) When the by default Identifier field is created, the generation strategy will be also automatically set and it’s strongly recommended to use this configuration.

  • Sequence Generator: the generator represents the seed for the values that will be used by the Generation Strategy. When the by default Identifier field is created the Sequence Generator will be also automatically generated and properly configured to be used by the Generation Strategy.

Column Properties:

The column properties section enables the customization of some properties of the database column that will store the field value.

  • Column name: optional value that sets the database column name for the given field.

  • Unique: When checked the unique property establishes that current field value should be a unique key when stored in the database. (if not set the default value is false)

  • Nullable: When checked establishes that current field value can be null when stored in a database. (if not set the default value is true)

  • Insertable: When checked establishes that column will be included in SQL INSERT statements generated by the persistence provider. (if not set the default value is true)

  • Updatable: When checked establishes that the column will be included SQL UPDATE statements generated by the persistence provider. (if not set the default value is true)

Relationship Properties:

When the field’s type is a Data Object type, or a list of a Data Object type a relationship type should be set in order to let the persistence provider to manage the relation. Fortunately this relation type is automatically set when such kind of fields are added to an already marked as persistable Data Object. The relationship type is set by the following popup.

field persistence tool window sections relationship dialog
Figure 98. Relationship configuration popup
  • Relationship type: sets the type of relation from one of the following options:

    One to one: typically used for 1:1 relations where "A is related to one instance of B", and B exists only when A exists. e.g. PurchaseOrder → PurchaseOrderHeader (a PurchaseOrderHeader exists only if the PurchaseOrder exists)

    One to many: typically used for 1:N relations where "A is related to N instances of B", and the related instances of B exists only when A exists. e.g. PurchaseOrder → PurchaseOrderLine (a PurchaseOrderLine exists only if the PurchaseOrder exists)

    Many to one: typically used for 1:1 relations where "A is related to one instance of B", and B can exist even without A. e.g. PurchaseOrder → Client (a Client can exist in the database even without an associated PurchaseOrder)

    Many to many: typically used for N:N relations where "A can be related to N instances of B, and B can be related to M instances of A at the same time", and both B and A instances can exist in the database independently of the related instances. e.g. Course → Student. (Course can be related to N Students, and a given Student can attend to M courses)

    When a field of type "Data Object" is added to a given persistable Data Object, the "Many to One" relationship type is generated by default.

    And when a field of type "list of Data Object" is added to a given persistable Data Object , the "One to Many" relationship is generated by default.

  • Cascade mode: Defines the set of cascadable operations that are propagated to the associated entity. The value cascade=ALL is equivalent to cascade={PERSIST, MERGE, REMOVE, REFRESH}. e.g. when A → B, and cascade "PERSIST or ALL" is set, if A is saved, then B will also be saved.

    The by default cascade mode created by the data modeller is "ALL" and it’s strongly recommended to use this mode when Data Objects are being used by jBPM processes and forms.

  • Fetch mode: Defines how related data will be fetched from database at reading time.

    EAGER: related data will be read at the same time. e.g. If A → B, when A is read from database B will be read at the same time.

    LAZY: reading of related data will be delayed usually to the moment they are required. e.g. If PurchaseOrder → PurchaseOrderLine the lines reading will be postponed until a method "getLines()" is invoked on a PurchaseOrder instance.

    The default fetch mode created by the data modeller is "EAGER" and it’s strongly recommended to use this mode when Data Objects are being used by jBPM processes and forms.

  • Optional: establishes if the right side member of a relationship can be null.

  • Mapped by: used for reverse relations.

Advanced domain

The advanced domain enables the configuration of whatever parameter set by the other domains as well as the adding of arbitrary parameters. As it will be shown in the code generation section every "Data Object / Field" parameter is represented by a java annotation. The advanced mode enables the configuration of this annotations.

Advanced domain Data Object / Field editor.

The advanced domain editor has the same shape for both Data Object and Field.

data object or field advanced tool window
Figure 99. Advanced domain editor.

The following operations are available

  • delete: enables the deletion of a given Data Object or Field annotation.

  • clear: clears a given annotation parameter value.

  • edit: enables the edition of a given annotation parameter value.

  • add annotation: The add annotation button will start a wizard that will let the addition of whatever java annotation available in the project dependencies.

    Add annotation wizard step #1: the first step of the wizard requires the entering of a fully qualified class name of an annotation, and by pressing the "search" button the annotation definition will be loaded into the wizard. Additionally when the annotation definition is loaded, different wizard steps will be created in order to enable the completion of the different annotation parameters. Required parameters will be marked with "*".

    add annotation wizard step1 annotation loaded
    Figure 100. Annotation definition loaded into the wizard.

    Whenever it’s possible the wizard will provide a suitable editor for the given parameters.

    add annotation wizard step2 enum param editor
    Figure 101. Automatically generated enum values editor for an Enumeration annotation parameter.

    A generic parameter editor will be provided when it’s not possible to calculate a customized editor

    add annotation wizard step2 generic param editor
    Figure 102. Generic annotation parameter editor

    When all required parameters have been entered and validated, the finish button will be enabled and the wizard can be completed by adding an annotation to the given Data Object or Field.

11.7.7.5. Generate data model code.

The data model in itself is merely a visual tool that allows the user to define high-level data structures, for them to interact with the Drools engine on the one hand, and the jBPM platform on the other. In order for this to become possible, these high-level visual structures have to be transformed into low-level artifacts that can effectively be consumed by these platforms. These artifacts are Java POJOs (Plain Old Java Objects), and they are generated every time the data model is saved, by pressing the "Save" button in the top Data Modeller Menu. Additionally when the user round trip between the "Editor" and "Source" tab, the code is auto generated to maintain the consistency with the Editor view and vice versa.

save top
Figure 103. Save the data model from the top menu

The resulting code is generated according to the following transformation rules:

  • The data object’s identifier property will become the Java class’s name. It therefore needs to be a valid Java identifier.

  • The data object’s package property becomes the Java class’s package declaration.

  • The data object’s superclass property (if present) becomes the Java class’s extension declaration.

  • The data object’s label and description properties will translate into the Java annotations "@org.kie.api.definition.type.Label" and "@org.kie.api.definition.type.Description", respectively. These annotations are merely a way of preserving the associated information, and as yet are not processed any further.

  • The data object’s role property (if present) will be translated into the "@org.kie.api.definition.type.Role" Java annotation, that IS interpreted by the application platform, in the sense that it marks this Java class as a Drools Event Fact-Type.

  • The data object’s type safe property (if present) will be translated into the "@org.kie.api.definition.type.TypeSafe Java annotation. (see Drools)

  • The data object’s class reactive property (if present) will be translated into the "@org.kie.api.definition.type.ClassReactive Java annotation. (see Drools)

  • The data object’s property reactive property (if present) will be translated into the "@org.kie.api.definition.type.PropertyReactive Java annotation. (see Drools)

  • The data object’s timestamp property (if present) will be translated into the "@org.kie.api.definition.type.Timestamp Java annotation. (see Drools)

  • The data object’s duration property (if present) will be translated into the "@org.kie.api.definition.type.Duration Java annotation. (see Drools)

  • The data object’s expires property (if present) will be translated into the "@org.kie.api.definition.type.Expires Java annotation. (see Drools)

  • The data object’s remotable property (if present) will be translated into the "@org.kie.api.remote.Remotable Java annotation. (see jBPM)

A standard Java default (or no parameter) constructor is generated, as well as a full parameter constructor, i.e. a constructor that accepts as parameters a value for each of the data object’s user-defined fields.

The data object’s user-defined fields are translated into Java class fields, each one of them with its own getter and setter method, according to the following transformation rules:

  • The data object field’s identifier will become the Java field identifier. It therefore needs to be a valid Java identifier.

  • The data object field’s type is directly translated into the Java class’s field type. In case the field was declared to be multiple (i.e. 'List'), then the generated field is of the "java.util.List" type.

  • The equals property: when it is set for a specific field, then this class property will be annotated with the "@org.kie.api.definition.type.Key" annotation, which is interpreted by the Drools engine, and it will 'participate' in the generated equals() method, which overwrites the equals() method of the Object class. The latter implies that if the field is a 'primitive' type, the equals method will simply compares its value with the value of the corresponding field in another instance of the class. If the field is a sub-entity or a collection type, then the equals method will make a method-call to the equals method of the corresponding data object’s Java class, or of the java.util.List standard Java class, respectively.

    If the equals property is checked for ANY of the data object’s user defined fields, then this also implies that in addition to the default generated constructors another constructor is generated, accepting as parameters all of the fields that were marked with Equals. Furthermore, generation of the equals() method also implies that also the Object class’s hashCode() method is overwritten, in such a manner that it will call the hashCode() methods of the corresponding Java class types (be it 'primitive' or user-defined types) for all the fields that were marked with Equals in the Data Model.

  • The position property: this field property is automatically set for all user-defined fields, starting from 0, and incrementing by 1 for each subsequent new field. However the user can freely change the position among the fields. At code generation time this property is translated into the "@org.kie.api.definition.type.Position" annotation, which can be interpreted by the Drools engine. Also, the established property order determines the order of the constructor parameters in the generated Java class.

As an example, the generated Java class code for the Purchase Order data object, corresponding to its definition as shown in the following figure purchase_example.jpg is visualized in the figure at the bottom of this chapter. Note that the two of the data object’s fields, namely 'header' and 'lines' were marked with Equals, and have been assigned with the positions 2 and 1, respectively).

generate purchase example
Figure 104. Purchase Order configuration
    package org.jbpm.examples.purchases;

    /**
    * This class was automatically generated by the data modeler tool.
    */
    @org.kie.api.definition.type.Label("Purchase Order")
    @org.kie.api.definition.type.TypeSafe(true)
    @org.kie.api.definition.type.Role(org.kie.api.definition.type.Role.Type.EVENT)
    @org.kie.api.definition.type.Expires("2d")
    @org.kie.api.remote.Remotable
    public class PurchaseOrder implements java.io.Serializable
    {

    static final long serialVersionUID = 1L;

    @org.kie.api.definition.type.Label("Total")
    @org.kie.api.definition.type.Position(3)
    private java.lang.Double total;

    @org.kie.api.definition.type.Label("Description")
    @org.kie.api.definition.type.Position(0)
    private java.lang.String description;

    @org.kie.api.definition.type.Label("Lines")
    @org.kie.api.definition.type.Position(2)
    @org.kie.api.definition.type.Key
    private java.util.List<org.jbpm.examples.purchases.PurchaseOrderLine> lines;

    @org.kie.api.definition.type.Label("Header")
    @org.kie.api.definition.type.Position(1)
    @org.kie.api.definition.type.Key
    private org.jbpm.examples.purchases.PurchaseOrderHeader header;

    @org.kie.api.definition.type.Position(4)
    private java.lang.Boolean requiresCFOApproval;

    public PurchaseOrder()
    {
    }

    public java.lang.Double getTotal()
    {
    return this.total;
    }

    public void setTotal(java.lang.Double total)
    {
    this.total = total;
    }

    public java.lang.String getDescription()
    {
    return this.description;
    }

    public void setDescription(java.lang.String description)
    {
    this.description = description;
    }

    public java.util.List<org.jbpm.examples.purchases.PurchaseOrderLine> getLines()
    {
    return this.lines;
    }

    public void setLines(java.util.List<org.jbpm.examples.purchases.PurchaseOrderLine> lines)
    {
    this.lines = lines;
    }

    public org.jbpm.examples.purchases.PurchaseOrderHeader getHeader()
    {
    return this.header;
    }

    public void setHeader(org.jbpm.examples.purchases.PurchaseOrderHeader header)
    {
    this.header = header;
    }

    public java.lang.Boolean getRequiresCFOApproval()
    {
    return this.requiresCFOApproval;
    }

    public void setRequiresCFOApproval(java.lang.Boolean requiresCFOApproval)
    {
    this.requiresCFOApproval = requiresCFOApproval;
    }

    public PurchaseOrder(java.lang.Double total, java.lang.String description,
    java.util.List<org.jbpm.examples.purchases.PurchaseOrderLine> lines,
    org.jbpm.examples.purchases.PurchaseOrderHeader header,
    java.lang.Boolean requiresCFOApproval)
    {
    this.total = total;
    this.description = description;
    this.lines = lines;
    this.header = header;
    this.requiresCFOApproval = requiresCFOApproval;
    }

    public PurchaseOrder(java.lang.String description,
    org.jbpm.examples.purchases.PurchaseOrderHeader header,
    java.util.List<org.jbpm.examples.purchases.PurchaseOrderLine> lines,
    java.lang.Double total, java.lang.Boolean requiresCFOApproval)
    {
    this.description = description;
    this.header = header;
    this.lines = lines;
    this.total = total;
    this.requiresCFOApproval = requiresCFOApproval;
    }

    public PurchaseOrder(
    java.util.List<org.jbpm.examples.purchases.PurchaseOrderLine> lines,
    org.jbpm.examples.purchases.PurchaseOrderHeader header)
    {
    this.lines = lines;
    this.header = header;
    }

    @Override
    public boolean equals(Object o)
    {
    if (this == o)
    return true;
    if (o == null || getClass() != o.getClass())
    return false;
    org.jbpm.examples.purchases.PurchaseOrder that = (org.jbpm.examples.purchases.PurchaseOrder) o;
    if (lines != null ? !lines.equals(that.lines) : that.lines != null)
    return false;
    if (header != null ? !header.equals(that.header) : that.header != null)
    return false;
    return true;
    }

    @Override
    public int hashCode()
    {
    int result = 17;
    result = 31 * result + (lines != null ? lines.hashCode() : 0);
    result = 31 * result + (header != null ? header.hashCode() : 0);
    return result;
    }

    }
11.7.7.6. Using external models

Using an external model means the ability to use a set for already defined POJOs in current project context. In order to make those POJOs available a dependency to the given JAR should be added. Once the dependency has been added the external POJOs can be referenced from current project data model.

There are two ways to add a dependency to an external JAR file:

  • Dependency to a JAR file already installed in current local M2 repository (typically associated the user home).

  • Dependency to a JAR file installed in current Business Central "Guvnor M2 repository". (internal to the application)

Dependency to a JAR file in local M2 repository

To add a dependency to a JAR file in local M2 repository, follow these steps.

Click the "Add" button to add a new dependency line.
add dependency 2
Figure 106. New dependency line.
Save the project to update its dependencies.

When project is saved the POJOs defined in the external file will be available.

add dependency 4
Figure 108. Save project.
Dependency to a JAR file in current "Guvnor M2 repository".

To add a dependency to a JAR file in current "Guvnor M2 repository", follow these steps.

Open the Maven Artifact Repository editor.
add dependency guvnor m2 1
Figure 109. Guvnor M2 Repository editor.
Upload the file using the Upload button.
add dependency guvnor m2 3
Figure 111. File upload success.
Guvnor M2 repository files.

Once the file has been loaded it will be displayed in the repository files list.

add dependency guvnor m2 4
Figure 112. Files list.
Provide a GAV for the uploaded file (optional).

If the uploaded file is not a valid Maven JAR (don’t have a pom.xml file) the system will prompt the user in order to provide a GAV for the file to be installed.

add dependency guvnor m2 not gav 1
Figure 113. Not valid POM.
add dependency guvnor m2 not gav 2
Figure 114. Enter GAV manually.
Add dependency from repository.

Open the project editor (see below) and click the "Add from repository" button to open the JAR selector to see all the installed JAR files in current "Guvnor M2 repository". When the desired file is selected the project should be saved in order to make the new dependency available.

add dependency guvnor m2 5
Figure 115. Select JAR from "Maven Artifact Repository".
Using the external objects

When a dependency to an external JAR has been set, the external POJOs can be used in the context of current project data model in the following ways:

  • External POJOs can be extended by current model data objects.

  • External POJOs can be used as field types for current model data objects.

The following screenshot shows how external objects are prefixed with the string " -ext- " in order to be quickly identified.

add dependency select external pojo
Figure 116. Identifying external objects.
11.7.7.7. Roundtrip and concurrency

Current version implements roundtrip and code preservation between Data modeller and Java source code. No matter where the Java code was generated (e.g. Eclipse, Data modeller), the data modeller will only create/delete/update the necessary code elements to maintain the model updated, i.e, fields, getter/setters, constructors, equals method and hashCode method. Also whatever Type or Field annotation not managed by the Data Modeler will be preserved when the Java sources are updated by the Data modeller.

Aside from code preservation, like in the other Business Central editors, concurrent modification scenarios are still possible. Common scenarios are when two different users are updating the model for the same project, e.g. using the data modeller or executing a 'git push command' that modifies project sources.

From an application context’s perspective, we can basically identify two different main scenarios:

No changes have been undertaken through the application

In this scenario the application user has basically just been navigating through the data model, without making any changes to it. Meanwhile, another user modifies the data model externally.

In this case, no immediate warning is issued to the application user. However, as soon as the user tries to make any kind of change, such as add or remove data objects or properties, or change any of the existing ones, the following pop-up will be shown:

extchanges reopen ignore
Figure 117. External changes warning

The user can choose to either:

  • Re-open the data model, thus loading any external changes, and then perform the modification he was about to undertake, or

  • Ignore any external changes, and go ahead with the modification to the model. In this case, when trying to persist these changes, another pop-up warning will be shown:

    extchanges forcesave reopen
    Figure 118. Force save / re-open

    The "Force Save" option will effectively overwrite any external changes, while "Re-open" will discard any local changes and reload the model.

    "Force Save" overwrites any external changes!

Changes have been undertaken through the application

The application user has made changes to the data model. Meanwhile, another user simultaneously modifies the data model from outside the application context.

In this alternative scenario, immediately after the external user commits his changes to the asset repository (or e.g. saves the model with the data modeller in a different session), a warning is issued to the application user:

extchanges reopen ignore
Figure 119. External changes warning

As with the previous scenario, the user can choose to either:

  • Re-open the data model, thus losing any modifications that were made through the application, or

  • Ignore any external changes, and continue working on the model.

    One of the following possibilities can now occur: ** The user tries to persist the changes he made to the model by clicking the "Save" button in the data modeller top level menu. This leads to the following warning message:

    +

    extchanges forcesave reopen
    Figure 120. Force save / re-open

    The "Force Save" option will effectively overwrite any external changes, while "Re-open" will discard any local changes and reload the model.

11.7.8. Data Sets

A data set is basically a set of columns populated with some rows, a matrix of data composed of timestamps, texts and numbers. A data set can be stored in different systems: a database, an excel file, in memory or in a lot of other different systems. On the other hand, a data set definition tells Business Central modules how such data can be accessed, read and parsed.

Notice, it’s very important to make the difference crystal clear between a data set and its definition since Business Central does not take care of storing any data, it just provides a standard way to define access to those data sets regardless of where the data is stored.

Let’s take for instance the data stored in a remote database. A valid data set could be, for example, an entire database table or the result of an SQL query. In both cases, the database will return a bunch of columns and rows. Now, imagine we want to get access to such data to feed some charts in a new Business Central page. First thing is to create and register a data set definition in order to indicate the following:

  • where the data set is stored,

  • how can be accessed, read and parsed and

  • what columns contains and of which type.

This chapter introduces the available Business Central tools for registering and handling data set definitions and how these definitions can be consumed in other Business Central modules like, for instance, the Page Editor.

For simplicity sake we will be using the term data set to refer to the actual data set definitions as Data set and Data set definition can be considered synonyms under the data set authoring context.

11.7.8.1. Data Set Authoring Page

Everything related to the authoring of data sets can be found under the Data Set Authoring page which is accessible from the following top level menu entry: Extensions>Data Sets, as shown in the following screenshot.

DataSetAuthoringPerspective
Figure 121. Data Set Authoring Page

The center panel, shows a welcome screen, whilst the left panel contains the Data Set Explorer listing all the data sets available

This page is only intended to Administrator users, since defining data sets can be considered a low level task.

11.7.8.2. Data Set Explorer

The Data Set Explorer list the data sets present in the system. Every time the user clicks on the data set it shows a brief summary alongside the following information:

DataSetExplorer
Figure 122. Data Set Explorer
  • (1) A button for creating a new Data set

  • (2) The list of currently available Data sets

  • (3) An icon that represents the Data set’s provider type (Bean, SQL, CSV, etc)

  • (4) Details of current cache and refresh policy status

  • (5) Details of current size on backend (unit as rows) and current size on client side (unit in bytes)

  • (6) The button for editing the Data set. Once clicked the Data set editor screen is opened on the center panel

The next section explains how to create, edit and fine-tune data set definitions.

11.7.8.3. Data Set Creation

Clicking on the New Data Set button opens a new screen from which the user is able to create a new data set definition in three steps:

  • Provider type selection

    Specify the kind of the remote storage system (BEAN, SQL, CSV, ElasticSearch)

  • Provider configuration

    Specify the attributes for being able to look up data from the remote system. The configuration varies depending on the data provider type selected.

  • Data set columns & filter

    Live data preview, column types and initial filter configuration.

Step 1: Provider type selection

Allows the user’s specify the type of data provider of the data set being created.

This screen lists all the current available data provider types and helper popovers with descriptions. Each data provider is represented with a descriptive image:

DataSetDefTypeSelection
Figure 123. Provider type selection

Four types are currently supported:

  • Bean (Java class) - To generate a data set directly from Java

  • SQL - For getting data from any ANSI-SQL compliant database

  • CSV - To upload the contents of a remote or local CSV file

  • Elastic Search - To query and get documents stored on Elastic Search nodes as data sets

Once a type is selected, click Next to continue with the next workflow step.

Step 2: Configuration
DataSetDefConfigScreen
Figure 124. CSV Configuration

The provider type selected in the previous step will determine which configuration settings the system asks for.

DataSetDefConfigTypes
Figure 125. Configuration screen per data set type

The UUID attribute is a read only field as it’s generated by the system. It’s only intended for usage in API calls or specific operations.

Step 3: Data set columns and preview

After clicking on the Test button (see previous step), the system executes a data set lookup test call in order to check if the remote system is up and the data is available. If everything goes ok the user will see the following screen:

DataSetDefLivePreview
Figure 126. Data set preview

This screen shows a live data preview along with the columns the user wants to be part of the resulting data set. The user can also navigate through the data and apply some changes to the data set structure. Once finished, we can click the Save button in order to register the new data set definition.

We can also change the configuration settings at any time just by going back to the configuration tab. We can repeat the Configuration>Test>Preview cycle as many times as needed until we consider it’s ready to be saved.

Columns

In the Columns tab area the user can select what columns are part of the resulting data set definition.

DataSetDefColumns
Figure 127. Data set columns
  • (1) To add or remove columns. Select only those columns you want to be part of the resulting data set

  • (2) Use the drop down image selector to change the column type

A data set may only contain columns of any of the following 4 types:

  • Label - For text values supporting group operations (similar to the SQL "group by" operator) which means you can perform data lookup calls and get one row per distinct value.

  • Text - For text values NOT supporting group operations. Typically for modeling large text columns such as abstracts, descriptions and the like.

  • Number - For numeric values. It does support aggregation functions on data lookup calls: sum, min, max, average, count, distinct.

  • Date - For date or timestamp values. It does support time based group operations by different time intervals: minute, hour, day, month, year, …​

No matter which remote system you want to retrieve data from, the resulting data set will always return a set of columns of one of the four types above. There exists, by default, a mapping between the remote system column types and the data set types. The user is able to modify the type for some columns, depending on the data provider and the column type of the remote system. The system supports the following changes to column types:

  • Label <> Text - Useful when we want to enable/disable the categorization (grouping) for the target column. For instance, imagine a database table called "document" containing a large text column called "abstract". As we do not want the system to treat such column as a "label" we might change its column type to "text". Doing so, we are optimizing the way the system handles the data set and

  • Number <> Label - Useful when we want to treat numeric columns as labels. This can be used for instance to indicate that a given numeric column is not a numeric value that can be used in aggregation functions. Despite its values are stored as numbers we want to handle the column as a "label". One example of such columns are: an item’s code, an appraisal id., …​

BEAN data sets do not support changing column types as it’s up to the developer to decide which are the concrete types for each column.

Filter

A data set definition may define a filter. The goal of the filter is to leave out rows the user does not consider necessary. The filter feature works on any data provider type and it lets the user to apply filter operations on any of the data set columns available.

DataSetDefFilter
Figure 128. Data set filter

While adding or removing filter conditions and operations, the preview table on central area is updated with live data that reflects the current filter status.

There exists two strategies for filtering data sets and it’s also important to note that choosing between the two have important implications. Imagine a dashboard with some charts feeding from a expense reports data set where such data set is built on top of an SQL table. Imagine also we only want to retrieve the expense reports from the "London" office. You may define a data set containing the filter "office=London" and then having several charts feeding from such data set. This is the recommended approach. Another option is to define a data set with no initial filter and then let the individual charts to specify their own filter. It’s up to the user to decide on the best approach.

Depending on the case it might be better to define the filter at a data set level for reusing across other modules. The decision may also have an impact on the performance since a filtered cached data set will have far better performance than a lot of individual non-cached data set lookup requests. (See the next section for more information about caching data sets).

Notice, for SQL data sets, the user can use both the filter feature introduced or, alternatively, just add custom filter criteria to the SQL sentence. Although, the first approach is more appropriate for non-technical users since they might not have the required SQL language skills.

11.7.8.4. Data set editor

To edit an existing data set definition go the data set explorer, expand the desired