Drools and Maven Hello World example

In this tutorial we will learn how to create a basic Drools Rule Engine example project using Maven as project builder and the latest version of kie-drools-archetype ( Updated to January 2022 ).

Hard requirements:

  • JDK 8 or higher
  • Maven 3.x

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 you can use it to set up an initial structure for our projects. The archetype we will use is the kie-drools-archetype. We will be running the latest version of it.

From a shell, issue the following command:

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

The archetype 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 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.63.0.Final</drools-version>
    <slf4j-version>1.7.30</slf4j-version>
    <junit-version>4.13.1</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.8</source>
          <target>1.8</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, our project runs the latest  Drools Engine version 7.63.0.Final. If you want to experiment a Beta version of the Kie Server, just update the drools-version property.

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
}

Next, add a simple Rule file 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 you will find the file kmodule.xml which provides declarative configuration for KIE projects:

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

An empty kmodule.xml file means that we will use the default KSession in order to insert our facts and fire the rules.

Finally, let’s code a simple Test class which creates two Server objects and then 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 values for the first server and verify that all Server configurations are now valid.

The source code for this Drools Hello World example is available 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. You can use it to inject the KieSession and KieBases objects in your code. Here is how to rewrite the above example using CDI.

Firstly, 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.

Finally, let’s code our Test class which creates the Weld container and asserts the Server validity:

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.63.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.63.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