4

I want to add a new rule-file (or modify an already existing one) to an existing KieSession dynamically at runtime.

I found an answer regarding this and tried the solution mentioned there, but got a runtime exception.

The code used is as follows:

Driver.java:

package app1;

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

import org.kie.api.KieBase;
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.ReleaseId;
import org.kie.api.builder.Results;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class Driver {

  public static final void main(String[] args) {
    try {
      KieServices kieServices = KieServices.Factory.get();
      KieFileSystem kfs = kieServices.newKieFileSystem();

      String ruleFilePath = "src/main/resources/rules/ruleFile1.drl";
      FileInputStream fis = null;
      try {
        fis = new FileInputStream(ruleFilePath);
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      }
      kfs = kfs.write(ruleFilePath, kieServices.getResources().newInputStreamResource(fis));

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

      ReleaseId releaseId1 = kieServices.newReleaseId("org.default", "artifact", "1.0.0-SNAPSHOT");
      KieContainer kieContainer = kieServices.newKieContainer(releaseId1);
      KieBase kieBase = kieContainer.newKieBase(kieServices.newKieBaseConfiguration());

      KieSession kSession = kieBase.newKieSession();
      String s = "hello";
      kSession.insert(s);
      kSession.fireAllRules();

      // I edit the rule file manually at this point.
      System.out.println("Waiting");
      Thread.sleep(5000);

      ReleaseId releaseId2 = kieServices.newReleaseId("org.default", "artifact", "1.0.1-SNAPSHOT");
      kieContainer.updateToVersion(releaseId2);
      kSession.fireAllRules();

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

ruleFile1.drl:

package app1;

rule "rule1"
when
    s: String()
then
    System.out.println("In rule - " + drools.getRule().getName());
    System.out.println("s = " + s);
end

The output I get is this:

In rule - rule1
s = hello
Waiting
java.lang.NullPointerException
  at org.drools.compiler.kie.util.ChangeSetBuilder.build(ChangeSetBuilder.java:53)
  at org.drools.compiler.kie.builder.impl.KieContainerImpl.update(KieContainerImpl.java:129)
  at org.drools.compiler.kie.builder.impl.KieContainerImpl.updateToVersion(KieContainerImpl.java:106)
  at app1.Driver.main(Driver.java:54)

I also read this code and noticed that it was using some code like this to add new rule-file dynamically to a KieSession:

KnowledgeBase kbase = SerializationHelper.serializeObject( loadKnowledgeBase( "test_Dynamic1.drl" ) );
Collection<KnowledgePackage> kpkgs = SerializationHelper.serializeObject( loadKnowledgePackages( "test_Dynamic2.drl" ) );
kbase.addKnowledgePackages(kpkgs);

but the problem is that KnowledgeBase is an internal API and not exposed to the end-users.

I am using Drools 6.2.0.

EDIT:

I've discovered that maybe KieScanner can be used to achieve what I want. But I am unable to find a proper example describing the use of KieScanner for either adding a new rule file or replacing an already existing one.

This answer contains some useful information, but I am not able to understand it properly. Also, I would prefer in-memory jars.

Community
  • 1
  • 1
Anmol Singh Jaggi
  • 8,376
  • 4
  • 36
  • 77
  • I've always been sceptical w.r.t. the dynamic change of a rule base by adding rules and with the session derived from that rule base running. What does this imply when there are facts in WM that trigger new rules that modify the facts so that old rules are triggered, while a few seconds they have not been triggered? (I guess you know what I mean.) -- If WM is empty, dispose the session and start a new one. -- If WM is not empty, it depends, and I'm not proposing anything without an analysis of the concrete application. – laune Nov 28 '16 at 18:05

0 Answers0