Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically Update Rules at Runtime. Drools + Spring-Boot

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.

like image 784
ReiSchneider Avatar asked Nov 13 '18 08:11

ReiSchneider


2 Answers

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

like image 153
Costin Aldea Avatar answered Nov 03 '22 06:11

Costin Aldea


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

like image 1
Hareesh Reddy Avatar answered Nov 03 '22 07:11

Hareesh Reddy