11

So currently I'm practicing on using Drools (7.13.0.Final) with Spring-boot(1.5.12.RELEASE). I have made a sample application in Spring-boot with the following classes

Model: TaxiFare.java

@Data
public class TaxiFare {
    private double surge;
    private double netFare;
    private double baseFare;
    private double distanceTraveled;
}

Service: TaxiFareService.java

@Service
public class TaxiFareService {

    @Autowired
    private KieContainer kieContainer;


    public TaxiFare getTaxiFare(TaxiFare fare) {

        KieSession kieSession = kieContainer.newKieSession("rulesSession");

        kieSession.insert(fare);
        kieSession.fireAllRules();
        kieSession.dispose();
        return fare;
    }
}

RestController: TaxiFareController.java

@RestController
public class TaxiFareController {

    @Autowired
    private TaxiFareService taxiFareService;

    @RequestMapping(value = "/getFare", method = RequestMethod.GET)
    public String getQuestions(@RequestParam(required = true) double baseFare, @RequestParam(required = true) double surge, @RequestParam(required = true) double distanceTraveled) {

        TaxiFare fare = new TaxiFare();
        fare.setBaseFare(baseFare);
        fare.setSurge(surge);
        fare.setDistanceTraveled(distanceTraveled);

        taxiFareService.getTaxiFare(fare);

        return String.format("NET FARE IS: %s", fare.getNetFare());
    }


}

Configuration:

@Bean
public KieContainer kieContainer2() {
    return KieServices.Factory.get().getKieClasspathContainer();
}

With a defined rules of

rule "No Surge"
    when
        $fareObject: TaxiFare(surge == 0.0);
    then
        $fareObject.setNetFare($fareObject.getBaseFare() * $fareObject.getDistanceTraveled());
end
rule "Has Surge"
    when
        $fareObject: TaxiFare(surge > 0.0);
    then
        $fareObject.setNetFare($fareObject.getSurge() * $fareObject.getBaseFare() * $fareObject.getDistanceTraveled());
end

I've built this sample application using various Drools + Spring integration tutorials I've found online. At present, the rule engine works fine as it is but what I am trying to do is I want to be able to reload the rules file dynamically during the application's runtime everytime a new rule is added or an existing rule is modified. The application is packaged as a WAR and deployed in a web server.

I've read multiple articles regarding the use of KieScanner but none of the written tutorials about it makes sense, even the documentation itself. Following the sample code they provide,

KieScanner kieScanner = kieServices.newKieScanner(kieContainer);

Always causes the build to fail as somehow the newKieScanner cannot seem to create a kieScanner based on the kieContainer provided. Is there any other way on having a dynamic rules setup for Drools or a clarification on how to implement KieScanner correctly?

Thank you.

ReiSchneider
  • 185
  • 1
  • 12

3 Answers3

3

You can try this, actually works fine

 @Test
public void messageRuleFromUTFString() {
 String ruleContent =
     "package rules\r\n"+
     "import mypackage.Message\r\n" +
         "rule \"myrule\"\r\n" +
        "    \twhen\r\n" +
        "        $id : Message([\"38196-2\"] contains id)\r\n" +
        "    then\r\n" +
        "\t\tSystem.out.println(\"Works!\");\r\n" +
        "end\r\n";
    KieSession kSession = null;
    try {
        KnowledgeBuilder kb = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kb.add(ResourceFactory.newByteArrayResource(ruleContent.getBytes("utf-8")), ResourceType.DRL);

        KnowledgeBuilderErrors errors = kb.getErrors();
        for (KnowledgeBuilderError error : errors) {
            System.out.println(error);
        }
        InternalKnowledgeBase kBase = KnowledgeBaseFactory.newKnowledgeBase();
        kBase.addPackages(kb.getKnowledgePackages());
        kSession = kBase.newKieSession();
        kSession.insert(createMessage("38196-2"));
        kSession.fireAllRules();

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } finally {
        if (kSession != null)
            kSession.dispose();
    }
}

Credits to one of the github users. My example is slightly modified to the latest version of drools: https://github.com/ityouknow/drools-examples.git

1

You can refer Edgex Rules Engine where they used Drools rules engine to add and remove Rules dynamically at run time. Please refer the below link for the same, it might help you. https://github.com/edgexfoundry/support-rulesengine

0

Try this, it works fine

public kieSession kiaSession(String key, String rdlFile){

        KieFileSystem kieFileSystem = getKieFileSystem(rdlFile);
        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
        kieBuilder.buildAll();
        KieModule kieModule = kieBuilder.getKieModule();
        KieContainer kieContainer = kieServices.newKieContainer(kieModule.getReleaseId());
        KieSession kieSession = kieContainer.newKieSession();
        return kieSession ;
    } 
   
private KieFileSystem getKieFileSystem(String rdlFile) {
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        kieFileSystem.write(ResourceFactory.newClassPathResource(rdlFile));
        return kieFileSystem;
    }

So you can call it this way

 KieSession session = this.droolsService.kiaSession("order.drl");
        session.insert(yourModel);
        session.fireAllRules();
        return order.toString();