optaPlannerLogo

1. OptaPlanner Engine

OptaPlanner Workbench (Business Central)

2. Quickstart

2.1. Cloud Balancing Example Setup

This chapter describes the process of setting up environment to run Cloud Balancing example using Business Central and KIE Server. At the end of the chapter, the user will be able to submit sample planning problem to the KIE Server and query the best solution.

2.1.1. Environment Setup

The first step consists of setting up Wildfly instance and deploying KIE artifacts.

2.1.1.1. Download Required Artifacts:
  • Java EE compliant application server. This example uses WildFly

  • KIE Server and Business Central war files from OptaPlanner website

2.1.1.2. Create New User
  • Unix users:

    $WILDFLY_HOME/bin/add-user.sh
  • Windows users:

    $WILDFLY_HOME/bin/add-user.bat
    • User type: application user

    • Username: planner

    • Password: Planner123_

    • Groups: kie-server,admin

2.1.1.3. Deploy Business Central and KIE Server
  • Copy Business Central war to $WILDFLY_HOME/standalone/deployments/business-central.war

  • Copy KIE Server war to $WILDFLY_HOME/standalone/deployments/kie-server.war

2.1.1.4. Start Server
  • Unix users:

    ./bin/standalone.sh --server-config=standalone-full.xml \
     -Dorg.kie.server.user=planner \
     -Dorg.kie.server.pwd=Planner123_ \
     -Dorg.kie.server.controller.user=planner \
     -Dorg.kie.server.controller.pwd=Planner123_ \
     -Dorg.kie.server.id=wildfly-kieserver \
     -Dorg.kie.server.location=http://localhost:8080/kie-server/services/rest/server \
     -Dorg.kie.server.controller=http://localhost:8080/business-central/rest/controller
  • Windows users:

    ./bin/standalone.bat --server-config=standalone-full.xml \
     -Dorg.kie.server.user=planner \
     -Dorg.kie.server.pwd=Planner123_ \
     -Dorg.kie.server.controller.user=planner \
     -Dorg.kie.server.controller.pwd=Planner123_ \
     -Dorg.kie.server.id=wildfly-kieserver \
     -Dorg.kie.server.location=http://localhost:8080/kie-server/services/rest/server \
     -Dorg.kie.server.controller=http://localhost:8080/business-central/rest/controller
2.1.1.5. Open Business Central in Browser

Navigate to http://localhost:8080/business-central in a web browser to access Business Central. Use credentials defined in the previous step to log in.

2.1.2. Project Setup

The second step consists of setting up logical structures required to create a new project.

2.1.2.1. Create Organizational Unit
  • Navigate to Authoring → Administration → Organizational Units → Manage Organizational Units and click Add

    • Name: Cloud department

    • Default Group ID: clouddepartment

2.1.2.2. Create Repository
  • Select Authoring → Administration → Repositories → New repository

    • Repository Name: cloudbalancing

    • In Organizational Unit: Cloud department

org unit repository
2.1.2.3. Create Project
  • Select Authoring → Project Authoring → New Project → Advanced setup

    • Project Name: cloudbalancing

    • Project Description: Assign processes to computers based on available CPU power, memory, network bandwidth and cost

    • Group ID: clouddepartment

    • Artifact ID: cloudbalancing

    • Version: 1.0

2.1.3. Data Model

This step consists of creating a data model for the Cloud Balancing problem. Data objects and their attributes are defined.

2.1.3.1. Create Data Object
  • Select Add Asset → Data Object

    • Data Object: CloudComputer

    • Package: clouddepartment.cloudbalancing

2.1.3.2. Add Fields

Add multiple fields of given types.

  • Click Add field

    • id: long

    • cpuPower: int

    • memory: int

    • networkBandwith: int

    • cost: int

  • Click Save

  • Click Close icon

data object
2.1.3.3. Complete the Data Model

Using the same approach, create CloudProcess and CloudBalance data objects with the following attributes:

  • CloudProcess

    • id: long

    • requiredCpuPower: int

    • requiredMemory: int

    • requiredNetworkBandwith: int

    • computer: clouddepartment.cloudbalancing.CloudComputer

  • CloudBalance

    • id: long

    • computerList: List<clouddepartment.cloudbalancing.CloudComputer>

    • processList: List<clouddepartment.cloudbalancing.CloudProcess>

2.1.4. Planner Configuration

This section explains how to enhance the data model created in the previous step with Planner annotations.

2.1.4.1. CloudBalance Data Object
  • Select CloudBalance

    • Open OptaPlanner dock

    • Check Planning Solution

planning solution
  • Select computerList field

    • Open OptaPlanner dock

    • Check Planning Value Range Provider

    • Set id to computerRange

  • Select processList field

    • Open OptaPlanner dock

    • Check Planning Entity Collection

  • Click Save

  • Click Close icon

2.1.4.2. CloudProcess
  • Select CloudProcess

    • Open OptaPlanner dock

    • Check Planning Entity

  • Select computer field

    • Open OptaPlanner dock

    • Check Planning Variable

    • Set valueRangeId to computerRange

  • Click Save

  • Click Close icon

2.1.5. Drools Rules

This section contains constraint definitions for the CloudBalancing problem using two different approaches - Free-form DRL Editor and Guided Rule Editor.

2.1.5.1. Free-form DRL Editor
  • Select Add Asset → DRL file

    • DRL file: cloudBalancingScoreRules

    • Package: clouddepartment.cloudbalancing

      package clouddepartment.cloudbalancing;
      
      import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScoreHolder;
      
      import clouddepartment.cloudbalancing.CloudBalance;
      import clouddepartment.cloudbalancing.CloudComputer;
      import clouddepartment.cloudbalancing.CloudProcess;
      
      rule "requiredCpuPowerTotal"
          when
              $computer : CloudComputer($cpuPower : cpuPower)
              accumulate(
                  CloudProcess(
                      computer == $computer,
                      $requiredCpuPower : requiredCpuPower);
                  $requiredCpuPowerTotal : sum($requiredCpuPower);
                  $requiredCpuPowerTotal > $cpuPower
              )
          then
              scoreHolder.addHardConstraintMatch(kcontext, $cpuPower - $requiredCpuPowerTotal);
      end
      
      rule "requiredMemoryTotal"
          when
              $computer : CloudComputer($memory : memory)
              accumulate(
                  CloudProcess(
                      computer == $computer,
                      $requiredMemory : requiredMemory);
                  $requiredMemoryTotal : sum($requiredMemory);
                  $requiredMemoryTotal > $memory
              )
          then
              scoreHolder.addHardConstraintMatch(kcontext, $memory - $requiredMemoryTotal);
      end
      
      rule "requiredNetworkBandwidthTotal"
          when
              $computer : CloudComputer($networkBandwidth : networkBandwidth)
              accumulate(
                  CloudProcess(
                      computer == $computer,
                      $requiredNetworkBandwidth : requiredNetworkBandwidth);
                  $requiredNetworkBandwidthTotal : sum($requiredNetworkBandwidth);
                  $requiredNetworkBandwidthTotal > $networkBandwidth
              )
          then
              scoreHolder.addHardConstraintMatch(kcontext, $networkBandwidth - $requiredNetworkBandwidthTotal);
      end
  • Click Save

  • Click Close icon

2.1.5.2. Guided Rule Editor
  • Select Add Asset → Guided Rule

    • Guided Rule: computerCost

    • Package: clouddepartment.cloudbalancing

guided rule
  • Click Save

  • Click Close icon

2.1.6. Solver Configuration

The following task is to create Planner Solver configuration to tweak Planner engine parameters.

2.1.6.1. Create Solver Configuration
  • Select Add Asset → Solver configuration

    • Solver configuration: Cloud Balancing Solver Configuration

    • Package: clouddepartment.cloudbalancing

    • Navigate to Termination

      • Click Add and select Time spent

      • Set Seconds to 30 to stop the solving process after 30 seconds

  • Click Save

  • Click Close icon

solver config

2.1.7. Build & Deploy

2.1.7.1. Add Kie Container
  • Navigate to Deploy → Execution Servers and click Add Container

    • Name: cloudbalancing

    • Group Name: clouddepartment

    • Artifact Id: cloudbalancing

    • Version: 1.0

2.1.7.2. Build Project
  • Navigate to Authoring → Project Authoring → cloudbalancing and click Build & Deploy

2.1.7.3. Start Container
  • Navigate to Deploy → Execution Servers

    • Select container cloudbalancing and click Start

container

2.1.8. KIE Server Integration

This section describes basic steps required to set up Planner & KIE Server integration. A sample Cloud Balancing problem instance is submitted to the KIE Server and the result is queried using REST API the server exposes.

All HTTP requests performed in this chapter use the following header:

authorization: Basic cGxhbm5lcjpQbGFubmVyMTIzXw==
X-KIE-ContentType: xstream
content-type: application/xml
2.1.8.1. Register Solver
2.1.8.2. Submit Solution
  • POST http://localhost:8080/kie-server/services/rest/server/containers/cloudbalancing/solvers/cloudBalancingSolver/state/solving

    Request body

    <planning-problem class="clouddepartment.cloudbalancing.CloudBalance" id="1">
      <id>0</id>
      <computerList id="2">
        <clouddepartment.cloudbalancing.CloudComputer id="3">
          <id>0</id>
          <cpuPower>24</cpuPower>
          <memory>96</memory>
          <networkBandwidth>16</networkBandwidth>
          <cost>4800</cost>
        </clouddepartment.cloudbalancing.CloudComputer>
        <clouddepartment.cloudbalancing.CloudComputer id="4">
          <id>1</id>
          <cpuPower>6</cpuPower>
          <memory>4</memory>
          <networkBandwidth>6</networkBandwidth>
          <cost>660</cost>
        </clouddepartment.cloudbalancing.CloudComputer>
      </computerList>
      <processList id="5">
        <clouddepartment.cloudbalancing.CloudProcess id="6">
          <id>0</id>
          <requiredCpuPower>1</requiredCpuPower>
          <requiredMemory>1</requiredMemory>
          <requiredNetworkBandwidth>1</requiredNetworkBandwidth>
        </clouddepartment.cloudbalancing.CloudProcess>
        <clouddepartment.cloudbalancing.CloudProcess id="7">
          <id>1</id>
          <requiredCpuPower>3</requiredCpuPower>
          <requiredMemory>6</requiredMemory>
          <requiredNetworkBandwidth>1</requiredNetworkBandwidth>
        </clouddepartment.cloudbalancing.CloudProcess>
        <clouddepartment.cloudbalancing.CloudProcess id="8">
          <id>2</id>
          <requiredCpuPower>1</requiredCpuPower>
          <requiredMemory>1</requiredMemory>
          <requiredNetworkBandwidth>3</requiredNetworkBandwidth>
        </clouddepartment.cloudbalancing.CloudProcess>
        <clouddepartment.cloudbalancing.CloudProcess id="9">
          <id>3</id>
          <requiredCpuPower>1</requiredCpuPower>
          <requiredMemory>2</requiredMemory>
          <requiredNetworkBandwidth>11</requiredNetworkBandwidth>
        </clouddepartment.cloudbalancing.CloudProcess>
        <clouddepartment.cloudbalancing.CloudProcess id="10">
          <id>4</id>
          <requiredCpuPower>1</requiredCpuPower>
          <requiredMemory>1</requiredMemory>
          <requiredNetworkBandwidth>1</requiredNetworkBandwidth>
        </clouddepartment.cloudbalancing.CloudProcess>
        <clouddepartment.cloudbalancing.CloudProcess id="11">
          <id>5</id>
          <requiredCpuPower>1</requiredCpuPower>
          <requiredMemory>1</requiredMemory>
          <requiredNetworkBandwidth>5</requiredNetworkBandwidth>
        </clouddepartment.cloudbalancing.CloudProcess>
      </processList>
    </planning-problem>

3. Business Central (General)

3.1. Installation

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

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

3.1.3. Troubleshooting

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

3.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'.

3.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 KIE Server controller

Use the following properties to configure the connections with the KIE Server nodes from the KIE Server controller:

  • org.kie.server.controller: The URL is used to connect to the KIE Server 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 KIE Server controller. This property is only required when using this Business Central installation as a KIE Server controller.

  • org.kie.server.pwd: Password used to connect to the KIE Server nodes from the KIE Server controller. This property is only required when using this Business Central installation as a KIE Server 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.

KIE Server controller

Use the following properties to configure how to connect to the KIE Server controller:

  • org.kie.workbench.controller: The URL used to connect to the KIE Server controller, for example, ws://localhost:8080/kie-server-controller/websocket/controller.

  • org.kie.workbench.controller.user: The KIE Server controller user. Default value: kieserver.

  • org.kie.workbench.controller.pwd: The KIE Server controller password. Default value: kieserver1!.

  • org.kie.workbench.controller.token: The token string used to connect to the KIE Server controller.

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 KIE Server controller.

  • kie.keystore.key.ctrl.pwd: The password of the alias for the default REST KIE Server 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.

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

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

3.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 1. New Project button

Give the Project a name and optional description.

QuickStart new project wizard
Figure 2. Giving Project a name

3.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 3. Creating "Data Object"

Set the name and select a package for the new type.

QuickStart create data object popup
Figure 4. 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 5. Click "Create" and add the field

Click "Save" to update the model.

QuickStart confirm save
Figure 6. Clicking "Save"

3.3.4. Define Rule

Select "DRL file" (for example) from the "Add Asset" menu.

QuickStart create drl file
Figure 7. 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 8. 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 9. Defining a rule

Once the rule has been defined it will need to be saved in the same way we saved the model.

3.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 10. 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.

3.4. Configuration

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

3.4.2. Roles

Business Central uses the following roles:

  • admin

  • analyst

  • developer

  • manager

  • user

3.4.2.1. Admin

Administrates the BPMS system.

  • Manages users

  • Manages VFS Repositories

  • Has full access to make any necessary changes

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

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

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

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

3.5. Introduction

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

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

3.5.3. Business Central overview

Business Central is structured with Spaces and Projects:

workbenchStructureOverview
3.5.3.1. Space

Spaces are useful to model departments and divisions.

A Space can hold multiple Projects.

Space
3.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.

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

3.6. Changing the layout

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

3.7. Authoring (General)

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

3.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 11. 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 12. 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 13. 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 14. 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 15. The Asset Editor - Locked assets cannot be edited by other users

3.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".

3.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 16. 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 17. Existing Tags

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

3.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 18. Expanded asset group
3.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 19. Switching view
Repository View examples
ProjectExplorer Repository Folders
Figure 20. Repository View - Folders
ProjectExplorer Repository Links
Figure 21. Repository View - Links
3.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 22. Repository and Project Downloads
3.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 23. Enabling Filter by Tag
ProjectExplorer Tag Filter Show
Figure 24. Filter by Tag
ProjectExplorer Tag Filter Working
Figure 25. Filtering by Tag
3.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 26. 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

3.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 27. Project Screen and the different views
3.7.5.1. Build & Deploy

Build & Deploy builds the current project and deploys the KJAR into the Business Central internal Maven repository.

3.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 28. 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 29. 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.

3.7.5.3. KIE base Settings

KIE base Settings edits the kmodule.xml file used by Drools.

kmodule
Figure 30. 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

3.7.5.4. Imports

Settings edits the project.imports file used by the Business Central editors.

ExternalDataObjects
Figure 31. 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.

3.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 32. Project Editor - Viewing resolved Repositories
MavenRepositories2
Figure 33. Project Editor - The list of resolved Repositories
MavenRepositories3
Figure 34. Duplicate GAV detected

3.7.6. Validation

Business Central provides a common and consistent service for users to understand whether files authored within the environment are valid.

3.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 35. The Problems Panel
3.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

3.7.7. Data Modeller

3.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 36. 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 37. Click a Data Object

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

overview
Figure 38. 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 39. New field creation
  • The Data Object’s "field browser" section displays a list with the data object fields.

    data object field browser
    Figure 40. 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 41. Data Object selector
    data object general properties
    Figure 42. Data Object general properties

    Field general properties can be selected by clicking on a field.

field selector
Figure 43. Field selector
field general properties
Figure 44. 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 45. Data modeller Tool Bar
    data object drools tool window
    Figure 46. Drools & jBPM tool window
    data object optaplanner tool window
    Figure 47. 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 48. Persistence tool window
    data object or field advanced tool window
    Figure 49. 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 50. Source editor

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

3.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 51. 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.

3.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 52. 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 53. 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 54. 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 55. 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.

3.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 56. 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 57. 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 58. 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 59. 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 60. 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 61. 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 62. 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 63. 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 64. 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.

3.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 65. 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 66. 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;
    }

    }
3.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.

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 70. 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 71. Guvnor M2 Repository editor.
Upload the file using the Upload button.
add dependency guvnor m2 3
Figure 73. 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 74. 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 75. Not valid POM.
add dependency guvnor m2 not gav 2
Figure 76. 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 77. 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 78. Identifying external objects.
3.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 79. 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 80. 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 81. 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 82. 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.

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

3.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 83. 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.

3.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 84. 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.

3.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 85. 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 86. CSV Configuration

The provider type selected in the previous step will determine which configuration settings the system asks for.

DataSetDefConfigTypes
Figure 87. 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 88. 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 89. 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 90. 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.

3.7.8.4. Data set editor

To edit an existing data set definition go the data set explorer, expand the desired data set definition and click the Edit button. This will cause a new editor panel to be opened and placed on the center of the screen, as shown in the next screenshot:

DataSetDefEditor
Figure 91. Data set definition editor
DataSetDefEditorSelector
Figure 92. Editor selector
  • Save - To validate the current changes and store the data set definition.

  • Delete - To remove permanently from storage the data set definition. Any client module referencing the data set may be affected.

  • Validate - To check that all the required parameters exists and are correct, as well as to validate the data set can be retrieved with no issues.

  • Copy - To create a brand new definition as a copy of the current one.

Data set definitions are stored in the underlying GIT repository as JSON files. Any action performed is registered in the repository logs so it is possible to audit the change log later on.

3.7.8.5. Advanced settings

In the Advanced settings tab area the user can specify caching and refresh settings. Those are very important for making the most of the system capabilities thus improving the performance and having better application responsive levels.

DataSetDefAdvanced
Figure 93. Advanced settings
  • (1) To enable or disable the client cache and specify the maximum size (bytes).

  • (2) To enable or disable the backend cache and specify the maximum cache size (number of rows).

  • (3) To enable or disable automatic refresh for the Data set and the refresh period.

  • (4) To enable or disable the refresh on stale data setting.

Let’s dig into more details about the meaning of these settings.

3.7.8.6. Caching

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:

  • Client level

  • Backend level

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

DataSetCacheArchitecture
Figure 94. Data set caching

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

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 Drools engine. This is the reason why the backend settings are not visible in the Advanced settings tab.

3.7.8.7. Refresh

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

DataSetDefRefreshSettings
Figure 95. Refresh settings
  • (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.

3.7.9. Data Source Management

The data source management system provides the ability of defining data sources for accessing external databases. This data sources can be later used by other Business Central components like the Data Sets.

3.7.9.1. Database Drivers

To be able to communicate with the target database a data source will need a database driver to access it. This is why the system additionally provides the ability of defining database drivers for the data sources operation. A database driver is basically a JDBC compliant driver. We will see them in the next topics.

3.7.9.2. Data Source Authoring Page

Everything related to the authoring of data sources and drivers can be found under the Data Source Authoring page accessible from the following top level menu entry: Extensions>Data Sources, as shown in the following screenshot.

DataSourceManagementPerspective
Figure 96. Data Source Authoring Page

This page is only intended for Administrator users, since defining data sources can be considered a low level task.

3.7.9.3. Data Source Explorer

The Data Source Explorer lists the data sources and drivers currently defined in the system, at the same time it provides the required actions for managing them.

DataSourceExplorer
Figure 97. Data Source Explorer
  • (1) Action link for creating a new data source

  • (2) List of currently available data sources

  • (3) Action link for creating a new driver

  • (4) List of currently available drivers

3.7.9.4. New Data Source Wizard

Clicking on the New Data Source action link opens the New Data Source Wizard:

NewDataSourceWizard
Figure 98. New Data Source Wizard

The following required parameters define a data source:

  • Name: A unique name for the data source definition.

  • Connection URL: A JDBC database connection url compliant with the selected driver type. This is an example of a connection url for a PostgreSQL database: jdbc:postgresql://localhost:5432/appformer.

  • User: A user name in the target database.

  • Password: The corresponding user password.

  • Driver: Selects the JDBC driver to be used for connecting to the target database. Note that the connection url format may vary depending on the driver, and different database vendors typically provides different drivers.

  • Test connection: Once clicked, the system will show a dialog similar to the one below showing the connection test status.

TestConnectionSuccessful
Figure 99. Test Connection Status

While not required, it’s recommended to use the test connection button to check the correctness of the data source parameters prior to finishing the data source creation.

3.7.9.5. Data Source Editor

The Data Source Editor is opened by clicking on a data source item in the Data Source Explorer.

The following screenshot shows the Data Source Editor opened for the data source of the example above.

DataSourceEditor
Figure 100. Data Source Editor
  • Main Panel: The main panel basically lets you modify the data source configuration parameters.

  • Test connection: Tests the connection.

It’s a recommended practice to test the connection prior saving a modified data source.

3.7.9.6. Data Source Content Browser

The data source content browser is opened by clicking on the Browse Content button, and enables the navigation through the database structure pointed by the data source. The navigation is performed in three levels, Schemas level, Current schema level and Current table level.

  • Schemas level: lists all the database schemas accessible by current data source. Which schemas are listed depends on the database access rights granted to the user which was used in the connection configuration. Similarly for the following item.

  • Current schema level: shows all the database tables for the selected schema.

  • Current table level: shows the table content for the selected table.

The following screenshots show the information shown at each level, for a user that realized the following navigation steps. Selects the "public" schema → Selects the "country" table.

Schema Selection:

Clicking on the Open button opens the Current schema level for the selected schema.

DataSourceContentBrowser1
Figure 101. Database schemas

Table Selection:

Clicking on the Open button opens the Current table level for the selected table.

DataSourceContentBrowser2
Figure 102. Schema tables

Table information:

The rows for the selected table are shown at this level.

DataSourceContentBrowser3
Figure 103. Table rows
3.7.9.7. External Data Sources

External data sources are typically not defined in Business Central, instead they exist in current container and for some containers like Wildfly 11 or the JBoss EAP 7 servers they can still be listed in read-only mode. In such cases, only the Data Source Content Browser is enabled.

ExternalDataSources
Figure 104. External Data Sources navigation
3.7.9.8. New Driver Wizard

Clicking on the New Driver action link opens the New Driver Wizard:

NewDriverWizard
Figure 105. New Driver Wizard

The following required parameters define a Driver:

  • Name: A unique name for the driver definition.

  • Driver Class Name: The java fully qualified name for the class that implements the JDBC driver contract.

  • Group Id: The maven group id for the artifact that contains the JDBC driver implementation.

  • Artifact Id: The maven artifact id for the artifact that contains the JDBC driver implementation.

  • Version: The maven version for the artifact that contains the JDBC driver implementation.

Some commercial database drivers (like Oracle) are not available in the maven central repository. You can use those by first uploading them via Artifact Repository page and then continue with the driver configuration as for the drivers available in the maven central repository.

3.7.9.9. Driver Editor

The Driver Editor is opened by clicking on a driver item in the Data Source Explorer.

The following screenshot shows the Driver Editor opened for the driver of the example above.

DriverEditor
Figure 106. Driver Editor
  • Main Panel: The main panel basically lets you modify the driver configuration parameters. See New Driver Wizard.

3.7.9.10. By Default Drivers

The system is shipped with a set of by default configured drivers for the most commonly used open source databases. And they are aligned with the latest database versions supported by the Wildfly 11 and the JBoss EAP 7 servers.

DefaultDrivers
Figure 107. By Default Drivers

The default drivers initialization can be enabled by setting the datasource.management.disableDefaultDrivers configuration property to false. It can be set by configuring the proper value in the datasource-management.properties file, or by passing the system property -Ddatasource.management.disableDefaultDrivers=false to the JVM. For more information see Advanced Settings.

3.7.9.11. Advanced Settings

The data source management system advanced settings can be found in the datasource-management.properties file in the WEB-INF/classes directory of the given Business Central distribution file.

The data source management system has the ability of working with two different internal implementations for the data sources and drivers. An implementation based on the Wildfly/EAP native data sources and drivers, and a container independent implementation. Wildfly/EAP Business Central distributions are configured by default for using the native Wildfly/EAP containers implementations, and Tomcat8 distributions are configured for using the container independent implementations. This latter implementation can also be used for Wildfly/EAP containers.

The valid combinations are:

WildflyDataSourceProvider + WildflyDriverProvider
or
DBCPDataSourceProvider + DBCPDriverProvider

The datasource.management.wildfly.xxxxx properties are only suited for the WildflyXXXProviders.

3.7.9.12. Advanced Settings for Business Central Wildfly/EAP distributions
Property name By default value Description

datasource.management.DataSourceProvider

WildflyDataSourceProvider

see Advanced Settings.

datasource.management.DriverProvider

WildflyDriverProvider

see Advanced Settings.

datasource.management.disableDefaultDrivers

true

Set to false to enable the default database drivers initialization.

datasource.management.wildfly.host

localhost

Name or ip address used for the Wildfly server management interface binding.

datasource.management.wildfly.port

9990

Port used for the Wildfly server management interface binding.

datasource.management.wildfly.admin

Administration user for connecting to the Wildfly server running current Business Central. In general, it’s not necessary to set this value but might be needed in cases when the Wildfly management interface is bound to an address different than localhost.

datasource.management.wildfly.password

Administration user password for connecting to the Wildfly server running current Business Central. In general, it’s not necessary to set this value but might be needed in cases when the Wildfly management interface is bound to an address different than localhost.

datasource.management.wildfly.realm

ManagementRealm

Realm for the administration user authentication.

datasource.management.wildfly.profile

The profile name used for starting the Wildfly domain, e.g. default, full, full-ha, etc. This value must only by set when Business Central is running in clustering mode and the hosting Wildfly servers are configured by using domains. Do not set if the Wildfly servers are running as standalone servers.

datasource.management.wildfly.serverGroup

The server group to which current Wildfly server instance belongs, e.g. primary-server-group, etc. This value must only by set when Business Central is running in clustering mode and the hosting Wildfly servers are configured by using domains. Do not set if the Wildfly servers are running as standalone servers.

datasource.management.DefChangeHandler

This value must only by set when Business Central is running in clustering mode. If the hosting Wildfly servers are configured by using domains the following value must be used DomainModeChangeHandler and the following value StandaloneModeChangeHandler must be used in cases when the hosting Wildfly servers are running as standalone servers. Clustering installations that uses the DBCPXXXProviders must be configured for using the StandaloneModeChangeHandler.

The properties above can also be set by passing system properties to the JVM using the Java standard mechanism. e.g. -Ddatasource.management.wildfly.port=1234. Values configured by using this mechanism will override the values configured in the datasource-management.properties file.

3.7.9.13. Advanced Settings for Tomcat distributions
Property name By default value Description

datasource.management.DataSourceProvider

DBCPDataSourceProvider

This is the only option available for Tomcat 8 distributions, see Advanced Settings.

datasource.management.DriverProvider

DBCPDriverProvider

This is the only option available for Tomcat 8 distributions, see Advanced Settings.

datasource.management.disableDefaultDrivers

true

Set to false to enable the default database drivers initialization.

datasource.management.DefChangeHandler

This value must only by set when Business Central is running in clustering mode. Tomcat distributions only support the StandaloneModeChangeHandler value.

The properties above can also be set by passing system properties to the JVM using the Java standard mechanism. e.g. -Ddatasource.management.wildfly.port=1234. Values configured by using this mechanism will override the values configured in the datasource-management.properties file.

3.8. Security management

This section describes how administrator users can manage the application’s users, groups and permissions using an intuitive and friendly user interface in order to configure who can access the different resources and features available.

3.8.1. Basic concepts

3.8.1.1. Introduction to Business Central users, groups and roles

The Business Central security domain defines three kinds of entities: user, group and role.

The security entities are being registered in the domain by consuming some realm. The realm can be either the application server’s one (Wildfly, EAP, Tomcat) or any other of the supported types, for example, using some Keycloak remote server that performs handles the target realm.

On the other hand, it’s important to notice that each realm provides, or potentially provides, its own capabilities, semantics or structure on the security domain. These kind of differences on the security domain results on inconsistencies between different environments when moving into the Business Central security domain. This way there exist some conventions which are important to understand - how security entities are being declared and how the platform behaves behind that complexity,

The way Business Central integrates the security entities from an external realm corresponds to:

  • User

A user, rather than attributes and any other kind of metadata, which can be different across domains, represents the same kind of entity in any of the supported security environments (Wildfly, EAP, Tomcat, Keycloak, etc), so the entity results in a user on Business Central as well

  • Role / Group

Both role and group are security entities, but rather than a user, the semantics, the behaviors or the structure in the domain is not usually common across environments. As an example, consider domains which do not support both of them, or domains where the semantics for group or role differs. As a result, the way the application behaves and figures out if an entity should be considered a group or a role is by checking the application’s Role Registry. This way an entity will be considered a role in case its identifier is present in the application’s Role Registry, otherwise, the entity will be considered as a group.

The Role Registry is an application’s component that provides the set of roles in the Business Central security domain. It’s being populated by consuming the entities (role-name) declared in the security-constraints section on the application’s deployment descriptor (web.xml). See source file org.uberfire.ext.security.server.RolesRegistry.

It means that depending on the concrete environment’s configuration, some entity can be as a role, on the security environment consumed by Business Central, but it results in a group in the Business Central security domain, or vice versa. It depends on the entity’s identifier by checking it it is present in the Role Registry.

A User can be assigned to multiple roles and groups, but it is mandatory to have at least, a single role assignment for being considered valid in the Business Central security domain. It does not mean, for instance, that the user is able to login, or able to consume remote services, because it depends on the concrete role/s assigned and how the roles and permissions are defined the application.

3.8.1.2. Permissions

A permission is basically something the user can do within the application. Usually, an action related to a specific resource. For instance:

  • View a page

  • Save a project

  • View a repository

  • Delete a dashboard

A permission can be granted or denied and it can be global or resource specific. For instance:

  • Global: “Create new pages”

  • Specific: “View the home page”

As you can see, a permission is a resource + action pair. In the concrete case of a page we have: read, update, delete and create as the available actions. That means that there are four possible permissions that could be granted for pages.

Permissions do not necessarily need to be tied to a resource. Sometimes it is also necessary to protect access to specific features, like for instance "generate a sales report". That means, permissions can be used not only to protect access to resources but also to custom features within the application.

3.8.1.3. Authorization policy

The set of permissions assigned to every role and/or group is called the authorization (or security) policy. Every application contains a single security policy which is used every time the system checks a permission.

The authorization policy file is stored in a file called WEB-INF/classes/security-policy.properties under the application’s WAR structure.

If no policy is defined then the authorization management features are disabled and the application behaves as if all the resources & features were granted by default.

Here is an example of a security policy file:

# Role "admin"
role.admin.permission.perspective.read=true
role.admin.permission.perspective.read.Dashboard=false

# Role "user"
role.user.permission.perspective.read=false
role.user.permission.perspective.read.Home=true
role.user.permission.perspective.read.Dashboard=true

Every entry defines a single permission which is assigned to a role/group. On application startup, the policy file is loaded and stored into memory.

3.8.1.4. Security provider

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

In most typical scenarios the application’s security is delegated to the container’s security mechanism, which consumes a given realm at the 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 there is no single security realm to rely on, it can be different in each installation.

Due to the potential different security environments that have to be supported, the security module provides a well defined API with some default built-in security providers. A security provider is the formal name given to a concrete user and group management service implementation for a given realm.

The user & group management features available will depend on the security provider configured. If the built-in providers do not fit with the application’s security realm, it is easy to build and register your own provider.

3.8.2. Installation and setup

At the time of this writing, the application provides two pre-installed security providers:

  • Wildfly 11 / EAP 7 distribution - Both distributions use the Wildfly security provider configured for the use of the default realm files application-users.properties and application-roles.properties

  • Tomcat distribution - It uses the Tomcat security provider configured for the use of the default realm file tomcat-users.xml

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

On the other hand, when either using a custom security provider or using one of the available security providers, 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 provider is installed, there will be no available user interface for managing the security realm. Once a security provider is installed and setup, the user and group management features are automatically enabled in the security management UI (see the Usage section below).

3.8.2.1. Enabling user & group management

Given an existing WAR distribution, follow these steps in order to install and enable the user & group management features:

  • Ensure the following libraries are present on WEB-INF/lib:

    • WEB-INF/lib/uberfire-security-management-api-?.jar

    • WEB-INF/lib/uberfire-security-management-backend-?.jar

  • Copy the security provider library to WEB-INF/lib:

    • Eg: WEB-INF/lib/uberfire-security-management-wildfly-?.jar

    • If the provider requires additional libraries, copy them as well (read each provider’s documentation for more information).

  • Replace the whole content of the WEB-INF/classes/security-management.properties file, or if not present, create it. The settings present on this file depend on the concrete implementation used. Please read each provider’s documentation for more information.

  • If deploying on Wildfly or EAP, check if the WEB-INF/jboss-deployment-structure.xml requires any update (read each provider’s documentation for more information).

3.8.2.2. Disabling user & group management

The user & groups management features can be disabled, and thus no services or user interface will be available, by means of either:

  • Uninstalling the security provider from the application

    When no concrete security provider is installed, the user and group management features will be disabled and no services or user interface will be displayed to the user. This is the case for instance, in Weblogic and Websphere installations as there is no security provider implementation available at the time of this writing.

  • Removing or commenting the security management configuration file

    Removing or commenting all the lines in the configuration file located at WEB-INF/classes/security-management.properties is another way to disable the user and group management features.

3.8.2.3. Upgrading an existing installation

In versions prior to 7, the only way to grant access to resources like Organizational Units, Repositories or Projects was to indicate which roles were able to access a given instance. Those roles were stored in GIT as part of the instance persistent status. The CLI was the tool used to add/remove roles:

  • remove-role-repo: remove role(s) from repository

  • add-role-org-unit: add role(s) to organizational unit

  • remove-role-org-unit: remove role(s) from organizational unit

  • add-role-project: add role(s) to project

  • remove-role-project: remove role(s) from project

As of version 7, the authorization policy is based on permissions. That means is no longer required to keep a list of roles per resource instance. What is required is to define proper permission entries into the active authorization policy using the security management UI (see the Usage section below).

The commands above are no longer required so they have been removed. Basically, what those commands did is to set what roles were able to read a specific item.

In order to guarantee backward compatibility with versions prior to 7, an automatic migration tool is bundled within the application, which converts the list of roles assigned to any organizational unit, repository or project into read permission entries of the security policy.

This tool is executed when the application starts for the first time, during the security policy deployment. So existing customers, do not have to worry about it, as they will keep their security settings.

3.8.3. Usage

The Security Management page is available under the Home section in the top menu bar.

SecurityManagementMenuEntry
Figure 108. Link to the Security Management page

The next screenshot shows how this new page looks:

SecurityManagementHome
Figure 109. Security Management Home

This page supports:

  • List all the roles, groups and users available

  • Create & delete users and groups

  • Edit users, assign roles or groups, and change user properties

  • Edit both roles & groups security settings, which include:

    • The home page a user will be directed to after login

    • The permissions granted or denied to the different Business Central resources and features available

All of the above together provides a complete users and groups management subsystem as well as a permission configuration UI for protecting access to specific resources or features.

The next sections provide a deep insight into all these features.

The user and group management related features can be entirely disabled. See the previous section Disabling user & group management. If that’s the case then both the Groups and _Users tabs will remain hidden from the user.
3.8.3.1. User management

By selecting the Users tab in the left sidebar, the application shows all the users present by default on the application’s security realm:

SecurityManagementUsersExplorer
  • Searching for users

In addition to listing all the users, search is also allowed:

+ When specifying the search pattern in the search box the users listed will be reduced to only those that matches the search pattern.

+

SecurityManagementUsersSearch

+ Search patterns depend on the concrete security provider being used by the application. Please read each provider’s documentation for more information.

  • Creating new users

    By clicking on the "New user +" anchor, a form is displayed on the screen’s right.

    SecurityManagementNewUserForm

This is a wizard like interface where the application asks for the new user name, a password as well as what roles/groups to assign.

  • Editing a user

After clicking on a user in the left sidebar, the user editor is opened on the screen’s right.

For instance, the details screen for the admin user when using the Wildfly security provider looks like the following screenshot:

SecurityManagementViewUser

Same screen but when using the Keycloak security provider looks as:

SecurityManagementViewUserKC

Note that when using the Keycloak provider, a new user attributes section is displayed, but it’s not present when using the Wildfly provider. This is due to the fact that the information and actions available always depend on each provider’s capabilities as explained in the Security provider capabilities section below.

Next is the type of information handled in the user’s details screen:

  • The user name

  • The user’s attributes

  • The assigned groups

  • The assigned roles

  • The permissions granted or denied

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

SecurityManagementEditUser

Once the editor is in edit mode, different operations can be done (provided the security provider supports them):

For instance, to modify the set of roles and groups assigned to the user or to change the user’s password as well.

  • Permissions summary

The Permissions tab shows a summary of all the permissions assigned to this particular user. This is a very helpful view as it allows administrator users to verify if a target user has the right permission levels according to the security settings of its roles and groups.

SecurityManagementUserPermissions

Further details about how to assign permissions to roles and groups are in the Security Settings Editor section below.

  • Updating the user’s attributes

    User attributes can be added or deleted using the actions available in the attributes table:

    SecurityManagementUserAttributes
  • Updating assigned groups

    From the Groups tab, a group selection popup is presented when clicking on the Add to groups button:

    SecurityManagementGroupsSelection

    This popup screen allows the user to search and select or deselect the groups assigned to the user.

  • Updating assigned roles

    From the Roles tab, a role selection popup is presented when clicking on Add to roles button:

    SecurityManagementRolesSelection

    This popup screen allows the user to search and select or deselect the roles assigned to the user.

  • Changing the user’s password

    A change password popup screen is presented when clicking on the Change password button:

    SecurityManagementChangePassword
  • Deleting users

    The user currently being edited can be deleted from the realm by clicking on the Delete button.

SecurityManagementDeleteUser
Security provider capabilities

Each security realm can provide support for 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

Notice 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 represented by a key and its user name, it does not have a name nor an address or any other meta information.

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

SecurityManagementViewUserKC

So the different services and client side components from the User 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 provider must specify a set of capabilities supported. From the previous examples, it is noted that the Wildfly security provider does not support the attributes management capability - 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 not be 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.

3.8.3.2. Group management

By selecting the Groups tab in the left sidebar, the application shows all the groups present by default on the application’s security realm:

SecurityManagementGroupsExplorer
  • Searching for groups

In addition to listing all the groups, search is also allowed:

+ When specifying the search pattern in the search box the groups listed will be reduced to only those that matches the search pattern.

+

SecurityManagementGroupsSearch

+ Search patterns depend on the concrete security provider being used by the application. Please read each provider’s documentation for more information.

  • Creating new groups

    By clicking on the "New group +" anchor, a new screen will be presented on the center panel to perform a new group creation.

SecurityManagementNewGroup

After typing a name anc clicking Save, the next step is to assign users to it:

+

SecurityManagementNewGroupUserSelection

+ Clicking on the "Add selected users" button finishes the group creation.

  • Modifying a group

After clicking on a group in the left sidebar, the security settings editor for the selected group instance is opened on the screen’s right. Further details at the Security Settings Editor section.

  • Deleting groups

To delete an existing group just click the Delete button.

3.8.3.3. Role management

By selecting the Roles tab in the left sidebar, the application shows all the application roles:

SecurityManagementRolesExplorer

Unlike users and groups, roles can neither be created nor deleted as they come from the application’s web.xml descriptor. After clicking on a role in the left sidebar, the role editor is opened on the screen’s right, which is exactly the same security settings editor used for groups. Further details at the Security Settings Editor section.

SecurityManagementEditRole

That means both role and group based permissions can be defined. The main difference between roles and groups are:

  • Roles are an application defined resource. They are defined as <security-role> entries in the application’s web.xml descriptor.

  • Groups are dynamic and can be defined at runtime. The installed security provider determines where groups instances are stored.

They can be used together without any trouble. Groups are recommended though as they are a more flexible than roles.

  • Searching for roles

In addition to listing all the roles, search is also allowed:

+ When specifying the search pattern in the search box the roles listed will be reduced to only those that matches the search pattern.

+

SecurityManagementRolesSearch

+ Search patterns depend on the concrete security provider being used by the application. Please read each provider’s documentation for more information.

3.8.4. Security Settings Editor

This editor is used to set several security settings for both roles and groups.

SecurityManagementSecuritySettsEditor

+

3.8.4.1. Home page

This is the page where the user is directed after login. This makes it possible to have different home pages for different users, since users can be assigned to different roles or groups.

3.8.4.2. Priority

It is used to determine what settings (home page, permissions, …​) have precedence for those users with more than one role or group assigned.

Without this setting, it won’t be possible to determine what role/group should take precedence. For instance, an administrative role has higher priority than a non-administrative one. For users with both administrative and non-administrative roles granted, administrative privileges will always win, provided the administrative role’s priority is greater than the other.

3.8.4.3. Permissions

Currently, Business Central support the following permission categories.

  • Business Central: General Business Central permissions, not tied to any specific resource type.

  • Pages: If access to a page is denied then it will not be shown in any of application menus. Update, Delete and Create permissions change the behaviour of the page management plugin editor.

  • Organizational Units: Sets who can Create, Update or Delete organizational units from the Organizational Unit section at the Administration page. Sets also what organizational units are visible in the Project Explorer at the Project Authoring page.

  • Repositories: Sets who can Create, Update or Delete repositories from the Repositories section at the Administration page. Sets also what repositories are visible in the Project Explorer at the Project Authoring page.

  • Projects: In the Project Authoring page, sets who can Create, Update, Delete or Build projects from the Project Editor screen as well as what projects are visible in the Project Explorer.

For pages, organizational units, repositories and projects it is possible to define global permissions and add single instance exceptions afterwards. For instance, Read access can be granted to all the pages and deny access just to an individual page. This is called the grant all deny a few strategy.

SecurityManagementPerspectiveDenied

The opposite, deny all grant a few strategy is also supported:

SecurityManagementPerspectiveGranted
In the example above, the Update and Delete permissions are disabled as it does not make sense to define such permissions if the user is not even able to read pages.

3.8.5. Security Policy Storage

The security policy is stored under the Business Central VFS. Most concrete, in a GIT repo called “security”. The ACL table is stored in a file called “security-policy.properties” under the “authz” directory. Next is an example of the entries this file contains:

role.admin.home=HomePage
role.admin.priority=0
role.admin.permission.perspective.read=true
role.admin.permission.perspective.create=true
role.admin.permission.perspective.delete=true
role.admin.permission.perspective.update=true

Every time the ACL is modified from the security settings UI, the changes are stored in the GIT repo.

Initially, when the application is deployed for the first time there is no security policy stored in GIT. However, the application might need to set-up a default policy with the different access profiles for each of the application roles.

In order to support default policies the system allows for declaring a security policy as part of the webapp’s content. This can be done just by placing a security-policy.properties file under the webapp’s resource classpath (the WEB-INF/classes directory inside the WAR archive is a valid one). On app start-up the following steps are executed:

  • Check if an active policy is already stored in GIT

  • If not, then check if a policy has been defined under the webapp’s classpath

  • If found, such a policy is stored under GIT

The above is an auto-deploy mechanism which is used in Business Central to set-up its default security policy.

One slight variation of the deployment process is the ability to split the “security-policy.properties” file into small pieces so that it is possible, for example, to define one file per role. The split files must start by the “security-module-” prefix, for instance: “security-module-admin.properties”. The deployment mechanism will read and deploy both the "security-policy.properties" and all the optional “security-module-?.properties” found on the classpath.

Notice, despite using the split approach, the “security-policy.properties” must always be present as it is used as a marker file by the security subsystem in order to locate the other policy files. This split mechanism allows for a better organization of the whole security policy.

3.9. SSH keystore

This section provides an overview of the Business Central SSH keystore and includes a guide for platform users. It explains how to use the Business Central SSH keystore to register and use it’s SSH public keys.

3.9.1. Introduction

Business Central includes an SSH keystore service to provide proper SSH authentication for users.

It provides a configurable default SSH keystore, extensible APIs to allow custom implementations, support for multiple SSH public keys formats, and a new UI available on the Admin page to enable users to register their SSH public keys.

3.9.1.1. The default SSH keystore

The default SSH keystore included with Business Central provides a file-based storage mechanism to store users' SSH public keys.

By default, it uses Business Central .security folder as a root path. It is possible to use a custom storage path by setting the appformer.ssh.keys.storage.folder property to direct to a different folder.

The SSH public keys are stored in the {securityFolderPath}/pkeys/{userName}/ folder structure.

Each SSH public key consists of a pair of files in the storage folder:

  • {keyId}.pub: a file containing the SSH public key content. The file name determines the logic key ID on the system, so do not modify the file name during runtime. For example

    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDmak4Wu23RZ6XmN94bOsqecZxuTa4RRhhQmHmTZjMB7HM57/90u/B/gB/GhsPEu1nAXL0npY56tT/MPQ8vRm2C2W9A7CzN5+z5yyL3W01YZy3kzslk77CjULjfhrcfQSL3b2sPG5jv5E5/nyC/swSytucwT/PE7aXTS9H6cHIKUdYPzIt94SHoBxWRIK7PJi9d+eLB+hmDzvbVa1ezu5a8yu2kcHi6NxxfI5iRj2rsceDTp0imC1jMoC6ZDfBvZSxL9FXTMwFdNnmTlJveBtv9nAbnAvIWlilS0VOkdj1s3GxBxeZYAcKbcsK9sJzusptk5dxGsG2Z8vInaglN6OaOQ7b7tcomzCYYwviGQ9gRX8sGsVrw39gsDIGYP2tA4bRr7ecHnlNg1b0HCchA5+QCDk4Hbz1UrnHmPA2Lg9c3WGm2qedvQdVJXuS3mlwYOqL40aXPs6890PvFJUlpiVSznF50djPnwsMxJZEf1HdTXgZD1Bh54ogZf7czyUNfkNkE69yJDbTHjpQd0cKUQnu9tVxqmBzhX31yF4VcsMeADcf2Z8wlA3n4LZnC/GwonYlq5+G93zJpFOkPhme8c2XuPuCXF795lsxyJ8SB/AlwPJAhEtm0y0s0l1l4eWqxsDxkBOgN+ivU0czrVMssHJEJb4o0FLf7iHhOW56/iMdD9w== userName
  • .{keyId}.pub.meta: a file containing the key metadata in JSON format. If a key has no metadata, a new metadata file is dynamically generated. For example:

    {
        "name":"Key",
        "creationDate":"Oct 10, 2018 10:10:50 PM",
        "lastTimeUsed":"Oct 11, 2018 12:11:23 PM"
    }
3.9.1.2. Using a custom SSH keystore

It is possible to extend and customize the platform default SSH keystore to meet more specific requirements.

Use the system property appformer.ssh.keystore to specify the Java class name of the service to use. If the property does not exist or it contains a wrong value, the default SSH keystore is loaded.

To create a custom implementation of the SSH keystore, your Java Class must implement the class org.uberfire.ssh.service.backend.keystore.SSHKeyStore defined in the uberfire-ssh-api module.

3.9.2. Using the SSH keystore

This section describes how to use the SSH keystore to register your own keys and how to use them.

3.9.2.1. The SSH keystore UI

The SSH keystore provides an intuitive UI to enable users to manage their SSH public keys on the system. It is accessible from the Admin page by using the SSH Keys menu option.

ssh keystore menu
Figure 110. SSH Keys Menu Option on Admin Page

After you click the SSH Keys menu option the SSH Keys Editor will open. the editor displays a table showing the user SSH public keys and provides access to the main action buttons.

  • Add SSH Key: Used to add an SSH public key for the user.

    ssh keystore editor new
    Figure 111. Adding new SSH public key
  • Delete SSH Key: Used to remove an existing SSH public key

    ssh keystore editor delete
    Figure 112. Deleting a SSH public key
ssh keystore editor
Figure 113. SSH keystore UI
3.9.2.2. Adding SSH keys

This section explains step by step how to add an SSH public key to the SSH keystore.

Creating the SSH key on your computer
  1. Open a terminal on your computer

  2. Run the ssh-keygen command to create the key:

    ssh-keygen -t rsa -b 4096 -C "<your_user_login_here>"

    The SSH key formats supported by the keystore are 'ssh-rsa', 'ssh-dss', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384' and 'ecdsa-sha2-nistp521'.

  3. When prompted, press Enter and accept the default key file location.

    Enter a file in which to save the key (/home/<your_login_here>/.ssh/id_rsa): [Press enter]
  4. When prompted, enter the pass phrase that you want to use.

    Enter passphrase (empty for no passphrase): [Type a passphrase]
    Enter same passphrase again: [Type passphrase again]
  5. Start the ssh-agent:

    eval "$(ssh-agent -s)"
    Agent pid <any-number-here>
  6. Add the new SSH private key to the ssh-agent. If you used a different key name, replace id_rsa with your key name

    ssh-add ~/.ssh/id_rsa
Registering your SSH public key with the SSH keystore
  1. In Business Central, go to the gear icon next to your login to open the Admin page.

    ssh keystore editor gear
    Figure 114. Accessing the Admin Page
  2. Open the SSH keystore UI by clicking the SSH Keys menu option.

    ssh keystore menu
    Figure 115. SSH Keys Menu Option on Admin Page
    ssh keystore editor empty
    Figure 116. SSH Keystore UI Without keys
  3. Copy the contents of your SSH Public key onto the clipboard. Use the cat command to display your key content. If you used a different key name: replace id_rsa with your key name, and copy it.

    cat ~/.ssh/id_rsa.pub
  4. In the SSH keystore UI press the Add SSH Key button to open the New SSH public key form. Specify a name, copy the key content into the key field and click Add SSH Key to register the key.

    ssh keystore editor new
    Figure 117. Adding new SSH public key
    • Name field cannot be empty, this field defines a meaningful name for the user to identify the key on the SSH public keys table.

    • Key must be a valid SSH Public key, so it cannot be empty and the key format must be supported by the platform.

3.10. Embedding Business Central in Your Application

Apart from the individual perspectives (such as the Library or Content Management), Business Central provides a number of editors used for designing and managing assets in different formats. Within Business Central, each asset type has a corresponding editor.

Business Central provides the possibility to embed the perspectives and editors in the user’s application using the standalone mode. Without actually switching to Business Central, it is possible to display perspectives and edit various assets, such as rules, processes, or decision tables, in separate applications.

To embed a part of Business Central in an application, Business Central must be deployed and running on a web server or an application server. Then, in your application, include an HTML inline frame with the proper HTTP query parameters as described in the following table.

Table 1. HTTP query parameters for the standalone mode
Parameter Values Description

standalone

none

This parameter must be included in each URL of a perspective or an editor that will be used in the standalone mode.

perspective

LibraryPerspective, ContentManagerPerspective, or any custom-created page

Used for specifying the perspective to be displayed.

header

UberfireBreadcrumbsContainer

Displays the breadcrumbs at the top of the page that can be used for navigating to the lists of spaces and projects within the Library. This parameter can be used only if perspective=LibraryPerspective is specified.

path

default://master@MySpace/Shop/src/main/java/com/Product.java

Specifies the path to the asset to be opened in a corresponding editor. The path must be specified in the format default://BRANCH@SPACE/PROJECT/PATH_TO_ASSET/ASSET_NAME.FILE_EXTENSION.

Table 2. Usage examples
URL Description

http://localhost:8080/business-central/kie-wb.jsp?standalone&perspective=LibraryPerspective

Opens the Library where it is possible to select a project to be managed.

http://localhost:8080/business-central/kie-wb.jsp?standalone&perspective=LibraryPerspective&header=UberfireBreadcrumbsContainer

Opens the Library with the list of projects. The header parameter displays the breadcrumbs at the top of the page, which allow the user to switch between the spaces as well as the projects.

http://localhost:8080/business-central/kie-wb.jsp?standalone&path=default://master@MySpace/Shop/src/main/java/com/Product.java

Opens the editor of the specified asset.

http://localhost:8080/business-central/kie-wb.jsp?standalone&perspective=ContentManagerPerspective

Opens the Content Management perspective, where it is possible to create and manage custom pages.

http://localhost:8080/business-central/kie-wb.jsp?standalone&perspective=MyCustomPage

Opens the specified custom page that has been created before using the Content Management perspective. The value of the perspective parameter must correspond to the actual name of the page.

3.11. Execution Server Management UI

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.

NewExecServerUI
Figure 118. Execution Server Management

The management UI is only available for KIE Managed Servers.

3.11.1. Server Templates

Server templates are used to define a common configuration that can be used for multiple servers, thus the name: Template.

Server Templates can be created directly from the management UI. A server template is automatically created when a server connects to the KIE Server controller and there isn’t a template definition for that remote server. Server templates may have one or more capabilities, such capabilities can’t be modified, if you need to modify the capabilities you’ll have to create a new template. Here is the list of current capabilities:

  • Rule (Drools)

  • Process (jBPM)

  • Planning (Optaplanner)

For Planner capability it’s mandatory to enable Rule’s capability too.

In order to create a new Server Template you have to click at New Server Template button and follow the wizard. It’s also possible to create a container during Wizard, but for now let’s limit to just the template.

NewServerTemplateWizard
Figure 119. New Server Template Wizard

Once created you’ll get the new Template listed on the left hand side, with the new Server Template highlighted. On the right hand side you get the 2nd level navigation that lists Containers and Remote Servers that are related to selected Server Template.

ServerTemplates
Figure 120. Server Templates

On top of the navigation is also possible to delete the current Server Template or create a copy of it.

ServerTemplateActions
Figure 121. Server Template Actions

3.11.2. Container

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 a specific KJAR that they are looking for.

NewContainerWizard
Figure 122. New Container Wizard

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

ProcessConfigNewContainerWizard
Figure 123. Process Configuration

Kie Base Name determines which Kie Base of the deployed artifact will be used.

Kie Session Name determines which Kie Session of the selected Kie Base will be used.

Please notice that configurations on this tab take effect only if the deployed project contains some business processes. It is not enough if the server template has the extension for processes enabled.

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.

NewContainer
Figure 124. Container

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.

Only started Containers are deployed to remote servers.

ContainerStatus
Figure 125. Status Container

For containers that do not have process capability the Version Configuration tab allows users to change the current version of the Container. Users can upgrade manually to a specific version using the "Upgrade" button or enable/disable the Scanner. It’s also possible to execute a Scan Now operation that will scan for new versions only once.

To redeploy SNAPSHOT kjars with your latest changes all existing containers with that version must first be removed. Executing 'build and deploy' will then create a container with the latest SNAPSHOT kjar. However, this is not possible for release versions. Following maven release conventions if the GAV of a kjar is anything but SNAPSHOT, the GAV will need to be updated to the newer release version and deployed to its own container. The new release version can also be used to upgrade an existing container as described previously provided the container does not have process capability.

ContainerVersionConfiguration
Figure 126. Version Configuration

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.

ContainerProcessConfiguration
Figure 127. Process Configuration

3.11.3. Remote Server

Remote Server is a Managed KIE Server instance running that has a KIE Server controller configured.

By default, Business Central comes with a KIE Server controller embedded.

The list of Remote Servers is displayed just under the list of Containers. Once selected the screens reveals the Remote Server details and a list of cards, each card represents a running Container.

RemoteServers
Figure 128. Remote Servers

3.12. Experimental Features Framework

This section describes the Experimental Features Framework functionality and how to use it.

3.12.1. Introduction

The Experimental Features Framework is a platform service that allows developers to deliver features which are still not part of Business Central (for example, ongoing developments, tech previews, POCs…​) and expose these features to users to let them have a preview of what is coming in the future.

The Experimental Features Framework provides the following features:

  • New Editor UI, accessible on the Admin page, where users can enable and disable Experimental Features.

  • Support for user-level features (stored as system preferences for each user) and global features (only available to admin users, in the editor)

  • Ability to dynamically handle the visibility for different Experimental Resources on Business Central.

    • Business Central Perspectives

    • Business Central Screens

    • Business Central Editors

    • Library Asset Types

    • Page Builder Layout Components

3.12.2. Types of Experimental Features

There are two types of Experimental Features, each with different scopes:

  • User: This type of feature can be enabled or disabled for any platform user, making the feature available for a single user without affecting other users, storing the feature state as a user preference.

  • Global: This type of feature is global for all users. Only users with administrator permissions user can enable them.

3.12.3. Experimental Features Editor

The Experimental Features Framework provides an editor where users can configure the features that they want to use. To open the editor, navigate to the Admin page and click the Experimental menu option.

admin page experimental menu option
Figure 129. Experimental Features Menu Option

The Experimental menu option only appears if the Experimental Features Framework is enabled and there are Experimental Features installed on Business Central

admin page experimental editor screen
Figure 130. Experimental Features Editor

The features and groups displayed on this documentation are examples.

The Experimental Features Editor displays all the Experimental Features installed on Business Central. For a better user experience these features are organized in collapsible groups. Click a label to expand or collapse a group.

admin page experimental editor feature group
Figure 131. Experimental Features Group

Each row inside of the group corresponds to an experimental feature. Click toggle button to enable or disable the feature.

You can also enable or disable all group features by clicking the group’s *Enable all" / "Disable all" button.

admin page experimental editor feature group enable all
Figure 132. Enable all group features

3.12.4. Enabling the Experimental Features Framework

By default, the Experimental Features Framework is disabled. You can enable it by starting Business Central and setting the system property appformer.experimental.features=true.

Any Experimental Feature present on Business Central will not be accessible to users while the Experimental Features Framework is disabled.

3.13. Business Central profiles

Starting on 7.15.0.Final, KIE Workbench is renamed to Business Central. Business Central contains all KIE Workbench features. To select between the set of available features, the concept of profiles is introduced. This chapter describes profiles and show how you can configure them in Business Central.

3.13.1. Introduction

When you start the Business Central application, all the features are available to you by default. To configure a set of features, you can select from a list of profile.

A profile is a set of features which contains:

  • Menus

  • Resources that it can handle

  • Specific home page

Currently, we have two profiles: * Full: All workbench features will be enabled (default); * Planner and Rules: Only Optaplanner and Drools features will be available.

3.13.2. Selecting a profile

Profiles can be selected on Administration page, by selecting the Profiles preference.

Only admin users have access to the Profiles preference.

profiles menu option
Figure 133. Profile Menu Option

It is also possible to select a profile using the system property org.kie.workbench.profile, which can have the values FULL (for Full profile) and PLANNER_AND_RULES (For Planner and Rules profile).

3.14. Performance tuning considerations with Business Central

The following key concepts or suggested practices can help you optimize Business Central configuration and OptaPlanner performance. These concepts are summarized in this section as a convenience and are explained in more detail in the cross-referenced documentation, where applicable. This section will expand or change as needed with new releases of OptaPlanner.

Ensure that development mode is enabled during development

You can set KIE Server or specific projects in Business Central to use production mode or development mode. By default, KIE Server and all new projects in Business Central are in development mode. This mode provides features that facilitate your development experience, such as flexible project deployment policies, and features that optimize KIE Server performance during development, such as disabled duplicate GAV detection. Use development mode until your OptaPlanner environment is established and completely ready for production mode.

For more information about configuring the environment mode or duplicate GAV detection, see the following resources:

Disable verification and validation of complex guided decision tables

The decision table verification and validation feature of Business Central is enabled by default. This feature helps you validate your guided decision tables, but with complex guided decision tables, this feature can hinder Drools engine performance. You can disable this feature by setting the org.kie.verification.disable-dtable-realtime-verification system property value to true.

For more information about guided decision table validation, see [guided-decision-tables-validation-disable-proc]

Disable automatic builds if you have many large projects

In Business Central, when you navigate between projects in the Project Explorer side panel, the selected project is built automatically so that the Alerts window is updated to show any build errors for the project. If you have large projects or frequently switch between many projects that are under active development, this feature can hinder Business Central and Drools engine performance.

To disable automatic project builds, set the org.kie.build.disable-project-explorer system property to true.

4. Authoring Planning Assets

4.1. Solver Editor

The solver editor creates a solver configuration that can be run in the Execution Solver or plain Java code after the kjar is deployed.

To see and use this editor, the user needs to have the Resource Planner permission.

Use the Validate button to validate the solver configuration. This will actually build a Solver, so most issues in your project will present itself then, without the need to deploy and run it.

By default, the solver configuration automatically scans for all planning entities and planning solution classes. If none are found (or too many), validation fails.

4.1.1. Score Director Factory

Use the Score Director Factory configuration section to define a KIE base, which contains scoring rule definitions. Select one of the KIE sessions defined within the KIE base. The sessions can be managed in the Project Editor.

Planner uses a default KIE session if none is specified.

score director factory

4.1.2. Termination Editor

By default, a time period that the Planner engine is given to solve a problem instance is not limited. While this might be enforced by some scenarios (e.g. real-time planning), it is useful to have a mechanism to control the total duration of the solving process.

Refer to OptaPlanner documentation for more information on supported termination types.

Solver can be terminated manually using REST API of the KIE Server.

termination editor

Use Add to create new termination element within selected logical group and pick termination type. Input field will be displayed based on the selection.

Termination elements are organized into a tree structure. The editor supports definition of logical groups (represented by termination type Nested termination), which join multiple termination elements using logical operators (And/Or). The scope of the operator is limited by the logical group in which it is defined.

Click Remove to remove the termination element from the termination tree. If the removal action is performed on the root element of a logical group, all its children will be removed as well.

4.1.3. Phase Configuration

Planner splits the solving process into multiple phases. Every phase represents a single optimization algorithm run, which consumes a result returned by the previous phase. For example, a Construction Heuristic phase is usually placed before a Local Search phase to provide a good initial solution that the Local Search further optimizes.

By default, the Solver uses a single Construction Heuristic phase followed by a Local Search phase.

phase configuration

Click Add to add a new phase. Individual phase elements provide additional configuration options. Click Remove to remove a specific phase from the Solver configuration.

4.2. Domain Editor

Planner leverages Data modeller to create domain model for constraint satisfaction problems.

In addition to the basic functionality the Data modeller provides (creating data objects and their properties), Business Central allows enhancing the data model with Planner-specific data object roles (Planning Solution, Planning Entity) in a user-friendly way. The options are available in the Planner dock.

optaplanner dock

The content of the dock varies depending on the current selection. Selecting a data object results in displaying top-level settings defined on data object level (Planning Solution, Planning Entity). On the other hand, selecting properties of the data object results in displaying fine-grained settings defined on property level of the data object.

The overview of the Planner dock capabilities is shown in the following division:

Data object level

Property level

4.2.1. Planning Entity Difficulty Comparator

Specified on Planning entity level, the Difficulty comparator provides a way to determine which Planning entities are more difficult to plan. This helps optimization algorithms to work in an efficient manner. Refer to OptaPlanner documentation for more details.

The Difficulty comparator definition tool is present in the Planner dock of the Data modeler and becomes available once a PlanningEntity selection is performed on a data object.

difficulty comparator

Click Add condition to add new sorting criteria for given planning entity. Once the criterion is added, Clicking Add field allows the user to select fields which will be used for difficulty comparison.

There are 2 types of fields:

  • Basic - value types (e.g. number, String)

  • Data object - complex types having nested attributes

Data object types allow nesting deep into object hierarchy, until a basic type is encountered. In this situation Add field button is no longer displayed. Sorting criteria are ordered. The ones defined first are prioritized when the Planner engine resolves planning entity difficulty.

Click the Remove icon within a label to remove the field from the sorting criteria. If the field is of type Data object, all its children are removed as well.

Click Arrow up, Arrow down to change the priority of the criterion by moving it up/down.

Select Sort order icon to define whether given criterion should be applied to sort the planning entities in ascending or descending order.

4.3. Guided Rule Editor

To solve an optimization problem, define score constraints that evaluate your solution. Planner integrates with the Guided Rule Editor and provides score modifiers which are used by the Planner engine during the solving process.

Score modifiers can be accessed in the action selector (+) of the THEN (right-hand side) section of a rule, provided the Planning Solution is defined within the project.

Make sure to define a Planning Solution before proceeding to a rule creation.

There are two types of Planner actions in the Guided Rule Editor:

  • Modify a single score level - use the action to modify only one score component (e.g. hard score)

  • Modify multiple score levels - use the action to modify multiple score components at the same time (e.g. hard and soft score)

Once the action is selected, Planner score input appears on the THEN (right-hand side) section of the rule. Insert the value of a constraint into the text input. Click Validate to verify the correctness of the inserted value.

guided rule editor rhs

5. Business Central integration

5.1. Knowledge Store REST API for Business Central spaces and projects

OptaPlanner provides a Knowledge Store REST API that you can use to interact with your projects and spaces in OptaPlanner without using the Business Central user interface. The Knowledge Store is the artifact repository for assets in OptaPlanner. This API support enables you to facilitate and automate maintenance of Business Central projects and spaces.

With the Knowledge Store REST API, you can perform the following actions:

  • Retrieve information about all projects and spaces

  • Create, update, or delete projects and spaces

  • Build, deploy, and test projects

  • Retrieve information about previous Knowledge Store REST API requests, or jobs

Knowledge Store REST API requests require the following components:

Authentication

The Knowledge Store REST API requires HTTP Basic authentication or token-based authentication for the user role rest-all. To view configured user roles for your OptaPlanner distribution, navigate to ~/$SERVER_HOME/standalone/configuration/application-roles.properties and ~/application-users.properties.

To add a user with the rest-all role, navigate to ~/$SERVER_HOME/bin and run the following command:

$ ./add-user.sh -a --user <USERNAME> --password <PASSWORD> --role rest-all

For more information about user roles and OptaPlanner installation options, see

HTTP headers

The Knowledge Store REST API requires the following HTTP headers for API requests:

  • Accept: Data format accepted by your requesting client:

    • application/json (JSON)

  • Content-Type: Data format of your POST or PUT API request data:

    • application/json (JSON)

HTTP methods

The Knowledge Store REST API supports the following HTTP methods for API requests:

  • GET: Retrieves specified information from a specified resource endpoint

  • POST: Creates or updates a resource

  • PUT: Updates a resource

  • DELETE: Deletes a resource

Base URL

The base URL for Knowledge Store REST API requests is http://SERVER:PORT/business-central/rest/, such as http://localhost:8080/business-central/rest/.

The REST API base URL for the Knowledge Store and for the KIE Server controller built in to Business Central are the same because both are considered part of Business Central REST services.
Endpoints

Knowledge Store REST API endpoints, such as /spaces/{spaceName} for a specified space, are the URIs that you append to the Knowledge Store REST API base URL to access the corresponding resource or type of resource in OptaPlanner.

Example request URL for /spaces/{spaceName} endpoint

http://localhost:8080/business-central/rest/spaces/MySpace

Request data

HTTP POST requests in the Knowledge Store REST API may require a JSON request body with data to accompany the request.

Example POST request URL and JSON request body data

http://localhost:8080/business-central/rest/spaces/MySpace/projects

{
  "name": "Employee_Rostering",
  "groupId": "employeerostering",
  "version": "1.0.0-SNAPSHOT",
  "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill."
}

5.1.1. Sending requests with the Knowledge Store REST API using a REST client or curl utility

The Knowledge Store REST API enables you to interact with your projects and spaces in OptaPlanner without using the Business Central user interface. You can send Knowledge Store REST API requests using any REST client or curl utility.

Prerequisites
  • Business Central is installed and running.

  • You have rest-all user role access to Business Central.

Procedure
  1. Identify the relevant API endpoint to which you want to send a request, such as [GET] /spaces to retrieve spaces in Business Central.

  2. In a REST client or curl utility, enter the following components for a GET request to /spaces. Adjust any request details according to your use case.

    For REST client:

    • Authentication: Enter the user name and password of the Business Central user with the rest-all role.

    • HTTP Headers: Set the following header:

      • Accept: application/json

    • HTTP method: Set to GET.

    • URL: Enter the Knowledge Store REST API base URL and endpoint, such as http://localhost:8080/business-central/rest/spaces.

    For curl utility:

    • -u: Enter the user name and password of the Business Central user with the rest-all role.

    • -H: Set the following header:

      • Accept: application/json

    • -X: Set to GET.

    • URL: Enter the Knowledge Store REST API base URL and endpoint, such as http://localhost:8080/business-central/rest/spaces.

    curl -u 'baAdmin:password@1' -H "Accept: application/json" -X GET "http://localhost:8080/business-central/rest/spaces"
  3. Execute the request and review the KIE Server response.

    Example server response (JSON):

    [
      {
        "name": "MySpace",
        "description": null,
        "projects": [
          {
            "name": "Employee_Rostering",
            "spaceName": "MySpace",
            "groupId": "employeerostering",
            "version": "1.0.0-SNAPSHOT",
            "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill.",
            "publicURIs": [
              {
                "protocol": "git",
                "uri": "git://localhost:9418/MySpace/example-Employee_Rostering"
              },
              {
                "protocol": "ssh",
                "uri": "ssh://localhost:8001/MySpace/example-Employee_Rostering"
              }
            ]
          },
          {
            "name": "Mortgage_Process",
            "spaceName": "MySpace",
            "groupId": "mortgage-process",
            "version": "1.0.0-SNAPSHOT",
            "description": "Getting started loan approval process in BPMN2, decision table, business rules, and forms.",
            "publicURIs": [
              {
                "protocol": "git",
                "uri": "git://localhost:9418/MySpace/example-Mortgage_Process"
              },
              {
                "protocol": "ssh",
                "uri": "ssh://localhost:8001/MySpace/example-Mortgage_Process"
              }
            ]
          }
        ],
        "owner": "admin",
        "defaultGroupId": "com.myspace"
      },
      {
        "name": "MySpace2",
        "description": null,
        "projects": [
          {
            "name": "IT_Orders",
            "spaceName": "MySpace",
            "groupId": "itorders",
            "version": "1.0.0-SNAPSHOT",
            "description": "Case Management IT Orders project",
            "publicURIs": [
              {
                "protocol": "git",
                "uri": "git://localhost:9418/MySpace/example-IT_Orders-1"
              },
              {
                "protocol": "ssh",
                "uri": "ssh://localhost:8001/MySpace/example-IT_Orders-1"
              }
            ]
          }
        ],
        "owner": "admin",
        "defaultGroupId": "com.myspace"
      }
    ]
  4. In your REST client or curl utility, send another API request with the following components for a POST request to /spaces/{spaceName}/projects to create a project within a space. Adjust any request details according to your use case.

    For REST client:

    • Authentication: Enter the user name and password of the Business Central user with the rest-all role.

    • HTTP Headers: Set the following header:

      • Accept: application/json

      • Content-Type: application/json

    • HTTP method: Set to POST.

    • URL: Enter the Knowledge Store REST API base URL and endpoint, such as http://localhost:8080/business-central/rest/spaces/MySpace/projects.

    • Request body: Add a JSON request body with the identification data for the new project:

    {
      "name": "Employee_Rostering",
      "groupId": "employeerostering",
      "version": "1.0.0-SNAPSHOT",
      "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill."
    }

    For curl utility:

    • -u: Enter the user name and password of the Business Central user with the rest-all role.

    • -H: Set the following headers:

      • Accept: application/json

      • Content-Type: application/json

    • -X: Set to POST.

    • URL: Enter the Knowledge Store REST API base URL and endpoint, such as http://localhost:8080/business-central/rest/spaces/MySpace/projects.

    • -d: Add a JSON request body or file (@file.json) with the identification data for the new project:

    curl -u 'baAdmin:password@1' -H "Accept: application/json" -H "Content-Type: application/json" -X POST "http://localhost:8080/business-central/rest/spaces/MySpace/projects" -d "{ \"name\": \"Employee_Rostering\", \"groupId\": \"employeerostering\", \"version\": \"1.0.0-SNAPSHOT\", \"description\": \"Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill.\"}"
    curl -u 'baAdmin:password@1' -H "Accept: application/json" -H "Content-Type: application/json" -X POST "http://localhost:8080/business-central/rest/spaces/MySpace/projects" -d @my-project.json
  5. Execute the request and review the KIE Server response.

    Example server response (JSON):

    {
      "jobId": "1541017411591-6",
      "status": "APPROVED",
      "spaceName": "MySpace",
      "projectName": "Employee_Rostering",
      "projectGroupId": "employeerostering",
      "projectVersion": "1.0.0-SNAPSHOT",
      "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill."
    }

    If you encounter request errors, review the returned error code messages and adjust your request accordingly.

5.1.2. Supported Knowledge Store REST API endpoints

The Knowledge Store REST API provides endpoints for managing spaces and projects in OptaPlanner and for retrieving information about previous Knowledge Store REST API requests, or jobs.

5.1.2.1. Spaces

The Knowledge Store REST API supports the following endpoints for managing spaces in Business Central. The Knowledge Store REST API base URL is http://SERVER:PORT/business-central/rest/. All requests require HTTP Basic authentication or token-based authentication for the rest-all user role.

[GET] /spaces

Returns all spaces in Business Central.

Example server response (JSON)
[
  {
    "name": "MySpace",
    "description": null,
    "projects": [
      {
        "name": "Employee_Rostering",
        "spaceName": "MySpace",
        "groupId": "employeerostering",
        "version": "1.0.0-SNAPSHOT",
        "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill.",
        "publicURIs": [
          {
            "protocol": "git",
            "uri": "git://localhost:9418/MySpace/example-Employee_Rostering"
          },
          {
            "protocol": "ssh",
            "uri": "ssh://localhost:8001/MySpace/example-Employee_Rostering"
          }
        ]
      },
      {
        "name": "Mortgage_Process",
        "spaceName": "MySpace",
        "groupId": "mortgage-process",
        "version": "1.0.0-SNAPSHOT",
        "description": "Getting started loan approval process in BPMN2, decision table, business rules, and forms.",
        "publicURIs": [
          {
            "protocol": "git",
            "uri": "git://localhost:9418/MySpace/example-Mortgage_Process"
          },
          {
            "protocol": "ssh",
            "uri": "ssh://localhost:8001/MySpace/example-Mortgage_Process"
          }
        ]
      }
    ],
    "owner": "admin",
    "defaultGroupId": "com.myspace"
  },
  {
    "name": "MySpace2",
    "description": null,
    "projects": [
      {
        "name": "IT_Orders",
        "spaceName": "MySpace",
        "groupId": "itorders",
        "version": "1.0.0-SNAPSHOT",
        "description": "Case Management IT Orders project",
        "publicURIs": [
          {
            "protocol": "git",
            "uri": "git://localhost:9418/MySpace/example-IT_Orders-1"
          },
          {
            "protocol": "ssh",
            "uri": "ssh://localhost:8001/MySpace/example-IT_Orders-1"
          }
        ]
      }
    ],
    "owner": "admin",
    "defaultGroupId": "com.myspace"
  }
]
[GET] /spaces/{spaceName}

Returns information about a specified space.

Table 3. Request parameters
Name Description Type Requirement

spaceName

Name of the space to be retrieved

String

Required

Example server response (JSON)
{
  "name": "MySpace",
  "description": null,
  "projects": [
    {
      "name": "Mortgage_Process",
      "spaceName": "MySpace",
      "groupId": "mortgage-process",
      "version": "1.0.0-SNAPSHOT",
      "description": "Getting started loan approval process in BPMN2, decision table, business rules, and forms.",
      "publicURIs": [
        {
          "protocol": "git",
          "uri": "git://localhost:9418/MySpace/example-Mortgage_Process"
        },
        {
          "protocol": "ssh",
          "uri": "ssh://localhost:8001/MySpace/example-Mortgage_Process"
        }
      ]
    },
    {
      "name": "Employee_Rostering",
      "spaceName": "MySpace",
      "groupId": "employeerostering",
      "version": "1.0.0-SNAPSHOT",
      "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill.",
      "publicURIs": [
        {
          "protocol": "git",
          "uri": "git://localhost:9418/MySpace/example-Employee_Rostering"
        },
        {
          "protocol": "ssh",
          "uri": "ssh://localhost:8001/MySpace/example-Employee_Rostering"
        }
      ]
    },
    {
      "name": "Evaluation_Process",
      "spaceName": "MySpace",
      "groupId": "evaluation",
      "version": "1.0.0-SNAPSHOT",
      "description": "Getting started Business Process for evaluating employees",
      "publicURIs": [
        {
          "protocol": "git",
          "uri": "git://localhost:9418/MySpace/example-Evaluation_Process"
        },
        {
          "protocol": "ssh",
          "uri": "ssh://localhost:8001/MySpace/example-Evaluation_Process"
        }
      ]
    },
    {
      "name": "IT_Orders",
      "spaceName": "MySpace",
      "groupId": "itorders",
      "version": "1.0.0-SNAPSHOT",
      "description": "Case Management IT Orders project",
      "publicURIs": [
        {
          "protocol": "git",
          "uri": "git://localhost:9418/MySpace/example-IT_Orders"
        },
        {
          "protocol": "ssh",
          "uri": "ssh://localhost:8001/MySpace/example-IT_Orders"
        }
      ]
    }
  ],
  "owner": "admin",
  "defaultGroupId": "com.myspace"
}
[POST] /spaces

Creates a space in Business Central.

Table 4. Request parameters
Name Description Type Requirement

body

The name, description, owner, defaultGroupId, and any other components of the new space

Request body

Required

Example request body (JSON)
{
  "name": "NewSpace",
  "description": "My new space.",
  "owner": "admin",
  "defaultGroupId": "com.newspace"
}
Example server response (JSON)
{
  "jobId": "1541016978154-3",
  "status": "APPROVED",
  "spaceName": "NewSpace",
  "owner": "admin",
  "defaultGroupId": "com.newspace",
  "description": "My new space."
}
[PUT] /spaces

Updates description, owner, and defaultGroupId of a space in Business Central.

Example request body (JSON)
{
  "name": "MySpace",
  "description": "This is updated description",
  "owner": "admin",
  "defaultGroupId": "com.updatedGroupId"
}
Example server response (JSON)
{
  "jobId": "1592214574454-1",
  "status": "APPROVED",
  "spaceName": "MySpace",
  "owner": "admin",
  "defaultGroupId": "com.updatedGroupId",
  "description": "This is updated description"
}
[DELETE] /spaces/{spaceName}

Deletes a specified space from Business Central.

Table 5. Request parameters
Name Description Type Requirement

spaceName

Name of the space to be deleted

String

Required

Example server response (JSON)
{
  "jobId": "1541127032997-8",
  "status": "APPROVED",
  "spaceName": "MySpace",
  "owner": "admin",
  "description": "My deleted space.",
  "repositories": null
}
5.1.2.2. Projects

The Knowledge Store REST API supports the following endpoints for managing, building, and deploying projects in Business Central. The Knowledge Store REST API base URL is http://SERVER:PORT/business-central/rest/. All requests require HTTP Basic authentication or token-based authentication for the rest-all user role.

[GET] /spaces/{spaceName}/projects

Returns projects in a specified space.

Table 6. Request parameters
Name Description Type Requirement

spaceName

Name of the space for which you are retrieving projects

String

Required

Example server response (JSON)
[
  {
    "name": "Mortgage_Process",
    "spaceName": "MySpace",
    "groupId": "mortgage-process",
    "version": "1.0.0-SNAPSHOT",
    "description": "Getting started loan approval process in BPMN2, decision table, business rules, and forms.",
    "publicURIs": [
      {
        "protocol": "git",
        "uri": "git://localhost:9418/MySpace/example-Mortgage_Process"
      },
      {
        "protocol": "ssh",
        "uri": "ssh://localhost:8001/MySpace/example-Mortgage_Process"
      }
    ]
  },
  {
    "name": "Employee_Rostering",
    "spaceName": "MySpace",
    "groupId": "employeerostering",
    "version": "1.0.0-SNAPSHOT",
    "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill.",
    "publicURIs": [
      {
        "protocol": "git",
        "uri": "git://localhost:9418/MySpace/example-Employee_Rostering"
      },
      {
        "protocol": "ssh",
        "uri": "ssh://localhost:8001/MySpace/example-Employee_Rostering"
      }
    ]
  },
  {
    "name": "Evaluation_Process",
    "spaceName": "MySpace",
    "groupId": "evaluation",
    "version": "1.0.0-SNAPSHOT",
    "description": "Getting started Business Process for evaluating employees",
    "publicURIs": [
      {
        "protocol": "git",
        "uri": "git://localhost:9418/MySpace/example-Evaluation_Process"
      },
      {
        "protocol": "ssh",
        "uri": "ssh://localhost:8001/MySpace/example-Evaluation_Process"
      }
    ]
  },
  {
    "name": "IT_Orders",
    "spaceName": "MySpace",
    "groupId": "itorders",
    "version": "1.0.0-SNAPSHOT",
    "description": "Case Management IT Orders project",
    "publicURIs": [
      {
        "protocol": "git",
        "uri": "git://localhost:9418/MySpace/example-IT_Orders"
      },
      {
        "protocol": "ssh",
        "uri": "ssh://localhost:8001/MySpace/example-IT_Orders"
      }
    ]
  }
]
[GET] /spaces/{spaceName}/projects/{projectName}

Returns information about a specified project in a specified space.

Table 7. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project is located

String

Required

projectName

Name of the project to be retrieved

String

Required

Example server response (JSON)
{
  "name": "Employee_Rostering",
  "spaceName": "MySpace",
  "groupId": "employeerostering",
  "version": "1.0.0-SNAPSHOT",
  "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill.",
  "publicURIs": [
    {
      "protocol": "git",
      "uri": "git://localhost:9418/MySpace/example-Employee_Rostering"
    },
    {
      "protocol": "ssh",
      "uri": "ssh://localhost:8001/MySpace/example-Employee_Rostering"
    }
  ]
}
[POST] /spaces/{spaceName}/projects

Creates a project in a specified space.

Table 8. Request parameters
Name Description Type Requirement

spaceName

Name of the space in which the new project will be created

String

Required

body

The name, groupId, version, description, and any other components of the new project

Request body

Required

Example request body (JSON)
{
  "name": "Employee_Rostering",
  "groupId": "employeerostering",
  "version": "1.0.0-SNAPSHOT",
  "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill."
}
Example server response (JSON)
{
  "jobId": "1541017411591-6",
  "status": "APPROVED",
  "spaceName": "MySpace",
  "projectName": "Employee_Rostering",
  "projectGroupId": "employeerostering",
  "projectVersion": "1.0.0-SNAPSHOT",
  "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill."
}
[DELETE] /spaces/{spaceName}/projects/{projectName}

Deletes a specified project from a specified space.

Table 9. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project is located

String

Required

projectName

Name of the project to be deleted

String

Required

Example server response (JSON)
{
  "jobId": "1541128617727-10",
  "status": "APPROVED",
  "projectName": "Employee_Rostering",
  "spaceName": "MySpace"
}
[POST] /spaces/{spaceName}/git/clone

Clones a project into a specified space from a specified Git address.

Table 10. Request parameters
Name Description Type Requirement

spaceName

Name of the space to which you are cloning a project

String

Required

body

The name, description, and Git repository userName, password, and gitURL for the project to be cloned

Request body

Required

Example request body (JSON)
{
  "name": "Employee_Rostering",
  "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill.",
  "userName": "baAdmin",
  "password": "password@1",
  "gitURL": "git://localhost:9418/MySpace/example-Employee_Rostering"
}
Example server response (JSON)
{
  "jobId": "1541129488547-13",
  "status": "APPROVED",
  "cloneProjectRequest": {
    "name": "Employee_Rostering",
    "description": "Employee rostering problem optimisation using Planner. Assigns employees to shifts based on their skill.",
    "userName": "baAdmin",
    "password": "password@1",
    "gitURL": "git://localhost:9418/MySpace/example-Employee_Rostering"
  },
  "spaceName": "MySpace2"
}
[POST] /spaces/{spaceName}/projects/{projectName}/maven/compile

Compiles a specified project in a specified space (equivalent to mvn compile).

Table 11. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project is located

String

Required

projectName

Name of the project to be compiled

String

Required

Example server response (JSON)
{
  "jobId": "1541128617727-10",
  "status": "APPROVED",
  "projectName": "Employee_Rostering",
  "spaceName": "MySpace"
}
[POST] /spaces/{spaceName}/projects/{projectName}/maven/test

Tests a specified project in a specified space (equivalent to mvn test).

Table 12. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project is located

String

Required

projectName

Name of the project to be tested

String

Required

Example server response (JSON)
{
  "jobId": "1541132591595-19",
  "status": "APPROVED",
  "projectName": "Employee_Rostering",
  "spaceName": "MySpace"
}
[POST] /spaces/{spaceName}/projects/{projectName}/maven/install

Installs a specified project in a specified space (equivalent to mvn install).

Table 13. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project is located

String

Required

projectName

Name of the project to be installed

String

Required

Example server response (JSON)
{
  "jobId": "1541132668987-20",
  "status": "APPROVED",
  "projectName": "Employee_Rostering",
  "spaceName": "MySpace"
}
[POST] /spaces/{spaceName}/projects/{projectName}/maven/deploy

Deploys a specified project in a specified space (equivalent to mvn deploy).

Table 14. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project is located

String

Required

projectName

Name of the project to be deployed

String

Required

Example server response (JSON)
{
  "jobId": "1541132816435-21",
  "status": "APPROVED",
  "projectName": "Employee_Rostering",
  "spaceName": "MySpace"
}
5.1.2.3. Jobs (API requests)

All POST and DELETE requests in the Knowledge Store REST API return a job ID associated with each request, in addition to the returned request details. You can use a job ID to view the request status or delete a sent request.

Knowledge Store REST API requests, or jobs, can have the following statuses:

Table 15. Job statuses (API request statuses)
Status Description

ACCEPTED

The request was accepted and is being processed.

BAD_REQUEST

The request contained incorrect content and was not accepted.

RESOURCE_NOT_EXIST

The requested resource (path) does not exist.

DUPLICATE_RESOURCE

The resource already exists.

SERVER_ERROR

An error occurred in KIE Server.

SUCCESS

The request finished successfully.

FAIL

The request failed.

APPROVED

The request was approved.

DENIED

The request was denied.

GONE

The job ID for the request could not be found due to one of the following reasons:

  • The request was explicitly removed.

  • The request finished and has been deleted from a status cache. A request is removed from a status cache after the cache has reached its maximum capacity.

  • The request never existed.

The Knowledge Store REST API supports the following endpoints for retrieving or deleting sent API requests. The Knowledge Store REST API base URL is http://SERVER:PORT/business-central/rest/. All requests require HTTP Basic authentication or token-based authentication for the rest-all user role.

[GET] /jobs/{jobId}

Returns the status of a specified job (a previously sent API request).

Table 16. Request parameters
Name Description Type Requirement

jobId

ID of the job to be retrieved (example: 1541010216919-1)

String

Required

Example server response (JSON)
{
  "status": "SUCCESS",
  "jobId": "1541010216919-1",
  "result": null,
  "lastModified": 1541010218352,
  "detailedResult": [
    "level:INFO, path:null, text:Build of module 'Mortgage_Process' (requested by system) completed.\n Build: SUCCESSFUL"
  ]
}
[DELETE] /jobs/{jobId}

Deletes a specified job (a previously sent API request). If the job is not being processed yet, this request removes the job from the job queue. This request does not cancel or stop an ongoing job.

Table 17. Request parameters
Name Description Type Requirement

jobId

ID of the job to be deleted (example: 1541010216919-1)

String

Required

Example server response (JSON)
{
  "status": "GONE",
  "jobId": "1541010216919-1",
  "result": null,
  "lastModified": 1541132054916,
  "detailedResult": [
    "level:INFO, path:null, text:Build of module 'Mortgage_Process' (requested by system) completed.\n Build: SUCCESSFUL"
  ]
}
5.1.2.4. Branches

The Knowledge Store REST API supports the following endpoints for managing branches in Business Central. The Knowledge Store REST API base URL is http://SERVER:PORT/business-central/rest/. All requests require HTTP Basic authentication or token-based authentication for the rest-all user role.

[GET] /spaces/{spaceName}/projects/{projectName}/branches

Returns all branches in a specified project and space.

Table 18. Request parameters
Name Description Type Requirement

spaceName

Name of the space for which you are retrieving projects

String

Required

projectName

Name of the project for which you are retrieving branches

String

Required

Example server response (JSON)
[
  {
    "name":"master"
  }
]
[POST] /spaces/{spaceName}/projects/{projectName}/branches

Adds a specified branch in a specified project and space.

Table 19. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project is located

String

Required

projectName

Name of the project in which the new branch needs to be created

String

Required

body

The newBranchName and baseBranchName of a project

Request body

Required

Example request body (JSON)
{
   "newBranchName":  "branch01",
   "baseBranchName": "master"
}
Example server response (JSON)
{
    "jobId":          "1576175811141-3",
    "status":         "APPROVED",
    "spaceName":      "Space123",
    "projectName":    "ProjABC",
    "newBranchName":  "b1",
    "baseBranchName": "master",
    "userIdentifier": "bc"
}
[DELETE] /spaces/{spaceName}/projects/{projectName}/branches/{branchName}

Deletes a specified branch in a specified project and space.

Table 20. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project is located

String

Required

projectName

Name of the project where the branch is located

String

Required

branchName

Name of the branch to be deleted

String

Required

Example server response (JSON)
{
    "jobId":          "1576175811421-5",
    "status":         "APPROVED",
    "spaceName":      "Space123",
    "projectName":    "ProjABC",
    "branchName":     "b1",
    "userIdentifier": "bc"
}
[POST] /spaces/{spaceName}/projects/{projectName}/branches/{branchName}/maven/compile

Compiles a specified branch in a specified project and space. If branchName is not specified, then request applies to the master branch.

Table 21. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project is located

String

Required

projectName

Name of the project where the branch is located

String

Required

branchName

Name of the branch to be compiled

String

Required

Example server response (JSON)
{
    "jobId":       "1576175811233-4",
    "status":      "APPROVED",
    "spaceName":   "Space123",
    "projectName": "ProjABC",
    "branchName":  "b1",
}
[POST] /spaces/{spaceName}/projects/{projectName}/branches/{branchName}/maven/install

Installs a specified branch in a specified project and space. If branchName is not specified, then request applies to the master branch.

Table 22. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project is located

String

Required

projectName

Name of the project where the branch is located

String

Required

branchName

Name of the branch to be installed

String

Required

Example server response (JSON)
{
    "jobId":       "1576175811233-4",
    "status":      "APPROVED",
    "spaceName":   "Space123",
    "projectName": "ProjABC",
    "branchName":  "b1",
}
[POST] /spaces/{spaceName}/projects/{projectName}/branches/{branchName}/maven/test

Tests a specified branch in a specified project and space. If branchName is not specified, then request applies to the master branch.

Table 23. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project located

String

Required

projectName

Name of the project where the branch is located

String

Required

branchName

Name of the branch to be tested

String

Required

Example server response (JSON)
{
    "jobId":       "1576175811233-4",
    "status":      "APPROVED",
    "spaceName":   "Space123",
    "projectName": "ProjABC",
    "branchName":  "b1",
}
[POST] /spaces/{spaceName}/projects/{projectName}/branches/{branchName}/maven/deploy

Deploys a specified branch in a specified project and space. If branchName is not specified, then request applies to the master branch.

Table 24. Request parameters
Name Description Type Requirement

spaceName

Name of the space where the project is located

String

Required

projectName

Name of the project where the branch is located

String

Required

branchName

Name of the branch to be deployed

String

Required

Example server response (JSON)
{
    "jobId":       "1576175811233-4",
    "status":      "APPROVED",
    "spaceName":   "Space123",
    "projectName": "ProjABC",
    "branchName":  "b1",
}

5.2. Embedded KIE Server controller calls

When running Business Central with the embedded KIE Server controller mode, a series of endpoints related to managing all aspects of KIE Server templates, instances, and containers are also available. For more details, see KIE Server controller REST API. A Java client API is also available for interacting with these endpoints.

5.3. Keycloak SSO integration

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, especially 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 Business Central

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

  • User session management

  • And much more…​

Next sections cover the following integration points with Keycloak:

  • Business Central 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 provide 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 Business Central and Execution Server, such as the REST API or remote file system services.

  • Keycloak and Business Central’s security administration area

5.3.1. Scenario

Consider the following diagram as the environment for this document’s example:

Keycloak is a standalone process that provides remote authentication, authorization and administration services that can be potentially consumed by one or more jBPM applications over the network.

KeyCloak sso scenario

Consider these main steps for building this environment:

  • Install and set up a Keycloak server

  • Create and set up a Realm for this example - Configure realm’s clients, users and roles

  • Install and set up the SSO client adapter & jBPM application

Note: The resulting environment and the different configurations for this document are based on Business Central.

5.3.2. Install and set up a Keycloak 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 an 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 set up:

  • Download the 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 to 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 'admin' user by navigating to http://localhost:8180/auth/

The Keycloak administration console will be available at http://localhost:8180/auth/admin/.

5.3.3. Create and set up the demo realm

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

    • Access type: confidential

    • Root URL: http://localhost:8080

    • Base URL: /business-central-x.y.z.Final

    • Redirect URIs: /business-central-x.y.z.Final/*

The resulting kie client settings screen:

kie client settings

As you can see in the above settings it’s being considered the value business-central-x.y.z.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 Business Central is to create the application’s user and roles:

  • Go to the Roles section and create the roles admin, kiemgmt and rest-all

  • Go to the Users section and create the admin user. Set the password with value password in the credentials tab, unset the temporary switch.

  • In the Users section navigate to the Role Mappings tab and assign the admin, kiemgmt and rest-all roles to the admin user

admin user roles

At this point a Keycloak server is running on the host, set up with a minimal configuration set. Let’s move to Business Central set up.

5.3.4. Install and set up Business Central

For this tutorial let’s use a Wildfly as the application server for Business Central, 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.

5.3.4.1. Install the KC adapter

In order to use the Keycloak’s authentication and authorization modules from the jBPM application, the Keycloak JBoss EAP/Wildfly Adapter 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 Securing Applications section from the Keycloak docs. Here are the steps to install and set up the adapter for Wildfly 11/10/9:

  • Download the adapter from Keycloak Client Adapter for Wildfly 11/10/9

  • Execute the following commands on your shell:

    cd $JBPM_HOME
    unzip keycloak-wildfly-adapter-dist-3.4.3.Final.zip // Install the KC client adapter
    
    cd $JBPM_HOME/bin
    ./standalone.sh -c standalone-full.xml // set up 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
5.3.4.2. Configure the KC adapter

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:

  • Per WAR configuration

  • Via Keycloak subsystem

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 Required Per WAR Configuration.

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="business-central-x.y.z.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 the 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 in 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 (Bearer) 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.

Ensure the following tag is NOT present in the Wildfly/EAP profile’s configuration file (eg: standalone.xml):

<single-sign-on/>

It’s enabled by default in some server versions. If present, it must be removed/disabled in order to allow Keycloak to properly handle the clients.

5.3.4.3. Run the environment

At this point a Keycloak server is up and running on the host, and the KC adapter is installed and configured for the jBPM application server. You can run the application using:

$JBPM_HOME/bin/standalone.sh -c standalone-full.xml

You can navigate into the application once the server is up at:

 http://localhost:8080/business-central-x.y.z.Final
jbpm login screen

Use your Keycloak’s admin user credentials to login: admin/password.

5.3.5. Securing Business Central remote services via Keycloak

Business Central provides different remote service endpoints that can be consumed by third party clients using the Knowledge Store REST API.

In order to authenticate those services through Keycloak, apply those modifications for the WEB-INF/web.xml file (app deployment descriptor) from jBPM’s WAR file:

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

The user that consumes the remote services must be member of role rest-all. As described in previous steps, the admin user in this example is already a member of the rest-all role.

5.3.6. Securing Business Central’s file system services via Keycloak

In order to consume other remote services such as the file system ones (e.g. remote GIT), a specific Keycloak login module must be used for the application’s security domain in the $JBPM_HOME/standalone/configuration/standalone-full.xml file. By default Business Central uses the other security domain, so the resulting configuration on the $JBPM_HOME/standalone/configuration/standalone-full.xml should be such as:

<security-domain name="other" cache-type="default">
    <authentication>
        <login-module code="org.keycloak.adapters.jaas.DirectAccessGrantsLoginModule" flag="required">
            <!-- Parameter value can be a file system absolute path or a classpath (e.g. "classpath:/some-path/kie-git.json")-->
            <module-option name="keycloak-config-file" value="$JBPM_HOME/kie-git.json"/>
        </login-module>
    </authentication>
</security-domain>

Note that:

  • The login modules on the other security domain in the $JBPM_HOME/standalone/configuration/standalone-full.xml file must be REPLACED by the above given one.

  • Replace $JBPM_HOME/kie-git.json by the path (on file system) or the classpath (e.g. classpath:/some-path/kie-git.json) for the json configuration file used for the remote services client. Please continue reading in order to create this Keycloak client and how to obtain this json file.

At this point, remote services that use JAAS for the authentication process, such as the file system ones (e.g. GIT), are secured by Keycloak using the client specified in the above json configuration file. So let’s create this client on Keycloak and generate the required JSON file:

  • Navigate to the KC administration console and create a new client for the demo realm using kie-git as name.

  • Enable Direct Access Grants Enabled option

  • Disable Standard Flow Enabled option

  • Use a confidential access type for this client. See below image as example:

kie git client settings
  • Go to the Installation tab in same kie-git client configuration screen and export using the Keycloak OIDC JSON type.

  • Finally copy this generated JSON file into an accessible directory on the server’s file system or add it in the application’s classpath. Use this path value as the keycloak-config-file argument for the above configuration of the org.keycloak.adapters.jaas.DirectAccessGrantsLoginModule login module.

  • More information about Keycloak JAAS Login modules can be found Keycloak JAAS plugin.

At this point, the internal Git repositories can be cloned by all users authenticated via the Keycloak server:

# Command example:
git clone ssh://admin@localhost:8001/system

5.3.7. Execution server

The KIE Execution Server provides a REST API that can be consumed for any third party clients. This section is about how to integrate 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:

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

  • Create the client for the execution server on Keycloak

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

5.3.7.1. Create the execution server’s client on Keycloak

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-x.y.z.Final/*

  • Base URL: /kie-server-x.y.z.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 a 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.

5.3.7.2. Install and set up the KC adapter on the execution server

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

Let’s install, set up and deploy the execution server:

  • Install another Wildfly server to use for the execution server and the KC client adapter as well. You can follow above instructions for Business Central or follow the securing applications guide

  • Edit the standalone-full.xml file from the Wildfly server’s configuration path and configure the KC subsystem adapter as:

    <secure-deployment name="kie-server-x.y.z.Final.war">
        <realm>demo</realm>
        <realm-public-key>MIGfMA0GCSqGSIb...</realm-public-key>
        <auth-server-url>http://localhost:8180/auth</auth-server-url>
        <ssl-required>external</ssl-required>
        <resource>kie-execution-server</resource>
        <enable-basic-auth>true</enable-basic-auth>
        <credential name="secret">e92ec68d-6177-4239-be05-28ef2f3460ff</credential>
        <principal-attribute>preferred_username</principal-attribute>
    </secure-deployment>

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 Business Central 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 Credentials tab of the KC admin console

5.3.7.3. Deploy and run the execution server

Just deploy the execution server in Wildfly using any of the available mechanisms. Run the execution server using this command:

$EXEC_SERVER_HOME/bin/standalone.sh -c standalone-full.xml -Djboss.socket.binding.port-offset=200 -Dorg.kie.server.id=<ID> -Dorg.kie.server.user=<USER> -Dorg.kie.server.pwd=<PWD> -Dorg.kie.server.location=<LOCATION_URL>  -Dorg.kie.server.controller=<CONTROLLER_URL> -Dorg.kie.server.controller.user=<CONTROLLER_USER> -Dorg.kie.server.controller.pwd=<CONTOLLER_PASSWORD>

Example:

$EXEC_SERVER_HOME/bin/standalone.sh -c standalone-full.xml -Djboss.socket.binding.port-offset=200 -Dorg.kie.server.id=kieserver1 -Dorg.kie.server.user=admin -Dorg.kie.server.pwd=password -Dorg.kie.server.location=http://localhost:8280/kie-server-x.y.z.Final/services/rest/server -Dorg.kie.server.controller=http://localhost:8080/business-central-x.y.z.Final/rest/controller -Dorg.kie.server.controller.user=admin -Dorg.kie.server.controller.pwd=password

The users that will consume the execution server remote service endpoints must have the role kie-server assigned. So create and assign this role in the KC admin console for the users that will consume the execution server remote services.

Once up, you can check the server status as (considered using Basic authentication for this request, see next Consuming remote services for more information):

curl http://admin:password@localhost:8280/kie-server-x.y.z.Final/services/rest/server/

5.3.8. Consuming remote services

In order to use the different remote services provided by Business Central 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:

  • The role rest-all for using the Business Central remote services

  • The role kie-server for using the Execution Server remote services

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:

  • Using basic authentication, if the application’s client supports it

  • Using Bearer (token) based authentication

5.3.8.1. Using basic authentication

If the KC client adapter configuration has the Basic authentication enabled, as proposed in this guide for both Business Central (step 3.2) and Execution Server, you can avoid the token grant/refresh calls and just call the services as the following examples.

Example for a Business Central remote repositories endpoint:

curl http://admin:password@localhost:8080/business-central-x.y.z.Final/rest/repositories

Example to check the status for the Execution Server:

curl http://admin:password@localhost:8280/kie-server-x.y.z.Final/services/rest/server/
5.3.8.2. Using token-based authentication

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:

  • Go to the KC admin console and create a new client using this configuration:

    • Client id: kie-remote

    • Client protocol: openid-connect

    • Access type: public

    • Valid redirect URIs: http://localhost/

  • As we are going to manually obtain a token and invoke the service let’s increase the lifespan of tokens slightly. In production access tokens should have a relatively low timeout, ideally less than 5 minutes:

    • Go to the KC admin console

    • Click your Realm Settings

    • Click Tokens tab

    • Change the value for Access Token Lifespan to 15 minutes. That should give us plenty of time to obtain a token and invoke the service before it expires.

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&password=password" 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 example, if you want to check the internal jBPM repositories:

curl -H "Authorization: bearer $TOKEN" http://localhost:8080/business-central-x.y.z.Final/rest/repositories

5.3.9. Keycloak and the Business Central’s security administration area

Business Central provides an administration area which provides user, group and role management features (see Security management).

By default the application’s security management system points to the application’s server realm. For instance, in case of using the packaged distribution for Wildfly, it points to the Wildfly’s ApplicationRealm (properties based). It means the entities from the realm presented in the administration area are not the ones from the Keycloak realm that the application is using. There exist the following options in order to change this default behavior:

  • Disable the user system administration

  • Use the built-in Keycloak security management provider instead of the default one

In order to customize an existing jBPM application (WAR file) for using the Keycloak security management provider replace the content for WEB-INF/classes/security-management.properties by:

org.uberfire.ext.security.management.api.userManagementServices=KCAdapterUserManagementService
org.uberfire.ext.security.management.keycloak.authServer=<authz_server_url>
# eg: org.uberfire.ext.security.management.keycloak.authServer=http://localhost:8180/auth

The properties org.uberfire.ext.security.management.api.userManagementServices and org.uberfire.ext.security.management.keycloak.authServer can be set as system properties as well.

The jar artifacts required in the steps above can be either downloaded from JBoss Nexus or either build from sources.

Once applying the above changes, the security administration area uses the access token present in the user’s session in order to authorize and manage the specific Keycloak realm data.

In order to be able to manage Keycloak realms remotely, please ensure the user has the realm-management client role assigned

6. Business Central High Availability

6.1. VFS clustering

The VFS repositories (usually git repositories) stores all the assets (such as rules, decision tables, process definitions, forms, etc). If that VFS is located 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 Business Central is built) 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 in a cluster equal the number of application servers in the cluster. The node names (nodeOne:12345 , …​) can be changed as needed.

      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>

      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.

6.2. jBPM clustering

In addition to the information above, jBPM clustering requires additional configuration. See this blog post to configure the database etc correctly.

OptaPlanner Execution Server

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

7. KIE Execution Server

7.1. Overview

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 Business Central.

At its core, KIE Server is a configurable web application packaged as a WAR file. Distributions are available 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:

  • BRM: provides support for the execution of Business Rules using the Drools engine.

  • BPM: provides support for the execution of Business Processes using the jBPM engine. It supports:

    • process execution

    • task execution

    • asynchronous job execution

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.

7.1.1. Glossary

  • Kie Server: execution server purely focusing on providing runtime environment for both rules and processes. These capabilities are provided by Kie Server Extensions. More capabilities can be added by further extensions (e.g. customer could add his own extensions in case of missing functionality that will then use infrastructure of the KIE Server). A Kie Server instance is a standalone Kie Server executing on a given application server/web container. A Kie Server instantiates and provides support for multiple Kie Containers.

  • Kie Server Extension: a "plugin" for the Kie Server that adds capabilities to the server. The Kie Server ships with two default kie server extensions: BRM and BPM.

  • Kie Container: an in-memory instantiation of a kjar, allowing for the instantiation and usage of its assets (domain models, processes, rules, etc). A Kie Server exposes Kie Containers through a standard API over transport protocols like REST and JMS.

  • Controller: a server-backed REST endpoint that will be responsible for managing KIE Server instances. Such end point must provide following capabilities:

    • respond to connect requests

    • sync all registered containers on the corresponding Kie Server ID

    • respond to disconnect requests

  • Kie Server state: currently known state of given Kie Server instance. This is a local storage (by default in file) that maintains the following information:

    • list of registered KIE Server controllers

    • list of known containers

    • kie server configuration

      The server state is persisted upon receival of events like: Kie Container created, Kie Container is disposed, KIE Server controller accepts registration of Kie Server instance, etc.

  • Kie Server ID: an arbitrary assigned identifier to which configurations are assigned. At boot, each Kie Server Instance is assigned an ID, and that ID is matched to a configuration on the KIE Server controller. The Kie Server Instance fetches and uses that configuration to setup itself.

7.2. Installing the KIE Server

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

  • webc - WAR for ordinary Web (Servlet) containers like Tomcat

  • ee6 - WAR for JavaEE 6 containers like JBoss EAP 6.x

  • ee7 - WAR for JavaEE 7 containers like WildFly 11.x

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

  1. Deploy the WAR file into your web container.

  2. Create a user with the role of kie-server on the container.

  3. Test that you can access the KIE Server by navigating to the endpoint in a browser window: http://SERVER:PORT/CONTEXT/services/rest/server/.

  4. When prompted for user name/password, type in the user name and password that you created in step 2.

  5. Once authenticated, you will see an XML response in the form of KIE Server status, similar to this:

    Example 1. Sample handshaking server response
    <response type="SUCCESS" msg="KIE Server info">
      <kie-server-info>
        <version>7.44.0.Final</version>
      </kie-server-info>
    </response>

7.2.1. Installation details for different containers

7.2.1.1. Tomcat 7.x/8.x
  1. Download and unzip the Tomcat distribution. Let’s call the root of the distribution TOMCAT_HOME. This directory is named after the Tomcat version, so for example apache-tomcat-7.0.55.

  2. Download kie-server- -webc.war and place it into TOMCAT_HOME/webapps.

  3. Configure user(s) and role(s). Make sure that file TOMCAT_HOME/conf/tomcat-users.xml contains the following user name and role definition. You can of course choose different user name and password, just make sure that the user has role kie-server:

    Example 2. User name and role definition for Tomcat
    <role rolename="kie-server"/>
    <user username="serveruser" password="my.s3cr3t.pass" roles="kie-server"/>
  4. Start the server by running TOMCAT_HOME/bin/startup.[sh|bat]. You can check out the Tomcat logs in TOMCAT_HOME/logs to see if the application deployed successfully. Please read the table above for the bootstrap switches that can be used to properly configure the instance. For instance:

    ./startup.sh -Dorg.kie.server.id=first-kie-server
                 -Dorg.kie.server.location=http://localhost:8080/kie-server/services/rest/server
  5. Verify the server is running. Go to http://SERVER:PORT/CONTEXT/services/rest/server/ and type the specified user name and password. You should see simple XML message with basic information about the server.

You can not leverage the JMS interface when running with Tomcat, or any other Web container. The Web container version of the WAR contains only the REST interface.

7.2.1.2. WildFly 11.x
  1. Download and unzip the WildFly distribution. Let’s call the root of the distribution WILDFLY_HOME. This directory is named after the WildFly version, so for example wildfly-14.0.1.Final.

  2. Download kie-server- -ee7.war and place it into WILDFLY_HOME/standalone/deployments.

  3. Configure user(s) and role(s). Execute the following command WILDFLY_HOME/bin/add-user.[sh|bat] -a -u 'kieserver' -p 'kieserver1!' -ro 'kie-server'. You can of course choose different user name and password, just make sure that the user has role kie-server.

  4. Start the server by running WILDFLY_HOME/bin/standalone.[sh|bat] -c standalone-full.xml <bootstrap_switches>. You can check out the standard output or WildFly logs in WILDFLY_HOME/standalone/logs to see if the application deployed successfully. Please read the table above for the bootstrap switches that can be used to properly configure the instance. For instance:

    ./standalone.sh  --server-config=standalone-full.xml
                     -Djboss.socket.binding.port-offset=150
                     -Dorg.kie.server.id=first-kie-server
                     -Dorg.kie.server.location=http://localhost:8230/kie-server/services/rest/server
  5. Verify the server is running. Go to http://SERVER:PORT/CONTEXT/services/rest/server/ and type the specified user name and password. You should see simple XML message with basic information about the server.

    kie server info

7.3. KIE Server system properties

The KIE Server accepts the following system properties (bootstrap switches) to configure the behavior of the server:

Table 25. System properties for disabling KIE Server extensions
Property Values Default Description

org.drools.server.ext.disabled

true, false

false

If set to true, disables the Business Rule Management (BRM) support (for example, rules support).

org.optaplanner.server.ext.disabled

true, false

false

If set to true, disables the OptaPlanner support.

org.kie.prometheus.server.ext.disabled

true, false

true

If set to true, disables the Prometheus Server extension.

org.kie.scenariosimulation.server.ext.disabled

true, false

true

If set to true, disables the Test scenario Server extension.

org.kie.dmn.server.ext.disabled

true, false

false

If set to true, disables the KIE Server DMN support.

org.kie.swagger.server.ext.disabled

true, false

false

If set to true, disables the KIE Server swagger documentation support

Some KIE Server controller properties listed in the following table are marked as required. Set these properties when you create or remove KIE Server containers in Business Central. If you use the KIE Server separately without any interaction with Business Central, you do not need to set the required properties.
Table 26. System properties required for KIE Server controller
Property Values Default Description

org.kie.server.id

String

N/A

An arbitrary ID to be assigned to the server. If a headless KIE Server controller is configured outside of Business Central, this is the ID under which the server connects to the headless KIE Server controller to fetch the KIE container configurations. If not provided, the ID is automatically generated.

org.kie.server.user

String

kieserver

The user name used to connect with the KIE Server from the KIE Server controller, required when running in managed mode. Set this property in Business Central system properties. Set this property when using a KIE Server controller.

org.kie.server.pwd

String

kieserver1!

The password used to connect with the KIE Server from the KIE Server controller, required when running in managed mode. Set this property in Business Central system properties. Set this property when using a KIE Server controller.

org.kie.server.token

String

N/A

A property that enables you to use token-based authentication between the KIE Server controller and the KIE Server instead of the basic user name and password authentication. The KIE Server controller sends the token as a parameter in the request header. The server requires long-lived access tokens because the tokens are not refreshed.

org.kie.server.location

URL

N/A

The URL of the KIE Server instance used by the KIE Server controller to call back on this server, for example, http://localhost:8230/kie-server/services/rest/server. Setting this property is required when using a KIE Server controller.

org.kie.server.controller

Comma-separated list

N/A

A comma-separated list of URLs to the KIE Server controller REST endpoints, for example, http://localhost:8080/business-central/rest/controller. Setting this property is required when using a KIE Server controller.

org.kie.server.controller.user

String

kieserver

The user name to connect to the KIE Server controller REST API. Setting this property is required when using a KIE Server controller.

org.kie.server.controller.pwd

String

kieserver1!

The password to connect to the KIE Server controller REST API. Setting this property is required when using a KIE Server controller.

org.kie.server.controller.token

String

N/A

A property that enables you to use token-based authentication between the KIE Server and the KIE Server controller instead of the basic user name and password authentication. The server sends the token as a parameter in the request header. The server requires long-lived access tokens because the tokens are not refreshed.

org.kie.server.controller.connect

Long

10000

The waiting time in milliseconds between repeated attempts to connect the KIE Server to the KIE Server controller when the server starts.

Table 27. System properties for loading keystore
Property Values Default Description

kie.keystore.keyStoreURL

URL

N/A

The URL is used to load a Java Cryptography Extension KeyStore (JCEKS). For example, file:///home/kie/keystores/keystore.jceks.

kie.keystore.keyStorePwd

String

N/A

The password is used for the JCEKS.

kie.keystore.key.server.alias

String

N/A

The alias name of the key for REST services where the password is stored.

kie.keystore.key.server.pwd

String

N/A

The password of an alias for REST services.

kie.keystore.key.ctrl.alias

String

N/A

The alias of the key for default REST KIE Server controller.

kie.keystore.key.ctrl.pwd

String

N/A

The password of an alias for default REST KIE Server controller.

Table 28. Other system properties
Property Values Default Description

kie.maven.settings.custom

Path

N/A

The location of a custom settings.xml file for Maven configuration.

kie.server.jms.queues.response

String

queue/KIE.SERVER.RESPONSE

The response queue JNDI name for JMS.

org.drools.server.filter.classes

true, false

false

When set to true, the Drools KIE Server extension accepts custom classes annotated by the XmlRootElement or Remotable annotations only.

org.kie.server.domain

String

N/A

The JAAS LoginContext domain used to authenticate users when using JMS.

org.kie.server.repo

Path

.

The location where KIE Server state files are stored.

org.kie.server.sync.deploy

true, false

false

A property that instructs the KIE Server to hold the deployment until the KIE Server controller provides the container deployment configuration. This property only affects servers running in managed mode. The following options are available:

* false: The connection to the KIE Server controller is asynchronous. The application starts, connects to the KIE Server controller, and once successful, deploys the containers. The application accepts requests even before the containers are available. * true: The deployment of the server application joins the KIE Server controller connection thread with the main deployment and awaits its completion. This option can lead to a potential deadlock in case more applications are on the same server. Use only one application on one server instance.

org.kie.server.startup.strategy

ControllerBasedStartupStrategy, LocalContainersStartupStrategy

ControllerBasedStartupStrategy

The Startup strategy of KIE Server used to control the KIE containers that are deployed and the order in which they are deployed.

org.kie.server.mgmt.api.disabled

true, false

false

When set to true, disables KIE Server management API.

org.kie.server.xstream.enabled.packages

Java packages like org.kie.example. You can also specify wildcard expressions like org.kie.example.*.

N/A

A property that specifies additional packages to whitelist for marshalling using XStream.

org.kie.store.services.class

String

org.drools.persistence.jpa.KnowledgeStoreServiceImpl

Fully qualified name of the class that implements KieStoreServices that are responsible for bootstrapping KieSession instances.

org.kie.server.strict.id.format

true, false

false

While using JSON marshalling, if the property is set to true, it will always return a response in the proper JSON format. For example, if the original response contains only a single number, then the response is wrapped in a JSON format. For example, {"value" : 1}.

7.4. KIE Server capabilities and extensions

The capabilities in KIE Server are determined by plug-in extensions that you can enable, disable, or further extend to meet your business needs. KIE Server supports the following default capabilities and extensions:

Table 29. KIE Server capabilities and extensions
Capability name Extension name Description

KieServer

KieServer

Provides the core capabilities of KIE Server, such as creating and disposing KIE containers on your server instance

BRM

Drools

Provides the Business Rule Management (BRM) capabilities, such as inserting facts and executing business rules

BRP

OptaPlanner

Provides the Business Resource Planning (BRP) capabilities, such as implementing solvers

DMN

DMN

Provides the Decision Model and Notation (DMN) capabilities, such as managing DMN data types and executing DMN models

Swagger

Swagger

Provides the Swagger web-interface capabilities for interacting with the KIE Server REST API

To view the supported extensions of a running KIE Server instance, send a GET request to the following REST API endpoint and review the XML or JSON server response:

Base URL for GET request for KIE Server information
http://SERVER:PORT/kie-server/services/rest/server
Example JSON response with KIE Server information
{
  "type": "SUCCESS",
  "msg": "Kie Server info",
  "result": {
    "kie-server-info": {
      "id": "test-kie-server",
      "version": "7.26.0.20190818-050814",
      "name": "test-kie-server",
      "location": "http://localhost:8080/kie-server/services/rest/server",
      "capabilities": [
        "KieServer",
        "BRM",
        "BRP",
        "DMN",
        "Swagger"
      ],
      "messages": [
        {
          "severity": "INFO",
          "timestamp": {
            "java.util.Date": 1566169865791
          },
          "content": [
            "Server KieServerInfo{serverId='test-kie-server', version='7.26.0.20190818-050814', name='test-kie-server', location='http:/localhost:8080/kie-server/services/rest/server', capabilities=[KieServer, BRM, BRP, DMN, Swagger]', messages=null', mode=DEVELOPMENT}started successfully at Sun Aug 18 23:11:05 UTC 2019"
          ]
        }
      ],
      "mode": "DEVELOPMENT"
    }
  }
}

To enable or disable KIE Server extensions, configure the related *.server.ext.disabled KIE Server system property. For example, to disable the BRM capability, set the system property org.drools.server.ext.disabled=true. For all KIE Server system properties, see KIE Server system properties.

By default, KIE Server extensions are exposed through REST or JMS data transports and use predefined client APIs. You can extend existing KIE Server capabilities with additional REST endpoints, extend supported transport methods beyond REST or JMS, or extend functionality in the KIE Server client.

This flexibility in KIE Server functionality enables you to adapt your KIE Server instances to your business needs, instead of adapting your business needs to the default KIE Server capabilities.

7.4.1. Extending an existing KIE Server capability with a custom REST API endpoint

The KIE Server REST API enables you to interact with your KIE containers and business assets (such as business rules, processes, and solvers) in OptaPlanner without using the Business Central user interface. The available REST endpoints are determined by the capabilities enabled in your KIE Server system properties (for example, org.drools.server.ext.disabled=false for the BRM capability). You can extend an existing KIE Server capability with a custom REST API endpoint to further adapt the KIE Server REST API to your business needs.

As an example, this procedure extends the Drools KIE Server extension (for the BRM capability) with the following custom REST API endpoint:

Example custom REST API endpoint
/server/containers/instances/{containerId}/ksession/{ksessionId}

This example custom endpoint accepts a list of facts to be inserted into the working memory of the Drools engine, automatically executes all rules, and retrieves all objects from the KIE session in the specified KIE container.

Procedure
  1. Create an empty Maven project and define the following packaging type and dependencies in the pom.xml file for the project:

    Example pom.xml file in the sample project
    <packaging>jar</packaging>
    
    <properties>
      <version.org.kie>7.43.0.Final</version.org.kie>
    </properties>
    
    <dependencies>
      <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-api</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-internal</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie.server</groupId>
        <artifactId>kie-server-api</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie.server</groupId>
        <artifactId>kie-server-services-common</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie.server</groupId>
        <artifactId>kie-server-services-drools</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie.server</groupId>
        <artifactId>kie-server-rest-common</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-core</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.25</version>
      </dependency>
    </dependencies>
  2. Implement the org.kie.server.services.api.KieServerApplicationComponentsService interface in a Java class in your project, as shown in the following example:

    Sample implementation of the KieServerApplicationComponentsService interface
    public class CusomtDroolsKieServerApplicationComponentsService implements KieServerApplicationComponentsService {  (1)
    
        private static final String OWNER_EXTENSION = "Drools";  (2)
    
        public Collection<Object> getAppComponents(String extension, SupportedTransports type, Object... services) {  (3)
            // Do not accept calls from extensions other than the owner extension:
            if ( !OWNER_EXTENSION.equals(extension) ) {
                return Collections.emptyList();
            }
    
            RulesExecutionService rulesExecutionService = null;  (4)
            KieServerRegistry context = null;
    
            for( Object object : services ) {
                if( RulesExecutionService.class.isAssignableFrom(object.getClass()) ) {
                    rulesExecutionService = (RulesExecutionService) object;
                    continue;
                } else if( KieServerRegistry.class.isAssignableFrom(object.getClass()) ) {
                    context = (KieServerRegistry) object;
                    continue;
                }
            }
    
            List<Object> components = new ArrayList<Object>(1);
            if( SupportedTransports.REST.equals(type) ) {
                components.add(new CustomResource(rulesExecutionService, context));  (5)
            }
    
            return components;
        }
    
    }
    1 Delivers REST endpoints to the KIE Server infrastructure that is deployed when the application starts.
    2 Specifies the extension that you are extending, such as the Drools extension in this example.
    3 Returns all resources that the REST container must deploy. Each extension that is enabled in your KIE Server instance calls the getAppComponents method, so the if ( !OWNER_EXTENSION.equals(extension) ) call returns an empty collection for any extensions other than the specified OWNER_EXTENSION extension.
    4 Lists the services from the specified extension that you want to use, such as the RulesExecutionService and KieServerRegistry services from the Drools extension in this example.
    5 Specifies the transport type for the extension, either REST or JMS (REST in this example), and the CustomResource class that returns the resource as part of the components list.
  3. Implement the CustomResource class that the KIE Server can use to provide the additional functionality for the new REST resource, as shown in the following example:

    Sample implementation of the CustomResource class
    // Custom base endpoint:
    @Path("server/containers/instances/{containerId}/ksession")
    public class CustomResource {
    
        private static final Logger logger = LoggerFactory.getLogger(CustomResource.class);
    
        private KieCommands commandsFactory = KieServices.Factory.get().getCommands();
    
        private RulesExecutionService rulesExecutionService;
        private KieServerRegistry registry;
    
        public CustomResource() {
    
        }
    
        public CustomResource(RulesExecutionService rulesExecutionService, KieServerRegistry registry) {
            this.rulesExecutionService = rulesExecutionService;
            this.registry = registry;
        }
    
        // Supported HTTP method, path parameters, and data formats:
        @POST
        @Path("/{ksessionId}")
        @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
        @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
        public Response insertFireReturn(@Context HttpHeaders headers,
                @PathParam("containerId") String id,
                @PathParam("ksessionId") String ksessionId,
                String cmdPayload) {
    
            Variant v = getVariant(headers);
            String contentType = getContentType(headers);
    
            // Marshalling behavior and supported actions:
            MarshallingFormat format = MarshallingFormat.fromType(contentType);
            if (format == null) {
                format = MarshallingFormat.valueOf(contentType);
            }
            try {
                KieContainerInstance kci = registry.getContainer(id);
    
                Marshaller marshaller = kci.getMarshaller(format);
    
                List<?> listOfFacts = marshaller.unmarshall(cmdPayload, List.class);
    
                List<Command<?>> commands = new ArrayList<Command<?>>();
                BatchExecutionCommand executionCommand = commandsFactory.newBatchExecution(commands, ksessionId);
    
                for (Object fact : listOfFacts) {
                    commands.add(commandsFactory.newInsert(fact, fact.toString()));
                }
                commands.add(commandsFactory.newFireAllRules());
                commands.add(commandsFactory.newGetObjects());
    
                ExecutionResults results = rulesExecutionService.call(kci, executionCommand);
    
                String result = marshaller.marshall(results);
    
    
                logger.debug("Returning OK response with content '{}'", result);
                return createResponse(result, v, Response.Status.OK);
            } catch (Exception e) {
                // If marshalling fails, return the `call-container` response to maintain backward compatibility:
                String response = "Execution failed with error : " + e.getMessage();
                logger.debug("Returning Failure response with content '{}'", response);
                return createResponse(response, v, Response.Status.INTERNAL_SERVER_ERROR);
            }
    
        }
    }

    In this example, the CustomResource class for the custom endpoint specifies the following data and behavior:

    • Uses the base endpoint server/containers/instances/{containerId}/ksession

    • Uses POST HTTP method

    • Expects the following data to be given in REST requests:

      • The containerId as a path argument

      • The ksessionId as a path argument

      • List of facts as a message payload

    • Supports all KIE Server data formats:

      • XML (JAXB, XStream)

      • JSON

    • Unmarshals the payload into a List<?> collection and, for each item in the list, creates an InsertCommand instance followed by FireAllRules and GetObject commands.

    • Adds all commands to the BatchExecutionCommand instance that calls to the Drools engine.

  4. To make the new endpoint discoverable for KIE Server, create a META-INF/services/org.kie.server.services.api.KieServerApplicationComponentsService file in your Maven project and add the fully qualified class name of the KieServerApplicationComponentsService implementation class within the file. For this example, the file contains the single line org.kie.server.ext.drools.rest.CusomtDroolsKieServerApplicationComponentsService.

  5. Build your project and copy the resulting JAR file into the ~/kie-server.war/WEB-INF/lib directory of your project.

  6. Start the KIE Server and deploy the built project to the running KIE Server. You can deploy the project using either the Business Central interface or the KIE Server REST API (a PUT request to http://SERVER:PORT/kie-server/services/rest/server/containers/{containerId}).

    After your project is deployed on a running KIE Server, you can start interacting with your new REST endpoint.

    For this example, you can use the following information to invoke the new endpoint:

    • Example request URL: http://localhost:8080/kie-server/services/rest/server/containers/instances/demo/ksession/defaultKieSession

    • HTTP method: POST

    • HTTP headers:

      • Content-Type: application/json

      • Accept: application/json

    • Example message payload:

      [
        {
          "org.jbpm.test.Person": {
            "name": "john",
            "age": 25
          }
        },
        {
          "org.jbpm.test.Person": {
            "name": "mary",
            "age": 22
          }
        }
      ]
    • Example server response: 200 (success)

    • Example server log output:

      13:37:20,347 INFO  [stdout] (default task-24) Hello mary
      13:37:20,348 INFO  [stdout] (default task-24) Hello john

7.4.2. Extending KIE Server to use a custom data transport

By default, KIE Server extensions are exposed through REST or JMS data transports. You can extend KIE Server to support a custom data transport to adapt KIE Server transport protocols to your business needs.

As an example, this procedure adds a custom data transport to KIE Server that uses the Drools extension and that is based on Apache MINA, an open-source Java network-application framework. The example custom MINA transport exchanges string-based data that relies on existing marshalling operations and supports only JSON format.

Procedure
  1. Create an empty Maven project and define the following packaging type and dependencies in the pom.xml file for the project:

    Example pom.xml file in the sample project
    <packaging>jar</packaging>
    
    <properties>
      <version.org.kie>7.43.0.Final</version.org.kie>
    </properties>
    
    <dependencies>
      <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-api</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-internal</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie.server</groupId>
        <artifactId>kie-server-api</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie.server</groupId>
        <artifactId>kie-server-services-common</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie.server</groupId>
        <artifactId>kie-server-services-drools</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-core</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.25</version>
      </dependency>
      <dependency>
        <groupId>org.apache.mina</groupId>
        <artifactId>mina-core</artifactId>
        <version>2.1.3</version>
      </dependency>
    </dependencies>
  2. Implement the org.kie.server.services.api.KieServerExtension interface in a Java class in your project, as shown in the following example:

    Sample implementation of the KieServerExtension interface
    public class MinaDroolsKieServerExtension implements KieServerExtension {
    
        private static final Logger logger = LoggerFactory.getLogger(MinaDroolsKieServerExtension.class);
    
        public static final String EXTENSION_NAME = "Drools-Mina";
    
        private static final Boolean disabled = Boolean.parseBoolean(System.getProperty("org.kie.server.drools-mina.ext.disabled", "false"));
        private static final String MINA_HOST = System.getProperty("org.kie.server.drools-mina.ext.port", "localhost");
        private static final int MINA_PORT = Integer.parseInt(System.getProperty("org.kie.server.drools-mina.ext.port", "9123"));
    
        // Taken from dependency on the `Drools` extension:
        private KieContainerCommandService batchCommandService;
    
        // Specific to MINA:
        private IoAcceptor acceptor;
    
        public boolean isActive() {
            return disabled == false;
        }
    
        public void init(KieServerImpl kieServer, KieServerRegistry registry) {
    
            KieServerExtension droolsExtension = registry.getServerExtension("Drools");
            if (droolsExtension == null) {
                logger.warn("No Drools extension available, quitting...");
                return;
            }
    
            List<Object> droolsServices = droolsExtension.getServices();
            for( Object object : droolsServices ) {
                // If the given service is null (not configured), continue to the next service:
                if (object == null) {
                    continue;
                }
                if( KieContainerCommandService.class.isAssignableFrom(object.getClass()) ) {
                    batchCommandService = (KieContainerCommandService) object;
                    continue;
                }
            }
            if (batchCommandService != null) {
                acceptor = new NioSocketAcceptor();
                acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
    
                acceptor.setHandler( new TextBasedIoHandlerAdapter(batchCommandService) );
                acceptor.getSessionConfig().setReadBufferSize( 2048 );
                acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
                try {
                    acceptor.bind( new InetSocketAddress(MINA_HOST, MINA_PORT) );
    
                    logger.info("{} -- Mina server started at {} and port {}", toString(), MINA_HOST, MINA_PORT);
                } catch (IOException e) {
                    logger.error("Unable to start Mina acceptor due to {}", e.getMessage(), e);
                }
    
            }
        }
    
        public void destroy(KieServerImpl kieServer, KieServerRegistry registry) {
            if (acceptor != null) {
                acceptor.dispose();
                acceptor = null;
            }
            logger.info("{} -- Mina server stopped", toString());
        }
    
        public void createContainer(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters) {
            // Empty, already handled by the `Drools` extension
    
        }
    
        public void disposeContainer(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters) {
          // Empty, already handled by the `Drools` extension
    
        }
    
        public List<Object> getAppComponents(SupportedTransports type) {
            // Nothing for supported transports (REST or JMS)
            return Collections.emptyList();
        }
    
        public <T> T getAppComponents(Class<T> serviceType) {
    
            return null;
        }
    
        public String getImplementedCapability() {
            return "BRM-Mina";
        }
    
        public List<Object> getServices() {
            return Collections.emptyList();
        }
    
        public String getExtensionName() {
            return EXTENSION_NAME;
        }
    
        public Integer getStartOrder() {
            return 20;
        }
    
        @Override
        public String toString() {
            return EXTENSION_NAME + " KIE Server extension";
        }
    }

    The KieServerExtension interface is the main extension interface that KIE Server can use to provide the additional functionality for the new MINA transport. The interface consists of the following components:

    Overview of the KieServerExtension interface
    public interface KieServerExtension {
    
        boolean isActive();
    
        void init(KieServerImpl kieServer, KieServerRegistry registry);
    
        void destroy(KieServerImpl kieServer, KieServerRegistry registry);
    
        void createContainer(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters);
    
        void disposeContainer(String id, KieContainerInstance kieContainerInstance, Map<String, Object> parameters);
    
        List<Object> getAppComponents(SupportedTransports type);
    
        <T> T getAppComponents(Class<T> serviceType);
    
        String getImplementedCapability();  (1)
    
        List<Object> getServices();
    
        String getExtensionName();  (2)
    
        Integer getStartOrder();  (3)
    }
    1 Specifies the capability that is covered by this extension. The capability must be unique within KIE Server.
    2 Defines a human-readable name for the extension.
    3 Determines when the specified extension should be started. For extensions that have dependencies on other extensions, this setting must not conflict with the parent setting. For example, in this case, this custom extension depends on the Drools extension, which has StartOrder set to 0, so this custom add-on extension must be greater than 0 (set to 20 in the sample implementation).

    In the previous MinaDroolsKieServerExtension sample implementation of this interface, the init method is the main element for collecting services from the Drools extension and for bootstrapping the MINA server. All other methods in the KieServerExtension interface can remain with the standard implementation to fulfill interface requirements.

    The TextBasedIoHandlerAdapter class is the handler on the MINA server that reacts to incoming requests.

  3. Implement the TextBasedIoHandlerAdapter handler for the MINA server, as shown in the following example:

    Sample implementation of the TextBasedIoHandlerAdapter handler
    public class TextBasedIoHandlerAdapter extends IoHandlerAdapter {
    
        private static final Logger logger = LoggerFactory.getLogger(TextBasedIoHandlerAdapter.class);
    
        private KieContainerCommandService batchCommandService;
    
        public TextBasedIoHandlerAdapter(KieContainerCommandService batchCommandService) {
            this.batchCommandService = batchCommandService;
        }
    
        @Override
        public void messageReceived( IoSession session, Object message ) throws Exception {
            String completeMessage = message.toString();
            logger.debug("Received message '{}'", completeMessage);
            if( completeMessage.trim().equalsIgnoreCase("quit") || completeMessage.trim().equalsIgnoreCase("exit") ) {
                session.close(false);
                return;
            }
    
            String[] elements = completeMessage.split("\\|");
            logger.debug("Container id {}", elements[0]);
            try {
                ServiceResponse<String> result = batchCommandService.callContainer(elements[0], elements[1], MarshallingFormat.JSON, null);
    
                if (result.getType().equals(ServiceResponse.ResponseType.SUCCESS)) {
                    session.write(result.getResult());
                    logger.debug("Successful message written with content '{}'", result.getResult());
                } else {
                    session.write(result.getMsg());
                    logger.debug("Failure message written with content '{}'", result.getMsg());
                }
            } catch (Exception e) {
    
            }
        }
    }

    In this example, the handler class receives text messages and executes them in the Drools service.

    Consider the following handler requirements and behavior when you use the TextBasedIoHandlerAdapter handler implementation:

    • Anything that you submit to the handler must be a single line because each incoming transport request is a single line.

    • You must pass a KIE container ID in this single line so that the handler expects the format containerID|payload.

    • You can set a response in the way that it is produced by the marshaller. The response can be multiple lines.

    • The handler supports a stream mode that enables you to send commands without disconnecting from a KIE Server session. To end a KIE Server session in stream mode, send either an exit or quit command to the server.

  4. To make the new data transport discoverable for KIE Server, create a META-INF/services/org.kie.server.services.api.KieServerExtension file in your Maven project and add the fully qualified class name of the KieServerExtension implementation class within the file. For this example, the file contains the single line org.kie.server.ext.mina.MinaDroolsKieServerExtension.

  5. Build your project and copy the resulting JAR file and the mina-core-2.0.9.jar file (which the extension depends on in this example) into the ~/kie-server.war/WEB-INF/lib directory of your project.

  6. Start the KIE Server and deploy the built project to the running KIE Server. You can deploy the project using either the Business Central interface or the KIE Server REST API (a PUT request to http://SERVER:PORT/kie-server/services/rest/server/containers/{containerId}).

    After your project is deployed on a running KIE Server, you can view the status of the new data transport in your KIE Server log and start using your new data transport:

    New data transport in the server log
    Drools-Mina KIE Server extension -- Mina server started at localhost and port 9123
    Drools-Mina KIE Server extension has been successfully registered as server extension

    For this example, you can use Telnet to interact with the new MINA-based data transport in KIE Server:

    Starting Telnet and connecting to KIE Server on port 9123 in a command terminal
    telnet 127.0.0.1 9123
    Example interactions with KIE Server in a command terminal
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    
    # Request body:
    demo|{"lookup":"defaultKieSession","commands":[{"insert":{"object":{"org.jbpm.test.Person":{"name":"john","age":25}}}},{"fire-all-rules":""}]}
    
    # Server response:
    {
      "results" : [ {
        "key" : "",
        "value" : 1
      } ],
      "facts" : [ ]
    }
    
    demo|{"lookup":"defaultKieSession","commands":[{"insert":{"object":{"org.jbpm.test.Person":{"name":"mary","age":22}}}},{"fire-all-rules":""}]}
    {
      "results" : [ {
        "key" : "",
        "value" : 1
      } ],
      "facts" : [ ]
    }
    
    demo|{"lookup":"defaultKieSession","commands":[{"insert":{"object":{"org.jbpm.test.Person":{"name":"james","age":25}}}},{"fire-all-rules":""}]}
    {
      "results" : [ {
        "key" : "",
        "value" : 1
      } ],
      "facts" : [ ]
    }
    exit
    Connection closed by foreign host.
    Example server log output
    16:33:40,206 INFO  [stdout] (NioProcessor-2) Hello john
    16:34:03,877 INFO  [stdout] (NioProcessor-2) Hello mary
    16:34:19,800 INFO  [stdout] (NioProcessor-2) Hello james

7.4.3. Extending the KIE Server client with a custom client API

KIE Server uses predefined client APIs that you can interact with to use KIE Server services. You can extend the KIE Server client with a custom client API to adapt KIE Server services to your business needs.

As an example, this procedure adds a custom client API to KIE Server to accommodate a custom data transport (configured previously for this scenario) that is based on Apache MINA, an open-source Java network-application framework.

Procedure
  1. Create an empty Maven project and define the following packaging type and dependencies in the pom.xml file for the project:

    Example pom.xml file in the sample project
    <packaging>jar</packaging>
    
    <properties>
       <version.org.kie>7.43.0.Final</version.org.kie>
     </properties>
    
     <dependencies>
       <dependency>
         <groupId>org.kie.server</groupId>
         <artifactId>kie-server-api</artifactId>
         <version>${version.org.kie}</version>
       </dependency>
       <dependency>
          <groupId>org.kie.server</groupId>
          <artifactId>kie-server-client</artifactId>
          <version>${version.org.kie}</version>
        </dependency>
       <dependency>
         <groupId>org.drools</groupId>
         <artifactId>drools-compiler</artifactId>
         <version>${version.org.kie}</version>
       </dependency>
     </dependencies>
  2. Implement the relevant ServicesClient interface in a Java class in your project, as shown in the following example:

    Sample RulesMinaServicesClient interface
    public interface RulesMinaServicesClient extends RuleServicesClient {
    
    }

    A specific interface is required because you must register client implementations based on the interface, and you can have only one implementation for a given interface.

    For this example, the custom MINA-based data transport uses the Drools extension, so this example RulesMinaServicesClient interface extends the existing RuleServicesClient client API from the Drools extension.

  3. Implement the RulesMinaServicesClient interface that the KIE Server can use to provide the additional client functionality for the new MINA transport, as shown in the following example:

    Sample implementation of the RulesMinaServicesClient interface
    public class RulesMinaServicesClientImpl implements RulesMinaServicesClient {
    
        private String host;
        private Integer port;
    
        private Marshaller marshaller;
    
        public RulesMinaServicesClientImpl(KieServicesConfiguration configuration, ClassLoader classloader) {
            String[] serverDetails = configuration.getServerUrl().split(":");
    
            this.host = serverDetails[0];
            this.port = Integer.parseInt(serverDetails[1]);
    
            this.marshaller = MarshallerFactory.getMarshaller(configuration.getExtraJaxbClasses(), MarshallingFormat.JSON, classloader);
        }
    
        public ServiceResponse<String> executeCommands(String id, String payload) {
    
            try {
                String response = sendReceive(id, payload);
                if (response.startsWith("{")) {
                    return new ServiceResponse<String>(ResponseType.SUCCESS, null, response);
                } else {
                    return new ServiceResponse<String>(ResponseType.FAILURE, response);
                }
            } catch (Exception e) {
                throw new KieServicesException("Unable to send request to KIE Server", e);
            }
        }
    
        public ServiceResponse<String> executeCommands(String id, Command<?> cmd) {
            try {
                String response = sendReceive(id, marshaller.marshall(cmd));
                if (response.startsWith("{")) {
                    return new ServiceResponse<String>(ResponseType.SUCCESS, null, response);
                } else {
                    return new ServiceResponse<String>(ResponseType.FAILURE, response);
                }
            } catch (Exception e) {
                throw new KieServicesException("Unable to send request to KIE Server", e);
            }
        }
    
        protected String sendReceive(String containerId, String content) throws Exception {
    
            // Flatten the content to be single line:
            content = content.replaceAll("\\n", "");
    
            Socket minaSocket = null;
            PrintWriter out = null;
            BufferedReader in = null;
    
            StringBuffer data = new StringBuffer();
            try {
                minaSocket = new Socket(host, port);
                out = new PrintWriter(minaSocket.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(minaSocket.getInputStream()));
    
                // Prepare and send data:
                out.println(containerId + "|" + content);
                // Wait for the first line:
                data.append(in.readLine());
                // Continue as long as data is available:
                while (in.ready()) {
                    data.append(in.readLine());
                }
    
                return data.toString();
            } finally {
                out.close();
                in.close();
                minaSocket.close();
            }
        }
    }

    This example implementation specifies the following data and behavior:

    • Uses socket-based communication for simplicity

    • Relies on default configurations from the KIE Server client and uses ServerUrl for providing the host and port of the MINA server

    • Specifies JSON as the marshalling format

    • Requires received messages to be JSON objects that start with an open bracket {

    • Uses direct socket communication with a blocking API while waiting for the first line of the response and then reads all lines that are available

    • Does not use stream mode and therefore disconnects the KIE Server session after invoking a command

  4. Implement the org.kie.server.client.helper.KieServicesClientBuilder interface in a Java class in your project, as shown in the following example:

    Sample implementation of the KieServicesClientBuilder interface
    public class MinaClientBuilderImpl implements KieServicesClientBuilder {  (1)
    
        public String getImplementedCapability() {  (2)
            return "BRM-Mina";
        }
    
        public Map<Class<?>, Object> build(KieServicesConfiguration configuration, ClassLoader classLoader) {  (3)
            Map<Class<?>, Object> services = new HashMap<Class<?>, Object>();
    
            services.put(RulesMinaServicesClient.class, new RulesMinaServicesClientImpl(configuration, classLoader));
    
            return services;
        }
    
    }
    1 Enables you to provide additional client APIs to the generic KIE Server client infrastructure
    2 Defines the KIE Server capability (extension) that the client uses
    3 Provides a map of the client implementations, where the key is the interface and the value is the fully initialized implementation
  5. To make the new client API discoverable for the KIE Server client, create a META-INF/services/org.kie.server.client.helper.KieServicesClientBuilder file in your Maven project and add the fully qualified class name of the KieServicesClientBuilder implementation class within the file. For this example, the file contains the single line org.kie.server.ext.mina.client.MinaClientBuilderImpl.

  6. Build your project and copy the resulting JAR file into the ~/kie-server.war/WEB-INF/lib directory of your project.

  7. Start the KIE Server and deploy the built project to the running KIE Server. You can deploy the project using either the Business Central interface or the KIE Server REST API (a PUT request to http://SERVER:PORT/kie-server/services/rest/server/containers/{containerId}).

    After your project is deployed on a running KIE Server, you can start interacting with your new KIE Server client. You use your new client in the same way as the standard KIE Server client, by creating the client configuration and client instance, retrieving the service client by type, and invoking client methods.

    For this example, you can create a RulesMinaServiceClient client instance and invoke operations on KIE Server through the MINA transport:

    Sample implementation to create the RulesMinaServiceClient client
    protected RulesMinaServicesClient buildClient() {
        KieServicesConfiguration configuration = KieServicesFactory.newRestConfiguration("localhost:9123", null, null);
        List<String> capabilities = new ArrayList<String>();
        // Explicitly add capabilities (the MINA client does not respond to `get-server-info` requests):
        capabilities.add("BRM-Mina");
    
        configuration.setCapabilities(capabilities);
        configuration.setMarshallingFormat(MarshallingFormat.JSON);
    
        configuration.addJaxbClasses(extraClasses);
    
        KieServicesClient kieServicesClient =  KieServicesFactory.newKieServicesClient(configuration);
    
        RulesMinaServicesClient rulesClient = kieServicesClient.getServicesClient(RulesMinaServicesClient.class);
    
        return rulesClient;
    }
    Sample configuration to invoke operations on KIE Server through the MINA transport
    RulesMinaServicesClient rulesClient = buildClient();
    
    List<Command<?>> commands = new ArrayList<Command<?>>();
    BatchExecutionCommand executionCommand = commandsFactory.newBatchExecution(commands, "defaultKieSession");
    
    Person person = new Person();
    person.setName("mary");
    commands.add(commandsFactory.newInsert(person, "person"));
    commands.add(commandsFactory.newFireAllRules("fired"));
    
    ServiceResponse<String> response = rulesClient.executeCommands(containerId, executionCommand);
    Assert.assertNotNull(response);
    
    Assert.assertEquals(ResponseType.SUCCESS, response.getType());
    
    String data = response.getResult();
    
    Marshaller marshaller = MarshallerFactory.getMarshaller(extraClasses, MarshallingFormat.JSON, this.getClass().getClassLoader());
    
    ExecutionResultImpl results = marshaller.unmarshall(data, ExecutionResultImpl.class);
    Assert.assertNotNull(results);
    
    Object personResult = results.getValue("person");
    Assert.assertTrue(personResult instanceof Person);
    
    Assert.assertEquals("mary", ((Person) personResult).getName());
    Assert.assertEquals("JBoss Community", ((Person) personResult).getAddress());
    Assert.assertEquals(true, ((Person) personResult).isRegistered());

7.5. Kie Server setup

Server setup and registration changed significantly from versions 6.2 and before. The following applies only to version 6.3 and forward.

7.5.1. Managed Kie Server

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

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

It’s important to mention that even though there can be multiple KIE Server controllers they should be kept in sync to make sure that regardless which one of them is contacted by KIE Server instance it will provide same set of configuration.

At startup, if a Kie Server is configured with a list of KIE Server controllers, it will try successively to connect to each of them until a connection is successfully established with one of them. If for any reason a connection can’t be established, 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.

In order to run the Kie Server in standalone mode, without connecting to any KIE Server controllers, please see "Unmanaged Kie Server".

The configuration sets, among other things:

  • kie containers to be deployed and started

  • configuration items - currently this is a placeholder for further enhancements that will allow remotely configure KIE Execution Server components - timers, persistence, etc

The KIE Server 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 KIE Server controller itself that is exposed to interact with KIE Execution Server instances

  • an administration API that allows to remotely manage Kie Server instances:

    • add/remove servers

    • add/remove containers to/from the servers

    • start/stop containers on servers

The KIE Server 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 KIE Server controller. The KIE Server controller is responsible for persisting the configuration to preserve restarts of the KIE Server controller itself. It should manage the synchronization as well in case multiple KIE Server controllers are configured to keep all definitions up to date on all instances of the KIE Server controller.

By default KIE Server controller is shipped with Business Central 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 KIE Server controllers synchronization as well.

kie server simple architecture

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

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

kie server architecture

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

7.5.1.1. Working with managed servers

There are two approaches that users can take when working with managed KIE Server instances:

  • Configuration first: with this approach, a user will start working with the KIE Server controller (either UI or REST api) and create and configure Kie Server definitions. That consists basically of an identification for the server definition (id and name + optionally version for improved readability) and the configuration for the Kie Containers to run on the server.

  • Registration first: with this approach, the Kie Server instances are started first and auto register themselves on KIE Server controller. The user then can configure the Kie Containers. This option simply skips the registration step done in the first approach and populates it with server id, name and version directly upon auto registration. There are no other differences between the two approaches.

7.5.2. Unmanaged KIE Execution Server

An unmanaged Kie Server is in turn just a standalone instance, and thus must be configured individually using REST/JMS api from the Kie Server itself. There is no KIE Server controller involved. The configuration is automatically persisted by the server into a file and that is used as the internal server state, in case of restarts.

The configuration is updated during the following operations:

  • deploy Kie Container

  • undeploy Kie Container

  • start Kie Container

  • stop Kie Container

If the Kie Server is restarted, it will try to establish the same state that was persisted before shutdown. That means that Kie Containers that were running, will be started, but the ones that were stopped/disposed before, will not.

In most use cases, the Kie Server should be executed in managed mode as that provides some benefits, like a web user interface (if using Business Central as a KIE Server controller) and some facilities for clustering.

7.6. Creating a Kie Container

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.

  1. Start by clicking the \+ icon next to the Execution Server where you want to deploy your Container. This will bring up the New Container screen.

  2. If you know the Group Name, Artifact Id and Version (GAV) of your deployed package, then you can enter those details and click the Ok button to select that instance (and provide a name for the Container);

  3. If you don’t know these values, you can search Business Central for all packages that can be deployed. Click the Search button without entering any value in the search field (you can narrow your search by entering any term that you know exists in the package that you want to deploy).

    INSERT SCREENSHOT HERE

    The figure above shows that there are three deployable packages available to be used as containers on the Execution Server. Select the one that you want by clicking the Select button. This will auto-populate the GAV and you can then click the Ok button to use this deployable as the new Container.

  4. Enter a name for this Container at the top and then press the Ok button.

    The Container name must be unique inside each execution server and must not contain any spaces.

Just below the GAV row, you will see an uneditable row that shows you the URL for your Container against which you will be able to execute REST commands.

7.7. Managing Containers

Containers within the Execution Server can be started, stopped and updated from within Business Central.⁠

7.7.1. Starting a Container

Once registered, a Container is in the 'Stopped' mode. It can be started by first selecting it and then clicking the Start button. You can also select multiple Containers and start them all at the same time.

Once the Container is in the 'Running' mode, a green arrow appears next to it. If there are any errors starting the Container(s), red icons appear next to Containers and the Execution Server that they are deployed on.

You should check the logs of both the Execution Server and the current Business Central to see what the errors are before redeploying the Containers (and possibly the Execution Server).⁠

7.7.2. Stopping and Deleting a Container

Similar to starting a Container, select the Container(s) that you want to stop (or delete) and click the Stop button (which replaces the Start button for that Container once it has entered the 'Running' mode) or the Delete button.⁠

7.7.3. Updating a Container

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 the icon next to the Container. This will open up the Container Info screen. An example of this screen is shown here:

INSERT SCREENSHOT 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 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 milliseconds).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.

7.8. KIE Server REST API for KIE containers and business assets

OptaPlanner provides a KIE Server REST API that you can use to interact with your KIE containers and business assets (such as business rules, processes, and solvers) in OptaPlanner without using the Business Central user interface. This API support enables you to maintain your OptaPlanner resources more efficiently and optimize your integration and development with OptaPlanner.

With the KIE Server REST API, you can perform the following actions:

  • Deploy or dispose KIE containers

  • Retrieve and update KIE container information

  • Return KIE Server status and basic information

  • Retrieve and update business asset information

  • Execute business assets (such as rules and processes)

KIE Server REST API requests require the following components:

Authentication

The KIE Server REST API requires HTTP Basic authentication or token-based authentication for the user role kie-server. To view configured user roles for your OptaPlanner distribution, navigate to ~/$SERVER_HOME/standalone/configuration/application-roles.properties and ~/application-users.properties.

To add a user with the kie-server role, navigate to ~/$SERVER_HOME/bin and run the following command:

$ ./add-user.sh -a --user <USERNAME> --password <PASSWORD> --role kie-server

For more information about user roles and OptaPlanner installation options, see

HTTP headers

The KIE Server REST API requires the following HTTP headers for API requests:

  • Accept: Data format accepted by your requesting client:

    • application/json (JSON)

    • application/xml (XML, for JAXB or XSTREAM)

  • Content-Type: Data format of your POST or PUT API request data:

    • application/json (JSON)

    • application/xml (XML, for JAXB or XSTREAM)

  • X-KIE-ContentType: Required header for application/xml XSTREAM API requests and responses:

    • XSTREAM

HTTP methods

The KIE Server REST API supports the following HTTP methods for API requests:

  • GET: Retrieves specified information from a specified resource endpoint

  • POST: Updates a resource or resource instance

  • PUT: Updates or creates a resource or resource instance

  • DELETE: Deletes a resource or resource instance

Base URL

The base URL for KIE Server REST API requests is http://SERVER:PORT/kie-server/services/rest/, such as http://localhost:8080/kie-server/services/rest/.

Endpoints

KIE Server REST API endpoints, such as /server/containers/{containerId} for a specified KIE container, are the URIs that you append to the KIE Server REST API base URL to access the corresponding resource or type of resource in OptaPlanner.

Example request URL for /server/containers/{containerId} endpoint

http://localhost:8080/kie-server/services/rest/server/containers/MyContainer

Request parameters and request data

Many KIE Server REST API requests require specific parameters in the request URL path to identify or filter specific resources and to perform specific actions. You can append URL parameters to the endpoint in the format ?<PARAM>=<VALUE>&<PARAM>=<VALUE>.

Example GET request URL with parameters

http://localhost:8080/kie-server/services/rest/server/containers?groupId=com.redhat&artifactId=Project1&version=1.0&status=STARTED

HTTP POST and PUT requests may additionally require a request body or file with data to accompany the request.

Example POST request URL and JSON request body data

http://localhost:8080/kie-server/services/rest/server/containers/MyContainer/release-id

{
  "release-id": {
    "artifact-id": "Project1",
    "group-id": "com.redhat",
    "version": "1.1"
  }
}

7.8.1. Sending requests with the KIE Server REST API using a REST client or curl utility

The KIE Server REST API enables you to interact with your KIE containers and business assets (such as business rules, processes, and solvers) in OptaPlanner without using the Business Central user interface. You can send KIE Server REST API requests using any REST client or curl utility.

Prerequisites
  • KIE Server is installed and running.

  • You have kie-server user role access to KIE Server.

Procedure
  1. Identify the relevant API endpoint to which you want to send a request, such as [GET] /server/containers to retrieve KIE containers from KIE Server.

  2. In a REST client or curl utility, enter the following components for a GET request to /server/containers. Adjust any request details according to your use case.

    For REST client:

    • Authentication: Enter the user name and password of the KIE Server user with the kie-server role.

    • HTTP Headers: Set the following header:

      • Accept: application/json

    • HTTP method: Set to GET.

    • URL: Enter the KIE Server REST API base URL and endpoint, such as http://localhost:8080/kie-server/services/rest/server/containers.

    For curl utility:

    • -u: Enter the user name and password of the KIE Server user with the kie-server role.

    • -H: Set the following header:

      • accept: application/json

    • -X: Set to GET.

    • URL: Enter the KIE Server REST API base URL and endpoint, such as http://localhost:8080/kie-server/services/rest/server/containers.

    curl -u 'baAdmin:password@1' -H "accept: application/json" -X GET "http://localhost:8080/kie-server/services/rest/server/containers"
  3. Execute the request and review the KIE Server response.

    Example server response (JSON):

    {
      "type": "SUCCESS",
      "msg": "List of created containers",
      "result": {
        "kie-containers": {
          "kie-container": [
            {
              "container-id": "itorders_1.0.0-SNAPSHOT",
              "release-id": {
                "group-id": "itorders",
                "artifact-id": "itorders",
                "version": "1.0.0-SNAPSHOT"
              },
              "resolved-release-id": {
                "group-id": "itorders",
                "artifact-id": "itorders",
                "version": "1.0.0-SNAPSHOT"
              },
              "status": "STARTED",
              "scanner": {
                "status": "DISPOSED",
                "poll-interval": null
              },
              "config-items": [],
              "container-alias": "itorders"
            }
          ]
        }
      }
    }
  4. For this example, copy or note the project group-id, artifact-id, and version (GAV) data from one of the deployed KIE containers returned in the response.

  5. In your REST client or curl utility, send another API request with the following components for a PUT request to /server/containers/{containerId} to deploy a new KIE container with the copied project GAV data. Adjust any request details according to your use case.

    For REST client:

    • Authentication: Enter the user name and password of the KIE Server user with the kie-server role.

    • HTTP Headers: Set the following headers:

      • Accept: application/json

      • Content-Type: application/json

    • HTTP method: Set to PUT.

    • URL: Enter the KIE Server REST API base URL and endpoint, such as http://localhost:8080/kie-server/services/rest/server/containers/MyContainer.

    • Request body: Add a JSON request body with the configuration items for the new KIE container:

    {
      "config-items": [
        {
          "itemName": "RuntimeStrategy",
          "itemValue": "SINGLETON",
          "itemType": "java.lang.String"
        },
        {
          "itemName": "MergeMode",
          "itemValue": "MERGE_COLLECTIONS",
          "itemType": "java.lang.String"
        },
        {
          "itemName": "KBase",
          "itemValue": "",
          "itemType": "java.lang.String"
        },
        {
          "itemName": "KSession",
          "itemValue": "",
          "itemType": "java.lang.String"
        }
      ],
      "release-id": {
        "group-id": "itorders",
        "artifact-id": "itorders",
        "version": "1.0.0-SNAPSHOT"
      },
      "scanner": {
        "poll-interval": "5000",
        "status": "STARTED"
      }
    }

    For curl utility:

    • -u: Enter the user name and password of the KIE Server user with the kie-server role.

    • -H: Set the following headers:

      • accept: application/json

      • content-type: application/json

    • -X: Set to PUT.

    • URL: Enter the KIE Server REST API base URL and endpoint, such as http://localhost:8080/kie-server/services/rest/server/containers/MyContainer.

    • -d: Add a JSON request body or file (@file.json) with the configuration items for the new KIE container:

    curl -u 'baAdmin:password@1' -H "accept: application/json" -H "content-type: application/json" -X PUT "http://localhost:8080/kie-server/services/rest/server/containers/MyContainer" -d "{ \"config-items\": [ { \"itemName\": \"RuntimeStrategy\", \"itemValue\": \"SINGLETON\", \"itemType\": \"java.lang.String\" }, { \"itemName\": \"MergeMode\", \"itemValue\": \"MERGE_COLLECTIONS\", \"itemType\": \"java.lang.String\" }, { \"itemName\": \"KBase\", \"itemValue\": \"\", \"itemType\": \"java.lang.String\" }, { \"itemName\": \"KSession\", \"itemValue\": \"\", \"itemType\": \"java.lang.String\" } ], \"release-id\": { \"group-id\": \"itorders\", \"artifact-id\": \"itorders\", \"version\": \"1.0.0-SNAPSHOT\" }, \"scanner\": { \"poll-interval\": \"5000\", \"status\": \"STARTED\" }}"
    curl -u 'baAdmin:password@1' -H "accept: application/json" -H "content-type: application/json" -X PUT "http://localhost:8080/kie-server/services/rest/server/containers/MyContainer" -d @my-container-configs.json
  6. Execute the request and review the KIE Server response.

    Example server response (JSON):

    {
      "type": "SUCCESS",
      "msg": "Container MyContainer successfully deployed with module itorders:itorders:1.0.0-SNAPSHOT.",
      "result": {
        "kie-container": {
          "container-id": "MyContainer",
          "release-id": {
            "group-id": "itorders",
            "artifact-id": "itorders",
            "version": "1.0.0-SNAPSHOT"
          },
          "resolved-release-id": {
            "group-id": "itorders",
            "artifact-id": "itorders",
            "version": "1.0.0-SNAPSHOT"
          },
          "status": "STARTED",
          "scanner": {
            "status": "STARTED",
            "poll-interval": 5000
          },
          "config-items": [],
          "messages": [
            {
              "severity": "INFO",
              "timestamp": {
                "java.util.Date": 1540584717937
              },
              "content": [
                "Container MyContainer successfully created with module itorders:itorders:1.0.0-SNAPSHOT."
              ]
            }
          ],
          "container-alias": null
        }
      }
    }

    If you encounter request errors, review the returned error code messages and adjust your request accordingly.

7.8.2. Sending requests with the KIE Server REST API using the Swagger interface

The KIE Server REST API supports a Swagger web interface that you can use instead of a standalone REST client or curl utility to interact with your KIE containers and business assets (such as business rules, processes, and solvers) in OptaPlanner without using the Business Central user interface.

By default, the Swagger web interface for KIE Server is enabled by the org.kie.swagger.server.ext.disabled=false system property. To disable the Swagger web interface in KIE Server, set this system property to true.
Prerequisites
  • KIE Server is installed and running.

  • You have kie-server user role access to KIE Server.

Procedure
  1. In a web browser, navigate to http://SERVER:PORT/kie-server/docs, such as http://localhost:8080/kie-server/docs, and log in with the user name and password of the KIE Server user with the kie-server role.

  2. In the Swagger page, select the relevant API endpoint to which you want to send a request, such as KIE Server and KIE containers[GET] /server/containers to retrieve KIE containers from KIE Server.

  3. Click Try it out and provide any optional parameters by which you want to filter results, if needed.

  4. In the Response content type drop-down menu, select the desired format of the server response, such as application/json for JSON format.

  5. Click Execute and review the KIE Server response.

    Example server response (JSON):

    {
      "type": "SUCCESS",
      "msg": "List of created containers",
      "result": {
        "kie-containers": {
          "kie-container": [
            {
              "container-id": "itorders_1.0.0-SNAPSHOT",
              "release-id": {
                "group-id": "itorders",
                "artifact-id": "itorders",
                "version": "1.0.0-SNAPSHOT"
              },
              "resolved-release-id": {
                "group-id": "itorders",
                "artifact-id": "itorders",
                "version": "1.0.0-SNAPSHOT"
              },
              "status": "STARTED",
              "scanner": {
                "status": "DISPOSED",
                "poll-interval": null
              },
              "config-items": [],
              "container-alias": "itorders"
            }
          ]
        }
      }
    }
  6. For this example, copy or note the project group-id, artifact-id, and version (GAV) data from one of the deployed KIE containers returned in the response.

  7. In the Swagger page, navigate to the KIE Server and KIE containers[PUT] /server/containers/{containerId} endpoint to send another request to deploy a new KIE container with the copied project GAV data. Adjust any request details according to your use case.

  8. Click Try it out and enter the following components for the request:

    • containerId: Enter the ID of the new KIE container, such as MyContainer.

    • body: Set the Parameter content type to the desired request body format, such as application/json for JSON format, and add a request body with the configuration items for the new KIE container:

    {
      "config-items": [
        {
          "itemName": "RuntimeStrategy",
          "itemValue": "SINGLETON",
          "itemType": "java.lang.String"
        },
        {
          "itemName": "MergeMode",
          "itemValue": "MERGE_COLLECTIONS",
          "itemType": "java.lang.String"
        },
        {
          "itemName": "KBase",
          "itemValue": "",
          "itemType": "java.lang.String"
        },
        {
          "itemName": "KSession",
          "itemValue": "",
          "itemType": "java.lang.String"
        }
      ],
      "release-id": {
        "group-id": "itorders",
        "artifact-id": "itorders",
        "version": "1.0.0-SNAPSHOT"
      },
      "scanner": {
        "poll-interval": "5000",
        "status": "STARTED"
      }
    }
  9. In the Response content type drop-down menu, select the desired format of the server response, such as application/json for JSON format.

  10. Click Execute and review the KIE Server response.

    Example server response (JSON):

    {
      "type": "SUCCESS",
      "msg": "Container MyContainer successfully deployed with module itorders:itorders:1.0.0-SNAPSHOT.",
      "result": {
        "kie-container": {
          "container-id": "MyContainer",
          "release-id": {
            "group-id": "itorders",
            "artifact-id": "itorders",
            "version": "1.0.0-SNAPSHOT"
          },
          "resolved-release-id": {
            "group-id": "itorders",
            "artifact-id": "itorders",
            "version": "1.0.0-SNAPSHOT"
          },
          "status": "STARTED",
          "scanner": {
            "status": "STARTED",
            "poll-interval": 5000
          },
          "config-items": [],
          "messages": [
            {
              "severity": "INFO",
              "timestamp": {
                "java.util.Date": 1540584717937
              },
              "content": [
                "Container MyContainer successfully created with module itorders:itorders:1.0.0-SNAPSHOT."
              ]
            }
          ],
          "container-alias": null
        }
      }
    }

    If you encounter request errors, review the returned error code messages and adjust your request accordingly.

7.8.3. Supported KIE Server REST API endpoints

The KIE Server REST API provides endpoints for the following types of resources in OptaPlanner:

  • KIE Server and KIE containers

  • KIE session assets (for runtime commands)

  • DMN assets

  • Planning solvers

The KIE Server REST API base URL is http://SERVER:PORT/kie-server/services/rest/. All requests require HTTP Basic authentication or token-based authentication for the kie-server user role.

For the full list of KIE Server REST API endpoints and descriptions, use one of the following resources:

  • Execution Server REST API on the jBPM Documentation page (static)

  • Swagger UI for the KIE Server REST API at http://SERVER:PORT/kie-server/docs (dynamic, requires running KIE Server)

    By default, the Swagger web interface for KIE Server is enabled by the org.kie.swagger.server.ext.disabled=false system property. To disable the Swagger web interface in KIE Server, set this system property to true.

7.9. KIE Server Java client API for KIE containers and business assets

OptaPlanner provides a KIE Server Java client API that enables you to connect to KIE Server using REST protocol from your Java client application. You can use the KIE Server Java client API as an alternative to the KIE Server REST API to interact with your KIE containers and business assets (such as business rules, processes, and solvers) in OptaPlanner without using the Business Central user interface. This API support enables you to maintain your OptaPlanner resources more efficiently and optimize your integration and development with OptaPlanner.

With the KIE Server Java client API, you can perform the following actions also supported by the KIE Server REST API:

  • Deploy or dispose KIE containers

  • Retrieve and update KIE container information

  • Return KIE Server status and basic information

  • Retrieve and update business asset information

  • Execute business assets (such as rules and processes)

KIE Server Java client API requests require the following components:

Authentication

The KIE Server Java client API requires HTTP Basic authentication for the user role kie-server. To view configured user roles for your OptaPlanner distribution, navigate to ~/$SERVER_HOME/standalone/configuration/application-roles.properties and ~/application-users.properties.

To add a user with the kie-server role, navigate to ~/$SERVER_HOME/bin and run the following command:

$ ./add-user.sh -a --user <USERNAME> --password <PASSWORD> --role kie-server

For more information about user roles and OptaPlanner installation options, see

Project dependencies

The KIE Server Java client API requires the following dependencies on the relevant classpath of your Java project:

<!-- For remote execution on KIE Server -->
<dependency>
  <groupId>org.kie.server</groupId>
  <artifactId>kie-server-client</artifactId>
  <version>${optaplanner.version}</version>
</dependency>

<!-- For runtime commands -->
<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-compiler</artifactId>
  <scope>runtime</scope>
  <version>${optaplanner.version}</version>
</dependency>

<!-- For debug logging (optional) -->
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>${logback.version}</version>
</dependency>

The <version> for OptaPlanner dependencies is the Maven artifact version for OptaPlanner currently used in your project (for example, 7.43.0.Final).

Client request configuration

All Java client requests with the KIE Server Java client API must define at least the following server communication components:

  • Credentials of the kie-server user

  • KIE Server location, such as http://localhost:8080/kie-server/services/rest/server

  • Marshalling format for API requests and responses (JSON, JAXB, or XSTREAM)

  • A KieServicesConfiguration object and a KieServicesClient object, which serve as the entry point for starting the server communication using the Java client API

  • A KieServicesFactory object defining REST protocol and user access

  • Any other client services used, such as RuleServicesClient, ProcessServicesClient, or QueryServicesClient

The following are examples of basic and advanced client configurations with these components:

Basic client configuration example
import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.client.KieServicesClient;
import org.kie.server.client.KieServicesConfiguration;
import org.kie.server.client.KieServicesFactory;

public class MyConfigurationObject {

  private static final String URL = "http://localhost:8080/kie-server/services/rest/server";
  private static final String USER = "baAdmin";
  private static final String PASSWORD = "password@1";

  private static final MarshallingFormat FORMAT = MarshallingFormat.JSON;

  private static KieServicesConfiguration conf;
  private static KieServicesClient kieServicesClient;

  public static void initialize() {
    conf = KieServicesFactory.newRestConfiguration(URL, USER, PASSWORD);

    //If you use custom classes, such as Obj.class, add them to the configuration.
    Set<Class<?>> extraClassList = new HashSet<Class<?>>();
    extraClassList.add(Obj.class);
    conf.addExtraClasses(extraClassList);

    conf.setMarshallingFormat(FORMAT);
    kieServicesClient = KieServicesFactory.newKieServicesClient(conf);
  }
}
Advanced client configuration example with additional client services
import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.client.CaseServicesClient;
import org.kie.server.client.DMNServicesClient;
import org.kie.server.client.DocumentServicesClient;
import org.kie.server.client.JobServicesClient;
import org.kie.server.client.KieServicesClient;
import org.kie.server.client.KieServicesConfiguration;
import org.kie.server.client.KieServicesFactory;
import org.kie.server.client.ProcessServicesClient;
import org.kie.server.client.QueryServicesClient;
import org.kie.server.client.RuleServicesClient;
import org.kie.server.client.SolverServicesClient;
import org.kie.server.client.UIServicesClient;
import org.kie.server.client.UserTaskServicesClient;
import org.kie.server.api.model.instance.ProcessInstance;
import org.kie.server.api.model.KieContainerResource;
import org.kie.server.api.model.ReleaseId;

public class MyAdvancedConfigurationObject {

    // REST API base URL, credentials, and marshalling format
    private static final String URL = "http://localhost:8080/kie-server/services/rest/server";
    private static final String USER = "baAdmin";
    private static final String PASSWORD = "password@1";;

    private static final MarshallingFormat FORMAT = MarshallingFormat.JSON;

    private static KieServicesConfiguration conf;

    // KIE client for common operations
    private static KieServicesClient kieServicesClient;

    // Rules client
    private static RuleServicesClient ruleClient;

    // Process automation clients
    private static CaseServicesClient caseClient;
    private static DocumentServicesClient documentClient;
    private static JobServicesClient jobClient;
    private static ProcessServicesClient processClient;
    private static QueryServicesClient queryClient;
    private static UIServicesClient uiClient;
    private static UserTaskServicesClient userTaskClient;

    // DMN client
    private static DMNServicesClient dmnClient;

    // Planning client
    private static SolverServicesClient solverClient;

    public static void main(String[] args) {
        initializeKieServerClient();
        initializeDroolsServiceClients();
        initializeJbpmServiceClients();
        initializeSolverServiceClients();
    }

    public static void initializeKieServerClient() {
        conf = KieServicesFactory.newRestConfiguration(URL, USER, PASSWORD);
        conf.setMarshallingFormat(FORMAT);
        kieServicesClient = KieServicesFactory.newKieServicesClient(conf);
    }

    public static void initializeDroolsServiceClients() {
        ruleClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
        dmnClient = kieServicesClient.getServicesClient(DMNServicesClient.class);
    }

    public static void initializeJbpmServiceClients() {
        caseClient = kieServicesClient.getServicesClient(CaseServicesClient.class);
        documentClient = kieServicesClient.getServicesClient(DocumentServicesClient.class);
        jobClient = kieServicesClient.getServicesClient(JobServicesClient.class);
        processClient = kieServicesClient.getServicesClient(ProcessServicesClient.class);
        queryClient = kieServicesClient.getServicesClient(QueryServicesClient.class);
        uiClient = kieServicesClient.getServicesClient(UIServicesClient.class);
        userTaskClient = kieServicesClient.getServicesClient(UserTaskServicesClient.class);
    }

    public static void initializeSolverServiceClients() {
        solverClient = kieServicesClient.getServicesClient(SolverServicesClient.class);
    }
}

7.9.1. Sending requests with the KIE Server Java client API

The KIE Server Java client API enables you to connect to KIE Server using REST protocol from your Java client application. You can use the KIE Server Java client API as an alternative to the KIE Server REST API to interact with your KIE containers and business assets (such as business rules, processes, and solvers) in OptaPlanner without using the Business Central user interface.

Prerequisites
  • KIE Server is installed and running.

  • You have kie-server user role access to KIE Server.

  • You have a Java project with OptaPlanner resources.

Procedure
  1. In your client application, ensure that the following dependencies have been added to the relevant classpath of your Java project:

    <!-- For remote execution on KIE Server -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-client</artifactId>
      <version>${optaplanner.version}</version>
    </dependency>
    
    <!-- For runtime commands -->
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-compiler</artifactId>
      <scope>runtime</scope>
      <version>${optaplanner.version}</version>
    </dependency>
    
    <!-- For debug logging (optional) -->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>${logback.version}</version>
    </dependency>
  2. In the ~/kie/server/client folder of the Java client API in GitHub , identify the relevant Java client for the request you want to send, such as KieServicesClient to access client services for KIE containers and other assets in KIE Server.

  3. In your client application, create a .java class for the API request. The class must contain the necessary imports, KIE Server location and user credentials, a KieServicesClient object, and the client method to execute, such as createContainer and disposeContainer from the KieServicesClient client. Adjust any configuration details according to your use case.

    Creating and disposing a container
    import org.kie.server.api.marshalling.MarshallingFormat;
    import org.kie.server.client.KieServicesClient;
    import org.kie.server.client.KieServicesConfiguration;
    import org.kie.server.client.KieServicesFactory;
    import org.kie.server.api.model.KieContainerResource;
    import org.kie.server.api.model.ServiceResponse;
    
    public class MyConfigurationObject {
    
      private static final String URL = "http://localhost:8080/kie-server/services/rest/server";
      private static final String USER = "baAdmin";
      private static final String PASSWORD = "password@1";
    
      private static final MarshallingFormat FORMAT = MarshallingFormat.JSON;
    
      private static KieServicesConfiguration conf;
      private static KieServicesClient kieServicesClient;
    
      public static void initialize() {
        conf = KieServicesFactory.newRestConfiguration(URL, USER, PASSWORD);
    
      public void disposeAndCreateContainer() {
          System.out.println("== Disposing and creating containers ==");
    
          // Retrieve list of KIE containers
          List<KieContainerResource> kieContainers = kieServicesClient.listContainers().getResult().getContainers();
          if (kieContainers.size() == 0) {
              System.out.println("No containers available...");
              return;
          }
    
          // Dispose KIE container
          KieContainerResource container = kieContainers.get(0);
          String containerId = container.getContainerId();
          ServiceResponse<Void> responseDispose = kieServicesClient.disposeContainer(containerId);
          if (responseDispose.getType() == ResponseType.FAILURE) {
              System.out.println("Error disposing " + containerId + ". Message: ");
              System.out.println(responseDispose.getMsg());
              return;
          }
          System.out.println("Success Disposing container " + containerId);
          System.out.println("Trying to recreate the container...");
    
          // Re-create KIE container
          ServiceResponse<KieContainerResource> createResponse = kieServicesClient.createContainer(containerId, container);
          if(createResponse.getType() == ResponseType.FAILURE) {
              System.out.println("Error creating " + containerId + ". Message: ");
              System.out.println(responseDispose.getMsg());
              return;
          }
          System.out.println("Container recreated with success!");
          }
      }
    }

    You define service responses using the org.kie.server.api.model.ServiceResponse<T> object, where T represents the type of returned response. The ServiceResponse object has the following attributes:

    • String message: Returns the response message

    • ResponseType type: Returns either SUCCESS or FAILURE

    • T result: Returns the requested object

    In this example, when you dispose a container, the ServiceResponse returns a Void response. When you create a container, the ServiceResponse returns a KieContainerResource object.

    A conversation between a client and a specific KIE Server container in a clustered environment is secured by a unique conversationID. The conversationID is transferred using the X-KIE-ConversationId REST header. If you update the container, unset the previous conversationID. Use KieServiesClient.completeConversation() to unset the conversationID for Java API.
  4. Run the configured .java class from your project directory to execute the request, and review the KIE Server response.

    If you enabled debug logging, KIE Server responds with a detailed response according to your configured marshalling format, such as JSON.

    Example server response for a new KIE container (log):

    10:23:35.194 [main] INFO  o.k.s.a.m.MarshallerFactory - Marshaller extensions init
    10:23:35.396 [main] DEBUG o.k.s.client.balancer.LoadBalancer - Load balancer RoundRobinBalancerStrategy{availableEndpoints=[http://localhost:8080/kie-server/services/rest/server]} selected url 'http://localhost:8080/kie-server/services/rest/server'
    10:23:35.398 [main] DEBUG o.k.s.c.i.AbstractKieServicesClientImpl - About to send GET request to 'http://localhost:8080/kie-server/services/rest/server'
    10:23:35.440 [main] DEBUG o.k.s.c.i.AbstractKieServicesClientImpl - About to deserialize content:
     '{
      "type" : "SUCCESS",
      "msg" : "Kie Server info",
      "result" : {
        "kie-server-info" : {
          "id" : "default-kieserver",
          "version" : "7.11.0.Final-redhat-00003",
          "name" : "default-kieserver",
          "location" : "http://localhost:8080/kie-server/services/rest/server",
          "capabilities" : [ "KieServer", "BRM", "BPM", "CaseMgmt", "BPM-UI", "BRP", "DMN", "Swagger" ],
          "messages" : [ {
            "severity" : "INFO",
            "timestamp" : {
      "java.util.Date" : 1540814906533
    },
            "content" : [ "Server KieServerInfo{serverId='default-kieserver', version='7.11.0.Final-redhat-00003', name='default-kieserver', location='http://localhost:8080/kie-server/services/rest/server', capabilities=[KieServer, BRM, BPM, CaseMgmt, BPM-UI, BRP, DMN, Swagger], messages=null}started successfully at Mon Oct 29 08:08:26 EDT 2018" ]
          } ]
        }
      }
    }'
     into type: 'class org.kie.server.api.model.ServiceResponse'
    10:23:35.653 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - KieServicesClient connected to: default-kieserver version 7.11.0.Final-redhat-00003
    10:23:35.653 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Supported capabilities by the server: [KieServer, BRM, BPM, CaseMgmt, BPM-UI, BRP, DMN, Swagger]
    10:23:35.653 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Building services client for server capability KieServer
    10:23:35.653 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - No builder found for 'KieServer' capability
    10:23:35.654 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Building services client for server capability BRM
    10:23:35.654 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Builder 'org.kie.server.client.helper.DroolsServicesClientBuilder@6b927fb' for capability 'BRM'
    10:23:35.655 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Capability implemented by {interface org.kie.server.client.RuleServicesClient=org.kie.server.client.impl.RuleServicesClientImpl@4a94ee4}
    10:23:35.655 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Building services client for server capability BPM
    10:23:35.656 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Builder 'org.kie.server.client.helper.JBPMServicesClientBuilder@4cc451f2' for capability 'BPM'
    10:23:35.672 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Capability implemented by {interface org.kie.server.client.JobServicesClient=org.kie.server.client.impl.JobServicesClientImpl@1189dd52, interface org.kie.server.client.admin.ProcessAdminServicesClient=org.kie.server.client.admin.impl.ProcessAdminServicesClientImpl@36bc55de, interface org.kie.server.client.DocumentServicesClient=org.kie.server.client.impl.DocumentServicesClientImpl@564fabc8, interface org.kie.server.client.admin.UserTaskAdminServicesClient=org.kie.server.client.admin.impl.UserTaskAdminServicesClientImpl@16d04d3d, interface org.kie.server.client.QueryServicesClient=org.kie.server.client.impl.QueryServicesClientImpl@49ec71f8, interface org.kie.server.client.ProcessServicesClient=org.kie.server.client.impl.ProcessServicesClientImpl@1d2adfbe, interface org.kie.server.client.UserTaskServicesClient=org.kie.server.client.impl.UserTaskServicesClientImpl@36902638}
    10:23:35.672 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Building services client for server capability CaseMgmt
    10:23:35.672 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Builder 'org.kie.server.client.helper.CaseServicesClientBuilder@223d2c72' for capability 'CaseMgmt'
    10:23:35.676 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Capability implemented by {interface org.kie.server.client.admin.CaseAdminServicesClient=org.kie.server.client.admin.impl.CaseAdminServicesClientImpl@2b662a77, interface org.kie.server.client.CaseServicesClient=org.kie.server.client.impl.CaseServicesClientImpl@7f0eb4b4}
    10:23:35.676 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Building services client for server capability BPM-UI
    10:23:35.676 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Builder 'org.kie.server.client.helper.JBPMUIServicesClientBuilder@5c33f1a9' for capability 'BPM-UI'
    10:23:35.677 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Capability implemented by {interface org.kie.server.client.UIServicesClient=org.kie.server.client.impl.UIServicesClientImpl@223191a6}
    10:23:35.678 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Building services client for server capability BRP
    10:23:35.678 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Builder 'org.kie.server.client.helper.OptaplannerServicesClientBuilder@49139829' for capability 'BRP'
    10:23:35.679 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Capability implemented by {interface org.kie.server.client.SolverServicesClient=org.kie.server.client.impl.SolverServicesClientImpl@77fbd92c}
    10:23:35.679 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Building services client for server capability DMN
    10:23:35.679 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Builder 'org.kie.server.client.helper.DMNServicesClientBuilder@67c27493' for capability 'DMN'
    10:23:35.680 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Capability implemented by {interface org.kie.server.client.DMNServicesClient=org.kie.server.client.impl.DMNServicesClientImpl@35e2d654}
    10:23:35.680 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - Building services client for server capability Swagger
    10:23:35.680 [main] DEBUG o.k.s.c.impl.KieServicesClientImpl - No builder found for 'Swagger' capability
    10:23:35.681 [main] DEBUG o.k.s.client.balancer.LoadBalancer - Load balancer RoundRobinBalancerStrategy{availableEndpoints=[http://localhost:8080/kie-server/services/rest/server]} selected url 'http://localhost:8080/kie-server/services/rest/server'
    10:23:35.701 [main] DEBUG o.k.s.c.i.AbstractKieServicesClientImpl - About to send PUT request to 'http://localhost:8080/kie-server/services/rest/server/containers/employee-rostering3' with payload '{
      "container-id" : null,
      "release-id" : {
        "group-id" : "employeerostering",
        "artifact-id" : "employeerostering",
        "version" : "1.0.0-SNAPSHOT"
      },
      "resolved-release-id" : null,
      "status" : null,
      "scanner" : null,
      "config-items" : [ ],
      "messages" : [ ],
      "container-alias" : null
    }'
    10:23:38.071 [main] DEBUG o.k.s.c.i.AbstractKieServicesClientImpl - About to deserialize content:
     '{
      "type" : "SUCCESS",
      "msg" : "Container employee-rostering3 successfully deployed with module employeerostering:employeerostering:1.0.0-SNAPSHOT.",
      "result" : {
        "kie-container" : {
          "container-id" : "employee-rostering3",
          "release-id" : {
            "group-id" : "employeerostering",
            "artifact-id" : "employeerostering",
            "version" : "1.0.0-SNAPSHOT"
          },
          "resolved-release-id" : {
            "group-id" : "employeerostering",
            "artifact-id" : "employeerostering",
            "version" : "1.0.0-SNAPSHOT"
          },
          "status" : "STARTED",
          "scanner" : {
            "status" : "DISPOSED",
            "poll-interval" : null
          },
          "config-items" : [ ],
          "messages" : [ {
            "severity" : "INFO",
            "timestamp" : {
      "java.util.Date" : 1540909418069
    },
            "content" : [ "Container employee-rostering3 successfully created with module employeerostering:employeerostering:1.0.0-SNAPSHOT." ]
          } ],
          "container-alias" : null
        }
      }
    }'
     into type: 'class org.kie.server.api.model.ServiceResponse'

    If you encounter request errors, review the returned error code messages and adjust your Java configurations accordingly.

7.9.2. Supported KIE Server Java clients

The following are some of the Java client services available in the org.kie.server.client package of your OptaPlanner distribution. You can use these services to interact with related resources in KIE Server similarly to the KIE Server REST API.

  • KieServicesClient: Used as the entry point for other KIE Server Java clients, and used to interact with KIE containers

  • JobServicesClient: Used to schedule, cancel, re-queue, and get job requests

  • RuleServicesClient: Used to send commands to the server to perform rule-related operations, such as executing rules or inserting objects into the KIE session

  • SolverServicesClient: Used to perform all OptaPlanner operations, such as getting the solver state and the best solution, or disposing a solver

The getServicesClient method provides access to any of these clients:

RuleServicesClient rulesClient = kieServicesClient.getServicesClient(RuleServicesClient.class);

For the full list of available KIE Server Java clients, see the Java client API source in GitHub.

7.9.3. Example requests with the KIE Server Java client API

The following are examples of KIE Server Java client API requests for basic interactions with KIE Server. For the full list of available KIE Server Java clients, see the Java client API source in GitHub.

Listing KIE Server capabilities

You can use the org.kie.server.api.model.KieServerInfo object to identify server capabilities. The KieServicesClient client requires the server capability information to correctly produce service clients. You can specify the capabilities globally in KieServicesConfiguration; otherwise they are automatically retrieved from KIE Server.

Example request to return KIE Server capabilities
public void listCapabilities() {

  KieServerInfo serverInfo = kieServicesClient.getServerInfo().getResult();
  System.out.print("Server capabilities:");

  for (String capability : serverInfo.getCapabilities()) {
    System.out.print(" " + capability);
  }

  System.out.println();
}
Listing KIE containers in KIE Server

KIE containers are represented by the org.kie.server.api.model.KieContainerResource object. The list of resources is represented by the org.kie.server.api.model.KieContainerResourceList object.

Example request to return KIE containers from KIE Server
public void listContainers() {
    KieContainerResourceList containersList = kieServicesClient.listContainers().getResult();
    List<KieContainerResource> kieContainers = containersList.getContainers();
    System.out.println("Available containers: ");
    for (KieContainerResource container : kieContainers) {
        System.out.println("\t" + container.getContainerId() + " (" + container.getReleaseId() + ")");
    }
}

You can optionally filter the KIE container results using an instance of the org.kie.server.api.model.KieContainerResourceFilter class, which is passed to the org.kie.server.client.KieServicesClient.listContainers() method.

Example request to return KIE containers by release ID and status
public void listContainersWithFilter() {

    // Filter containers by releaseId "org.example:container:1.0.0.Final" and status FAILED
    KieContainerResourceFilter filter = new KieContainerResourceFilter.Builder()
            .releaseId("org.example", "container", "1.0.0.Final")
            .status(KieContainerStatus.FAILED)
            .build();

    // Using previously created KieServicesClient
    KieContainerResourceList containersList = kieServicesClient.listContainers(filter).getResult();
    List<KieContainerResource> kieContainers = containersList.getContainers();

    System.out.println("Available containers: ");

    for (KieContainerResource container : kieContainers) {
        System.out.println("\t" + container.getContainerId() + " (" + container.getReleaseId() + ")");
    }
}
Creating and disposing KIE containers in KIE Server

You can use the createContainer and disposeContainer methods in the KieServicesClient client to dispose and create KIE containers. In this example, when you dispose a container, the ServiceResponse returns a Void response. When you create a container, the ServiceResponse returns a KieContainerResource object.

Example request to dispose and re-create a KIE container
public void disposeAndCreateContainer() {
    System.out.println("== Disposing and creating containers ==");

    // Retrieve list of KIE containers
    List<KieContainerResource> kieContainers = kieServicesClient.listContainers().getResult().getContainers();
    if (kieContainers.size() == 0) {
        System.out.println("No containers available...");
        return;
    }

    // Dispose KIE container
    KieContainerResource container = kieContainers.get(0);
    String containerId = container.getContainerId();
    ServiceResponse<Void> responseDispose = kieServicesClient.disposeContainer(containerId);
    if (responseDispose.getType() == ResponseType.FAILURE) {
        System.out.println("Error disposing " + containerId + ". Message: ");
        System.out.println(responseDispose.getMsg());
        return;
    }
    System.out.println("Success Disposing container " + containerId);
    System.out.println("Trying to recreate the container...");

    // Re-create KIE container
    ServiceResponse<KieContainerResource> createResponse = kieServicesClient.createContainer(containerId, container);
    if(createResponse.getType() == ResponseType.FAILURE) {
        System.out.println("Error creating " + containerId + ". Message: ");
        System.out.println(responseDispose.getMsg());
        return;
    }
    System.out.println("Container recreated with success!");
}
Executing runtime commands in KIE Server

OptaPlanner supports runtime commands that you can send to KIE Server for asset-related operations, such as inserting or retracting objects in a KIE session or firing all rules. The full list of supported runtime commands is located in the org.drools.core.command.runtime package in your OptaPlanner instance.

You can use the org.kie.api.command.KieCommands class to insert commands, and use org.kie.api.KieServices.get().getCommands() to instantiate the KieCommands class. If you want to add multiple commands, use the BatchExecutionCommand wrapper.

Example request to insert an object and fire all rules
import org.kie.api.command.Command;
import org.kie.api.command.KieCommands;
import org.kie.server.api.model.ServiceResponse;
import org.kie.server.client.RuleServicesClient;
import org.kie.server.client.KieServicesClient;
import org.kie.api.KieServices;

import java.util.Arrays;

...

public void executeCommands() {

  String containerId = "hello";
  System.out.println("== Sending commands to the server ==");
  RuleServicesClient rulesClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
  KieCommands commandsFactory = KieServices.Factory.get().getCommands();

  Command<?> insert = commandsFactory.newInsert("Some String OBJ");
  Command<?> fireAllRules = commandsFactory.newFireAllRules();
  Command<?> batchCommand = commandsFactory.newBatchExecution(Arrays.asList(insert, fireAllRules));

  ServiceResponse<String> executeResponse = rulesClient.executeCommands(containerId, batchCommand);

  if(executeResponse.getType() == ResponseType.SUCCESS) {
    System.out.println("Commands executed with success! Response: ");
    System.out.println(executeResponse.getResult());
  } else {
    System.out.println("Error executing rules. Message: ");
    System.out.println(executeResponse.getMsg());
  }
}
A conversation between a client and a specific KIE Server container in a clustered environment is secured by a unique conversationID. The conversationID is transferred using the X-KIE-ConversationId REST header. If you update the container, unset the previous conversationID. Use KieServiesClient.completeConversation() to unset the conversationID for Java API.

7.10. KIE Server and KIE container commands in OptaPlanner

OptaPlanner supports server commands that you can send to KIE Server for server-related or container-related operations, such as retrieving server information or creating or deleting a container. The full list of supported KIE Server configuration commands is located in the org.kie.server.api.commands package in your OptaPlanner instance.

In the KIE Server REST API, you use the org.kie.server.api.commands commands as the request body for POST requests to http://SERVER:PORT/kie-server/services/rest/server/config. For more information about using the KIE Server REST API, see KIE Server REST API for KIE containers and business assets.

In the KIE Server Java client API, you use the corresponding method in the parent KieServicesClient Java client as an embedded API request in your Java application. All KIE Server commands are executed by methods provided in the Java client API, so you do not need to embed the actual KIE Server commands in your Java application. For more information about using the KIE Server Java client API, see KIE Server Java client API for KIE containers and business assets.

7.10.1. Sample KIE Server and KIE container commands

The following are sample KIE Server commands that you can use with the KIE Server REST API or Java client API for server-related or container-related operations in KIE Server:

  • GetServerInfoCommand

  • GetServerStateCommand

  • CreateContainerCommand

  • GetContainerInfoCommand

  • ListContainersCommand

  • CallContainerCommand

  • DisposeContainerCommand

  • GetScannerInfoCommand

  • UpdateScannerCommand

  • UpdateReleaseIdCommand

For the full list of supported KIE Server configuration and management commands, see the org.kie.server.api.commands package in your OptaPlanner instance.

You can run KIE Server commands individually or together as a batch REST API request or batch Java API request:

Batch REST API request to create, call, and dispose a KIE container (JSON)
{
  "commands": [
    {
      "create-container": {
        "container": {
          "status": "STARTED",
          "container-id": "command-script-container",
          "release-id": {
            "version": "1.0",
            "group-id": "com.redhat",
            "artifact-id": "Project1"
          }
        }
      }
    },
    {
      "call-container": {
        "payload": "{\n  \"commands\" : [ {\n    \"fire-all-rules\" : {\n      \"max\" : -1,\n      \"out-identifier\" : null\n    }\n  } ]\n}",
        "container-id": "command-script-container"
      }
    },
    {
      "dispose-container": {
        "container-id": "command-script-container"
      }
    }
  ]
}
Batch Java API request to retrieve, dispose, and re-create a KIE container
public void disposeAndCreateContainer() {
    System.out.println("== Disposing and creating containers ==");

    // Retrieve list of KIE containers
    List<KieContainerResource> kieContainers = kieServicesClient.listContainers().getResult().getContainers();
    if (kieContainers.size() == 0) {
        System.out.println("No containers available...");
        return;
    }

    // Dispose KIE container
    KieContainerResource container = kieContainers.get(0);
    String containerId = container.getContainerId();
    ServiceResponse<Void> responseDispose = kieServicesClient.disposeContainer(containerId);
    if (responseDispose.getType() == ResponseType.FAILURE) {
        System.out.println("Error disposing " + containerId + ". Message: ");
        System.out.println(responseDispose.getMsg());
        return;
    }
    System.out.println("Success Disposing container " + containerId);
    System.out.println("Trying to recreate the container...");

    // Re-create KIE container
    ServiceResponse<KieContainerResource> createResponse = kieServicesClient.createContainer(containerId, container);
    if(createResponse.getType() == ResponseType.FAILURE) {
        System.out.println("Error creating " + containerId + ". Message: ");
        System.out.println(responseDispose.getMsg());
        return;
    }
    System.out.println("Container recreated with success!");
}

Each command in this section includes a REST request body example (JSON) for the KIE Server REST API and an embedded method example from the KieServicesClient Java client for the KIE Server Java client API.

GetServerInfoCommand

Returns information about the KIE Server.

Example REST request body (JSON)
{
  "commands" : [ {
    "get-server-info" : { }
  } ]
}
Example Java client method
KieServerInfo serverInfo = kieServicesClient.getServerInfo();
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Kie Server info",
      "result": {
        "kie-server-info": {
          "id": "default-kieserver",
          "version": "7.11.0.Final-redhat-00001",
          "name": "default-kieserver",
          "location": "http://localhost:8080/kie-server/services/rest/server",
          "capabilities": [
            "KieServer",
            "BRM",
            "BPM",
            "CaseMgmt",
            "BPM-UI",
            "BRP",
            "DMN",
            "Swagger"
          ],
          "messages": [
            {
              "severity": "INFO",
              "timestamp": {
                "java.util.Date": 1538502533321
              },
              "content": [
                "Server KieServerInfo{serverId='default-kieserver', version='7.11.0.Final-redhat-00001', name='default-kieserver', location='http://localhost:8080/kie-server/services/rest/server', capabilities=[KieServer, BRM, BPM, CaseMgmt, BPM-UI, BRP, DMN, Swagger], messages=null}started successfully at Tue Oct 02 13:48:53 EDT 2018"
              ]
            }
          ]
        }
      }
    }
  ]
}
GetServerStateCommand

Returns information about the current state and configurations of the KIE Server.

Example REST request body (JSON)
{
  "commands" : [ {
    "get-server-state" : { }
  } ]
}
Example Java client method
KieServerStateInfo serverStateInfo = kieServicesClient.getServerState();
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Successfully loaded server state for server id default-kieserver",
      "result": {
        "kie-server-state-info": {
          "controller": [
            "http://localhost:8080/business-central/rest/controller"
          ],
          "config": {
            "config-items": [
              {
                "itemName": "org.kie.server.location",
                "itemValue": "http://localhost:8080/kie-server/services/rest/server",
                "itemType": "java.lang.String"
              },
              {
                "itemName": "org.kie.server.controller.user",
                "itemValue": "controllerUser",
                "itemType": "java.lang.String"
              },
              {
                "itemName": "org.kie.server.controller",
                "itemValue": "http://localhost:8080/business-central/rest/controller",
                "itemType": "java.lang.String"
              }
            ]
          },
          "containers": [
            {
              "container-id": "employee-rostering",
              "release-id": {
                "group-id": "employeerostering",
                "artifact-id": "employeerostering",
                "version": "1.0.0-SNAPSHOT"
              },
              "resolved-release-id": null,
              "status": "STARTED",
              "scanner": {
                "status": "STOPPED",
                "poll-interval": null
              },
              "config-items": [
                {
                  "itemName": "KBase",
                  "itemValue": "",
                  "itemType": "BPM"
                },
                {
                  "itemName": "KSession",
                  "itemValue": "",
                  "itemType": "BPM"
                },
                {
                  "itemName": "MergeMode",
                  "itemValue": "MERGE_COLLECTIONS",
                  "itemType": "BPM"
                },
                {
                  "itemName": "RuntimeStrategy",
                  "itemValue": "SINGLETON",
                  "itemType": "BPM"
                }
              ],
              "messages": [],
              "container-alias": "employeerostering"
            }
          ]
        }
      }
    }
  ]
}
CreateContainerCommand

Creates a KIE container in the KIE Server.

Table 30. Command attributes
Name Description Requirement

container

Map containing the container-id, release-id data (group ID, artifact ID, version), status, and any other components of the new KIE container

Required

Example REST request body (JSON)
{
  "commands" : [ {
    "create-container" : {
      "container" : {
        "status" : null,
        "messages" : [ ],
        "container-id" : "command-script-container",
        "release-id" : {
          "version" : "1.0",
          "group-id" : "com.redhat",
          "artifact-id" : "Project1"
        },
        "config-items" : [ ]
      }
    }
  } ]
}
Example Java client method
ServiceResponse<KieContainerResource> response = kieServicesClient.createContainer("command-script-container", resource);
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container command-script-container successfully deployed with module com.redhat:Project1:1.0.",
      "result": {
        "kie-container": {
          "container-id": "command-script-container",
          "release-id": {
            "version" : "1.0",
            "group-id" : "com.redhat",
            "artifact-id" : "Project1"
          },
          "resolved-release-id": {
            "version" : "1.0",
            "group-id" : "com.redhat",
            "artifact-id" : "Project1"
          },
          "status": "STARTED",
          "scanner": {
            "status": "DISPOSED",
            "poll-interval": null
          },
          "config-items": [],
          "messages": [
            {
              "severity": "INFO",
              "timestamp": {
                "java.util.Date": 1538762455510
              },
              "content": [
                "Container command-script-container successfully created with module com.redhat:Project1:1.0."
              ]
            }
          ],
          "container-alias": null
        }
      }
    }
  ]
}
GetContainerInfoCommand

Returns information about a specified KIE container in KIE Server.

Table 31. Command attributes
Name Description Requirement

container-id

ID of the KIE container

Required

Example REST request body (JSON)
{
  "commands" : [ {
    "get-container-info" : {
      "container-id" : "command-script-container"
    }
  } ]
}
Example Java client method
ServiceResponse<KieContainerResource> response = kieServicesClient.getContainerInfo("command-script-container");
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Info for container command-script-container",
      "result": {
        "kie-container": {
          "container-id": "command-script-container",
          "release-id": {
            "group-id": "com.redhat",
            "artifact-id": "Project1",
            "version": "1.0"
          },
          "resolved-release-id": {
            "group-id": "com.redhat",
            "artifact-id": "Project1",
            "version": "1.0"
          },
          "status": "STARTED",
          "scanner": {
            "status": "DISPOSED",
            "poll-interval": null
          },
          "config-items": [

          ],
          "container-alias": null
        }
      }
    }
  ]
}
ListContainersCommand

Returns a list of KIE containers that have been created in the KIE Server.

Table 32. Command attributes
Name Description Requirement

kie-container-filter

Optional map containing release-id-filter, container-status-filter, and any other KIE container properties by which you want to filter results

Optional

Example REST request body (JSON)
{
  "commands" : [ {
    "list-containers" : {
      "kie-container-filter" : {
        "release-id-filter" : { },
        "container-status-filter" : {
          "accepted-status" : ["FAILED"]
        }
      }
    }
  } ]
}
Example Java client method
KieContainerResourceFilter filter = new KieContainerResourceFilter.Builder()
        .status(KieContainerStatus.FAILED)
        .build();

KieContainerResourceList containersList = kieServicesClient.listContainers(filter);
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "List of created containers",
      "result": {
        "kie-containers": {
          "kie-container": [
            {
              "container-id": "command-script-container",
              "release-id": {
                "group-id": "com.redhat",
                "artifact-id": "Project1",
                "version": "1.0"
              },
              "resolved-release-id": {
                "group-id": "com.redhat",
                "artifact-id": "Project1",
                "version": "1.0"
              },
              "status": "STARTED",
              "scanner": {
                "status": "STARTED",
                "poll-interval": 5000
              },
              "config-items": [
                {
                  "itemName": "RuntimeStrategy",
                  "itemValue": "SINGLETON",
                  "itemType": "java.lang.String"
                },
                {
                  "itemName": "MergeMode",
                  "itemValue": "MERGE_COLLECTIONS",
                  "itemType": "java.lang.String"
                },
                {
                  "itemName": "KBase",
                  "itemValue": "",
                  "itemType": "java.lang.String"
                },
                {
                  "itemName": "KSession",
                  "itemValue": "",
                  "itemType": "java.lang.String"
                }
              ],
              "messages": [
                {
                  "severity": "INFO",
                  "timestamp": {
                    "java.util.Date": 1538504619749
                  },
                  "content": [
                    "Container command-script-container successfully created with module com.redhat:Project1:1.0."
                  ]
                }
              ],
              "container-alias": null
            }
          ]
        }
      }
    }
  ]
}
CallContainerCommand

Calls a KIE container and executes one or more runtime commands. For information about OptaPlanner runtime commands, see Runtime commands in OptaPlanner.

Table 33. Command attributes
Name Description Requirement

container-id

ID of the KIE container to be called

Required

payload

One or more commands in a BatchExecutionCommand wrapper to be executed on the KIE container

Required

Example REST request body (JSON)
{
  "commands" : [ {
    "call-container" : {
      "payload" : "{\n  \"lookup\" : \"defaultKieSession\",\n  \"commands\" : [ {\n    \"fire-all-rules\" : {\n      \"max\" : -1,\n      \"out-identifier\" : null\n    }\n  } ]\n}",
      "container-id" : "command-script-container"
    }
  } ]
}
Example Java client method
List<Command<?>> commands = new ArrayList<Command<?>>();
      BatchExecutionCommand batchExecution1 = commandsFactory.newBatchExecution(commands, "defaultKieSession");
      commands.add(commandsFactory.newFireAllRules());

      ServiceResponse<ExecutionResults> response1 = ruleClient.executeCommandsWithResults("command-script-container", batchExecution1);
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container command-script-container successfully called.",
      "result": "{\n  \"results\" : [ ],\n  \"facts\" : [ ]\n}"
    }
  ]
}
DisposeContainerCommand

Disposes a specified KIE container in the KIE Server.

Table 34. Command attributes
Name Description Requirement

container-id

ID of the KIE container to be disposed

Required

Example REST request body (JSON)
{
  "commands" : [ {
    "dispose-container" : {
      "container-id" : "command-script-container"
    }
  } ]
}
Example Java client method
ServiceResponse<Void> response = kieServicesClient.disposeContainer("command-script-container");
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container command-script-container successfully disposed.",
      "result": null
    }
  ]
}
GetScannerInfoCommand

Returns information about the KIE scanner used for automatic updates in a specified KIE container, if applicable.

Table 35. Command attributes
Name Description Requirement

container-id

ID of the KIE container where the KIE scanner is used

Required

Example REST request body (JSON)
{
  "commands" : [ {
    "get-scanner-info" : {
      "container-id" : "command-script-container"
    }
  } ]
}
Example Java client method
ServiceResponse<KieScannerResource> response = kieServicesClient.getScannerInfo("command-script-container");
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Scanner info successfully retrieved",
      "result": {
        "kie-scanner": {
          "status": "DISPOSED",
          "poll-interval": null
        }
      }
    }
  ]
}
UpdateScannerCommand

Starts or stops a KIE scanner that controls polling for updated KIE container deployments.

Avoid using a KIE scanner with business processes. Using a KIE scanner with processes can lead to unforeseen updates that can then cause errors in long-running processes when changes are not compatible with running process instances.
Table 36. Command attributes
Name Description Requirement

container-id

ID of the KIE container where the KIE scanner is used

Required

status

Status to be set on the KIE scanner (STARTED, STOPPED)

Required

poll-interval

Permitted polling duration in milliseconds

Required only when starting scanner

Example REST request body (JSON)
{
  "commands" : [ {
    "update-scanner" : {
      "scanner" : {
        "status" : "STARTED",
        "poll-interval" : 10000
      },
      "container-id" : "command-script-container"
    }
  } ]
}
Example Java client method
KieScannerResource scannerResource = new KieScannerResource();
scannerResource.setPollInterval(10000);
scannerResource.setStatus(KieScannerStatus. STARTED);

ServiceResponse<KieScannerResource> response = kieServicesClient.updateScanner("command-script-container", scannerResource);
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Kie scanner successfully created.",
      "result": {
        "kie-scanner": {
          "status": "STARTED",
          "poll-interval": 10000
        }
      }
    }
  ]
}
UpdateReleaseIdCommand

Updates the release ID data (group ID, artifact ID, version) for a specified KIE container.

Table 37. Command attributes
Name Description Requirement

container-id

ID of the KIE container to be updated

Required

releaseId

Updated GAV (group ID, artifact ID, version) data to be applied to the KIE container

Required

Example REST request body (JSON)
{
  "commands" : [ {
    "update-release-id" : {
      "releaseId" : {
        "version" : "1.1",
        "group-id" : "com.redhat",
        "artifact-id" : "Project1"
      },
      "container-id" : "command-script-container"
    }
  } ]
}
Example Java client method
ServiceResponse<ReleaseId> response = kieServicesClient.updateReleaseId("command-script-container", "com.redhat:Project1:1.1");
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Release id successfully updated",
      "result": {
        "release-id": {
          "group-id": "com.redhat",
          "artifact-id": "Project1",
          "version": "1.1"
        }
      }
    }
  ]
}

7.11. Runtime commands in OptaPlanner

OptaPlanner supports runtime commands that you can send to KIE Server for asset-related operations, such as executing all rules or inserting or retracting objects in a KIE session. The full list of supported runtime commands is located in the org.drools.core.command.runtime package in your OptaPlanner instance.

In the KIE Server REST API, you use the global org.drools.core.command.runtime commands or the rule-specific org.drools.core.command.runtime.rule commands as the request body for POST requests to http://SERVER:PORT/kie-server/services/rest/server/containers/instances/{containerId}. For more information about using the KIE Server REST API, see KIE Server REST API for KIE containers and business assets.

In the KIE Server Java client API, you can embed these commands in your Java application along with the relevant Java client. For example, for rule-related commands, you use the RuleServicesClient Java client with the embedded commands. For more information about using the KIE Server Java client API, see KIE Server Java client API for KIE containers and business assets.

7.11.1. Sample runtime commands in OptaPlanner

The following are sample runtime commands that you can use with the KIE Server REST API or Java client API for asset-related operations in KIE Server:

  • BatchExecutionCommand

  • InsertObjectCommand

  • RetractCommand

  • ModifyCommand

  • GetObjectCommand

  • GetObjectsCommand

  • InsertElementsCommand

  • FireAllRulesCommand

  • QueryCommand

  • SetGlobalCommand

  • GetGlobalCommand

For the full list of supported runtime commands, see the org.drools.core.command.runtime package in your OptaPlanner instance.

Each command in this section includes a REST request body example (JSON) for the KIE Server REST API and an embedded Java command example for the KIE Server Java client API. The Java examples use an object org.drools.compiler.test.Person with the fields name (String) and age (Integer).

BatchExecutionCommand

Contains multiple commands to be executed together.

Table 38. Command attributes
Name Description Requirement

commands

List of commands to be executed.

Required

lookup

Sets the KIE session ID on which the commands will be executed. For stateless KIE sessions, this attribute is required. For stateful KIE sessions, this attribute is optional and if not specified, the default KIE session is used.

Required for stateless KIE session, optional for stateful KIE session

KIE session IDs are in the kmodule.xml file of your OptaPlanner project. To view or add a KIE session ID in Business Central to use with the lookup command attribute, navigate to the relevant project in Business Central and go to project SettingsKIE basesKIE sessions. If no KIE bases exist, click Add KIE baseKIE sessions to define the new KIE base and KIE sessions.
Example JSON request body
{
  "lookup": "ksession1",
  "commands": [ {
      "insert": {
        "object": {
          "org.drools.compiler.test.Person": {
            "name": "john",
            "age": 25
          }
        }
      }
    },
    {
      "fire-all-rules": {
        "max": 10,
        "out-identifier": "firedActivations"
      }
    }
  ]
}
Example Java command
BatchExecutionCommand command = new BatchExecutionCommand();
command.setLookup("ksession1");

InsertObjectCommand insertObjectCommand = new InsertObjectCommand(new Person("john", 25));
FireAllRulesCommand fireAllRulesCommand = new FireAllRulesCommand();

command.getCommands().add(insertObjectCommand);
command.getCommands().add(fireAllRulesCommand);

ksession.execute(command);
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container command-script-container successfully called.",
      "result": {
        "execution-results": {
          "results": [
            {
              "value": 0,
              "key": "firedActivations"
            }
          ],
          "facts": []
        }
      }
    }
  ]
}
InsertObjectCommand

Inserts an object into the KIE session.

Table 39. Command attributes
Name Description Requirement

object

The object to be inserted

Required

out-identifier

ID of the FactHandle created from the object insertion and added to the execution results

Optional

return-object

Boolean to determine whether the object must be returned in the execution results (default: true)

Optional

entry-point

Entry point for the insertion

Optional

Example JSON request body
{
  "commands": [ {
      "insert": {
        "entry-point": "my stream",
        "object": {
          "org.drools.compiler.test.Person": {
            "age": 25,
            "name": "john"
          }
        },
        "out-identifier": "john",
        "return-object": false
      }
    }
  ]
}
Example Java command
Command insertObjectCommand =
  CommandFactory.newInsert(new Person("john", 25), "john", false, null);

ksession.execute(insertObjectCommand);
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container command-script-container successfully called.",
      "result": {
        "execution-results": {
          "results": [],
          "facts": [
            {
              "value": {
                "org.drools.core.common.DefaultFactHandle": {
                  "external-form": "0:4:436792766:-2127720265:4:DEFAULT:NON_TRAIT:java.util.LinkedHashMap"
                }
              },
              "key": "john"
            }
          ]
        }
      }
    }
  ]
}
RetractCommand

Retracts an object from the KIE session.

Table 40. Command attributes
Name Description Requirement

fact-handle

The FactHandle associated with the object to be retracted

Required

Example JSON request body
{
  "commands": [ {
      "retract": {
        "fact-handle": "0:4:436792766:-2127720265:4:DEFAULT:NON_TRAIT:java.util.LinkedHashMap"
      }
    }
  ]
}
Example Java command: Use FactHandleFromString
RetractCommand retractCommand = new RetractCommand();
retractCommand.setFactHandleFromString("123:234:345:456:567");
Example Java command: Use FactHandle from inserted object
RetractCommand retractCommand = new RetractCommand(factHandle);
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container employee-rostering successfully called.",
      "result": {
        "execution-results": {
          "results": [],
          "facts": []
        }
      }
    }
  ]
}
ModifyCommand

Modifies a previously inserted object in the KIE session.

Table 41. Command attributes
Name Description Requirement

fact-handle

The FactHandle associated with the object to be modified

Required

setters

List of setters for object modifications

Required

Example JSON request body
{
  "commands": [ {
      "modify": {
        "fact-handle": "0:4:436792766:-2127720265:4:DEFAULT:NON_TRAIT:java.util.LinkedHashMap",
        "setters": {
          "accessor": "age",
          "value": 25
        }
      }
    }
  ]
}
Example Java command
ModifyCommand modifyCommand = new ModifyCommand(factHandle);

List<Setter> setters = new ArrayList<Setter>();
setters.add(new SetterImpl("age", "25"));

modifyCommand.setSetters(setters);
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container employee-rostering successfully called.",
      "result": {
        "execution-results": {
          "results": [],
          "facts": []
        }
      }
    }
  ]
}
GetObjectCommand

Retrieves an object from a KIE session.

Table 42. Command attributes
Name Description Requirement

fact-handle

The FactHandle associated with the object to be retrieved

Required

out-identifier

ID of the FactHandle created from the object insertion and added to the execution results

Optional

Example JSON request body
{
  "commands": [ {
      "get-object": {
        "fact-handle": "0:4:436792766:-2127720265:4:DEFAULT:NON_TRAIT:java.util.LinkedHashMap",
        "out-identifier": "john"
      }
    }
  ]
}
Example Java command
GetObjectCommand getObjectCommand = new GetObjectCommand();
getObjectCommand.setFactHandleFromString("123:234:345:456:567");
getObjectCommand.setOutIdentifier("john");
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container command-script-container successfully called.",
      "result": {
        "execution-results": {
          "results": [
            {
              "value": null,
              "key": "john"
            }
          ],
          "facts": []
        }
      }
    }
  ]
}
GetObjectsCommand

Retrieves all objects from the KIE session as a collection.

Table 43. Command attributes
Name Description Requirement

object-filter

Filter for the objects returned from the KIE session

Optional

out-identifier

Identifier to be used in the execution results

Optional

Example JSON request body
{
  "commands": [ {
      "get-objects": {
        "out-identifier": "objects"
      }
    }
  ]
}
Example Java command
GetObjectsCommand getObjectsCommand = new GetObjectsCommand();
getObjectsCommand.setOutIdentifier("objects");
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container command-script-container successfully called.",
      "result": {
        "execution-results": {
          "results": [
            {
              "value": [
                {
                  "org.apache.xerces.dom.ElementNSImpl": "<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n<object xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"person\"><age>25</age><name>john</name>\n <\/object>"
                },
                {
                  "org.drools.compiler.test.Person": {
                    "name": "john",
                    "age": 25
                  }
                }
              ],
              "key": "objects"
            }
          ],
          "facts": []
        }
      }
    }
  ]
}
InsertElementsCommand

Inserts a list of objects into the KIE session.

Table 44. Command attributes
Name Description Requirement

objects

The list of objects to be inserted into the KIE session

Required

out-identifier

ID of the FactHandle created from the object insertion and added to the execution results

Optional

return-object

Boolean to determine whether the object must be returned in the execution results. Default value: true.

Optional

entry-point

Entry point for the insertion

Optional

Example JSON request body
{
  "commands": [ {
    "insert-elements": {
        "objects": [
            {
                "containedObject": {
                    "@class": "org.drools.compiler.test.Person",
                    "age": 25,
                    "name": "john"
                }
            },
            {
                "containedObject": {
                    "@class": "Person",
                    "age": 35,
                    "name": "sarah"
                }
            }
        ]
    }
  }
]
}
Example Java command
List<Object> objects = new ArrayList<Object>();
objects.add(new Person("john", 25));
objects.add(new Person("sarah", 35));

Command insertElementsCommand = CommandFactory.newInsertElements(objects);
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container command-script-container successfully called.",
      "result": {
        "execution-results": {
          "results": [],
          "facts": [
            {
              "value": {
                "org.drools.core.common.DefaultFactHandle": {
                  "external-form": "0:4:436792766:-2127720265:4:DEFAULT:NON_TRAIT:java.util.LinkedHashMap"
                }
              },
              "key": "john"
            },
            {
              "value": {
                "org.drools.core.common.DefaultFactHandle": {
                  "external-form": "0:4:436792766:-2127720266:4:DEFAULT:NON_TRAIT:java.util.LinkedHashMap"
                }
              },
              "key": "sarah"
            }
          ]
        }
      }
    }
  ]
}
FireAllRulesCommand

Executes all rules in the KIE session.

Table 45. Command attributes
Name Description Requirement

max

Maximum number of rules to be executed. The default is -1 and does not put any restriction on execution.

Optional

out-identifier

ID to be used for retrieving the number of fired rules in execution results.

Optional

agenda-filter

Agenda Filter to be used for rule execution.

Optional

Example JSON request body
{
  "commands" : [ {
    "fire-all-rules": {
        "max": 10,
        "out-identifier": "firedActivations"
    }
  } ]
}
Example Java command
FireAllRulesCommand fireAllRulesCommand = new FireAllRulesCommand();
fireAllRulesCommand.setMax(10);
fireAllRulesCommand.setOutIdentifier("firedActivations");
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container command-script-container successfully called.",
      "result": {
        "execution-results": {
          "results": [
            {
              "value": 0,
              "key": "firedActivations"
            }
          ],
          "facts": []
        }
      }
    }
  ]
}
QueryCommand

Executes a query defined in the KIE base.

Table 46. Command attributes
Name Description Requirement

name

Query name.

Required

out-identifier

ID of the query results. The query results are added in the execution results with this identifier.

Optional

arguments

List of objects to be passed as a query parameter.

Optional

Example JSON request body
{
  "commands": [
    {
      "query": {
        "name": "persons",
        "arguments": [],
        "out-identifier": "persons"
      }
    }
  ]
}
Example Java command
QueryCommand queryCommand = new QueryCommand();
queryCommand.setName("persons");
queryCommand.setOutIdentifier("persons");
Example server response (JSON)
{
  "type": "SUCCESS",
  "msg": "Container stateful-session successfully called.",
  "result": {
    "execution-results": {
      "results": [
        {
          "value": {
            "org.drools.core.runtime.rule.impl.FlatQueryResults": {
              "idFactHandleMaps": {
                "type": "LIST",
                "componentType": null,
                "element": [
                  {
                    "type": "MAP",
                    "componentType": null,
                    "element": [
                      {
                        "value": {
                          "org.drools.core.common.DisconnectedFactHandle": {
                            "id": 1,
                            "identityHashCode": 1809949690,
                            "objectHashCode": 1809949690,
                            "recency": 1,
                            "object": {
                              "org.kie.server.testing.Person": {
                                "fullname": "John Doe",
                                "age": 47
                              }
                            },
                            "entryPointId": "DEFAULT",
                            "traitType": "NON_TRAIT",
                            "external-form": "0:1:1809949690:1809949690:1:DEFAULT:NON_TRAIT:org.kie.server.testing.Person"
                          }
                        },
                        "key": "$person"
                      }
                    ]
                  }
                ]
              },
              "idResultMaps": {
                "type": "LIST",
                "componentType": null,
                "element": [
                  {
                    "type": "MAP",
                    "componentType": null,
                    "element": [
                      {
                        "value": {
                          "org.kie.server.testing.Person": {
                            "fullname": "John Doe",
                            "age": 47
                          }
                        },
                        "key": "$person"
                      }
                    ]
                  }
                ]
              },
              "identifiers": {
                "type": "SET",
                "componentType": null,
                "element": [
                  "$person"
                ]
              }
            }
          },
          "key": "persons"
        }
      ],
      "facts": []
    }
  }
}
SetGlobalCommand

Sets an object to a global state.

Table 47. Command attributes
Name Description Requirement

identifier

ID of the global variable defined in the KIE base

Required

object

Object to be set into the global variable

Optional

out

Boolean to exclude the global variable you set from the execution results

Optional

out-identifier

ID of the global execution result

Optional

Example JSON request body
{
  "commands": [
    {
      "set-global": {
        "identifier": "helper",
        "object": {
          "org.kie.server.testing.Person": {
            "fullname": "kyle",
            "age": 30
          }
        },
        "out-identifier": "output"
      }
    }
  ]
}
Example Java command
SetGlobalCommand setGlobalCommand = new SetGlobalCommand();
setGlobalCommand.setIdentifier("helper");
setGlobalCommand.setObject(new Person("kyle", 30));
setGlobalCommand.setOut(true);
setGlobalCommand.setOutIdentifier("output");
Example server response (JSON)
{
  "type": "SUCCESS",
  "msg": "Container stateful-session successfully called.",
  "result": {
    "execution-results": {
      "results": [
        {
          "value": {
            "org.kie.server.testing.Person": {
              "fullname": "kyle",
              "age": 30
            }
          },
          "key": "output"
        }
      ],
      "facts": []
    }
  }
}
GetGlobalCommand

Retrieves a previously defined global object.

Table 48. Command attributes
Name Description Requirement

identifier

ID of the global variable defined in the KIE base

Required

out-identifier

ID to be used in the execution results

Optional

Example JSON request body
{
  "commands": [ {
      "get-global": {
        "identifier": "helper",
        "out-identifier": "helperOutput"
      }
    }
  ]
}
Example Java command
GetGlobalCommand getGlobalCommand = new GetGlobalCommand();
getGlobalCommand.setIdentifier("helper");
getGlobalCommand.setOutIdentifier("helperOutput");
Example server response (JSON)
{
  "response": [
    {
      "type": "SUCCESS",
      "msg": "Container command-script-container successfully called.",
      "result": {
        "execution-results": {
          "results": [
            {
              "value": null,
              "key": "helperOutput"
            }
          ],
          "facts": []
        }
      }
    }
  ]
}

7.12. KIE Server controller REST API for KIE Server templates and instances

OptaPlanner provides a KIE Server controller REST API that you can use to interact with your KIE Server templates (configurations), KIE Server instances (remote servers), and associated KIE containers (deployment units) in OptaPlanner without using the Business Central user interface. This API support enables you to maintain your OptaPlanner servers and resources more efficiently and optimize your integration and development with OptaPlanner.

With the KIE Server controller REST API, you can perform the following actions:

  • Retrieve information about KIE Server templates, instances, and associated KIE containers

  • Update, start, or stop KIE containers associated with KIE Server templates and instances

  • Create, update, or delete KIE Server templates

  • Create, update, or delete KIE Server instances

Requests to the KIE Server controller REST API require the following components:

Authentication

The KIE Server controller REST API requires HTTP Basic authentication or token-based authentication for the following user roles, depending on controller type:

  • rest-all user role if you installed Business Central and you want to use the built-in KIE Server controller

  • kie-server user role if you installed the headless KIE Server controller separately from Business Central

To view configured user roles for your OptaPlanner distribution, navigate to ~/$SERVER_HOME/standalone/configuration/application-roles.properties and ~/application-users.properties.

To add a user with the kie-server role or the rest-all role or both, navigate to ~/$SERVER_HOME/bin and run the following command with the role or roles specified:

$ ./add-user.sh -a --user <USERNAME> --password <PASSWORD> --role kie-server,rest-all

To configure the kie-server or rest-all user with KIE Server controller access, navigate to ~/$SERVER_HOME/standalone/configuration/standalone-full.xml, uncomment the org.kie.server properties (if applicable), and add the controller user login credentials and controller location (if needed):

<property name="org.kie.server.location" value="http://localhost:8080/kie-server/services/rest/server"/>
<property name="org.kie.server.controller" value="http://localhost:8080/business-central/rest/controller"/>
<property name="org.kie.server.controller.user" value="baAdmin"/>
<property name="org.kie.server.controller.pwd" value="password@1"/>
<property name="org.kie.server.id" value="default-kieserver"/>

For more information about user roles and OptaPlanner installation options, see

HTTP headers

The KIE Server controller REST API requires the following HTTP headers for API requests:

  • Accept: Data format accepted by your requesting client:

    • application/json (JSON)

    • application/xml (XML, for JAXB)

  • Content-Type: Data format of your POST or PUT API request data:

    • application/json (JSON)

    • application/xml (XML, for JAXB)

HTTP methods

The KIE Server controller REST API supports the following HTTP methods for API requests:

  • GET: Retrieves specified information from a specified resource endpoint

  • POST: Updates a resource or resource instance

  • PUT: Creates a resource or resource instance

  • DELETE: Deletes a resource or resource instance

Base URL

The base URL for KIE Server controller REST API requests is http://SERVER:PORT/CONTROLLER/rest/, such as http://localhost:8080/business-central/rest/ if you are using the KIE Server controller built in to Business Central.

Endpoints

KIE Server controller REST API endpoints, such as /controller/management/servers/{serverTemplateId} for a specified KIE Server template, are the URIs that you append to the KIE Server controller REST API base URL to access the corresponding server resource or type of server resource in OptaPlanner.

Example request URL for /controller/management/servers/{serverTemplateId} endpoint

http://localhost:8080/business-central/rest/controller/management/servers/default-kieserver

Request parameters and request data

Some KIE Server controller REST API requests require specific parameters in the request URL path to identify or filter specific resources and to perform specific actions. You can append URL parameters to the endpoint in the format ?<PARAM>=<VALUE>&<PARAM>=<VALUE>.

Example DELETE request URL with parameters

http://localhost:8080/business-central/rest/controller/server/new-kieserver-instance?location=http://localhost:8080/kie-server/services/rest/server

HTTP POST and PUT requests may additionally require a request body or file with data to accompany the request.

Example PUT request URL and JSON request body data

http://localhost:8080/business-central/rest/controller/management/servers/new-kieserver

{
  "server-id": "new-kieserver",
  "server-name": "new-kieserver",
  "container-specs": [],
  "server-config": {},
  "capabilities": [
    "RULE",
    "PROCESS",
    "PLANNING"
  ]
}

7.12.1. Sending requests with the KIE Server controller REST API using a REST client or curl utility

The KIE Server controller REST API enables you to interact with your KIE Server templates (configurations), KIE Server instances (remote servers), and associated KIE containers (deployment units) in OptaPlanner without using the Business Central user interface. You can send KIE Server controller REST API requests using any REST client or curl utility.

Prerequisites
  • KIE Server is installed and running.

  • The KIE Server controller or headless KIE Server controller is installed and running.

  • You have rest-all user role access to the KIE Server controller if you installed Business Central, or kie-server user role access to the headless KIE Server controller installed separately from Business Central.

Procedure
  1. Identify the relevant API endpoint to which you want to send a request, such as [GET] /controller/management/servers to retrieve KIE Server templates from the KIE Server controller.

  2. In a REST client or curl utility, enter the following components for a GET request to controller/management/servers. Adjust any request details according to your use case.

    For REST client:

    • Authentication: Enter the user name and password of the KIE Server controller user with the rest-all role or the headless KIE Server controller user with the kie-server role.

    • HTTP Headers: Set the following header:

      • Accept: application/json

    • HTTP method: Set to GET.

    • URL: Enter the KIE Server controller REST API base URL and endpoint, such as http://localhost:8080/business-central/rest/controller/management/servers.

    For curl utility:

    • -u: Enter the user name and password of the KIE Server controller user with the rest-all role or the headless KIE Server controller user with the kie-server role.

    • -H: Set the following header:

      • accept: application/json

    • -X: Set to GET.

    • URL: Enter the KIE Server controller REST API base URL and endpoint, such as http://localhost:8080/business-central/rest/controller/management/servers.

    curl -u 'baAdmin:password@1' -H "accept: application/json" -X GET "http://localhost:8080/business-central/rest/controller/management/servers"
  3. Execute the request and review the KIE Server controller response.

    Example server response (JSON):

    {
      "server-template": [
        {
          "server-id": "default-kieserver",
          "server-name": "default-kieserver",
          "container-specs": [
            {
              "container-id": "employeerostering_1.0.0-SNAPSHOT",
              "container-name": "employeerostering",
              "server-template-key": {
                "server-id": "default-kieserver",
                "server-name": "default-kieserver"
              },
              "release-id": {
                "group-id": "employeerostering",
                "artifact-id": "employeerostering",
                "version": "1.0.0-SNAPSHOT"
              },
              "configuration": {
                "RULE": {
                  "org.kie.server.controller.api.model.spec.RuleConfig": {
                    "pollInterval": null,
                    "scannerStatus": "STOPPED"
                  }
                },
                "PROCESS": {
                  "org.kie.server.controller.api.model.spec.ProcessConfig": {
                    "runtimeStrategy": "SINGLETON",
                    "kbase": "",
                    "ksession": "",
                    "mergeMode": "MERGE_COLLECTIONS"
                  }
                }
              },
              "status": "STARTED"
            },
            {
              "container-id": "mortgage-process_1.0.0-SNAPSHOT",
              "container-name": "mortgage-process",
              "server-template-key": {
                "server-id": "default-kieserver",
                "server-name": "default-kieserver"
              },
              "release-id": {
                "group-id": "mortgage-process",
                "artifact-id": "mortgage-process",
                "version": "1.0.0-SNAPSHOT"
              },
              "configuration": {
                "RULE": {
                  "org.kie.server.controller.api.model.spec.RuleConfig": {
                    "pollInterval": null,
                    "scannerStatus": "STOPPED"
                  }
                },
                "PROCESS": {
                  "org.kie.server.controller.api.model.spec.ProcessConfig": {
                    "runtimeStrategy": "PER_PROCESS_INSTANCE",
                    "kbase": "",
                    "ksession": "",
                    "mergeMode": "MERGE_COLLECTIONS"
                  }
                }
              },
              "status": "STARTED"
            }
          ],
          "server-config": {},
          "server-instances": [
            {
              "server-instance-id": "default-kieserver-instance@localhost:8080",
              "server-name": "default-kieserver-instance@localhost:8080",
              "server-template-id": "default-kieserver",
              "server-url": "http://localhost:8080/kie-server/services/rest/server"
            }
          ],
          "capabilities": [
            "RULE",
            "PROCESS",
            "PLANNING"
          ]
        }
      ]
    }
  4. In your REST client or curl utility, send another API request with the following components for a PUT request to /controller/management/servers/{serverTemplateId} to create a new KIE Server template. Adjust any request details according to your use case.

    For REST client:

    • Authentication: Enter the user name and password of the KIE Server controller user with the rest-all role or the headless KIE Server controller user with the kie-server role.

    • HTTP Headers: Set the following headers:

      • Accept: application/json

      • Content-Type: application/json

    • HTTP method: Set to PUT.

    • URL: Enter the KIE Server controller REST API base URL and endpoint, such as http://localhost:8080/business-central/rest/controller/management/servers/new-kieserver.

    • Request body: Add a JSON request body with the configurations for the new KIE Server template:

    {
      "server-id": "new-kieserver",
      "server-name": "new-kieserver",
      "container-specs": [],
      "server-config": {},
      "capabilities": [
        "RULE",
        "PROCESS",
        "PLANNING"
      ]
    }

    For curl utility:

    • -u: Enter the user name and password of the KIE Server controller user with the rest-all role or the headless KIE Server controller user with the kie-server role.

    • -H: Set the following headers:

      • accept: application/json

      • content-type: application/json

    • -X: Set to PUT.

    • URL: Enter the KIE Server controller REST API base URL and endpoint, such as http://localhost:8080/business-central/rest/controller/management/servers/new-kieserver.

    • -d: Add a JSON request body or file (@file.json) with the configurations for the new KIE Server template:

    curl -u 'baAdmin:password@1' -H "accept: application/json" -H "content-type: application/json" -X PUT "http://localhost:8080/business-central/rest/controller/management/servers/new-kieserver" -d "{ \"server-id\": \"new-kieserver\", \"server-name\": \"new-kieserver\", \"container-specs\": [], \"server-config\": {}, \"capabilities\": [ \"RULE\", \"PROCESS\", \"PLANNING\" ]}"
    curl -u 'baAdmin:password@1' -H "accept: application/json" -H "content-type: application/json" -X PUT "http://localhost:8080/business-central/rest/controller/management/servers/new-kieserver" -d @my-server-template-configs.json
  5. Execute the request and confirm the successful KIE Server controller response.

    If you encounter request errors, review the returned error code messages and adjust your request accordingly.

7.12.2. Sending requests with the KIE Server controller REST API using the Swagger interface

The KIE Server controller REST API supports a Swagger web interface that you can use instead of a standalone REST client or curl utility to interact with your KIE Server templates, instances, and associated KIE containers in OptaPlanner without using the Business Central user interface.

By default, the Swagger web interface for the KIE Server controller is enabled by the org.kie.workbench.swagger.disabled=false system property. To disable the Swagger web interface for the KIE Server controller, set this system property to true.
Prerequisites
  • The KIE Server controller is installed and running.

  • You have rest-all user role access to the KIE Server controller if you installed Business Central, or kie-server user role access to the headless KIE Server controller installed separately from Business Central.

Procedure
  1. In a web browser, navigate to http://SERVER:PORT/CONTROLLER/docs, such as http://localhost:8080/business-central/docs, and log in with the user name and password of the KIE Server controller user with the rest-all role or the headless KIE Server controller user with the kie-server role.

    If you are using the KIE Server controller built in to Business Central, the Swagger page associated with the KIE Server controller is identified as the "Business Central API" for Business Central REST services. If you are using the headless KIE Server controller without Business Central, the Swagger page associated with the headless KIE Server controller is identified as the "Controller API". In both cases, the KIE Server controller REST API endpoints are the same.
  2. In the Swagger page, select the relevant API endpoint to which you want to send a request, such as Controller :: KIE Server templates and KIE containers[GET] /controller/management/servers to retrieve KIE Server templates from the KIE Server controller.

  3. Click Try it out and provide any optional parameters by which you want to filter results, if applicable.

  4. In the Response content type drop-down menu, select the desired format of the server response, such as application/json for JSON format.

  5. Click Execute and review the KIE Server response.

    Example server response (JSON):

    {
      "server-template": [
        {
          "server-id": "default-kieserver",
          "server-name": "default-kieserver",
          "container-specs": [
            {
              "container-id": "employeerostering_1.0.0-SNAPSHOT",
              "container-name": "employeerostering",
              "server-template-key": {
                "server-id": "default-kieserver",
                "server-name": "default-kieserver"
              },
              "release-id": {
                "group-id": "employeerostering",
                "artifact-id": "employeerostering",
                "version": "1.0.0-SNAPSHOT"
              },
              "configuration": {
                "RULE": {
                  "org.kie.server.controller.api.model.spec.RuleConfig": {
                    "pollInterval": null,
                    "scannerStatus": "STOPPED"
                  }
                },
                "PROCESS": {
                  "org.kie.server.controller.api.model.spec.ProcessConfig": {
                    "runtimeStrategy": "SINGLETON",
                    "kbase": "",
                    "ksession": "",
                    "mergeMode": "MERGE_COLLECTIONS"
                  }
                }
              },
              "status": "STARTED"
            },
            {
              "container-id": "mortgage-process_1.0.0-SNAPSHOT",
              "container-name": "mortgage-process",
              "server-template-key": {
                "server-id": "default-kieserver",
                "server-name": "default-kieserver"
              },
              "release-id": {
                "group-id": "mortgage-process",
                "artifact-id": "mortgage-process",
                "version": "1.0.0-SNAPSHOT"
              },
              "configuration": {
                "RULE": {
                  "org.kie.server.controller.api.model.spec.RuleConfig": {
                    "pollInterval": null,
                    "scannerStatus": "STOPPED"
                  }
                },
                "PROCESS": {
                  "org.kie.server.controller.api.model.spec.ProcessConfig": {
                    "runtimeStrategy": "PER_PROCESS_INSTANCE",
                    "kbase": "",
                    "ksession": "",
                    "mergeMode": "MERGE_COLLECTIONS"
                  }
                }
              },
              "status": "STARTED"
            }
          ],
          "server-config": {},
          "server-instances": [
            {
              "server-instance-id": "default-kieserver-instance@localhost:8080",
              "server-name": "default-kieserver-instance@localhost:8080",
              "server-template-id": "default-kieserver",
              "server-url": "http://localhost:8080/kie-server/services/rest/server"
            }
          ],
          "capabilities": [
            "RULE",
            "PROCESS",
            "PLANNING"
          ]
        }
      ]
    }
  6. In the Swagger page, navigate to the Controller :: KIE Server templates and KIE containers[GET] /controller/management/servers/{serverTemplateId} endpoint to send another request to create a new KIE Server template. Adjust any request details according to your use case.

  7. Click Try it out and enter the following components for the request:

    • serverTemplateId: Enter the ID of the new KIE Server template, such as new-kieserver.

    • body: Set the Parameter content type to the desired request body format, such as application/json for JSON format, and add a request body with the configurations for the new KIE Server template:

    {
      "server-id": "new-kieserver",
      "server-name": "new-kieserver",
      "container-specs": [],
      "server-config": {},
      "capabilities": [
        "RULE",
        "PROCESS",
        "PLANNING"
      ]
    }
  8. In the Response content type drop-down menu, select the desired format of the server response, such as application/json for JSON format.

  9. Click Execute and confirm the successful KIE Server controller response.

    If you encounter request errors, review the returned error code messages and adjust your request accordingly.

7.12.3. Supported KIE Server controller REST API endpoints

The KIE Server controller REST API provides endpoints for interacting with KIE Server templates (configurations), KIE Server instances (remote servers), and associated KIE containers (deployment units). The KIE Server controller REST API base URL is http://SERVER:PORT/CONTROLLER/rest/. All requests require HTTP Basic authentication or token-based authentication for the rest-all user role if you installed Business Central and you want to use the built-in KIE Server controller, or the kie-server user role if you installed the headless KIE Server controller separately from Business Central.

For the full list of KIE Server controller REST API endpoints and descriptions, use one of the following resources:

  • Controller REST API on the jBPM Documentation page (static)

  • Swagger UI for the KIE Server controller REST API at http://SERVER:PORT/CONTROLLER/docs (dynamic, requires running KIE Server controller)

    By default, the Swagger web interface for the KIE Server controller is enabled by the org.kie.workbench.swagger.disabled=false system property. To disable the Swagger web interface for the KIE Server controller, set this system property to true.

    If you are using the KIE Server controller built in to Business Central, the Swagger page associated with the KIE Server controller is identified as the "Business Central API" for Business Central REST services. If you are using the headless KIE Server controller without Business Central, the Swagger page associated with the headless KIE Server controller is identified as the "Controller API". In both cases, the KIE Server controller REST API endpoints are the same.

7.13. KIE Server controller Java client API for KIE Server templates and instances

OptaPlanner provides a KIE Server controller Java client API that enables you to connect to the KIE Server controller using REST or WebSocket protocol from your Java client application. You can use the KIE Server controller Java client API as an alternative to the KIE Server controller REST API to interact with your KIE Server templates (configurations), KIE Server instances (remote servers), and associated KIE containers (deployment units) in OptaPlanner without using the Business Central user interface. This API support enables you to maintain your OptaPlanner servers and resources more efficiently and optimize your integration and development with OptaPlanner.

With the KIE Server controller Java client API, you can perform the following actions also supported by the KIE Server controller REST API:

  • Retrieve information about KIE Server templates, instances, and associated KIE containers

  • Update, start, or stop KIE containers associated with KIE Server templates and instances

  • Create, update, or delete KIE Server templates

  • Create, update, or delete KIE Server instances

KIE Server controller Java client API requests require the following components:

Authentication

The KIE Server controller Java client API requires HTTP Basic authentication for the following user roles, depending on controller type:

  • rest-all user role if you installed Business Central and you want to use the built-in KIE Server controller

  • kie-server user role if you installed the headless KIE Server controller separately from Business Central

To view configured user roles for your OptaPlanner distribution, navigate to ~/$SERVER_HOME/standalone/configuration/application-roles.properties and ~/application-users.properties.

To add a user with the kie-server role or the rest-all role or both, navigate to ~/$SERVER_HOME/bin and run the following command with the role or roles specified:

$ ./add-user.sh -a --user <USERNAME> --password <PASSWORD> --role kie-server,rest-all

To configure the kie-server or rest-all user with KIE Server controller access, navigate to ~/$SERVER_HOME/standalone/configuration/standalone-full.xml, uncomment the org.kie.server properties (if applicable), and add the controller user login credentials and controller location (if needed):

<property name="org.kie.server.location" value="http://localhost:8080/kie-server/services/rest/server"/>
<property name="org.kie.server.controller" value="http://localhost:8080/business-central/rest/controller"/>
<property name="org.kie.server.controller.user" value="baAdmin"/>
<property name="org.kie.server.controller.pwd" value="password@1"/>
<property name="org.kie.server.id" value="default-kieserver"/>

For more information about user roles and OptaPlanner installation options, see

Project dependencies

The KIE Server controller Java client API requires the following dependencies on the relevant classpath of your Java project:

<!-- For remote execution on controller -->
<dependency>
  <groupId>org.kie.server</groupId>
  <artifactId>kie-server-controller-client</artifactId>
  <version>${optaplanner.version}</version>
</dependency>

<!-- For REST client -->
<dependency>
  <groupId>org.jboss.resteasy</groupId>
  <artifactId>resteasy-client</artifactId>
  <version>${resteasy.version}</version>
</dependency>

<!-- For WebSocket client -->
<dependency>
  <groupId>io.undertow</groupId>
  <artifactId>undertow-websockets-jsr</artifactId>
  <version>${undertow.version}</version>
</dependency>

<!-- For debug logging (optional) -->
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>${logback.version}</version>
</dependency>

The <version> for OptaPlanner dependencies is the Maven artifact version for OptaPlanner currently used in your project (for example, 7.43.0.Final).

Client request configuration

All Java client requests with the KIE Server controller Java client API must define at least the following controller communication components:

  • Credentials of the rest-all user if you installed Business Central, or the kie-server user if you installed the headless KIE Server controller separately from Business Central

  • KIE Server controller location for REST or WebSocket protocol:

    • Example REST URL: http://localhost:8080/business-central/rest/controller

    • Example WebSocket URL: ws://localhost:8080/headless-controller/websocket/controller

  • Marshalling format for API requests and responses (JSON or JAXB)

  • A KieServerControllerClient object, which serves as the entry point for starting the server communication using the Java client API

  • A KieServerControllerClientFactory defining REST or WebSocket protocol and user access

  • The KIE Server controller client service or services used, such as listServerTemplates, getServerTemplate, or getServerInstances

The following are examples of REST and WebSocket client configurations with these components:

Client configuration example with REST
import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.controller.api.model.spec.ServerTemplateList;
import org.kie.server.controller.client.KieServerControllerClient;
import org.kie.server.controller.client.KieServerControllerClientFactory;

public class ListServerTemplatesExample {

    private static final String URL = "http://localhost:8080/business-central/rest/controller";
    private static final String USER = "baAdmin";
    private static final String PASSWORD = "password@1";

    private static final MarshallingFormat FORMAT = MarshallingFormat.JSON;

    public static void main(String[] args) {
        KieServerControllerClient client = KieServerControllerClientFactory.newRestClient(URL,
                                                                                          USER,
                                                                                          PASSWORD);

        final ServerTemplateList serverTemplateList = client.listServerTemplates();
        System.out.println(String.format("Found %s server template(s) at controller url: %s",
                                         serverTemplateList.getServerTemplates().length,
                                         URL));
    }
}
Client configuration example with WebSocket
import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.controller.api.model.spec.ServerTemplateList;
import org.kie.server.controller.client.KieServerControllerClient;
import org.kie.server.controller.client.KieServerControllerClientFactory;

public class ListServerTemplatesExample {

    private static final String URL = "ws://localhost:8080/my-controller/websocket/controller";
    private static final String USER = "baAdmin";
    private static final String PASSWORD = "password@1";

    private static final MarshallingFormat FORMAT = MarshallingFormat.JSON;

    public static void main(String[] args) {
        KieServerControllerClient client = KieServerControllerClientFactory.newWebSocketClient(URL,
                                                                                               USER,
                                                                                               PASSWORD);

        final ServerTemplateList serverTemplateList = client.listServerTemplates();
        System.out.println(String.format("Found %s server template(s) at controller url: %s",
                                         serverTemplateList.getServerTemplates().length,
                                         URL));
    }
}

7.13.1. Sending requests with the KIE Server controller Java client API

The KIE Server controller Java client API enables you to connect to the KIE Server controller using REST or WebSocket protocols from your Java client application. You can use the KIE Server controller Java client API as an alternative to the KIE Server controller REST API to interact with your KIE Server templates (configurations), KIE Server instances (remote servers), and associated KIE containers (deployment units) in OptaPlanner without using the Business Central user interface.

Prerequisites
  • KIE Server is installed and running.

  • The KIE Server controller or headless KIE Server controller is installed and running.

  • You have rest-all user role access to the KIE Server controller if you installed Business Central, or kie-server user role access to the headless KIE Server controller installed separately from Business Central.

  • You have a Java project with OptaPlanner resources.

Procedure
  1. In your client application, ensure that the following dependencies have been added to the relevant classpath of your Java project:

    <!-- For remote execution on controller -->
    <dependency>
      <groupId>org.kie.server</groupId>
      <artifactId>kie-server-controller-client</artifactId>
      <version>${optaplanner.version}</version>
    </dependency>
    
    <!-- For REST client -->
    <dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>resteasy-client</artifactId>
      <version>${resteasy.version}</version>
    </dependency>
    
    <!-- For WebSocket client -->
    <dependency>
      <groupId>io.undertow</groupId>
      <artifactId>undertow-websockets-jsr</artifactId>
      <version>${undertow.version}</version>
    </dependency>
    
    <!-- For debug logging (optional) -->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>${logback.version}</version>
    </dependency>
  2. In the ~/kie/server/controller/client folder of the Java client API in GitHub , identify the relevant Java client implementation for the request you want to send, such as the RestKieServerControllerClient implementation to access client services for KIE Server templates and KIE containers in REST protocol.

  3. In your client application, create a .java class for the API request. The class must contain the necessary imports, the KIE Server controller location and user credentials, a KieServerControllerClient object, and the client method to execute, such as createServerTemplate and createContainer from the RestKieServerControllerClient implementation. Adjust any configuration details according to your use case.

    Creating and interacting with a KIE Server template and KIE containers
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.kie.server.api.marshalling.MarshallingFormat;
    import org.kie.server.api.model.KieContainerStatus;
    import org.kie.server.api.model.KieScannerStatus;
    import org.kie.server.api.model.ReleaseId;
    import org.kie.server.controller.api.model.spec.*;
    import org.kie.server.controller.client.KieServerControllerClient;
    import org.kie.server.controller.client.KieServerControllerClientFactory;
    
    public class RestTemplateContainerExample {
    
      private static final String URL = "http://localhost:8080/business-central/rest/controller";
      private static final String USER = "baAdmin";
      private static final String PASSWORD = "password@1";
    
        private static KieServerControllerClient client;
    
        public static void main(String[] args) {
            KieServerControllerClient client = KieServerControllerClientFactory.newRestClient(URL,
                                                                                              USER,
                                                                                              PASSWORD,
                                                                                              MarshallingFormat.JSON);
            // Create server template and KIE container, start and stop KIE container, and delete server template
            ServerTemplate serverTemplate = createServerTemplate();
            ContainerSpec container = createContainer(serverTemplate);
            client.startContainer(container);
            client.stopContainer(container);
            client.deleteServerTemplate(serverTemplate.getId());
        }
    
        // Re-create and configure server template
        protected static ServerTemplate createServerTemplate() {
            ServerTemplate serverTemplate = new ServerTemplate();
            serverTemplate.setId("example-client-id");
            serverTemplate.setName("example-client-name");
            serverTemplate.setCapabilities(Arrays.asList(Capability.PROCESS.name(),
                                                         Capability.RULE.name(),
                                                         Capability.PLANNING.name()));
    
            client.saveServerTemplate(serverTemplate);
    
            return serverTemplate;
        }
    
        // Re-create and configure KIE containers
        protected static ContainerSpec createContainer(ServerTemplate serverTemplate){
            Map<Capability, ContainerConfig> containerConfigMap = new HashMap();
    
            ProcessConfig processConfig = new ProcessConfig("PER_PROCESS_INSTANCE", "kieBase", "kieSession", "MERGE_COLLECTION");
            containerConfigMap.put(Capability.PROCESS, processConfig);
    
            RuleConfig ruleConfig = new RuleConfig(500l, KieScannerStatus.SCANNING);
            containerConfigMap.put(Capability.RULE, ruleConfig);
    
            ReleaseId releaseId = new ReleaseId("org.kie.server.testing", "stateless-session-kjar", "1.0.0-SNAPSHOT");
    
            ContainerSpec containerSpec = new ContainerSpec("example-container-id", "example-client-name", serverTemplate, releaseId, KieContainerStatus.STOPPED, containerConfigMap);
            client.saveContainerSpec(serverTemplate.getId(), containerSpec);
    
            return containerSpec;
        }
    }
  4. Run the configured .java class from your project directory to execute the request, and review the KIE Server controller response.

    If you enabled debug logging, KIE Server responds with a detailed response according to your configured marshalling format, such as JSON. If you encounter request errors, review the returned error code messages and adjust your Java configurations accordingly.

7.13.2. Supported KIE Server controller Java clients

The following are some of the Java client services available in the org.kie.server.controller.client package of your OptaPlanner distribution. You can use these services to interact with related resources in the KIE Server controller similarly to the KIE Server controller REST API.

  • KieServerControllerClient: Used as the entry point for communicating with the KIE Server controller

  • RestKieServerControllerClient: Implementation used to interact with KIE Server templates and KIE containers in REST protocol (found in ~/org/kie/server/controller/client/rest)

  • WebSocketKieServerControllerClient: Implementation used to interact with KIE Server templates and KIE containers in WebSocket protocol (found in ~/org/kie/server/controller/client/websocket)

For the full list of available KIE Server controller Java clients, see the Java client API source in GitHub.

7.13.3. Example requests with the KIE Server controller Java client API

The following are examples of KIE Server controller Java client API requests for basic interactions with the KIE Server controller. For the full list of available KIE Server controller Java clients, see the Java client API source in GitHub.

Creating and interacting with KIE Server templates and KIE containers

You can use the ServerTemplate and ContainerSpec services in the REST or WebSocket KIE Server controller clients to create, dispose, and update KIE Server templates and KIE containers, and to start and stop KIE containers, as illustrated in this example.

Example request to create and interact with a KIE Server template and KIE containers
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.api.model.KieContainerStatus;
import org.kie.server.api.model.KieScannerStatus;
import org.kie.server.api.model.ReleaseId;
import org.kie.server.controller.api.model.spec.*;
import org.kie.server.controller.client.KieServerControllerClient;
import org.kie.server.controller.client.KieServerControllerClientFactory;

public class RestTemplateContainerExample {

  private static final String URL = "http://localhost:8080/business-central/rest/controller";
  private static final String USER = "baAdmin";
  private static final String PASSWORD = "password@1";

    private static KieServerControllerClient client;

    public static void main(String[] args) {
        KieServerControllerClient client = KieServerControllerClientFactory.newRestClient(URL,
                                                                                          USER,
                                                                                          PASSWORD,
                                                                                          MarshallingFormat.JSON);
        // Create server template and KIE container, start and stop KIE container, and delete server template
        ServerTemplate serverTemplate = createServerTemplate();
        ContainerSpec container = createContainer(serverTemplate);
        client.startContainer(container);
        client.stopContainer(container);
        client.deleteServerTemplate(serverTemplate.getId());
    }

    // Re-create and configure server template
    protected static ServerTemplate createServerTemplate() {
        ServerTemplate serverTemplate = new ServerTemplate();
        serverTemplate.setId("example-client-id");
        serverTemplate.setName("example-client-name");
        serverTemplate.setCapabilities(Arrays.asList(Capability.PROCESS.name(),
                                                     Capability.RULE.name(),
                                                     Capability.PLANNING.name()));

        client.saveServerTemplate(serverTemplate);

        return serverTemplate;
    }

    // Re-create and configure KIE containers
    protected static ContainerSpec createContainer(ServerTemplate serverTemplate){
        Map<Capability, ContainerConfig> containerConfigMap = new HashMap();

        ProcessConfig processConfig = new ProcessConfig("PER_PROCESS_INSTANCE", "kieBase", "kieSession", "MERGE_COLLECTION");
        containerConfigMap.put(Capability.PROCESS, processConfig);

        RuleConfig ruleConfig = new RuleConfig(500l, KieScannerStatus.SCANNING);
        containerConfigMap.put(Capability.RULE, ruleConfig);

        ReleaseId releaseId = new ReleaseId("org.kie.server.testing", "stateless-session-kjar", "1.0.0-SNAPSHOT");

        ContainerSpec containerSpec = new ContainerSpec("example-container-id", "example-client-name", serverTemplate, releaseId, KieContainerStatus.STOPPED, containerConfigMap);
        client.saveContainerSpec(serverTemplate.getId(), containerSpec);

        return containerSpec;
    }
}
Listing KIE Server templates and specifying connection timeout (REST)

When you use REST protocol for KIE Server controller Java client API requests, you can provide your own javax.ws.rs.core.Configuration specification to modify the underlying REST client API, such as connection timeout.

Example REST request to return server templates and specify connection timeout
import java.util.concurrent.TimeUnit;
import javax.ws.rs.core.Configuration;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;

import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.controller.api.model.spec.ServerTemplateList;
import org.kie.server.controller.client.KieServerControllerClient;
import org.kie.server.controller.client.KieServerControllerClientFactory;

public class RESTTimeoutExample {

  private static final String URL = "http://localhost:8080/business-central/rest/controller";
  private static final String USER = "baAdmin";
  private static final String PASSWORD = "password@1";

  public static void main(String[] args) {

      // Specify connection timeout
      final Configuration configuration =
              new ResteasyClientBuilder()
                      .establishConnectionTimeout(10,
                                                    TimeUnit.SECONDS)
                      .socketTimeout(60,
                                       TimeUnit.SECONDS)
                        .getConfiguration();
        KieServerControllerClient client = KieServerControllerClientFactory.newRestClient(URL,
                                                                                          USER,
                                                                                          PASSWORD,
                                                                                          MarshallingFormat.JSON,
                                                                                          configuration);

        // Retrieve list of server templates
        final ServerTemplateList serverTemplateList = client.listServerTemplates();
        System.out.println(String.format("Found %s server template(s) at controller url: %s",
                                         serverTemplateList.getServerTemplates().length,
                                         URL));
    }
}
Listing KIE Server templates and specifying event notifications (WebSocket)

When you use WebSocket protocol for KIE Server controller Java client API requests, you can enable event notifications based on changes that happen in the particular KIE Server controller to which the client API is connected. For example, you can receive notifications when KIE Server templates or instances are connected to or updated in the KIE Server controller.

Example WebSocket request to return server templates and specify event notifications
import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.controller.api.model.events.*;
import org.kie.server.controller.api.model.spec.ServerTemplateList;
import org.kie.server.controller.client.KieServerControllerClient;
import org.kie.server.controller.client.KieServerControllerClientFactory;
import org.kie.server.controller.client.event.EventHandler;

public class WebSocketEventsExample {

    private static final String URL = "ws://localhost:8080/my-controller/websocket/controller";
    private static final String USER = "baAdmin";
    private static final String PASSWORD = "password@1";

    public static void main(String[] args) {
        KieServerControllerClient client = KieServerControllerClientFactory.newWebSocketClient(URL,
                                                                                               USER,
                                                                                               PASSWORD,
                                                                                               MarshallingFormat.JSON,
                                                                                               new TestEventHandler());

        // Retrieve list of server templates
        final ServerTemplateList serverTemplateList = client.listServerTemplates();
        System.out.println(String.format("Found %s server template(s) at controller url: %s",
                                         serverTemplateList.getServerTemplates().length,
                                         URL));
        try {
            Thread.sleep(60 * 1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Set up event notifications
    static class TestEventHandler implements EventHandler {

        @Override
        public void onServerInstanceConnected(ServerInstanceConnected serverInstanceConnected) {
            System.out.println("serverInstanceConnected = " + serverInstanceConnected);
        }

        @Override
        public void onServerInstanceDeleted(ServerInstanceDeleted serverInstanceDeleted) {
            System.out.println("serverInstanceDeleted = " + serverInstanceDeleted);
        }

        @Override
        public void onServerInstanceDisconnected(ServerInstanceDisconnected serverInstanceDisconnected) {
            System.out.println("serverInstanceDisconnected = " + serverInstanceDisconnected);
        }

        @Override
        public void onServerTemplateDeleted(ServerTemplateDeleted serverTemplateDeleted) {
            System.out.println("serverTemplateDeleted = " + serverTemplateDeleted);
        }

        @Override
        public void onServerTemplateUpdated(ServerTemplateUpdated serverTemplateUpdated) {
            System.out.println("serverTemplateUpdated = " + serverTemplateUpdated);
        }

        @Override
        public void onServerInstanceUpdated(ServerInstanceUpdated serverInstanceUpdated) {
            System.out.println("serverInstanceUpdated = " + serverInstanceUpdated);
        }

        @Override
        public void onContainerSpecUpdated(ContainerSpecUpdated containerSpecUpdated) {
            System.out.println("onContainerSpecUpdated = " + containerSpecUpdated);
        }
    }
}

7.14. Securing password using key store

KIE server is using for some communication (e.g. REST api) basic authentication with passwords. From a security perspective it is not safe to store such passwords in clear text form on the disc. For this purpose a mechanism was developed to store passwords in a key store and then use it in the application.

7.14.1. Simple use case

User wants to secure his password for communicating via REST client. He creates new keystore where he will put his password, he will setup system variables with the info to the keystore and KIE will automatically load the keystore and will use the password for securing the communication.

7.14.2. Implementation and business logic

Current implementation is using key store if it is defined. If not, the functionality is falling back to old behavior using config parameters.

7.14.3. System requirements

To use a key store we need to create it first. As JKS is not supporting symmetric keys we have to create JCEKS key store. Moreover, password can be stored in a key store only for Java 8 and above. For generating a key store you can use standard tool KeyTool which is part of JDK installation.

7.14.4. Initialization of a key store

For keystore initialization we recommend to use keytool. Syntax is the following:

${JAVA_HOME}/bin/keytool -importpassword -keystore _keystore_url_ -keypass _alias_key_password_ -alias _password_alias_ -storepass _keystore_password_ -storetype JCEKS
  • alias - alias name of the entry to process

  • keypass - key password

  • keystore - keystore name

  • storepass - keystore password

  • storetype - keystore type

After running this command user will be asked to enter the password which he wants to store.

7.14.5. System parameters for loading key store

  • kie.keystore.keyStoreURL - URL to a keystore which should be used

  • kie.keystore.keyStorePwd - password to a keystore

  • kie.keystore.key.server.alias - alias of the key for REST services where password is stored

  • kie.keystore.key.server.pwd - password of an alias for REST services with stored password

  • kie.keystore.key.ctrl.alias - alias of the key for default REST KIE Server controller where password is stored

  • kie.keystore.key.ctrl.pwd - password of an alias for default REST KIE Server controller with stored password

7.14.6. Example

  1. create user and password in application server (it has to have kie-server role)

${EAP_HOME}/add-user.sh -a -e -u kieserver -p "kiePassword1!" -g kie-server
  1. use key tool to create keystore with password in it

${JAVA_HOME}/bin/keytool -importpassword -keystore /home/kie/keystores/droolsServer.jceks -keypass keypwd -alias droolsKey -storepass serverpwd -storetype JCEKS

Enter the password to be stored:
Re-enter password:

${JAVA_HOME}/bin/keytool -importpassword -keystore /home/kie/keystores/droolsServer.jceks -keypass keypwd -alias restKey -storepass serverpwd -storetype JCEKS

Enter the password to be stored:
Re-enter password:
  1. set following system properties on application server that will let the KIE Server or KIE Server controller to read password from keystore

    <system-properties>
        <property name="kie.keystore.keyStoreURL" value="file:///home/kie/keystores/droolsServer.jceks"/>
        <property name="kie.keystore.keyStorePwd" value="serverpwd"/>
        <property name="kie.keystore.key.server.alias" value="restKey"/>
        <property name="kie.keystore.key.server.pwd" value="keypwd"/>
        <property name="kie.keystore.key.ctrl.alias" value="droolsKey"/>
        <property name="kie.keystore.key.ctrl.pwd" value="keypwd"/>
    </system-properties>
  1. start server to verify configuration

7.15. Prometheus metrics monitoring in OptaPlanner

Prometheus is an open-source systems monitoring toolkit that you can use with OptaPlanner to collect and store metrics related to the execution of business rules, processes, Decision Model and Notation (DMN) models, and other OptaPlanner assets. You can access the stored metrics through a REST API call to the KIE Server, through the Prometheus expression browser, or using a data-graphing tool such as Grafana.

You can configure Prometheus metrics monitoring for an on-premise KIE Server instance, for KIE Server on Spring Boot, or for a KIE Server deployment on Red Hat OpenShift Container Platform.

For the list of available metrics that KIE Server exposes with Prometheus, see the KIE Server Prometheus Extension page in GitHub.

7.15.1. Configuring Prometheus metrics monitoring for KIE Server

You can configure your KIE Server instances to use Prometheus to collect and store metrics related to your business asset activity in OptaPlanner. For the list of available metrics that KIE Server exposes with Prometheus, see the KIE Server Prometheus Extension page in GitHub.

Prerequisites
  • KIE Server is installed.

  • You have kie-server user role access to KIE Server.

  • Prometheus is installed. For information about downloading and using Prometheus, see the Prometheus documentation page.

Procedure
  1. In your KIE Server instance, set the org.kie.prometheus.server.ext.disabled system property to false to enable the Prometheus extension. You can define this property when you start KIE Server or in the standalone.xml or standalone-full.xml file of OptaPlanner distribution.

  2. If you are running OptaPlanner on Spring Boot, configure the required key in the application.properties system property:

    Spring Boot application.properties key for OptaPlanner and Prometheus
    kieserver.drools.enabled=true
    kieserver.dmn.enabled=true
    kieserver.prometheus.enabled=true
  3. In the prometheus.yaml file of your Prometheus distribution, add the following settings in the scrape_configs section to configure Prometheus to scrape metrics from KIE Server:

    Scrape configurations in prometheus.yaml file
    scrape_configs:
      - job_name: 'kie-server'
        metrics_path: /SERVER_PATH/services/rest/metrics
        basicAuth:
          username: USER_NAME
          password: PASSWORD
        static_configs:
          - targets: ["HOST:PORT"]
    Scrape configurations in prometheus.yaml file for Spring Boot (if applicable)
    scrape_configs:
      - job_name: 'kie'
        metrics_path: /rest/metrics
        static_configs:
          - targets: ["HOST:PORT"]

    Replace the values according to your KIE Server location and settings.

  4. Start the KIE Server instance.

    After you start the configured KIE Server instance, Prometheus begins collecting metrics and KIE Server publishes the metrics to the REST API endpoint http://HOST:PORT/SERVER/services/rest/metrics (or on Spring Boot, to http://HOST:PORT/rest/metrics).

  5. In a REST client or curl utility, send a REST API request with the following components to verify that KIE Server is publishing the metrics:

    For REST client:

    • Authentication: Enter the user name and password of the KIE Server user with the kie-server role.

    • HTTP Headers: Set the following header:

      • Accept: application/json

    • HTTP method: Set to GET.

    • URL: Enter the KIE Server REST API base URL and metrics endpoint, such as http://localhost:8080/kie-server/services/rest/metrics (or on Spring Boot, http://localhost:8080/rest/metrics).

    For curl utility:

    • -u: Enter the user name and password of the KIE Server user with the kie-server role.

    • -H: Set the following header:

      • accept: application/json

    • -X: Set to GET.

    • URL: Enter the KIE Server REST API base URL and metrics endpoint, such as http://localhost:8080/kie-server/services/rest/metrics (or on Spring Boot, http://localhost:8080/rest/metrics).

    Example curl command for OptaPlanner on Red Hat JBoss EAP
    curl -u 'baAdmin:password@1' -X GET "http://localhost:8080/kie-server/services/rest/metrics"
    Example curl command for OptaPlanner on Spring Boot
    curl -u 'baAdmin:password@1' -X GET "http://localhost:8080/rest/metrics"
    Example server response
    # HELP kie_server_container_started_total Kie Server Started Containers
    # TYPE kie_server_container_started_total counter
    kie_server_container_started_total{container_id="task-assignment-kjar-1.0",} 1.0
    # HELP solvers_running Number of solvers currently running
    # TYPE solvers_running gauge
    solvers_running 0.0
    # HELP dmn_evaluate_decision_nanosecond DMN Evaluation Time
    # TYPE dmn_evaluate_decision_nanosecond histogram
    # HELP solver_duration_seconds Time in seconds it took solver to solve the constraint problem
    # TYPE solver_duration_seconds summary
    solver_duration_seconds_count{solver_id="100tasks-5employees.xml",} 1.0
    solver_duration_seconds_sum{solver_id="100tasks-5employees.xml",} 179.828255925
    solver_duration_seconds_count{solver_id="24tasks-8employees.xml",} 1.0
    solver_duration_seconds_sum{solver_id="24tasks-8employees.xml",} 179.995759653
    # HELP drl_match_fired_nanosecond Drools Firing Time
    # TYPE drl_match_fired_nanosecond histogram
    # HELP dmn_evaluate_failed_count DMN Evaluation Failed
    # TYPE dmn_evaluate_failed_count counter
    # HELP kie_server_start_time Kie Server Start Time
    # TYPE kie_server_start_time gauge
    kie_server_start_time{name="myapp-kieserver",server_id="myapp-kieserver",location="http://myapp-kieserver-demo-monitoring.127.0.0.1.nip.io:80/services/rest/server",version="7.4.0.redhat-20190428",} 1.557221271502E12
    # HELP kie_server_container_running_total Kie Server Running Containers
    # TYPE kie_server_container_running_total gauge
    kie_server_container_running_total{container_id="task-assignment-kjar-1.0",} 1.0
    # HELP solver_score_calculation_speed Number of moves per second for a particular solver solving the constraint problem
    # TYPE solver_score_calculation_speed summary
    solver_score_calculation_speed_count{solver_id="100tasks-5employees.xml",} 1.0
    solver_score_calculation_speed_sum{solver_id="100tasks-5employees.xml",} 6997.0
    solver_score_calculation_speed_count{solver_id="24tasks-8employees.xml",} 1.0
    solver_score_calculation_speed_sum{solver_id="24tasks-8employees.xml",} 19772.0

    If the metrics are not available in KIE Server, review and verify the KIE Server and Prometheus configurations described in this section.

    You can also interact with your collected metrics in the Prometheus expression browser at http://HOST:PORT/graph, or integrate your Prometheus data source with a data-graphing tool such as Grafana:

    prometheus expression browser data
    Figure 134. Prometheus expression browser with KIE Server metrics
    prometheus expression browser targets
    Figure 135. Prometheus expression browser with KIE Server target
    prometheus grafana data dmn
    Figure 136. Grafana dashboard with KIE Server metrics for DMN models
    prometheus grafana data optimizer
    Figure 137. Grafana dashboard with KIE Server metrics for solvers

7.15.2. Extending Prometheus metrics monitoring in KIE Server with custom metrics

After you configure your KIE Server instance to use Prometheus metrics monitoring, you can extend the Prometheus functionality in KIE Server to use custom metrics according to your business needs. Prometheus then collects and stores your custom metrics along with the default metrics that KIE Server exposes with Prometheus.

As an example, this procedure defines custom Decision Model and Notation (DMN) metrics to be collected and stored by Prometheus.

Prerequisites
Procedure
  1. Create an empty Maven project and define the following packaging type and dependencies in the pom.xml file for the project:

    Example pom.xml file in the sample project
    <packaging>jar</packaging>
    
    <properties>
      <version.org.kie>7.43.0.Final</version.org.kie>
    </properties>
    
    <dependencies>
      <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-api</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie.server</groupId>
        <artifactId>kie-server-api</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie.server</groupId>
        <artifactId>kie-server-services-common</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie.server</groupId>
        <artifactId>kie-server-services-drools</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie.server</groupId>
        <artifactId>kie-server-services-prometheus</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-dmn-api</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.kie</groupId>
        <artifactId>kie-dmn-core</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.jbpm</groupId>
        <artifactId>jbpm-services-api</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.jbpm</groupId>
        <artifactId>jbpm-executor</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>org.optaplanner</groupId>
        <artifactId>optaplanner-core</artifactId>
        <version>${version.org.kie}</version>
      </dependency>
      <dependency>
        <groupId>io.prometheus</groupId>
        <artifactId>simpleclient</artifactId>
        <version>0.5.0</version>
      </dependency>
    </dependencies>
  2. Implement the relevant listener from the org.kie.server.services.prometheus.PrometheusMetricsProvider interface as part of the custom listener class that defines your custom Prometheus metrics, as shown in the following example:

    Sample implementation of the DMNRuntimeEventListener listener in a custom listener class
    package org.kie.server.ext.prometheus;
    
    import io.prometheus.client.Gauge;
    import org.kie.dmn.api.core.ast.DecisionNode;
    import org.kie.dmn.api.core.event.AfterEvaluateBKMEvent;
    import org.kie.dmn.api.core.event.AfterEvaluateContextEntryEvent;
    import org.kie.dmn.api.core.event.AfterEvaluateDecisionEvent;
    import org.kie.dmn.api.core.event.AfterEvaluateDecisionServiceEvent;
    import org.kie.dmn.api.core.event.AfterEvaluateDecisionTableEvent;
    import org.kie.dmn.api.core.event.BeforeEvaluateBKMEvent;
    import org.kie.dmn.api.core.event.BeforeEvaluateContextEntryEvent;
    import org.kie.dmn.api.core.event.BeforeEvaluateDecisionEvent;
    import org.kie.dmn.api.core.event.BeforeEvaluateDecisionServiceEvent;
    import org.kie.dmn.api.core.event.BeforeEvaluateDecisionTableEvent;
    import org.kie.dmn.api.core.event.DMNRuntimeEventListener;
    import org.kie.server.api.model.ReleaseId;
    import org.kie.server.services.api.KieContainerInstance;
    
    public class ExampleCustomPrometheusMetricListener implements DMNRuntimeEventListener {
    
        private final KieContainerInstance kieContainer;
    
        private final Gauge randomGauge = Gauge.build()
                .name("random_gauge_nanosecond")
                .help("Random gauge as an example of custom KIE Prometheus metric")
                .labelNames("container_id", "group_id", "artifact_id", "version", "decision_namespace", "decision_name")
                .register();
    
        public ExampleCustomPrometheusMetricListener(KieContainerInstance containerInstance) {
            kieContainer = containerInstance;
        }
    
        public void beforeEvaluateDecision(BeforeEvaluateDecisionEvent e) {
        }
    
        public void afterEvaluateDecision(AfterEvaluateDecisionEvent e) {
            DecisionNode decisionNode = e.getDecision();
            ReleaseId releaseId = kieContainer.getResource().getReleaseId();
            randomGauge.labels(kieContainer.getContainerId(), releaseId.getGroupId(),
                               releaseId.getArtifactId(), releaseId.getVersion(),
                               decisionNode.getModelName(), decisionNode.getModelNamespace())
                    .set((int) (Math.random() * 100));
        }
    
        public void beforeEvaluateBKM(BeforeEvaluateBKMEvent event) {
        }
    
        public void afterEvaluateBKM(AfterEvaluateBKMEvent event) {
        }
    
        public void beforeEvaluateContextEntry(BeforeEvaluateContextEntryEvent event) {
        }
    
        public void afterEvaluateContextEntry(AfterEvaluateContextEntryEvent event) {
        }
    
        public void beforeEvaluateDecisionTable(BeforeEvaluateDecisionTableEvent event) {
        }
    
        public void afterEvaluateDecisionTable(AfterEvaluateDecisionTableEvent event) {
        }
    
        public void beforeEvaluateDecisionService(BeforeEvaluateDecisionServiceEvent event) {
        }
    
        public void afterEvaluateDecisionService(AfterEvaluateDecisionServiceEvent event) {
        }
    }

    The PrometheusMetricsProvider interface contains the required listeners for collecting Prometheus metrics. The interface is incorporated by the kie-server-services-prometheus dependency that you declared in your project pom.xml file.

    In this example, the ExampleCustomPrometheusMetricListener class implements the DMNRuntimeEventListener listener (from the PrometheusMetricsProvider interface) and defines the custom DMN metrics to be collected and stored by Prometheus.

  3. Implement the PrometheusMetricsProvider interface as part of a custom metrics provider class that associates your custom listener with the PrometheusMetricsProvider interface, as shown in the following example:

    Sample implementation of the PrometheusMetricsProvider interface in a custom metrics provider class
    package org.kie.server.ext.prometheus;
    
    import org.jbpm.executor.AsynchronousJobListener;
    import org.jbpm.services.api.DeploymentEventListener;
    import org.kie.api.event.rule.AgendaEventListener;
    import org.kie.api.event.rule.DefaultAgendaEventListener;
    import org.kie.dmn.api.core.event.DMNRuntimeEventListener;
    import org.kie.server.services.api.KieContainerInstance;
    import org.kie.server.services.prometheus.PrometheusMetricsProvider;
    import org.optaplanner.core.impl.phase.event.PhaseLifecycleListener;
    import org.optaplanner.core.impl.phase.event.PhaseLifecycleListenerAdapter;
    
    public class MyPrometheusMetricsProvider implements PrometheusMetricsProvider {
    
        public DMNRuntimeEventListener createDMNRuntimeEventListener(KieContainerInstance kContainer) {
            return new ExampleCustomPrometheusMetricListener(kContainer);
        }
    
        public AgendaEventListener createAgendaEventListener(String kieSessionId, KieContainerInstance kContainer) {
            return new DefaultAgendaEventListener();
        }
    
        public PhaseLifecycleListener createPhaseLifecycleListener(String solverId) {
            return new PhaseLifecycleListenerAdapter() {
            };
        }
    
        public AsynchronousJobListener createAsynchronousJobListener() {
            return null;
        }
    
        public DeploymentEventListener createDeploymentEventListener() {
            return null;
        }
    }

    In this example, the MyPrometheusMetricsProvider class implements the PrometheusMetricsProvider interface and includes your custom ExampleCustomPrometheusMetricListener listener class.

  4. To make the new metrics provider discoverable for KIE Server, create a META-INF/services/org.kie.server.services.prometheus.PrometheusMetricsProvider file in your Maven project and add the fully qualified class name of the PrometheusMetricsProvider implementation class within the file. For this example, the file contains the single line org.kie.server.ext.prometheus.MyPrometheusMetricsProvider.

  5. Build your project and copy the resulting JAR file into the ~/kie-server.war/WEB-INF/lib directory of your project.

  6. Start the KIE Server and deploy the built project to the running KIE Server. You can deploy the project using the Business Central interface or the KIE Server REST API (a PUT request to http://SERVER:PORT/kie-server/services/rest/server/containers/{containerId}).

    After your project is deployed on a running KIE Server, Prometheus begins collecting metrics and KIE Server publishes the metrics to the REST API endpoint http://HOST:PORT/SERVER/services/rest/metrics (or on Spring Boot, to http://HOST:PORT/rest/metrics).

7.16. Performance tuning considerations with KIE Server

The following key concepts or suggested practices can help you optimize KIE Server performance. These concepts are summarized in this section as a convenience and are explained in more detail in the cross-referenced documentation, where applicable. This section will expand or change as needed with new releases of OptaPlanner.

Ensure that development mode is enabled during development

You can set KIE Server or specific projects in Business Central to use production mode or development mode. By default, KIE Server and all new projects in Business Central are in development mode. This mode provides features that facilitate your development experience, such as flexible project deployment policies, and features that optimize KIE Server performance during development, such as disabled duplicate GAV detection. Use development mode until your OptaPlanner environment is established and completely ready for production mode.

For more information about configuring the environment mode or duplicate GAV detection, see the following resources:

Adapt KIE Server capabilities and extensions to your specific needs

The capabilities in KIE Server are determined by plug-in extensions that you can enable, disable, or further extend to meet your business needs. By default, KIE Server extensions are exposed through REST or JMS data transports and use predefined client APIs. You can extend existing KIE Server capabilities with additional REST endpoints, extend supported transport methods beyond REST or JMS, or extend functionality in the KIE Server client.

This flexibility in KIE Server functionality enables you to adapt your KIE Server instances to your business needs, instead of adapting your business needs to the default KIE Server capabilities.

For information about enabling, disabling, or extending KIE Server capabilities, see KIE Server capabilities and extensions.

7.17. KIE Server Task Assigning

7.17.1. Introduction to business processes

Business process management systems (BPMS) products such as jBPM have the ability to model and execute multiple business processes. A business process is typically composed of nodes such as events, gateways, and tasks that are connected to each other for defining the process flow. Every type of node has a specific semantic and is instantiated by the process runtime engine when a process instance is executed. Business processes that require human interaction are modelled by using human task nodes.

The following image shows a process where three tasks require human interaction:

PurchaseOrderProcessDefinition
Figure 138. Example process

It is usual for a system that executes several process instances to have many human task instances that are waiting for an external human action.

BPMDefaultAssignment
Figure 139. Default task list

OptaPlanner integrates with jBPM to provide the ability to assign human tasks to users as part of an optimized plan.

This is referred to as task assigning integration.

7.17.1.1. BPM standard task assigning

In general, business process runtime engines assign human tasks to users on a group basis. The target audience is usually included as part of the human task configuration.

The following image shows how the Review Purchase Order human task is configured with the PurchaseDepartment group:

ReviewPurchaseOrderTaskConfiguration
Figure 140. Human task configuration

At runtime, every time a new instance of the Review Purchase Order task is created it is automatically assigned to the PurchaseDepartment group with the status Ready. This makes the task automatically available to all users that belong to the group. All users in the group see it on their respective Task Inbox but none are the actual owner or responsible for the task. To be able to work with a particular task, a user must execute the claim operation to reserve the task for that user.

The following image shows an example of the claim operation execution for the task #152:

UserClaimsTask
Figure 141. User claims a task

When the claim operation is executed, the task status is changed to Reserved and the task is assigned to the claiming user. In the preceding example, the claimer of the task is wbadmin user. After the user claims the task, he is known as the task "actual owner”.

TaskClaimed
Figure 142. Task claimed by wbadmin

Although this is the standard procedure for most BPMS products, it is not flexible enough for all use cases. For example, this procedure does not work well with scenarios where an optimal distribution of a huge set of tasks between users by given criteria is required. In these cases, users usually find a large list of tasks up-front but do not have the knowledge to claim and execute them in the best way.

7.17.1.2. OptaPlanner driven task assigning

OptaPlanner and jBPM integration provides the ability to assign the human tasks produced by the process runtime engine between users according to an optimized plan. Instead of users having to claim the tasks, the tasks are assigned to them.

The following image shows how the tasks are assigned when integration is enabled.

TasksAlreadyDistributed
Figure 143. Assignments produced by OptaPlanner

The following assignments are shown:

  • User katy is assigned to tasks #150 and #148

  • User john is assigned to tasks #151 and #149

  • Tasks #152, #153, #154, #155, #156 and #157 are left un-assigned (these tasks will be analysed later)

Behind the scenes the following actions took place:

  1. All of the available tasks with the status "Ready" consumed by OptaPlanner.

  2. The users john and katy were identified as belonging to the "PurchaseDepartment" users group.

  3. It was identified that the "Review Purchase Order" tasks were identified as defined for the "PurchaseDepartment" group.

  4. An optimized plan was calculated and all of the tasks (including the "un-assigned" tasks) were assigned according to their configuration, for example group condition and OptaPlanner optimization rules. The resulting plan stated that:

    • Tasks #150 and #148 must be assigned to katy

    • Tasks #151 and #149 must be assigned to john

  5. OptaPlanner executed the correct process runtime actions to make these assignments happen. Note that the users were not required to execute the "claim" operation. Instead they can focus on completing their respective assigned work and leave the distribution and assignment work to OptaPlanner.

This simple example shows the main concept behind integration:

"OptaPlanner analyses the available work, calculates an optimized plan, and produces the necessary assignments in the process runtime. Users then rely on that plan and focus on executing their assigned work".

Unassigned tasks

Usually, a running BPM creates many process instances and many human tasks. At the same time, users are working and completing these human tasks. This cycle is repeated over and over.

OptaPlanner addresses this situation by re-calculating the optimized plan when new human tasks are created a/or completed and produce "new assignments" to reflect the new optimized plan. This is often achieved by combining different "Repeated Planning and Real Time Planning" techniques. For detailed information see the OptaPlanner documentation.

Additionally it might be the case that a plan that was optimal at time N is no longer optimal at time N+1. For example, a higher priority task has arrived and must be performed as soon as possible. The direct impact of this situation is that the programmed assignments at time N might change at time N+1, which means that tasks are routinely re-assigned many times when the new optimized plans are calculated. One of OptaPlanner’s strengths is the ability to react to a changing context.

User impact

If not controlled, continuous task re-assignment might negatively impact the user’s experience because they might feel that tasks come in and out of their workload randomly. This situation is present in other types of optimization problems as well and is usually managed by combining different repeated and continuous planning techniques. For detailed information see the "Repeated Planning" section of the OptaPlanner documentation.

A simple strategy is to introduce the concept of a planning window which is a defined subset of the available work that will not be changed or re-assigned even when new plans are calculated. Only this subset is available to users. The tasks in the planning window are called published tasks.

The previous example contains a planning window with a size of two. This means that only two tasks from the optimized plan are assigned in the processes runtime for each user so that users have at most two tasks assigned to them and they must focus on those two tasks. As soon they start completing these tasks OptaPlanner assigns them additional tasks according to the last optimized plan. However, internally OptaPlanner maintains information about the best assignments for all of the tasks and not only the published tasks.

This is how the assignments are distributed in the preceding example:

  • User katy is assigned to tasks #150 and #148 which belong to the planning window

  • User john is assigned to tasks #151 and #149 which belong to the planning window

  • The un-assigned tasks are outside of the planning window which means they are assigned only internally by OptaPlanner. As long as these tasks remain unpublished they can be reassigned if necessary during the different optimized plans calculation.

7.17.2. Configuring the integration

7.17.2.1. Product version

The current task assigning integration implementation is provided for the OptaPlanner, jBPM, and KIE Server 7.38.x+ series.

KIE Server provides many installation alternatives, for example controller driven servers, standalone servers, high availability, etc. The purpose of this guide is to show you how to configure your KIE Server installation for the task assigning integration.

For KIE Server and jBPM configuration information see their respective product documentation.

The following procedure is recommended:

  1. Install the KIE Servers topology that you require.

  2. If you are using the jBPM schema generation scripts be sure to execute the following sql script corresponding to the target database management system:

    jBPM installer → /db/ddl-scripts/<dbms_vendor>/task_assigning_tables_<dbms_vendor>.sql

    For example, in the case of a db2 database you must execute the following script:

    jBPM installer → /db/ddl-scripts/db2/task_assigning_tables_db2.sql

    For more information related to these scripts see jBPM documentation.

    Note: the reverse script in cases where the generated schema needs to be deleted can be found in the same location and has the following name: task_assigning_tables_drop_<dbms_vendor>.sql

  1. Be sure the process runtime is executing well.

  2. Install a dedicated Planning kie-server (see next topics).

  3. Complete the task assigning integration specific configuration parameters in all of the associated Process Runtime kie-servers and the Planning kie-server.

7.17.2.2. Simplified architecture

The following simplified architecture identifies the key components and configuration parameters for the task assigning integration.

SimplifiedArchitecture
Figure 144. Simplified architecture
Process Runtime kie-server

This is the KIE Server instance where the business processes execute. In clustered and high-availability configurations, multiple instances can be used.

The task assigning integration can manage multiple process runtime KIE Servers as long they share the same database where the process instances, human tasks instances, and so forth are stored and have the same set of deployed containers. In topologies where a KIE Server controller is configured this usually happens when they belong to the same KIE Server template. Be sure these statements are true before running the task assigning integration.

Planning kie-server

This is the KIE Server instance where OptaPlanner will execute, for example where the optimized plans and so forth, will be calculated and where the UserSystemService integration component will run. The task assigning integration requires a single dedicated KIE Server instance for this purpose. Be sure no other KIE Server extensions are enabled on this server.

7.17.2.3. Configuration parameters setup

All of the configuration parameters that are defined in the next topics are defined through the Java system properties. In Wildfly and Red Hat Enterprise Application Server (EAP) installations, these parameters are usually configured in the <system-properties> section of the selected configuration file, for example:

<server xmlns="urn:jboss:domain:8.0">
...
    <system-properties>
        ...
        <property name="org.kie.server.taskAssigning.runtime.ext.disabled" value="false"/>
        ...
    </system-properties>
...
</server>

You can also use other methods of setting system properties, for example passing JVM parameters on the command line:

-Dorg.kie.server.taskAssigning.runtime.ext.disabled=false

It is recommended to use the same configuration method for all KIE Server required parameters.

7.17.2.4. Process Runtime kie-server configuration

The following table shows the only parameter that must be configured in all of the Process Runtime kie-servers in the target topology.

Parameter Requirement Description

org.kie.server.taskAssigning.runtime.ext.disabled

Not required

The default value is "true", meaning that the task assigning integration is always disabled.

Must be set to "false" for making it work.

Process Runtime kie-server Wildfly/EAP configuration example
<server>
...
    <system-properties>
       ...
        <property name="org.kie.server.taskAssigning.runtime.ext.disabled" value="false"/>
       ...
    </system-properties>
...
</server>
7.17.2.5. Planning kie-server configuration

The following topics explain the parameters that you must configure in the Planning kie-server. Whatever the target topology is, only one instance of this server will exist.

The parameters tagged as "Required" must be set only in cases where the task assigning integration is enabled. Some of them have a default value that automatically applies when not set.

Global configuration parameters
Parameter Requirement Description

org.kie.server.taskAssigning.planning.ext.disabled

Not required

The default value is "true", meaning that the task assigning integration is always disabled.

Must be set to "false" for making it work.

org.kie.server.services.taskAssigning.core.model.planningUserId

Required

The default value is "planninguser".

This value configures the user for being assigned with the tasks that no other user in the system can be assigned to.

For example If a task has a required skill "astronaut" and no user can be found with this skill, it will be assigned to the planninguser.

But it is not only restricted to skills, another example might be a task configured for a users group "Finance". If no user exists in that group it will be assigned to the planning user.

It is strongly recommended that the planning user has the required human tasks administration grants in all of the target Process Runtime kie-servers. By doing so it can easily proceed to track and eventually re-assign the tasks that couldn’t be managed by the tasks assigning integration.

Note: it is recommended to keep this name.

org.kie.server.taskAssigning.processRuntime.url

Required

The default value is http://localhost:8080/kie-server/services/rest/server

This value configures the URL for connecting to the Process Runtime kie-server rest services.

In a clustered environment a list of "|" separated urls can be used for doing load balancing between the different Process Runtime kie-servers.

org.kie.server.taskAssigning.processRuntime.user

Required

The default value is wbadmin

This value configures the user id for connecting to the Process Runtime kie-server. In a clustered environment it must exist in all of the configured target servers.

The configured user must belong to the human tasks administration group. This group is usually found by looking at the target Process Runtine kie-server configuration parameter:

<property name="org.jbpm.ht.admin.group" value="process-admin"/>

Following the example above the configured user must belong to the group "process-admin"

org.kie.server.taskAssigning.processRuntime.pwd

Required

No default value is set.

This value configures the password for the user configured in org.kie.server.taskAssigning.processRuntime.user parameter.

org.kie.server.taskAssigning.processRuntime.targetUser

Required

No default value is set.

This value configures the user ID used to execute the process runtime operations "on behalf of", and is usually the same as the value of the org.kie.server.taskAssigning.processRuntime.user parameter

org.kie.server.taskAssigning.processRuntime.key.alias

Not Required

No default value is set.

This parameter can be used in cases where it is required to get the runtime user password from the KIE Server keystore and represents the alias for locating it.

org.kie.server.taskAssigning.processRuntime.key.pwd

Not Required

No default value is set.

This parameter must be used in cases where the runtime user password is stored in the KIE Server keystore, and represents the password for accessing the corresponding keystore entry.

kie.keystore.keyStoreURL

Not Required

No default value is set.

URL for the JCEKS that you want to use, for example file:///home/kie/keystores/keystore.jceks

kie.keystore.keyStorePwd

Not Required

No default value is set.

Password for the JCEKS

org.kie.server.taskAssigning.processRuntime.timeout

Not Required

The default value is 90000.

This value configures the timeout in milliseconds for the operation invocations on the Process runtime kie-server.

org.kie.server.taskAssigning.runtimeDelegate.pageSize

Not Required

The default value is 3000.

This value configures the page size for the paged queries. The default value is good for most scenarios and it’s not recommended to be modified unless specific fine tunings are required.

org.kie.server.taskAssigning.solutionSyncInterval

Required

The default value is "PT2S" (two seconds).

This value configures the time interval for the tasks information refreshing from the Process Runtime kie-server.

The accepted format is based on the ISO-8601 duration format PnDTnHnMn.nS with days considered to be exactly 24 hours. For example:

"PT1.500S": configures 1500 milliseconds.

"PT0.500S": configures 500 milliseconds.

"PT3S": configures 3000 milliseconds.

org.kie.server.taskAssigning.solutionSyncQueriesShift

Required

The default value is "PT10M"

This value configures a timeshift for adjusting the tasks information refreshing queries. In most cases it should never be modified and should not be less than PT5M (five minutes).

The accepted format is based on the ISO-8601 duration format PnDTnHnMn.nS with days considered to be exactly 24 hours.

org.kie.server.taskAssigning.publishWindowSize

Required

The default value is 2.

This value configures the maximum amount of tasks per user that will be assigned to it in the Process Runtime kie-server when an optimized plan is calculated. See "published tasks"

This value should usually be low 2, 3, or 4, since it is expected that the tasks will be assigned to the users according to an optimized plan that is changing over the time. High values might lead into the BPM Standard task assigning which could make the tasks assigning integration senseless.

org.kie.server.taskAssigning.usersSyncInterval

Required

The default value is "PT2H" (two hours)

This value configures the time interval for the user’s information refreshing from the UserSystemService integration component.

The accepted format is based on the ISO-8601 duration format PnDTnHnMn.nS with days considered to be exactly 24 hours.

org.kie.server.taskAssigning.waitForImprovedSolutionDuration

Not Required

The default value is "PT0S" (no wait)

This value configures the time interval to improve a solution before the corresponding optimized plan is sent to the Process Runtime kie-server.

Because this wait time is applied every time a new set of changes is processed it should usually be short, for example "PT0.500" (500 milliseconds). Use it in cases when early improvements are desired.

The accepted format is based on the ISO-8601 duration format PnDTnHnMn.nS with days considered to be exactly 24 hours.

org.kie.server.taskAssigning.improveSolutionOnBackgroundDuration

Not Required

The default value is "PT1M" (one minute)

This value configures the time interval for doing a background optimization of the current solution after the corresponding optimized plan is sent to the Process Runtime kie-server.

In situations where no changes in the processes are produced and a better solution is calculated during that period, the new optimized plan is automatically sent to the Process Runtime kie-server.

The accepted format is based on the ISO-8601 duration format PnDTnHnMn.nS with days considered to be exactly 24 hours.

Solver configuration parameters

As it was mentioned, the task assigning integration delegates the calculation of "which tasks must be assigned to whom" to OptaPlanner and it will resolve this requirement by producing an optimized plan. This plan is calculated by using a Solver with a set of configured constraints. See OptaPlanner product documentation for more information.

Two mechanisms are available for configuring the OptaPlanner’s Solver specifics.

Note: The parameter tagged as "Required" must have a value independently of the selected Solver configuration mechanism.

Class path based solver configuration

This mechanism implements the ability of configuring the Solver by using a class path resource.

Parameter Requirement Description

org.kie.server.taskAssigning.solver.configResource

Required

The default value is: "org/kie/server/services/taskassigning/solver/taskAssigningDefaultSolverConfig.xml"

This value configures the path to a class-path resource with the Solver configuration.

If the resource can’t be found or the configuration is wrong, a controlled error will be added to the Planning kie-server error messages and the task assigning integration won’t be initialized. The KIE Server’s APIs can be used for querying these error messages and checking the status.

org.kie.server.taskAssigning.solver.moveThreadCount

Not Required

The default value is AUTO.

This value configures the solver’s ability of using multithreaded incremental solving.

For more information see OptaPlanner documentation.

Note: when the container based solver configuration is used this value is not considered, the configuration provided in the KJAR is used instead.

org.kie.server.taskAssigning.solver.moveThreadBufferSize

Not Required

No default value is set.

This value power tweaks the number of moves that are selected but won’t be foraged when multithreaded incremental solving is used. Setting it too low reduces performance, but setting it too high too. Unless you’re deeply familiar with the inner workings of multithreaded solving, don’t configure this parameter.

For more information see OptaPlanner documentation.

Note: when the container based solver configuration is used this value is not considered, the configuration provided in the KJAR is used instead.

org.kie.server.taskAssigning.solver.threadFactoryClass

Not Required

No default value is set.

The threadFactoryClass allows you to plug in a custom ThreadFactory for environments where arbitrary thread creation should be avoided.

For more information see OptaPlanner documentation.

Note: when the container based solver configuration is used this value is not considered, the configuration provided in the KJAR is used instead.

The default solver configuration includes a set of constraints for implementing optimized task assigning, therefore it is not necessary to provide a different set of constraints in most cases. Use cases that require specific tunings, for example related to business data, can use this alternative. However it is recommended to use a Container based configuration for these purposes.

Container based solver configuration

This mechanism implements the ability to configure the Solver by using a container. Finally, given that the KIE Server architecture is based on containers this is usually the recommended approach. However in many of the use cases the by default configuration is good enough and no container configuration is necessary see Default Constraints

The following table shows the container-based configuration parameters:

Parameter Requirement Description

org.kie.server.taskAssigning.solver.container.id

Not Required

No default value is set.

This value configures the Identifier of the container to use.

When set the container based configuration will be activated and the following container related parameters are required.

org.kie.server.taskAssigning.solver.container.groupId

Required if the container configuration is activated

No default value is set.

This value configures the Maven groupId of the artifact to use for creating the container when needed.

org.kie.server.taskAssigning.solver.container.artifactId

Required if the container configuration is activated

No default value is set.

This value configures the Maven artifactId for the artifact to use for creating the container when needed.

org.kie.server.taskAssigning.solver.container.version

Required if the container configuration is activated

No default value is set.

This value configures the Maven version for the artifact to use for creating the container when needed.

org.kie.server.taskAssigning.solver.configResource

Required if the container configuration is activated

This value configures the path to the resource with the Solver configuration in the container class-path.

In case of errors, analogous to the "Class path based solver configuration" proper KIE Server error messages will be generated and the task assigning integration won’t be initialized. The KIE Server’s apis can be used for querying these error messages and checking the status.

UserSystemService integration component

Calculating an optimized plan for assigning tasks to users often requires considering business related information. Common examples, included in the current task assigning integration version, are the usage of the groups, the skills that a given user has or the affinities in certain topics, etc. See Skills and Affinities. This business oriented information must be provided by each particular installation and is delegated to the UserSystemService integration component. It is up to the tasks assigning integrator to provide this component.

UserSystemService API

A user system service component must implement the following API.

public interface UserSystemService {

    /**
     * Invoked by the task assigning integration as part of the initialization procedure and
     * before any other method is invoked.
     */
    void start();

    /**
     * Invoked by the task assigning integration as part of the initialization procedure and
     * after the start() method is invoked.
     * @throws Exception if the test method failed.
     */
    void test() throws Exception;

    /**
     * @return the name of the UserSystemService implementation.
     */
    String getName();

    /**
     * @return the list of all users present in the external user system. This method is normally
     * invoked each time the solver is initialized or when the users information is updated from
     * the external user system.
     */
    List<User> findAllUsers();

    /**
     * Get the user information for a particular user.
     * @param id user identifier for querying.
     * @return the User corresponding to the given identifier, null if no user was found.
     */
    User findUser(String id);
}
UserSystemService configuration

Analogous to the Solver configuration two mechanisms are available for configuring the UserSystemService and in both cases the standard Java SPI (Service Provider Interface) and ServiceLoader mechanisms are used for its instantiation.

Class path based UserSystemService configuration

Use the following resource for configuring the different UserSystemService provider implementations:

META-INF/services/org.kie.server.services.taskassigning.user.system.api.UserSystemService

And finally add the following configuration parameters for configuring the selected implementation:

Parameter Requirement Description

org.kie.server.taskAssigning.userSystem.name

Required

No default value is set.

This value configures the name of the UserSystemService provider instance to use.

See: UserSystemService.getName()

All of the configured providers are loaded from the application class-path and the one that matches with the configured name will be used.

A simple user system service implementation is provided see SimpleUserSystemService

Container based UserSystemService configuration

Use the following resource in your Kie Module (KJAR) to configure the different UserSystemService provider implementations:

project_home/src/main/resources/META-INF/services/org.kie.server.services.taskassigning.user.system.api.UserSystemService

And finally add the following configuration parameters for configuring the selected implementation:

Parameter Requirement Description

org.kie.server.taskAssigning.userSystem.name

Required

No default value is set.

This value configures the name of the UserSystemService provider instance to use.

See: UserSystemService.getName()

org.kie.server.taskAssigning.userSystem.container.id

Not Required

No default value is set.

This value configures the Identifier of the container to use.

When set the container based configuration will be activated and all of the potential UserSystemService providers that might be defined in the container class-path will be considered for selection, additionally to the ones in the application class-path.

The following parameters will be required.

org.kie.server.taskAssigning.userSystem.container.groupId

Required if the container configuration is activated.

No default value is set.

This value configures the Maven groupId of the artifact to use for creating the container when needed.

org.kie.server.taskAssigning.userSystem.container.artifactId

Required if the container configuration is activated.

No default value is set.

This value configures the Maven artifactId for the artifact to use for creating the container when needed.

org.kie.server.taskAssigning.userSystem.container.version

Required if the container configuration is activated.

No default value is set.

This value configures the Maven version for the artifact to use for creating the container when needed.

In case of errors, for example if the configured provider name was not found, the container couldn’t be instantiated, etc, a controlled error will be added to the Planning kie-server error messages and the task assigning integration won’t be initialized. The KIE Server’s apis can be used for querying these error messages and checking the status.

SimpleUserSystemService

The SimpleUserSystemService is a basic UserSystemService implementation that loads the user definitions, skills and affinities from Java properties file in the format used by the Wildfly/EAP application servers. This implementation is always present in the Planning kie-server and is intended mainly for development and testing purposes.

The following example shows a user definitions file:

katy=analyst,HR
john=IT,Developer

In this example, two users are defined:

  • User katy that belongs to the groups analyst and HR

  • User john that belongs to the groups IT and Developer

The following parameters can be used to configure it:

Parameter Requirement Description

org.kie.server.taskAssigning.userSystem.name

Required

Must be the value SimpleUserSystemService

org.kie.server.services.taskassigning.user.system.simple.users

Required

This value configures a Planning kie-server web application accessible path with the user definitions file.

For example in Wildfly/EAP installations can be like this.

${jboss.server.config.dir}/roles.properties

Note: the configured file must have the same values as the roles.properties files of the Process Runtime kie-servers in the target topology.

org.kie.server.services.taskassigning.user.system.simple.skills

Not Required

This value configures a Planning kie-server web application accessible path with the users skills definitions if desired, see Skills and Affinities.

For example in Wildfly/EAP installations can be like this.

${jboss.server.config.dir}/skills.properties

Note: the format is analogous to the user definitions file.

katy=skill1,skill2 john=skill1,skill2

org.kie.server.services.taskassigning.user.system.simple.affinities

Not Required

This value configures a Planning kie-server web application accessible path with the users affinities definition if desired, Skills and Affinities.

For example in Wildfly/EAP installations can be like this.

${jboss.server.config.dir}/affinities.properties

Note: the format is analogous to the user definitions file.

katy=affinity1,affinity4 In this example john has no affinities.

Planning kie-server Wildfly/EAP configuration example

Below is an extract of the task assigning configuration parameters for a Wildfly/EAP server.

<server>
...
<system-properties>
...
  <!-- the following kie-server extensions must be disabled in the Planning kie-server -->
  <property name="org.optaplanner.server.ext.disabled" value="true"/>
  <property name="org.jbpm.server.ext.disabled" value="true"/>
  <property name="org.jbpm.ui.server.ext.disabled" value="true"/>
  <property name="org.jbpm.case.server.ext.disabled" value="true"/>
  <property name="org.kie.dmn.server.ext.disabled" value="true"/>
  <property name="org.kie.swagger.server.ext.disabled" value="true"/>

  <!-- enable the TaskAssigningPlanningKieServerExtension -->
  <property name="org.kie.server.taskAssigning.planning.ext.disabled" value="false"/>

  <property name="org.kie.server.taskAssigning.processRuntime.url"
            value="http://localhost:8080/kie-server/services/rest/server"/>
  <property name="org.kie.server.taskAssigning.processRuntime.user" value="wbadmin"/>
  <property name="org.kie.server.taskAssigning.processRuntime.pwd" value="wbadmin"/>
  <property name="org.kie.server.taskAssigning.processRuntime.targetUser" value="wbadmin"/>
  <property name="org.kie.server.taskAssigning.solutionSyncInterval" value="PT2S"/>

  <!-- example of a Solver configuration based on a user provided kjar -->
  <!--
  <property name="org.kie.server.taskAssigning.solver.configResource" value="org/kie/server/services/taskassigning/solver/taskAssigningDefaultSolverConfig.xml"/>
  <property name="org.kie.server.taskAssigning.solver.container.id"
            value="kie-server-task-assigning-default-planner-kjar-container"/>
  <property name="org.kie.server.taskAssigning.solver.container.groupId" value="org.kie.server"/>
  <property name="org.kie.server.taskAssigning.solver.container.artifactId"
            value="kie-server-task-assigning-default-planner-kjar"/>
  <property name="org.kie.server.taskAssigning.solver.container.version" value="X.XX.XXX"/>
  -->

  <!-- default SimpleUserSystemService configuration -->
  <property name="org.kie.server.taskAssigning.userSystem.name" value="SimpleUserSystemService"/>
  <property name="org.kie.server.services.taskassigning.user.system.simple.users"
            value="${jboss.server.config.dir}/roles.properties"/>

  <!-- un-comment and configure if skills information will be loaded -->
  <!--
  <property name="org.kie.server.services.taskassigning.user.system.simple.skills"
            value="${jboss.server.config.dir}/skills.properties"/>
  -->

  <!-- un-comment and configure if affinities information will be loaded -->
  <!--
  <property name="org.kie.server.services.taskassigning.user.system.simple.affinities"
            value="${jboss.server.config.dir}/affinities.properties"/>
  -->
  <!-- end of default SimpleUserSystemService configuration -->

  <!-- example of a UserSystemService configuration based on a user provided kjar -->
  <!--
  <property name="org.kie.server.taskAssigning.userSystem.name"
            value="SimpleUserSystemServiceByKjar"/>
  <property name="org.kie.server.taskAssigning.userSystem.container.id"
            value="task-assigning-user-system-service-simple-by-kjar-container"/>
  <property name="org.kie.server.taskAssigning.userSystem.container.groupId"
            value="org.kie.server"/>
  <property name="org.kie.server.taskAssigning.userSystem.container.artifactId"
            value="kie-server-task-assigning-user-system-simple-kjar"/>
  <property name="org.kie.server.taskAssigning.userSystem.container.version" value="X.XX.XXX"/>
  -->
...
</system-properties>
...
</server>
Spring Boot configuration

When the KIE Server Spring Boot Starter version is used the following configuration parameters are used to configure the task assigning integration. These parameters are usually configured in the corresponding Spring Boot application.properties file. The same statements as for standard KIE Server topologies apply in this case.

Parameter Requirement Description

kieserver.taskAssigning.runtime.enabled

Required

Must be set to "true" in order to enable the task assigning integration in the Process Runtime kie-server

kieserver.taskAssigning.planning.enabled

Required

Must be set to "true" in order to enable the task assigning integration in the Planning kie-server

taskassigning.core.model.planningUserId

Required

This value is analogous to the org.kie.server.services.taskAssigning.core.model.planningUserId configuration parameter, see Global configuration parameters

taskassigning.processRuntime.url

Required

This value is analogous to the org.kie.server.taskAssigning.processRuntime.url configuration parameter, see Global configuration parameters

taskassigning.processRuntime.user

Required

This value is analogous to the org.kie.server.taskAssigning.processRuntime.user configuration parameter, see Global configuration parameters

taskassigning.processRuntime.pwd

Required

This value is analogous to the org.kie.server.taskAssigning.processRuntime.pwd configuration parameter, see Global configuration parameters

taskassigning.processRuntime.targetUser

Required

This value is analogous to the org.kie.server.taskAssigning.processRuntime.targetUser configuration parameter, see Global configuration parameters

taskassigning.processRuntime.key.alias

Not Required

This value is analogous to the org.kie.server.taskAssigning.processRuntime.key.alias configuration parameter, see Global configuration parameters

taskassigning.processRuntime.key.pwd

Not Required

This value is analogous to the org.kie.server.taskAssigning.processRuntime.key.pwd configuration parameter, see Global configuration parameters

taskassigning.processRuntime.timeout

Not Required

This value is analogous to the org.kie.server.taskAssigning.processRuntime.timeout configuration parameter, see Global configuration parameters

taskassigning.runtimeDelegate.pageSize

Not Required

This value is analogous to the org.kie.server.taskAssigning.runtimeDelegate.pageSize configuration parameter, see Global configuration parameters

taskassigning.solutionSyncInterval

Required

This value is analogous to the org.kie.server.taskAssigning.solutionSyncInterval configuration parameter, see Global configuration parameters

taskassigning.solutionSyncQueriesShift

Required

This value is analogous to the org.kie.server.taskAssigning.solutionSyncQueriesShift configuration parameter, see Global configuration parameters

taskassigning.publishWindowSize

Required

This value is analogous to the org.kie.server.taskAssigning.publishWindowSize configuration parameter, see Global configuration parameters

taskassigning.usersSyncInterval

Required

This value is analogous to the org.kie.server.taskAssigning.usersSyncInterval configuration parameter, see Global configuration parameters

taskassigning.waitForImprovedSolutionDuration

Not Required

This value is analogous to the org.kie.server.taskAssigning.waitForImprovedSolutionDuration configuration parameter, see Global configuration parameters

taskassigning.improveSolutionOnBackgroundDuration

Not Required

This value is analogous to the org.kie.server.taskAssigning.improveSolutionOnBackgroundDuration configuration parameter, see Global configuration parameters

taskassigning.solver.configResource

Required

This value is analogous to the org.kie.server.taskAssigning.solver.configResource configuration parameter, see Solver configuration parameters

taskassigning.solver.moveThreadCount

Not Required

This value is analogous to the org.kie.server.taskAssigning.solver.moveThreadCount configuration parameter, see Solver configuration parameters

taskassigning.solver.moveThreadBufferSize

Not Required

This value is analogous to the org.kie.server.taskAssigning.solver.moveThreadBufferSize configuration parameter, see Solver configuration parameters

taskassigning.solver.threadFactoryClass

Not Required

This value is analogous to the org.kie.server.taskAssigning.solver.threadFactoryClass configuration parameter, see Solver configuration parameters

taskassigning.solver.container.id

Not Required

This value is analogous to the org.kie.server.taskAssigning.solver.container.id configuration parameter, see Container based solver configuration

taskassigning.solver.container.groupId

Required if the container configuration is activated

This value is analogous to the org.kie.server.taskAssigning.solver.container.groupId configuration parameter, see Container based solver configuration

taskassigning.solver.container.artifactId

Required if the container configuration is activated

This value is analogous to the org.kie.server.taskAssigning.solver.container.artifactId configuration parameter, see Container based solver configuration

taskassigning.solver.container.version

Required if the container configuration is activated

This value is analogous to the org.kie.server.taskAssigning.solver.container.version configuration parameter, see Container based solver configuration

taskassigning.solver.configResource

Required if the container configuration is activated

This value is analogous to the org.kie.server.taskAssigning.solver.configResource configuration parameter, see Container based solver configuration

taskassigning.userSystem.name

Required

This value is analogous to the org.kie.server.taskAssigning.userSystem.name configuration parameter, see UserSystemService configuration

taskassigning.userSystem.container.id

Not Required

This value is analogous to the org.kie.server.taskAssigning.userSystem.container.id configuration parameter, see Container based UserSystemService configuration

taskassigning.userSystem.container.groupId

Required if the container configuration is activated

This value is analogous to the org.kie.server.taskAssigning.userSystem.container.groupId configuration parameter, see Container based UserSystemService configuration

taskassigning.userSystem.container.artifactId

Required if the container configuration is activated

This value is analogous to the org.kie.server.taskAssigning.userSystem.container.artifactId configuration parameter, see Container based UserSystemService configuration

taskassigning.userSystem.container.version

Required if the container configuration is activated

This value is analogous to the org.kie.server.taskAssigning.userSystem.container.version configuration parameter, see Container based UserSystemService configuration

tastaskassigning.userSystem.simple.users

Required if the Simple User System is configured

This value is analogous to the org.kie.server.services.taskassigning.user.system.simple.users configuration parameter, see SimpleUserSystemService

taskassigning.userSystem.simple.skills

Not Required

This value is analogous to the org.kie.server.services.taskassigning.user.system.simple.skills configuration parameter, see SimpleUserSystemService

taskassigning.userSystem.simple.affinities

Not Required

This value is analogous to the org.kie.server.services.taskassigning.user.system.simple.affinities configuration parameter, see see SimpleUserSystemService

Default Constraints

The following table gives a high level description of the set of constraints that are included in the task assigning integration. These constraints are used for the construction of the optimized plan, in other words "for determining which tasks should be assigned to whom".

In general a large set of use cases can be covered by using them and no extensions are required, but it is possible to work with a user provided-customized set of constraints if needed, see Container based solver configuration.

Optimized solutions construction is made by using a BendableLongScore with two levels of Hard constraints and six levels of Soft constraints. These constraint levels can be customized by following a set of restrictions.

Constraint Level/Requirement Description

Required Potential Owner

Hard Constraint 0 (required)

Determines that a task must be assigned to one of it is "Potential Owners", or to the "Planning User" in cases where no "Potential Owners" are found.

User provided customizations must always include this constraint as the first level hard constraint. Otherwise the business process semantics won’t be considered by the task assigning integration, i.e., tasks might be assigned to users that are not "Potential Owners" for it.

In cases where this constraint is still customized, it must always consider assigning the "Planning User" when no other user fits the customized condition.

Required Skills

Hard Constraint 1

Determines that a task can only be assigned to a user that has all of the task’s configured skills, see Skills and Affinities.

If a task has configured skills but no user with all of these skills can be found it’ll be assigned to the "Planning User".

If the task doesn’t have configured skills the constraint has no effect.

In cases where this constraint is customized, it must always consider assigning the "Planning User" when no other user fits the customized condition.

PlanningUser assignment

Soft Constraint 0 (required)

Penalizes the "Planning User" assignment. This constraint enforces the minimization of the "Planning User" assignment and ensures it’ll be assigned as the "last available option"

Do not customize or change this constraint.

High level priority

Soft Constraint 1

Enforces the assignment of higher priority tasks first whenever it is possible.

Desired Affinities

Soft Constraint 2

Makes a best effort for assigning tasks according to its configured affinities, see Skills and Affinities

If a task has configured affinities, whenever it is possible, a user with the most of them will be picked for its assignment.

If the task doesn’t have configured affinities the constraint has no effect.

Minimize makespan

Soft Constraint 3 (required)

Reduce the time to complete all tasks.

This constraint must always be included.

Medium level priority

Soft Constraint 4

Medium level priority tasks are assigned after higher priority tasks whenever it is possible.

Low level priority

Soft Constraint 5

Low level priority tasks are assigned lastly whenever it is possible.

The current TaskAssigningSolution implementation is based on a BendableLongScore scoring function and thus any potential extension of the provided constraints, etc., typically by using a user provided KJAR, will be based on it. However this scoring function as well as the core model classes might change in future releases.

Constraints configuration by using a DRL file

The following example shows the key parts of the DRL file that contains the constraints configurations.

// ############################################################################
// Hard constraints
// ############################################################################

// A task can only be assigned to one of its potential owners or to the PlanningUser
rule "Required Potential Owner"
   when
       $task : Task(user != null, !TaskAssigningConditions.userMeetsPotentialOwnerOrPlanningUserCondition($task, user))
   then
       scoreHolder.addHardConstraintMatch(kcontext, 0, -1);
end

// A task with defined skills can only be assigned to users that has all of the of them or to the PlanningUser
rule "Required Skills"
   when
       $task : Task(user != null, !TaskAssigningConditions.userMeetsRequiredSkillsOrPlanningUserCondition($task, user))
   then
       scoreHolder.addHardConstraintMatch(kcontext, 1, -1);
end

// ############################################################################
// Soft constraints
// ############################################################################

// First level soft constraint for penalizing the assignment of the PLANNING_USER.
rule "PlanningUser assignment"
   when
       Task(user != null, ModelConstants.IS_PLANNING_USER.test(user.getEntityId()))
   then
       // a penalization is added each time the PLANNING_USER is assigned.
       scoreHolder.addSoftConstraintMatch(kcontext, 0, -1);
end

// Second level soft constraint for penalizing the assignment of the PLANNING_USER.
rule "High level priority"
   when
       $task : Task(user != null, PriorityHelper.isHighLevel(priority))
   then
       scoreHolder.addSoftConstraintMatch(kcontext, 1, PriorityHelper.calculateWeightedPenalty($task.getPriority(), $task.getEndTimeInMinutes()));
end


// Third level soft constraint, when a task has defined affinities consider assigning users that match
// the most of them as possible.
rule "Desired Affinities"
   when
       $task : Task(user != null, user.isEnabled())
   then
       scoreHolder.addSoftConstraintMatch(kcontext, 2, TaskHelper.countMatchingLabels($task, $task.getUser(), DefaultLabels.AFFINITIES.name()));
end

// Fourth level soft constraint.
rule "Minimize makespan (starting with the latest ending user first)"
   when
       Task(user != null, nextTask == null, $endTimeInMinutes : endTimeInMinutes)
   then
       scoreHolder.addSoftConstraintMatch(kcontext, 3, - ($endTimeInMinutes * $endTimeInMinutes));
end

// Fifth level soft constraint.
rule "Medium level priority"
   when
       $task : Task(user != null, PriorityHelper.isMediumLevel(priority))
   then
       scoreHolder.addSoftConstraintMatch(kcontext, 4, PriorityHelper.calculateWeightedPenalty($task.getPriority(), $task.getEndTimeInMinutes()));
end

// Sixth level soft constraint.
rule "Low level priority"
   when
       $task : Task(user != null, PriorityHelper.isLowLevel(priority))
   then
       scoreHolder.addSoftConstraintMatch(kcontext, 5, PriorityHelper.calculateWeightedPenalty($task.getPriority(), $task.getEndTimeInMinutes()));
end

The current by default DRL might change in future versions and thus can not be considered as part of the product public API. Any potential customization of the provided constraints might use this DRL as a start point or could also use other mechanisms as the constraints streams for implementing them.

Skills and Affinities

The use of skills and affinities implements the ability of declaring business related data for being considered by the default provided constraints or any other user defined ones. This is a fine grained decision mechanism that you can use on top of the groups-based assignment semantics defined in the business process.

Internally, this mechanism is based on the ability to label the human tasks generated by the business processes runtime and the users information.

Labeling mechanism

The following procedure shows how the labeling mechanism converts information in human tasks, and users information to labels:

LabelingMechanismTasks
Figure 145. Tasks Labeling
  1. Any human task is created in the processes runtime.

  2. When the new task is detected by the task assigning solution refreshing mechanism, a set of LabelValueExtrators is applied.

  3. These LabelValueExtractors can transform any piece of information in the human task or user into a label.

  4. The default constraints consider these labels.

In the preceding example,the following labels are produced:

  • The input data "skills", with the value "skill1, skill2" resulted in the label SKILLS with the following set of values {"skill1", "skill2"}

  • The input data "affinities" with the value "affinity1" resulted in the label AFFINITIES with the following set of values {"affinity1"}

Task labels are calculated only the first time the task is identified by the task assigning integration and can use any of the information present in the task.

User labeling works in a similar way:

LabelingMechanismUsers
Figure 146. Tasks Labeling
Default HumanTask and User LabelValueExtractors

Four label value extractors are provided to manage the SKILLS and AFFINITIES labels.

Extractor Name Description

DefaultTaskDataSkillsValueExtractor

Processes the human task "skills" input value as a string of comma separated values, and creates a java Set<Object> with tokenized String values. The resulting set is assigned to the label SKILLS.

For example, the "skills" input value "english,finance" is extracted as a set with the values {"english", "finance"} and assigned to the label with name SKILLS.

By default extraction can be customized by using the following system property for defining the task input value from where the SKILLS will be extracted.

For example: org.kie.server.services.taskassigning.planning.data.DefaultTaskDataSkillsValueExtractor.skills=someOtherName

DefaultTaskDataAffinitiesValueExtractor

Processes the human task "affinities" input value, as a string comma separated values, and creates a java Set<Object> with tokenized String values. The resulting set is assigned to the label AFFINITIES.

Ej. The "affinities" input value "news,history" is extracted as a set with the values {"news", "history"} and assigned to the label with name AFFINITIES.

By default extraction can be customized by using the following system property for defining the task input value from where the AFFINITIES will be extracted.

For example: org.kie.server.services.taskassigning.planning.data.DefaultTaskDataAffinitiesValueExtractor.affinities=someOtherName

DefaultUserSkillsValueExtractor

Analogous to the DefaultTaskDataSkillsValueExtractor By default extraction can be customized by using the following system property for defining the user attribute from where the SKILLS will be extracted.

For example: org.kie.server.services.taskassigning.planning.data.DefaultUserSkillsValueExtractor.skills=someOtherName

DefaultUserAffinitiesValueExtractor

Analogous to the DefaultTaskDataAffinitiesValueExtractor By default extraction can be customized by using the following system property for defining the user attribute from where the AFFINITIES will be extracted.

For example: org.kie.server.services.taskassigning.planning.data.DefaultUserAffinitiesValueExtractor.affinities=someOtherName

The current core model classes like the TaskAssigningSolution, Task and User might change in future releases.

Linking the human tasks inputs with the labels

A simple approach for labeling tasks with business related information is implemented using the task inputs configuration. The following image shows an example of such a configuration.

SkillsAndAffinitiesConfigurationExample
Figure 147. Skills and affinities configuration

The example above links the process variable "variableWithTheSkills" with the task input name "skills", and the corresponding value will be processed by the "DefaultTaskDataSkillsValueExtractor" and automatically associated with the label name SKILLS.

This mechanism can be used for any other user provided LabelValueExtractor.

Custom extractors

Installations that require the definition of customized LabelValueExtractors can add them by providing their implementations in the customized KJARs with the UserSystemIntegration implementation or the Solver configuration.

  1. Add a component in the specified KJAR that implements the following interface:

    org.kie.server.api.model.taskassigning.data.LabelValueExtractor

    Note: Ensure that the following dependency is added to the given KJAR:

<dependency>
  <groupId>org.kie.server</groupId>
  <artifactId>kie-server-api</artifactId>
  <version>corresponding version</version>
  <scope>provided</scope>
</dependency>
  1. Declare the component implementation by using the Java standard service provider mechanism in the following resource:

    project_home/src/main/resources/META-INF/services/project_home/src/main/resources/META-INF/services/org.kie.server.api.model.taskassigning.data.LabelValueExtractor

When configured, the LabelValueExtractor will be processed accordingly.

The following example shows a custom LabelValueExtractor:

import org.kie.server.api.model.taskassigning.data.LabelValueExtractor;
import org.kie.server.services.taskassigning.user.system.api.User;

public class UserExampleValueExtractor implements LabelValueExtractor<User> {

   public Class<User> getType() {
       // consider this extractor for processing users information.
       return org.kie.server.services.taskassigning.user.system.api.User.class;
   }

   public String getLabelName() {
       return "PASSPORT";
   }

   public int getPriority() {
       return 1;
   }

   public Set<Object> extract(User source) {
       Map<String, Object> attributes = source.getAttributes();
       Object value = attributes != null ? attributes.get("passport_number") : null;
       return value != null ? new HashSet<Object>(Collections.singleton(value)) : null;
   }
}

Ensure that the following dependency is added to the specified KJAR:

<dependency>
  <groupId>org.kie.server</groupId>
  <artifactId>kie-server-services-task-assigning-user-system-api</artifactId>
  <version>corresponding version</version>
  <scope>provided</scope>
</dependency>

Extractors for processing the human tasks information must use the class org.kie.server.api.model.taskassigning.TaskData as source type.

The current core model classes like the TaskAssigningSolution, Task and User might change in future releases.

7.17.3. Integration alternatives

System integrators usually consume the human tasks available in the Process Runtime kie-server for different purposes. One example is the Business Central "Task Inbox" in this case, Business Central acts as an "integrator" which means that the human tasks are consumed from the Process Runtime kie-server by using the kie-server queries APIs and applying different filtering criterias. Finally these tasks are listed in the "Task Inbox" UI, etc. In this way, Business Central is decoupled from the Process Runtime kie-server, etc.

The next topics present a set of queries similar to queries used by the Business Central "Task Inbox". These queries might facilitate integrations in cases where the task assigning integration is enabled.

7.17.3.1. Task Assigning Human Tasks Query

This query facilitates the consumption of the available human tasks. The task can integrate additional information depending on the query variant. It is up to the "integrator" to select the query variant that best supports it’s needs.

Filtering parameters

The available filtering parameters are defined in the following kie-server-api enums:

org.kie.server.api.model.definition.TaskField
org.kie.server.api.model.taskassigning.PlanningTaskField

Both classes are found in the following maven artifact:

<dependency>
    <groupId>org.kie.server</groupId>
    <artifactId>kie-server-api</artifactId>
</dependency>

The following table shows the parameter name and the expected type.

Parameter Type Description

ACTIVATIONTIME

Date

Time when this task was activated.

ACTUALOWNER

String

Actual owner assigned to this task - only set when task is claimed.

CREATEDBY

String

User who created this task.

CREATEDON

Date

Date when task was created.

DEPLOYMENTID

String

Deployment id this task is part of, typically the KIE Server container.

DESCRIPTION

String

Description of the task if any.

DUEDATE

Date

Due date set on this task if any.

NAME

String

Name of the task.

PARENTID

Long

Parent task id if any.

PRIORITY

Integer

Priority of the task.

PROCESSID

String

Process definition id that this task belongs to.

PROCESSINSTANCEID

Long

Process instance id that this task is associated with.

PROCESSSESSIONID

Long

KieSession id used to create this task.

STATUS

String

Current status of the task.

TASKID

Long

Identifier of task.

WORKITEMID

Long

Identifier of work item assigned on process side to this task id.

PTTASKID

Long

Same value as TASKID.

ASSIGNEDUSER

String

Same value as the ACTUALOWNER for published tasks.

PUBLISHED

Integer

Indicates if the task is published. For example "published = 1" can be used as filtering criteria in cases of filtering by the task that are currently assigned by the task assigning integration.

Querying the human tasks as TaskData instances

This query execution variant enables getting the result values as instances of:

org.kie.server.api.model.taskassigning.TaskData

The following example shows how to use this variant:

Example 1)

// Create the kie-server query services client.
QueryServicesClient queryServices = createQueryServicesClient();

// Set the filtering and ordering criteria and consider only the currently published tasks.
QueryFilterSpec filter = new QueryFilterSpecBuilder()
    .equalsTo(TaskField.STATUS.toString(), "Reserved", "InProgress", "Completed")
    .equalsTo(PlanningTaskField.PUBLISHED.toString(), 1)
    .oderBy(TaskField.TASKID.toString(), true)
    .get();

// Execute the query
List<TaskData> result = queryServices.query(TaskAssigningQueries.JBPM_HUMAN_TASKS_QUERY,
                                            TaskAssigningQueries.TASK_DATA_QUERY_MAPPER,
                                            filter,
                                            0,    // staring page
                                            30,   // page size
                                            TaskData.class);

In this case, only the tasks currently assigned by the task assigning integration will be considered. This is the usual scenario when task assigning integration is enabled, because it is expected that the tasks are consumed and executed accordingly with the generated planning.

The task inputs and potential owners are not loaded by this query.

Example 2)

// Create the kie-server query services client.
QueryServicesClient queryServices = createQueryServicesClient();

// Set the filtering and ordering criteria and consider all of the tasks.
QueryFilterSpec filter = new QueryFilterSpecBuilder()
    .equalsTo(TaskField.STATUS.toString(), "Ready”, Reserved", "InProgress", "Completed")
    .oderBy(TaskField.TASKID.toString(), true)
    .get();

// Execute the query
List<TaskData> result = queryServices.query(TaskAssigningQueries.JBPM_HUMAN_TASKS_QUERY,
                                            TaskAssigningQueries.TASK_DATA_QUERY_MAPPER,
                                            filter,
                                            0,    // staring page
                                            30,   // page size
                                            TaskData.class);

In this case all of the tasks will be considered but only the property assigned by the task assigning integration will have the TaskData.planningTask filled. It means that non assigned tasks or not yet managed by the task assigning integration might be included in the results. This alternative facilitates a more advanced processing of the "potential" tasks, however it is strongly encouraged to make available to the users only the tasks that are currently assigned by the task assigning integration . i.e. the ones with TaskData.planningTask != null otherwise the integration becomes senseless.

The task inputs and potential owners are not loaded by this query.

See KIE Server API documentation for more information on how to create the KIE Server clients and the query API general functioning.

7.17.4. Examples

7.17.4.1. Credit dispute process

The following credit dispute process example is intended to show a simple use case where you can use the "skills" configuration to influence the way tasks are assigned according to the solver constraints and the process data.

CreditDisputeProcess
Figure 148. Credit dispute process
Process start

When the process starts, the user is asked to complete the information in the following image. In particular, the credit card brand for which the dispute is related to and the preferred language for receiving the process notifications are requested. This information is used for assigning the process tasks.

StartCreditDisputeForm
Figure 149. Start credit dispute process form
Process configuration

The following image shows the process variables that are used for holding the card brand and language respectively.

CreditDisputeProcessWithVariables
Figure 150. Credit dispute process variables

The process start form populates these variables with the user inputs.

Resolve dispute task configuration

The following image shows the ResolveDispute task configuration, which establishes that the task input parameter skills is assigned with the value of the process variable cardType.

ResolveDisputeTaskConfiguration
Figure 151. Resolve dispute task configuration

With this configuration, OptaPlanner assigns this task to users that meet the following criteria:

  1. Are in the user group CreditAnalyst

  2. Have all of the skills configured in the task input parameter skills

Notify customer task configuration

The following image shows the NotifyCustomer task configuration, which establishes that the task input parameter skills is assigned with the value of the process variable language.

NotifyCustomerTaskConfiguration
Figure 152. Notify customer task configuration

With this configuration OptaPlanner assigns this task to users that meet the following criteria:

  1. Are in the group ClientRelations

  2. Have all of the skills configured in the task input parameter skills

  3. Note that in this case the language selection is optional since the form field is not marked with "*" see the process start form, meaning that when no language is selected the task won’t have any configured skills. This implies that in such cases whatever users that are in group ClientRelations can be assigned to the task.

Process execution (example users)

Let’s assume that the following users configurations are used for executing the process.

users.properties file:

john=analyst,admin,user,Accounting,PM,ClientRelations
mary=analyst,admin,user,ClientRelations
katy=analyst,admin,user,HR,CreditAnalyst
maciek=admin,analyst,user,PM,HR,CreditAnalyst

skills.properties file:

john=ES,EN                     (has skills in the Spanish and English languages)
mary=ZH                        (has skills in the Chinese language)
katy=CITI,MASTER               (has skills in the CITI and MASTER cards)
maciek=VISA,AMERICAN_EXPRESS   (has skills in the VISA and AMERICAN EXPRESS cards)
Process execution (example instances)

With the preceding configurations the following execution scenarios are expected:

Process instance #1:

1) Start process

StartCreditDisputeInstance1Simple
Figure 153. Start credit dispute process instance #1

2) ResolveDispute task

ResolveDisputeTaskForProcessInstance1WasCreated
Figure 154. Resolve dispute task for process instance #1

The ResolveDispute task is assigned to the user maciek since it requires VISA skills.

In real environments there might be many users with this skill. In this case OptaPlanner assigns the new created task considering the optimized plan, which means that depending on the workload a different user could have been assigned.

3) NotifyCustomer task

NotifyCustomerTaskForProcessInstance1WasCreated
Figure 155. Notify customer task for process instance #1

When the ResolveDispute task is completed, a new task NotifyCustomer is created and assigned to the user john because that task requires skills in Spanish.

Process instance #2:

1) Start process

StartCreditDisputeInstance2Simple
Figure 156. Start credit dispute process instance #2

2) ResolveDispute task

ResolveDisputeTaskForProcessInstance2WasCreated
Figure 157. Resolve dispute task for process instance #2

The ResolveDispute task is assigned to the user katy since it requires CITI skills.

3) NotifyCustomer task

NotifyCustomerTaskForProcessInstance2WasCreated
Figure 158. Notify customer task for process instance #2

When the ResolveDispute task is completed, a new task NotifyCustomer is created and assigned to the user mary because that task requires skills in Chinese.

Process instance #3:

1) Start process

StartCreditDisputeInstance3Simple
Figure 159. Start credit dispute process instance #3

2) ResolveDispute task

ResolveDisputeTaskForProcessInstance3WasCreated
Figure 160. Resolve dispute task for process instance #3

The ResolveDispute task is assigned to the user katy because that task requires MASTER skills.

3) NotifyCustomer task

NotifyCustomerTaskForProcessInstance3WasCreated
Figure 161. Notify customer task for process instance #3

When the ResolveDispute task is completed, a new task NotifyCustomer is created and assigned to the planninguser because none of the users has the required skills in Hindi. In this case, an external interaction is required to determine the best suited user to complete the task. The planinguser must perform this action by delegating the task.

The planninguser assignment is used to cover edge cases and should not be part of the modelling strategy. In the preceding example, if it is known that no user will have skills in Hindi. A similar but softer constraint can be configured by using affinities.

7.17.4.2. Customized User System Service

For creating a custom user system service implementation follow these steps:

1) Create a KJAR project structure

2) Add the following dependency

<dependency>
  <!-- Kie Server, OptaPlanner, or any other product dependencies must use provided scope -->
  <groupId>org.kie.server</groupId>
    <artifactId>kie-server-services-task-assigning-user-system-api</artifactId>
    <version>configure the proper version number aligned with the target kie-server</version>
    <scope>provided</scope>
</dependency>

3) Provide your UserSystemService implementation, see the following example:

public class MyDBUserSystemService implements UserSystemService {

    private DataSource dataSource;

    public String getName() {
        return "MyDBUserSystemService";
    }

    public void start() {
        String dataSourceName = System.getProperty("org.example.DBUserSystemService.ds",
                                                   "java:jboss/datasources/ExampleDS");
        try {
            InitialContext initialContext = new InitialContext();
            dataSource = (DataSource) initialContext.lookup(dataSourceName);
        } catch (NamingException e) {
             // throw an exception if there are unrecoverable errors that prevent
             // the service to start.
            throw new DBUserSystemServiceException("Unable to find data source under name " +
                                                   dataSourceName, e);
       }
    }

    public void test() throws Exception {
         // test your database queries etc.
    }

    public List<User> findAllUsers() {
        try (Connection conn = dataSource.getConnection()) {
            List<User> myUsers;
            // query the users information from the database.
           return myUsers;
       } catch (SQLException e) {
           throw new DBUserSystemServiceException("An error was produced finding all users: " +
                                                  e.getMessage(), e);
       }
   }

    public User findUser(String userId) {
        if (userId == null) {
            return null;
        }
        try (Connection conn = dataSource.getConnection()) {
            User user;
            // query the user information from the database.
            return user;
        } catch (SQLException e) {
          throw new DBUserSystemServiceException("An error was produced finding user: "+
                                                  e.getMessage(), e);
        }
    }
}

4) Add the following resource to the project and declare your user system service provider class on it.

src/main/resources/META-INF/services/org.kie.server.services.taskassigning.user.system.api.UserSystemService

org.example.MyDBUserSystemService

Finally for using it in the Planning kie-server follow these steps:

1) Build your KJAR and be sure the corresponding maven generated artifact is installed in the maven repository used by your Planning kie-server.

2) Add a datasource configuration to your Planning kie-server pointing to the target DB (this step is only required for the example above) For example with JNDI name java:jboss/datasources/db-user-system-datasource

3) Finally add the following items to the Planning kie-server configuration file:

<server>
...
<system-properties>
  <property name="org.kie.server.taskAssigning.userSystem.name"
            value="MyDBUserSystemService" />
  <property name="org.kie.server.taskAssigning.userSystem.container.id"
            value="my-db-user-system-container" />
  <property name="org.kie.server.taskAssigning.userSystem.container.groupId"
            value="your KJARs groupId" />
  <property name="org.kie.server.taskAssigning.userSystem.container.artifactId"
            value="your KJARs artifactId" />
  <property name="org.kie.server.taskAssigning.userSystem.container.version"
            value="your KJARs version number" />
  <property name="org.example.DBUserSystemService.ds"
            value="java:jboss/datasources/db-user-system-datasource" />
</system-properties>
...
</server>