Working with drools using excel sheet decision table— part-2

Paras Bansal
5 min readAug 29, 2021

part-1 link: https://paras301.medium.com/working-with-drools-using-excel-sheet-supplied-from-outside-project-part-1-8be30afc8180

In the part-1 of the story, we execute drools from a decision table spreadsheet supplied from outside the project during runtime. This resulted in compilation of the sheet on each request. This has its own pros and cons. Pros is that your application is generic enough to take any set of rules spreadsheet and give you the output, and cons is that it adds the compilation time.

Well, even if you create the spreadsheet within the project, the cons will continue if you always create a stateless kie session. Only in a stateful kie session, the session will continue open and only the execution of rules will happen with each request.

I came to the conclusion after performing a series of test with “part-1” code and also creating another repo with xls sheet inside. Also, I expanded the sheet with 10k rules to see the impact. With part-1 code, execution and SpreadSheetCompiler compilation of rules didn’t take much time, but the session creation took as much as 20s(1st time) and 12s(subsequent request):

--1st request2021-08-29 13:16:45.166  WARN 2256 --- [nio-8080-exec-2] o.d.c.kie.builder.impl.KieBuilderImpl    : File 'file0.drl' is in folder '' but declares package 'rules'. It is advised to have a correspondance between package and folder names.
2021-08-29 13:17:05.142 INFO 2256 --- [nio-8080-exec-2] o.d.c.kie.builder.impl.KieContainerImpl : Start creation of KieBase: defaultKieBase
2021-08-29 13:17:08.321 INFO 2256 --- [nio-8080-exec-2] o.d.c.kie.builder.impl.KieContainerImpl : End creation of KieBase: defaultKieBase
--Subsequent request2021-08-29 13:18:26.685 WARN 2256 --- [nio-8080-exec-9] o.d.c.kie.builder.impl.KieBuilderImpl : File 'file0.drl' is in folder '' but declares package 'rules'. It is advised to have a correspondance between package and folder names.
2021-08-29 13:18:38.546 INFO 2256 --- [nio-8080-exec-9] o.d.c.kie.builder.impl.KieContainerImpl : Start creation of KieBase: defaultKieBase
2021-08-29 13:18:40.395 INFO 2256 --- [nio-8080-exec-9] o.d.c.kie.builder.impl.KieContainerImpl : End creation of KieBase: defaultKieBase

And when the sheet was inside “src/main/resources/rules/discount.xls” (you’ll find the new sheet inside the code now) with “part-1” code slightly modified to read sheet from inside jar, the execution stats were pretty much the same:

--1st Reuqest2021-08-29 13:32:26.910  WARN 7552 --- [nio-8080-exec-3] o.d.c.kie.builder.impl.KieBuilderImpl    : File 'file0.drl' is in folder '' but declares package 'rules'. It is advised to have a correspondance between package and folder names.
2021-08-29 13:32:45.819 INFO 7552 --- [nio-8080-exec-3] o.d.c.kie.builder.impl.KieContainerImpl : Start creation of KieBase: defaultKieBase
2021-08-29 13:32:48.616 INFO 7552 --- [nio-8080-exec-3] o.d.c.kie.builder.impl.KieContainerImpl : End creation of KieBase: defaultKieBase
--Subsequent request2021-08-29 13:34:42.465 WARN 7552 --- [nio-8080-exec-7] o.d.c.kie.builder.impl.KieBuilderImpl : File 'file0.drl' is in folder '' but declares package 'rules'. It is advised to have a correspondance between package and folder names.
2021-08-29 13:34:52.174 INFO 7552 --- [nio-8080-exec-7] o.d.c.kie.builder.impl.KieContainerImpl : Start creation of KieBase: defaultKieBase
2021-08-29 13:34:54.134 INFO 7552 --- [nio-8080-exec-7] o.d.c.kie.builder.impl.KieContainerImpl : End creation of KieBase: defaultKieBase

I didn’t test the stateful session because its a known fact that stateful session is created only once and it lives as long as the application lives.

On this part-2, my main focus was to make a generic project, which can take data in a generic format so that you don’t have to code for the POJO every time. The simplest solution I found was to use a JSONNode type of object, and then create the rules sheet based on that. Let’s dive in.

Created Data.java as:

package com.company.vo;import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.*;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
public class Data {
private String ruleFilepath;
private JsonNode data;public String get(String xpath) {
try {
JsonNode jsonNode = data.at(xpath);
return jsonNode.asText();
} catch (Exception e) {
log.error("Can not get xpath " + xpath, e);
}
return null;
}
public Integer getInt(String xpath) {
return Integer.valueOf(get(xpath));
}
public Long getLong(String xpath) {
return Long.valueOf(get(xpath));
}
public Double getDouble(String xpath) {
return Double.valueOf(get(xpath));
}
public Boolean getBoolean(String xpath) {
return Boolean.valueOf(get(xpath));
}
public void set(String xpath, String value) {
try {
log.debug("set called for xpath " + xpath + " with value " + value);
((ObjectNode) data).put(xpath, value);
} catch (Exception e) {
log.error("Can not set xpath " + xpath + " with value " + value + " as parent is null", e);
}
}
public void remove(String xpath) {
log.debug("remove called for xpath " + xpath);
((ObjectNode) data).remove(xpath);
}
}

With this request can be specified with a “data” as JSON with the ruleFilePath. The rules sheet now looks like this (same is put in the code at “src/main/resources/rules/discount.xls” for your reference, this is currently not used can be deleted, this needs to be supplied from the postman request as part-1")

In the rules sheet “Sequential” has been added and set to FALSE. This will ensure that all rules are not executed one after the other and there can be a degree of parallelism based on PRIORITY. The rules will highest PRIORITY will be executed FIRST and with same PRIORITY will be executed in PARALLEL.

With the custom Getter and Setter methods, the data can be read from input request and added to output as well. You can also use Remove method to remove anything you don’t want in output. This generic way allows you to structure your data and sheet as you would like and takes off the tightly coupled schema dependency.

The new request looks like this:

So you see, this can be implemented in many ways. For a performance perspective, best will be to create a stateful session but then wary of the fact that “Facts” will live and will cause memory consumption with each request.

That’s it readers! If you have any questions, feel free to put in your comments and I’ll try to answer.

--

--