feature #I9DQDU 允许对不存在的组件增加全局参数
This commit is contained in:
parent
07b45657bf
commit
4abeabbcb1
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(" website:https://liteflow.cc\n");
|
||||
str.append(" wechat:bryan_31\n");
|
||||
str.append(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
liteflow.rule-source=uncheckNode/flow.el.xml
|
||||
liteflow.check-node-exists=false
|
|
@ -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>
|
Loading…
Reference in New Issue