Drools是Jboss开源的一个规则引擎,简单来说就是一种运算速度极快且配置非常灵活的计算工具,这篇博客不分析底层实现了,因为互联网上面随便一搜就能发现很多介绍,但是真正去使用的博客却太少了,也许真正用的很深的不多大家都只是抄来抄去那些原理
公司最近正好需要这么一个服务我们便开始研究起来并最终上线,其实在实践过程中遇到很多的坑,并且由于网上解决资料非常少导致耽误了不少时间,在这里写出来也是为了帮助后续的小伙伴排雷,Jboss官方文档中提到得接入方式其实分为2种:
1.离线接入(下载Drools官方jar使用内部jar得API进行)
2.Kie-Server接入(搭建官方集群,作为client接入Drools服务)
两种做法都有优缺点:
离线 | Kie | |
接入难度 | 中 | 高 |
分布式集群 | 官方jar支持很弱,需要自己二次开发 | 支持 |
性能 | 极高,因为本地内存直接运算 | 较高,有了网络交互得消耗,损失部分性能 |
扩展性 | 低,基本都需要自己二次开发 | 高 |
从上面这个表格可以看出初学者入门使用离线方式是最好得,不过即使使用这种方式由于中文文档得缺失其实也是比较复杂得,我们公司当时前期使用得是第一种方式
那么开始进入主题,如何快速搭建Drools并且使用,公司使用的是Drools 7.7版本
POM文件配置加入:
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>7.7.0.Final</version>
<exclusions>
<exclusion>
<artifactId>mvel2</artifactId>
<groupId>org.mvel</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>7.7.0.Final</version>
<exclusions>
<exclusion>
<artifactId>protobuf-java</artifactId>
<groupId>com.google.protobuf</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>7.7.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-templates</artifactId>
<version>7.7.0.Final</version>
</dependency>
Drools有动态和静态规则两种,我们公司采用的是动态规则,利用Drools的API进行开发将规则原始数据存储到Mysql中,然后动态加入Drools的工作内存并计算,其实原理是一样得,都是采用DRL规则语法,只是一个是静态加载DRL文件一个是动态内存中生成DRL规范得字符串
Drools 中文文档网站:http://www.drools.org.cn/category/use (版本比较老了,但是是为数不多得中文文档)
Drools 官方网站:https://www.drools.org/ (可以下载最新版官方接入document,但是是全英语版本得)
公司存放规则得数据库sql如下:
/*
Navicat Premium Data Transfer
Source Server : wms4-test-shard
Source Server Type : MySQL
Source Server Version : 50718
Source Host : 10.88.27.117:3306
Source Schema : drools
Target Server Type : MySQL
Target Server Version : 50718
File Encoding : 65001
Date: 18/06/2019 15:14:41
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for factremarks
-- ----------------------------
DROP TABLE IF EXISTS `factremarks`;
CREATE TABLE `factremarks` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`attribute` varchar(200) NOT NULL,
`remarks` varchar(200) NOT NULL,
`type` varchar(200) NOT NULL,
`create_time` date DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for rulecondition
-- ----------------------------
DROP TABLE IF EXISTS `rulecondition`;
CREATE TABLE `rulecondition` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`ruleInfo_id` bigint(20) NOT NULL,
`conditionKey` varchar(200) DEFAULT NULL,
`op` varchar(200) NOT NULL,
`conditionValue` varchar(200) DEFAULT NULL,
`associationType` varchar(200) DEFAULT NULL,
`create_time` date DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
`paramType` varchar(200) DEFAULT NULL,
`type` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `ruleInfo_id` (`ruleInfo_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=404 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for ruleglobal
-- ----------------------------
DROP TABLE IF EXISTS `ruleglobal`;
CREATE TABLE `ruleglobal` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`rule_id` bigint(20) NOT NULL,
`globalName` varchar(40) NOT NULL,
`globalType` varchar(40) NOT NULL,
`create_time` date DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=125 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for rulegroup
-- ----------------------------
DROP TABLE IF EXISTS `rulegroup`;
CREATE TABLE `rulegroup` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`groupCode` varchar(40) NOT NULL,
`groupName` varchar(40) DEFAULT '',
`description` varchar(200) DEFAULT '',
`create_time` date DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
`ou_id` varchar(30) DEFAULT NULL,
`type` int(11) DEFAULT NULL COMMENT '规则组属于什么模块 1-上架',
`groupType` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `groupCode` (`groupCode`) USING BTREE,
KEY `ouid` (`ou_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=108 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for rulegroupref
-- ----------------------------
DROP TABLE IF EXISTS `rulegroupref`;
CREATE TABLE `rulegroupref` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`rule_id` bigint(20) NOT NULL,
`ruleGroup_id` bigint(20) NOT NULL,
`orderNo` int(11) DEFAULT NULL,
`state` int(11) DEFAULT NULL,
`create_time` date DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `ruleGroup_id` (`ruleGroup_id`),
KEY `rule_Id` (`rule_id`),
KEY `state` (`state`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=151 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for rulehead
-- ----------------------------
DROP TABLE IF EXISTS `rulehead`;
CREATE TABLE `rulehead` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`ruleName` varchar(100) NOT NULL,
`packageName` varchar(40) NOT NULL,
`remarks` varchar(200) DEFAULT NULL,
`ruleString` varchar(60) DEFAULT NULL,
`create_time` date DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
`rule_str` varchar(500) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `ruleString` (`ruleString`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=122 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for ruleinfo
-- ----------------------------
DROP TABLE IF EXISTS `ruleinfo`;
CREATE TABLE `ruleinfo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`rule_id` bigint(20) NOT NULL,
`type` varchar(40) NOT NULL,
`parent` varchar(200) DEFAULT NULL,
`obj` varchar(200) NOT NULL,
`calculation` varchar(200) DEFAULT NULL,
`attribute` varchar(200) DEFAULT NULL,
`create_time` date DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `rule_id` (`rule_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=374 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for ruleop
-- ----------------------------
DROP TABLE IF EXISTS `ruleop`;
CREATE TABLE `ruleop` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`rule_id` bigint(20) NOT NULL,
`objName` varchar(200) NOT NULL,
`attribute` varchar(200) NOT NULL,
`value` varchar(200) NOT NULL,
`create_time` date DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
`type` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `rule_id` (`rule_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=223 DEFAULT CHARSET=utf8;
ALTER TABLE `drools`.`rulecondition`
ADD COLUMN `brackets` varchar(200) NULL AFTER `type`;
ALTER TABLE `drools`.`ruleinfo`
ADD COLUMN `associationType` varchar(30) NULL AFTER `update_by`;
ALTER TABLE `drools`.`rulehead`
ADD COLUMN `frontEndData` text NULL AFTER `rule_str`;
SET FOREIGN_KEY_CHECKS = 1;
表结构说明文档下载地址:https://download.csdn.net/download/wmq880204/11665077
公司离线方式流程图如下:
整个流程还是比较简单易懂得,核心加载代码如下
@Autowired
private RuleLoadManager ruleLoadManager;
@Autowired
private KnowLedgeBaseManger knowLedgeBaseManger;
//查出数据库所有启用状态得规则并且装载到Map结构中
Map<String, List<BaseResource>> map = ruleLoadManager.loadAllRules();
//开始循环所有规则数据加载至工作内存中
map.forEach((group, resourceList) -> knowLedgeBaseManger.createKnowledgeBase(resourceList, group));
KnowLedgeBaseManager 类实现方法
@Autowired
private DroolsServicesBuilderFactory droolsServicesBuilderFactory;
@Autowired
private RuleLoadManager ruleLoadManager;
@Autowired
private KnowledgeBaseLib knowledgeBaseLib;
/**
* 根据传入规则创建知识库
*
* @param resources 规则
* @param knowLedgeBaseName 知识库名称
* @return
*/
@Override
public InternalKnowledgeBase createKnowledgeBase(List<BaseResource> resources, String knowLedgeBaseName) {
KnowledgeBuilder knowledgeBuilder = droolsServicesBuilderFactory.createKnowledgeBuilder();
InternalKnowledgeBase internalKnowledgeBase = droolsServicesBuilderFactory.createInternalKnowledgeBase();
droolsServicesBuilderFactory.addRules( knowledgeBuilder, resources, ResourceType.DRL );
BiConsumer<InternalKnowledgeBase, KnowledgeBuilder> baseBuilder = droolsServicesBuilderFactory::buliderBase;
baseBuilder.accept( internalKnowledgeBase, knowledgeBuilder );
return internalKnowledgeBase;
}
/**
* 测试规则
*
* @param resources
*/
@Override
public KnowledgeMessage testRule(List<BaseResource> resources) {
KnowledgeBuilder knowledgeBuilder = droolsServicesBuilderFactory.createKnowledgeBuilder();
KnowledgeMessage knowledgeMessage = null;
try {
droolsServicesBuilderFactory.addRules( knowledgeBuilder, resources, ResourceType.DRL );
knowledgeBuilder.undo();
knowledgeMessage = new KnowledgeMessage( "", SUCCESS, null );
} catch (KnowLedgeBuilderException ruleException) {
knowledgeMessage = new KnowledgeMessage( "", FAILED, ruleException.toString() );
}
return knowledgeMessage;
}
/**
* 重载全部知识库
*/
@Override
public void reloadRules() {
knowledgeBaseLib.getAllInternalKnowledgeBase().forEach( (name, internalKnowledgeBase) -> internalKnowledgeBase.getKieSessions().forEach( kieSession -> kieSession.destroy() ) );
knowledgeBaseLib.clearAllInternalKnowledgeBase();
ruleLoadManager.loadAllRules().forEach( (knowledgeBaseName, resources) -> createKnowledgeBase( resources, knowledgeBaseName ) );
}
@Override
public void reloadRulesByName(String knowLedgeBaseName) {
knowledgeBaseLib.removeInternalKnowledgeBase( knowLedgeBaseName );
reloadRules();
}
/**
* 重载特定知识库规则
*
* @param knowLedgeBaseName
*/
@Override
public InternalKnowledgeBase reloadRule(String knowLedgeBaseName) {
knowledgeBaseLib.getInternalKnowledgeBase( knowLedgeBaseName ).getKieSessions().forEach( kiesession -> kiesession.destroy() );
knowledgeBaseLib.removeInternalKnowledgeBase( knowLedgeBaseName );
createKnowledgeBase( ruleLoadManager.loadRule( knowLedgeBaseName ), knowLedgeBaseName );
return knowledgeBaseLib.getInternalKnowledgeBase( knowLedgeBaseName );
}
/**
* 释放session资源
*
* @param kieSession
*/
@Override
public void disposeKieSession(KieSession kieSession) {
kieSession.dispose();
}
/**
* 销毁session
*
* @param kieSession
*/
@Override
public void destoryKieSession(KieSession kieSession) {
kieSession.destroy();
}
DroolsServicesBuilderFactory 类实现方法
private static final Logger log = LoggerFactory.getLogger(DroolsServicesBuilderFactory.class);
@Autowired
private CustomKieBaseConfiguration customKieBaseConfiguration;
@Autowired
private RuleHeadDao ruleHeadDao;
/**
* 知识规则的构建器
*
* @return
*/
public KnowledgeBuilder createKnowledgeBuilder() {
return KnowledgeBuilderFactory.newKnowledgeBuilder();
}
/**
* 添加规则
* @param knowledgeBuilder
* @param resources
* @param type
*/
public void addRules(KnowledgeBuilder knowledgeBuilder, List<BaseResource> resources,
ResourceType type) {
resources.forEach(resource -> {
try {
log.info( new String( resource.getBytes(), StandardCharsets.UTF_8 ) );
knowledgeBuilder.add(resource,type);
} catch (Exception e) {
log.error( "addRuleError exction is {}",e );
}
});
if(knowledgeBuilder.hasErrors()){
log.error( "addRuleError is {}",knowledgeBuilder.getErrors().toString() );
}
}
/**
* @author QIQI
* @Description: 根据ruleId删除规则
* @params [ruleId]
* @return void
* @throws
* @date 2019-06-21 21:37
@LmisDataSource( "ds4" )
public void removeRule(Long ruleId){
RuleSaveModel groupCode = ruleHeadDao.getRuleInfoById(Integer.parseInt( String.valueOf( ruleId ) ));
KnowledgeBuilder knowledgeBuilder = createKnowledgeBuilder();
knowledgeBuilder.newKieBase().removeRule( FinalArgs.RULE_PACKAGE,groupCode.getRuleName() );
}*/
/**
* 创建内部支持库
* @return
*/
public InternalKnowledgeBase createInternalKnowledgeBase(){
KieBaseConfiguration kbc = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
customKieBaseConfiguration.getKieBaseconfiguration().forEach((key,value)->kbc.setProperty(key,value));
return KnowledgeBaseFactory.newKnowledgeBase(kbc);
}
/**
* 构建基础库
* @param internalKnowledgeBase
* @param knowledgeBuilder
*/
public void buliderBase(InternalKnowledgeBase internalKnowledgeBase,KnowledgeBuilder knowledgeBuilder){
internalKnowledgeBase.addPackages(knowledgeBuilder.getKnowledgePackages());
}
/**
* 创建有状态session
* @param internalKnowledgeBase
* @return
*/
public KieSession createKieSession(InternalKnowledgeBase internalKnowledgeBase){
Supplier<KieSession> kieSessionSupplier = internalKnowledgeBase::newKieSession;
return kieSessionSupplier.get();
}
/**
* 创建无状态session
* @param internalKnowledgeBase
* @return
*/
public StatelessKieSession createStatelessKieSession(InternalKnowledgeBase internalKnowledgeBase){
Supplier<StatelessKieSession> kieSessionSupplier = internalKnowledgeBase::newStatelessKieSession;
return kieSessionSupplier.get();
}
/**
* 释放session
* @param kieSession
*/
public void disposeKieSession(KieSession kieSession){
kieSession.dispose();
}
/**
* 销毁Kiession
* @param kieSession
*/
public void destroyKiession(KieSession kieSession){
kieSession.destroy();
}
KnowledgeBaseLib 类实现方法
private Logger logger = LogManager.getLogger(KnowledgeBaseLib.class);
private Map<String,InternalKnowledgeBase> internalKnowledgeBaseMap = new ConcurrentHashMap<>();
private static final String NORULEEXCEPTION = "not found any rule exception";
@Autowired
private RuleLoadManager ruleLoadManager;
@Autowired
private KnowLedgeBaseManger knowLedgeBaseManger;
/**
* 添加知识库到容器
* @param knowLedgeBaseName
* @param internalKnowledgeBase
*/
public void addInternalKnowledgeBase(String knowLedgeBaseName,InternalKnowledgeBase internalKnowledgeBase){
this.internalKnowledgeBaseMap.put(knowLedgeBaseName,internalKnowledgeBase);
}
/**
* 获得知识库
* @param knowLedgeBaseName
* @return
*/
public InternalKnowledgeBase getInternalKnowledgeBase(String knowLedgeBaseName){
if(hasInternalKnowledgeBase(knowLedgeBaseName)){
return this.internalKnowledgeBaseMap.get(knowLedgeBaseName);
}else{
List<BaseResource> resourceList = ruleLoadManager.loadRule(knowLedgeBaseName);
if(resourceList.isEmpty()){
logger.warn(NORULEEXCEPTION);
throw new KnowLedgeBuilderException(NORULEEXCEPTION);
}
knowLedgeBaseManger.createKnowledgeBase(resourceList,knowLedgeBaseName);
return this.internalKnowledgeBaseMap.get(knowLedgeBaseName);
}
}
/**
* 检测是否存在知识库
* @param knowLedgeBaseName
* @return
*/
public boolean hasInternalKnowledgeBase(String knowLedgeBaseName){
return this.internalKnowledgeBaseMap.containsKey(knowLedgeBaseName);
}
public Map<String,InternalKnowledgeBase> getAllInternalKnowledgeBase(){
return this.internalKnowledgeBaseMap;
}
public void clearAllInternalKnowledgeBase(){
this.internalKnowledgeBaseMap.clear();
}
public void removeInternalKnowledgeBase(String knowLedgeBaseName){
this.internalKnowledgeBaseMap.remove(knowLedgeBaseName);
}
CustomKieBaseConfiguration 类代码
@Component
@ConfigurationProperties(prefix = "droolsconfig")
public class CustomKieBaseConfiguration {
private Map<String,String> kieBaseconfiguration = new HashMap<>();
public Map<String, String> getKieBaseconfiguration() {
return kieBaseconfiguration;
}
public void setKieBaseconfiguration(Map<String, String> kieBaseconfiguration) {
this.kieBaseconfiguration = kieBaseconfiguration;
}
}
KnowLedgeBaseHandlerProxyConfig 知识库初始化使用
@EnableAspectJAutoProxy
@Configuration
public class KnowLedgeBaseHandlerProxyConfig {
/**
* 用于添加知识库
* @return
*/
@Bean
public KnowLedgeBaseHandler knowLedgeBaseHandler(){
return new KnowLedgeBaseHandler();
}
}
KnowLedgeBaseHandler 知识库切面,拦截知识库进行存储
/**
* 用于拦截添加知识库,将知识库进行存储
*/
@Aspect
@Order(2)
@Component
public class KnowLedgeBaseHandler {
@Autowired
private KnowledgeBaseLib knowledgeBaseLib;
@Pointcut("execution(public * com.lmis.manager.knowledge.KnowLedgeBaseMangerImpl.*(..))")
public void pointCut() {};
@AfterReturning(value = "pointCut()", returning = "result")
public void storeInternalKnowledgeBase(JoinPoint joinPoint, InternalKnowledgeBase result) {
String name = "";
try{
name = joinPoint.getArgs()[1].toString();
}catch(Exception e){
name = joinPoint.getArgs()[0].toString();
}
if(!knowledgeBaseLib.hasInternalKnowledgeBase(name)){
knowledgeBaseLib.addInternalKnowledgeBase(name,result);
}
}
}
DroolsConvertToResource 将数据库查询得数据转换成Drools可认得Resource使用(这个类中包含了很多规则模板类,因为是内存拼接DRL语句,所以肯定会制作很多DRL模板,这里就不放出来了,有需要得可以去下载资源,资源地址:https://download.csdn.net/download/wmq880204/11665278)
/**
* Created with IntelliJ IDEA.
* User: Dean Lu
* Date: 9/18/18
* Time: 9:52 AM
* <p>
* 用于将当前数据结构转换为Resource
*/
public final class DroolsConvertToResource {
private DroolsConvertToResource(){}
public static Map<String, List<BaseResource>> getResourceMap(List<RuleCommand> ruleCommands) {
Map<String, List<BaseResource>> map = new HashMap<>();
for (RuleCommand ruleCommand : ruleCommands) {
configRule(map, ruleCommand);
}
return map;
}
public static void configRule(Map<String, List<BaseResource>> map, RuleCommand ruleCommand) {
ruleCommand.getRuleGroupRefList().forEach(ruleGroupRef -> configRuleHead(map, ruleCommand, ruleGroupRef));
}
public static void configRuleHead(Map<String, List<BaseResource>> map, RuleCommand ruleCommand, RuleGroupRef ruleGroupRef) {
ruleGroupRef.getRuleHeadList().forEach(ruleHead -> {
ByteArrayResource byteArrayResource = null;
if (null != ruleHead.getRuleString()) {
CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder = configRuleHeaderTemplate(ruleCommand, ruleGroupRef, ruleHead);
configRuleInfo(ruleHead, ceDescrBuilder);
byteArrayResource = configRuleEndTemplate(ruleHead, ceDescrBuilder);
} else {
byteArrayResource = configRuleWithRuleString(ruleHead);
}
configResourceMap(map, byteArrayResource, ruleCommand.getGroupCode());
});
}
public static ByteArrayResource configRuleWithRuleString(RuleHead ruleHead) {
ByteArrayResource byteArrayResource;
StringTemplate stringTemplate = new StringTemplate();
byteArrayResource = stringTemplate.setStringTemplate(ruleHead.getRuleString());
return byteArrayResource;
}
public static ByteArrayResource configRuleEndTemplate(RuleHead ruleHead, CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder) {
ByteArrayResource byteArrayResource;
StringBuilder op = configRuleOp(ruleHead);
EndTemplate endTemplate = new EndTemplate(ceDescrBuilder, op.toString());
byteArrayResource = endTemplate.returnRuleString();
return byteArrayResource;
}
public static CEDescrBuilder<RuleDescrBuilder, AndDescr> configRuleHeaderTemplate(RuleCommand ruleCommand, RuleGroupRef ruleGroupRef, RuleHead ruleHead) {
Map<String, String> ruleGlobals = configRuleGlobal(ruleHead);
HanderTemplate handerTemplate = new HanderTemplate(ruleHead.getPackageName(), ruleHead.getRuleName(), ruleGlobals, ruleCommand.getGroupCode(), String.valueOf(ruleGroupRef.getOrderNo()));
return handerTemplate.getCeDescrBuilder();
}
public static StringBuilder configRuleOp(RuleHead ruleHead) {
StringBuilder op = new StringBuilder();
ruleHead.getRuleOpList().forEach(ruleOp -> {
if (BaseOperationTemplate.SIMPLEOPERATIONTYPE.equals(ruleOp.getType())) {
SimpleOperationTemplate simpleOperationTemplate = new SimpleOperationTemplate();
op.append(simpleOperationTemplate.opTemplate(ruleOp.getObjName(), ruleOp.getAttribute(), ruleOp.getValue()));
}
if (BaseOperationTemplate.STRINGYPE.equals(ruleOp.getType())) {
StringOperationTemplate stringOperationTemplate = new StringOperationTemplate();
op.append(stringOperationTemplate.opTemplate(null, null, ruleOp.getValue()));
}
});
return op;
}
public static void configRuleInfo(RuleHead ruleHead, CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder) {
List<RuleInfo> ruleInfos = ruleHead.getRuleInfoList();
for (RuleInfo ruleInfo : ruleInfos) {
configRuleInfo(ceDescrBuilder, ruleInfo);
}
}
public static Map<String, String> configRuleGlobal(RuleHead ruleHead) {
Map<String, String> ruleGlobals = new HashMap<>();
ruleHead.getRuleGlobalList().forEach(ruleGlobal -> ruleGlobals.put(ruleGlobal.getGlobalName(), ruleGlobal.getGlobalType()));
return ruleGlobals;
}
public static void configResourceMap(Map<String, List<BaseResource>> map, ByteArrayResource byteArrayResource, String ruleGroupCode) {
List<BaseResource> list = map.get(ruleGroupCode);
if (null == list) {
list = new ArrayList<>();
list.add(byteArrayResource);
map.put(ruleGroupCode, list);
} else {
list.add(byteArrayResource);
}
}
public static void configRuleInfo(CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder, RuleInfo ruleInfo) {
//各种主模板的判断加入
List<BaseConditionTemplate> conditionList = buildCondition(ruleInfo);
if (SimpleRuleTemplate.TYPE.equals(ruleInfo.getType())) {
configSimpleRuleTemplate(ceDescrBuilder, ruleInfo, conditionList);
}
else if (NestingCountTemplate.TYPE.equals(ruleInfo.getType())) {
configNestingCountTemplate(ceDescrBuilder, ruleInfo, conditionList);
}
else if (NestingExistsTemplate.TYPE.equals(ruleInfo.getType())) {
configNestingExistsTemplate(ceDescrBuilder, ruleInfo, conditionList);
}
else if (NestingCalculationTemplate.TYPE.equals(ruleInfo.getType())) {
configNestingCalculationTemplate(ceDescrBuilder, ruleInfo, conditionList);
}
else if (NestingAllTemplate.TYPE.equals(ruleInfo.getType())) {
configNestingAllTemplate(ceDescrBuilder, ruleInfo, conditionList);
}
else if (NestingAccumulateTemplate.TYPE.equals(ruleInfo.getType())) {
configNestingAccumulateTemplate(ceDescrBuilder, ruleInfo, conditionList);
}
else if (NestingMatchesTemplate.TYPE.equals(ruleInfo.getType())) {
configNestingMatchesTemplate(ceDescrBuilder, ruleInfo, conditionList);
}
}
public static void configNestingAccumulateTemplate(CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder, RuleInfo ruleInfo, List<BaseConditionTemplate> conditionList) {
NestingAccumulateTemplate nestingAccumulateTemplate = new NestingAccumulateTemplate();
nestingAccumulateTemplate.setObjName(ruleInfo.getObj());
nestingAccumulateTemplate.setAttribute(ruleInfo.getAttribute());
nestingAccumulateTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM));
nestingAccumulateTemplate.setParentName(ruleInfo.getParent());
nestingAccumulateTemplate.setDescrBuilder(ceDescrBuilder);
nestingAccumulateTemplate.setNestingAccumulateTemplate();
}
public static void configNestingCalculationTemplate(CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder, RuleInfo ruleInfo, List<BaseConditionTemplate> conditionList) {
NestingCalculationTemplate nestingCalculationTemplate = new NestingCalculationTemplate(ceDescrBuilder);
nestingCalculationTemplate.setObjName(ruleInfo.getObj());
nestingCalculationTemplate.setAttribute(ruleInfo.getAttribute());
nestingCalculationTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM));
nestingCalculationTemplate.setCalConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CALPARAM));
nestingCalculationTemplate.setParentName(ruleInfo.getParent());
nestingCalculationTemplate.setCalculation(ruleInfo.getCalculation());
nestingCalculationTemplate.setDescrBuilder(ceDescrBuilder);
nestingCalculationTemplate.setNestingCalculationTemplate();
}
public static void configNestingAllTemplate(CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder, RuleInfo ruleInfo, List<BaseConditionTemplate> conditionList) {
NestingAllTemplate nestingAllTemplate = new NestingAllTemplate(ceDescrBuilder);
nestingAllTemplate.setObjName(ruleInfo.getObj());
nestingAllTemplate.setAttribute(ruleInfo.getAttribute());
nestingAllTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM));
nestingAllTemplate.setParentName(ruleInfo.getParent());
nestingAllTemplate.setDescrBuilder(ceDescrBuilder);
nestingAllTemplate.setNestingAllTemplate();
}
public static void configNestingExistsTemplate(CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder, RuleInfo ruleInfo, List<BaseConditionTemplate> conditionList) {
NestingExistsTemplate nestingExistsTemplate = new NestingExistsTemplate();
nestingExistsTemplate.setObjName(ruleInfo.getObj());
nestingExistsTemplate.setAttribute(ruleInfo.getAttribute());
nestingExistsTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM));
nestingExistsTemplate.setParentName(ruleInfo.getParent());
nestingExistsTemplate.setDescrBuilder(ceDescrBuilder);
nestingExistsTemplate.setNestingExistsTemplate();
}
public static void configNestingMatchesTemplate(CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder, RuleInfo ruleInfo, List<BaseConditionTemplate> conditionList) {
NestingMatchesTemplate nestingMatchesTemplate = new NestingMatchesTemplate();
nestingMatchesTemplate.setObjName(ruleInfo.getObj());
nestingMatchesTemplate.setAttribute(ruleInfo.getAttribute());
nestingMatchesTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM));
nestingMatchesTemplate.setParentName(ruleInfo.getParent());
nestingMatchesTemplate.setDescrBuilder(ceDescrBuilder);
nestingMatchesTemplate.setNestingExistsTemplate();
}
public static void configNestingCountTemplate(CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder, RuleInfo ruleInfo, List<BaseConditionTemplate> conditionList) {
NestingCountTemplate nestingCountTemplate = new NestingCountTemplate();
nestingCountTemplate.setObjName(ruleInfo.getObj());
nestingCountTemplate.setAttribute(ruleInfo.getAttribute());
nestingCountTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM));
nestingCountTemplate.setCalConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CALPARAM));
nestingCountTemplate.setParentName(ruleInfo.getParent());
nestingCountTemplate.setDescrBuilder(ceDescrBuilder);
nestingCountTemplate.setCalculation(ruleInfo.getCalculation());
nestingCountTemplate.setNestingCountTemplate();
}
public static void configSimpleRuleTemplate(CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder, RuleInfo ruleInfo, List<BaseConditionTemplate> conditionList) {
SimpleRuleTemplate simpleRuleTemplate = new SimpleRuleTemplate();
simpleRuleTemplate.setRuleInfo(ruleInfo);
simpleRuleTemplate.setConditionList(conditionListFilter(conditionList, BaseConditionTemplate.CONDITIONPARAM));
simpleRuleTemplate.setDescrBuilder(ceDescrBuilder);
simpleRuleTemplate.setSimpleRuleTemplate();
}
public static List<BaseConditionTemplate> conditionListFilter(List<BaseConditionTemplate> baseConditionTemplates, String filter) {
return baseConditionTemplates.stream().filter(baseConditionTemplate -> filter.equals(baseConditionTemplate.getParamType())).collect(Collectors.toList());
}
/**
* @author QIQI
* @Description: 子模板的判断加入
* @params [ruleInfo]
* @return java.util.List<com.wms.utility.template.condition.BaseConditionTemplate>
* @throws
* @date 2019-06-20 09:56
*/
public static List<BaseConditionTemplate> buildCondition(RuleInfo ruleInfo) {
List<BaseConditionTemplate> conditionList = new ArrayList<>();
ruleInfo.getRuleConditions().forEach(ruleCondition -> {
if (ruleCondition.getType().equals(BaseConditionTemplate.CONTAINSTYPE)) {
ContainsConditionTemplate containsConditionTemplate = new ContainsConditionTemplate(ruleCondition.getConditionKey(),
ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType());
containsConditionTemplate.setParamType(ruleCondition.getParamType());
conditionList.add(containsConditionTemplate);
}
else if (ruleCondition.getType().equals(BaseConditionTemplate.EQUALTYPE)) {
EqualConditionTemplate equalConditionTemplate = new EqualConditionTemplate(ruleCondition.getConditionKey(),
ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType());
equalConditionTemplate.setParamType(ruleCondition.getParamType());
conditionList.add(equalConditionTemplate);
}
else if (ruleCondition.getType().equals(BaseConditionTemplate.MEMBEROFTYPE)) {
MemberOfConditionTemplate memberOfConditionTemplate = new MemberOfConditionTemplate(ruleCondition.getConditionKey(),
ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType());
memberOfConditionTemplate.setParamType(ruleCondition.getParamType());
conditionList.add(memberOfConditionTemplate);
}
else if (ruleCondition.getType().equals(BaseConditionTemplate.RANGETYPE)) {
RangeConditionTemplate rangeConditionTemplate = new RangeConditionTemplate(ruleCondition.getConditionKey(),
ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType());
rangeConditionTemplate.setParamType(ruleCondition.getParamType());
conditionList.add(rangeConditionTemplate);
}
else if (ruleCondition.getType().equals(BaseConditionTemplate.MATCHESTYPE)) {
MatchesConditionTemplate matchesConditionTemplate = new MatchesConditionTemplate(ruleCondition.getConditionKey(),
ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType());
matchesConditionTemplate.setParamType(ruleCondition.getParamType());
conditionList.add(matchesConditionTemplate);
}
else if (ruleCondition.getType().equals(BaseConditionTemplate.ACCUMULATETYPE)) {
AccumulateConditionTemplate accumulateConditionTemplate = new AccumulateConditionTemplate(ruleCondition.getConditionKey(),
ruleCondition.getOp(), ruleCondition.getConditionValue(), ruleCondition.getAssociationType());
accumulateConditionTemplate.setParamType(ruleCondition.getParamType());
conditionList.add(accumulateConditionTemplate);
}
});
return conditionList;
}
public static boolean checkRuleId(CEDescrBuilder<RuleDescrBuilder, AndDescr> ceDescrBuilder, String objName) {
boolean flag = true;
List<PatternDescr> patternDescrList = ceDescrBuilder.getDescr().getAllPatternDescr();
if (patternDescrList.isEmpty()) {
return flag;
}
for (PatternDescr patternDescr : patternDescrList) {
if (objName.equals(patternDescr.getIdentifier())) {
flag = false;
}
}
return flag;
}
}
QueryManagerImpl 实现类(这个类主要用作规则数据匹配打标使用,分为无状态session和有状态session,差异就不详细介绍了,小伙伴可以自行百度)
@Service
public class QueryManagerImpl<T, V> implements QueryManager<T, V> {
private static Logger log = LogManager.getLogger("QueryManagerImpl");
@Autowired
private KnowledgeBaseLib knowledgeBaseLib;
/**
* 使用有状态SESSION进行请求
*
* @param knowLedgeBaseName
* @param data
* @return T
*/
@Override
public T queryCommandWithKieSessionAsList(String knowLedgeBaseName, V data) {
Function<String, InternalKnowledgeBase> internalKnowledgeBaseFunction = knowledgeBaseLib::getInternalKnowledgeBase;
Supplier<KieSession> kieSessionSupplier = internalKnowledgeBaseFunction.apply(knowLedgeBaseName)::newKieSession;
KieSession kieSession = kieSessionSupplier.get();
List resultList = new ArrayList();
if (data instanceof List) {
List dataList = (List) data;
//kieSession.setGlobal(FinalArgs.DROOLS_GLOBAL_TYPE, resultList);
dataList.forEach(dataInfo->{
kieSession.insert(dataInfo);
kieSession.getAgenda().getAgendaGroup( knowLedgeBaseName ).setFocus();
kieSession.fireAllRules();
});
}
kieSession.dispose();
return (T) resultList;
}
/**
* @author QIQI
* @Description: 使用无状态SESSION进行请求
* @params [knowLedgeBaseName, dataTmp]
* @return T
* @throws
* @date 2019-06-17 14:17
*/
@Override
public T queryCommandWithStatelessKieSessionAsList(String knowLedgeBaseName, V data) {
Function<String, InternalKnowledgeBase> internalKnowledgeBaseFunction = knowledgeBaseLib::getInternalKnowledgeBase;
Supplier<StatelessKieSession> statelessKieSessionSupplier = internalKnowledgeBaseFunction.apply(knowLedgeBaseName)::newStatelessKieSession;
StatelessKieSession statelessKieSession = statelessKieSessionSupplier.get();
if (data instanceof List) {
((List) data).parallelStream().forEach(datainfo->statelessKieSession.execute(datainfo));
}
return (T) data;
}
/**
* 使用有状态SESSION进行请求,返回具体请求规则的结果
*
* @param knowLedgeBaseName
* @param ruleMap
* @param data
* @return T
*/
@Override
public T queryCommandWithKieSession(String knowLedgeBaseName, Map<String, Map<String, List<String>>> ruleMap, V data) {
Function<String, InternalKnowledgeBase> internalKnowledgeBaseFunction = knowledgeBaseLib::getInternalKnowledgeBase;
Supplier<KieSession> kieSessionSupplier = internalKnowledgeBaseFunction.apply(knowLedgeBaseName)::newKieSession;
KieSession kieSession = kieSessionSupplier.get();
List<Command> list = new ArrayList<>();
if (data instanceof List) {
List dataList = (List) data;
int dataSize = dataList.size();
for (int i = 0; i < dataSize; i++) {
list.add(CommandFactory.newInsert(dataList.get(i)));
}
list.add(CommandFactory.newFireAllRules());
list.add(CommandFactory.newGetObjects());
ruleMap.forEach((ruleName, queryNames) -> queryNames.forEach((queryName, args) -> list.add(CommandFactory.newQuery(ruleName, queryName, args.toArray()))));
}
return (T) kieSession.execute(CommandFactory.newBatchExecution(list));
}
/**
* 使用无状态SESSION进行请求,返回具体请求规则的结果
*
* @param knowLedgeBaseName
* @param ruleMap
* @param data
* @return T
*/
@Override
public T queryCommandWithStatelessKieSession(String knowLedgeBaseName, Map<String, Map<String, List<String>>> ruleMap, V data) {
Function<String, InternalKnowledgeBase> internalKnowledgeBaseFunction = knowledgeBaseLib::getInternalKnowledgeBase;
Supplier<StatelessKieSession> statelessKieSessionSupplier = internalKnowledgeBaseFunction.apply(knowLedgeBaseName)::newStatelessKieSession;
StatelessKieSession statelessKieSession = statelessKieSessionSupplier.get();
List<Command> list = new ArrayList<>();
if (data instanceof List) {
List dataList = (List) data;
int dataSize = dataList.size();
for (int i = 0; i < dataSize; i++) {
list.add(CommandFactory.newInsert(dataList.get(i)));
}
list.add(CommandFactory.newFireAllRules());
list.add(CommandFactory.newGetObjects());
ruleMap.forEach((ruleName, queryNames) -> queryNames.forEach((queryName, args) -> list.add(CommandFactory.newQuery(ruleName, queryName, args.toArray()))));
}
return (T) statelessKieSession.execute(CommandFactory.newBatchExecution(list));
}
}