JBoss.orgCommunity Documentation

Chapter 3. API Reference

3.1. Building
3.1.1. Creating and building a Kie Project
3.1.2. The kmodule.xml file
3.1.3. Defining a KieModule programmatically
3.1.4. Changing the Default Build Result Severity
3.2. Deploying
3.2.1. KieBase
3.2.2. KieSessions and KieBase Modifications
3.2.3. KieScanner
3.3. Running
3.3.1. KieBase
3.3.2. KieSession
3.3.3. KieRuntime
3.3.4. Agenda
3.3.5. Event Model
3.3.6. KieRuntimeLogger
3.3.7. StatelessKieSession
3.3.8. Commands and the CommandExecutor
3.3.9. Marshalling
3.3.10. Persistence and Transactions

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 resource 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 KieBase and all the Kie artifacts stored undered the resources folder, or any of its subfolder, 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 build from the classpath as it follows:


where 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: workingMemoryEventListener, 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 EntryPoint provides the methods around inserting, updating and retrieving facts. The term "entry point" is related to the fact that we have multiple partitions in a Working Memory and you can choose which one you are inserting into, although this use case is aimed at event processing and covered in more detail in the Fusion manual. Most rule based applications will work with the default entry point alone.

The KieRuntime interface provides the main interaction with the engine. It is available in rule consequences and process actions. In this manual the focus is on the methods and interfaces related to rules, and the methods pertaining to processes will be ignored for now. But you'll notice that the KieRuntime inherits methods from both the WorkingMemory and the ProcessRuntime, thereby providing a unified API to work with processes and rules. When working with rules, three interfaces form the KieRuntime: EntryPoint, WorkingMemory and the KieRuntime itself.


Insertion is the act of telling the WorkingMemory about a fact, which you do by ksession.insert(yourObject), for example. When a fact is inserted it is not immediately examined for matches against the rules. This means that all of the work for deciding about firing or not firing a rule is done lazily when fireAllRules() is invoked. Expert systems typically use the term assert or assertion to refer to facts made available to the system. However, due to "assert" being a keyword in most languages, we have decided to use the insert keyword; however, expect to hear the two terms used interchangeably.

When an Object is inserted it returns a FactHandle. This FactHandle is the token used to represent your inserted object within the WorkingMemory. It is also used for interactions with the WorkingMemory when you wish to retract or modify an object.

Cheese stilton = new Cheese("stilton");

FactHandle stiltonHandle = ksession.insert( stilton );      

As mentioned in the KieBase section, a Working Memory may operate in two assertion modes, i.e., equality or identity, with identity being the default.

Identity means that the Working Memory uses an IdentityHashMap to store all asserted objects. New instance assertions always result in the return of new FactHandle, but if an instance is asserted again then it returns the original fact handle, i.e., it ignores repeated insertions for the same object.

Equality means that the Working Memory uses a HashMap to store all asserted objects. An object instance assertion will only return a new FactHandle if the inserted object is not equal (according to its equal method) to an already existing fact.

The RuleRuntime provides access to the Agenda, permits query executions, and lets you access named Entry Points.


Invoking queries and processing the results by iterating over the returned set is not a good way to monitor changes over time.

To alleviate this, Drools provides Live Queries, which have a listener attached instead of returning an iterable result set. These live queries stay open by creating a view and publishing change events for the contents of this view. To activate, you start your query with parameters and listen to changes in the resulting view. The dispose method terminates the query and discontinues this reactive scenario.


A Drools blog article contains an example of Glazed Lists integration for live queries:

http://blog.athico.com/2010/07/glazed-lists-examples-for-drools-live.html

The Agenda is a Rete feature. During actions on the WorkingMemory, rules may become fully matched and eligible for execution; a single Working Memory Action can result in multiple eligible rules. When a rule is fully matched a Match is created, referencing the rule and the matched facts, and placed onto the Agenda. The Agenda controls the execution order of these Matches using a Conflict Resolution strategy.

The engine cycles repeatedly through two phases:


The process repeats until the agenda is clear, in which case control returns to the calling application. When Working Memory Actions are taking place, no rules are being fired.


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, WorkingMemoryEventManager and ProcessEventManager. We will only cover the WorkingMemoryEventManager here.


The WorkingMemoryEventManager 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 DebugWorkingMemoryEventListener 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

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.


With Rete you have a stateful session where objects can be asserted and modified over time, and where rules can also be added and removed. Now what happens if we assume a stateless session, where after the initial data set no more data can be asserted or modified and rules cannot be added or removed? Certainly it won't be necessary to re-evaluate rules, and the engine will be able to operate in a simplified way.

The LeftInputAdapterNode no longer creates a Tuple, adding the Object, and then propagate the Tuple – instead a Command object is created and added to a list in the Working Memory. This Command object holds a reference to the LeftInputAdapterNode and the propagated object. This stops any left-input propagations at insertion time, so that we know that a right-input propagation will never need to attempt a join with the left-inputs (removing the need for left-input memory). All nodes have their memory turned off, including the left-input Tuple memory but excluding the right-input object memory, which means that the only node remembering an insertion propagation is the right-input object memory. Once all the assertions are finished and all right-input memories populated, we can then iterate the list of LeftInputAdatperNode Command objects calling each in turn. They will propagate down the network attempting to join with the right-input objects, but they won't be remembered in the left input as we know there will be no further object assertions and thus propagations into the right-input memory.

There is no longer an Agenda, with a priority queue to schedule the Tuples; instead, there is simply an elements for the number of rules. The sequence number of the RuleTerminalNode indicates the element within the elements where to place the Match. Once all Command objects have finished we can iterate our elements, checking each element in turn, and firing the Matches if they exist. To improve performance, we remember the first and the last populated cell in the elements. The network is constructed, with each RuleTerminalNode being given a sequence number based on a salience number and its order of being added to the network.

Typically the right-input node memories are Hash Maps, for fast object deletion; here, as we know there will be no object deletions, we can use a list when the values of the object are not indexed. For larger numbers of objects indexed Hash Maps provide a performance increase; if we know an object type has only a few instances, indexing is probably not advantageous, and a list can be used.

Sequential mode can only be used with a Stateless Session and is off by default. To turn it on, either call RuleBaseConfiguration.setSequential(true), or set the rulebase configuration property drools.sequential to true. Sequential mode can fall back to a dynamic agenda by calling setSequentialAgenda with SequentialAgenda.DYNAMIC. You may also set the "drools.sequential.agenda" property to "sequential" or "dynamic".

Drools has the concept of stateful or stateless sessions. We've already covered stateful sessions, which use the standard working memory that can be worked with iteratively over time. Stateless is a one-off execution of a working memory 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 a rule engine like a function call with optional return results.

In Drools 4 we supported these two paradigms but the way the user interacted with them was different. StatelessSession used an execute(...) method which would insert a collection of objects as facts. StatefulSession didn't have this method, and insert used the more traditional insert(...) method. The other issue was that the StatelessSession did not return any results, so that users themselves had to map globals to get results, and it wasn't possible to do anything besides inserting objects; users could not start processes or execute queries.

Drools 5.0 addresses all of these issues and more. The foundation for this is the CommandExecutor interface, which both the stateful and stateless interfaces extend, creating consistency and ExecutionResults:



The CommandFactory allows for commands to be executed on those sessions, the only difference being that the Stateless Knowledge Session executes fireAllRules() at the end before disposing the session. The currently supported commands are:

  • FireAllRules

  • GetGlobal

  • SetGlobal

  • InsertObject

  • InsertElements

  • Query

  • StartProcess

  • BatchExecution

InsertObject will insert a single object, with an optional "out" identifier. InsertElements will iterate an Iterable, inserting each of the elements. What this means is that a Stateless Knowledge Session is no longer limited to just inserting objects, it can now start processes or execute queries, and do this in any order.


The execute method always returns an ExecutionResults instance, which allows access to any command results if they specify an out identifier such as the "stilton_id" above.


The execute method only allows for a single command. That's where BatchExecution comes in, which represents a composite command, created from a list of commands. Now, execute 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.

As mentioned previosly, 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.

Commands support out identifiers. Any command that has an out identifier set on it will add its results to the returned ExecutionResults instance. Let's look at a simple example to see how this works.


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.

A custom XStream marshaller can be used with the Drools Pipeline to achieve XML scripting, which is perfect for services. Here are two simple XML samples, one for the BatchExecution and one for the ExecutionResults.



Spring and Camel, covered in the integrations book, facilitate declarative services.


The CommandExecutor returns an ExecutionResults, and this is handled by the pipeline code snippet as well. A similar output for the <batch-execution> XML sample above would be:


The BatchExecutionHelper provides a configured XStream instance to support the marshalling of Batch Executions, where the resulting XML can be used as a message format, as shown above. Configured converters only exist for the commands supported via the Command Factory. The user may add other converters for their user objects. This is very useful for scripting stateless or stateful knowledge sessions, especially when services are involved.

There is currently no XML schema to support schema validation. The basic format is outlined here, and the drools-pipeline module has an illustrative unit test in the XStreamBatchExecutionTest unit test. The root element is <batch-execution> and it can contain zero or more commands elements.


This contains a list of elements that represent commands, the supported commands is limited to those Commands provided by the Command Factory. The most basic of these is the <insert> element, which inserts objects. The contents of the insert element is the user object, as dictated by XStream.


The insert element features an "out-identifier" attribute, demanding that the inserted object will also be returned as part of the result payload.


It's also possible to insert a collection of objects using the <insert-elements> element. This command does not support an out-identifier. The org.domain.UserClass is just an illustrative user object that XStream would serialize.


Next, there is the <set-global> element, which sets a global for the session.


<set-global> also supports two other optional attributes, out and out-identifier. A true value for the boolean out will add the global to the <batch-execution-results> payload, using the name from the identifier attribute. out-identifier works like out but additionally allows you to override the identifier used in the <batch-execution-results> payload.


There is also a <get-global> element, without contents, with just an out-identifier attribute. (There is no need for an out attribute because retrieving the value is the sole purpose of a <get-global> element.


While the out attribute is useful in returning specific instances as a result payload, we often wish to run actual queries. Both parameter and parameterless queries are supported. The name attribute is the name of the query to be called, and the out-identifier is the identifier to be used for the query results in the <execution-results> payload.


The <start-process> command accepts optional parameters. Other process related methods will be added later, like interacting with work items.





Support for more commands will be added over time.

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. You will need to have some implementation of the Java Transaction API (JTA) installed. For development purposes we recommend the Bitronix Transaction Manager, 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 you can continue to use it after a rollback. To load a previously persisted Stateful Knowledge Session 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: