当前位置:网站首页>Drools dynamically add, modify, and delete rules
Drools dynamically add, modify, and delete rules
2022-07-02 12:14:00 【huan_ one thousand nine hundred and ninety-three】
List of articles
- 1、 background
- 2、 Pre knowledge
- 3、 demand
- 4、 Realization
- 5、 Complete code
- 6、 Reference documents
1、 background
In previous chapters , our drools The rule files are all in src/main/resources The directory says dead , This is not flexible enough . Suppose I want to run the program , Dynamically modify rules , This is not easy to achieve . Here we save the rule file to the database , Realize the dynamic loading of rules 、 Refresh .
2、 Pre knowledge
1、 How to dynamically build a kmodule.xml file

2、kmodule.xml Who should load it
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
kieFileSystem.writeKModuleXML(kieModuleModel.toXML());
3、 We drl How to load rule content
kieFileSystem.write("src/main/resources/rules/rule01/1.drl","drl The content of the rules ");
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
kieBuilder.buildAll();
Results results = kieBuilder.getResults();
List<Message> messages = results.getMessages(Message.Level.ERROR);
if(null != messages && !messages.isEmpty()){
for (Message message : messages) {
System.out.println(message);
}
}
Be careful :
From here we can see ,drl The content of the rules Be being kieFileSystem Loaded , Later, if we want to realize Dynamically update the rule content , that kieFileSystem Whether it should be the same , That is, we need to cache this kieFileSystem.
What are the consequences of not caching ?
When we load a new rule content , Then the previous rule content may be lost .
You can see , The path we write is src/main/resources/rules/rule01/1.drl That's true , So what does that mean ? The simple understanding is as follows :src/main/resources: This can be understood as a fixed writing .rules/rule01: This needs to see 1、 How to dynamically build a kmodule.xml file , There is a dynamic build kieBase01, Then add package yes rules/rule01. That is, it needs to be corresponding .1.drl: The name of the rule file .
KieFileSystem: This is a virtual file system , Does not actually create files on disk , It's memory based .
4、 Build dynamically KieContainer
if (null == kieContainer) {
kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
}
// to update
((KieContainerImpl) kieContainer).updateToKieModule((InternalKieModule) kieBuilder.getKieModule());
The question here ?
1、kieContainer Can we create one each time , Then cover the old one with the new one ?
Personally, I don't think so , because , Cover , Means , We need to destroy the old KieContainer object , call kieContainer.dispose(), So if this time , We have created in our system KieSession, Processing rules , Then there will be problems .
2、kieServices.newKieContainer(ReleaseId) Medium ReleaseId How to get ?
The figure above illustrates ReleaseId How to get , Here we simply use the direct through kieServices.getRepository().getDefaultReleaseId() Get it .
3、updateToKieModule The role of
New KieModule Apply to existing KieContainer On the object , If KieSession The correspondence already exists , So the new rules are right KieSession Is visible .
** such as :** We modified the content of the rule , that KieSession Yes, I know. .
3、 demand
- The contents of rules need to be dynamically loaded from the database , In the example, it is stored in memory .
- More than one... Needs to be created
KieBase, Implement rule isolation . - You can dynamically update or add rules .
- You can delete rules .
4、 Realization
1、 introduce jar package
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-bom</artifactId>
<type>pom</type>
<version>7.69.0.Final</version>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.7</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-mvel</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
</dependencies>
2、 Create a rule entity class
This entity class corresponds to the tables in the database one by one .
package com.huan.drools.entity;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
/** * drools Rule entity class * * @author huan.fu * @date 2022/5/27 - 10:00 */
@Getter
@Setter
public class DroolsRule {
/** * The rules id */
private Long ruleId;
/** * kbase Name */
private String kieBaseName;
/** * Set the kbase You need to load files from that directory , This is a virtual directory , be relative to `src/main/resources` * such as :kiePackageName=rules/rule01 Then the current rule file write path is : kieFileSystem.write("src/main/resources/rules/rule01/1.drl") */
private String kiePackageName;
/** * The content of the rules */
private String ruleContent;
/** * Rule creation time */
private Date createdTime;
/** * Rule update time */
private Date updateTime;
public void validate() {
if (this.ruleId == null || isBlank(kieBaseName) || isBlank(kiePackageName) || isBlank(ruleContent)) {
throw new RuntimeException(" There is a problem with the parameters ");
}
}
private boolean isBlank(String str) {
return str == null || str.isEmpty();
}
}
Properties that need attention :kieBaseName: Created kbase Name .kiePackageName: The kbase Properties of package Value .
3、 Realization drools Dynamic rules
package com.huan.drools;
import com.huan.drools.entity.DroolsRule;
import lombok.extern.slf4j.Slf4j;
import org.drools.compiler.kie.builder.impl.InternalKieModule;
import org.drools.compiler.kie.builder.impl.KieContainerImpl;
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.Results;
import org.kie.api.builder.model.KieBaseModel;
import org.kie.api.builder.model.KieModuleModel;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.List;
/** * drools management * * @author huan.fu * @date 2022/5/27 - 14:42 */
@Component
@Slf4j
public class DroolsManager {
// This class itself is a singleton
private final KieServices kieServices = KieServices.get();
// kie file system , Cache required , If every time you add a rule, you re new One word , There may be problems . That is, the rules previously added to the file system are gone
private final KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
// It can be understood as building kmodule.xml
private final KieModuleModel kieModuleModel = kieServices.newKieModuleModel();
// The global unique one is required , If you create a new rule every time you add one , So the old one needs to be destroyed kieContainer, If there is one in use at this time KieSession, There may be a problem
private KieContainer kieContainer;
/** * Judge that kbase Whether there is */
public boolean existsKieBase(String kieBaseName) {
if (null == kieContainer) {
return false;
}
Collection<String> kieBaseNames = kieContainer.getKieBaseNames();
if (kieBaseNames.contains(kieBaseName)) {
return true;
}
log.info(" Need to create KieBase:{}", kieBaseName);
return false;
}
public void deleteDroolsRule(String kieBaseName, String packageName, String ruleName) {
if (existsKieBase(kieBaseName)) {
KieBase kieBase = kieContainer.getKieBase(kieBaseName);
kieBase.removeRule(packageName, ruleName);
log.info(" Delete kieBase:[{}] package :[{}] The rules under :[{}]", kieBaseName, packageName, ruleName);
}
}
/** * Add or update drools The rules */
public void addOrUpdateRule(DroolsRule droolsRule) {
// obtain kbase The name of
String kieBaseName = droolsRule.getKieBaseName();
// Judge that kbase Whether there is
boolean existsKieBase = existsKieBase(kieBaseName);
// This object corresponds to kmodule.xml Medium kbase label
KieBaseModel kieBaseModel = null;
if (!existsKieBase) {
// Create a kbase
kieBaseModel = kieModuleModel.newKieBaseModel(kieBaseName);
// Not by default kieBase
kieBaseModel.setDefault(false);
// Set the KieBase Package path to be loaded
kieBaseModel.addPackage(droolsRule.getKiePackageName());
// Set up kieSession
kieBaseModel.newKieSessionModel(kieBaseName + "-session")
// Not by default session
.setDefault(false);
} else {
// Get the existing kbase object
kieBaseModel = kieModuleModel.getKieBaseModels().get(kieBaseName);
// Get packages
List<String> packages = kieBaseModel.getPackages();
if (!packages.contains(droolsRule.getKiePackageName())) {
kieBaseModel.addPackage(droolsRule.getKiePackageName());
log.info("kieBase:{} Add a new package :{}", kieBaseName, droolsRule.getKiePackageName());
} else {
kieBaseModel = null;
}
}
String file = "src/main/resources/" + droolsRule.getKiePackageName() + "/" + droolsRule.getRuleId() + ".drl";
log.info(" Load the virtual rule file :{}", file);
kieFileSystem.write(file, droolsRule.getRuleContent());
if (kieBaseModel != null) {
String kmoduleXml = kieModuleModel.toXML();
log.info(" load kmodule.xml:[\n{}]", kmoduleXml);
kieFileSystem.writeKModuleXML(kmoduleXml);
}
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
// adopt KieBuilder structure KieModule All of them KieBase
kieBuilder.buildAll();
// Get the results of the build process
Results results = kieBuilder.getResults();
// Get error messages
List<Message> messages = results.getMessages(Message.Level.ERROR);
if (null != messages && !messages.isEmpty()) {
for (Message message : messages) {
log.error(message.getText());
}
throw new RuntimeException(" Exception occurred while loading rules ");
}
// KieContainer Only the first time you need to create , Then you use this
if (null == kieContainer) {
kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
} else {
// Realize dynamic update
((KieContainerImpl) kieContainer).updateToKieModule((InternalKieModule) kieBuilder.getKieModule());
}
}
/** * Trigger rule , Here is a simple simulation , A... Will be inserted into the rule Integer Type value */
public String fireRule(String kieBaseName, Integer param) {
// establish kieSession
KieSession kieSession = kieContainer.newKieSession(kieBaseName + "-session");
StringBuilder resultInfo = new StringBuilder();
kieSession.setGlobal("resultInfo", resultInfo);
kieSession.insert(param);
kieSession.fireAllRules();
kieSession.dispose();
return resultInfo.toString();
}
}
It should be noted that :
KieFileSystemNeed to be a singleton , That is, the same .KieContainerNeed to be a singleton , That is, the same .- adopt
updateToKieModuleMethod dynamic update .
4、 Analog database , Implementation rule CRUD
package com.huan.drools.service.com;
import com.huan.drools.DroolsManager;
import com.huan.drools.entity.DroolsRule;
import com.huan.drools.service.DroolsRuleService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
/** * @author huan.fu * @date 2022/5/27 - 14:34 */
@Service
public class DroolsRuleServiceImpl implements DroolsRuleService {
@Resource
private DroolsManager droolsManager;
/** * Analog database */
private Map<Long, DroolsRule> droolsRuleMap = new HashMap<>(16);
@Override
public List<DroolsRule> findAll() {
return new ArrayList<>(droolsRuleMap.values());
}
@Override
public void addDroolsRule(DroolsRule droolsRule) {
droolsRule.validate();
droolsRule.setCreatedTime(new Date());
droolsRuleMap.put(droolsRule.getRuleId(), droolsRule);
droolsManager.addOrUpdateRule(droolsRule);
}
@Override
public void updateDroolsRule(DroolsRule droolsRule) {
droolsRule.validate();
droolsRule.setUpdateTime(new Date());
droolsRuleMap.put(droolsRule.getRuleId(), droolsRule);
droolsManager.addOrUpdateRule(droolsRule);
}
@Override
public void deleteDroolsRule(Long ruleId, String ruleName) {
DroolsRule droolsRule = droolsRuleMap.get(ruleId);
if (null != droolsRule) {
droolsRuleMap.remove(ruleId);
droolsManager.deleteDroolsRule(droolsRule.getKieBaseName(), droolsRule.getKiePackageName(), ruleName);
}
}
}
Here is the memory saving rule , It can also be saved to a database .
5、 Create a control layer
@RestController
@RequestMapping("/drools/rule")
public class DroolsRuleController {
@Resource
private DroolsRuleService droolsRuleService;
@Resource
private DroolsManager droolsManager;
@GetMapping("findAll")
public List<DroolsRule> findAll() {
return droolsRuleService.findAll();
}
@PostMapping("add")
public String addRule(@RequestBody DroolsRule droolsRule) {
droolsRuleService.addDroolsRule(droolsRule);
return " Add success ";
}
@PostMapping("update")
public String updateRule(@RequestBody DroolsRule droolsRule) {
droolsRuleService.updateDroolsRule(droolsRule);
return " Modification successful ";
}
@PostMapping("deleteRule")
public String deleteRule(Long ruleId, String ruleName) {
droolsRuleService.deleteDroolsRule(ruleId, ruleName);
return " Delete successful ";
}
@GetMapping("fireRule")
public String fireRule(String kieBaseName, Integer param) {
return droolsManager.fireRule(kieBaseName, param);
}
}
6、 Dynamic addition of test rules
1、 Add rules
curl --location --request POST 'http://localhost:8080/drools/rule/add' \
--header 'User-Agent: apifox/1.0.0 (https://www.apifox.cn)' \
--header 'Content-Type: application/json' \
--data-raw '{ "ruleId": 1, "kieBaseName": "kieBase01", "kiePackageName": "rules.rule01", "ruleContent": "package rules.rule01 \n global java.lang.StringBuilder resultInfo \n rule \"rule-01\" when $i: Integer() then resultInfo.append(drools.getRule().getPackageName()).append(\".\").append(drools.getRule().getName()).append(\" Yes , Parameters passed by the front end :\").append($i); end" }'
package rules.rule01
global java.lang.StringBuilder resultInfo
rule "rule-01"
when
$i: Integer()
then
resultInfo.append(drools.getRule().getPackageName()).append(".").append(drools.getRule().getName()).append(" Yes , Parameters passed by the front end :").append($i);
end
2、 function
* ~ curl http://localhost:8080/drools/rule/fireRule\?kieBaseName\=kieBase01\¶m\=1
rules.rule01.rule-01 Yes , Parameters passed by the front end :1%
* ~
You can see that our dynamically loaded rules are executed .
7、 Modify rules
demand : stay 6、 Dynamic addition of test rules On the basis of , Modify rules .
The previous rules
package rules.rule01
global java.lang.StringBuilder resultInfo
rule "rule-01"
when
$i: Integer()
then
resultInfo.append(drools.getRule().getPackageName()).append(".").append(drools.getRule().getName()).append(" Yes , Parameters passed by the front end :").append($i);
end
Revised rules
package rules.rule01
global java.lang.StringBuilder resultInfo
rule "rule-01"
when
$i: Integer(intValue() > 3) // Notice here that
then
resultInfo.append(drools.getRule().getPackageName()).append(".").append(drools.getRule().getName()).append(" Yes , Parameters passed by the front end :").append($i);
end
You can see that the changes are $i: Integer(intValue() > 3), That is, a conditional judgment is added .
1、 Modify rules
* ~ curl --location --request POST 'http://localhost:8080/drools/rule/update' \
--header 'User-Agent: apifox/1.0.0 (https://www.apifox.cn)' \
--header 'Content-Type: application/json' \
--data-raw '{ "ruleId": 1, "kieBaseName": "kieBase01", "kiePackageName": "rules.rule01", "ruleContent": "package rules.rule01 \n global java.lang.StringBuilder resultInfo \n rule \"rule-01\" when $i: Integer(intValue() > 3) then resultInfo.append(drools.getRule().getPackageName()).append(\".\").append(drools.getRule().getName()).append(\" Yes , Parameters passed by the front end :\").append($i); end" }'
The rule memory is modified here Integer The value must be >3 Execution only .
2、 function
* ~ curl http://localhost:8080/drools/rule/fireRule\?kieBaseName\=kieBase01\¶m\=1
* ~ curl http://localhost:8080/drools/rule/fireRule\?kieBaseName\=kieBase01\¶m\=6
rules.rule01.rule-01 Yes , Parameters passed by the front end :6%
* ~
You can see from above , When we deliver param=1 when , No result data , When param=6 Results are output from time to time .
8、 Delete
demand : Delete the rule created in the previous step
1、 Deletion rule
* ~ curl --location --request POST 'http://localhost:8080/drools/rule/deleteRule?ruleId=1&ruleName=rule-01'
Delete successful %
* ~
2、 Running results
* ~ curl http://localhost:8080/drools/rule/fireRule\?kieBaseName\=kieBase01\¶m\=6
* ~ curl http://localhost:8080/drools/rule/fireRule\?kieBaseName\=kieBase01\¶m\=1
* ~
You can see that the deletion succeeded .
9、 simulation 2 individual kbase
1、 Add rules and execute
* ~ curl --location --request POST 'http://localhost:8080/drools/rule/add' \
--header 'Content-Type: application/json' \
--data-raw '{ "ruleId": 1, "kieBaseName": "kieBase01", "kiePackageName": "rules.rule01", "ruleContent": "package rules.rule01 \n global java.lang.StringBuilder resultInfo \n rule \"rule-01\" when $i: Integer() then resultInfo.append(drools.getRule().getPackageName()).append(\".\").append(drools.getRule().getName()).append(\" Yes , Parameters passed by the front end :\").append($i); end" }'
Add success %
* ~ curl --location --request POST 'http://localhost:8080/drools/rule/add' \
--header 'Content-Type: application/json' \
--data-raw '{ "ruleId": 2, "kieBaseName": "kieBase02", "kiePackageName": "rules.rule02", "ruleContent": "package rules.rule02 \n global java.lang.StringBuilder resultInfo \n rule \"rule-01\" when $i: Integer() then resultInfo.append(drools.getRule().getPackageName()).append(\".\").append(drools.getRule().getName()).append(\" Yes , Parameters passed by the front end :\").append($i); end" }'
Add success %
* ~ curl http://localhost:8080/drools/rule/fireRule\?kieBaseName\=kieBase01\¶m\=1
rules.rule01.rule-01 Yes , Parameters passed by the front end :1%
* ~ curl http://localhost:8080/drools/rule/fireRule\?kieBaseName\=kieBase02\¶m\=1
rules.rule02.rule-01 Yes , Parameters passed by the front end :1%
* ~
2、 perform

5、 Complete code
https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-dynamic-crud-rule
6、 Reference documents
边栏推荐
- AI中台技术调研
- WSL 2 will not be installed yet? It's enough to read this article
- This article takes you to understand the operation of vim
- 倍增 LCA(最近公共祖先)
- Leetcode922 按奇偶排序数组 II
- Lekao: contents of the provisions on the responsibility of units for fire safety in the fire protection law
- 单指令多数据SIMD的SSE/AVX指令集和API
- The most understandable f-string tutorial in history, collecting this one is enough
- Yygh-10-wechat payment
- (C语言)输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
猜你喜欢

XSS labs master shooting range environment construction and 1-6 problem solving ideas

深入理解P-R曲线、ROC与AUC

kubenetes中port、targetPort、nodePort、containerPort的区别与联系

Deep understanding of P-R curve, ROC and AUC

MSI announced that its motherboard products will cancel all paper accessories

Yygh-9-make an appointment to place an order

甜心教主:王心凌

PyTorch nn.RNN 参数全解析

Deep understanding of NN in pytorch Embedding

AI中台技术调研
随机推荐
CDH存在隐患 : 该角色的进程使用的交换内存为xx兆字节。警告阈值:200字节
小程序链接生成
Performance tuning project case
(C language) octal conversion decimal
MSI announced that its motherboard products will cancel all paper accessories
浅谈sklearn中的数据预处理
Take you ten days to easily finish the finale of go micro services (distributed transactions)
Codeforces 771-div2 C (trouble, permutation is not very good)
使用Sqoop把ADS层数据导出到MySQL
Filtre de profondeur de la série svo2
Thesis translation: 2022_ PACDNN: A phase-aware composite deep neural network for speech enhancement
Repeat, tile and repeat in pytorch_ The difference between interleave
求16以内正整数的阶乘,也就是n的阶层(0=<n<=16)。输入1111退出。
Tas (file d'attente prioritaire)
高德地图测试用例
深入理解PyTorch中的nn.Embedding
drools执行指定的规则
Jenkins voucher management
史上最易懂的f-string教程,收藏这一篇就够了
(C语言)输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。