Load Drools rules from the database using a template DRL file in a spring boot app

Indranil Majumder
3 min readMay 23, 2023

--

Recently for an application, we were required to use a rule engine in a Spring Boot app. The rules need to be dynamically maintained via a UI. Figuring it out was not straightforward, hence putting some code snippets here in case it helps someone else.

First, create a Spring Boot 3 application with the following dependencies:-

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>

I am using Postgres as the DB, Java 17, and Drools 7.59.0.Final.

Next, add a DRL template file in your src/main/resources folder

template header
id
ifcondition
thencondition

template "tmp1"

rule "@{id}"
dialect "mvel"
when
@{ifcondition};
then
@{thencondition};
end

end template

The database table storing rules looks like this:- (Rule.java)

package com.springproject.droolEngineProject.model;

//import javax.persistence.*;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Entity
@Table(name = "rule_table")
@Getter
@Setter
public class Rule {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@Column(name = "ifcondition")
private String ifcondition;
@Column(name = "thencondition")
private String thencondition;
@Column(name = "version")
private int version;

// getters and setters...
}

Spring boot configuration looks like this:-

spring.datasource.url=jdbc:postgresql://localhost:5432/testdb
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

This configuration will take care of auto-creating the rule and other tables in Postgres.

Then I added a RestController to CRUD Rules:-

@RestController
public class RulesController {

@Autowired
private DroolRulesRepo rulesRepo;

@PostMapping("/rule")
public void addRule (@RequestBody Rule rule) {
rulesRepo.save(rule);
}

@GetMapping("/rules")
public List<Rule> getRules () {
List<Rule> rules = new ArrayList<Rule>();
rulesRepo.findAll().forEach(rules::add);
return rules;
}
}

The Rule engine is to determine discounts for Orders, so here is the OrderService executing all the rules to find the discount:-

public Order getDiscountForOrderV2(Order order) throws FileNotFoundException{
List<Rule> ruleAttributes = new ArrayList<>();
rulesRepo.findAll().forEach(ruleAttributes::add);

ObjectDataCompiler compiler = new ObjectDataCompiler();
String generatedDRL = compiler.compile(ruleAttributes, Thread.currentThread().getContextClassLoader().getResourceAsStream(DroolConfig.RULES_TEMPLATE_FILE));
KieServices kieServices = KieServices.Factory.get();

KieHelper kieHelper = new KieHelper();

//multiple such resoures/rules can be added
byte[] b1 = generatedDRL.getBytes();
Resource resource1 = kieServices.getResources().newByteArrayResource(b1);
kieHelper.addResource(resource1, ResourceType.DRL);

KieBase kieBase = kieHelper.build();

KieSession kieSession = kieBase.newKieSession();
kieSession.insert(order);
int numberOfRulesFired = kieSession.fireAllRules();
kieSession.dispose();

return order;
}

To add a rule using Postman:-

Now run an Order to get the discount:-

The full project can be found here.

#drools #springboot #ruleengine

--

--

No responses yet