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:
<?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.
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.
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.