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));
}
}