Building a DRL based project makes use of Apache Maven and aligns with standard Apache Maven practices. These projects or modules are simply an Apache Maven Java project or module; with an additional metadata: file META-INF/kmodule.xml. The kmodule.xml file is the descriptor that selects resources to knowledge bases and configures those bases and sessions.

While standard Apache Maven can build and package these resources, it will not provide validation at build time. There is an Apache Maven plugin (kie-maven-plugin) which is recommended to use to get build time validation. The plugin also generates many classes, making the runtime loading faster too.

kmodule.xml

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:

An empty kmodule.xml example
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule"/>

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.

Creating a KieContainer that reads the files to be built from the classpath
KieServices kieServices = KieServices.Factory.get();
KieContainer kieContainer = kieServices.getKieClasspathContainer();

KieServices is the interface from where it is possible to access all the KIE building and runtime facilities. In the code above, all the Java sources and the KIE resources are compiled and deployed into the KieContainer which makes its contents available for use at runtime.

The kmodule.xml allows to define and configure one or more KieBase s and for each KieBase all the different KieSession s that can be created from it, as showed by the example. Then it is possible to simply retrieve the KieBase s and KieSession s from the KieContainer using their names.

Obtaining KieBase and KieSession using their names from kmodule.xml
KieServices kieServices = KieServices.Factory.get();
KieContainer kieContainer = kieServices.getKieClasspathContainer();

KieBase kieBase1 = kieContainer.getKieBase("KBase1");
KieSession kieSession1 = kieContainer.newKieSession("KSession2_1");
StatelessKieSession kieSession2 = kieContainer.newStatelessKieSession("KSession2_2");

pom.xml

To run decision in embedded java mode, we will need to use kie-maven-plugin in our project. Also few a KIE specific dependencies are needed. Please update your pom.xml in the following way.

  <packaging>kjar</packaging>
  ...
  <dependencies>
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-compiler</artifactId>
    </dependency>
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-model-compiler</artifactId>
    </dependency>
    <!-- For DebugRuleRuntimeEventListener.java -->
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-core</artifactId>
    </dependency>
    <!-- For DRL files -->
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-mvel</artifactId>
    </dependency>
    <!-- For kmodule.xml -->
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-xml-support</artifactId>
    </dependency>
    <!-- Logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.13</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>2.0.13</version>
    </dependency>
  </dependencies>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.kie</groupId>
        <artifactId>kie-maven-plugin</artifactId>
        <extensions>true</extensions>
      </plugin>
    </plugins>
  </build>

KieBase

The 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. The KieBase can be obtained from the KieContainer containing the KieModule where the KieBase has been defined.

KieBase kieBase = kieContainer.getKieBase();

KieSession

The KieSession stores and executes on the runtime data. It is created from the KieBase and has two implementations.

Stateful

The first session stateful. It is obtained using the newKieSession() method. Stateful sessions can be worked with iteratively over time.

KieSession kieSession = kieBase.newKieSession();

Stateless

The session is stateless. It is obtained using newStatelessKieSession() method. 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.

StatelessKieSession kieSession = kieBase.newStatelessKieSession();

KieRuntime

The KieRuntime provides methods that are applicable to both rules and processes, such as setting globals and registering channels. ("Exit point" is an obsolete synonym for "channel".)

Globals

Globals are named objects that are made visible to the Drools rule engine, but in a way that is fundamentally different from the one for facts: changes in the object backing a global do not trigger reevaluation of rules. Still, globals are useful for providing static information, as an object offering services that are used in the RHS of a rule, or as a means to return objects from the Drools rule engine. When you use a global on the LHS of a rule, make sure it is immutable, or, at least, don’t expect changes to have any effect on the behavior of your rules.

A global must be declared in a rules file, then it needs to be backed up with a Java object.

global java.util.List list

With the KieBase now aware of the global identifier and its type, it is now possible to call ksession.setGlobal() with the global's name and an object, for any session, to associate the object with the global. Failure to declare the global type and identifier in DRL code will result in an exception being thrown from this call.

List<String> list = new ArrayList<>();
kieSession.setGlobal("list", list);

Make sure to set any global before it is used in the evaluation of a rule. Otherwise a NullPointerException will be thrown.

Event Model

The event package provides means to be notified of Drools rule engine events, including rules firing, objects being asserted, etc. This allows separation of 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.

kieSession.addEventListener(new DefaultAgendaEventListener() {
    public void afterMatchFired(AfterMatchFiredEvent event) {
        super.afterMatchFired(event);
        System.out.println(event);
    }
});

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:

kieSession.addEventListener(new DebugRuleRuntimeEventListener());

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

Note
To see available events browse org.kie.api.event.rule package.

KieRuntimeLogger

The KieRuntimeLogger uses the comprehensive event system in Drools to create an audit log that can be used to log the execution of an application for later inspection.

KieRuntimeLogger logger =
  KieServices.Factory.get().getLoggers().newFileLogger(kieSession, "logdir/mylogfile");
// ... kieSession in action ...
logger.close();

Commands and the CommandExecutor

Both the stateful and stateless session interfaces extend the CommandExecutor interface. 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 CommandFactory.

ExecutionResults executionResults = statelessKieSession.execute(
    CommandFactory.newBatchExecution(Arrays.asList(
        CommandFactory.newInsert(new Applicant("#0001", 20), "applicant"),
        CommandFactory.newInsert(new LoanApplication("#0001"), "application"),
        new SetActiveAgendaGroup("applicationGroup")
      )
    )
);

executionResults.getResults().get("application");

The previous example executes a single command. 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. Please notice "applicant" and "application" identifiers in our example.

Complete example

Most of the mentioned concepts can be seen as rules-embedded-mode-example. The example is based on the loan application age limit rule present Business Rules with Drools document.