mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-06-14 11:31:46 +08:00
enhancement #IBQCWB FlowExecutor 入口支持执行调用 EL 表达式
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
package com.yomahub.liteflow.builder.el;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.*;
|
||||
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 com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ql.util.express.DefaultContext;
|
||||
@@ -27,7 +30,10 @@ import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
@@ -36,6 +42,7 @@ import java.util.*;
|
||||
* @author Bryan.Zhang
|
||||
* @author Jay li
|
||||
* @author jason
|
||||
* @author luo yi
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class LiteFlowChainELBuilder {
|
||||
@@ -268,6 +275,11 @@ public class LiteFlowChainELBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
public LiteFlowChainELBuilder setElMd5(String md5) {
|
||||
this.chain.setElMd5(md5);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void build() {
|
||||
this.chain.setRouteItem(this.route);
|
||||
this.chain.setConditionList(this.conditionList);
|
||||
|
||||
@@ -13,8 +13,10 @@ import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.lang.Tuple;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.*;
|
||||
import cn.hutool.crypto.digest.MD5;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.common.ChainConstant;
|
||||
import com.yomahub.liteflow.common.entity.ValidationResp;
|
||||
import com.yomahub.liteflow.enums.ChainExecuteModeEnum;
|
||||
import com.yomahub.liteflow.enums.ParseModeEnum;
|
||||
import com.yomahub.liteflow.exception.*;
|
||||
@@ -40,6 +42,7 @@ import com.yomahub.liteflow.slot.Slot;
|
||||
import com.yomahub.liteflow.spi.holder.ContextCmpInitHolder;
|
||||
import com.yomahub.liteflow.spi.holder.PathContentParserHolder;
|
||||
import com.yomahub.liteflow.thread.ExecutorHelper;
|
||||
import com.yomahub.liteflow.util.ElRegexUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -51,6 +54,7 @@ import java.util.stream.Collectors;
|
||||
* 流程规则主要执行器类
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @author luo yi
|
||||
*/
|
||||
public class FlowExecutor {
|
||||
|
||||
@@ -252,8 +256,9 @@ public class FlowExecutor {
|
||||
*
|
||||
* @param elStr EL 表达式
|
||||
* @return LiteflowResponse
|
||||
* @throws ELParseException
|
||||
*/
|
||||
public LiteflowResponse execute2RespWithEL(String elStr) {
|
||||
public LiteflowResponse execute2RespWithEL(String elStr) throws Exception {
|
||||
return this.execute2RespWithEL(elStr, null, null, DefaultContext.class);
|
||||
}
|
||||
|
||||
@@ -263,8 +268,9 @@ public class FlowExecutor {
|
||||
* @param elStr EL 表达式
|
||||
* @param param 入参
|
||||
* @return LiteflowResponse
|
||||
* @throws ELParseException
|
||||
*/
|
||||
public LiteflowResponse execute2RespWithEL(String elStr, Object param) {
|
||||
public LiteflowResponse execute2RespWithEL(String elStr, Object param) throws Exception {
|
||||
return this.execute2RespWithEL(elStr, param, null, DefaultContext.class);
|
||||
}
|
||||
|
||||
@@ -276,8 +282,9 @@ public class FlowExecutor {
|
||||
* @param requestId 请求 ID
|
||||
* @param contextBeanClazzArray 上下文 Class
|
||||
* @return LiteflowResponse
|
||||
* @throws ELParseException
|
||||
*/
|
||||
public LiteflowResponse execute2RespWithEL(String elStr, Object param, String requestId, Class<?>... contextBeanClazzArray) {
|
||||
public LiteflowResponse execute2RespWithEL(String elStr, Object param, String requestId, Class<?>... contextBeanClazzArray) throws Exception {
|
||||
return this.execute2RespWithEL(elStr, param, requestId, contextBeanClazzArray, null);
|
||||
}
|
||||
|
||||
@@ -289,8 +296,9 @@ public class FlowExecutor {
|
||||
* @param requestId 请求 ID
|
||||
* @param contextBeanArray 上下文对象
|
||||
* @return LiteflowResponse
|
||||
* @throws ELParseException
|
||||
*/
|
||||
public LiteflowResponse execute2RespWithEL(String elStr, Object param, String requestId, Object... contextBeanArray) {
|
||||
public LiteflowResponse execute2RespWithEL(String elStr, Object param, String requestId, Object... contextBeanArray) throws Exception {
|
||||
return this.execute2RespWithEL(elStr, param, requestId, null, contextBeanArray);
|
||||
}
|
||||
|
||||
@@ -303,14 +311,35 @@ public class FlowExecutor {
|
||||
* @param contextBeanClazzArray 上下文 Class 数组
|
||||
* @param contextBeanArray 上下文对象数组
|
||||
* @return LiteflowResponse
|
||||
* @throws ELParseException
|
||||
*/
|
||||
private LiteflowResponse execute2RespWithEL(String elStr, Object param, String requestId, Class<?>[] contextBeanClazzArray, Object[] contextBeanArray) {
|
||||
// 调用表达式构造 chain,并且返回 UUID 作为 chainId
|
||||
String chainId = IdUtil.fastSimpleUUID();
|
||||
LiteFlowChainELBuilder.createChain()
|
||||
.setChainId(chainId)
|
||||
.setEL(elStr)
|
||||
.build();
|
||||
private LiteflowResponse execute2RespWithEL(String elStr, Object param, String requestId, Class<?>[] contextBeanClazzArray, Object[] contextBeanArray) throws Exception {
|
||||
// 规范化 el 表达式
|
||||
String normalizedEl = ElRegexUtil.normalize(elStr);
|
||||
|
||||
// 校验 EL 是否正常
|
||||
ValidationResp validationResp = LiteFlowChainELBuilder.validateWithEx(normalizedEl);
|
||||
|
||||
if (!validationResp.isSuccess()) {
|
||||
// 实际封装的是 ELParseException 类型
|
||||
throw validationResp.getCause();
|
||||
}
|
||||
|
||||
// 计算 EL MD5 值,并检查对应的 chain 是否已加载到内存中
|
||||
String elMd5 = MD5.create().digestHex(normalizedEl);
|
||||
|
||||
String chainId;
|
||||
|
||||
if (StrUtil.isEmpty(chainId = FlowBus.getChainIdByElMd5(elMd5))) {
|
||||
// 调用表达式构造 chain,并且返回 UUID 作为 chainId
|
||||
chainId = IdUtil.fastSimpleUUID();
|
||||
LiteFlowChainELBuilder.createChain()
|
||||
.setChainId(chainId)
|
||||
.setEL(normalizedEl)
|
||||
.setElMd5(elMd5)
|
||||
.build();
|
||||
}
|
||||
|
||||
return this.execute2Resp(chainId, param, requestId, contextBeanClazzArray, contextBeanArray);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,13 @@ import com.yomahub.liteflow.core.ComponentInitializer;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.core.ScriptComponent;
|
||||
import com.yomahub.liteflow.core.proxy.DeclWarpBean;
|
||||
import com.yomahub.liteflow.core.proxy.LiteFlowProxyUtil;
|
||||
import com.yomahub.liteflow.enums.FlowParserTypeEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.enums.ParseModeEnum;
|
||||
import com.yomahub.liteflow.exception.ComponentCannotRegisterException;
|
||||
import com.yomahub.liteflow.exception.NullNodeTypeException;
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.Condition;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
import com.yomahub.liteflow.lifecycle.LifeCycleHolder;
|
||||
import com.yomahub.liteflow.log.LFLog;
|
||||
@@ -43,14 +43,10 @@ import com.yomahub.liteflow.spi.ContextAware;
|
||||
import com.yomahub.liteflow.spi.holder.ContextAwareHolder;
|
||||
import com.yomahub.liteflow.spi.holder.DeclComponentParserHolder;
|
||||
import com.yomahub.liteflow.util.CopyOnWriteHashMap;
|
||||
import com.yomahub.liteflow.core.proxy.LiteFlowProxyUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 流程元数据类
|
||||
@@ -58,384 +54,395 @@ import java.util.stream.Stream;
|
||||
* @author Bryan.Zhang
|
||||
* @author DaleLee
|
||||
* @author Jay li
|
||||
* @author luo yi
|
||||
*/
|
||||
public class FlowBus {
|
||||
|
||||
private static final LFLog LOG = LFLoggerManager.getLogger(FlowBus.class);
|
||||
private static final LFLog LOG = LFLoggerManager.getLogger(FlowBus.class);
|
||||
|
||||
private static final Map<String, Chain> chainMap;
|
||||
private static final Map<String, Chain> chainMap;
|
||||
|
||||
private static final Map<String, Node> nodeMap;
|
||||
private static final Map<String, Node> nodeMap;
|
||||
|
||||
private static final Map<String, Node> fallbackNodeMap;
|
||||
private static final Map<String, Node> fallbackNodeMap;
|
||||
|
||||
private static final AtomicBoolean initStat = new AtomicBoolean(false);
|
||||
private static final Map<String/* elMd5 */, String/* chainId */> elMd5Map;
|
||||
|
||||
static {
|
||||
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
|
||||
if (liteflowConfig.getFastLoad()){
|
||||
chainMap = new HashMap<>();
|
||||
nodeMap = new HashMap<>();
|
||||
fallbackNodeMap = new HashMap<>();
|
||||
}else{
|
||||
chainMap = new CopyOnWriteHashMap<>();
|
||||
nodeMap = new CopyOnWriteHashMap<>();
|
||||
fallbackNodeMap = new CopyOnWriteHashMap<>();
|
||||
}
|
||||
}
|
||||
private static final AtomicBoolean initStat = new AtomicBoolean(false);
|
||||
|
||||
public static Chain getChain(String id) {
|
||||
return chainMap.get(id);
|
||||
}
|
||||
static {
|
||||
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
|
||||
if (liteflowConfig.getFastLoad()) {
|
||||
chainMap = new HashMap<>();
|
||||
nodeMap = new HashMap<>();
|
||||
fallbackNodeMap = new HashMap<>();
|
||||
elMd5Map = new HashMap<>();
|
||||
} else {
|
||||
chainMap = new CopyOnWriteHashMap<>();
|
||||
nodeMap = new CopyOnWriteHashMap<>();
|
||||
fallbackNodeMap = new CopyOnWriteHashMap<>();
|
||||
elMd5Map = new CopyOnWriteHashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
// 这一方法主要用于第一阶段chain的预装载
|
||||
public static void addChain(String chainName) {
|
||||
if (!chainMap.containsKey(chainName)) {
|
||||
chainMap.put(chainName, new Chain(chainName));
|
||||
}
|
||||
}
|
||||
public static Chain getChain(String id) {
|
||||
return chainMap.get(id);
|
||||
}
|
||||
|
||||
// 这个方法主要用于第二阶段的替换chain
|
||||
public static void addChain(Chain chain) {
|
||||
//如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessChainBuildLifeCycleList())){
|
||||
LifeCycleHolder.getPostProcessChainBuildLifeCycleList().forEach(
|
||||
postProcessAfterChainBuildLifeCycle -> postProcessAfterChainBuildLifeCycle.postProcessBeforeChainBuild(chain)
|
||||
);
|
||||
}
|
||||
// 这一方法主要用于第一阶段chain的预装载
|
||||
public static void addChain(String chainName) {
|
||||
if (!chainMap.containsKey(chainName)) {
|
||||
chainMap.put(chainName, new Chain(chainName));
|
||||
}
|
||||
}
|
||||
|
||||
chainMap.put(chain.getChainId(), chain);
|
||||
// 这个方法主要用于第二阶段的替换chain
|
||||
public static void addChain(Chain chain) {
|
||||
//如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessChainBuildLifeCycleList())) {
|
||||
LifeCycleHolder.getPostProcessChainBuildLifeCycleList().forEach(
|
||||
postProcessAfterChainBuildLifeCycle -> postProcessAfterChainBuildLifeCycle.postProcessBeforeChainBuild(chain)
|
||||
);
|
||||
}
|
||||
|
||||
//如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessChainBuildLifeCycleList())){
|
||||
LifeCycleHolder.getPostProcessChainBuildLifeCycleList().forEach(
|
||||
postProcessAfterChainBuildLifeCycle -> postProcessAfterChainBuildLifeCycle.postProcessAfterChainBuild(chain)
|
||||
);
|
||||
}
|
||||
}
|
||||
chainMap.put(chain.getChainId(), chain);
|
||||
|
||||
public static boolean containChain(String chainId) {
|
||||
return chainMap.containsKey(chainId);
|
||||
}
|
||||
elMd5Map.put(chain.getElMd5(), chain.getChainId());
|
||||
|
||||
public static boolean needInit() {
|
||||
return initStat.compareAndSet(false, true);
|
||||
}
|
||||
//如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessChainBuildLifeCycleList())) {
|
||||
LifeCycleHolder.getPostProcessChainBuildLifeCycleList().forEach(
|
||||
postProcessAfterChainBuildLifeCycle -> postProcessAfterChainBuildLifeCycle.postProcessAfterChainBuild(chain)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean containNode(String nodeId) {
|
||||
return nodeMap.containsKey(nodeId);
|
||||
}
|
||||
public static boolean containChain(String chainId) {
|
||||
return chainMap.containsKey(chainId);
|
||||
}
|
||||
|
||||
public static void addManagedNode(String nodeId) {
|
||||
ContextAware contextAware = ContextAwareHolder.loadContextAware();
|
||||
if (contextAware.hasBean(nodeId)){
|
||||
addManagedNode(nodeId, contextAware.getBean(nodeId));
|
||||
}
|
||||
}
|
||||
public static boolean needInit() {
|
||||
return initStat.compareAndSet(false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加已托管的节点(如:Spring、Solon 管理的节点)
|
||||
* @param nodeId nodeId
|
||||
* @param nodeComponent nodeComponent
|
||||
*/
|
||||
public static void addManagedNode(String nodeId, NodeComponent nodeComponent) {
|
||||
// 根据class来猜测类型
|
||||
NodeTypeEnum type = NodeTypeEnum.guessType(nodeComponent.getClass());
|
||||
public static boolean containNode(String nodeId) {
|
||||
return nodeMap.containsKey(nodeId);
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
throw new NullNodeTypeException(StrUtil.format("node type is null for node[{}]", nodeId));
|
||||
}
|
||||
public static void addManagedNode(String nodeId) {
|
||||
ContextAware contextAware = ContextAwareHolder.loadContextAware();
|
||||
if (contextAware.hasBean(nodeId)) {
|
||||
addManagedNode(nodeId, contextAware.getBean(nodeId));
|
||||
}
|
||||
}
|
||||
|
||||
Node node = new Node(ComponentInitializer.loadInstance()
|
||||
.initComponent(nodeComponent, type, nodeComponent.getName(), nodeId));
|
||||
put2NodeMap(nodeId, node);
|
||||
addFallbackNode(node);
|
||||
}
|
||||
/**
|
||||
* 添加已托管的节点(如:Spring、Solon 管理的节点)
|
||||
*
|
||||
* @param nodeId nodeId
|
||||
* @param nodeComponent nodeComponent
|
||||
*/
|
||||
public static void addManagedNode(String nodeId, NodeComponent nodeComponent) {
|
||||
// 根据class来猜测类型
|
||||
NodeTypeEnum type = NodeTypeEnum.guessType(nodeComponent.getClass());
|
||||
|
||||
/**
|
||||
* 添加 node
|
||||
* @param nodeId 节点id
|
||||
* @param name 节点名称
|
||||
* @param type 节点类型
|
||||
* @param cmpClazz 节点组件类
|
||||
*/
|
||||
public static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz) {
|
||||
addNode(nodeId, name, type, cmpClazz, null, null);
|
||||
}
|
||||
if (type == null) {
|
||||
throw new NullNodeTypeException(StrUtil.format("node type is null for node[{}]", nodeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 node
|
||||
* @param nodeId 节点id
|
||||
* @param name 节点名称
|
||||
* @param nodeType 节点类型
|
||||
* @param cmpClazzStr 节点组件类路径
|
||||
*/
|
||||
public static void addNode(String nodeId, String name, NodeTypeEnum nodeType, String cmpClazzStr) {
|
||||
Class<?> cmpClazz;
|
||||
try {
|
||||
cmpClazz = Class.forName(cmpClazzStr);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new ComponentCannotRegisterException(e.getMessage());
|
||||
}
|
||||
addNode(nodeId, name, nodeType, cmpClazz, null, null);
|
||||
}
|
||||
Node node = new Node(ComponentInitializer.loadInstance()
|
||||
.initComponent(nodeComponent, type, nodeComponent.getName(), nodeId));
|
||||
put2NodeMap(nodeId, node);
|
||||
addFallbackNode(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加脚本 node
|
||||
* @param nodeId 节点id
|
||||
* @param name 节点名称
|
||||
* @param nodeType 节点类型
|
||||
* @param script 脚本
|
||||
* @param language 语言
|
||||
*/
|
||||
public static void addScriptNode(String nodeId, String name, NodeTypeEnum nodeType, String script,
|
||||
String language) {
|
||||
/**
|
||||
* 添加 node
|
||||
*
|
||||
* @param nodeId 节点id
|
||||
* @param name 节点名称
|
||||
* @param type 节点类型
|
||||
* @param cmpClazz 节点组件类
|
||||
*/
|
||||
public static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz) {
|
||||
addNode(nodeId, name, type, cmpClazz, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 node
|
||||
*
|
||||
* @param nodeId 节点id
|
||||
* @param name 节点名称
|
||||
* @param nodeType 节点类型
|
||||
* @param cmpClazzStr 节点组件类路径
|
||||
*/
|
||||
public static void addNode(String nodeId, String name, NodeTypeEnum nodeType, String cmpClazzStr) {
|
||||
Class<?> cmpClazz;
|
||||
try {
|
||||
cmpClazz = Class.forName(cmpClazzStr);
|
||||
} catch (Exception e) {
|
||||
throw new ComponentCannotRegisterException(e.getMessage());
|
||||
}
|
||||
addNode(nodeId, name, nodeType, cmpClazz, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加脚本 node
|
||||
*
|
||||
* @param nodeId 节点id
|
||||
* @param name 节点名称
|
||||
* @param nodeType 节点类型
|
||||
* @param script 脚本
|
||||
* @param language 语言
|
||||
*/
|
||||
public static void addScriptNode(String nodeId, String name, NodeTypeEnum nodeType, String script,
|
||||
String language) {
|
||||
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
|
||||
|
||||
// 如果是PARSE_ONE_ON_FIRST_EXEC模式,则不进行脚本加载,而是直接把脚本内容放到node中
|
||||
// 如果是PARSE_ONE_ON_FIRST_EXEC模式,则不进行脚本加载,而是直接把脚本内容放到node中
|
||||
if (liteflowConfig.getParseMode().equals(ParseModeEnum.PARSE_ONE_ON_FIRST_EXEC)) {
|
||||
List<Node> nodes = LiteflowMetaOperator.getNodesInAllChain(nodeId);
|
||||
if (CollectionUtil.isNotEmpty(nodes)) {
|
||||
nodes.forEach(node -> {
|
||||
List<Node> nodes = LiteflowMetaOperator.getNodesInAllChain(nodeId);
|
||||
if (CollectionUtil.isNotEmpty(nodes)) {
|
||||
nodes.forEach(node -> {
|
||||
node.setCompiled(false);
|
||||
node.setScript(script);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Node node = new Node(nodeId, name, nodeType, script, language);
|
||||
nodeMap.put(nodeId, node);
|
||||
} else {
|
||||
addScriptNodeAndCompile(nodeId, name, nodeType, script, language);
|
||||
Node node = new Node(nodeId, name, nodeType, script, language);
|
||||
nodeMap.put(nodeId, node);
|
||||
} else {
|
||||
addScriptNodeAndCompile(nodeId, name, nodeType, script, language);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加脚本 node,并且编译脚本
|
||||
* @param nodeId nodeId
|
||||
* @param name name
|
||||
* @param type type
|
||||
* @param script script content
|
||||
* @param language language
|
||||
* @return NodeComponent instance
|
||||
*/
|
||||
public static NodeComponent addScriptNodeAndCompile(String nodeId, String name, NodeTypeEnum type, String script,
|
||||
String language) {
|
||||
addNode(nodeId, name, type, ScriptComponent.ScriptComponentClassMap.get(type), script, language);
|
||||
return nodeMap.get(nodeId).getInstance();
|
||||
}
|
||||
/**
|
||||
* 添加脚本 node,并且编译脚本
|
||||
*
|
||||
* @param nodeId nodeId
|
||||
* @param name name
|
||||
* @param type type
|
||||
* @param script script content
|
||||
* @param language language
|
||||
* @return NodeComponent instance
|
||||
*/
|
||||
public static NodeComponent addScriptNodeAndCompile(String nodeId, String name, NodeTypeEnum type, String script,
|
||||
String language) {
|
||||
addNode(nodeId, name, type, ScriptComponent.ScriptComponentClassMap.get(type), script, language);
|
||||
return nodeMap.get(nodeId).getInstance();
|
||||
}
|
||||
|
||||
|
||||
private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz, String script,
|
||||
String language) {
|
||||
try {
|
||||
// 判断此类是否是声明式的组件,如果是声明式的组件,就用动态代理生成实例
|
||||
// 如果不是声明式的,就用传统的方式进行判断
|
||||
List<NodeComponent> cmpInstanceList = new ArrayList<>();
|
||||
if (LiteFlowProxyUtil.isDeclareCmp(cmpClazz)) {
|
||||
// 如果是spring体系,把原始的类往spring上下文中进行注册,那么会走到ComponentScanner中
|
||||
// 由于ComponentScanner中已经对原始类进行了动态代理,出来的对象已经变成了动态代理类,所以这时候的bean已经是NodeComponent的子类了
|
||||
// 所以spring体系下,无需再对这个bean做二次代理
|
||||
// 非spring体系下,从2.11.4开始不再支持声明式组件
|
||||
List<DeclWarpBean> declWarpBeanList = DeclComponentParserHolder.loadDeclComponentParser().parseDeclBean(cmpClazz, nodeId, name);
|
||||
private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz, String script,
|
||||
String language) {
|
||||
try {
|
||||
// 判断此类是否是声明式的组件,如果是声明式的组件,就用动态代理生成实例
|
||||
// 如果不是声明式的,就用传统的方式进行判断
|
||||
List<NodeComponent> cmpInstanceList = new ArrayList<>();
|
||||
if (LiteFlowProxyUtil.isDeclareCmp(cmpClazz)) {
|
||||
// 如果是spring体系,把原始的类往spring上下文中进行注册,那么会走到ComponentScanner中
|
||||
// 由于ComponentScanner中已经对原始类进行了动态代理,出来的对象已经变成了动态代理类,所以这时候的bean已经是NodeComponent的子类了
|
||||
// 所以spring体系下,无需再对这个bean做二次代理
|
||||
// 非spring体系下,从2.11.4开始不再支持声明式组件
|
||||
List<DeclWarpBean> declWarpBeanList = DeclComponentParserHolder.loadDeclComponentParser().parseDeclBean(cmpClazz, nodeId, name);
|
||||
|
||||
cmpInstanceList = declWarpBeanList.stream().map(
|
||||
declWarpBean -> (NodeComponent)ContextAwareHolder.loadContextAware().registerDeclWrapBean(nodeId, declWarpBean)
|
||||
).collect(Collectors.toList());
|
||||
}
|
||||
else {
|
||||
// 以node方式配置,本质上是为了适配无spring的环境,如果有spring环境,其实不用这么配置
|
||||
// 这里的逻辑是判断是否能从spring上下文中取到,如果没有spring,则就是new instance了
|
||||
// 如果是script类型的节点,因为class只有一个,所以也不能注册进spring上下文,注册的时候需要new Instance
|
||||
if (!type.isScript()) {
|
||||
cmpInstanceList = ListUtil
|
||||
.toList((NodeComponent) ContextAwareHolder.loadContextAware().registerOrGet(nodeId, cmpClazz));
|
||||
}
|
||||
// 如果为空
|
||||
if (cmpInstanceList.isEmpty()) {
|
||||
NodeComponent cmpInstance = (NodeComponent) cmpClazz.newInstance();
|
||||
cmpInstanceList.add(cmpInstance);
|
||||
}
|
||||
}
|
||||
// 进行初始化component
|
||||
cmpInstanceList = cmpInstanceList.stream()
|
||||
.map(cmpInstance -> ComponentInitializer.loadInstance()
|
||||
.initComponent(cmpInstance, type, name,
|
||||
cmpInstance.getNodeId() == null ? nodeId : cmpInstance.getNodeId()))
|
||||
.collect(Collectors.toList());
|
||||
cmpInstanceList = declWarpBeanList.stream().map(
|
||||
declWarpBean -> (NodeComponent) ContextAwareHolder.loadContextAware().registerDeclWrapBean(nodeId, declWarpBean)
|
||||
).collect(Collectors.toList());
|
||||
} else {
|
||||
// 以node方式配置,本质上是为了适配无spring的环境,如果有spring环境,其实不用这么配置
|
||||
// 这里的逻辑是判断是否能从spring上下文中取到,如果没有spring,则就是new instance了
|
||||
// 如果是script类型的节点,因为class只有一个,所以也不能注册进spring上下文,注册的时候需要new Instance
|
||||
if (!type.isScript()) {
|
||||
cmpInstanceList = ListUtil
|
||||
.toList((NodeComponent) ContextAwareHolder.loadContextAware().registerOrGet(nodeId, cmpClazz));
|
||||
}
|
||||
// 如果为空
|
||||
if (cmpInstanceList.isEmpty()) {
|
||||
NodeComponent cmpInstance = (NodeComponent) cmpClazz.newInstance();
|
||||
cmpInstanceList.add(cmpInstance);
|
||||
}
|
||||
}
|
||||
// 进行初始化component
|
||||
cmpInstanceList = cmpInstanceList.stream()
|
||||
.map(cmpInstance -> ComponentInitializer.loadInstance()
|
||||
.initComponent(cmpInstance, type, name,
|
||||
cmpInstance.getNodeId() == null ? nodeId : cmpInstance.getNodeId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
// 初始化Node,把component放到Node里去
|
||||
List<Node> nodes = cmpInstanceList.stream().map(Node::new).collect(Collectors.toList());
|
||||
// 初始化Node,把component放到Node里去
|
||||
List<Node> nodes = cmpInstanceList.stream().map(Node::new).collect(Collectors.toList());
|
||||
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
Node node = nodes.get(i);
|
||||
NodeComponent cmpInstance = cmpInstanceList.get(i);
|
||||
// 如果是脚本节点,则还要加载script脚本
|
||||
if (type.isScript()) {
|
||||
if (StrUtil.isNotBlank(script)) {
|
||||
node.setScript(script);
|
||||
node.setLanguage(language);
|
||||
((ScriptComponent) cmpInstance).loadScript(script, language);
|
||||
}
|
||||
else {
|
||||
String errorMsg = StrUtil.format("script for node[{}] is empty", nodeId);
|
||||
throw new ScriptLoadException(errorMsg);
|
||||
}
|
||||
}
|
||||
String activeNodeId = StrUtil.isEmpty(cmpInstance.getNodeId()) ? nodeId : cmpInstance.getNodeId();
|
||||
put2NodeMap(activeNodeId, node);
|
||||
addFallbackNode(node);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
String error = StrUtil.format("component[{}] register error",
|
||||
StrUtil.isEmpty(name) ? nodeId : StrUtil.format("{}({})", nodeId, name));
|
||||
LOG.error(e.getMessage());
|
||||
throw new ComponentCannotRegisterException(StrUtil.format("{} {}", error, e.getMessage()));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
Node node = nodes.get(i);
|
||||
NodeComponent cmpInstance = cmpInstanceList.get(i);
|
||||
// 如果是脚本节点,则还要加载script脚本
|
||||
if (type.isScript()) {
|
||||
if (StrUtil.isNotBlank(script)) {
|
||||
node.setScript(script);
|
||||
node.setLanguage(language);
|
||||
((ScriptComponent) cmpInstance).loadScript(script, language);
|
||||
} else {
|
||||
String errorMsg = StrUtil.format("script for node[{}] is empty", nodeId);
|
||||
throw new ScriptLoadException(errorMsg);
|
||||
}
|
||||
}
|
||||
String activeNodeId = StrUtil.isEmpty(cmpInstance.getNodeId()) ? nodeId : cmpInstance.getNodeId();
|
||||
put2NodeMap(activeNodeId, node);
|
||||
addFallbackNode(node);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String error = StrUtil.format("component[{}] register error",
|
||||
StrUtil.isEmpty(name) ? nodeId : StrUtil.format("{}({})", nodeId, name));
|
||||
LOG.error(e.getMessage());
|
||||
throw new ComponentCannotRegisterException(StrUtil.format("{} {}", error, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public static Node getNode(String nodeId) {
|
||||
return nodeMap.get(nodeId);
|
||||
}
|
||||
public static Node getNode(String nodeId) {
|
||||
return nodeMap.get(nodeId);
|
||||
}
|
||||
|
||||
public static Map<String, Node> getNodeMap() {
|
||||
return nodeMap;
|
||||
}
|
||||
public static Map<String, Node> getNodeMap() {
|
||||
return nodeMap;
|
||||
}
|
||||
|
||||
public static Map<String, Chain> getChainMap() {
|
||||
return chainMap;
|
||||
}
|
||||
public static Map<String, Chain> getChainMap() {
|
||||
return chainMap;
|
||||
}
|
||||
|
||||
public static Node getFallBackNode(NodeTypeEnum nodeType){
|
||||
String key = StrUtil.format("FB_{}", nodeType.name());
|
||||
return fallbackNodeMap.get(key);
|
||||
}
|
||||
public static Node getFallBackNode(NodeTypeEnum nodeType) {
|
||||
String key = StrUtil.format("FB_{}", nodeType.name());
|
||||
return fallbackNodeMap.get(key);
|
||||
}
|
||||
|
||||
public static void cleanCache() {
|
||||
chainMap.clear();
|
||||
nodeMap.clear();
|
||||
fallbackNodeMap.clear();
|
||||
cleanScriptCache();
|
||||
}
|
||||
public static void cleanCache() {
|
||||
chainMap.clear();
|
||||
nodeMap.clear();
|
||||
fallbackNodeMap.clear();
|
||||
elMd5Map.clear();
|
||||
cleanScriptCache();
|
||||
}
|
||||
|
||||
public static void cleanScriptCache() {
|
||||
// 如果引入了脚本组件SPI,则还需要清理脚本的缓存
|
||||
try {
|
||||
ScriptExecutorFactory.loadInstance().cleanScriptCache();
|
||||
}
|
||||
catch (ScriptSpiException ignored) {
|
||||
}
|
||||
}
|
||||
public static void cleanScriptCache() {
|
||||
// 如果引入了脚本组件SPI,则还需要清理脚本的缓存
|
||||
try {
|
||||
ScriptExecutorFactory.loadInstance().cleanScriptCache();
|
||||
} catch (ScriptSpiException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void refreshFlowMetaData(FlowParserTypeEnum type, String content) throws Exception {
|
||||
if (type.equals(FlowParserTypeEnum.TYPE_EL_XML)) {
|
||||
new LocalXmlFlowELParser().parse(content);
|
||||
}
|
||||
else if (type.equals(FlowParserTypeEnum.TYPE_EL_JSON)) {
|
||||
new LocalJsonFlowELParser().parse(content);
|
||||
}
|
||||
else if (type.equals(FlowParserTypeEnum.TYPE_EL_YML)) {
|
||||
new LocalYmlFlowELParser().parse(content);
|
||||
}
|
||||
}
|
||||
public static void refreshFlowMetaData(FlowParserTypeEnum type, String content) throws Exception {
|
||||
if (type.equals(FlowParserTypeEnum.TYPE_EL_XML)) {
|
||||
new LocalXmlFlowELParser().parse(content);
|
||||
} else if (type.equals(FlowParserTypeEnum.TYPE_EL_JSON)) {
|
||||
new LocalJsonFlowELParser().parse(content);
|
||||
} else if (type.equals(FlowParserTypeEnum.TYPE_EL_YML)) {
|
||||
new LocalYmlFlowELParser().parse(content);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean removeChain(String chainId) {
|
||||
if (containChain(chainId)) {
|
||||
chainMap.remove(chainId);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
String errMsg = StrUtil.format("cannot find the chain[{}]", chainId);
|
||||
LOG.error(errMsg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static String getChainIdByElMd5(String elMd5) {
|
||||
return elMd5Map.get(elMd5);
|
||||
}
|
||||
|
||||
public static void removeChain(String... chainIds) {
|
||||
Arrays.stream(chainIds).forEach(FlowBus::removeChain);
|
||||
}
|
||||
public static boolean removeChain(String chainId) {
|
||||
if (containChain(chainId)) {
|
||||
Chain removedChain = chainMap.remove(chainId);
|
||||
// 移除 elMd5 对应的 chainId
|
||||
elMd5Map.remove(removedChain.getElMd5());
|
||||
return true;
|
||||
} else {
|
||||
String errMsg = StrUtil.format("cannot find the chain[{}]", chainId);
|
||||
LOG.error(errMsg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 移除节点
|
||||
public static boolean removeNode(String nodeId) {
|
||||
return nodeMap.remove(nodeId) != null;
|
||||
}
|
||||
public static void removeChain(String... chainIds) {
|
||||
Arrays.stream(chainIds).forEach(FlowBus::removeChain);
|
||||
}
|
||||
|
||||
// 判断是否是降级组件,如果是则添加到 fallbackNodeMap
|
||||
private static void addFallbackNode(Node node) {
|
||||
NodeComponent nodeComponent = node.getInstance();
|
||||
FallbackCmp fallbackCmp = AnnoUtil.getAnnotation(nodeComponent.getClass(), FallbackCmp.class);
|
||||
if (fallbackCmp == null) {
|
||||
return;
|
||||
}
|
||||
// 移除节点
|
||||
public static boolean removeNode(String nodeId) {
|
||||
return nodeMap.remove(nodeId) != null;
|
||||
}
|
||||
|
||||
NodeTypeEnum nodeType = node.getType();
|
||||
String key = StrUtil.format("FB_{}", nodeType.name());
|
||||
fallbackNodeMap.put(key, node);
|
||||
}
|
||||
// 判断是否是降级组件,如果是则添加到 fallbackNodeMap
|
||||
private static void addFallbackNode(Node node) {
|
||||
NodeComponent nodeComponent = node.getInstance();
|
||||
FallbackCmp fallbackCmp = AnnoUtil.getAnnotation(nodeComponent.getClass(), FallbackCmp.class);
|
||||
if (fallbackCmp == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
NodeTypeEnum nodeType = node.getType();
|
||||
String key = StrUtil.format("FB_{}", nodeType.name());
|
||||
fallbackNodeMap.put(key, node);
|
||||
}
|
||||
|
||||
// 重新加载脚本
|
||||
public static void reloadScript(String nodeId, String script) {
|
||||
Node node = getNode(nodeId);
|
||||
if (node == null || !node.getType().isScript()) {
|
||||
return;
|
||||
}
|
||||
public static void reloadScript(String nodeId, String script) {
|
||||
Node node = getNode(nodeId);
|
||||
if (node == null || !node.getType().isScript()) {
|
||||
return;
|
||||
}
|
||||
// 更新元数据模版中的脚本
|
||||
node.setScript(script);
|
||||
node.setScript(script);
|
||||
|
||||
// 更新Chain中的Node中的脚本
|
||||
LiteflowMetaOperator.getNodesInAllChain(nodeId).forEach(n -> n.setScript(script));
|
||||
// 更新Chain中的Node中的脚本
|
||||
LiteflowMetaOperator.getNodesInAllChain(nodeId).forEach(n -> n.setScript(script));
|
||||
|
||||
ScriptExecutorFactory.loadInstance()
|
||||
.getScriptExecutor(node.getLanguage())
|
||||
.load(nodeId, script);
|
||||
}
|
||||
ScriptExecutorFactory.loadInstance()
|
||||
.getScriptExecutor(node.getLanguage())
|
||||
.load(nodeId, script);
|
||||
}
|
||||
|
||||
// 卸载脚本节点
|
||||
public static boolean unloadScriptNode(String nodeId) {
|
||||
Node node = getNode(nodeId);
|
||||
if (node == null || !node.getType().isScript()) {
|
||||
return false;
|
||||
}
|
||||
// 卸载脚本
|
||||
ScriptExecutorFactory.loadInstance()
|
||||
.getScriptExecutor(node.getLanguage())
|
||||
.unLoad(nodeId);
|
||||
// 移除脚本
|
||||
return removeNode(nodeId);
|
||||
}
|
||||
// 卸载脚本节点
|
||||
public static boolean unloadScriptNode(String nodeId) {
|
||||
Node node = getNode(nodeId);
|
||||
if (node == null || !node.getType().isScript()) {
|
||||
return false;
|
||||
}
|
||||
// 卸载脚本
|
||||
ScriptExecutorFactory.loadInstance()
|
||||
.getScriptExecutor(node.getLanguage())
|
||||
.unLoad(nodeId);
|
||||
// 移除脚本
|
||||
return removeNode(nodeId);
|
||||
}
|
||||
|
||||
// 重新加载规则
|
||||
public static void reloadChain(String chainId, String elContent) {
|
||||
reloadChain(chainId, elContent, null);
|
||||
}
|
||||
// 重新加载规则
|
||||
public static void reloadChain(String chainId, String elContent) {
|
||||
reloadChain(chainId, elContent, null);
|
||||
}
|
||||
|
||||
public static void reloadChain(String chainId, String elContent, String routeContent) {
|
||||
LiteFlowChainELBuilder.createChain().setChainId(chainId).setEL(elContent).setRoute(routeContent).build();
|
||||
}
|
||||
public static void reloadChain(String chainId, String elContent, String routeContent) {
|
||||
LiteFlowChainELBuilder.createChain().setChainId(chainId).setEL(elContent).setRoute(routeContent).build();
|
||||
}
|
||||
|
||||
public static void clearStat(){
|
||||
initStat.set(false);
|
||||
}
|
||||
public static void clearStat() {
|
||||
initStat.set(false);
|
||||
}
|
||||
|
||||
private static void put2NodeMap(String nodeId, Node node){
|
||||
// 如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessNodeBuildLifeCycleList())){
|
||||
LifeCycleHolder.getPostProcessNodeBuildLifeCycleList().forEach(
|
||||
postProcessAfterNodeBuildLifeCycle -> postProcessAfterNodeBuildLifeCycle.postProcessBeforeNodeBuild(node)
|
||||
);
|
||||
}
|
||||
private static void put2NodeMap(String nodeId, Node node) {
|
||||
// 如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessNodeBuildLifeCycleList())) {
|
||||
LifeCycleHolder.getPostProcessNodeBuildLifeCycleList().forEach(
|
||||
postProcessAfterNodeBuildLifeCycle -> postProcessAfterNodeBuildLifeCycle.postProcessBeforeNodeBuild(node)
|
||||
);
|
||||
}
|
||||
|
||||
nodeMap.put(nodeId, node);
|
||||
nodeMap.put(nodeId, node);
|
||||
|
||||
// 如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessNodeBuildLifeCycleList())){
|
||||
LifeCycleHolder.getPostProcessNodeBuildLifeCycleList().forEach(
|
||||
postProcessAfterNodeBuildLifeCycle -> postProcessAfterNodeBuildLifeCycle.postProcessAfterNodeBuild(node)
|
||||
);
|
||||
}
|
||||
}
|
||||
// 如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessNodeBuildLifeCycleList())) {
|
||||
LifeCycleHolder.getPostProcessNodeBuildLifeCycleList().forEach(
|
||||
postProcessAfterNodeBuildLifeCycle -> postProcessAfterNodeBuildLifeCycle.postProcessAfterNodeBuild(node)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.yomahub.liteflow.flow.element;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.crypto.digest.MD5;
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.common.ChainConstant;
|
||||
@@ -30,207 +31,206 @@ import java.util.List;
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @author jason
|
||||
* @author luo yi
|
||||
*/
|
||||
public class Chain implements Executable{
|
||||
public class Chain implements Executable {
|
||||
|
||||
private static final LFLog LOG = LFLoggerManager.getLogger(Chain.class);
|
||||
private static final LFLog LOG = LFLoggerManager.getLogger(Chain.class);
|
||||
|
||||
private String chainId;
|
||||
private String chainId;
|
||||
|
||||
private Executable routeItem;
|
||||
private Executable routeItem;
|
||||
|
||||
private List<Condition> conditionList = new ArrayList<>();
|
||||
private List<Condition> conditionList = new ArrayList<>();
|
||||
|
||||
private String el;
|
||||
private String el;
|
||||
|
||||
private boolean isCompiled = true;
|
||||
private boolean isCompiled = true;
|
||||
|
||||
private String namespace = ChainConstant.DEFAULT_NAMESPACE;
|
||||
private String namespace = ChainConstant.DEFAULT_NAMESPACE;
|
||||
|
||||
private String elMd5;
|
||||
|
||||
private String threadPoolExecutorClass;
|
||||
|
||||
private final TransmittableThreadLocal<Long> runtimeIdTL = new TransmittableThreadLocal<>();
|
||||
private final TransmittableThreadLocal<Long> runtimeIdTL = new TransmittableThreadLocal<>();
|
||||
|
||||
public Chain(String chainName) {
|
||||
this.chainId = chainName;
|
||||
}
|
||||
public Chain(String chainName) {
|
||||
this.chainId = chainName;
|
||||
}
|
||||
|
||||
public Chain() {
|
||||
}
|
||||
public Chain() {
|
||||
}
|
||||
|
||||
public Chain(String chainName, List<Condition> conditionList) {
|
||||
this.chainId = chainName;
|
||||
this.conditionList = conditionList;
|
||||
}
|
||||
public Chain(String chainName, List<Condition> conditionList) {
|
||||
this.chainId = chainName;
|
||||
this.conditionList = conditionList;
|
||||
}
|
||||
|
||||
public List<Condition> getConditionList() {
|
||||
return conditionList;
|
||||
}
|
||||
public List<Condition> getConditionList() {
|
||||
return conditionList;
|
||||
}
|
||||
|
||||
public void setConditionList(List<Condition> conditionList) {
|
||||
this.conditionList = conditionList;
|
||||
}
|
||||
public void setConditionList(List<Condition> conditionList) {
|
||||
this.conditionList = conditionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 请使用{@link #getChainId()}
|
||||
* @return chainId
|
||||
*/
|
||||
@Deprecated
|
||||
public String getChainName() {
|
||||
return chainId;
|
||||
}
|
||||
/**
|
||||
* @return chainId
|
||||
* @deprecated 请使用{@link #getChainId()}
|
||||
*/
|
||||
@Deprecated
|
||||
public String getChainName() {
|
||||
return chainId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param chainName chainId
|
||||
* @deprecated 请使用 {@link #setChainId(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setChainName(String chainName) {
|
||||
this.chainId = chainName;
|
||||
}
|
||||
/**
|
||||
* @param chainName chainId
|
||||
* @deprecated 请使用 {@link #setChainId(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setChainName(String chainName) {
|
||||
this.chainId = chainName;
|
||||
}
|
||||
|
||||
public String getChainId() {
|
||||
return chainId;
|
||||
}
|
||||
public String getChainId() {
|
||||
return chainId;
|
||||
}
|
||||
|
||||
public void setChainId(String chainId) {
|
||||
this.chainId = chainId;
|
||||
}
|
||||
public void setChainId(String chainId) {
|
||||
this.chainId = chainId;
|
||||
}
|
||||
|
||||
// 执行chain的主方法
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
//生成runtimeId
|
||||
this.runtimeIdTL.set(System.nanoTime());
|
||||
// 执行chain的主方法
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
//生成runtimeId
|
||||
this.runtimeIdTL.set(System.nanoTime());
|
||||
|
||||
//如果EL还未编译,则进行编译
|
||||
if (BooleanUtil.isFalse(isCompiled)) {
|
||||
LiteFlowChainELBuilder.buildUnCompileChain(this);
|
||||
}
|
||||
//如果EL还未编译,则进行编译
|
||||
if (BooleanUtil.isFalse(isCompiled)) {
|
||||
LiteFlowChainELBuilder.buildUnCompileChain(this);
|
||||
}
|
||||
|
||||
if (CollUtil.isEmpty(conditionList)) {
|
||||
throw new FlowSystemException("no conditionList in this chain[" + chainId + "]");
|
||||
}
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
try {
|
||||
//如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessChainExecuteLifeCycleList())){
|
||||
LifeCycleHolder.getPostProcessChainExecuteLifeCycleList().forEach(
|
||||
postProcessChainExecuteLifeCycle -> postProcessChainExecuteLifeCycle.postProcessBeforeChainExecute(chainId, slot)
|
||||
);
|
||||
}
|
||||
if (CollUtil.isEmpty(conditionList)) {
|
||||
throw new FlowSystemException("no conditionList in this chain[" + chainId + "]");
|
||||
}
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
try {
|
||||
//如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessChainExecuteLifeCycleList())) {
|
||||
LifeCycleHolder.getPostProcessChainExecuteLifeCycleList().forEach(
|
||||
postProcessChainExecuteLifeCycle -> postProcessChainExecuteLifeCycle.postProcessBeforeChainExecute(chainId, slot)
|
||||
);
|
||||
}
|
||||
|
||||
// 设置主ChainId
|
||||
slot.setChainId(chainId);
|
||||
slot.addChainInstance(this);
|
||||
// 执行主体Condition
|
||||
for (Condition condition : conditionList) {
|
||||
condition.setCurrChainId(chainId);
|
||||
condition.execute(slotIndex);
|
||||
}
|
||||
}
|
||||
catch (ChainEndException e) {
|
||||
// 这里单独catch ChainEndException是因为ChainEndException是用户自己setIsEnd抛出的异常
|
||||
// 是属于正常逻辑,所以会在FlowExecutor中判断。这里不作为异常处理
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
// 这里事先取到exception set到slot里,为了方便finally取到exception
|
||||
slot.setException(e);
|
||||
throw e;
|
||||
}finally {
|
||||
//如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessChainExecuteLifeCycleList())){
|
||||
LifeCycleHolder.getPostProcessChainExecuteLifeCycleList().forEach(
|
||||
postProcessChainExecuteLifeCycle -> postProcessChainExecuteLifeCycle.postProcessAfterChainExecute(chainId, slot)
|
||||
);
|
||||
}
|
||||
runtimeIdTL.remove();
|
||||
}
|
||||
}
|
||||
// 设置主ChainId
|
||||
slot.setChainId(chainId);
|
||||
slot.addChainInstance(this);
|
||||
// 执行主体Condition
|
||||
for (Condition condition : conditionList) {
|
||||
condition.setCurrChainId(chainId);
|
||||
condition.execute(slotIndex);
|
||||
}
|
||||
} catch (ChainEndException e) {
|
||||
// 这里单独catch ChainEndException是因为ChainEndException是用户自己setIsEnd抛出的异常
|
||||
// 是属于正常逻辑,所以会在FlowExecutor中判断。这里不作为异常处理
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// 这里事先取到exception set到slot里,为了方便finally取到exception
|
||||
slot.setException(e);
|
||||
throw e;
|
||||
} finally {
|
||||
//如果有生命周期则执行相应生命周期实现
|
||||
if (CollUtil.isNotEmpty(LifeCycleHolder.getPostProcessChainExecuteLifeCycleList())) {
|
||||
LifeCycleHolder.getPostProcessChainExecuteLifeCycleList().forEach(
|
||||
postProcessChainExecuteLifeCycle -> postProcessChainExecuteLifeCycle.postProcessAfterChainExecute(chainId, slot)
|
||||
);
|
||||
}
|
||||
runtimeIdTL.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void executeRoute(Integer slotIndex) throws Exception {
|
||||
if (routeItem == null) {
|
||||
throw new FlowSystemException("no route condition or node in this chain[" + chainId + "]");
|
||||
}
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
try {
|
||||
// 设置主ChainName
|
||||
slot.setChainId(chainId);
|
||||
public void executeRoute(Integer slotIndex) throws Exception {
|
||||
if (routeItem == null) {
|
||||
throw new FlowSystemException("no route condition or node in this chain[" + chainId + "]");
|
||||
}
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
try {
|
||||
// 设置主ChainName
|
||||
slot.setChainId(chainId);
|
||||
|
||||
// 执行决策路由
|
||||
routeItem.setCurrChainId(chainId);
|
||||
routeItem.execute(slotIndex);
|
||||
// 执行决策路由
|
||||
routeItem.setCurrChainId(chainId);
|
||||
routeItem.execute(slotIndex);
|
||||
|
||||
boolean routeResult = routeItem.getItemResultMetaValue(slotIndex);
|
||||
boolean routeResult = routeItem.getItemResultMetaValue(slotIndex);
|
||||
|
||||
slot.setRouteResult(routeResult);
|
||||
}
|
||||
catch (ChainEndException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
slot.setException(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
slot.setRouteResult(routeResult);
|
||||
} catch (ChainEndException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
slot.setException(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecuteableTypeEnum getExecuteType() {
|
||||
return ExecuteableTypeEnum.CHAIN;
|
||||
}
|
||||
@Override
|
||||
public ExecuteableTypeEnum getExecuteType() {
|
||||
return ExecuteableTypeEnum.CHAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(String id) {
|
||||
this.chainId = id;
|
||||
}
|
||||
@Override
|
||||
public void setId(String id) {
|
||||
this.chainId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return chainId;
|
||||
}
|
||||
@Override
|
||||
public String getId() {
|
||||
return chainId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTag(String tag) {
|
||||
//do nothing
|
||||
}
|
||||
@Override
|
||||
public void setTag(String tag) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTag() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getTag() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Executable getRouteItem() {
|
||||
return routeItem;
|
||||
}
|
||||
public Executable getRouteItem() {
|
||||
return routeItem;
|
||||
}
|
||||
|
||||
public void setRouteItem(Executable routeItem) {
|
||||
this.routeItem = routeItem;
|
||||
}
|
||||
public void setRouteItem(Executable routeItem) {
|
||||
this.routeItem = routeItem;
|
||||
}
|
||||
|
||||
public String getEl() {
|
||||
return el;
|
||||
}
|
||||
public String getEl() {
|
||||
return el;
|
||||
}
|
||||
|
||||
public void setEl(String el) {
|
||||
this.el = el;
|
||||
}
|
||||
public void setEl(String el) {
|
||||
this.el = el;
|
||||
}
|
||||
|
||||
public boolean isCompiled() {
|
||||
return isCompiled;
|
||||
}
|
||||
public boolean isCompiled() {
|
||||
return isCompiled;
|
||||
}
|
||||
|
||||
public void setCompiled(boolean compiled) {
|
||||
isCompiled = compiled;
|
||||
}
|
||||
public void setCompiled(boolean compiled) {
|
||||
isCompiled = compiled;
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
public String getThreadPoolExecutorClass() {
|
||||
return threadPoolExecutorClass;
|
||||
@@ -240,7 +240,15 @@ public class Chain implements Executable{
|
||||
this.threadPoolExecutorClass = threadPoolExecutorClass;
|
||||
}
|
||||
|
||||
public Long getRuntimeId(){
|
||||
return runtimeIdTL.get();
|
||||
}
|
||||
public Long getRuntimeId() {
|
||||
return runtimeIdTL.get();
|
||||
}
|
||||
|
||||
public String getElMd5() {
|
||||
return elMd5 == null ? MD5.create().digestHex(el) : elMd5;
|
||||
}
|
||||
|
||||
public void setElMd5(String elMd5) {
|
||||
this.elMd5 = elMd5;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.yomahub.liteflow.flow.instanceId;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.crypto.digest.MD5;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.Condition;
|
||||
@@ -9,11 +8,14 @@ import com.yomahub.liteflow.flow.element.Node;
|
||||
import com.yomahub.liteflow.flow.entity.InstanceInfoDto;
|
||||
import com.yomahub.liteflow.util.JsonUtil;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.yomahub.liteflow.util.SerialsUtil.generateShortUUID;
|
||||
|
||||
/**
|
||||
* @author lhh
|
||||
* @author luo yi
|
||||
* @since 2.13.0
|
||||
*/
|
||||
public abstract class BaseNodeInstanceIdManageSpi implements NodeInstanceIdManageSpi {
|
||||
@@ -156,7 +158,7 @@ public abstract class BaseNodeInstanceIdManageSpi implements NodeInstanceIdManag
|
||||
public void setNodesInstanceId(Condition condition, Chain chain) {
|
||||
NodeInstanceIdManageSpi nodeInstanceIdManageSpi = NodeInstanceIdManageSpiHolder.getInstance().getNodeInstanceIdManageSpi();
|
||||
|
||||
String elMd5 = MD5.create().digestHex(chain.getEl());
|
||||
String elMd5 = chain.getElMd5();
|
||||
String chainId = chain.getChainId();
|
||||
List<String> instanceIdFile = nodeInstanceIdManageSpi.readInstanceIdFile(chainId);
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.yomahub.liteflow.util;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.exception.ParseException;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
@@ -56,4 +54,15 @@ public class ElRegexUtil {
|
||||
public static boolean isAbstractChain(String elStr) {
|
||||
return Pattern.compile(REGEX_ABSTRACT_HOLDER).matcher(elStr).find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化 EL
|
||||
* @param elStr
|
||||
* @return String
|
||||
*/
|
||||
public static String normalize(String elStr) {
|
||||
// 替换 EL 中多余空格,并在末尾保留分号
|
||||
return elStr.replaceAll("\\s", "").replaceFirst(";*$", ";");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.yomahub.liteflow.test.base;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
@@ -16,6 +17,7 @@ import javax.annotation.Resource;
|
||||
* springboot环境EL常规的例子测试
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @author luo yi
|
||||
*/
|
||||
@TestPropertySource(value = "classpath:/base/application.properties")
|
||||
@SpringBootTest(classes = BaseELSpringbootTest.class)
|
||||
@@ -64,8 +66,27 @@ public class BaseELSpringbootTest extends BaseTest {
|
||||
// 入参执行 EL 表达式
|
||||
@Test
|
||||
public void testBase6() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2RespWithEL("THEN(a,b,c)");
|
||||
LiteflowResponse response = flowExecutor.execute2RespWithEL("THEN(a, b,c);;");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
|
||||
LiteflowResponse response1 = flowExecutor.execute2RespWithEL("THEN(\na, \tb,c);");
|
||||
Assertions.assertTrue(response1.isSuccess());
|
||||
|
||||
Assertions.assertEquals(response.getChainId(), response1.getChainId());
|
||||
}
|
||||
|
||||
// 入参执行 EL 表达式,测试移除 chain
|
||||
@Test
|
||||
public void testBase7() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2RespWithEL("THEN(a,b, \nc);;");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
|
||||
FlowBus.removeChain(response.getChainId());
|
||||
|
||||
LiteflowResponse response1 = flowExecutor.execute2RespWithEL("THEN(a,b, c);");
|
||||
Assertions.assertTrue(response1.isSuccess());
|
||||
|
||||
Assertions.assertNotEquals(response.getChainId(), response1.getChainId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user