feature #I9DQDU 允许对不存在的组件增加全局参数

This commit is contained in:
everywhere.z 2024-04-08 12:23:15 +08:00
parent 07b45657bf
commit 4abeabbcb1
14 changed files with 246 additions and 11 deletions

View File

@ -1,10 +1,7 @@
package com.yomahub.liteflow.builder.el;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.*;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ql.util.express.DefaultContext;
@ -23,6 +20,8 @@ import com.yomahub.liteflow.flow.element.condition.AndOrCondition;
import com.yomahub.liteflow.flow.element.condition.NotCondition;
import com.yomahub.liteflow.log.LFLog;
import com.yomahub.liteflow.log.LFLoggerManager;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.property.LiteflowConfigGetter;
import com.yomahub.liteflow.util.ElRegexUtil;
import java.util.ArrayList;
@ -154,10 +153,6 @@ public class LiteFlowChainELBuilder {
throw new RouteELInvalidException("the route EL can only be a boolean node, or an AND or OR expression.");
}
if (Objects.isNull(routeExecutable)){
throw new QLException(StrUtil.format("parse route el fail,el:[{}]", routeEl));
}
// 把主要的condition加入
this.route = routeExecutable;
return this;
@ -186,6 +181,14 @@ public class LiteFlowChainELBuilder {
throw new FlowSystemException(errMsg);
}
this.chain.setEl(elStr);
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
// 如果设置了不检查Node是否存在那么这里是不解析的
if (BooleanUtil.isFalse(liteflowConfig.getCheckNodeExists())){
this.chain.setCompiled(false);
return this;
}
List<String> errorList = new ArrayList<>();
try {
DefaultContext<String, Object> context = new DefaultContext<>();
@ -285,7 +288,7 @@ public class LiteFlowChainELBuilder {
* 解析 EL 表达式查找未定义的 id 并构建错误信息
* @param elStr el 表达式
*/
private String buildDataNotFoundExceptionMsg(String elStr) {
private static String buildDataNotFoundExceptionMsg(String elStr) {
String msg = String.format("[node/chain is not exist or node/chain not register]\n EL: %s",
StrUtil.trim(elStr));
try {
@ -336,6 +339,62 @@ public class LiteFlowChainELBuilder {
}
return msg;
}
// #endregion
public static void buildUnCompileChain(Chain chain){
if (StrUtil.isBlank(chain.getEl())){
throw new FlowSystemException(StrUtil.format("no el content in this unCompile chain[{}]", chain.getChainId()));
}
// 如果chain已经有Condition了那说明已经解析过了这里只对未解析的chain进行解析
if (CollUtil.isNotEmpty(chain.getConditionList())){
return;
}
List<String> errorList = new ArrayList<>();
try {
DefaultContext<String, Object> context = new DefaultContext<>();
// 这里一定要先放chain再放node因为node优先于chain所以当重名时node会覆盖掉chain
// 往上下文里放入所有的chain是的el表达式可以直接引用到chain
FlowBus.getChainMap().values().forEach(chainItem -> context.put(chainItem.getChainId(), chainItem));
// 往上下文里放入所有的node使得el表达式可以直接引用到nodeId
FlowBus.getNodeMap().keySet().forEach(nodeId -> context.put(nodeId, FlowBus.getNode(nodeId)));
// 放入当前主chain的ID
context.put(ChainConstant.CURR_CHAIN_ID, chain.getChainId());
// 解析el成为一个Condition
// 为什么这里只是一个Condition而不是一个List<Condition>
// 这里无论多复杂的外面必定有一个最外层的Condition所以这里只有一个内部可以嵌套很多层这点和以前的不太一样
Condition condition = (Condition) EXPRESS_RUNNER.execute(chain.getEl(), context, errorList, true, true);
if (Objects.isNull(condition)){
throw new QLException(StrUtil.format("parse el fail,el:[{}]", chain.getEl()));
}
// 把主要的condition加入
chain.setConditionList(CollUtil.toList(condition));
// 把chain的isCompiled设置为true
chain.setCompiled(true);
FlowBus.addChain(chain);
} catch (QLException e) {
// EL 底层会包装异常这里是曲线处理
if (ObjectUtil.isNotNull(e.getCause()) && Objects.equals(e.getCause().getMessage(), DataNotFoundException.MSG)) {
// 构建错误信息
String msg = buildDataNotFoundExceptionMsg(chain.getEl());
throw new ELParseException(msg);
}else if (ObjectUtil.isNotNull(e.getCause())){
throw new ELParseException(e.getCause().getMessage());
}else{
throw new ELParseException(e.getMessage());
}
} catch (Exception e) {
String errMsg = StrUtil.format("parse el fail in this chain[{}];\r\n", chain.getChainId());
throw new ELParseException(errMsg + e.getMessage());
}
}
}

View File

@ -9,6 +9,8 @@
package com.yomahub.liteflow.flow.element;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
import com.yomahub.liteflow.exception.ChainEndException;
import com.yomahub.liteflow.log.LFLog;
import com.yomahub.liteflow.log.LFLoggerManager;
@ -34,6 +36,10 @@ public class Chain implements Executable{
private List<Condition> conditionList = new ArrayList<>();
private String el;
private boolean isCompiled = true;
public Chain(String chainName) {
this.chainId = chainName;
}
@ -81,6 +87,10 @@ public class Chain implements Executable{
// 执行chain的主方法
@Override
public void execute(Integer slotIndex) throws Exception {
if (BooleanUtil.isFalse(isCompiled)) {
LiteFlowChainELBuilder.buildUnCompileChain(this);
}
if (CollUtil.isEmpty(conditionList)) {
throw new FlowSystemException("no conditionList in this chain[" + chainId + "]");
}
@ -169,4 +179,20 @@ public class Chain implements Executable{
public void setRouteItem(Executable routeItem) {
this.routeItem = routeItem;
}
public String getEl() {
return el;
}
public void setEl(String el) {
this.el = el;
}
public boolean isCompiled() {
return isCompiled;
}
public void setCompiled(boolean compiled) {
isCompiled = compiled;
}
}

View File

@ -118,6 +118,9 @@ public class LiteflowConfig {
//是否快速加载规则如果快速加载规则意味着不用copyOnWrite机制了
private Boolean fastLoad;
//检查node是否存在
private Boolean checkNodeExists;
public Boolean getEnableMonitorFile() {
return enableMonitorFile;
}
@ -490,4 +493,16 @@ public class LiteflowConfig {
public void setFastLoad(Boolean fastLoad) {
this.fastLoad = fastLoad;
}
public Boolean getCheckNodeExists() {
if (ObjectUtil.isNull(checkNodeExists)){
return Boolean.TRUE;
}else{
return checkNodeExists;
}
}
public void setCheckNodeExists(Boolean checkNodeExists) {
this.checkNodeExists = checkNodeExists;
}
}

View File

@ -31,7 +31,7 @@ public class LOGOPrinter {
str.append(" | |___ | | | | | |__|_____| _| | |__| |_| |\\ V V / \n");
str.append(" |_____|___| |_| |_____| |_| |_____\\___/ \\_/\\_/ \n\n");
str.append(" Version: " + VERSION_NO + "\n");
str.append(" This Is My Rule.\n");
str.append(" This Is Our Rule.\n");
str.append(" websitehttps://liteflow.cc\n");
str.append(" wechatbryan_31\n");
str.append(

View File

@ -94,6 +94,9 @@ public class LiteflowProperty {
//是否快速加载规则如果快速加载规则意味着不用copyOnWrite机制了
private boolean fastLoad;
//是否检查节点存在
private boolean checkNodeExists;
public boolean isEnableMonitorFile() {
return enableMonitorFile;
}
@ -311,4 +314,12 @@ public class LiteflowProperty {
public void setFastLoad(boolean fastLoad) {
this.fastLoad = fastLoad;
}
public boolean isCheckNodeExists() {
return checkNodeExists;
}
public void setCheckNodeExists(boolean checkNodeExists) {
this.checkNodeExists = checkNodeExists;
}
}

View File

@ -49,6 +49,7 @@ public class LiteflowPropertyAutoConfiguration {
liteflowConfig.setParallelLoopExecutorClass(property.getParallelLoopExecutorClass());
liteflowConfig.setFallbackCmpEnable(property.isFallbackCmpEnable());
liteflowConfig.setFastLoad(property.isFastLoad());
liteflowConfig.setCheckNodeExists(property.isCheckNodeExists());
liteflowConfig.setEnableLog(liteflowMonitorProperty.isEnableLog());
liteflowConfig.setQueueLimit(liteflowMonitorProperty.getQueueLimit());
liteflowConfig.setDelay(liteflowMonitorProperty.getDelay());

View File

@ -159,6 +159,13 @@
"sourceType": "com.yomahub.liteflow.springboot.LiteflowProperty",
"defaultValue": false
},
{
"name": "liteflow.check-node-exists",
"type": "java.lang.Boolean",
"description": "Whether to check the existence of a node or not.",
"sourceType": "com.yomahub.liteflow.springboot.LiteflowProperty",
"defaultValue": true
},
{
"name": "liteflow.monitor.enable-log",
"type": "java.lang.Boolean",

View File

@ -17,6 +17,7 @@ liteflow.node-executor-class=com.yomahub.liteflow.flow.executor.DefaultNodeExecu
liteflow.print-execution-log=true
liteflow.fallback-cmp-enable=false
liteflow.fast-load=false
liteflow.check-node-exists=true
liteflow.parallel-max-workers=16
liteflow.parallel-queue-limit=512
liteflow.parallel-loop-executor-class=com.yomahub.liteflow.thread.LiteFlowDefaultParallelLoopExecutorBuilder

View File

@ -0,0 +1,46 @@
package com.yomahub.liteflow.test.uncheckNode;
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.test.BaseTest;
import com.yomahub.liteflow.test.uncheckNode.cmp.XCmp;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.TestPropertySource;
import javax.annotation.Resource;
/**
* springboot环境不检查Node存在与否测试
*
* @author Bryan.Zhang
*/
@TestPropertySource(value = "classpath:/uncheckNode/application.properties")
@SpringBootTest(classes = UnCheckNodeSpringbootTest.class)
@EnableAutoConfiguration
@ComponentScan({ "com.yomahub.liteflow.test.uncheckNode.cmp" })
public class UnCheckNodeSpringbootTest extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
// X不存在,能启动就算成功
@Test
public void testUncheckNode1() throws Exception {
}
// X不存在但是启动好加入进去就可以
@Test
public void testUncheckNode2() throws Exception {
LiteFlowNodeBuilder.createCommonNode().setId("x").setClazz(XCmp.class).build();
LiteflowResponse response = flowExecutor.execute2Resp("chain1");
Assertions.assertTrue(response.isSuccess());
}
}

View File

@ -0,0 +1,20 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.uncheckNode.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("a")
public class ACmp extends NodeComponent {
@Override
public void process() {
System.out.println("ACmp executed!");
}
}

View File

@ -0,0 +1,21 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.uncheckNode.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("b")
public class BCmp extends NodeComponent {
@Override
public void process() {
System.out.println("BCmp executed!");
}
}

View File

@ -0,0 +1,19 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.uncheckNode.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
public class XCmp extends NodeComponent {
@Override
public void process() {
System.out.println("XCmp executed!");
}
}

View File

@ -0,0 +1,2 @@
liteflow.rule-source=uncheckNode/flow.el.xml
liteflow.check-node-exists=false

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE flow PUBLIC "liteflow" "liteflow.dtd">
<flow>
<chain name="chain1">
THEN(a,b,x);
</chain>
</flow>