0

I am trying to execute a very basic example demonstrating the use of the accumulate() function of Drools, but am getting a java.lang.NullPointerException exception.

Here is the code:

Metric.java:

package com.sample;

public class Metric
{
  public String id;
  public double value;

  public Metric(String id, double value)
  {
    this.id = id;
    this.value = value;
  }
}

ruleFile1.drl:

package com.sample

declare Metric
    @role( event )
end

rule "rule1"
when
    Metric()
    metricAverage: Number() from accumulate(
        Metric( $value : value ),
        average( $value ) )
then
    System.out.println("metric value average " + metricAverage);
end

KSessionGenerator.java:

package com.sample;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import org.kie.api.KieBase;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class KSessionGenerator {

  public KieSession buildKSession(String ruleFilePath){
    KieServices kieServices = KieServices.Factory.get();

    FileInputStream fis = null;
    try {
      fis = new FileInputStream(ruleFilePath);
    } catch (FileNotFoundException e) {
      e.printStackTrace();
      return null;
    }

    String virtualRuleFilePath = "src/main/resources/ruleFile1.drl";
    KieFileSystem kfs = kieServices.newKieFileSystem();
    kfs.write(virtualRuleFilePath, kieServices.getResources().newInputStreamResource(fis));

    KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
    Results results = kieBuilder.getResults();
    if (results.hasMessages(Message.Level.ERROR)) {
      System.out.println(results.getMessages());
      throw new IllegalStateException("### errors ###");
    }

    KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());

    // Change the engine mode to 'stream'
    KieBaseConfiguration config = kieServices.newKieBaseConfiguration();
    config.setOption( EventProcessingOption.STREAM );

    KieBase kieBase = kieContainer.newKieBase( config );
    KieSession kSession = kieBase.newKieSession();

    return kSession;
  }
}

DroolsTest1.java:

package com.sample;

import org.kie.api.runtime.KieSession;

public class DroolsTest1 {

  public static final void main(String[] args) {
    try {
      String ruleFilePath = "src/main/resources/rules/ruleFile1.drl";
      KieSession kSession = (new KSessionGenerator()).buildKSession(ruleFilePath);

      // go !
      Metric metric1 = new Metric("m1", 50);
      Metric metric2 = new Metric("m2", 60);

      kSession.insert(metric1);
      kSession.insert(metric2);

      System.out.println("Firing all rules ...");
      kSession.fireAllRules();
      System.out.println("Rules fired!");

      System.out.println("Bye");
    } catch (Throwable t) {
      t.printStackTrace();
    }
  }
}

kmodule.xml:

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

The full stack trace of the exception:

Firing all rules ...
java.lang.RuntimeException: java.lang.NullPointerException
  at org.drools.core.rule.SingleAccumulate.accumulate(SingleAccumulate.java:90)
  at org.drools.core.phreak.PhreakAccumulateNode.addMatch(PhreakAccumulateNode.java:759)
  at org.drools.core.phreak.PhreakAccumulateNode.doLeftInserts(PhreakAccumulateNode.java:163)
  at org.drools.core.phreak.PhreakAccumulateNode.doNode(PhreakAccumulateNode.java:80)
  at org.drools.core.phreak.RuleNetworkEvaluator.switchOnDoBetaNode(RuleNetworkEvaluator.java:562)
  at org.drools.core.phreak.RuleNetworkEvaluator.evalBetaNode(RuleNetworkEvaluator.java:533)
  at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(RuleNetworkEvaluator.java:334)
  at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(RuleNetworkEvaluator.java:161)
  at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(RuleNetworkEvaluator.java:116)
  at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(RuleExecutor.java:235)
  at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:106)
  at org.drools.core.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:1016)
  at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1302)
  at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1289)
  at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:1262)
  at com.sample.DroolsTest1.main(DroolsTest1.java:20)
Caused by: java.lang.NullPointerException
  at org.drools.core.rule.Declaration.getValue(Declaration.java:228)
  at com.sample.Rule_rule11017979978AccumulateExpression0Invoker.evaluate(Rule_rule11017979978AccumulateExpression0Invoker.java:19)
  at org.drools.core.base.accumulators.JavaAccumulatorFunctionExecutor.accumulate(JavaAccumulatorFunctionExecutor.java:109)
  at org.drools.core.rule.SingleAccumulate.accumulate(SingleAccumulate.java:82)
  ... 15 more

I am using Drools version 6.2.0 Final via plugin on Eclipse Mars 4.5.2

Can anyone tell me the cause of the error along with its solution ?

Anmol Singh Jaggi
  • 8,376
  • 4
  • 36
  • 77
  • Possible duplicate of [What is a NullPointerException, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – Raedwald Sep 30 '16 at 08:41
  • 1
    @Raedwald How is this a duplicate of that question? – Anmol Singh Jaggi Sep 30 '16 at 08:50
  • 1
    @Raedwald: I think OP is well aware of what NPE is, and the question targets a specific, non-trivial case, see my answer below. IMHO this is definitely not a duplicate of the general question you linked – hammerfest Sep 30 '16 at 09:10

1 Answers1

3

Tried the code, the NPE is caused by

"$value" -> "Method threw 'java.lang.NullPointerException' exception. 
Cannot evaluate org.drools.core.rule.Declaration.toString()"

This is due to the Metric class not having any getter methods for its fields. Add the getters and the code will execute without problems

hammerfest
  • 2,203
  • 1
  • 20
  • 43
  • This resolves the error. But I don't understand how? Why should the presence of getters affect the rules execution? The class properties are anyway public. Also, the error you mentioned - `Cannot evaluate org.drools.core.rule.Declaration.toString()"` is not present in the stacktrace I wrote in the question. How did you get this? – Anmol Singh Jaggi Sep 30 '16 at 08:54
  • 1
    The stacktrace includes org.drools.core.rule.Declaration.getValue(Declaration.java:228). Put a breakpoint into this method and you will see the wrapped error in the debugger. Class fields being public not necessarily imply that they are visible for processing by framework engines, which often work through getters only, using reflection. I did not check it in more detail regarding Drools but met similar issues in the past in other frameworks. Using private fields and public getter methods is usually a good practice. – hammerfest Sep 30 '16 at 09:04