当前位置:网站首页>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 :
KieFileSystem
Need to be a singleton , That is, the same .KieContainer
Need to be a singleton , That is, the same .- adopt
updateToKieModule
Method 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
边栏推荐
- Jenkins user rights management
- 小程序链接生成
- Performance tuning project case
- 记录一下MySql update会锁定哪些范围的数据
- 甜心教主:王心凌
- SCM power supply
- 史上最易懂的f-string教程,收藏这一篇就够了
- Dynamic debugging of multi file program x32dbg
- [old horse of industrial control] detailed explanation of Siemens PLC TCP protocol
- Multiply LCA (nearest common ancestor)
猜你喜欢
How does Premiere (PR) import the preset mogrt template?
drools中then部分的写法
jenkins 凭证管理
测试左移和右移
HR wonderful dividing line
Depth filter of SvO2 series
SparkContext: Error initializing SparkContext解决方法
[QT] Qt development environment installation (QT version 5.14.2 | QT download | QT installation)
Sparkcontext: error initializing sparkcontext solution
Go学习笔记—多线程
随机推荐
Le tutoriel F - String le plus facile à comprendre de l'histoire.
[C language] convert decimal numbers to binary numbers
Larvel modify table fields
Natural language processing series (I) -- RNN Foundation
【C语言】杨辉三角,自定义三角的行数
Leetcode122 the best time to buy and sell stocks II
Jenkins user rights management
[geek challenge 2019] upload
Jenkins用户权限管理
深入理解PyTorch中的nn.Embedding
Sub thread get request
Lekao: contents of the provisions on the responsibility of units for fire safety in the fire protection law
小程序链接生成
How does Premiere (PR) import the preset mogrt template?
(C语言)输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
Input a three digit number and output its single digit, ten digit and hundred digit.
5g era, learning audio and video development, a super hot audio and video advanced development and learning classic
Experiment of connecting mobile phone hotspot based on Arduino and esp8266 (successful)
Leetcode14 longest public prefix
uniapp uni-list-item @click,uniapp uni-list-item带参数跳转