JBoss.orgCommunity Documentation

OptaPlanner Workbench and Execution Server User Guide

Version 6.4.0.Final


I. OptaPlanner Engine
II. OptaPlanner Workbench
1. Workbench (General)
1.1. Installation
1.1.1. War installation
1.1.2. Workbench data
1.1.3. System properties
1.1.4. Trouble shooting
1.2. Quick Start
1.2.1. Add repository
1.2.2. Add project
1.2.3. Define Data Model
1.2.4. Define Rule
1.2.5. Build and Deploy
1.3. Administration
1.3.1. Administration overview
1.3.2. Organizational unit
1.3.3. Repositories
1.4. Configuration
1.4.1. Basic user management
1.4.2. Roles
1.4.3. Restricting access to repositories
1.4.4. Command line config tool
1.5. Introduction
1.5.1. Log in and log out
1.5.2. Home screen
1.5.3. Workbench concepts
1.5.4. Initial layout
1.6. Changing the layout
1.6.1. Resizing
1.6.2. Repositioning
1.7. Authoring (General)
1.7.1. Artifact Repository
1.7.2. Asset Editor
1.7.3. Tags Editor
1.7.4. Project Explorer
1.7.5. Project Editor
1.7.6. Validation
1.7.7. Data Modeller
1.7.8. Data Sets
1.8. User and group management
1.8.1. Introduction
1.8.2. Security management providers
1.8.3. Installation and setup
1.8.4. Usage
1.9. Embedding Workbench In Your Application
1.10. Asset Management
1.10.1. Asset Management Overview
1.10.2. Managed vs Unmanaged Repositories
1.10.3. Asset Management Processes
1.10.4. Usage Flow
1.10.5. Repository Structure
1.10.6. Managed Repositories Operations
1.11. Execution Server Management UI
1.11.1. Server Templates
1.11.2. Container
1.11.3. Remote Server
2. Authoring Planning Assets
2.1. Solver Editor
3. Workbench Integration
3.1. REST
3.1.1. Job calls
3.1.2. Repository calls
3.1.3. Organizational unit calls
3.1.4. Maven calls
3.1.5. REST summary
3.2. Keycloak SSO integration
3.2.1. Scenario
3.2.2. Install and setup a Keycloak server
3.2.3. Create and setup the demo realm
3.2.4. Install and setup jBPM Workbench
3.2.5. Securing workbench remote services via Keycloak
3.2.6. Execution server
3.2.7. Consuming remote services
4. Workbench High Availability
4.1.
4.1.1. VFS clustering
4.1.2. jBPM clustering
III. OptaPlanner Execution Server
5. KIE Execution Server
5.1. Overview
5.1.1. Glossary
5.2. Installing the KIE Server
5.2.1. Bootstrap switches
5.2.2. Installation details for different containers
5.3. Kie Server setup
5.3.1. Managed Kie Server
5.3.2. Unmanaged KIE Execution Server
5.4. Creating a Kie Container
5.5. Managing Containers
5.5.1. Starting a Container
5.5.2. Stopping and Deleting a Container
5.5.3. Updating a Container
5.6. Kie Server REST API
5.6.1. [GET] /
5.6.2. [POST] /
5.6.3. [GET] /containers
5.6.4. ⁠[GET] /containers/{id}
5.6.5. [PUT] /containers/{id}
5.6.6. [DELETE] /containers/{id}
5.6.7. [POST] /containers/instances/{id}
5.6.8. [GET] /containers/{id}/release-id
5.6.9. [POST] /containers/{id}/release-id
5.6.10. [GET] /containers/{id}/scanner
5.6.11. [POST] /containers/{id}/scanner
5.6.12. Native REST client for Execution Server
5.7. OptaPlanner REST API
5.7.1. [GET] /containers/{containerId}/solvers
5.7.2. [PUT] /containers/{containerId}/solvers/{solverId}
5.7.3. [GET] /containers/{containerId}/solvers/{solverId}
5.7.4. [POST] /containers/{containerId}/solvers/{solverId}
5.7.5. [GET] /containers/{containerId}/solvers/{solverId}/bestsolution
5.7.6. [DELETE] /containers/{containerId}/solvers/{solverId}
5.8. Controller REST API
5.8.1. [GET] /management/servers
5.8.2. [GET] /management/server/{id}
5.8.3. [PUT] /management/server/{id}
5.8.4. [DELETE] /management/server/{id}
5.8.5. [GET] /management/server/{id}/containers
5.8.6. [GET] /management/server/{id}/containers/{containerId}
5.8.7. [PUT] /management/server/{id}/containers/{containerId}
5.8.8. [DELETE] /management/server/{id}/containers/{containerId}
5.8.9. [POST] /management/server/{id}/containers/{containerId}/status/started
5.8.10. [POST] /management/server/{id}/containers/{containerId}/status/stopped
5.9. Kie Server Java Client API
5.9.1. Maven Configuration
5.9.2. Client Configuration
5.9.3. Server Response
5.9.4. Server Capabilities
5.9.5. Kie Containers
5.9.6. Managing Containers
5.9.7. Available Clients for the Decision Server
5.9.8. Sending commands to the server
5.9.9. Listing available business processes

The OptaPlanner

Table of Contents

1. Workbench (General)
1.1. Installation
1.1.1. War installation
1.1.2. Workbench data
1.1.3. System properties
1.1.4. Trouble shooting
1.2. Quick Start
1.2.1. Add repository
1.2.2. Add project
1.2.3. Define Data Model
1.2.4. Define Rule
1.2.5. Build and Deploy
1.3. Administration
1.3.1. Administration overview
1.3.2. Organizational unit
1.3.3. Repositories
1.4. Configuration
1.4.1. Basic user management
1.4.2. Roles
1.4.3. Restricting access to repositories
1.4.4. Command line config tool
1.5. Introduction
1.5.1. Log in and log out
1.5.2. Home screen
1.5.3. Workbench concepts
1.5.4. Initial layout
1.6. Changing the layout
1.6.1. Resizing
1.6.2. Repositioning
1.7. Authoring (General)
1.7.1. Artifact Repository
1.7.2. Asset Editor
1.7.3. Tags Editor
1.7.4. Project Explorer
1.7.5. Project Editor
1.7.6. Validation
1.7.7. Data Modeller
1.7.8. Data Sets
1.8. User and group management
1.8.1. Introduction
1.8.2. Security management providers
1.8.3. Installation and setup
1.8.4. Usage
1.9. Embedding Workbench In Your Application
1.10. Asset Management
1.10.1. Asset Management Overview
1.10.2. Managed vs Unmanaged Repositories
1.10.3. Asset Management Processes
1.10.4. Usage Flow
1.10.5. Repository Structure
1.10.6. Managed Repositories Operations
1.11. Execution Server Management UI
1.11.1. Server Templates
1.11.2. Container
1.11.3. Remote Server
2. Authoring Planning Assets
2.1. Solver Editor
3. Workbench Integration
3.1. REST
3.1.1. Job calls
3.1.2. Repository calls
3.1.3. Organizational unit calls
3.1.4. Maven calls
3.1.5. REST summary
3.2. Keycloak SSO integration
3.2.1. Scenario
3.2.2. Install and setup a Keycloak server
3.2.3. Create and setup the demo realm
3.2.4. Install and setup jBPM Workbench
3.2.5. Securing workbench remote services via Keycloak
3.2.6. Execution server
3.2.7. Consuming remote services
4. Workbench High Availability
4.1.
4.1.1. VFS clustering
4.1.2. jBPM clustering

Here's a list of all system properties:

To change one of these system properties in a WildFly or JBoss EAP cluster:

These steps help you get started with minimum of effort.

They should not be a substitute for reading the documentation in full.

Provides capabilities to manage the system repository from command line. System repository contains the data about general workbench settings: how editors behave, organizational groups, security and other settings that are not editable by the user. System repository exists in the .niogit folder, next to all the repositories that have been created or cloned into the workbench.

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:

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 be given too.

  • Using Maven, mvn deploy to that Maven repository. Refresh the list to make it show up.

Note

This remote Maven repository is relatively simple. It does not support proxying, mirroring, ... like Nexus or Archiva.

The Asset Editor is the principle component of the workbench User-Interface. It consists of two main views Editor and Overview.

The Project Explorer provides the ability to browse different Organizational Units, Repositories, Projects and their files.

The Project Editor screen can be accessed from Project Explorer. Project Editor shows the settings for the currently active project.

Unlike most of the workbench editors, project editor edits more than one file. Showing everything that is needed for configuring the KIE project in one place.


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 perspective is open.

To start the creation of a data model inside a project, take the following steps:

This will start up the Data Modeller tool, which has the following general aspect:


The "Editor" tab is divided into the following sections:

The "Source" tab shows an editor that allows the visualization and modification of the generated java code.

The "Overview" tab shows the standard metadata and version information as the other workbench editors.

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:

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:


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.

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 & jJBPM", "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.

The Drools & jBPM domain editors manages the set of Data Object or Field properties related to drools applications.

The Drools & jBPM object editor manages the object level drools 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 engine will use the timestamp from the given attribute instead of reading it from the Session Clock. If not, the 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 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).

The Persistence domain editors manages the set of Data Object or Field properties related to persistence.

The persistence domain field editor manages the field level persistence properties and is divided in three sections.


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.

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.


  • 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 an A instances can exits 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 be also 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.

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.

The advanced domain editor has the same shape for both Data Object and Field.


The following operations are available

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.


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 changes 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).




    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;
    }

    }

  

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:

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 workbench 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:

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 the workbench modules how such data can be accessed, read and parsed.

Notice, it's very important to make crystal clear the difference between a data set and its definition since the workbench does not take care of storing any data, it just provides an standard way to define access to those data sets regardless 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 workbench perspective. First thing is to create and register a data set definition in order to indicate the following:

This chapter introduces the available workbench tools for registering and handling data set definitions and how this definitions can be consumed in other workbench modules like, for instance, the Perspective Editor.

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:

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:


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 on 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 may 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.


  • (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, disctinct.

  • 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., ...

Note

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.


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 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).

Note

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 appropriated for non technical users since they might not have the required SQL language skills.

The system provides caching mechanisms out-of-the-box for holding data sets and performing data operations using in-memory strategies. The use of these features brings a lot of advantages, like reducing the network traffic, remote system payload, processing times etc. On the other hand, it's up to the user to fine tune properly the caching settings to avoid hitting performance issues.

Two cache levels are supported:

The following diagram shows how caching is involved in any data set operation:


Any data look up call produces a resulting data set, so the use of the caching techniques determines where the data lookup calls are executed and where the resulting data set is located.

Client cache

If ON then the data set involved in a look up operation is pushed into the web browser so that all the components that feed from this data set do not need to perform any requests to the backend since data set operations are resolved at a client side:

  • The data set is stored in the web browser's memory

  • The client components feed from the data set stored in the browser

  • Data set operations (grouping, aggregations, filters and sort) are processed within the web browser, by means of a Javascript data set operation engine.

If you know beforehand that your data set will remain small, you can enable the client cache. It will reduce the number of backend requests, including the requests to the storage system. On the other hand, if you consider that your data set will be quite big, disable the client cache so as to not hitting with browser issues such as slow performance or intermittent hangs.

Backend cache

Its goal is to provide a caching mechanism for data sets on backend side.

This feature allows to reduce the number of requests to the remote storage system , by holding the data set in memory and performing group, filter and sort operations using the in-memory engine.

It's useful for data sets that do not change very often and their size can be considered acceptable to be held and processed in memory. It can be also helpful on low latency connectivity issues with the remote storage. On the other hand, if your data set is going to be updated frequently, it's better to disable the backend cache and perform the requests to the remote storage on each look up request, so the storage system is in charge of resolving the data set lookup request.

Note

BEAN and CSV data providers relies by default on the backend cache, as in both cases the data set must be always loaded into memory in order to resolve any data lookup operation using the in-memory engine. This is the reason why the backend settings are not visible in the Advanced settings tab.

The refresh feature allows for the invalidation of any cached data when certain conditions are meet.


  • (1) To enable or disable the refresh feature.

  • (2) To specify the refresh interval.

  • (3) To enable or disable data set invalidation when the data is outdated.

The data set refresh policy is tightly related to data set caching, detailed in previous section. This invalidation mechanism determines the cache life-cycle.

Depending on the nature of the data there exist three main use cases:

  • Source data changes predictable - Imagine a database being updated every night. In that case, the suggested configuration is to use a "refresh interval = 1 day" and disable "refresh on stale data". That way, the system will always invalidate the cached data set every day. This is the right configuration when we know in advance that the data is going to change.

  • Source data changes unpredictable - On the other hand, if we do not know whether the database is updated every day, the suggested configuration is to use a "refresh interval = 1 day" and enable "refresh on stale data". If so the system, before invalidating any data, will check for modifications. On data modifications, the system will invalidate the current stale data set so that the cache is populated with fresh data on the next data set lookup call.

  • Real time scenarios - In real time scenarios caching makes no sense as data is going to be updated constantly. In this kind of scenarios the data sent to the client has to be constantly updated, so rather than enabling the refresh settings (remember this settings affect the caching, and caching is not enabled) it's up to the clients consuming the data set to decide when to refresh. When the client is a dashboard then it's just a matter of modifying the refresh settings in the Displayer Editor configuration screen and set a proper refresh period, "refresh interval = 1 second" for example.

A security environment is usually provided by the use of a realm. Realms are used to restrict the access for the different application's resources. So realms contains information about the users, groups, roles, permissions and and any other related information.

In most of the typical scenarios the application's security is delegated to the container's security mechanism, which consumes a given realm at same time. It's important to consider that there exist several realm implementations, for example Wildfly provides a realm based on the application-users.properties/application-roles.properties files, Tomcat provides a realm based on the tomcat-users.xml file, etc. So keep in mind that there is no single security realm to rely on, it can be different in each installation.

The jBPM and Drools workbenches are not an exception, they're build on top Uberfire framework (aka UF), which delegates the authorization and authentication to the underlying container's security environment as well, so the consumed realm is given by the concrete deployment configuration.

Each security realm can provide support different operations. For example consider the use of a Wildfly's realm based on properties files, The contents for the applications-users.properties is like:

admin=207b6e0cc556d7084b5e2db7d822555c
salaboy=d4af256e7007fea2e581d539e05edd1b
maciej=3c8609f5e0c908a8c361ca633ed23844
kris=0bfd0f47d4817f2557c91cbab38bb92d
katy=fd37b5d0b82ce027bfad677a54fbccee
john=afda4373c6021f3f5841cd6c0a027244
jack=984ba30e11dda7b9ed86ba7b73d01481
director=6b7f87a92b62bedd0a5a94c98bd83e21
user=c5568adea472163dfc00c19c6348a665
guest=b5d048a237bfd2874b6928e1f37ee15e
kiewb=78541b7b451d8012223f29ba5141bcc2
kieserver=16c6511893651c9b4b57e0c027a96075

Note that it's based on key-value pairs where the key is the username, and the value is the hashed value for the user's password. So a user is just defined by the key, by its username, it does not have a name nor address or any other meta information.

On the other hand, consider the use of a realm provided by a Keycloak server. The information for a user is composed by more user meta-data, such as surname, address, etc, as in the following image:


So the different services and client side components from the users and group management API are based on capabilities.Capabilities are used to expose or restrict the available functionality provided by the different services and client side components. Examples of capabilities are:

  • Create a user

  • Update a user

  • Delete a user

  • Update user's attributes

  • Create a group

  • Update a group

  • Assign groups to a user

  • Assign roles to a user

Each security management provider must specify a set of capabilities supported. From the previous examples you can note that the Wildfly security management provider does not support the capability for the management of the attributes for a user - the user is only composed by the user name. On the other hand the Keycloak provider does support this capability.

The different views and user interface components rely on the capabilities supported by each provider, so if a capability is not supported by the provider in use, the UI does not provide the views for the management of that capability. As an example, consider that a concrete provider does not support deleting users - the delete user button on the user interface will be not available.

Please take a look at the concrete service provider documentation to check all the supported capabilities for each one, the default ones can be found here.

Before considering the installation and setup steps please note the following Drools and jBPM distributions come with built-in, pre-installed security management providers by default:

Please read each provider's documentation in order to apply the concrete settings for the target deployment environment.

On the other hand, if using a custom security management provider or need to include it on an existing application, consider the following installation options:

  • Enable the security management feature on an existing WAR distribution

  • Setup and installation in an existing or new project

NOTE: If no security management provider is installed in the application, there will be no available user interface for managing the security realm. Once a security management provider is installed and setup, the user and group management user interfaces are automatically enabled and accessible from the main menu.

If you're building an Uberfire based web application and you want to include the user and group management feature, please read this instructions.

The user and group management feature is presented using two different perspectives that are available from the main Home menu (considering that the feature is enabled) as:


Read the following sections for using both user and group management perspectives.

The user management interface is available from the User management menu entry in the Home menu.

The interface is presented using two main panels: the users explorer on the west panel and the user editor on the center one:


The users explorer, on west panel, lists by default all the users present on the application's security realm:


In addition to listing all users, the users explorer allows:

The user editor, on the center panel, is used to create, view, update or delete users. Once creating a new user o clicking an existing user on the users explorer, the user editor screen is opened.

To view an existing user, click on an existing user in the Users Explorer to open the User Editor screen. For example, viewing the admin user when using the Wildfly security management provider results in this screen:


Same admin user view operation but when using the Keycloak security management provider, instead of the Wildfly's one, results in this screen:


Note that the user editor, when using the Keycloak sec. management provider, includes the user attributes management section, but it's not present when using the Wildfly's one. So remember that the information and actions available on the user interface depends on each provider's capabilities (as explained in previous sections).

Viewing a user in the user editor provides the following information (if provider supports it):

  • The user name

  • The user's attributes

  • The assigned groups

  • The assigned roles

In order to update or delete an existing user, click on the Edit button present near to the username in the user editor screen:


Once the user editor presented in edit mode, different operations can be done (if the security management provider in use supports it):

There are 4 main processes which represent the stages of the Asset Management feature: Configure Repository, Promote Changes, Build and Release.

The Execution Server Management UI allows users create and modify Server Templates and Containers, it also allows users manage Remote Servers. This screen is available via Deploy -> Rule Deployments menu.


Note

The management UI is only available for KIE Managed Servers.

A Container is a KIE Container configuration of the Server Template. Click the Add Container button to create a new container for the current Server Template.

The search area can help users find an specific KJARs that they are looking for.


For Server Templates that have Process capabilities enabled, the Wizard has a 2nd optional step where users can configure some process related behaviors.


Once created the new Container will be displayed on the containers list just above the list of remote servers. Just after created a container is by default Stopped which is the only state that allows users to remove it.


A Container has the following tabs available for management and/or configuration:

  • Status

  • Version Configuration

  • Process Configuration

Status tab lists all the Remote Servers that are running the active Container. Each Remote Server is rendered as a Card, which displays to users status and endpoint.

Note

Only started Containers are deployed to remote servers.


Version Configuration tab allow users change the current version of the Container. User's can upgrade manually to a specific version using the "Upgrade" button, or enable/disable the Scanner. It's also possible to execute a ScanNow operation, that will scan for new versions only once.


Process Configuration is the same form that is displayed during New Container Wizard for Template Servers that have Process Capability. If Template Server doesn't have such capability, the action buttons will be disabled.


REST API calls to Knowledge Store allow you to manage the Knowledge Store content and manipulate the static data in the repositories of the Knowledge Store. The calls are asynchronous, that is, they continue their execution after the call was performed as a job. The job ID is returned by every calls to allow after the REST API call was performed to request the job status and verify whether the job finished successfully. Parameters of these calls are provided in the form of JSON entities.

When using Java code to interface with the REST API, the classes used in POST operations or otherwise returned by various operations can be found in the (org.kie.workbench.services:)kie-wb-common-services JAR. All of the classes mentioned below can be found in the org.kie.workbench.common.services.shared.rest package in that JAR.

Every Knowledge Store REST call returns its job ID after it was sent. This is necessary as the calls are asynchronous and you need to be able to reference the job to check its status as it goes through its lifecycle. During its lifecycle, a job can have the following statuses:

The following job calls are provided:

Repository calls are calls to the Knowledge Store that allow you to manage its Git repositories and their projects.

The following repositories calls are provided:

[GET] /repositories

Gets information about the repositories in the Knowledge Store

Returns a Collection<Map<String, String>> or Collection<RepositoryRequest> instance, depending on the JSON serialization library being used. The keys used in the Map<String, String> instance match the fields in the RepositoryRequest class


[GET] /repositories/{repositoryName}

Gets information about a repository

Returns a Map<String, String> or RepositoryRequest instance, depending on the JSON serialization library being used. The keys used in the Map<String, String> instance match the fields in the RepositoryRequest class


[POST] /repositories

Creates a new empty repository or a new repository cloned from an existing (git) repository

Consumes a RepositoryRequest instance

Returns a CreateOrCloneRepositoryRequest instance


[DELETE] /repositories/{repositoryName}

Removes the repository from the Knowledge Store

Returns a RemoveRepositoryRequest instance

[POST] /repositories/{repositoryName}/projects/

Creates a project in the repository

Consumes an Entity instance

Returns a CreateProjectRequest instance


[DELETE] /repositories/{repositoryName}/projects/

Deletes the project in the repository

Returns a DeleteProjectRequest instance

[GET] /repositories/{repositoryName}/projects/

Gets information about the projects

Returns a Collection<Map<String, String>> or Collection<ProjectResponse> instance, depending on the JSON serialization library being used. The keys used in the Map<String, String> instance match the fields in the ProjectResponse class


Organizational unit calls are calls to the Knowledge Store that allow you to manage its organizational units, so as to organize the connected Git repositories.

The following organizationalUnits calls are provided:

[POST] /organizationalunits

Creates an organizational unit in the Knowledge Store

Consumes an OrganizationalUnit instance

Returns a CreateOrganizationalUnitRequest instance


[GET] /organizationalunits/{orgUnitName}

Creates an organizational unit

Consumes an OrganizationalUnit instance

Returns a CreateOrganizationalUnitRequest instance


[POST] /organizationalunits/{orgUnitName}

Creates an organizational unit in the Knowledge Store

Consumes an UpdateOrganizationalUnit instance

Returns a UpdateOrganizationalUnitRequest instance


[DELETE] /organizationalunits/{organizationalUnitName}

Deletes a organizational unit

Returns a RemoveOrganizationalUnitRequest instance

[POST] /organizationalunits/{organizationalUnitName}/repositories/{repositoryName}

Adds the repository to the organizational unit

Returns a AddRepositoryToOrganizationalUnitRequest instance

[DELETE] /organizationalunits/{organizationalUnitName}/repositories/{repositoryName}

Removes the repository from the organizational unit

Returns a RemoveRepositoryFromOrganizationalUnitRequest instance

The URL templates in the table below are relative the following URL:


Single Sign On (SSO) and related token exchange mechanisms are becoming the most common scenario for the authentication and authorization in different environments on the web, specially when moving into the cloud.

This section talks about the integration of Keycloak with jBPM or Drools applications in order to use all the features provided on Keycloak. Keycloak is an integrated SSO and IDM for browser applications and RESTful web services. Lean more about it in the Keycloak's home page.

The result of the integration with Keycloak has lots of advantages such as:

  • Provide an integrated SSO and IDM environment for different clients, including jBPM and Drools workbenches

  • Social logins - use your Facebook, Google, Linkedin, etc accounts

  • User session management

  • And much more...

Next sections cover the following integration points with Keycloak:

  • Workbench authentication through a Keycloak server

    It basically consists of securing both web client and remote service clients through the Keycloak SSO. So either web interface or remote service consumers ( whether a user or a service ) will authenticate into trough KC.

  • Execution server authentication through a Keycloak server

    Consists of securing the remote services provided by the execution server (as it does not provides web interface). Any remote service consumer ( whether a user or a service ) will authenticate trough KC.

  • Consuming remote services

    This section describes how a third party clients can consume the remote service endpoints provided by both Workbench and Execution Server.

Keycloak provides an extensive documentation and several articles about the installation on different environments. This section describes the minimal setup for being able to build the integrated environment for the example. Please refer to the Keycloak documentation if you need more information.

Here are the steps for a minimal Keycloak installation and setup:

  • Download latest version of Keycloak from the Downloads section. This example is based on Keycloak 1.9.0.Final

  • Unzip the downloaded distribution of Keycloak into a folder, let's refer it as

    $KC_HOME
  • Run the KC server - This example is based on running both Keycloak and jBPM on same host. In order to avoid port conflicts you can use a port offset for the Keycloak's server as:

    $KC_HOME/bin/standalone.sh -Djboss.socket.binding.port-offset=100

  • Create a Keycloak's administration user - Execute the following command to create an admin user for this example:

    $KC_HOME/bin/add-user.sh -r master -u 'admin' -p 'admin'

The Keycloak administration console will be available at http://localhost:8180/auth/admin (use the admin/admin for login credentials).

Security realms are used to restrict the access for the different application's resources.

Once the Keycloak server is running next step is about creating a realm. This realm will provide the different users, roles, sessions, etc for the jBPM application/s.

Keycloak provides several examples for the realm creation and management, from the official examples to different articles with more examples.

Follow these steps in order to create the demo realm used later in this document:

  • Go to the Keycloak administration console and click on Add realm button. Give it the name demo.

  • Go to the Clients section (from the main admin console menu) and create a new client for the demo realm:

    • Client ID: kie

    • Client protocol: openid-connect

    • Acces type: confidential

    • Root URL: http://localhost:8080

    • Base URL: /kie-wb-6.4.0.Final

    • Redirect URIs: /kie-wb-6.4.0.Final/*

The resulting kie client settings screen:


Note: As you can see in the above settings it's being considered the value kie-wb-6.4.0.Final for the application's context path. If your jbpm application will be deployed on a different context path, host or port, just use your concrete settings here.

Last step for being able to use the demo realm from the jBPM workbench is create the application's user and roles:

At this point a Keycloak server is running on the host, setup with a minimal configuration set. Let's move to the jBPM workbench setup.

For this tutorial let's use a Wildfly as the application server for the jBPM workbench, as the jBPM installer does by default.

Let's assume, after running the jBPM installer, the $JBPM_HOME as the root path for the Wildfly server where the application has been deployed.

In order to use the Keycloak's authentication and authorization modules from the jBPM application, the Keycloak adapter for Wildfly must be installed on our server at $JBPM_HOME. Keycloak provides multiple adapters for different containers out of the box, if you are using another container or need to use another adapter, please take a look at the adapters configuration from Keycloak docs. Here are the steps to install and setup the adapter for Wildfly 8.2.x:

  • Download the adapter from here

  • Execute the following commands on your shell:

    cd $JBPM_HOME/unzip keycloak-wf8-adapter-dist.zip // Install the KC client adapter
    
    cd $JBPM_HOME/bin
    ./standalone.sh -c standalone-full.xml // Setup the KC client adapter.
    
    // ** Once server is up, open a new command line terminal and run:
    cd $JBPM_HOME/bin
    ./jboss-cli.sh -c --file=adapter-install.cli

Once installed the KC adapter into Wildfly, next step is to configure the adapter in order to specify different settings such as the location for the authentication server, the realm to use and so on.

Keycloak provides two ways of configuring the adapter:

In this example let's use the second option, use the Keycloak subsystem, so our WAR is free from this kind of settings. If you want to use the per WAR approach, please take a look here.

Edit the configuration file $JBPM_HOME/standalone/configuration/standalone-full.xml and locate the subsystem configuration section. Add the following content:

<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
  <secure-deployment name="kie-wb-6.4.0-Final.war">
    <realm>demo</realm>
    <realm-public-key>MIIBIjANBgkqhkiG9w0BAQEFAAOCA...</realm-public-key>
    <auth-server-url>http://localhost:8180/auth</auth-server-url>
    <ssl-required>external</ssl-required>
    <resource>kie</resource>
    <enable-basic-auth>true</enable-basic-auth>
    <credential name="secret">925f9190-a7c1-4cfd-8a3c-004f9c73dae6</credential>
    <principal-attribute>preferred_username</principal-attribute>
  </secure-deployment>
</subsystem>

If you have imported the example json files from this document in step 2, you can just use same configuration as above by using your concrete deployment name . Otherwise please use your values for these configurations:

  • Name for the secure deployment - Use your concrete application's WAR file name

  • Realm - Is the realm that the applications will use, in our example, the demo realm created the previous step.

  • Realm Public Key - Provide here the public key for the demo realm. It's not mandatory, if it's not specified, it will be retrieved from the server. Otherwise, you can find it in the Keycloak admin console -> Realm settings ( for demo realm ) -> Keys

  • Authentication server URL - The URL for the Keycloak's authentication server

  • Resource - The name for the client created on step 2. In our example, use the value kie.

  • Enable basic auth - For this example let's enable Basic authentication mechanism as well, so clients can use both Token (Baerer) and Basic approaches to perform the requests.

  • Credential - Use the password value for the kie client. You can find it in the Keycloak admin console -> Clients -> kie -> Credentials tab -> Copy the value for the secret.

For this example you have to take care about using your concrete values for secure-deployment name, realm-public-key and credential password. You can find detailed information about the KC adapter configurations here.

Both jBPM and Drools workbenches provides different remote service endpoints that can be consumed by third party clients using the remote API.

In order to authenticate those services thorough Keycloak the BasicAuthSecurityFilter must be disabled, apply those modifications for the the WEB-INF/web.xml file (app deployment descriptor) from jBPM's WAR file:

  • Remove the following filter from the deployment descriptor:

    <filter>  
      <filter-name>HTTP Basic Auth Filter</filter-name>
      <filter-class>org.uberfire.ext.security.server.BasicAuthSecurityFilter</filter-class>
      <init-param>
        <param-name>realmName</param-name>
        <param-value>KIE Workbench Realm</param-value>
      </init-param>
    </filter>
    
    <filter-mapping>
      <filter-name>HTTP Basic Auth Filter</filter-name>
      <url-pattern>/rest/*</url-pattern>
      <url-pattern>/maven2/*</url-pattern>
      <url-pattern>/ws/*</url-pattern>
    </filter-mapping>

  • Constraint the remote services URL patterns as:

    <security-constraint>
      <web-resource-collection>
        <web-resource-name>remote-services</web-resource-name>
        <url-pattern>/rest/*</url-pattern>
        <url-pattern>/maven2/*</url-pattern>
        <url-pattern>/ws/*</url-pattern>
      </web-resource-collection>
      <auth-constraint>
        <role-name>rest-all</role-name>
      </auth-constraint>
    </security-constraint>

Important note: The user that consumes the remote services must be member of role rest-all. As on described previous steps, the admin user in this example it's already a member of the rest-all role.

The KIE Execution Server provides a REST API than can be consumed for any third party clients,. This this section is about how to integration the KIE Execution Server with the Keycloak SSO in order to delegate the third party clients identity management to the SSO server.

Consider the above environment running, so consider having:

  • A Keycloak server running and listening on http://localhost:8180/auth

  • A realm named demo with a client named kie for the jBPM Workbench

  • A jBPM Workbench running at http://localhost:8080/kie-wb-6.4.0-Final

Follow these steps in order to add an execution server into this environment:

  • Create the client for the execution server on Keycloak

  • Install setup and the Execution server ( with the KC client adapter )

As per each execution server is going to be deployed, you have to create a new client on the demo realm in Keycloak.:

  • Go to the KC admin console -> Clients -> New client

  • Name: kie-execution-server

  • Root URL: http://localhost:8280/

  • Client protocol: openid-connect

  • Access type: confidential ( or public if you want so, but not recommended for production environments)

  • Valid redirect URIs: /kie-server-6.4.0.Final/*

  • Base URL: /kie-server-6.4.0.Final

In this example the admin user already created on previous steps is the one used for the client requests. So ensure that the admin user is member of the role kie-server in order to use the execution server's remote services. If the role does not exist, create it.

Note: This example considers that the execution server will be configured to run using a port offset of 200, so the HTTP port will be available at localhost:8280.

At this point, a client named kie-execution-server is ready on the KC server to use from the execution server.

Let's install, setup and deploy the execution server:

Consider your concrete environment settings if different from this example:

  • Secure deployment name -> use the name of the execution server war file being deployed

  • Public key -> Use the demo realm public key or leave it blank, the server will provide one if so

  • Resource -> This time, instead of the kie client used in the WB configuration, use the kie-execution-server client

  • Enable basic auth -> Up to you. You can enable Basic auth for third party service consumers

  • Credential -> Use the secret key for the kie-execution-server client. You can find it in the Credentialstab of the KC admin console

In order to use the different remote services provided by the Workbench or by an Execution Server, your client must be authenticated on the KC server and have a valid token to perform the requests.

Remember that in order to use the remote services, the authenticated user must have assigned:

Please ensure necessary roles are created and assigned to the users that will consume the remote services on the Keycloak admin console.

You have two options to consume the different remove service endpoints:

First step is to create a new client on Keycloak that allows the third party remote service clients to obtain a token. It can be done as:

Once a public client for our remote clients has been created, you can now obtain the token by performing an HTTP request to the KC server's tokens endpoint. Here is an example for command line:

RESULT=`curl --data "grant_type=password&client_id=kie-remote&username=admin&passwordpassword=<the_client_secret>" http://localhost:8180/auth/realms/demo/protocol/openid-connect/token`

TOKEN=`echo $RESULT | sed 's/.*access_token":"//g' | sed 's/".*//g'`

At this point, if you echo the $TOKEN it will output the token string obtained from the KC server, that can be now used to authorize further calls to the remote endpoints. For exmple, if you want to check the internal jBPM repositories:

curl -H "Authorization: bearer $TOKEN" http://localhost:8080/kie-wb-6.4.0.Final/rest/repositories

The VFS repositories (usually git repositories) stores all the assets (such as rules, decision tables, process definitions, forms, etc). If that VFS resides on each local server, then it must be kept in sync between all servers of a cluster.

Use Apache Zookeeper and Apache Helix to accomplish this. Zookeeper glues all the parts together. Helix is the cluster management component that registers all cluster details (nodes, resources and the cluster itself). Uberfire (on top of which Workbench is build) uses those 2 components to provide VFS clustering.

To create a VFS cluster:

  1. Download Apache Zookeeper and Apache Helix.

  2. Install both:

    1. Unzip Zookeeper into a directory ($ZOOKEEPER_HOME).

    2. In $ZOOKEEPER_HOME, copy zoo_sample.conf to zoo.conf

    3. Edit zoo.conf. Adjust the settings if needed. Usually only these 2 properties are relevant:

      # the directory where the snapshot is stored.
      dataDir=/tmp/zookeeper
      # the port at which the clients will connect
      clientPort=2181
    4. Unzip Helix into a directory ($HELIX_HOME).

  3. Configure the cluster in Zookeeper:

    1. Go to its bin directory:

      $ cd $ZOOKEEPER_HOME/bin
    2. Start the Zookeeper server:

      $ sudo ./zkServer.sh start

      If the server fails to start, verify that the dataDir (as specified in zoo.conf) is accessible.

    3. To review Zookeeper's activities, open zookeeper.out:

      $ cat $ZOOKEEPER_HOME/bin/zookeeper.out
  4. Configure the cluster in Helix:

    1. Go to its bin directory:

      $ cd $HELIX_HOME/bin
    2. Create the cluster:

      $ ./helix-admin.sh --zkSvr localhost:2181 --addCluster kie-cluster

      The zkSvr value must match the used Zookeeper server. The cluster name (kie-cluster) can be changed as needed.

    3. Add nodes to the cluster:

      # Node 1
      $ ./helix-admin.sh --zkSvr localhost:2181 --addNode kie-cluster nodeOne:12345
      # Node 2
      $ ./helix-admin.sh --zkSvr localhost:2181 --addNode kie-cluster nodeTwo:12346
      ...

      Usually the number of nodes a in cluster equal the number of application servers in the cluster. The node names (nodeOne:12345 , ...) can be changed as needed.

      Note

      nodeOne:12345 is the unique identifier of the node, which will be referenced later on when configuring application servers. It is not a host and port number, but instead it is used to uniquely identify the logical node.

    4. Add resources to the cluster:

      $ ./helix-admin.sh --zkSvr localhost:2181 --addResource kie-cluster vfs-repo 1 LeaderStandby AUTO_REBALANCE

      The resource name (vfs-repo) can be changed as needed.

    5. Rebalance the cluster to initialize it:

      $ ./helix-admin.sh --zkSvr localhost:2181 --rebalance kie-cluster vfs-repo 2
    6. Start the Helix controller to manage the cluster:

      $  ./run-helix-controller.sh --zkSvr localhost:2181 --cluster kie-cluster 2>&1 > /tmp/controller.log &
  5. Configure the security domain correctly on the application server. For example on WildFly and JBoss EAP:

    1. Edit the file $JBOSS_HOME/domain/configuration/domain.xml.

      For simplicity sake, presume we use the default domain configuration which uses the profile full that defines two server nodes as part of main-server-group.

    2. Locate the profile full and add a new security domain by copying the other security domain already defined there by default:

      <security-domain name="kie-ide" 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>
          </authentication>
      </security-domain>

      Important

      The security-domain name is a magic value.

  6. Configure the system properties for the cluster on the application server. For example on WildFly and JBoss EAP:

    1. Edit the file $JBOSS_HOME/domain/configuration/host.xml.

    2. Locate the XML elements server that belong to the main-server-group and add the necessary system property.

      For example for nodeOne:

      <system-properties>
        <property name="jboss.node.name" value="nodeOne" boot-time="false"/>
        <property name="org.uberfire.nio.git.dir" value="/tmp/kie/nodeone" boot-time="false"/>
        <property name="org.uberfire.metadata.index.dir" value="/tmp/kie/nodeone" boot-time="false"/>
        <property name="org.uberfire.cluster.id" value="kie-cluster" boot-time="false"/>
        <property name="org.uberfire.cluster.zk" value="localhost:2181" boot-time="false"/>
        <property name="org.uberfire.cluster.local.id" value="nodeOne_12345" boot-time="false"/>
        <property name="org.uberfire.cluster.vfs.lock" value="vfs-repo" boot-time="false"/>
        <!-- If you're running both nodes on the same machine: -->
        <property name="org.uberfire.nio.git.daemon.port" value="9418" boot-time="false"/>
      </system-properties>

      And for nodeTwo:

      <system-properties>
        <property name="jboss.node.name" value="nodeTwo" boot-time="false"/>
        <property name="org.uberfire.nio.git.dir" value="/tmp/kie/nodetwo" boot-time="false"/>
        <property name="org.uberfire.metadata.index.dir" value="/tmp/kie/nodetwo" boot-time="false"/>
        <property name="org.uberfire.cluster.id" value="kie-cluster" boot-time="false"/>
        <property name="org.uberfire.cluster.zk" value="localhost:2181" boot-time="false"/>
        <property name="org.uberfire.cluster.local.id" value="nodeTwo_12346" boot-time="false"/>
        <property name="org.uberfire.cluster.vfs.lock" value="vfs-repo" boot-time="false"/>
        <!-- If you're running both nodes on the same machine: -->
        <property name="org.uberfire.nio.git.daemon.port" value="9419" boot-time="false"/>
      </system-properties>

      Make sure the cluster, node and resource names match those configured in Helix.

The KIE Server is a standalone execution server for rules, planning and workflows.

Table of Contents

5. KIE Execution Server
5.1. Overview
5.1.1. Glossary
5.2. Installing the KIE Server
5.2.1. Bootstrap switches
5.2.2. Installation details for different containers
5.3. Kie Server setup
5.3.1. Managed Kie Server
5.3.2. Unmanaged KIE Execution Server
5.4. Creating a Kie Container
5.5. Managing Containers
5.5.1. Starting a Container
5.5.2. Stopping and Deleting a Container
5.5.3. Updating a Container
5.6. Kie Server REST API
5.6.1. [GET] /
5.6.2. [POST] /
5.6.3. [GET] /containers
5.6.4. ⁠[GET] /containers/{id}
5.6.5. [PUT] /containers/{id}
5.6.6. [DELETE] /containers/{id}
5.6.7. [POST] /containers/instances/{id}
5.6.8. [GET] /containers/{id}/release-id
5.6.9. [POST] /containers/{id}/release-id
5.6.10. [GET] /containers/{id}/scanner
5.6.11. [POST] /containers/{id}/scanner
5.6.12. Native REST client for Execution Server
5.7. OptaPlanner REST API
5.7.1. [GET] /containers/{containerId}/solvers
5.7.2. [PUT] /containers/{containerId}/solvers/{solverId}
5.7.3. [GET] /containers/{containerId}/solvers/{solverId}
5.7.4. [POST] /containers/{containerId}/solvers/{solverId}
5.7.5. [GET] /containers/{containerId}/solvers/{solverId}/bestsolution
5.7.6. [DELETE] /containers/{containerId}/solvers/{solverId}
5.8. Controller REST API
5.8.1. [GET] /management/servers
5.8.2. [GET] /management/server/{id}
5.8.3. [PUT] /management/server/{id}
5.8.4. [DELETE] /management/server/{id}
5.8.5. [GET] /management/server/{id}/containers
5.8.6. [GET] /management/server/{id}/containers/{containerId}
5.8.7. [PUT] /management/server/{id}/containers/{containerId}
5.8.8. [DELETE] /management/server/{id}/containers/{containerId}
5.8.9. [POST] /management/server/{id}/containers/{containerId}/status/started
5.8.10. [POST] /management/server/{id}/containers/{containerId}/status/stopped
5.9. Kie Server Java Client API
5.9.1. Maven Configuration
5.9.2. Client Configuration
5.9.3. Server Response
5.9.4. Server Capabilities
5.9.5. Kie Containers
5.9.6. Managing Containers
5.9.7. Available Clients for the Decision Server
5.9.8. Sending commands to the server
5.9.9. Listing available business processes
5.1. Overview
5.1.1. Glossary
5.2. Installing the KIE Server
5.2.1. Bootstrap switches
5.2.2. Installation details for different containers
5.3. Kie Server setup
5.3.1. Managed Kie Server
5.3.2. Unmanaged KIE Execution Server
5.4. Creating a Kie Container
5.5. Managing Containers
5.5.1. Starting a Container
5.5.2. Stopping and Deleting a Container
5.5.3. Updating a Container
5.6. Kie Server REST API
5.6.1. [GET] /
5.6.2. [POST] /
5.6.3. [GET] /containers
5.6.4. ⁠[GET] /containers/{id}
5.6.5. [PUT] /containers/{id}
5.6.6. [DELETE] /containers/{id}
5.6.7. [POST] /containers/instances/{id}
5.6.8. [GET] /containers/{id}/release-id
5.6.9. [POST] /containers/{id}/release-id
5.6.10. [GET] /containers/{id}/scanner
5.6.11. [POST] /containers/{id}/scanner
5.6.12. Native REST client for Execution Server
5.7. OptaPlanner REST API
5.7.1. [GET] /containers/{containerId}/solvers
5.7.2. [PUT] /containers/{containerId}/solvers/{solverId}
5.7.3. [GET] /containers/{containerId}/solvers/{solverId}
5.7.4. [POST] /containers/{containerId}/solvers/{solverId}
5.7.5. [GET] /containers/{containerId}/solvers/{solverId}/bestsolution
5.7.6. [DELETE] /containers/{containerId}/solvers/{solverId}
5.8. Controller REST API
5.8.1. [GET] /management/servers
5.8.2. [GET] /management/server/{id}
5.8.3. [PUT] /management/server/{id}
5.8.4. [DELETE] /management/server/{id}
5.8.5. [GET] /management/server/{id}/containers
5.8.6. [GET] /management/server/{id}/containers/{containerId}
5.8.7. [PUT] /management/server/{id}/containers/{containerId}
5.8.8. [DELETE] /management/server/{id}/containers/{containerId}
5.8.9. [POST] /management/server/{id}/containers/{containerId}/status/started
5.8.10. [POST] /management/server/{id}/containers/{containerId}/status/stopped
5.9. Kie Server Java Client API
5.9.1. Maven Configuration
5.9.2. Client Configuration
5.9.3. Server Response
5.9.4. Server Capabilities
5.9.5. Kie Containers
5.9.6. Managing Containers
5.9.7. Available Clients for the Decision Server
5.9.8. Sending commands to the server
5.9.9. Listing available business processes

The Kie Server is a modular, standalone server component that can be used to instantiate and execute rules and processes. It exposes this functionality via REST, JMS and Java interfaces to client application. It also provides seamless integration with the Kie Workbench.

At its core, the Kie Server is a configurable web application packaged as a WAR file. Distributions are availables for pure web containers (like Tomcat) and for JEE 6 and JEE 7 containers.

Most capabilities on the Kie Server are configurable, and based on the concepts of extensions. Each extension can be enabled/disabled independently, allowing the user to configure the server to its need.

The current version of the Kie Server ships with two default extensions:

Both extensions enabled by default, but can be disabled by setting the corresponding property (see configuration chapter for details).

This server was designed to have a low footprint, with minimal memory consumption, and therefore, to be easily deployable on a cloud environment. Each instance of this server can open and instantiate multiple Kie Containers which allows you to execute multiple services in parallel.

The KIE Server is distributed as a web application archive (WAR) file. The WAR file comes in three different packagings:

To install the KIE Execution Server and verify it is running, complete the following steps:

The Kie Server accepts a number of bootstrap switches (system properties) to configure the behaviour of the server. The following is a table of all the supported switches.

Table 5.1. Kie Server bootstrap switches

PropertyValueDescriptionRequired
org.drools.server.ext.disabledboolean (default is "false")If true, disables the BRM support (i.e. rules support).No
org.jbpm.server.ext.disabledboolean (default is "false")If true, disables the BPM support (i.e. processes support)No
org.kie.server.idstringAn arbitrary ID to be assigned to this server. If a remote controller is configured, this is the ID under which the server will connect to the controller to fetch the kie container configurations.No. If not provided, an ID is automatically generated.
org.kie.server.userstring (default is "kieserver")User name used to connect with the kieserver from the controller, required when running in managed modeNo
org.kie.server.pwdstring (default is "kieserver1!")Password used to connect with the kieserver from the controller, required when running in managed modeNo
org.kie.server.controllercomma separated list of urlsList of urls to controller REST endpoint. E.g.: http://localhost:8080/kie-wb/restYes when using a controller
org.kie.server.controller.userstring (default is "kieserver")Username used to connect to the controller REST apiYes when using a controller
org.kie.server.controller.pwdstring (default is "kieserver1!")Password used to connect to the controller REST apiYes when using a controller
org.kie.server.locationURL location of kie server instanceThe URL used by the controller to call back on this server. E.g.: http://localhost:8230/kie-server/services/rest/serverYes when using a controller
org.kie.server.domainstringJAAS LoginContext domain that shall be used to authenticate users when using JMSNo
org.kie.server.bypass.auth.userboolean (default is "false")Allows to bypass the authenticated user for task related operations e.g. queriesNo
org.kie.server.repovalid file system path (default is ".")Location on local file system where kie server state files will be storedNo
org.kie.server.persistence.dsstringDatasource JNDI nameYes when BPM support enabled
org.kie.server.persistence.tmstringTransaction manager platform for Hibernate properties setYes when BPM support enabled
org.kie.server.persistence.dialectstringHibernate dialect to be usedYes when BPM support enabled
org.jbpm.ht.callbackstringOne of supported callbacks for Task Service (default jaas)No
org.jbpm.ht.custom.callbackstringCustom implementation of UserGroupCallback in case org.jbpm.ht.callback was set to ‘custom’No
kie.maven.settings.customvalid file system path Location of custom settings.xml for maven configurationNo
org.kie.executor.intervalinteger (default is 3)Number of time units between polls by executorNo
org.kie.executor.pool.sizeinteger (default is 1)Number of threads in the pool for async workNo
org.kie.executor.retry.countinteger (default is 3)Number of retries to handle errorsNo
org.kie.executor.timeunitTimeUnit (default is "SECONDS")TimeUnit representing intervalNo
org.kie.executor.disabledboolean (default is "false")Disables executor completelyNo
kie.server.jms.queues.responsestring (default is "queue/KIE.SERVER.RESPONSE")JNDI name of response queue for JMSNo
org.kie.server.controller.connectlong (default is 10000)Waiting time in milliseconds between repeated attempts to connect kie server to controller when kie server starts upNo
org.drools.server.filter.classesboolean (default is "false")If true, accept only classes which are annotated with @org.kie.api.remote.Remotable or @javax.xml.bind.annotation.XmlRootElement as extra JAXB classesNo
    


A managed instance is one that requires a controller to be available to properly startup the Kie Server instance.

A Controller is a component responsible for keeping and managing a Kie Server Configuration in centralized way. Each controller can manager multiple configurations at once and there can be multiple controllers in the environment. Managed KIE Servers can be configured with a list of controllers but will connect to only one at a time.

At startup, if a Kie Server is configured with a list of controllers, it will try succesivelly to connect to each of them until a connection is successfully stablished with one of them. If for any reason a connection can't be stablished, the server will not start, even if there is local storage available with configuration. This happens by design in order to ensure consistency. For instance, if the Kie Server was down and the configuration has changed, this restriction guarantees that it will run with up to date configuration or not at all.

The configuration sets, among other things:

The Controller, besides providing configuration management, is also responsible for overall management of Kie Servers. It provides a REST api that is divided into two parts:

The controller deals only with the Kie Server configuration or definition to put it differently. It does not handle any runtime components of KIE Execution Server instances. They are always considered remote to controller. The controller is responsible for persisting the configuration to preserve restarts of the controller itself. It should manage the synchronization as well in case multiple controllers are configured to keep all definitions up to date on all instances of the controller.

By default controller is shipped with Kie Workbench and provides a fully featured management interface (both REST api and UI). It uses underlying git repository as persistent store and thus when GIT repositories are clustered (using Apache Zookeeper and Apache Helix) it will cover the controllers synchronization as well.

The diagram above illustrates the single controller (workbench) setup with multiple Kie Server instances managed by it.

The diagram bellow illustrates the clustered setup where there are multiple instances of controller synchronized over Zookeeper.

In the above diagram we can see that the Kie Server instances are capable of connecting to any controllers, but they will connect to only one. Each instance will attempt to connect to controller as long as it can reach one. Once connection is established with one of the controllers it will skip the others.

Once your Execution Server is registered, you can start adding Kie Containers to it.

Kie Containers are self contained environments that have been provisioned to hold instances of your packaged and deployed rule instances.

Containers within the Execution Server can be started, stopped and updated from within KIE Workbench.⁠

You can update deployed KieContainers without restarting the Execution Server. This is useful in cases where the Business Rules change, creating new versions of packages to be provisioned.

You can have multiple versions of the same package provisioned and deployed, each to a different KieContainer.

To update deployments in a KieContainer dynamically, click on the icon next to the Container. This will open up the Container Info screen. An example of this screen is shown here:

The Container Info screen is a useful tool because it not only allows you to see the endpoint for this KieContainer, but it also allows you to either manually or automatically refresh the provision if an update is available. The update can be manual or automatic:

Manual Update: To manually update a KieContainer, enter the new Version number in the Version box and click on the Update button. You can of course, update the Group Id or the Artifact Id , if these have changed as well. Once updated, the Execution server updates the container and shows you the resolved GAV attributes at the bottom of the screen in the Resolved Release Id section.

Automatic Update: If you want a deployed Container to always have the latest version of your deployment without manually editing it, you will need to set the Version property to the value of LATEST and start a Scanner. This will ensure that the deployed provision always contains the latest version. The Scanner can be started just once on demand by clicking the Scan Now button or you can start it in the background with scans happening at a specified interval (in seconds).You can also set this value to LATEST when you are first creating this deployment. The Resolved Release Id in this case will show you the actual, latest version number.

The Execution Server supports the following commands via the REST API.

Please note the following before using these commands:

Commands outlined in this section can be sent with any REST client, whether it is curl, RESTEasy or .NET based application. However, when sending requests from Java based application, users can utilize out of the box native client for remote communication with Execution Server. This client is part of the org.kie:kie-server-client project. It doesn't allow creating XML request, therefore it is necessary generate them before, for example, using Drools API.


Once the request is generated it can be sent using kie-server-client as follows:


When the Planner capability is enabled, the Kie Server supports the following additional REST APIs. As usual, all these APIs are also available through JMS and the Java client API. Please also note:

The example requests and responses used below presume that a kie container is build using the optacloud example of OptaPlanner Workbench, by calling a PUT on /services/rest/server/containers/optacloud-kiecontainer-1 with this content:

<kie-container container-id="optacloud-kiecontainer-1">
  <release-id>
    <group-id>opta</group-id>
    <artifact-id>optacloud</artifact-id> 
    <version>1.0.0</version> 
  </release-id> 
</kie-container>

Updates the state of the {solverId} in container {containerId}, most notably to start solving. The request's body is a marshalled SolverInstance and can either request the solver to solve a planning problem or to stop solving one. The SolverInstance state determines which operation should be executed and can be set one of two possible values:

For example, to solve an optacloud problem with 2 computers and 1 process:


Notice that the response does not contain the best solution yet, because solving can take seconds, minutes, hours or days and this would time out the HTTP request:


Instead, it's solving asynchronously and you need to call the bestsolution URL to get the best solution.

Returns the best solution found at the time the request is made. If the solver hasn't terminated yet (so the status field is still SOLVING), it will return the best solution found up to then, but later calls can return a better solution.⁠

For example, the problem submitted above would return this solution, with the process assigned to the second computer (because the first one doesn't have enough memory).


When you have Managed Kie Server setup, you need to manage Kie Servers and Containers via a Controller. Generally, it's done by workbench UI but you may also use Controller REST API.

The Kie Server has a great Java API to wrap REST or JMS requests to be sent to the server. In this section we will explore some of the possibilities of this API.

To build commands to the server you must use the class org.kie.api.command.KieCommands, that can be created using org.kie.api.KieServices.get().getCommands(). The command to be send must be a BatchExecutionCommand or a single command(if a single command is sent, the server wraps it into a BatchExecutionCommand):