JBoss.orgCommunity Documentation

Chapter 4. KIE

4.1. Overview
4.1.1. Anatomy of Projects
4.1.2. Lifecycles
4.2. Build, Deploy, Utilize and Run
4.2.1. Introduction
4.2.2. Building
4.2.3. Deploying
4.2.4. Running
4.2.5. Build, Deploy and Utilize Examples

The process of researching an integration knowledge solution for Drools and jBPM has simply used the "droolsjbpm" group name. This name permeates github accounts and maven poms. As scopes broadened and new projects were spun KIE, an acronym for Knowledge Is Everything, was chosen as the new group name. The KIE name is also used for the shared aspects of the system; such as the unified build, deploy and utilization.

KIE currently consists of the following sub projects:


OptaPlanner, a local search and optimization tool, has been spun off from Drools Planner and is now a top level project with Drools and jBPM. This was a natural evolution as Optaplanner, while having strong Drools integration, has long been independant of Drools.

From the Polymita acquisition, along with other things, comes the powerful Dashboard Builder which provides powerful reporting capabities. Dashboard Builder is currently a temporary name and after the 6.0 release a new name will be chosen. Dashboard Builder is completely independant of Drools and jBPM and will be used by many projects at JBoss, and hopefully outside of JBoss :)

UberFire is the new base workbench project, spun off from the ground up rewrite. UberFire provides Eclipse-like workbench capabilities, with panels and perspectives from plugins. The project is independant of Drools and jBPM and anyone can use it as a basis of building flexible and powerful workbenches. UbeFire will be used for console and workbench development throughout JBoss.

It was determined that the Guvnor brand leaked too much from it's intended role; such as the authoring metaphores, like Decision Tables, being considered Guvnor components instead of Drools components. This wasn't helped by the monolithic projects structure used in 5.x for Guvnor. In 6.0 Guvnor 's focus has been narrowed to encapsulates the set of UberFire plugins that provide the basis for building a web based IDE. Such as Maven integration for building and deploying, management of Maven repositories and activity notifications via inboxes. Drools and jBPM build workbench distributions using Uberfire as the base and including a set of plugins, such as Guvnor, along with their own plugins for things like decision tables, guided editors, bpm2 designer, human tasks. The Drools workbench is called Drools-WB. KIE-WB is the uber workbench that combined all the Guvnor, Drools and jBPM plugins. The jBPM-WB is ghosted out, as it doesn't actually exist, being made redundant by KIE-WB.

6.0 introduces a new configuration and convention approach to building knowledge bases, instead of the using the programmatic builder approach in 5.x. Atlhough a builder is still available to fall back on, as it's used for the tooling integration.

Building now uses Maven, and aligns with Maven practices. A KIE projcet or module is simply a Maven java project or module; with an additional meta data file META-INF/kmodule.xml. The kmodule.xml file is the descriptor that selects resources to knowledge bases and configures those knowledge bases and sessions. There is also alternative xml support via Spring and OSGi BluePrints.

While standard Maven can build and package KIE resources, it will not provide validation at build time. There is a Maven plugin which is recommend to use to get build time validation. The plugin also pre-genenerates many classes, making the runtime loading faster too.

The example project layout and maven pom descriptor is illustarted in the screenshot


KIE uses defaults to minimise the amount of configuration. With an empty kmodule.xml being the simplest configuration. There must always be a kmodule.xml file, even if empty, as it's used for discover of the jar and it's contents.

Maven can either 'mvn install' to deploy a KieModule to the local machine, where all other applications on the local machine use it. Or it can 'mvn 'deploy' to push the KieModule to a remote Maven repository. Building the Application wil pull in the KieModule, popualting it's local Maven repository, as it does so.


Jars can be deployed in one of two ways. Either added to the classpath, like any other jar in a Maven dependency listing, or they can be dynamically loaded at runtime. KIE will scan the classpath to find all the jars with a kmodule.xml in it. Each found jar is represented by the KieModule interface. The term Classpath KieModules and dynamic KieModule is used to refer to the two loading approaches. While dynamic modules supports side by side versioning, classpath modules do not. Further once module is on the classpath, no other version may be loaded dynamically.

Detailed referencs for the api are included in the next sections, the impatiant can jump straight to the examples section, which is fairly intuitive for the different use cases.


A Kie Project has the structure of a normal maven project with the only peculiarity of including a kmodule.xml file defining in a declaratively way the KieBases and KieSessions that can be created from it. This file has to be placed in the resources/META-INF folder of the maven project while all the other Kie artifacts, such as DRL or a Excel files, must be stored in the resources folder or in any other subfolder under it.

Since meaningful defaults have been provided for all configuration aspects, the simplest kmodule.xml file can contain just an empty kmodule tag like the following:


In this way the kmodule will contain one single default KieBase. All Kie assets stored under the resources folder, or any of its subfolders, will be compiled and added to it. To trigger the building of these artifacts it is enough to create a KieContainer for them.


For this simple case it is enough to create a KieContainer that reads the files to be built from the classpath:


KieServices is the interface from where it possible to access all the Kie building and runtime facilities:


In this way all the java sources and the Kie resources are compiled and deployed into the KieContainer which makes its contents available for use at runtime.

As anticipated in the former section the kmodule.xml file is the place where it is possible to declaratively configure the KieBase(s) and KieSession(s) that can be created from a KIE project.

In particular a KieBase is a repository of all the application's knowledge definitions. It will contain rules, processes, functions, and type models. The KieBase itself does not contain data; instead, sessions are created from the KieBase into which data can be inserted and from which process instances may be started. Creating the KieBase can be heavy, whereas session creation is very light, so it is recommended that KieBase be cached where possible to allow for repeated session creation. However end-users usually shouldn't worry about it, because this caching mechanism is already automatically provided by the KieContainer.


Conversely the KieSession stores and executes on the runtime data. It is created from the KieBase or more easily can be created directly from the KieContainer if it has been defined in the kmodule.xml file


The kmodule.xml allows to define and configure one or more KieBases and for each KieBase all the different KieSessions that can be created from it, as showed by the follwing example:


Here 2 KieBases have been defined and it is possible to instance 2 different types of KieSessions from the first one, while only one from the second. A list of the attributes that can be defined on the kbase tag, together with their meaning and default values follows:


In the same way also all attributes of the ksession tag (except of course the name) have meaningful default. They are listed and described in the following table:


As outlined in the former kmodule.xml sample, it is also possible to declaratively create on each KieSession a file (or a console) logger, one or more WorkItemHandlers and some listeners that can be of 3 different types: ruleRuntimeEventListener, agendaEventListener and processEventListener

Having defined a kmodule.xml like the one in the former sample, it is now possible to simply retrieve the KieBases and KieSessions from the KieContainer using their names.


It has to be noted that since KSession2_1 and KSession2_2 are of 2 different types (the first is stateful, while the second is stateless) it is necessary to invoke 2 different methods on the KieContainer according to their declared type. If the type of the KieSession requested to the KieContainer doesn't correspond with the one declared in the kmodule.xml file the KieContainer will throw a RuntimeException. Also since a KieBase and a KieSession have been flagged as default is it possible to get them from the KieContainer without passing any name.


Since a Kie project is also a maven project the groupId, artifactId and version declared in the pom.xml file are also used to generate a ReleaseId that uniquely identify this project inside your application. This also allows to create a new KieContainer from that project by simply passing its ReleaseId to the KieServices.


It is also possible to define the KieBases and KieSessions belonging to a KieModule programatically instead of declaratively define them in the kmodule.xml file. The same programatic API also allows to explicitly add the file containing the Kie artifacts instead of automatically read them from the resources folder of your project. To do that it is necessary to create a KieFileSystem, a sort of virtual file system, and add all the resources contained in your project to it.


Like all other Kie core component you can obtain an instance of the KieFileSystem from the KieServices. One of the thing that for sure it will be necessary to add to this file system is the kmodule.xml configuration file. As anticipated above Kie also provides a convenient fluent API, implemented by the KieModuleModel, to programatically create this file.


To do this in practice it is necessary to create a KieModuleModel from the KieServices, configure it with the desired KieBases and KieSessions, convert it in xml and add the xml to the KieFileSystem. This process is shown by the following example:


At this point it is also necessary to add to the KieFileSystem, through its fluent API, all others Kie artifacts composing your project. These artifacts have to be added in the same position of a corresponding usual maven project.


This example shows that it is possible to add the Kie artifacts both as plain Strings and as Resources. In this second case the Resources can be created by the KieResources factory, also provided by the KieServices. The KieResources provides many convenient factory methods to convert an InputStream, a URL, a File, or a String representing a path of your file system to a Resource that can be managed by the KieFileSystem.


Normally the type of a Resource can be inferred from the extension of the name used to add it to the KieFileSystem. However it also possible to not follow the Kie conventions about file extension and then explicitly assign a specific ResourceType to aResource as in the following example


After having added to the KieFileSystem all the resources that has to be included into the project, it is possible to build it by passing the KieFileSystem to a KieBuilder


When a the contents of a KieFileSystem is successfully built, the KieModule resulting from this compilation is automatically added to the KieRepository. The KieRepository is a singleton acting as a repository for all the available KieModules.


After this it is possible to create through the KieServices a new KieContainer for that KieModule using its ReleaseId. However, since in this case the KieFileSystem don't contain any pom.xml file (it is possible to add one using the KieFileSystem.writePomXML method), Kie cannot determine the ReleaseId of the KieModule and assign to it a default one. This default ReleaseId can be obtained from the KieRepository and used to identify the KieModule inside the KieRepository itself. The following example shows this whole process.


At this point it is possible to get KieBases and create new KieSessions from this KieContainer exactly in the same way as in the case of a KieContainer created directly from the classpath.

It is a best practice to check the compilation results. The KieBuilder can report compilation results of 3 different severities: ERROR, WARNING and INFO. An ERROR indicates that the compilation of the project failed and in the case no KieModule is produced and then nothing is added to the KieRepository. WARNING and INFO results can be ignored, but are available for inspection nonetheless.


The event package provides means to be notified of rule engine events, including rules firing, objects being asserted, etc. This allows you, for instance, to separate logging and auditing activities from the main part of your application (and the rules).

The KieRuntimeEventManager interface is implemented by the KieRuntime which provides two interfaces, RuleRuntimeEventManager and ProcessEventManager. We will only cover the RuleRuntimeEventManager here.


The RuleRuntimeEventManager allows for listeners to be added and removed, so that events for the working memory and the agenda can be listened to.


The following code snippet shows how a simple agenda listener is declared and attached to a session. It will print matches after they have fired.


Drools also provides DebugRuleRuntimeEventListener and DebugAgendaEventListener which implement each method with a debug print statement. To print all Working Memory events, you add a listener like this:


All emitted events implement the KieRuntimeEvent interface which can be used to retrieve the actual KnowlegeRuntime the event originated from.


The events currently supported are:

  • MatchCreatedEvent

  • MatchCancelledEvent

  • BeforeMatchFiredEvent

  • AfterMatchFiredEvent

  • AgendaGroupPushedEvent

  • AgendaGroupPoppedEvent

  • ObjectInsertEvent

  • ObjectDeletedEvent

  • ObjectUpdatedEvent

  • ProcessCompletedEvent

  • ProcessNodeLeftEvent

  • ProcessNodeTriggeredEvent

  • ProcessStartEvent

KIE has the concept of stateful or stateless sessions. Stateful sessions have already been covered, which use the standard KieRuntime, and can be worked with iteratively over time. Stateless is a one-off execution of a KieRuntime with a provided data set. It may return some results, with the session being disposed at the end, prohibiting further iterative interactions. You can think of stateless as treating an engine like a function call with optional return results.

The foundation for this is the CommandExecutor interface, which both the stateful and stateless interfaces extend. This returns an ExecutionResults:



The CommandExecutor allows for commands to be executed on those sessions, the only difference being that the StatelessKieSession executes fireAllRules() at the end before disposing the session. The commands can be created using the CommandExecutor .The Javadocs provides the full list of the provided comands using the CommandExecutor .

SetGloban and getGlobal are two commands relevant to both Drools and jBPM.

Set Global calls setGlobal underneath. The optional boolean indicates on whether the command should return value as part of the ExecutionResults. If true it uses the same name as the global name. A String cna be used instead of the boolean, if an alternative name is desired.

Example 4.21. Set Global Command

<!-- <br/> --><span class="java_type">StatelessKieSession</span><!-- <br/> --><span class="java_plain">&nbsp;ksession&nbsp;</span><!-- <br/> --><span class="java_operator">=</span><!-- <br/> --><span class="java_plain">&nbsp;kbase</span><!-- <br/> --><span class="java_separator">.</span><!-- <br/> --><span class="java_plain">newStatelessKieSession</span><!-- <br/> --><span class="java_separator">();</span>
<!--  --><br/><span class="java_type">ExecutionResults</span><span class="java_plain">&nbsp;bresults&nbsp;</span><span class="java_operator">=</span>
<!--  --><br/><span class="java_plain">&nbsp;&nbsp;&nbsp;&nbsp;ksession</span><span class="java_separator">.</span><span class="java_plain">execute</span><span class="java_separator">(</span><span class="java_plain">&nbsp;</span><span class="java_type">CommandFactory</span><span class="java_separator">.</span><span class="java_plain">newSetGlobal</span><span class="java_separator">(</span><span class="java_plain">&nbsp;</span><span class="java_literal">&quot;stilton&quot;</span><span class="java_separator">,</span><span class="java_plain">&nbsp;</span><span class="java_keyword">new</span><span class="java_plain">&nbsp;</span><span class="java_type">Cheese</span><span class="java_separator">(</span><span class="java_plain">&nbsp;</span><span class="java_literal">&quot;stilton&quot;</span><span class="java_plain">&nbsp;</span><span class="java_separator">),</span><span class="java_plain">&nbsp;</span><span class="java_literal">true</span><span class="java_separator">);</span>
<!--  --><br/><span class="java_type">Cheese</span><span class="java_plain">&nbsp;stilton&nbsp;</span><span class="java_operator">=</span><span class="java_plain">&nbsp;bresults</span><span class="java_separator">.</span><span class="java_plain">getValue</span><span class="java_separator">(</span><span class="java_plain">&nbsp;</span><span class="java_literal">&quot;stilton&quot;</span><span class="java_plain">&nbsp;</span><span class="java_separator">);</span>


Allows an existing global to be returned. The second optional String argument allows for an alternative return name.


The examples above all execute single commands. The BatchExecution represents a composite command, created from a list of commands. It will iterate over the list and execute each command in turn. This means you can insert some objects, start a process, call fireAllRules and execute a query, all in a single execute(...) call, which is quite powerful.

The StatelessKieSession will execute fireAllRules() automatically at the end. However the keen-eyed reader probably has already noticed the FireAllRules command and wondered how that works with a StatelessKieSession. The FireAllRules command is allowed, and using it will disable the automatic execution at the end; think of using it as a sort of manual override function.

Any command, in the batch, that has an out identifier set will add its results to the returned ExecutionResults instance. Let's look at a simple example to see how this works. The example presented includes command from the Drools and jBPM, for the sake of illustartion. They are covered in more detail in the Drool and jBPM specific sections.


In the above example multiple commands are executed, two of which populate the ExecutionResults. The query command defaults to use the same identifier as the query name, but it can also be mapped to a different identifier.

All commands support XML and jSON marshalling using XStream, as well as JAXB marshalling. This is covered in section XXX.

The StatelessKieSession wraps the KieSession, instead of extending it. Its main focus is on decision service type scenarios. It avoids the need to call dispose(). Stateless sessions do not support iterative insertions and the method call fireAllRules() from Java code; the act of calling execute() is a single-shot method that will internally instantiate a KieSession, add all the user data and execute user commands, call fireAllRules(), and then call dispose(). While the main way to work with this class is via the BatchExecution (a subinterface of Command) as supported by the CommandExecutor interface, two convenience methods are provided for when simple object insertion is all that's required. The CommandExecutor and BatchExecution are talked about in detail in their own section.


Our simple example shows a stateless session executing a given collection of Java objects using the convenience API. It will iterate the collection, inserting each element in turn.


If this was done as a single Command it would be as follows:


If you wanted to insert the collection itself, and the collection's individual elements, then CommandFactory.newInsert(collection) would do the job.

Methods of the CommandFactory create the supported commands, all of which can be marshalled using XStream and the BatchExecutionHelper. BatchExecutionHelper provides details on the XML format as well as how to use Drools Pipeline to automate the marshalling of BatchExecution and ExecutionResults.

StatelessKieSession supports globals, scoped in a number of ways. I'll cover the non-command way first, as commands are scoped to a specific execution call. Globals can be resolved in three ways.

The CommandExecutor interface also offers the ability to export data via "out" parameters. Inserted facts, globals and query results can all be returned.


The KieMarshallers is used to marshal and unmarshal KieSessions.


An instance of the KieMarshallers can be retrieved from the KieServices and at the simplest the it can be used as follows:


However, with marshalling you need more flexibility when dealing with referenced user data. To achieve this we have the ObjectMarshallingStrategy interface. Two implementations are provided, but users can implement their own. The two supplied strategies are IdentityMarshallingStrategy and SerializeMarshallingStrategy. SerializeMarshallingStrategy is the default, as used in the example above, and it just calls the Serializable or Externalizable methods on a user instance. IdentityMarshallingStrategy instead creates an integer id for each user object and stores them in a Map, while the id is written to the stream. When unmarshalling it accesses the IdentityMarshallingStrategy map to retrieve the instance. This means that if you use the IdentityMarshallingStrategy, it is stateful for the life of the Marshaller instance and will create ids and keep references to all objects that it attempts to marshal. Below is he code to use an Identity Marshalling Strategy.


For added flexability we can't assume that a single strategy is suitable. Therefore we have added the ObjectMarshallingStrategyAcceptor interface that each Object Marshalling Strategy contains. The Marshaller has a chain of strategies, and when it attempts to read or write a user object it iterates the strategies asking if they accept responsability for marshalling the user object. One of the provided implementations is ClassFilterAcceptor. This allows strings and wild cards to be used to match class names. The default is "*.*", so in the above example the Identity Marshalling Strategy is used which has a default "*.*" acceptor.

Assuming that we want to serialize all classes except for one given package, where we will use identity lookup, we could do the following:


Note that the acceptance checking order is in the natural order of the supplied elements.

Also note that if you are using scheduled matches (i.e. some of your rules use timers or calendars) they are marshallable only if, before you use it, you configure your KieSession to use a trackable timer job factory manager as it follows:


Longterm out of the box persistence with Java Persistence API (JPA) is possible with Drools. It is necessary to have some implementation of the Java Transaction API (JTA) installed. For development purposes the Bitronix Transaction Manager is suggested, as it's simple to set up and works embedded, but for production use JBoss Transactions is recommended.


To use a JPA, the Environment must be set with both the EntityManagerFactory and the TransactionManager. If rollback occurs the ksession state is also rolled back, so it is possible continue to use it after a rollback. To load a previously persisted KieSession you'll need the id, as shown below:


To enable persistence several classes must be added to your persistence.xml, as in the example below:


The jdbc JTA data source would have to be configured first. Bitronix provides a number of ways of doing this, and its documentation should be contsulted for details. For a quick start, here is the programmatic approach:


Bitronix also provides a simple embedded JNDI service, ideal for testing. To use it add a jndi.properties file to your META-INF and add the following line to it:


The best way to learn the new build system is by example. The source project "drools-examples-api" contains a number of examples, and can be found at github:

https://github.com/droolsjbpm/drools/tree/6.0.x/drools-examples-api

Each example is described below, the order starts with the simplest and most default working it's way up to more complex use cases.

The Deploy use cases here all involve mvn install. Remote deployment of jars in Maven is well covered is Maven literature. Utilize refers to the initial act loading the resources and providing access to the KIE runtimes. Where as Run refers to the act of interacting with those runtimes.

kmodule.xml will produce a single named KieBase, 'kbase2' that includes all files found under resources path, be it DRL, BPMN2, XLS etc. Further it will include all the resources found from the KieBase 'kbase1', due to the use of the 'includes' attribute. KieSession 'ksession2' is associated with that KieBase and can be created by name.


This example requires that the previous example, 'named-kiesession', is built and installed to the local Maven repository first. Once installed it can be included as a dependency, using the standard Maven <dependencies> element.


Once 'named-kiesession' is built and installed this example can be built and installed as normal. Again the act of installing, will force the unit tests to run, demonstrating the use case.


ks.getKieClasspathContainer() returns the KieContainer that contains the KieBases deployed onto the environment classpath. This time the KieSession uses the name 'ksession2'. You do not need to lookup the KieBase first, as it knows which KieBase 'ksession1' is assocaited with. Notice two rules fire this time, showing that KieBase 'kbase2' has included the resources from the dependency KieBase 'kbase1'.


kmodule.xml produces 6 different named KieBases. 'kbase1' includes all resources from the KieModule. The other KieBases include resources from other selected folders, via the 'packages' attribute. Note the use wildcard '*' use, to select this package and all packages below it.



Only part of the example is included below, as there is a test method per KieSession, but each one is a repetitino of the other, with just different list expectations.


The pom.xml must include kie-ci as a depdency, to ensure Maven is available at runtime. As this uses Maven under the hood you can also use the standard Maven settings.xml file.



In the previous examples the classpath KieContainer used. This example creates a dynamic KieContainer as specified by the ReleaseId. The ReleaseId uses Maven conventions for group id, artifact id and version. It also obey's LATEST and SNAPSHOT for versions.


No kmodue.xml file exists. The projects 'named-kiesession' and 'kiebase-include' must be built first, so that the resulting jars, in the target folders, be be reference as Files.


Creates two resources. One is for the main KieModule 'exRes1' the other is for the dependency 'exRes2'. Even though kie-ci is not present and thus Maven is not there to resolve the dependencies, this shows how you can manually specify the dependency KieModuels, for the vararg.



This programmatically builds a KieModule. It populates the model that represents the ReleaseId and kmodule.xml, as well as added the resources tht. A pom.xml is generated from the ReleaseId.

Example 4.62. Utilize and Run - Java

KieServices ks = KieServices.Factory.get();

KieFileSystem kfs = ks.newKieFileSystem();
Resource ex1Res = ks.getResources().newFileSystemResource(getFile("named-kiesession"));
Resource ex2Res = ks.getResources().newFileSystemResource(getFile("kiebase-inclusion"));
ReleaseId rid = ks.newReleaseId("org.drools", "kiemodulemodel-example", "6.0.0-SNAPSHOT");
kfs.generateAndWritePomXML(rid);
KieModuleModel kModuleModel = ks.newKieModuleModel();
kModuleModel.newKieBaseModel("kiemodulemodel")
            .addInclude("kiebase1")
            .addInclude("kiebase2")
            .newKieSessionModel("ksession6");
kfs.writeKModuleXML(kModuleModel.toXML());
kfs.write("src/main/resources/kiemodulemodel/HAL6.drl", getRule());
KieBuilder kb = ks.newKieBuilder(kfs);
kb.setDependencies(ex1Res, ex2Res);
kb.buildAll(); // kieModule is automatically deployed to KieRepository if successfully built.
if (kb.getResults().hasMessages(Level.ERROR)) {
    throw new RuntimeException("Build Errors:\n" + kb.getResults().toString());
}
KieContainer kContainer = ks.newKieContainer(rid);
KieSession kSession = kContainer.newKieSession("ksession6");
kSession.setGlobal("out", out);
Object msg1 = createMessage(kContainer, "Dave", "Hello, HAL. Do you read me, HAL?");
kSession.insert(msg1);
kSession.fireAllRules();
Object msg2 = createMessage(kContainer, "Dave", "Open the pod bay doors, HAL.");
kSession.insert(msg2);
kSession.fireAllRules();
Object msg3 = createMessage(kContainer, "Dave", "What's the problem?");
kSession.insert(msg3);
kSession.fireAllRules();