Drools tutorial – The Rule Engine made simple

In this tutorial we will learn about the JBoss Drools Rule engine and how to run a simple application on the top of it using Drools latest release (7.61.0 released November 2021 ). Before getting into a simple example, we need to clarify some concepts about Rules, Rule engines and what is Drools.

What is Drools Rule Engine ?

A Rule Engine refers to a system that uses rules, in any form, to a set of data to produce outcomes. It may refer to simple systems like form validation or more complex systems like dynamic expression engines. In a few words, a Rule engine allows you to say “What to do” and not “How to do it”.

Why using Drools Rule Engine ?

Rule systems can solve very hard problems, explaining of each “decision” taken along the way. Here is a list of a Rule engine benefits:

  • Logic and Data Separation: Breaking your domain objects from business rules can lead to a simpler application maintenance. That can shield from changes in the future, since the logic is all laid out in rules.
  • Speed and Scalability: Many times we apply “if” conditions that we don’t really need. The Rete algorithm, as implemented by Drools, replaces all the if … then statements with an optimized network.
  • Centralization of Knowledge: By using rules, you create a repository of knowledge  for your business policy. Ideally, rules are so readable that they can also serve as documentation
  • Tool Integration: Writing rules means also to get accustomed to Rule language, validation and debugging. Eclipse provides an excellent tool to deliver and test your Rules.
  • Understandable Rules: JBoss Drools rules can make it easy to express solutions to complex problems and consequently have those solutions verified (rules are much easier to read then code). Often, business users are more comfortable expressing things that they know to be true, than to express things in an if…then format. Examples of things that you might hear from a business expert are:

We need to buy that estate if the price is not over 1000000 $ and estate agency doesn’t claim more than 5000 $“.
We buy shares when the price goes over 15 Euro before next week

By focusing on what we know to be true, rather than traditional “if…then” clause, the logic is much cleaner.

Drools Rule engine ecosystem

Now that we know what a Rule system is, our drool tutorial will focus on the following components that make up the Drools Rule engine ecosystem:

Drools Fusion gives the rules engine the ability to perform event processing, often referred to as complex event processing ( CEP ).

jBPM is a means of describing some process that occurs within your organization as a series of steps. jBPM lets you design how to connect these steps and to assign an owner to each step. jBPM, which is based on the BPMN 2.0 specification, serves as a tool for describing such processes in a flowchart
format. jBPM supports the entire process life cycle, from development to execution and management up to retirement.

Drools Guvnor provides us with a centralized repository with a layer of user authentication in which we can store and manage our rules, processes, models, and other entities related to knowledge bases.

Drools Planner helps us to carry out automated planning, to optimize how we distribute and utilize resources in an organization. This process helps to consider multiple solutions and choose which works best for us.

Business Central Workbench: Business Central Workbench is the web application and repository to govern Rules and Business Process. Within the Business Central, you can design and deploy your assets. It was formerly known as the Kie WorkBench.

The following picture depicts the core components of Drools Rule engine architecture:

Developing applications with JBoss Drools

In order to develop applications using Drools, you can use any IDE which supports Maven. We, however, recommend using an Eclipse based environment (Eclipse or Code Ready Studio) which can use the Drools Plugin for Eclipse.

Therefore, in this tutorial we will show how to create a simple project using Eclipse with Drools Plugin. If you want to check how to install the Drools Plugin on Eclipse / JBoss Developer Studio, check this tutorial: Installing Drools plugin on Eclipse

An Hello World Drool Project

Once you have installed the Drools plugin for Eclipse, you will be able to create a New Drools project from the “New…” Menu

Click Next. In the following Window, choose the initial project contents. We will just need a blank project with the correct Maven folders:

In the last screen you have to choose how to build your project. You have mainly two options:

  • Use a local Drools Runtime: This can be a handy solution if you are working offline and you want to use the libraries which are bundled in Drools Engine.
  • Use a Maven project: This should be your default option as it generates a Maven project with all Drools dependencies in place.

We will choose to use a Maven project. Check at the end of the article for instructions how to use the local Drools Runtime.

Now the project will be created so we can add two core pieces:

  1. A simple Rule which interacts with a Java instance (a fact) passed to the Rule
  2. A Java main class to execute the Rule

Let’s add at first a new Rule. From the File menu choose to add a new Rule:

As you can see, you will be requested to enter a Rule file name and the Type of resource Rule. In our case we will create the Rule.drl file name as part of a rule package. The rule will be in the rules package name. Here is the simple Rule:

package com.sample.rules

dialect "mvel"

import com.sample.DroolsShop.Customer
import com.sample.DroolsShop.Product
import com.sample.DroolsShop.Purchase
import com.sample.DroolsShop.Discount
 
rule "Purchase notification"
    salience 10

    when
        $c : Customer()
        $p : Purchase( customer == $c )
    then
        System.out.println( "Customer " + $c.name + " just purchased " + $p.product.name );
end
 
rule "Discount removed notification"
    when
        $c : Customer()
        not Discount( customer == $c )
    then
        $c.discount = 0;
        System.out.println( "Customer " + $c.name + " now has a discount of " + $c.discount );
end

rule "Discount awarded notification"
    when
        $c : Customer()
        $d : Discount( customer == $c )
    then
        System.out.println( "Customer " + $c.name + " now has a discount of " + $d.amount );
end

rule "Apply 10% discount if total purchases is over 100"
    no-loop true
    dialect "java"
    when
        $c : Customer()
        $i : Double(doubleValue > 100) from accumulate (
                Purchase( customer == $c, $price : product.price ),
                sum( $price )
        )
    then
        $c.setDiscount( 10 );
        insertLogical( new Discount( $c, 10 ) );
        System.out.println( "Customer " + $c.getName() + " now has a shopping total of " + $i );
end

Let’s learn a bit about Drools Rule syntax.

dialect

The first keyword we have met is “dialect” which shows which language you can use to code your Drool Rules. You have mainly two options:

  • mvel” which an expression language with a simple and powerful syntax which simplifies access to getter and setter methods of your objects
  • java” which allows using java to code Drools rules. Some restrictions apply: you cannot use Java code inside “when” part of a condition but you can use Java code in “then” part.

salience

salience is a keyword in the .drl file that we can assign a positive or negative number. The number determines the salience priority. A higher number denotes a higher priority, so the Drools engine will execute rules with a higher salience first.

no-loop true

Self-loops are very common to find in our rules, hence Drools already comes with a special attribute we can use in our rules to avoid these situations: no-loop. If you don’t want to activate your Rules multiple times, mark them with the no-loop attribute.

accumulate functions

Accumulate is a conditional element available in Drools since version 4.0 and it is used to iterate over the list of objects and allows to perform java operations to validate the data.

In our case, when this condition is met:

    when
        $c : Customer()
        $i : Double(doubleValue > 100) from accumulate (
                Purchase( customer == $c, $price : product.price ),
                sum( $price )
        )

Then the variable “i” will be set to the sum of items which have been purchased.

insertLogical

insertLogical(new Something()); is similar to insert, but the Rule engine will automatically retract it when there are no more facts to support the truth of the currently firing rule.

In order to execute them we’ll create a Java Class named DroolsShop. For the sake of simplicity, we will include all Java Beans in the Main class, so that we have to create just one Java class:

package com.sample;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;

public class DroolsShop {

    public static final void main(String[] args) {
        KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
        System.out.println(kc.verify().getMessages().toString());
        execute( kc );
    }

    public static void execute( KieContainer kc ) {
        KieSession ksession = kc.newKieSession("ksession-rules");

        Customer mark = new Customer( "mark",
                                      0 );
        ksession.insert( mark );

        Product shoes = new Product( "shoes",
                                     60 );
        ksession.insert( shoes );

        Product hat = new Product( "hat",
                                   60 );
        ksession.insert( hat );

        ksession.insert( new Purchase( mark,
                                       shoes ) );

        FactHandle hatPurchaseHandle = ksession.insert( new Purchase( mark,
                                                                      hat ) );

        ksession.fireAllRules();

        ksession.delete( hatPurchaseHandle );
        System.out.println( "Customer mark has returned the hat" );
        ksession.fireAllRules();
    }

    public static class Customer {
        private String name;

        private int    discount;

        public Customer(String name,
                        int discount) {
            this.name = name;
            this.discount = discount;
        }

        public String getName() {
            return name;
        }

        public int getDiscount() {
            return discount;
        }

        public void setDiscount(int discount) {
            this.discount = discount;
        }

    }

    public static class Discount {
        private Customer customer;
        private int      amount;

        public Discount(Customer customer,
                        int amount) {
            this.customer = customer;
            this.amount = amount;
        }

        public Customer getCustomer() {
            return customer;
        }

        public int getAmount() {
            return amount;
        }

    }

    public static class Product {
        private String name;
        private float  price;

        public Product(String name,
                       float price) {
            this.name = name;
            this.price = price;
        }

        public String getName() {
            return name;
        }

        public float getPrice() {
            return price;
        }

    }

    public static class Purchase {
        private Customer customer;
        private Product  product;

        public Purchase(Customer customer,
                        Product product) {
            this.customer = customer;
            this.product = product;
        }

        public Customer getCustomer() {
            return customer;
        }

        public Product getProduct() {
            return product;
        }
    }
}

This class does the following actions:

  • Creates a KieContainer from the KieServices.Factory
  • Bootstraps the Rule Engine session: The KieSession represents a running instance of the Rule Engine with a specific configuration and set of rules. It holds the evaluation algorithm used to match the rules against our domain objects.
  • Let the Rule Engine to know about our data: We are responsible for providing all the information to the engine through the insert() method on KieSession. Next, if the information that we provided matches with one or more available rules, we will get Matches. Calling the fireAllRules() method will execute these matches.

As you might have noticed, we have inserted two objects in the KieSession:

ksession.insert( new Purchase( mark, shoes ) );

FactHandle hatPurchaseHandle = ksession.insert( new Purchase( mark, hat ) );

For the latter Purchase, we return the FactHandle so that we can later delete it from the KieSession:

ksession.delete( hatPurchaseHandle );

Then, as a proof of concept, we fire again all Rules to verify that the Discount (for purchases over 100) has been cancelled.

The last thing we need to do in order to complete our project, is a file in the src/main/resources/META-INF/ directory called kmodule.xml. This file is used to configure how to load the rules defined in the project in the rule engine. For now, the content of kmodule.xml will be quite simple as we will be using all the default configurations. Here is a sample content of it:

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
    <kbase name="rules" packages="com.sample.rules">
        <ksession name="ksession-rules"/>
    </kbase>
    <kbase name="dtables" packages="com.sample.dtables">
        <ksession name="ksession-dtables"/>
    </kbase>
    <kbase name="process" packages="com.sample.process">
        <ksession name="ksession-process"/>
    </kbase>
</kmodule>

Here is how your project source tree should look like:

src
└── main
    ├── java
    │   └── com
    │       └── sample
    │           └── DroolsShop.java
    └── resources
        ├── com
        │   └── sample
        │       ├── dtables
        │       ├── process
        │       └── rules
        │           └── Rule.drl
        ├── logback-test.xml
        └── META-INF
            ├── kmodule.xml
            └── maven
                └── pom.properties

Building and Running the application

To build Drools application we recommend including the following Bill of Material:

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-bom</artifactId>
        <type>pom</type>
        <version>${drools-version}</version>
        <scope>import</scope>
      </dependency>
    </dependencies>
</dependencyManagement>

Then, include as property the latest version of Drools which is 7.61.0:

<drools-version>7.61.0.Final</drools-version>

You can run the App class from the IDE with “Run as Java Application”.

When executed the output will be:

Customer mark just purchased shoes
Customer mark just purchased hat
Customer mark now has a discount of 0
Customer mark now has a shopping total of 120.0
Customer mark now has a discount of 10
Customer mark has returned the hat
Customer mark now has a discount of 0

This is a basic example taken from the Drools examples available in the GitHub repository. In the following articles we’ll see how a rules engine can significantly reduce the complexity of components that implement the business-rules logic in your Java applications. By expressing your rules using JBoss Drools declarative approach your application has a higher chance of being more maintainable and extensible than one that doesn’t.

Source code for this tutorial: https://github.com/fmarchioni/mastertheboss/tree/master/drools/helloworld-eclipse

Using a Local Drools Rule Engine Runtime

If you prefer, you can complete this tutorial by using a Drools Rule Engine Runtime which can be downloaded as a zip from http://www.drools.org/download/download.html

As you can see from the above screen, you have two options:

1. Specify where the Drools Rule Engine Runtime is located

2. Specify the Maven GAV

In case you have already a Runtime,  you can simply choose to Add Runtime selecting the “binaries” sub folder of your Drools Distribution:

Continue Learning Drools Rule Engine

Continue Learning Drools Rule Engine through the following tutorials:

1) Creating a Drools project from the Command Line with Maven

If you are not using Red Hat Code Ready Studio or Eclipse to develop your project, as simple environment Maven based will work.  The following tutorial shows how to create a minimal Drools project using Maven: Drools and Maven Hello World example

Then, import the project in your IDE and manage it from there.

2) Coding Rules in Decision Tables

In Drools, Decision Tables are a way to generate rules from the data entered into a spreadsheet. The spreadsheet can be a standard Excel (XLS) or a CSV File.

If you want to learn how to code your Rules into an excel Spread Sheet, keep reading this tutorial: Getting started with Decision Tables in Drools

3) Getting started with the Kie Execution Server

The Kie Server is a Java web application that allows us to expose rules and business process to be executed remotely using REST and JMS interfaces. The following tutorial shows how to install it on the top of WildFly: Configure Kie Execution Server on WildFly

4) Deploy your assets on the Business Central

Once that you are familiar with the Kie Execution Server, you can learn how install also the Business Central where you can design, build and deploy your assets. Here is the tutorial for you: Getting started with Business Central Workbench

Enterprise Drools

Are you interested in a supported versions of Drools and jBPM?  Red Hat provides support for them as follows:

Introduction to Drools Rules

This tutorial provides an introduction to JBoss Drools, covering the core concepts, how to bootstrap a Drools project, how to code a simple Drool rule file and which tools can be used to run the Drools runtime engine

Drools in a nutshell

Drools is a business-rule management system with an inference-based rules engine, which allows a fast and reliable evaluation of business rules and complex event processing. A rules engine is also a fundamental building block to create an expert system which, in artificial intelligence, is a computer system that emulates the decision-making ability of a human expert.

Drools is part of KIE (Knowledge Is Everything) which is an umbrella project that includes:

  • Drools Rule engine
  • jBPM which is a flexible Business Process Management suite
  • Business Central which is a full featured web application for the visual composition of custom business rules and processes.
  • Drools Planner which helps us to carry out automated planning, in order to optimize how we distribute and utilize resources in an organization, sometimes we need to consider multiple possible solutions and choose which works best for us.

Getting started with Drools

The Drools Rule engine is the heart of Drools. The Drools engine stores, processes, and evaluates data to execute the business rules or decision models that you define. The basic function of the Drools engine is to match incoming data, or facts, to the conditions of rules and determine whether and how to execute the rules.

The Drools engine operates using the following basic components:

  • Rules: Business rules or DMN decisions that you define. All rules must contain at a minimum the conditions that trigger the rule and the actions that the rule dictates.
  • Facts: are domain model objects (Plain Old Java Objects (POJOs)) used by Drools to evaluate conditions and execute consequences.
  • Production memory: location where rules are stored in the Drools engine.
  • Working memory: a stateful object which contains objects acted upon by business rules.
  • Agenda: location where activated rules are registered and sorted (if applicable) in preparation for execution.

When a business user or an automated system adds or updates rule-related information in Drools, that information is inserted into the Working Memory of the Drools engine in the form of one or more Facts.

The Drools engine matches those facts to the conditions of the rules that are stored in the Production Memory to determine eligible rule executions. (The process of matching facts with rules is often referred to as “pattern matching”.) When rule conditions are met, the Drools engine activates and registers rules in the Agenda, where the Drools engine then sorts prioritized or conflicting rules in preparation for execution.

Methods for authoring Drools Rules

The following methods are available for coding Drools Rules:

  • DRL files (drl and rdrl ) using the Drools Rule Language syntax.
  • Decision tables stored in an Excel/CSV spreadsheet (xsl, xslx) following a Drools template for defining Constraints and Facts.
  • Domain-Specific Language (DSL) rule files (rdslr) using a “natural” programming language that mimics the domain specific language. This provides business users more control of modeling decisions without a complex programming language.

We will provide an overview of DRL files. To see an example of Drools Decision Tables check this example: Getting started with Drools Decision Tables

Coding Drools Rules with DRL

Drools Rule Language (DRL) is a declarative language for writing rules that supports expressions written in multiple dialects. Currently, Drools supports two dialects:

  • Java
  • MVEL Expression Language

Rules are organized in the same way as Java packages and are stored in plain text DRL files. A rule is composed of:

  • A list of constraints on facts expressed as a series of WHEN statements.
  • An action executed by this rule if facts with the list of constraints are found in the working, specified as a series of THEN actions.

Taking as an example, the following Rule validates a Server configuration:

import com.sample.Server
rule "Check Server Configuration"
  when
  $server : Server( processors < 2 || memory<=1024 || diskspace <= 2048)
  then
  $server.setValid(false);
  System.out.println("Server "+ $server.getName() + " configuration does not meet requirements!");
end

How do we fire Drools Rules? we need to use an object called KIE Session.

KIE sessions

In order to insert facts in the Working Memory and fire rules, you need to reference a KIE session. The KIE session is in turn created from a KIE base or directly from a KIE container if you have defined the KIE session in the KIE module descriptor file (kmodule.xml) for your project.

For example, the following kmodule.xml file defines the following KIE Sessions for Rules, Processes and Decision Tables:

<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
    <kbase name="rules" packages="com.sample.rules">
        <ksession name="ksession-rules"/>
    </kbase>
    <kbase name="dtables" packages="com.sample.dtables">
        <ksession name="ksession-dtables"/>
    </kbase>
    <kbase name="process" packages="com.sample.process">
        <ksession name="ksession-process"/>
    </kbase>
</kmodule>

For test purposes, you can also leave an empty definition of KIE session in the kmodule.xml file. In this case, you will be using the default Kie Session:

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

Stateless vs Stateful Kie Session

A stateless KIE session is a session that does not use inference to make iterative changes to facts over time. In a stateless KIE session, data from a previous invocation of the KIE session (the previous session state) is discarded between session invocations, whereas in a stateful KIE session, that data is retained.

In a stateless KIE session configuration, the execute() call acts as a combination method that instantiates the KieSession object, adds all the user data and executes user commands, calls fireAllRules(), and then calls dispose(). See the following example, which inserts some Server objects in the KieSession and then fires the Rules loaded:

KieServices kieServices = KieServices.Factory.get();

KieContainer kContainer = kieServices.getKieClasspathContainer();

KieBase kieBase = kContainer.getKieBase();

LOG.info("There should be rules: ");
for ( KiePackage kp : kieBase.getKiePackages() ) {
    for (Rule rule : kp.getRules()) {
        LOG.info("kp " + kp + " rule " + rule.getName());
    }
}

KieSession session = kieBase.newKieSession();

Server s1 = new Server("rhel7",2,1024,2048);
session.insert(s1);
session.fireAllRules();
assertTrue(s1.isValid());

Server s2 = new Server("rhel8",2,2048,4096);
session.insert(s2);
session.fireAllRules();
assertTrue(s2.isValid());

Building Drools projects

When using Maven, the recommended way to build Drools project is to include the Drools BOM in your dependencyManagement section, and the drools-compiler and kie-api as a dependency:

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-bom</artifactId>
        <type>pom</type>
        <version>${drools-version}</version>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-api</artifactId>
    </dependency>
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-compiler</artifactId>
      <scope>runtime</scope>
    </dependency>
    ...
  <dependencies>

The Maven project for this example is available here: https://github.com/fmarchioni/mastertheboss/tree/master/drools/helloworld

Tools for writing Drools Rules

There are mainly two options for authoring Drools Rules:

  • Using JBoss Tooling for Eclipse: this option requires installing some tooling on the top of your Eclipse IDE. That’s the ideal option for developers and tester to get started.
  • Using the Business Central: this is an advanced Web application, which is part of the Process Automation Manager (PAM) suite, which includes a guided Rules authoring interface that will let you write your Rules from Business models without programming expertise.

Creating Rules with Drools Eclipse plugin

Drools provides an Eclipse-based IDE which requires to download and install the JBoss Tools Eclipse plug-in. This will provide you with all the dependencies you need to get going: you can simply create a new rule project and everything will be set in place for you. Then, it’s just a matter of adding a Business Rule Task to your Process, with the Rule definition:

Refer to the following tutorials for learning how to install and use the JBoss Tools plugin for Eclipse: Installing Drools plugin on Eclipse

Using the Eclipse plug-in for coding your Rules is not required though. Rule files are just textual input (or spreadsheets as the case may be) and the IDE (also known as Business Central) is just a convenience. In real-world scenario, where Rule developers don’t have deep developer’s experitse, it is recommended to use the Business Central and its guided Process and Rule designer.

Creating Rules with the Business Central

The Process Automation Manager (PAM) is a middleware platform for creating cloud-native business automation applications and microservices. It includes the following core components:

  • Business Central: provides a graphical environment for authoring Drool Rules (Business Rule Management System) and jBPM processes (Business Process Management System) and manage their deployments. It includes an embedded Maven repository that stores all the artifacts generated, and a Git repository that manages the updates made to the artifacts.
  • Kie Execution Server: is the runtime component of the PAM and can be deployed on any environment that supports Java EE application servers. It is in charge to execute the processes, rules, and planning execution from OptaPlanner.
  • KIE Controller: accessible from the Business Central web UI, the KIE Controller manages each application deployed on Process Automation Manager.

The following is an high level overview of the Business Central:

When editing Rules with the BRMS, maven is fully supported in both direction :

1. The BRMS can retrieve maven artifact from its local repository as well as from remote maven repositories.

2. The BRMS can act as a remote Maven repository and can be access from external maven builds.

To learn more about the Business Central, we recommend reading the following tutorial: Getting started with jBPM Business Central

Drools Community version and Enterprise version

Drools is available in two versions: a Community version and an Enterprise version, called Red Hat Decision Manager, which is supported by Red Hat

You can download the Community version of Drools from: https://www.drools.org/download/download.html

https://www.drools.org/

If you have an active subscription with Red Hat, you can access Red Hat Decision Manager from: https://access.redhat.com/products/red-hat-decision-manager/

What is JBoss Drools?

In this tutorial we will learn what is Drools and some basics of its architecture and API.

Drools is the rules engine of the KIE (Knowledge Is Everything) umbrella project. Drools engine stores, processes, and evaluates data to execute the business rules or decision models that you define.

The main concept to understand about Drools is that its decision engine matches incoming data, or facts, to the conditions of rules and determine whether and how to execute the rules.

Where Drools can be downloaded

The current version of Drools is the 7.36 and can be downloaded from here: https://www.drools.org/download/download.html.
The Enterprise-ready supported by Red Hat version of Drools is called Red Hat Decision Manager and can be downloaded from here: https://developers.redhat.com/products/red-hat-decision-manager/download

Drools main components

Drools engine includes the following components:

  • Rules: Business rules or DMN decisions defined by you. All rules contain the conditions that trigger the rule execution and the actions to be taken accordingly.
  • Facts: This is the data used by the Rules and thus are used by the decision engine to match the rule conditions and execute actions.
  • Production memory: This is where rules are stored in Drools.
  • Working memory: This is where facts are stored in Drools.
  • Agenda: This is where activated rules are registered and sorted (if applicable) in order to be executed.

When an user or an automated process inserts/updates Facts, that information is inserted into the working memory of the Drools. Drools’ decision engine then matches those facts to the conditions of the rules that are stored in the production memory to determine which Rule are eligible for execution. This process is also known as pattern matching. Finally, if rule conditions are met, Drools engine activates and registers rules in the agenda, where the decision engine then sorts prioritized or conflicting rules in preparation for execution.

Here is an example of Rule defined to determine the age limit of an user:

rule "CanDrive"
  salience 15
  agenda-group "applicationGroup"
  when
    $application : LoanApplication()
    Applicant( age < 18 )
  then
    $application.setApproved( false );
    $application.setExplanation( "Sorry you cannot drive" );
end

The following diagram illustrates these basic components of the decision engine:

Drools API

These are the main API available to manage Drools engine from your code:

  • KieBase: This is the repository of all the application’s knowledge definitions. It contains rules, processes, functions, type models. The KieBase itself does not contain runtime data, instead sessions are created from the KieBase in which data can be inserted and process instances started.
  • KieModule: This is the container of all the resources necessary to define a set of KieBases, It is defined in a file named kmodule.xml which deckres the KieBases names and configurations together with all the .KieSession that can be created and all the other files necessary to build the KieBases themselves.
  • KieContainer: This is the container for all the KieBases of a given KieModule.
  • KieFileSystem: This is the in.memory file system used to define the resources composing a KieModule.
  • KieBuilder: This is the tool to build the resources contained in a KieModule.

Now let’s see how to create these objects.

KieContainer

This is the way to programmatically create a KieContainer in Drools 7:

KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();

KieBase

Once we have created the KieContainer, we create the KieBase. This is how to retrieve the default KieBase:

KieBase kBase1 = kContainer.getKieBase();  

On the other hand, to retrieve an user-defined KieBase named “KBase1”:

KieBase kBase1 = kContainer.getKieBase("KBase1");

Stateless Session

A stateless KIE session is a session that does not use inference to make iterative changes to facts over time. In a stateless KIE session, data from a previous invocation of the KIE session (the previous session state) is discarded between session invocations. Here is how to create a new Stateless Session:

KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();
StatelessKieSession kSession = kContainer.newStatelessKieSession();

Stateful Session

A stateful KIE session is a session that uses inference to make iterative changes to facts over time. In a stateful KIE session, data from a previous invocation of the KIE session is retained between session invocations.

KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();
KieSession ksession = kContainer.newKieSession();

KieContainer

Since a Kie project is also a Maven project the groupId, artifactId and version declared in the pom.xml file are used to generate a ReleaseId that uniquely identifies your project in your application. Therefore you can create a KieContainer from the project by passing thr ReleaseId to the KieServices.

KieServices kieServices = KieServices.Factory.get();
ReleaseId releaseId = kieServices.newReleaseId( "com.sample", "myapplication", "1.0" );
KieContainer kieContainer = kieServices.newKieContainer( releaseId );

Installing Drools plugin on Eclipse

In order to design your Drools or BPM Rules you have two main alternatives:

  • Install the Drools Plugin for Eclipse (available as part of Red Hat Integration Stack for Eclipse)
  • Install the Business Central Workbench and design your Rules/Processes in its Web application as discussed in this tutorial: Getting started with jBPM Business Central

Here we will show how to install the Drools plugin on the latest version of Eclipse.

Installing Drools Plugin on Eclipse

Reach out Drools Download page at: http://www.drools.org/download/download.html

Download the “Drools and jBPM tools” distribution zip file.

$ unzip droolsjbpm-tools-distribution-7.41.0.Final.zip -d /home/francesco/jboss

Once done with it unzip it in a folder. Next perform the following steps:

– Open Eclipse.
– Open the menu “Help“, menu item “Install new software...”
– Click on the button “Add…” to add a new software site.
– Fill in a name for it:  “Drools local”
– Click on the button “Local…” and point to the folder where you have unpacked  and point to its subdirectory “binaries/org.drools.updatesite” as you can see from the following picture:

– Select all the plugins. Click the buttons “Next” and “Finish”. You will need to restart Eclipse at the end of the installation.

Verifying the installation

With the Drools plugin activated, you will be able to create a New Drools project from the “New…” Menu

Click Next. In the following Window, choose the initial project contents. We will just need a blank project with the correct Maven folders:

In the last screen you have to choose where Drools libraries are to be found:

As you can see from the above screen, you have two options:

1. Specify where the Drools Runtime is located

2. Specify the Maven GAV

In case you have already downloaded the Drools Distribution zip from http://www.drools.org/download/download.html you can simply choose to Add Runtime selecting the “binaries” subfolder of your Drools Distribution:

Continue reading how to write Drools Rules: Drools Rule Engine tutorial

Getting started with jBPM Business Central

In this tutorial we will learn how to install the JBPM Business Central (which is the new name for the Drools workbench) and the Kie Execution Server on WildFly so that you have a full blown environment for designing and deploying your Kie assets!

The Business Central Workbench (Drools Workbench) is a web application where we can design and deploy your Kie assets, such as Drool Rules, Processes, and data models. It is an awesome tool to bridge the gap between developers and business people with little technical knowledge of the specifics of implementation into the development cycle, because it provides a user-friendly environment for rule writing.

Business rules, process definition files, and other assets and resources created in Business Central are stored in the Artifact Repository (Knowledge Store) that can be accessed by the Execution Server. If you want to know more about the Kie Execution Server take a look at the following article:

The Knowledge Store is a centralized repository for your business knowledge. It connects multiple git repositories so that you can access them from a single environment while storing different kinds of knowledge and artifacts in different locations. The Business Central provides a web front-end that enables you to view and update the stored content.

Before adding a sample asset to our repository we need some intallation.

Installing the Business Central

You can install the Business Central in two ways:

1) Download the jBPM Server Distribution which includes in the bundle

This is the simplest option and it is recommended if you are starting from scratch. Within the jBPM Server Distribution you’ll get the following components out of the box.
WildFly server

  • Business Central
  • KIE Server
  • jBPM Case Management showcase app
  • jBPM Service repository (with community work items)

In order to download the jBPM Server Distribution, pick up the latest final version at: https://www.jbpm.org/download/download.html

Unzip the distribution, then start the jBPM Server distribution with:

$ ./standalone.sh 

2) Download the Business Central and Kie Server war files

This option requires installing the Business Central, Kie Server and Kie Server Controller on the top of WildFly. Additionally, you will need to add some System Properties to fix the communication between the Business Central and the Kie Server. We have a tutorial which covers this option: Installing the Business Central on WildFly

Creating a Project using the Drools Workbench

Once that you have started WildFly, you can login into the into the Business Central Workbench with one of the available credentials (for example kieserver / kieserver1!) and you will be taken to the main screen:

We will now create a Project, add an Asset to it and deploy it to the Kie Server that is available on the same WildFly server.

Go to Menu → Design → Projects in Business Central and click on “Add Project

Enter the Project name and Description:

Next, click on Add Asset:

The list of assets you can add will be displayed in the next UI. Select to add a DRL file (a Drools Rule):

Choose a name for the DRL file and a default package:

The content of the Rule will be pretty simple: An Hello message will be printed to the variable “name” passed as attribute to the Rule:

Here is the same Rule, if you want to copy and paste it into the editor:

rule 'hello'
when
    $name: String()
then
    System.out.println("Hello " + $name);
end

Click on Save. You will return to the list of Assets for your Project:

Now Build and Deploy the Rule so that it will be copied into the Knowledge Store.

Return the main screen and click on the Deploy Menu. From there, you will have to create a new Server Configuration which will let you connect to your Assets. Choose a name and the capabilities for your server configuration as shown above and click on Next.

 

In the last screen, you have to enter the Deployment unit GAV. To make it simpler, a list of available assets is displayed in the GAV table so by clicking on Select will populate automatically the UI.

 

That’s all. Click on Finish and the Configuration will be available on your Kie Execution Server:

Testing our simple Rule

Now we can test our simple Rule with any available REST Client. Linux users have the ‘curl’ command available so just create an input file, say ‘hello.json‘ with the following content:

{
      "lookup" : null,
      "commands" : [ {
        "insert" : {
          "object" : "Francesco"
        }

      }, {
        "fire-all-rules" : { }
      } ]
    }

And now invoke the Rule on the Execution Server as follows (please notice the URL is slightly different from the one appearing in the Business Central Deploy UI):

curl -X POST -H 'X-KIE-ContentType: JSON' -H 'Content-type: application/json' -u 'kieserver:kieserver1!' --data @hello.json http://localhost:8080/kie-server/services/ret/server/containers/instances/DemoRule_1.0.0

Conclusion

In this tutorial we have learnt how to install the Drools WorkBench (now known as Business Central ) and the Kie Execution Server on WildFly, then we have created a simple Asset and made it available on a Kie Execution Server Container. We have finally executed the Asset with a minimal shell command.

Getting started with Drools Decision Tables

Drools Decision Tables are a compact way of representing conditional logic, and they can be used in Drools to define business rules. In this tutorial we will learn how to design and test them with an example.

A Drool Decision Table is a way to generate rules from the data entered into a spreadsheet. The spreadsheet can be a standard Excel (XLS) or a CSV File.

In a Drool Decision Table, each row is a rule and each column in that row is either a condition or action for that rule. Ideally, rules are authored without regard for the order of rows; this makes maintenance easier as rows will not need to be moved around all the time. As the rule engine processes the facts, any rules that match will fire. Here is an example of Excel using a Drool Decision Table:

In this spreadsheet a simple rule is included: if the Customer object’s age parameter equals to “1” the Customer is allowed a discount of 15%. If the Customer’s age is greater, a 25% discount is allowed.

Entries in a Rule Set area may define DRL constructs (except rules) and specify rule attributes. Entries must be given in a vertically stacked sequence of cell pairs. Here is a list of Entries that can be included in the SpreadSheet:

RuleSet: The package name for the generated DRL file. Must be First entry in the Drool Decision Table.

Sequential: Can be “true” or “false”. If “true”, then salience is used to ensure that rules fire from the top down. Optional, at most once. If omitted, no firing order is imposed.

EscapeQuotes: Can be “true” or “false”. If “true”, then quotation marks are escaped so that they appear literally in the DRL. If omitted, quotation marks are escaped.

Import: A comma-separated list of Java classes to import. Optional, may be used repeatedly.

Variables: Declarations of DRL globals, i.e., a type followed by a variable name.

Functions: One or more function definitions, according to DRL syntax. Optional.

Queries: One or more query definitions, according to DRL syntax. Optional.

Declare: One or more declarative types, according to DRL syntax. Optional.

Building the Drool Decision Table example

In the SpreadSheet we have declared a Java Object named Customer, so we will add it into our Project:

package com.mastertheboss.model;

public class Customer {

	private int age;
	private int discount;
	private String name;

	public Customer(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getDiscount() {
		return discount;
	}

	public void setDiscount(int discount) {
		this.discount = discount;
	}

}

And now a simple Java main class to test the Drool Rule contained in the Spreadsheet:

package com.mastertheboss;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;

import com.mastertheboss.model.Customer;

public class DroolsTest {

	public static final void main(String[] args) {
		try {
			KieServices ks = KieServices.Factory.get();
			KieContainer kContainer = ks.getKieClasspathContainer();
			KieSession kSession = kContainer.newKieSession("ksession-rule");

			Customer customer1 = new Customer("Frank");
			customer1.setAge(4);

			Customer customer2 = new Customer("John");
			customer2.setAge(1);

			FactHandle fact1 = kSession.insert(customer1);
			FactHandle fact2 = kSession.insert(customer2);
			
			kSession.fireAllRules();

			System.out.println("The discount for the Customer " + customer1.getName() + " is " + customer1.getDiscount());
			System.out.println("The discount for the Customer " + customer2.getName() + " is " + customer2.getDiscount());

		} catch (Throwable t) {
			t.printStackTrace();
		}
	}

}

Please notice that in this example it is assumed that a KieSession named “ksession-rule” is available in the classpath. Here is a view of the project structure which includes the kmodule.xml into the resources/META-INF folder and the spreadsheet into resources/rules:

src
├── main
│   ├── java
│   │   └── com
│   │       └── mastertheboss
│   │           ├── DroolsTest.java
│   │           └── model
│   │               └── Customer.java
│   └── resources
│       ├── Discount.xls
│       ├── META-INF
│       │   └── kmodule.xml
│       └── rules
│           └── rules.xls
└── test
    ├── java
    │   └── com
    │       └── mastertheboss
    │           └── RuleTest.java
    └── resources
        └── log4j.properties

When running the project, the expected output is:

The discount for the Customer Frank is 25
The discount for the Customer John is 15

Coding an Unit Test for our Drools Decision Table

We can easily turn our sample project into a JUnit Test. The set up will be a bit more verbose as we will build the KieSession from an external Resource:

package com.mastertheboss;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieRepository;
import org.kie.api.builder.ReleaseId;
import org.kie.api.io.Resource;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mastertheboss.model.Customer;

public class RuleTest {
	static final Logger LOG = LoggerFactory.getLogger(RuleTest.class);
	private KieServices kieServices = KieServices.Factory.get();
	private KieSession kSession;

	@Before
	public void setup() {
		Resource dt = ResourceFactory.newClassPathResource("rules/rules.xls", getClass());
		kSession = getKieSession(dt);
	}

	public KieSession getKieSession(Resource dt) {
		KieFileSystem kieFileSystem = kieServices.newKieFileSystem().write(dt);
		KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem).buildAll();
		KieRepository kieRepository = kieServices.getRepository();
		ReleaseId krDefaultReleaseId = kieRepository.getDefaultReleaseId();
		KieContainer kieContainer = kieServices.newKieContainer(krDefaultReleaseId);
		KieSession ksession = kieContainer.newKieSession();

		return ksession;
	}

	@Test
	public void testCustomer1CorrectDiscount() throws Exception {

		Customer customer = new Customer("Frank");
		customer.setAge(4);

		kSession.insert(customer);
		kSession.fireAllRules();

		assertEquals(customer.getDiscount(), 25);
	}

	@Test
	public void testCustomer2CorrectDiscount() throws Exception {
		Customer customer = new Customer("John");
		customer.setAge(1);
		kSession.insert(customer);
		kSession.fireAllRules();

		assertEquals(customer.getDiscount(), 15);
	}

}

When running the example from the Command Line or the Ide, is it expected that both assertions pass:

When to Use Drools Decision Tables?

Consider using Drools Decision Tables if your business rules exist can be expressed as rule templates and data: each row of a Decision Table provides data that is combined with a template to generate a rule. Many businesses already use spreadsheets for managing data. With Drools decision tables, you can also manage your business rules with spreadsheets. This assumes you are familiar to manage packages of rules in .xls or .csv files.

On the other hand, Drools Decision tables are not recommended for rules that do not follow a set of templates or where there are a small number of rules.

You can find the source code for this tutorial on Github: https://github.com/fmarchioni/mastertheboss/tree/master/drools/DecisionTable

Creating a Drools Project using kie-drools-archetype

In this short tutorial we will learn how to create a Drools Project using Maven’s kie-drools-archetype.

I’ve seen in many forums the questions which is the archetype for creating a Drools project. As you can see from the Maven’s repository (https://mvnrepository.com/artifact/org.kie/kie-drools-archetype) the correct archetype is the following one (in its latest version):

<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-drools-archetype</artifactId>
    <version>7.41.0.Final</version>
</dependency>

Please note: the version of the kie-drools-archetype matches with the Drools Engine version.

mvn archetype:generate -B -DarchetypeGroupId=org.kie -DarchetypeArtifactId=kie-drools-archetype -DarchetypeVersion=7.41.0.Final -DgroupId=com.mastertheboss -DartifactId=drools-project -Dversion=1.0-SNAPSHOT -Dpackage=drools.project

The above command will create the drools-project folder with a Maven project. Let’s check that everything is in order:

├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── drools
    │   │       └── project
    │   │           └── Measurement.java
    │   └── resources
    │       ├── META-INF
    │       │   └── kmodule.xml
    │       └── rules.drl
    └── test
        ├── java
        │   └── drools
        │       └── project
        │           └── RuleTest.java
        └── resources
            └── log4j.properties

The archetype has create a very basic Rule file (rules.drl) which loads a simple Fact in it:

package drools.project;

global java.util.Set controlSet;

rule "will execute per each Measurement having ID color"
no-loop
when
	Measurement( id == "color", $colorVal : val )
then
	controlSet.add($colorVal);
end

A Test class is included in the Archetype, which will insert into a KieSession new Measurement. Then it fires the Rule and expects that the Session contains the three different kind of Measurement inserted:

package drools.project;

import static org.junit.Assert.*;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.drools.core.time.SessionPseudoClock;
import org.junit.Test;
import org.kie.api.KieBase;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.definition.KiePackage;
import org.kie.api.definition.rule.Rule;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.conf.ClockTypeOption;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RuleTest {
    static final Logger LOG = LoggerFactory.getLogger(RuleTest.class);

    @Test
    public void test() {
        KieServices kieServices = KieServices.Factory.get();

        KieContainer kContainer = kieServices.getKieClasspathContainer();
        Results verifyResults = kContainer.verify();
        for (Message m : verifyResults.getMessages()) {
            LOG.info("{}", m);
        }

        LOG.info("Creating kieBase");
        KieBase kieBase = kContainer.getKieBase();

        LOG.info("There should be rules: ");
        for ( KiePackage kp : kieBase.getKiePackages() ) {
            for (Rule rule : kp.getRules()) {
                LOG.info("kp " + kp + " rule " + rule.getName());
            }
        }

        LOG.info("Creating kieSession");
        KieSession session = kieBase.newKieSession();

        LOG.info("Populating globals");
        Set<String> check = new HashSet<String>();
        session.setGlobal("controlSet", check);

        LOG.info("Now running data");

        Measurement mRed= new Measurement("color", "red");
        session.insert(mRed);
        session.fireAllRules();

        Measurement mGreen= new Measurement("color", "green");
        session.insert(mGreen);
        session.fireAllRules();

        Measurement mBlue= new Measurement("color", "blue");
        session.insert(mBlue);
        session.fireAllRules();

        LOG.info("Final checks");

        assertEquals("Size of object in Working Memory is 3", 3, session.getObjects().size());
        assertTrue("contains red", check.contains("red"));
        assertTrue("contains green", check.contains("green"));
        assertTrue("contains blue", check.contains("blue"));

    }
}

In order to build and test the project, the following pom.xml has been included, which uses drools-bom to handle the Drool dependencies version (in this example 7.7.0.Final).

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.mastertheboss</groupId>
  <artifactId>drools-project</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>kjar</packaging>

  <name>drools-project</name>
  <url>http://drools.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <drools-version>7.41.0.Final</drools-version>
    <slf4j-version>1.7.26</slf4j-version>
    <junit-version>4.12</junit-version>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-bom</artifactId>
        <type>pom</type>
        <version>${drools-version}</version>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>

    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <scope>test</scope>
      </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit-version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${slf4j-version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.kie</groupId>
        <artifactId>kie-maven-plugin</artifactId>
        <version>${drools-version}</version>
        <extensions>true</extensions>
      </plugin>
    </plugins>

  </build>
</project>

That’s all. Compile and build the project with:

$ mvn clean install test

Continue Learning Drools through the following tutorials:

1) Coding Rules in Decision Tables

In Drools, Decision Tables are a way to generate rules from the data entered into a spreadsheet. The spreadsheet can be a standard Excel (XLS) or a CSV File.

If you want to learn how to code your Rules into an excel Spread Sheet, keep reading this tutorial:
Getting started with Drools Decision Tables

2) Getting started with the Kie Execution Server

The Kie Server is a Java web application that allow us to expose rules and business process to be executed remotely using REST and JMS interfaces. The following tutorial shows how to install it on the top of WildFly: Configure Kie Execution Server on WildFly

3) Deploy your assets on the Business Central

Once that you are familiar with the Kie Execution Server, you can learn how install also the Business Central where you can design, build and deploy your assets. Here is the tutorial for you: Getting started with jBPM Business Central

Drools and Maven Hello World example

[Tutorial updated on August 2020]

In the following tutorial we will learn how to create a basic Drools Rule Engine example project using Maven as project builder.

The prerequisite to this tutorial is that you have installed Maven on your pc. We will learn at first how to create a project from the shell. As an alternative, you can use an IDE like Eclipse with Drools plugin or Red Hat Code Ready Studio.

Create a new Maven Project for Drools

In order to get started you just need a basic Maven archetype which can be used to set up an initial structure for our projects. The kie-drools-archetype can be used for this purpose. From a shell, issue the following command:

mvn archetype:generate -B -DarchetypeGroupId=org.kie -DarchetypeArtifactId=kie-drools-archetype -DarchetypeVersion=7.41.0.Final -DgroupId=com.sample -DartifactId=helloworld -Dversion=1.0-SNAPSHOT -Dpackage=com.sample

The project will create a basic Drool project with an example Rule file and a Java class to test it.

Let’s have a look at the generated pom.xml file for this project:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.sample</groupId>
  <artifactId>helloworld</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>kjar</packaging>

  <name>helloworld</name>
  <url>http://drools.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <drools-version>7.41.0.Final</drools-version>
    <slf4j-version>1.7.26</slf4j-version>
    <junit-version>4.12</junit-version>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-bom</artifactId>
        <type>pom</type>
        <version>${drools-version}</version>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>

    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <scope>test</scope>
      </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit-version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${slf4j-version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.kie</groupId>
        <artifactId>kie-maven-plugin</artifactId>
        <version>${drools-version}</version>
        <extensions>true</extensions>
      </plugin>
    </plugins>

  </build>
</project>

As you can see, the archetype version has created for us a project using the same Drools Engine version (7.41.0.Final), therefore in order to have an updated version of the Engine just use the matching archetype version.

Add Classes and Rules

Ok, now we need to set up a simple Rule which is based on the Server class. This rule will issue a warning if the Server class does not meet minimal requirements.

package com.sample;

public class Server {

    private String name;
    private int processors;
    private int memory;
    private int diskspace;
    private boolean isValid=true;

    public Server(String name, int processors, int memory, int diskspace) {
        this.name = name;
        this.processors = processors;
        this.memory = memory;
        this.diskspace = diskspace;
    }

    // Getter/Setters method omitted for brevity
}

And here’s our simple Rule contained in src/main/resources/rules.drl:

import com.sample.Server
rule "Check Server Configuration"
  when
  $server : Server( processors < 2 || memory<=1024 || diskspace <= 2048)
  then
  $server.setValid(false);
  System.out.println("Server "+ $server.getName() + " configuration does not meet requirements!");
end

Under the folder srm/main/resources/META-INF the file kmodule.xml has been added with just an empty module:

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

This means, we will use the default KSession in order to insert our facts and fire the rules.

Now, let’s code a simple Test class which will create two Server resources and validate them using our rule:

package com.sample;

import org.junit.Test;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.definition.KiePackage;
import org.kie.api.definition.rule.Rule;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.junit.Assert.assertTrue;

public class RuleTest {
    static final Logger LOG = LoggerFactory.getLogger(RuleTest.class);

    @Test
    public void test() {
        KieServices kieServices = KieServices.Factory.get();

        KieContainer kContainer = kieServices.getKieClasspathContainer();

        LOG.info("Creating kieBase");
        KieBase kieBase = kContainer.getKieBase();

        LOG.info("There should be rules: ");
        for ( KiePackage kp : kieBase.getKiePackages() ) {
            for (Rule rule : kp.getRules()) {
                LOG.info("kp " + kp + " rule " + rule.getName());
            }
        }

        LOG.info("Creating kieSession");
        KieSession session = kieBase.newKieSession();

        LOG.info("Now running data");

        Server s1 = new Server("rhel7",2,1024,2048);
        session.insert(s1);
        session.fireAllRules();
        assertTrue(s1.isValid());

        Server s2 = new Server("rhel8",2,2048,4096);
        session.insert(s2);
        session.fireAllRules();
        assertTrue(s2.isValid());

    }
}

You can run the Test as follows:

$ mvn clean install

The expected outcome is that the first Server configuration will not pass the minimal requirements:

Server rhel7 configuration does not meet requirements!

You can try increasing the Server settings for the first server and verify that all Server configurations are now valid

You can find the source code for this Drools Hello World example at: https://github.com/fmarchioni/mastertheboss/tree/master/drools/helloworld

Running the Hello World Drools with CDI

It is noteworthy to mention that CDI is now tightly integrated into the KIE API. It can be used to inject versioned KieSession and KieBases. Here is how to rewrite the above example using CDI.

First, we need to enable CDI, so we will add a beans.xml file under the folder resources/META-INF

$ touch src/main/resources/META-INF/beans.xml

Then, let’s add a CDI Bean which will get injected the default KSession:

package com.sample;

import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
import org.kie.api.cdi.KSession;
import org.kie.api.runtime.KieSession;

import javax.inject.Inject;

public class CDIExample {

    @Inject
    @KSession
    KieSession session;

    public boolean go(Server server) {
        session.insert(server);
        session.fireAllRules();
        return server.isValid();
    }

    public static void main(String[] args) {

        Weld w = new Weld();
        WeldContainer wc = w.initialize();

        CDIExample bean = wc.instance().select(CDIExample.class).get();

        Server s1 = new Server("rhel7",2,2048,1024);

        boolean isValid = bean.go(s1);
        System.out.println("Configuration isValid "+isValid);
        w.shutdown();
    }

}

As you can see this CDI Bean also contains a main method so that the example can be tested using the maven-exec plugin as well.

And now, our test class which creates the Weld container where the CDIExample is added:

package com.sample;

import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
import org.junit.Test;

import static org.junit.Assert.assertTrue;

public class RuleTest {

    @Test
    public void testGo() {

        Weld w = new Weld();
        WeldContainer wc = w.initialize();

        com.sample.CDIExample bean = wc.instance().select(com.sample.CDIExample.class).get();
        
        Server s1 = new Server("rhel7",2,2048,4096);

        boolean isValid = bean.go(s1);
        assertTrue(isValid);

        w.shutdown();

    }
}

In terms of dependencies you have to include also the cdi and weld dependencies (with the exclusion of javax.el and javax.interceptor) in order to be able to use the CDI Container:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.drools</groupId>
    <artifactId>drools</artifactId>
    <version>7.41.0.Final</version>
  </parent>
  <groupId>com.sample</groupId>
  <artifactId>helloworld-cdi</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>kjar</packaging>

  <name>helloworld-cdi</name>
  <url>http://drools.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <drools-version>7.41.0.Final</drools-version>
    <slf4j-version>1.7.26</slf4j-version>
    <junit-version>4.12</junit-version>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-bom</artifactId>
        <type>pom</type>
        <version>${drools-version}</version>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>

 <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-cdi</artifactId>
    </dependency>
    <dependency>
      <groupId>javax.enterprise</groupId>
      <artifactId>cdi-api</artifactId>
      <exclusions>
        <exclusion>
          <groupId>javax.el</groupId>
          <artifactId>javax.el-api</artifactId>
        </exclusion>
        <exclusion>
          <groupId>javax.interceptor</groupId>
          <artifactId>javax.interceptor-api</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <dependency>
      <groupId>org.jboss.weld.se</groupId>
      <artifactId>weld-se-core</artifactId>
    </dependency>

    <dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <scope>test</scope>
      </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.kie</groupId>
        <artifactId>kie-maven-plugin</artifactId>
        <version>${drools-version}</version>
        <extensions>true</extensions>
      </plugin>
    </plugins>

  </build>
</project>

With the single Server we are testing, the unit test will pass:

[INFO] Running com.sample.RuleTest
Aug 14, 2020 3:37:00 PM org.jboss.weld.bootstrap.WeldStartup <clinit>
INFO: WELD-000900: 2.4.1 (Final)
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Aug 14, 2020 3:37:07 PM org.jboss.weld.bootstrap.WeldStartup startContainer
INFO: WELD-000101: Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
Aug 14, 2020 3:37:07 PM org.jboss.weld.environment.se.WeldContainer complete
INFO: WELD-ENV-002003: Weld SE container 6efac82c-0c7d-4297-91d2-c48811e91808 initialized
Aug 14, 2020 3:37:08 PM org.jboss.weld.environment.se.WeldContainer shutdown
INFO: WELD-ENV-002001: Weld SE container 6efac82c-0c7d-4297-91d2-c48811e91808 shut down
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 7.391 s - in com.sample.RuleTest

This project is available on github at https://github.com/fmarchioni/mastertheboss/tree/master/drools/helloworld-cdi

Continue Learning Drools through the following tutorials:

1) Coding Rules in Decision Tables

In Drools, Decision Tables are a way to generate rules from the data entered into a spreadsheet. The spreadsheet can be a standard Excel (XLS) or a CSV File.


If you want to learn how to code your Rules into an excel Spread Sheet, keep reading this tutorial:
Getting started with Drools Decision Tables

2) Getting started with the Kie Execution Server

The Kie Server is a Java web application that allow us to expose rules and business process to be executed remotely using REST and JMS interfaces. The following tutorial shows how to install it on the top of WildFly: Configure Kie Execution Server on WildFly

3) Deploy your assets on the Business Central

Once that you are familiar with the Kie Execution Server, you can learn how install also the Business Central where you can design, build and deploy your assets. Here is the tutorial for you: Getting started with jBPM Business Central

Using the Drools Guvnor Repository to store your Rules

Guvnor is the business rules manager included with Drools to manage knowledge and to be a centralized repository for Drools knowledge bases. In this tutorial we will show how to upload and use some rules in its repository.

In order to get started you need at first to install the Guvnor repository into JBoss AS as shown in this tutorial. Once installed start the guvnor by opening your browser to http://localhost:8080/drools-guvnor/
Now in order to create some rules into our repository we will need to perform the following steps:

Create a package for your Model classes

From your Knowledge Bases left menu choose to Create New > Package and enter a name for it.

Upload your Model classes

Let’s compile and package the following class which will be used into our Rule. Package it in a file named Account.jar

package com.sample.model;
public class Account {
    private Integer balance;

    public Account() {}
    public Integer getBalance() {
        return balance;
    }
    public void setBalance(Integer balance) {
        this.balance = balance;
    }
    public Account(Integer balance) {
        super();
        this.balance = balance;
    }
    public void withdraw(int money) {
        balance -= money;
    }
}

Uploading your Facts requires at first selecting Create New > Upload POJO Model


From there enter your Model Name and select the package you have just created. In the next screen of the Wizard pickup the JAR file with the Model.

 

Note: If you don’t want to upload your Model, it is also possible to define your Model class by using the Declarative Model editor which will let you create your facts from the Class fields.

Create your Rules

Now it’s time to insert your first Rule into your Guvnor repository. From the left Menu select Create New > Rule.

In the next screen you can opt for the Business Rule (guided editor) or, if you already have coded your rule, just use the Technical editor and enter the following rule:

import com.sample.model.Account
rule "accountBalanceAtLeast"
  when
  $account : Account( balance < 100 )
  then
  System.out.println("Warning! money running out!");
end

Once you have a stable knowledge you can create a deployment snapshots which freezes the knowledge for when you need it, saving a state of the knowledge that cannot be modified. Of course, you can still modify the knowledge through the Knowledge Bases, but any change will not be reflected in the snapshots.

Select the Package from the Left and enter in the Edit Tab. From there at first build the binary package by clicking on the Build package button. Building a package will collect all the assets, validate and compile into a deployable package.

Next create a snapshot for deployment. Once you have clicked on the button, a pop-up, New snapshot, will appear on the screen. Select a package to generate a snapshot. Now from the Edit Menu, copy the URL location of your package source

The source will be used in the following Test class which loads the accountBalanceAtLeast from the Guvnor Repository:

public class GuvnorTest  {
    @Test
    public void testDroolsWithGuvnor() throws Exception {
        KnowledgeBase knowledgeBase = createKnowledgeBase();
        StatefulKnowledgeSession session = knowledgeBase.newStatefulKnowledgeSession();
        try {
            Account account = new Account();
            account.setBalance(10);
            session.insert(account);

            session.fireAllRules();

        }
        finally {
            session.dispose();
        }
    }

    private static KnowledgeBase createKnowledgeBase() {
        KnowledgeAgentConfiguration kaconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
        kaconf.setProperty( "drools.agent.scanDirectories", "false" );
        KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent", kaconf );
        kagent.applyChangeSet( ResourceFactory.newClassPathResource("guvnor-jboss.xml"));
        return kagent.getKnowledgeBase();
    }
}

And here’s the guvnor-jboss.xml file which contains the resource path and the basic authentication info:

<change-set xmlns='http://drools.org/drools-5.0/change-set'
    xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
    xs:schemaLocation='http://drools.org/drools-5.0/change-set
    http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-api/src/main/resources/change-set-1.0.0.xsd' >
   <add>
      <resource
      source='http://localhost:8080/drools-guvnor/rest/packages/com.sample.model/source'
      type='DRL' basicAuthentication="enabled" username="admin" password="admin" />
   </add>
</change-set>

That’s all ! Enjoy coding your Rules into the Guvnor Repository.

Instant Drools Starter book review

Today I’ve gone through the Drools Instant starter book and I’ll add a short review of it. 

This pocket book has been created to provide you with all the information that you need to get started with Drools. You can read it in one day
and at the end you will learn the basics of Drools, get started with building your first rule system, and learn some core functions and helpful tips and tricks when it comes to using Drools in your applications. Basically the book is made up of just 52 pages and well divided into the following sections:

1) What is Drools? this will tell you what Drools actually is, what a Business Rule Management System such as Drools can do for you, when you should and shouldn’t choose a rule engine, and why Drools is a great choice.

2) Installation will teach you how to integrate Drools into a new or existing Java project with minimum hassle in order to get you writing and evaluating rules as soon as possible.

3) Quick start will kick start you with Drools Expert and your simple rule file using the Drools Rule Language.

4) Top 5 features you need to know about: this will teach the essentials for reading and writing basic rules in Drools Rule Language syntax, work with facts (objects fed to the rule engine), test your rules and debug the rule evaluation process

5) People and places you should get to know: provides many useful links to project documentation and mailing lists, as well as a number of helpful articles, tutorials, blogs, and the Twitter feeds of Drools.

This book is an extremely enjoyable reading at a convenient price (7.99€) which leaves me wishing to learn more about this great Rules engine. I’ll be glad to share with my readers all my on-going progress in this area