javaeclipsemavennullpointerexceptiondrools

Drools Rule Engine Null Pointer Exception


I'm trying the following tutorial https://www.mastertheboss.com/bpm/drools/jboss-drools-tutorial/?expand_article=1 to help familiarise myself with drools and am encountering the following error.

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "org.kie.api.runtime.KieSession.insert(Object)" because "ksession" is null
    at com.sample.DroolsShop.execute(DroolsShop.java:22)
    at com.sample.DroolsShop.main(DroolsShop.java:13)

(I am using Eclipse and the droolsjbpm-tools-distribution-7.41.0.Final plugin)

Having done some research, I'm aware that common reasons for this error include, missing a pom.properties file, missing the kmodule file or failing to name the kbase rule. However, as far as I'm aware this is not the case for me.

Here is the code:

DroolsShop.java:

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");
        //KieSession ksession = kc.newKieSession();

        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;
        }
    }
}

Rule.drl:

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

kmodule.xml:

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

pom.xml:

<?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>DemoDrools</artifactId>
  <version>1.0.0-SNAPSHOT</version>

  <name>Drools :: Sample Maven Project</name>
  <description>A sample Drools Maven project</description>

  <properties>
    <runtime.version>7.0.0.Final</runtime.version>
    <drools.version>8.44.0.Final</drools.version>
  </properties>

  <repositories>
    <repository>
      <id>jboss-public-repository-group</id>
      <name>JBoss Public Repository Group</name>
      <url>http://repository.jboss.org/nexus/content/groups/public/</url>
      <releases>
        <enabled>true</enabled>
        <updatePolicy>never</updatePolicy>
      </releases>
      <snapshots>
        <enabled>true</enabled>
        <updatePolicy>daily</updatePolicy>
      </snapshots>
    </repository>
  </repositories>
  
  <dependencies>
      
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-core</artifactId>
      <version>${drools.version}</version>
    </dependency>
    
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-compiler</artifactId>
      <version>${drools.version}</version>
    </dependency>
    
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-mvel</artifactId>
      <version>${drools.version}</version>
    </dependency>
    
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-io</artifactId>
      <version>${drools.version}</version>
    </dependency>
    
    <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-xml-support</artifactId>
      <version>${drools.version}</version>
    </dependency>
    
    <dependency>
      <groupId>org.kie</groupId>
      <artifactId>kie-api</artifactId>
      <version>${drools.version}</version>
    </dependency>
    
  </dependencies>
 
</project>

Project Structure: DroolsShop Eclipse project structure

Any help in diagnosing what could be the problem here would be much appreciated. Thank you.


Solution

  • Here, your KieSession "kiesession-rules" is a a property of the KieBase "rules", not of the container.

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