Merge branch 'dev' of https://gitee.com/noear_admin/liteFlow into dev
This commit is contained in:
commit
7483baadd3
|
@ -21,8 +21,6 @@ You can find out how to join the community on the official website!
|
|||
## Documents url: [Click here to enter the documentation to learn](https://liteflow.yomahub.com/en/pages/5816c5/)
|
||||
## Demo projects: [DEMO1](https://github.com/bryan31/message-demo) | [DEMO2](https://gitee.com/bryan31/liteflow-example)
|
||||
|
||||
LiteFlow has more than 1000 test cases in the source code, including most scenarios, you can see the test cases in the source code.
|
||||
|
||||
## Feature
|
||||
* **Component definition unified:** All logic is a component, for all logic to provide a unified component implementation, small size, large energy.
|
||||
* **Rules lightweight:** based on the rules file to arrange the process, learning the rules entry only takes 5 minutes, a read both understand.
|
||||
|
@ -55,7 +53,7 @@ These processes can be easily solved with LiteFlow! The framework has a very low
|
|||
|
||||
LiteFlow has an extremely detailed and easy-to-understand documentation, it can help you solve more than 95% of your problems when using the framework.
|
||||
|
||||
Right now LiteFlow has 658 test cases and more. Complete documentation and comprehensive test case coverage guarantee the stability of LiteFlow framework!
|
||||
LiteFlow has 658 test cases and more. Complete documentation and comprehensive test case coverage guarantee the stability of LiteFlow framework!
|
||||
|
||||
Looking forward to your use!
|
||||
|
||||
|
@ -67,7 +65,7 @@ Discord Link: [https://discord.gg/MpdBSBnFTu](https://discord.gg/MpdBSBnFTu)
|
|||
|
||||
Since the community group is over 200 people, you need to be invited to join the group. Follow the WECHAT OFFICIAL ACCOUNT and click `Personal WeChat` to add me, I can invite you into the group
|
||||
|
||||

|
||||

|
||||
|
||||
Open source is not easy, please sponsor LiteFlow if you support it
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
|
||||
<h3>您的star是我继续前进的动力,如果喜欢LiteFlow请右上角帮忙点个star</h3>
|
||||
|
||||
## 概述
|
||||
## 🌈概述
|
||||
LiteFlow是一个轻量且强大的国产规则引擎框架,可用于复杂的组件化业务的编排领域,独有的DSL规则驱动整个复杂业务,并可实现平滑刷新热部署,支持多种脚本语言规则的嵌入。帮助系统变得更加丝滑且灵活。
|
||||
|
||||
LiteFlow于2020年正式开源,2021年获得开源中国年度最受欢迎开源软件殊荣。于2022年获得Gitee最有价值开源项目(GVP)荣誉。是一个正处在高速发展中的开源项目。
|
||||
|
||||
LiteFlow是一个由社区驱动的项目,我们非常重视社区建设,拥有一个800多人的使用者社区,在使用中碰到任何问题或者建议都可以在社区中反应。
|
||||
LiteFlow是一个由社区驱动的项目,我们非常重视社区建设,拥有一个1800多人的使用者社区,在使用中碰到任何问题或者建议都可以在社区中反应。
|
||||
|
||||
你在官网中可以找到加入社区的方式!
|
||||
|
||||
|
@ -19,18 +19,17 @@ LiteFlow是一个由社区驱动的项目,我们非常重视社区建设,拥
|
|||
## 文档链接:[点这里进入文档进行学习](https://liteflow.yomahub.com/pages/5816c5/)
|
||||
## 示例工程:[DEMO1](https://github.com/bryan31/message-demo) | [DEMO2](https://gitee.com/bryan31/liteflow-example)
|
||||
|
||||
**同时LiteFlow的源码中拥有超过1000个的测试用例,包含了大部分的场景,在源码中可以看到测试用例**
|
||||
|
||||
## 特性
|
||||
## 🍬特性
|
||||
* **组件定义统一:** 所有的逻辑都是组件,为所有的逻辑提供统一化的组件实现方式,小身材,大能量。
|
||||
* **规则轻量:** 基于规则文件来编排流程,学习规则入门只需要5分钟,一看既懂。
|
||||
* **规则多样化:** 规则支持xml、json、yml三种规则文件写法方式,喜欢哪种用哪个。
|
||||
* **任意编排:** 再复杂的逻辑过程,利用LiteFlow的规则,都是很容易做到的,看规则文件就能知道逻辑是如何运转的。
|
||||
* **规则持久化:** 框架原生支持把规则存储在标准结构化数据库,Nacos,Etcd,Zookeeper。您也可以自己扩展,把规则存储在任何地方。
|
||||
* **规则持久化:** 框架原生支持把规则存储在标准结构化数据库,Nacos,Etcd,Zookeeper,Apollo。您也可以自己扩展,把规则存储在任何地方。
|
||||
* **优雅热刷新机制:** 规则变化,无需重启您的应用,即时改变应用的规则。高并发下不会因为刷新规则导致正在执行的规则有任何错乱。
|
||||
* **支持广泛:** 不管你的项目是不是基于Springboot,Spring还是任何其他java框架构建,LiteFlow都能游刃有余。
|
||||
* **JDK支持:** 从JDK8到JDK17,统统支持。无需担心JDK版本。
|
||||
* **脚本语言支持:** 可以定义脚本语言节点,支持QLExpress和Groovy两种脚本。未来还会支持更多的脚本语言。
|
||||
* **脚本语言支持:** 可以定义脚本语言节点,支持Groovy,Javascript,QLExpress,Python,Lua。未来还会支持更多的脚本语言。
|
||||
* **脚本和Java全打通:** 所有脚本语言均可调用Java方法,甚至于可以引用任意的实例,在脚本中调用RPC也是支持的。
|
||||
* **规则嵌套支持:** 只要你想的出,你可以利用简单的表达式完成多重嵌套的复杂逻辑编排。
|
||||
* **组件重试支持:** 组件可以支持重试,每个组件均可自定义重试配置和指定异常。
|
||||
* **上下文隔离机制:** 可靠的上下文隔离机制,你无需担心高并发情况下的数据串流。
|
||||
|
@ -40,7 +39,7 @@ LiteFlow是一个由社区驱动的项目,我们非常重视社区建设,拥
|
|||
* **性能卓越:** 框架本身几乎不消耗额外性能,性能取决你的组件执行效率。
|
||||
* **自带简单监控:** 框架内自带一个命令行的监控,能够知道每个组件的运行耗时排行。
|
||||
|
||||
## 什么场景适用
|
||||
## ☘️什么场景适用
|
||||
|
||||
LiteFlow是一款编排式的规则引擎,最擅长去解耦你的系统,如果你的系统业务复杂,并且代码臃肿不堪,那LiteFlow框架会是一个非常好的解决方案。
|
||||
|
||||
|
@ -53,7 +52,7 @@ LiteFlow利用规则表达式为驱动引擎,去驱动你定义的组件。你
|
|||
|
||||
LiteFlow拥有极其详细易懂的文档体系,能帮助你解决在使用框架的时候95%以上的问题。
|
||||
|
||||
目前为止,LiteFlow拥有658个测试用例,并且不断在增加中。完备的文档+覆盖全面的测试用例保障了LiteFlow框架的稳定性!
|
||||
目前为止,LiteFlow拥有800多个测试用例,并且不断在增加中。完备的文档+覆盖全面的测试用例保障了LiteFlow框架的稳定性!
|
||||
|
||||
LiteFlow期待你的了解!
|
||||
|
||||
|
|
|
@ -46,5 +46,9 @@
|
|||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>QLExpress</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package com.yomahub.liteflow.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
|
|
|
@ -3,7 +3,9 @@ package com.yomahub.liteflow.annotation;
|
|||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
|
|
|
@ -5,6 +5,9 @@ import com.yomahub.liteflow.enums.NodeTypeEnum;
|
|||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
|
@ -13,8 +16,11 @@ public @interface LiteflowMethod {
|
|||
|
||||
LiteFlowMethodEnum value();
|
||||
|
||||
// 节点ID,用于区分节点
|
||||
// 默认为空 则按照Spring模式下BeanName为准。
|
||||
/**
|
||||
* 节点ID,用于区分节点
|
||||
* 默认为空 则按照Spring模式下BeanName为准。
|
||||
* @return
|
||||
*/
|
||||
String nodeId() default "";
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,7 +11,10 @@ import java.lang.reflect.AnnotatedElement;
|
|||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 注解工具类
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class AnnoUtil {
|
||||
|
||||
public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
|
@ -41,7 +44,7 @@ public class AnnoUtil {
|
|||
return annotation;
|
||||
}
|
||||
|
||||
public static <A extends Annotation> Object getDefaultValue(Class<A> annotationType, String property){
|
||||
private static <A extends Annotation> Object getDefaultValue(Class<A> annotationType, String property){
|
||||
try{
|
||||
return annotationType.getMethod(property).getDefaultValue();
|
||||
}catch (Exception e){
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/10/22
|
||||
|
@ -16,7 +17,17 @@ import com.yomahub.liteflow.slot.Slot;
|
|||
*/
|
||||
public interface ICmpAroundAspect {
|
||||
|
||||
/**
|
||||
* 前置处理
|
||||
* @param nodeId 节点ID
|
||||
* @param slot
|
||||
*/
|
||||
void beforeProcess(String nodeId, Slot slot);
|
||||
|
||||
/**
|
||||
* 后置处理
|
||||
* @param nodeId 节点ID
|
||||
* @param slot
|
||||
*/
|
||||
void afterProcess(String nodeId, Slot slot);
|
||||
}
|
||||
|
|
|
@ -1,115 +0,0 @@
|
|||
package com.yomahub.liteflow.builder;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.enums.ConditionTypeEnum;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.condition.Condition;
|
||||
import com.yomahub.liteflow.flow.element.condition.ThenCondition;
|
||||
import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Chain基于代码形式的组装器
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.8
|
||||
*/
|
||||
public class LiteFlowChainBuilder {
|
||||
|
||||
private Chain chain;
|
||||
|
||||
//这是主体的Condition,不包含前置和后置
|
||||
//声明这个变量,而不是用chain.getConditionList的目的,是为了辅助平滑加载
|
||||
//虽然FlowBus里面的map都是CopyOnWrite类型的,但是在buildCondition的时候,为了平滑加载,所以不能事先把chain.getConditionList给设为空List
|
||||
//所以在这里做一个缓存,等conditionList全部build完毕后,再去一次性替换chain里面的conditionList
|
||||
private final List<Condition> conditionList;
|
||||
|
||||
//前置处理Condition,用来区别主体的Condition
|
||||
private final List<Condition> preConditionList;
|
||||
|
||||
//后置处理Condition,用来区别主体的Condition
|
||||
private final List<Condition> finallyConditionList;
|
||||
|
||||
public static LiteFlowChainBuilder createChain() {
|
||||
return new LiteFlowChainBuilder();
|
||||
}
|
||||
|
||||
public LiteFlowChainBuilder() {
|
||||
chain = new Chain();
|
||||
conditionList = new ArrayList<>();
|
||||
preConditionList = new ArrayList<>();
|
||||
finallyConditionList = new ArrayList<>();
|
||||
}
|
||||
|
||||
//在parser中chain的build是2段式的,因为涉及到依赖问题,以前是递归parser
|
||||
//2.6.8之后取消了递归的模式,两段式组装,先把带有chainName的chain对象放进去,第二段再组装chain里面的condition
|
||||
//所以这里setChainName的时候需要判断下
|
||||
public LiteFlowChainBuilder setChainName(String chainName) {
|
||||
if (FlowBus.containChain(chainName)) {
|
||||
this.chain = FlowBus.getChain(chainName);
|
||||
} else {
|
||||
this.chain.setChainName(chainName);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiteFlowChainBuilder setCondition(Condition condition) {
|
||||
//这里把condition组装进conditionList,
|
||||
buildConditions(condition);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void build() {
|
||||
this.chain.setConditionList(this.conditionList);
|
||||
this.chain.setPreConditionList(this.preConditionList);
|
||||
this.chain.setFinallyConditionList(this.finallyConditionList);
|
||||
|
||||
checkBuild();
|
||||
|
||||
FlowBus.addChain(this.chain);
|
||||
}
|
||||
|
||||
/**
|
||||
* build 前简单校验
|
||||
*/
|
||||
private void checkBuild() {
|
||||
List<String> errorList = new ArrayList<>();
|
||||
if (StrUtil.isBlank(this.chain.getChainName())) {
|
||||
errorList.add("name is blank");
|
||||
}
|
||||
if (CollUtil.isNotEmpty(errorList)) {
|
||||
throw new RuntimeException(CollUtil.join(errorList, ",", "[", "]"));
|
||||
}
|
||||
}
|
||||
|
||||
private void buildConditions(Condition condition) {
|
||||
//这里进行合并逻辑
|
||||
//对于then来说,相邻的2个then会合并成一个condition
|
||||
//对于when来说,相同组的when会合并成一个condition,不同组的when还是会拆开
|
||||
if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_PRE)) {
|
||||
this.preConditionList.add(condition);
|
||||
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY)) {
|
||||
this.finallyConditionList.add(condition);
|
||||
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_THEN)) {
|
||||
if (this.conditionList.size() >= 1 &&
|
||||
CollectionUtil.getLast(this.conditionList) instanceof ThenCondition) {
|
||||
CollectionUtil.getLast(this.conditionList).getExecutableList().addAll(condition.getExecutableList());
|
||||
} else {
|
||||
this.conditionList.add(condition);
|
||||
}
|
||||
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_WHEN)) {
|
||||
if (this.conditionList.size() >= 1 &&
|
||||
CollectionUtil.getLast(this.conditionList) instanceof WhenCondition &&
|
||||
((WhenCondition)CollectionUtil.getLast(this.conditionList)).getGroup().equals(((WhenCondition)condition).getGroup())) {
|
||||
CollectionUtil.getLast(this.conditionList).getExecutableList().addAll(condition.getExecutableList());
|
||||
} else {
|
||||
this.conditionList.add(condition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,8 +11,13 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class LiteFlowNodeBuilder {
|
||||
|
||||
|
@ -132,33 +137,16 @@ public class LiteFlowNodeBuilder {
|
|||
public void build() {
|
||||
checkBuild();
|
||||
try {
|
||||
if (this.node.getType().equals(NodeTypeEnum.COMMON)) {
|
||||
FlowBus.addCommonNode(this.node.getId(), this.node.getName(), this.node.getClazz());
|
||||
} else if (this.node.getType().equals(NodeTypeEnum.SWITCH)) {
|
||||
FlowBus.addSwitchNode(this.node.getId(), this.node.getName(), this.node.getClazz());
|
||||
} else if (this.node.getType().equals(NodeTypeEnum.IF)) {
|
||||
FlowBus.addIfNode(this.node.getId(), this.node.getName(), this.node.getClazz());
|
||||
} else if (this.node.getType().equals(NodeTypeEnum.FOR)) {
|
||||
FlowBus.addForNode(this.node.getId(), this.node.getName(), this.node.getClazz());
|
||||
} else if (this.node.getType().equals(NodeTypeEnum.WHILE)) {
|
||||
FlowBus.addWhileNode(this.node.getId(), this.node.getName(), this.node.getClazz());
|
||||
} else if (this.node.getType().equals(NodeTypeEnum.BREAK)) {
|
||||
FlowBus.addBreakNode(this.node.getId(), this.node.getName(), this.node.getClazz());
|
||||
} else if (this.node.getType().equals(NodeTypeEnum.SCRIPT)) {
|
||||
FlowBus.addCommonScriptNode(this.node.getId(), this.node.getName(), this.node.getScript());
|
||||
} else if (this.node.getType().equals(NodeTypeEnum.SWITCH_SCRIPT)) {
|
||||
FlowBus.addSwitchScriptNode(this.node.getId(), this.node.getName(), this.node.getScript());
|
||||
} else if (this.node.getType().equals(NodeTypeEnum.IF_SCRIPT)) {
|
||||
FlowBus.addIfScriptNode(this.node.getId(), this.node.getName(), this.node.getScript());
|
||||
} else if (this.node.getType().equals(NodeTypeEnum.FOR_SCRIPT)) {
|
||||
FlowBus.addForScriptNode(this.node.getId(), this.node.getName(), this.node.getScript());
|
||||
} else if (this.node.getType().equals(NodeTypeEnum.WHILE_SCRIPT)) {
|
||||
FlowBus.addWhileScriptNode(this.node.getId(), this.node.getName(), this.node.getScript());
|
||||
} else if (this.node.getType().equals(NodeTypeEnum.BREAK_SCRIPT)) {
|
||||
FlowBus.addBreakScriptNode(this.node.getId(), this.node.getName(), this.node.getScript());
|
||||
}
|
||||
// 用于处理脚本 node
|
||||
if (this.node.getType().isScript()){
|
||||
FlowBus.addScriptNode(this.node.getId(), this.node.getName(), this.node.getType(), this.node.getScript());
|
||||
}
|
||||
// 用于处理普通 node
|
||||
else{
|
||||
FlowBus.addNode(this.node.getId(), this.node.getName(), this.node.getType(), this.node.getClazz());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String errMsg = StrUtil.format("An exception occurred while building the node[{}],{}", this.node.getId(),e.getMessage());
|
||||
String errMsg = StrUtil.format("An exception occurred while building the node[{}],{}", this.node.getId(), e.getMessage());
|
||||
LOG.error(errMsg, e);
|
||||
throw new NodeBuildException(errMsg);
|
||||
}
|
||||
|
|
|
@ -6,19 +6,19 @@ import com.ql.util.express.DefaultContext;
|
|||
import com.ql.util.express.ExpressRunner;
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.*;
|
||||
import com.yomahub.liteflow.common.ChainConstant;
|
||||
import com.yomahub.liteflow.exception.DataNofFoundException;
|
||||
import com.yomahub.liteflow.exception.ELParseException;
|
||||
import com.yomahub.liteflow.exception.FlowSystemException;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.condition.*;
|
||||
import com.yomahub.liteflow.script.ScriptBeanManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Chain基于代码形式的组装器
|
||||
|
@ -29,47 +29,49 @@ import java.util.function.BiConsumer;
|
|||
*/
|
||||
public class LiteFlowChainELBuilder {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LiteFlowChainELBuilder.class);
|
||||
|
||||
|
||||
private Chain chain;
|
||||
|
||||
//这是主体的Condition,不包含前置和后置
|
||||
//声明这个变量,而不是用chain.getConditionList的目的,是为了辅助平滑加载
|
||||
//虽然FlowBus里面的map都是CopyOnWrite类型的,但是在buildCondition的时候,为了平滑加载,所以不能事先把chain.getConditionList给设为空List
|
||||
//所以在这里做一个缓存,等conditionList全部build完毕后,再去一次性替换chain里面的conditionList
|
||||
/**
|
||||
* //这是主体的Condition
|
||||
* //声明这个变量,而不是用chain.getConditionList的目的,是为了辅助平滑加载
|
||||
* //虽然FlowBus里面的map都是CopyOnWrite类型的,但是在buildCondition的时候,为了平滑加载,所以不能事先把chain.getConditionList给设为空List
|
||||
* //所以在这里做一个缓存,等conditionList全部build完毕后,再去一次性替换chain里面的conditionList
|
||||
*/
|
||||
private final List<Condition> conditionList;
|
||||
|
||||
//前置处理Condition,用来区别主体的Condition
|
||||
private final List<Condition> preConditionList;
|
||||
|
||||
//后置处理Condition,用来区别主体的Condition
|
||||
private final List<Condition> finallyConditionList;
|
||||
|
||||
//EL解析引擎
|
||||
private final static ExpressRunner EXPRESS_RUNNER = new ExpressRunner();
|
||||
/**
|
||||
* EL解析引擎
|
||||
*/
|
||||
public final static ExpressRunner EXPRESS_RUNNER = new ExpressRunner();
|
||||
|
||||
static {
|
||||
//初始化QLExpress的Runner
|
||||
EXPRESS_RUNNER.addFunction("THEN", new ThenOperator());
|
||||
EXPRESS_RUNNER.addFunction("WHEN", new WhenOperator());
|
||||
EXPRESS_RUNNER.addFunction("SWITCH", new SwitchOperator());
|
||||
EXPRESS_RUNNER.addFunction("PRE", new PreOperator());
|
||||
EXPRESS_RUNNER.addFunction("FINALLY", new FinallyOperator());
|
||||
EXPRESS_RUNNER.addFunction("IF", new IfOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("ELSE", Object.class, new ElseOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("ELIF", Object.class, new ElifOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("TO", Object.class, new ToOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("to", Object.class, new ToOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("tag", Object.class, new TagOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("any", Object.class, new AnyOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("id", Object.class, new IdOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("ignoreError", Object.class, new IgnoreErrorOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("threadPool", Object.class, new ThreadPoolOperator());
|
||||
EXPRESS_RUNNER.addFunction("NODE", new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction("node", new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction("FOR", new ForOperator());
|
||||
EXPRESS_RUNNER.addFunction("WHILE", new WhileOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("DO", Object.class, new DoOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("BREAK", Object.class, new BreakOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod("data", Object.class, new DataOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.THEN, new ThenOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.WHEN, new WhenOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.SWITCH, new SwitchOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.PRE, new PreOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.FINALLY, new FinallyOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.IF, new IfOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELSE, Object.class, new ElseOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELIF, Object.class, new ElifOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO, Object.class, new ToOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO.toLowerCase(), Object.class, new ToOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DEFAULT, Object.class, new DefaultOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TAG, Object.class, new TagOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ANY, Object.class, new AnyOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ID, Object.class, new IdOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.IGNORE_ERROR, Object.class, new IgnoreErrorOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.THREAD_POOL, Object.class, new ThreadPoolOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NODE.toUpperCase(), new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NODE, new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.FOR, new ForOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.WHILE, new WhileOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DO, Object.class, new DoOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BREAK, Object.class, new BreakOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DATA, Object.class, new DataOperator());
|
||||
}
|
||||
|
||||
public static LiteFlowChainELBuilder createChain() {
|
||||
|
@ -79,13 +81,16 @@ public class LiteFlowChainELBuilder {
|
|||
public LiteFlowChainELBuilder() {
|
||||
chain = new Chain();
|
||||
conditionList = new ArrayList<>();
|
||||
preConditionList = new ArrayList<>();
|
||||
finallyConditionList = new ArrayList<>();
|
||||
}
|
||||
|
||||
//在parser中chain的build是2段式的,因为涉及到依赖问题,以前是递归parser
|
||||
//2.6.8之后取消了递归的模式,两段式组装,先把带有chainName的chain对象放进去,第二段再组装chain里面的condition
|
||||
//所以这里setChainName的时候需要判断下
|
||||
|
||||
/**
|
||||
* @return LiteFlowChainELBuilder
|
||||
* @deprecated 请使用 {@link #setChainId(String)}
|
||||
*/
|
||||
public LiteFlowChainELBuilder setChainName(String chainName) {
|
||||
if (FlowBus.containChain(chainName)) {
|
||||
this.chain = FlowBus.getChain(chainName);
|
||||
|
@ -95,9 +100,18 @@ public class LiteFlowChainELBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public LiteFlowChainELBuilder setChainId(String chainId) {
|
||||
if (FlowBus.containChain(chainId)) {
|
||||
this.chain = FlowBus.getChain(chainId);
|
||||
} else {
|
||||
this.chain.setChainId(chainId);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiteFlowChainELBuilder setEL(String elStr) {
|
||||
if (StrUtil.isBlank(elStr)) {
|
||||
String errMsg = StrUtil.format("no conditionList in this chain[{}]", chain.getChainName());
|
||||
String errMsg = StrUtil.format("no content in this chain[{}]", chain.getChainId());
|
||||
throw new FlowSystemException(errMsg);
|
||||
}
|
||||
|
||||
|
@ -107,11 +121,14 @@ public class LiteFlowChainELBuilder {
|
|||
|
||||
//这里一定要先放chain,再放node,因为node优先于chain,所以当重名时,node会覆盖掉chain
|
||||
//往上下文里放入所有的chain,是的el表达式可以直接引用到chain
|
||||
FlowBus.getChainMap().values().forEach(chain -> context.put(chain.getChainName(), chain));
|
||||
FlowBus.getChainMap().values().forEach(chain -> context.put(chain.getChainId(), chain));
|
||||
|
||||
//往上下文里放入所有的node,使得el表达式可以直接引用到nodeId
|
||||
FlowBus.getNodeMap().keySet().forEach(nodeId -> context.put(nodeId, FlowBus.getNode(nodeId)));
|
||||
|
||||
//放入当前主chain的ID
|
||||
context.put(ChainConstant.CURR_CHAIN_ID, this.chain.getChainId());
|
||||
|
||||
//解析el成为一个Condition
|
||||
//为什么这里只是一个Condition,而不是一个List<Condition>呢
|
||||
//这里无论多复杂的,外面必定有一个最外层的Condition,所以这里只有一个,内部可以嵌套很多层,这点和以前的不太一样
|
||||
|
@ -121,13 +138,13 @@ public class LiteFlowChainELBuilder {
|
|||
//为什么只寻找第一层,而不往下寻找了呢?
|
||||
//因为这是一个规范,如果在后面的层级中出现pre和finally,语义上也不好理解,所以pre和finally只能定义在第一层
|
||||
//如果硬是要在后面定义,则执行的时候会忽略,相关代码已做了判断
|
||||
for (Executable executable : condition.getExecutableList()) {
|
||||
/*for (Executable executable : condition.getExecutableList()) {
|
||||
if (executable instanceof PreCondition) {
|
||||
this.preConditionList.add((PreCondition) executable);
|
||||
} else if (executable instanceof FinallyCondition) {
|
||||
this.finallyConditionList.add((FinallyCondition) executable);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
//把主要的condition加入
|
||||
this.conditionList.add(condition);
|
||||
|
@ -143,10 +160,23 @@ public class LiteFlowChainELBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EL表达式校验
|
||||
* @param elStr EL表达式
|
||||
* @return true 校验成功 false 校验失败
|
||||
*/
|
||||
public static boolean validate(String elStr) {
|
||||
try {
|
||||
LiteFlowChainELBuilder.createChain().setEL(elStr);
|
||||
return Boolean.TRUE;
|
||||
} catch (ELParseException e) {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
public void build() {
|
||||
this.chain.setConditionList(this.conditionList);
|
||||
this.chain.setPreConditionList(this.preConditionList);
|
||||
this.chain.setFinallyConditionList(this.finallyConditionList);
|
||||
|
||||
checkBuild();
|
||||
|
||||
|
@ -158,7 +188,7 @@ public class LiteFlowChainELBuilder {
|
|||
*/
|
||||
private void checkBuild() {
|
||||
List<String> errorList = new ArrayList<>();
|
||||
if (StrUtil.isBlank(this.chain.getChainName())) {
|
||||
if (StrUtil.isBlank(this.chain.getChainId())) {
|
||||
errorList.add("name is blank");
|
||||
}
|
||||
if (CollUtil.isNotEmpty(errorList)) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
||||
|
@ -13,14 +12,14 @@ import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
|||
*/
|
||||
public class AnyOperator extends BaseOperator<WhenCondition> {
|
||||
|
||||
@Override
|
||||
public WhenCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
@Override
|
||||
public WhenCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
WhenCondition whenCondition = OperatorHelper.convert(objects[0], WhenCondition.class);
|
||||
WhenCondition whenCondition = OperatorHelper.convert(objects[0], WhenCondition.class);
|
||||
|
||||
Boolean any = OperatorHelper.convert(objects[1], Boolean.class);
|
||||
whenCondition.setAny(any);
|
||||
return whenCondition;
|
||||
}
|
||||
Boolean any = OperatorHelper.convert(objects[1], Boolean.class);
|
||||
whenCondition.setAny(any);
|
||||
return whenCondition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,7 @@ import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
|||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
import com.yomahub.liteflow.flow.element.condition.Condition;
|
||||
import com.yomahub.liteflow.flow.element.condition.ForCondition;
|
||||
import com.yomahub.liteflow.flow.element.condition.LoopCondition;
|
||||
import com.yomahub.liteflow.flow.element.condition.WhileCondition;
|
||||
|
||||
/**
|
||||
* EL规则中的BREAK的操作符
|
||||
|
@ -31,9 +28,9 @@ public class BreakOperator extends BaseOperator<LoopCondition> {
|
|||
|
||||
//获得需要执行的可执行表达式
|
||||
Node breakNode = OperatorHelper.convert(objects[1], Node.class);
|
||||
if (ListUtil.toList(NodeTypeEnum.BREAK, NodeTypeEnum.BREAK_SCRIPT).contains(breakNode.getType())){
|
||||
if (ListUtil.toList(NodeTypeEnum.BREAK, NodeTypeEnum.BREAK_SCRIPT).contains(breakNode.getType())) {
|
||||
condition.setBreakNode(breakNode);
|
||||
}else{
|
||||
} else {
|
||||
throw new QLException("The parameter must be node-break item");
|
||||
}
|
||||
return condition;
|
||||
|
|
|
@ -12,16 +12,16 @@ import com.yomahub.liteflow.flow.element.Node;
|
|||
*/
|
||||
public class DataOperator extends BaseOperator<Node> {
|
||||
|
||||
@Override
|
||||
public Node build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
@Override
|
||||
public Node build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
Node node = OperatorHelper.convert(objects[0], Node.class);
|
||||
Node node = OperatorHelper.convert(objects[0], Node.class);
|
||||
|
||||
String cmpData = OperatorHelper.convert(objects[1], String.class);
|
||||
String cmpData = OperatorHelper.convert(objects[1], String.class);
|
||||
|
||||
node.setCmpData(cmpData);
|
||||
node.setCmpData(cmpData);
|
||||
|
||||
return node;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.condition.SwitchCondition;
|
||||
|
||||
/**
|
||||
* EL规则中的default的操作符,用法须和SWITCH联合使用
|
||||
*
|
||||
* @author Tingliang Wang
|
||||
* @since 2.9.5
|
||||
*/
|
||||
public class DefaultOperator extends BaseOperator<SwitchCondition> {
|
||||
|
||||
@Override
|
||||
public SwitchCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
SwitchCondition switchCondition = OperatorHelper.convert(objects[0], SwitchCondition.class);
|
||||
|
||||
Executable target = OperatorHelper.convert(objects[1], Executable.class);
|
||||
switchCondition.setDefaultExecutor(target);
|
||||
|
||||
return switchCondition;
|
||||
}
|
||||
}
|
|
@ -1,14 +1,10 @@
|
|||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.condition.Condition;
|
||||
import com.yomahub.liteflow.flow.element.condition.ForCondition;
|
||||
import com.yomahub.liteflow.flow.element.condition.LoopCondition;
|
||||
import com.yomahub.liteflow.flow.element.condition.WhileCondition;
|
||||
|
||||
/**
|
||||
* EL规则中的DO的操作符
|
||||
|
|
|
@ -34,7 +34,7 @@ public class ForOperator extends BaseOperator<ForCondition> {
|
|||
node = new Node();
|
||||
NodeForComponent nodeForComponent = new NodeForComponent() {
|
||||
@Override
|
||||
public int processFor() throws Exception {
|
||||
public int processFor() {
|
||||
return forCount;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.condition.Condition;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* EL规则中的id的操作符,只有condition可加id
|
||||
|
@ -15,18 +12,16 @@ import org.slf4j.LoggerFactory;
|
|||
*/
|
||||
public class IdOperator extends BaseOperator<Condition> {
|
||||
|
||||
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
|
||||
@Override
|
||||
public Condition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
@Override
|
||||
public Condition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
Condition condition = OperatorHelper.convert(objects[0], Condition.class);
|
||||
|
||||
Condition condition = OperatorHelper.convert(objects[0], Condition.class);
|
||||
String id = OperatorHelper.convert(objects[1], String.class);
|
||||
|
||||
String id = OperatorHelper.convert(objects[1], String.class);
|
||||
condition.setId(id);
|
||||
|
||||
condition.setId(id);
|
||||
|
||||
return condition;
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,29 +17,29 @@ import com.yomahub.liteflow.flow.element.condition.IfCondition;
|
|||
*/
|
||||
public class IfOperator extends BaseOperator<IfCondition> {
|
||||
|
||||
@Override
|
||||
public IfCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEq(objects, 2, 3);
|
||||
@Override
|
||||
public IfCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEq(objects, 2, 3);
|
||||
|
||||
//解析第一个参数
|
||||
Node ifNode = OperatorHelper.convert(objects[0], Node.class);
|
||||
if (!ListUtil.toList(NodeTypeEnum.IF, NodeTypeEnum.IF_SCRIPT).contains(ifNode.getType())) {
|
||||
throw new QLException("The first parameter must be If item");
|
||||
}
|
||||
//解析第一个参数
|
||||
Node ifNode = OperatorHelper.convert(objects[0], Node.class);
|
||||
if (!ListUtil.toList(NodeTypeEnum.IF, NodeTypeEnum.IF_SCRIPT).contains(ifNode.getType())) {
|
||||
throw new QLException("The first parameter must be If item");
|
||||
}
|
||||
|
||||
//解析第二个参数
|
||||
Executable trueCaseExecutableItem = OperatorHelper.convert(objects[1], Executable.class);
|
||||
//解析第二个参数
|
||||
Executable trueCaseExecutableItem = OperatorHelper.convert(objects[1], Executable.class);
|
||||
|
||||
//解析第三个参数,如果有的话
|
||||
Executable falseCaseExecutableItem = null;
|
||||
if (objects.length == 3) {
|
||||
falseCaseExecutableItem = OperatorHelper.convert(objects[2], Executable.class);
|
||||
}
|
||||
//解析第三个参数,如果有的话
|
||||
Executable falseCaseExecutableItem = null;
|
||||
if (objects.length == 3) {
|
||||
falseCaseExecutableItem = OperatorHelper.convert(objects[2], Executable.class);
|
||||
}
|
||||
|
||||
IfCondition ifCondition = new IfCondition();
|
||||
ifCondition.setExecutableList(ListUtil.toList(ifNode));
|
||||
ifCondition.setTrueCaseExecutableItem(trueCaseExecutableItem);
|
||||
ifCondition.setFalseCaseExecutableItem(falseCaseExecutableItem);
|
||||
return ifCondition;
|
||||
}
|
||||
IfCondition ifCondition = new IfCondition();
|
||||
ifCondition.setExecutableList(ListUtil.toList(ifNode));
|
||||
ifCondition.setTrueCaseExecutableItem(trueCaseExecutableItem);
|
||||
ifCondition.setFalseCaseExecutableItem(falseCaseExecutableItem);
|
||||
return ifCondition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
|
@ -14,14 +13,14 @@ import com.yomahub.liteflow.flow.element.condition.PreCondition;
|
|||
*/
|
||||
public class PreOperator extends BaseOperator<PreCondition> {
|
||||
|
||||
@Override
|
||||
public PreCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGtZero(objects);
|
||||
@Override
|
||||
public PreCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGtZero(objects);
|
||||
|
||||
PreCondition preCondition = new PreCondition();
|
||||
for (Object obj : objects) {
|
||||
preCondition.addExecutable(OperatorHelper.convert(obj, Executable.class));
|
||||
}
|
||||
return preCondition;
|
||||
}
|
||||
PreCondition preCondition = new PreCondition();
|
||||
for (Object obj : objects) {
|
||||
preCondition.addExecutable(OperatorHelper.convert(obj, Executable.class));
|
||||
}
|
||||
return preCondition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
|
@ -14,14 +13,14 @@ import com.yomahub.liteflow.flow.element.condition.ThenCondition;
|
|||
*/
|
||||
public class ThenOperator extends BaseOperator<ThenCondition> {
|
||||
|
||||
@Override
|
||||
public ThenCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGtZero(objects);
|
||||
@Override
|
||||
public ThenCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGtZero(objects);
|
||||
|
||||
ThenCondition thenCondition = new ThenCondition();
|
||||
for (Object obj : objects) {
|
||||
thenCondition.addExecutable(OperatorHelper.convert(obj, Executable.class));
|
||||
}
|
||||
return thenCondition;
|
||||
}
|
||||
ThenCondition thenCondition = new ThenCondition();
|
||||
for (Object obj : objects) {
|
||||
thenCondition.addExecutable(OperatorHelper.convert(obj, Executable.class));
|
||||
}
|
||||
return thenCondition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
||||
|
@ -13,14 +12,14 @@ import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
|||
*/
|
||||
public class ThreadPoolOperator extends BaseOperator<WhenCondition> {
|
||||
|
||||
@Override
|
||||
public WhenCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
@Override
|
||||
public WhenCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
WhenCondition whenCondition = OperatorHelper.convert(objects[0], WhenCondition.class);
|
||||
WhenCondition whenCondition = OperatorHelper.convert(objects[0], WhenCondition.class);
|
||||
|
||||
whenCondition.setThreadExecutorClass(OperatorHelper.convert(objects[1], String.class));
|
||||
whenCondition.setThreadExecutorClass(OperatorHelper.convert(objects[1], String.class));
|
||||
|
||||
return whenCondition;
|
||||
}
|
||||
return whenCondition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
|
@ -14,16 +13,16 @@ import com.yomahub.liteflow.flow.element.condition.SwitchCondition;
|
|||
*/
|
||||
public class ToOperator extends BaseOperator<SwitchCondition> {
|
||||
|
||||
@Override
|
||||
public SwitchCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGtTwo(objects);
|
||||
@Override
|
||||
public SwitchCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGtTwo(objects);
|
||||
|
||||
SwitchCondition switchCondition = OperatorHelper.convert(objects[0], SwitchCondition.class);
|
||||
SwitchCondition switchCondition = OperatorHelper.convert(objects[0], SwitchCondition.class);
|
||||
|
||||
for (int i = 1; i < objects.length; i++) {
|
||||
Executable target = OperatorHelper.convert(objects[i], Executable.class);
|
||||
switchCondition.addTargetItem(target);
|
||||
}
|
||||
return switchCondition;
|
||||
}
|
||||
for (int i = 1; i < objects.length; i++) {
|
||||
Executable target = OperatorHelper.convert(objects[i], Executable.class);
|
||||
switchCondition.addTargetItem(target);
|
||||
}
|
||||
return switchCondition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
|
|
|
@ -3,13 +3,13 @@ package com.yomahub.liteflow.builder.el.operator.base;
|
|||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.exception.DataNofFoundException;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Operator 常用工具类
|
||||
*
|
||||
* @author gaibu
|
||||
* @since 2.8.6
|
||||
*/
|
||||
|
@ -131,17 +131,16 @@ public class OperatorHelper {
|
|||
* 如果是Node类型的则进行copy
|
||||
*/
|
||||
public static <T> T convert(Object object, Class<T> clazz, String errorMsg) throws QLException {
|
||||
try{
|
||||
try {
|
||||
if (clazz.isAssignableFrom(object.getClass())) {
|
||||
|
||||
if(clazz.equals(Node.class)){
|
||||
if (clazz.equals(Node.class)) {
|
||||
Node node = (Node) object;
|
||||
return (T) node.copy();
|
||||
}else{
|
||||
} else {
|
||||
return (T) object;
|
||||
}
|
||||
}
|
||||
}catch (Exception e){
|
||||
} catch (Exception e) {
|
||||
throw new QLException("An error occurred while copying an object");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
package com.yomahub.liteflow.builder.entity;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 执行器的实体类
|
||||
* </pre>
|
||||
*
|
||||
* @author sikadai
|
||||
* @version 2.6.11
|
||||
* @since 2022/3/13 15:28
|
||||
*/
|
||||
public class ExecutableEntity {
|
||||
private String id;
|
||||
private String tag;
|
||||
private List<ExecutableEntity> nodeCondComponents;
|
||||
|
||||
public ExecutableEntity() {
|
||||
|
||||
}
|
||||
|
||||
public ExecutableEntity(String id, String tag) {
|
||||
this.id = id;
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public ExecutableEntity setId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public ExecutableEntity setTag(String tag) {
|
||||
this.tag = tag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<ExecutableEntity> getNodeCondComponents() {
|
||||
return nodeCondComponents;
|
||||
}
|
||||
|
||||
public ExecutableEntity setNodeCondComponents(List<ExecutableEntity> nodeCondComponents) {
|
||||
this.nodeCondComponents = nodeCondComponents;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ExecutableEntity addNodeCondComponent(ExecutableEntity conditionNodeEntity) {
|
||||
if (CollUtil.isEmpty(this.nodeCondComponents)) {
|
||||
this.nodeCondComponents = new ArrayList<>();
|
||||
}
|
||||
this.nodeCondComponents.add(conditionNodeEntity);
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -25,15 +25,47 @@ public interface ChainConstant {
|
|||
|
||||
String VALUE = "value";
|
||||
|
||||
String ERROR_RESUME = "errorResume";
|
||||
|
||||
String GROUP = "group";
|
||||
|
||||
String ANY = "any";
|
||||
|
||||
String THREAD_EXECUTOR_CLASS = "threadExecutorClass";
|
||||
|
||||
String CONDITION = "condition";
|
||||
|
||||
String TYPE = "type";
|
||||
|
||||
String THEN = "THEN";
|
||||
|
||||
String WHEN = "WHEN";
|
||||
|
||||
String SWITCH = "SWITCH";
|
||||
|
||||
String PRE = "PRE";
|
||||
|
||||
String FINALLY = "FINALLY";
|
||||
|
||||
String IF = "IF";
|
||||
|
||||
String ELSE = "ELSE";
|
||||
|
||||
String ELIF = "ELIF";
|
||||
|
||||
String TO = "TO";
|
||||
|
||||
String TAG = "tag";
|
||||
|
||||
String IGNORE_ERROR = "ignoreError";
|
||||
|
||||
String THREAD_POOL = "threadPool";
|
||||
|
||||
String WHILE = "WHILE";
|
||||
|
||||
String FOR = "FOR";
|
||||
|
||||
String DO = "DO";
|
||||
|
||||
String BREAK = "BREAK";
|
||||
|
||||
String DATA = "data";
|
||||
|
||||
String MONITOR_BUS = "monitorBus";
|
||||
|
||||
String CURR_CHAIN_ID = "currChainId";
|
||||
|
||||
String DEFAULT = "DEFAULT";
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.yomahub.liteflow.common;
|
||||
|
||||
/**
|
||||
* @author Yun
|
||||
*/
|
||||
public class LocalDefaultFlowConstant {
|
||||
public static final String DEFAULT="default";
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package com.yomahub.liteflow.core;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowRetry;
|
||||
import com.yomahub.liteflow.annotation.util.AnnoUtil;
|
||||
import com.yomahub.liteflow.flow.executor.NodeExecutor;
|
||||
import com.yomahub.liteflow.common.ChainConstant;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.flow.executor.NodeExecutor;
|
||||
import com.yomahub.liteflow.monitor.MonitorBus;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
|
@ -15,6 +15,7 @@ import com.yomahub.liteflow.spi.holder.LiteflowComponentSupportHolder;
|
|||
|
||||
/**
|
||||
* 组件初始化器
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.0
|
||||
*/
|
||||
|
@ -22,38 +23,40 @@ public class ComponentInitializer {
|
|||
|
||||
private static ComponentInitializer instance;
|
||||
|
||||
public static ComponentInitializer loadInstance(){
|
||||
if (ObjectUtil.isNull(instance)){
|
||||
public static ComponentInitializer loadInstance() {
|
||||
if (ObjectUtil.isNull(instance)) {
|
||||
instance = new ComponentInitializer();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public NodeComponent initComponent(NodeComponent nodeComponent, NodeTypeEnum type, String name, String nodeId){
|
||||
public NodeComponent initComponent(NodeComponent nodeComponent, NodeTypeEnum type, String name, String nodeId) {
|
||||
nodeComponent.setNodeId(nodeId);
|
||||
nodeComponent.setSelf(nodeComponent);
|
||||
nodeComponent.setType(type);
|
||||
|
||||
//设置MonitorBus,如果没有就不注入
|
||||
MonitorBus monitorBus = ContextAwareHolder.loadContextAware().getBean(MonitorBus.class);
|
||||
if(ObjectUtil.isNotNull(monitorBus)){
|
||||
nodeComponent.setMonitorBus(monitorBus);
|
||||
if (ContextAwareHolder.loadContextAware().hasBean(ChainConstant.MONITOR_BUS)) {
|
||||
MonitorBus monitorBus = ContextAwareHolder.loadContextAware().getBean(MonitorBus.class);
|
||||
if (ObjectUtil.isNotNull(monitorBus)) {
|
||||
nodeComponent.setMonitorBus(monitorBus);
|
||||
}
|
||||
}
|
||||
|
||||
//先取传进来的name值(配置文件中配置的),再看有没有配置@LiteflowComponent标注
|
||||
//@LiteflowComponent标注只在spring体系下生效,这里用了spi机制取到相应环境下的实现类
|
||||
nodeComponent.setName(name);
|
||||
if (!type.isScript() && StrUtil.isBlank(nodeComponent.getName())){
|
||||
if (!type.isScript() && StrUtil.isBlank(nodeComponent.getName())) {
|
||||
nodeComponent.setName(LiteflowComponentSupportHolder.loadLiteflowComponentSupport().getCmpName(nodeComponent));
|
||||
}
|
||||
|
||||
//先从组件上取@RetryCount标注,如果没有,则看全局配置,全局配置如果不配置的话,默认是0
|
||||
//默认retryForExceptions为Exception.class
|
||||
LiteflowRetry liteflowRetryAnnotation = AnnoUtil.getAnnotation(nodeComponent.getClass(), LiteflowRetry.class);
|
||||
LiteflowRetry liteFlowRetryAnnotation = AnnoUtil.getAnnotation(nodeComponent.getClass(), LiteflowRetry.class);
|
||||
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
|
||||
if (liteflowRetryAnnotation != null) {
|
||||
nodeComponent.setRetryCount(liteflowRetryAnnotation.retry());
|
||||
nodeComponent.setRetryForExceptions(liteflowRetryAnnotation.forExceptions());
|
||||
if (liteFlowRetryAnnotation != null) {
|
||||
nodeComponent.setRetryCount(liteFlowRetryAnnotation.retry());
|
||||
nodeComponent.setRetryForExceptions(liteFlowRetryAnnotation.forExceptions());
|
||||
} else {
|
||||
nodeComponent.setRetryCount(liteflowConfig.getRetryCount());
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public class FlowExecutor {
|
|||
//设置FlowExecutor的Holder,虽然大部分地方都可以通过Spring上下文获取到,但放入Holder,还是为了某些地方能方便的取到
|
||||
FlowExecutorHolder.setHolder(this);
|
||||
if (BooleanUtil.isTrue(liteflowConfig.isParseOnStart())) {
|
||||
this.init();
|
||||
this.init(true);
|
||||
}
|
||||
//初始化DataBus
|
||||
DataBus.init();
|
||||
|
@ -69,7 +69,7 @@ public class FlowExecutor {
|
|||
/**
|
||||
* FlowExecutor的初始化化方式,主要用于parse规则文件
|
||||
*/
|
||||
public void init() {
|
||||
public void init(boolean hook) {
|
||||
if (ObjectUtil.isNull(liteflowConfig)) {
|
||||
throw new ConfigErrorException("config error, please check liteflow config property");
|
||||
}
|
||||
|
@ -161,12 +161,23 @@ public class FlowExecutor {
|
|||
throw new FlowExecutorNotInitException(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
//如果是ruleSource方式的,最后判断下有没有解析出来,如果没有解析出来则报错
|
||||
if (FlowBus.getChainMap().isEmpty()){
|
||||
String errMsg = StrUtil.format("no valid rule config found in rule path [{}]", liteflowConfig.getRuleSource());
|
||||
throw new ConfigErrorException(errMsg);
|
||||
}
|
||||
|
||||
//执行钩子
|
||||
if(hook){
|
||||
FlowInitHook.executeHook();
|
||||
}
|
||||
}
|
||||
|
||||
//此方法就是从原有的配置源主动拉取新的进行刷新
|
||||
//和FlowBus.refreshFlowMetaData的区别就是一个为主动拉取,一个为被动监听到新的内容进行刷新
|
||||
public void reloadRule() {
|
||||
init();
|
||||
init(false);
|
||||
}
|
||||
|
||||
//隐式流程的调用方法
|
||||
|
@ -265,7 +276,7 @@ public class FlowExecutor {
|
|||
Integer slotIndex,
|
||||
InnerChainTypeEnum innerChainType) {
|
||||
if (FlowBus.needInit()) {
|
||||
init();
|
||||
init(true);
|
||||
}
|
||||
|
||||
//如果不是隐式流程,那么需要分配Slot
|
||||
|
|
|
@ -4,6 +4,9 @@ import cn.hutool.core.util.ObjectUtil;
|
|||
import com.yomahub.liteflow.exception.FlowExecutorNotInitException;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
|
||||
/**
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class FlowExecutorHolder {
|
||||
|
||||
private static FlowExecutor flowExecutor;
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package com.yomahub.liteflow.core;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
* 流程初始化的钩子类,所有的钩子都放在这里
|
||||
* 目前钩子主要是放一些第三方中间件的规则监听
|
||||
* 放的钩子要求都是无入参无返回的,所以这里是BooleanSupplier
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.9.4
|
||||
*/
|
||||
public class FlowInitHook {
|
||||
|
||||
private static final List<BooleanSupplier> supplierList = new ArrayList<>();
|
||||
|
||||
public static void executeHook(){
|
||||
if (CollUtil.isNotEmpty(supplierList)){
|
||||
supplierList.forEach(BooleanSupplier::getAsBoolean);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addHook(BooleanSupplier hookSupplier){
|
||||
supplierList.add(hookSupplier);
|
||||
}
|
||||
|
||||
public static void cleanHook(){
|
||||
supplierList.clear();
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ import cn.hutool.core.util.ObjectUtil;
|
|||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
import com.yomahub.liteflow.flow.executor.NodeExecutor;
|
||||
import com.yomahub.liteflow.flow.executor.DefaultNodeExecutor;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
|
@ -58,7 +59,15 @@ public abstract class NodeComponent{
|
|||
/** 节点执行器的类全名 */
|
||||
private Class<? extends NodeExecutor> nodeExecutorClass = DefaultNodeExecutor.class;
|
||||
|
||||
/********************以下的属性为线程附加属性,并非不变属性********************/
|
||||
/**当前对象为单例,注册进spring上下文,但是node实例不是单例,这里通过对node实例的引用来获得一些链路属性**/
|
||||
|
||||
private final TransmittableThreadLocal<Node> refNodeTL = new TransmittableThreadLocal<>();
|
||||
|
||||
/**
|
||||
*******************以下的属性为线程附加属性********************
|
||||
* 线程属性是指每一个request的值都是不一样的
|
||||
* 这里NodeComponent是单例,所以要用ThreadLocal来修饰
|
||||
*/
|
||||
|
||||
//当前slot的index
|
||||
private final TransmittableThreadLocal<Integer> slotIndexTL = new TransmittableThreadLocal<>();
|
||||
|
@ -66,15 +75,6 @@ public abstract class NodeComponent{
|
|||
//是否结束整个流程,这个只对串行流程有效,并行流程无效
|
||||
private final TransmittableThreadLocal<Boolean> isEndTL = new TransmittableThreadLocal<>();
|
||||
|
||||
//tag标签
|
||||
private final TransmittableThreadLocal<String> tagTL = new TransmittableThreadLocal<>();
|
||||
|
||||
//当前流程名字
|
||||
private final TransmittableThreadLocal<String> currChainNameTL = new TransmittableThreadLocal<>();
|
||||
|
||||
//组件外部参数
|
||||
private final TransmittableThreadLocal<String> cmpDataTL = new TransmittableThreadLocal<>();
|
||||
|
||||
public NodeComponent() {
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ public abstract class NodeComponent{
|
|||
|
||||
//在元数据里加入step信息
|
||||
CmpStep cmpStep = new CmpStep(nodeId, name, CmpStepTypeEnum.SINGLE);
|
||||
cmpStep.setTag(tagTL.get());
|
||||
cmpStep.setTag(this.getTag());
|
||||
slot.addStep(cmpStep);
|
||||
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
|
@ -273,16 +273,8 @@ public abstract class NodeComponent{
|
|||
this.nodeExecutorClass = nodeExecutorClass;
|
||||
}
|
||||
|
||||
public void setTag(String tag){
|
||||
this.tagTL.set(tag);
|
||||
}
|
||||
|
||||
public String getTag(){
|
||||
return this.tagTL.get();
|
||||
}
|
||||
|
||||
public void removeTag(){
|
||||
this.tagTL.remove();
|
||||
return this.refNodeTL.get().getTag();
|
||||
}
|
||||
|
||||
public MonitorBus getMonitorBus() {
|
||||
|
@ -298,16 +290,25 @@ public abstract class NodeComponent{
|
|||
}
|
||||
|
||||
public <T> T getSubChainReqData(){
|
||||
return getSlot().getChainReqData(this.getCurrChainName());
|
||||
return getSlot().getChainReqData(this.getCurrChainId());
|
||||
}
|
||||
|
||||
public <T> T getSubChainReqDataInAsync(){
|
||||
return getSlot().getChainReqDataFromQueue(this.getCurrChainName());
|
||||
return getSlot().getChainReqDataFromQueue(this.getCurrChainId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 请使用 {@link #getChainId()}
|
||||
* @return String
|
||||
*/
|
||||
@Deprecated
|
||||
public String getChainName(){
|
||||
return getSlot().getChainName();
|
||||
}
|
||||
|
||||
public String getChainId(){
|
||||
return getSlot().getChainId();
|
||||
}
|
||||
|
||||
public String getDisplayName(){
|
||||
if(StrUtil.isEmpty(this.name)){
|
||||
|
@ -317,33 +318,38 @@ public abstract class NodeComponent{
|
|||
}
|
||||
}
|
||||
|
||||
public void setCurrChainName(String currChainName){
|
||||
this.currChainNameTL.set(currChainName);
|
||||
public String getCurrChainId(){
|
||||
return getRefNode().getCurrChainId();
|
||||
}
|
||||
|
||||
public String getCurrChainName(){
|
||||
return this.currChainNameTL.get();
|
||||
public Node getRefNode(){
|
||||
return this.refNodeTL.get();
|
||||
}
|
||||
|
||||
public void removeCurrChainName(){
|
||||
this.currChainNameTL.remove();
|
||||
public void setRefNode(Node refNode){
|
||||
this.refNodeTL.set(refNode);
|
||||
}
|
||||
|
||||
public void setCmpData(String cmpData){
|
||||
this.cmpDataTL.set(cmpData);
|
||||
public void removeRefNode(){
|
||||
this.refNodeTL.remove();
|
||||
}
|
||||
|
||||
public <T> T getCmpData(Class<T> clazz){
|
||||
if (StrUtil.isBlank(this.cmpDataTL.get())){
|
||||
String cmpData = getRefNode().getCmpData();
|
||||
if (StrUtil.isBlank(cmpData)){
|
||||
return null;
|
||||
}
|
||||
return JsonUtil.parseObject(this.cmpDataTL.get(), clazz);
|
||||
if (clazz.equals(String.class) || clazz.equals(Object.class)){
|
||||
return (T) cmpData;
|
||||
}
|
||||
return JsonUtil.parseObject(cmpData, clazz);
|
||||
}
|
||||
|
||||
public void removeCmpData(){
|
||||
this.cmpDataTL.remove();
|
||||
public Integer getLoopIndex(){
|
||||
return this.refNodeTL.get().getLoopIndex();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void invoke(String chainId, Object param) throws Exception {
|
||||
FlowExecutorHolder.loadInstance().invoke(chainId, param, this.getSlotIndex());
|
||||
}
|
||||
|
@ -352,6 +358,7 @@ public abstract class NodeComponent{
|
|||
return FlowExecutorHolder.loadInstance().invoke2Resp(chainId, param, this.getSlotIndex());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void invokeInAsync(String chainId, Object param) throws Exception {
|
||||
FlowExecutorHolder.loadInstance().invokeInAsync(chainId, param, this.getSlotIndex());
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ public class ScriptBreakComponent extends NodeBreakComponent implements ScriptCo
|
|||
@Override
|
||||
public boolean processBreak() throws Exception {
|
||||
ScriptExecuteWrap wrap = new ScriptExecuteWrap();
|
||||
wrap.setCurrChainName(this.getCurrChainName());
|
||||
wrap.setCurrChainId(this.getCurrChainId());
|
||||
wrap.setNodeId(this.getNodeId());
|
||||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
|
|
|
@ -17,7 +17,7 @@ public class ScriptCommonComponent extends NodeComponent implements ScriptCompon
|
|||
@Override
|
||||
public void process() throws Exception {
|
||||
ScriptExecuteWrap wrap = new ScriptExecuteWrap();
|
||||
wrap.setCurrChainName(this.getCurrChainName());
|
||||
wrap.setCurrChainId(this.getCurrChainId());
|
||||
wrap.setNodeId(this.getNodeId());
|
||||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
|
|
|
@ -1,11 +1,32 @@
|
|||
package com.yomahub.liteflow.core;
|
||||
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 脚本接口
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public interface ScriptComponent {
|
||||
/**
|
||||
* 用于维护脚本类型和脚本 cmp 的映射关系
|
||||
*/
|
||||
Map<NodeTypeEnum, Class<?>> ScriptComponentClassMap = new HashMap<NodeTypeEnum, Class<?>>() {{
|
||||
put(NodeTypeEnum.SCRIPT, ScriptCommonComponent.class);
|
||||
put(NodeTypeEnum.SWITCH_SCRIPT, ScriptSwitchComponent.class);
|
||||
put(NodeTypeEnum.IF_SCRIPT, ScriptIfComponent.class);
|
||||
put(NodeTypeEnum.FOR_SCRIPT, ScriptForComponent.class);
|
||||
put(NodeTypeEnum.WHILE_SCRIPT, ScriptWhileComponent.class);
|
||||
put(NodeTypeEnum.BREAK_SCRIPT, ScriptBreakComponent.class);
|
||||
}};
|
||||
|
||||
|
||||
/**
|
||||
* 加载脚本
|
||||
* @param script
|
||||
*/
|
||||
void loadScript(String script);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ public class ScriptForComponent extends NodeForComponent implements ScriptCompon
|
|||
@Override
|
||||
public int processFor() throws Exception {
|
||||
ScriptExecuteWrap wrap = new ScriptExecuteWrap();
|
||||
wrap.setCurrChainName(this.getCurrChainName());
|
||||
wrap.setCurrChainId(this.getCurrChainId());
|
||||
wrap.setNodeId(this.getNodeId());
|
||||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
|
|
|
@ -12,7 +12,7 @@ public class ScriptIfComponent extends NodeIfComponent implements ScriptComponen
|
|||
@Override
|
||||
public boolean processIf() throws Exception {
|
||||
ScriptExecuteWrap wrap = new ScriptExecuteWrap();
|
||||
wrap.setCurrChainName(this.getCurrChainName());
|
||||
wrap.setCurrChainId(this.getCurrChainId());
|
||||
wrap.setNodeId(this.getNodeId());
|
||||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
|
|
|
@ -13,7 +13,7 @@ public class ScriptSwitchComponent extends NodeSwitchComponent implements Script
|
|||
@Override
|
||||
public String processSwitch() throws Exception {
|
||||
ScriptExecuteWrap wrap = new ScriptExecuteWrap();
|
||||
wrap.setCurrChainName(this.getCurrChainName());
|
||||
wrap.setCurrChainId(this.getCurrChainId());
|
||||
wrap.setNodeId(this.getNodeId());
|
||||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
|
|
|
@ -13,7 +13,7 @@ public class ScriptWhileComponent extends NodeWhileComponent implements ScriptCo
|
|||
@Override
|
||||
public boolean processWhile() throws Exception {
|
||||
ScriptExecuteWrap wrap = new ScriptExecuteWrap();
|
||||
wrap.setCurrChainName(this.getCurrChainName());
|
||||
wrap.setCurrChainId(this.getCurrChainId());
|
||||
wrap.setNodeId(this.getNodeId());
|
||||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
|
|
|
@ -62,7 +62,7 @@ public class ComponentProxy {
|
|||
beanClazz = bean.getClass();
|
||||
}
|
||||
//得到当前bean里所覆盖的LiteflowMethod(一定是被@LiteFlowMethod修饰的),自己定义的不算
|
||||
Map<String, List<Method>> methodListMap = Arrays.stream(beanClazz.getDeclaredMethods()).filter(
|
||||
Map<String, List<Method>> methodListMap = Arrays.stream(beanClazz.getMethods()).filter(
|
||||
m -> m.getAnnotation(LiteflowMethod.class) != null
|
||||
).collect(Collectors.groupingBy(
|
||||
m -> m.getAnnotation(LiteflowMethod.class).nodeId()
|
||||
|
@ -70,7 +70,7 @@ public class ComponentProxy {
|
|||
|
||||
return methodListMap.entrySet().stream().map(entry -> {
|
||||
// 获取当前节点的原有注解,如:LiteFlowRetry 之类的规则注解
|
||||
Annotation[] beanClassAnnotation = bean.getClass().getAnnotations();
|
||||
Annotation[] beanClassAnnotation = beanClazz.getAnnotations();
|
||||
// 如果entry的key为空字符串,则是为了兼容老版本的写法,即:没有指定nodeId的情况
|
||||
// 判断是否是方法级创造节点
|
||||
boolean isMethodCreate = !StrUtil.isEmpty(entry.getKey());
|
||||
|
@ -139,7 +139,7 @@ public class ComponentProxy {
|
|||
//被拦截的对象也根据被代理对象根据@LiteFlowMethod所标注的进行了动态判断
|
||||
Object instance = new ByteBuddy().subclass(cmpClazz)
|
||||
.name(StrUtil.format("{}.ByteBuddy${}${}",
|
||||
ClassUtil.getPackage(bean.getClass()),
|
||||
ClassUtil.getPackage(beanClazz),
|
||||
activeNodeId,
|
||||
SerialsUtil.generateShortUUID()))
|
||||
.method(ElementMatchers.namedOneOf(methodList.stream().map(m -> m.value().getMethodName()).toArray(String[]::new)))
|
||||
|
@ -163,8 +163,11 @@ public class ComponentProxy {
|
|||
|
||||
private final Object bean;
|
||||
|
||||
private final Class<?> clazz;
|
||||
|
||||
public AopInvocationHandler(Object bean) {
|
||||
this.bean = bean;
|
||||
this.clazz = LiteFlowProxyUtil.getUserClass(bean.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -172,7 +175,7 @@ public class ComponentProxy {
|
|||
//这里做了2件事情
|
||||
//先是从普通的bean里过滤出含有@LiteFlowMethod这个标注的方法
|
||||
//然后进行转换成LiteFlowMethodBean对象List,形成<methodName,Method>键值对的对象
|
||||
List<LiteFlowMethodBean> liteFlowMethodBeanList = Arrays.stream(ReflectUtil.getMethods(bean.getClass())).filter(m -> {
|
||||
List<LiteFlowMethodBean> liteFlowMethodBeanList = Arrays.stream(ReflectUtil.getMethods(clazz)).filter(m -> {
|
||||
LiteflowMethod liteFlowMethod = m.getAnnotation(LiteflowMethod.class);
|
||||
return ObjectUtil.isNotNull(liteFlowMethod);
|
||||
}).filter(m -> {
|
||||
|
|
|
@ -2,6 +2,9 @@ package com.yomahub.liteflow.core.proxy;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class LiteFlowMethodBean {
|
||||
|
||||
private String methodName;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.yomahub.liteflow.enums;
|
||||
|
||||
/**
|
||||
* @author Yun
|
||||
*/
|
||||
public enum ConditionTypeEnum {
|
||||
TYPE_THEN("then","then"),
|
||||
TYPE_WHEN("when","when"),
|
||||
|
|
|
@ -5,6 +5,7 @@ import cn.hutool.core.util.StrUtil;
|
|||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.*;
|
||||
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -16,170 +17,175 @@ import java.util.function.Predicate;
|
|||
|
||||
/**
|
||||
* 节点类型枚举
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public enum NodeTypeEnum {
|
||||
|
||||
COMMON("common","普通", false, NodeComponent.class),
|
||||
COMMON("common", "普通", false, NodeComponent.class),
|
||||
|
||||
SWITCH("switch", "选择", false, NodeSwitchComponent.class),
|
||||
SWITCH("switch", "选择", false, NodeSwitchComponent.class),
|
||||
|
||||
IF("if", "条件", false, NodeIfComponent.class),
|
||||
IF("if", "条件", false, NodeIfComponent.class),
|
||||
|
||||
FOR("for","循环次数", false, NodeForComponent.class),
|
||||
FOR("for", "循环次数", false, NodeForComponent.class),
|
||||
|
||||
WHILE("while", "循环条件", false, NodeWhileComponent.class),
|
||||
WHILE("while", "循环条件", false, NodeWhileComponent.class),
|
||||
|
||||
BREAK("break", "循环跳出", false, NodeBreakComponent.class),
|
||||
SCRIPT("script","脚本", true, ScriptCommonComponent.class),
|
||||
BREAK("break", "循环跳出", false, NodeBreakComponent.class),
|
||||
|
||||
SWITCH_SCRIPT("switch_script", "选择脚本", true, ScriptSwitchComponent.class),
|
||||
SCRIPT("script", "脚本", true, ScriptCommonComponent.class),
|
||||
|
||||
IF_SCRIPT("if_script", "条件脚本", true, ScriptIfComponent.class),
|
||||
SWITCH_SCRIPT("switch_script", "选择脚本", true, ScriptSwitchComponent.class),
|
||||
|
||||
FOR_SCRIPT("for_script", "循环次数脚本", true, ScriptForComponent.class),
|
||||
IF_SCRIPT("if_script", "条件脚本", true, ScriptIfComponent.class),
|
||||
|
||||
WHILE_SCRIPT("while_script", "循环条件脚本", true, ScriptWhileComponent.class),
|
||||
FOR_SCRIPT("for_script", "循环次数脚本", true, ScriptForComponent.class),
|
||||
|
||||
BREAK_SCRIPT("break_script", "循环跳出脚本", true, ScriptBreakComponent.class)
|
||||
;
|
||||
WHILE_SCRIPT("while_script", "循环条件脚本", true, ScriptWhileComponent.class),
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(NodeTypeEnum.class);
|
||||
BREAK_SCRIPT("break_script", "循环跳出脚本", true, ScriptBreakComponent.class);
|
||||
|
||||
private String code;
|
||||
private String name;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(NodeTypeEnum.class);
|
||||
|
||||
private boolean isScript;
|
||||
private String code;
|
||||
private String name;
|
||||
|
||||
private Class<? extends NodeComponent> mappingClazz;
|
||||
private boolean isScript;
|
||||
|
||||
NodeTypeEnum(String code, String name, boolean isScript, Class<? extends NodeComponent> mappingClazz) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.isScript = isScript;
|
||||
this.mappingClazz = mappingClazz;
|
||||
}
|
||||
private Class<? extends NodeComponent> mappingClazz;
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
NodeTypeEnum(String code, String name, boolean isScript, Class<? extends NodeComponent> mappingClazz) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.isScript = isScript;
|
||||
this.mappingClazz = mappingClazz;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isScript() {
|
||||
return isScript;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setScript(boolean script) {
|
||||
isScript = script;
|
||||
}
|
||||
public boolean isScript() {
|
||||
return isScript;
|
||||
}
|
||||
|
||||
public Class<? extends NodeComponent> getMappingClazz() {
|
||||
return mappingClazz;
|
||||
}
|
||||
public void setScript(boolean script) {
|
||||
isScript = script;
|
||||
}
|
||||
|
||||
public void setMappingClazz(Class<? extends NodeComponent> mappingClazz) {
|
||||
this.mappingClazz = mappingClazz;
|
||||
}
|
||||
public Class<? extends NodeComponent> getMappingClazz() {
|
||||
return mappingClazz;
|
||||
}
|
||||
|
||||
public static NodeTypeEnum getEnumByCode(String code) {
|
||||
for (NodeTypeEnum e : NodeTypeEnum.values()) {
|
||||
if (e.getCode().equals(code)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public void setMappingClazz(Class<? extends NodeComponent> mappingClazz) {
|
||||
this.mappingClazz = mappingClazz;
|
||||
}
|
||||
|
||||
public static NodeTypeEnum guessTypeBySuperClazz(Class<?> clazz){
|
||||
Class<?> superClazz = clazz;
|
||||
while(true){
|
||||
superClazz = superClazz.getSuperclass();
|
||||
if (superClazz.getPackage().getName().startsWith("com.yomahub.liteflow.core")){
|
||||
break;
|
||||
}
|
||||
if(superClazz.equals(Object.class)){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static NodeTypeEnum getEnumByCode(String code) {
|
||||
for (NodeTypeEnum e : NodeTypeEnum.values()) {
|
||||
if (e.getCode().equals(code)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
for (NodeTypeEnum e : NodeTypeEnum.values()) {
|
||||
if (e.getMappingClazz().equals(superClazz)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static NodeTypeEnum guessTypeBySuperClazz(Class<?> clazz) {
|
||||
Class<?> superClazz = clazz;
|
||||
while (true) {
|
||||
superClazz = superClazz.getSuperclass();
|
||||
if (superClazz.getPackage().getName().startsWith("com.yomahub.liteflow.core")) {
|
||||
break;
|
||||
}
|
||||
if (superClazz.equals(Object.class)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static NodeTypeEnum guessType(Class<?> clazz){
|
||||
NodeTypeEnum nodeType = guessTypeBySuperClazz(clazz);
|
||||
if (nodeType == null){
|
||||
//尝试从类声明处进行推断
|
||||
LiteflowCmpDefine liteflowCmpDefine = clazz.getAnnotation(LiteflowCmpDefine.class);
|
||||
if (liteflowCmpDefine != null){
|
||||
//类声明方式中@LiteflowMethod是无需设置nodeId的
|
||||
//但是如果设置了,那么核心逻辑其实是取类上定义的id的
|
||||
//这种可以运行,但是理解起来不大好理解,所以给出提示,建议不要这么做
|
||||
boolean mixDefined = Arrays.stream(clazz.getDeclaredMethods()).anyMatch(method -> {
|
||||
LiteflowMethod liteflowMethod = AnnotationUtil.getAnnotation(method, LiteflowMethod.class);
|
||||
if (liteflowMethod != null){
|
||||
return StrUtil.isNotBlank(liteflowMethod.nodeId());
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
for (NodeTypeEnum e : NodeTypeEnum.values()) {
|
||||
if (e.getMappingClazz().equals(superClazz)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mixDefined){
|
||||
LOG.warn("[[[WARNING!!!]]]The @liteflowMethod in the class[{}] defined by @liteflowCmpDefine should not configure the nodeId again!",
|
||||
clazz.getName());
|
||||
}
|
||||
public static NodeTypeEnum guessType(Class<?> clazz) {
|
||||
if(LiteFlowProxyUtil.isCglibProxyClass(clazz)){
|
||||
clazz = LiteFlowProxyUtil.getUserClass(clazz);
|
||||
}
|
||||
|
||||
NodeTypeEnum nodeType = guessTypeBySuperClazz(clazz);
|
||||
if (nodeType == null) {
|
||||
//尝试从类声明处进行推断
|
||||
LiteflowCmpDefine liteflowCmpDefine = clazz.getAnnotation(LiteflowCmpDefine.class);
|
||||
if (liteflowCmpDefine != null) {
|
||||
//类声明方式中@LiteflowMethod是无需设置nodeId的
|
||||
//但是如果设置了,那么核心逻辑其实是取类上定义的id的
|
||||
//这种可以运行,但是理解起来不大好理解,所以给出提示,建议不要这么做
|
||||
boolean mixDefined = Arrays.stream(clazz.getDeclaredMethods()).anyMatch(method -> {
|
||||
LiteflowMethod liteflowMethod = AnnotationUtil.getAnnotation(method, LiteflowMethod.class);
|
||||
if (liteflowMethod != null) {
|
||||
return StrUtil.isNotBlank(liteflowMethod.nodeId());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (mixDefined) {
|
||||
LOG.warn("[[[WARNING!!!]]]The @liteflowMethod in the class[{}] defined by @liteflowCmpDefine should not configure the nodeId again!",
|
||||
clazz.getName());
|
||||
}
|
||||
|
||||
|
||||
//在返回之前,还要对方法级别的@LiteflowMethod进行检查,如果存在方法上的类型与类上的不一致时,给予警告信息
|
||||
AtomicReference<Method> differenceTypeMethod = new AtomicReference<>();
|
||||
boolean hasDifferenceNodeType = Arrays.stream(clazz.getDeclaredMethods()).anyMatch(method -> {
|
||||
LiteflowMethod liteflowMethod = AnnotationUtil.getAnnotation(method, LiteflowMethod.class);
|
||||
if (liteflowMethod != null){
|
||||
if (!liteflowMethod.nodeType().equals(liteflowCmpDefine.value())){
|
||||
differenceTypeMethod.set(method);
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
//在返回之前,还要对方法级别的@LiteflowMethod进行检查,如果存在方法上的类型与类上的不一致时,给予警告信息
|
||||
AtomicReference<Method> differenceTypeMethod = new AtomicReference<>();
|
||||
boolean hasDifferenceNodeType = Arrays.stream(clazz.getDeclaredMethods()).anyMatch(method -> {
|
||||
LiteflowMethod liteflowMethod = AnnotationUtil.getAnnotation(method, LiteflowMethod.class);
|
||||
if (liteflowMethod != null) {
|
||||
if (!liteflowMethod.nodeType().equals(liteflowCmpDefine.value())) {
|
||||
differenceTypeMethod.set(method);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
//表示存在不一样的类型
|
||||
if (hasDifferenceNodeType){
|
||||
LOG.warn("[[[WARNING!!!]]]The nodeType in @liteflowCmpDefine declared on the class[{}] does not match the nodeType in @liteflowMethod declared on the method[{}]!",
|
||||
clazz.getName(), differenceTypeMethod.get().getName());
|
||||
}
|
||||
//表示存在不一样的类型
|
||||
if (hasDifferenceNodeType) {
|
||||
LOG.warn("[[[WARNING!!!]]]The nodeType in @liteflowCmpDefine declared on the class[{}] does not match the nodeType in @liteflowMethod declared on the method[{}]!",
|
||||
clazz.getName(), differenceTypeMethod.get().getName());
|
||||
}
|
||||
|
||||
return liteflowCmpDefine.value();
|
||||
}
|
||||
return liteflowCmpDefine.value();
|
||||
}
|
||||
|
||||
//再尝试声明式组件这部分的推断
|
||||
LiteflowMethod liteflowMethod = Arrays.stream(clazz.getDeclaredMethods()).map(
|
||||
method -> AnnotationUtil.getAnnotation(method, LiteflowMethod.class)
|
||||
).filter(Objects::nonNull).filter(lfMethod -> lfMethod.value().isMainMethod()).findFirst().orElse(null);
|
||||
//再尝试声明式组件这部分的推断
|
||||
LiteflowMethod liteflowMethod = Arrays.stream(clazz.getDeclaredMethods()).map(
|
||||
method -> AnnotationUtil.getAnnotation(method, LiteflowMethod.class)
|
||||
).filter(Objects::nonNull).filter(lfMethod -> lfMethod.value().isMainMethod()).findFirst().orElse(null);
|
||||
|
||||
if (liteflowMethod != null) {
|
||||
nodeType = liteflowMethod.nodeType();
|
||||
}
|
||||
}
|
||||
return nodeType;
|
||||
}
|
||||
if (liteflowMethod != null) {
|
||||
nodeType = liteflowMethod.nodeType();
|
||||
}
|
||||
}
|
||||
return nodeType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
|
||||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 链端异常
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class ChainEndException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 链端不存在
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class ChainNotFoundException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
|
||||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 组件方法定义错误异常
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class ComponentMethodDefineErrorException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 组件不可访问异常
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class ComponentNotAccessException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
|
||||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 组件代理错误异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class ComponentProxyErrorException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 配置错误异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class ConfigErrorException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
|
||||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 循环依赖异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class CyclicDependencyException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 未找到数据异常
|
||||
* @author tangkc
|
||||
*/
|
||||
public class DataNofFoundException extends RuntimeException {
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* EL 解析异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class ELParseException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
|
||||
/**
|
||||
* 空条件值异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class EmptyConditionValueException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 错误支持路径异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class ErrorSupportPathException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 流程执行者未初始化
|
||||
* @author Yun
|
||||
*/
|
||||
public class FlowExecutorNotInitException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 流程系统异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class FlowSystemException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 如果目标不能是 Pre 或 Finally 异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class IfTargetCannotBePreOrFinallyException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 类型错误异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class IfTypeErrorException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* Json 进程异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class JsonProcessException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 重复解析器异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class MultipleParsersException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 无可用插槽异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class NoAvailableSlotException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 没有节点异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class NoForNodeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 节点不为真异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class NoIfTrueNodeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 无切换目标节点异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class NoSwitchTargetNodeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 没有 While 节点异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class NoWhileNodeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
|
||||
/**
|
||||
* 节点构建异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class NodeBuildException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 找不到节点类异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class NodeClassNotFoundException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 节点类型无法猜测异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class NodeTypeCanNotGuessException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
|
||||
/**
|
||||
* 不支持条件异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class NotSupportConditionException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 空节点异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class NullNodeTypeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 解析异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class ParseException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 解析器找不到异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class ParserCannotFindException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* ScriptBean的方法无法被调用异常
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class ScriptBeanMethodInvokeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 异常信息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
public ScriptBeanMethodInvokeException(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 切换目标不能是 Pre 或 Finally 异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class SwitchTargetCannotBePreOrFinallyException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 开关类型错误异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class SwitchTypeErrorException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
|
||||
/**
|
||||
* 执行异常时
|
||||
* @author Yun
|
||||
*/
|
||||
public class WhenExecuteException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
|
||||
/**
|
||||
* 当超时异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class WhenTimeoutException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
|
@ -35,12 +35,16 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 流程元数据类
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class FlowBus {
|
||||
|
@ -54,20 +58,20 @@ public class FlowBus {
|
|||
private FlowBus() {
|
||||
}
|
||||
|
||||
public static Chain getChain(String id){
|
||||
public static Chain getChain(String id) {
|
||||
return chainMap.get(id);
|
||||
}
|
||||
|
||||
//这一方法主要用于第一阶段chain的预装载
|
||||
public static void addChain(String chainName){
|
||||
if (!chainMap.containsKey(chainName)){
|
||||
public static void addChain(String chainName) {
|
||||
if (!chainMap.containsKey(chainName)) {
|
||||
chainMap.put(chainName, new Chain(chainName));
|
||||
}
|
||||
}
|
||||
|
||||
//这个方法主要用于第二阶段的替换chain
|
||||
public static void addChain(Chain chain) {
|
||||
chainMap.put(chain.getChainName(), chain);
|
||||
chainMap.put(chain.getChainId(), chain);
|
||||
}
|
||||
|
||||
public static boolean containChain(String chainId) {
|
||||
|
@ -86,119 +90,53 @@ public class FlowBus {
|
|||
//根据class来猜测类型
|
||||
NodeTypeEnum type = NodeTypeEnum.guessType(nodeComponent.getClass());
|
||||
|
||||
if (type == null){
|
||||
if (type == null) {
|
||||
throw new NullNodeTypeException(StrUtil.format("node type is null for node[{}]", nodeId));
|
||||
}
|
||||
|
||||
nodeMap.put(nodeId, new Node(ComponentInitializer.loadInstance().initComponent(nodeComponent, type, null, nodeId)));
|
||||
}
|
||||
|
||||
public static void addCommonNode(String nodeId, String name, String cmpClazzStr){
|
||||
/**
|
||||
* 添加 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 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{
|
||||
try {
|
||||
cmpClazz = Class.forName(cmpClazzStr);
|
||||
}catch (Exception e){
|
||||
} catch (Exception e) {
|
||||
throw new ComponentCannotRegisterException(e.getMessage());
|
||||
}
|
||||
addNode(nodeId, name, NodeTypeEnum.COMMON, cmpClazz, null);
|
||||
addNode(nodeId, name, nodeType, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addCommonNode(String nodeId, String name, Class<?> cmpClazz){
|
||||
addNode(nodeId, name, NodeTypeEnum.COMMON, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addSwitchNode(String nodeId, String name, String cmpClazzStr){
|
||||
Class<?> cmpClazz;
|
||||
try{
|
||||
cmpClazz = Class.forName(cmpClazzStr);
|
||||
}catch (Exception e){
|
||||
throw new ComponentCannotRegisterException(e.getMessage());
|
||||
}
|
||||
addNode(nodeId, name, NodeTypeEnum.SWITCH, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addSwitchNode(String nodeId, String name, Class<?> cmpClazz){
|
||||
addNode(nodeId, name, NodeTypeEnum.SWITCH, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addIfNode(String nodeId, String name, String cmpClazzStr){
|
||||
Class<?> cmpClazz;
|
||||
try{
|
||||
cmpClazz = Class.forName(cmpClazzStr);
|
||||
}catch (Exception e){
|
||||
throw new ComponentCannotRegisterException(e.getMessage());
|
||||
}
|
||||
addNode(nodeId, name, NodeTypeEnum.IF, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addIfNode(String nodeId, String name, Class<?> cmpClazz){
|
||||
addNode(nodeId, name, NodeTypeEnum.IF, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addForNode(String nodeId, String name, String cmpClazzStr){
|
||||
Class<?> cmpClazz;
|
||||
try{
|
||||
cmpClazz = Class.forName(cmpClazzStr);
|
||||
}catch (Exception e){
|
||||
throw new ComponentCannotRegisterException(e.getMessage());
|
||||
}
|
||||
addNode(nodeId, name, NodeTypeEnum.FOR, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addForNode(String nodeId, String name, Class<?> cmpClazz){
|
||||
addNode(nodeId, name, NodeTypeEnum.FOR, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addWhileNode(String nodeId, String name, String cmpClazzStr){
|
||||
Class<?> cmpClazz;
|
||||
try{
|
||||
cmpClazz = Class.forName(cmpClazzStr);
|
||||
}catch (Exception e){
|
||||
throw new ComponentCannotRegisterException(e.getMessage());
|
||||
}
|
||||
addNode(nodeId, name, NodeTypeEnum.WHILE, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addWhileNode(String nodeId, String name, Class<?> cmpClazz){
|
||||
addNode(nodeId, name, NodeTypeEnum.WHILE, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addBreakNode(String nodeId, String name, String cmpClazzStr){
|
||||
Class<?> cmpClazz;
|
||||
try{
|
||||
cmpClazz = Class.forName(cmpClazzStr);
|
||||
}catch (Exception e){
|
||||
throw new ComponentCannotRegisterException(e.getMessage());
|
||||
}
|
||||
addNode(nodeId, name, NodeTypeEnum.BREAK, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addBreakNode(String nodeId, String name, Class<?> cmpClazz){
|
||||
addNode(nodeId, name, NodeTypeEnum.BREAK, cmpClazz, null);
|
||||
}
|
||||
|
||||
public static void addCommonScriptNode(String nodeId, String name, String script){
|
||||
addNode(nodeId, name, NodeTypeEnum.SCRIPT, ScriptCommonComponent.class, script);
|
||||
}
|
||||
|
||||
public static void addSwitchScriptNode(String nodeId, String name, String script){
|
||||
addNode(nodeId, name, NodeTypeEnum.SWITCH_SCRIPT, ScriptSwitchComponent.class, script);
|
||||
}
|
||||
|
||||
public static void addIfScriptNode(String nodeId, String name, String script){
|
||||
addNode(nodeId, name, NodeTypeEnum.IF_SCRIPT, ScriptIfComponent.class, script);
|
||||
}
|
||||
|
||||
public static void addForScriptNode(String nodeId, String name, String script){
|
||||
addNode(nodeId, name, NodeTypeEnum.FOR_SCRIPT, ScriptForComponent.class, script);
|
||||
}
|
||||
|
||||
public static void addWhileScriptNode(String nodeId, String name, String script){
|
||||
addNode(nodeId, name, NodeTypeEnum.WHILE_SCRIPT, ScriptWhileComponent.class, script);
|
||||
}
|
||||
|
||||
public static void addBreakScriptNode(String nodeId, String name, String script){
|
||||
addNode(nodeId, name, NodeTypeEnum.BREAK_SCRIPT, ScriptBreakComponent.class, script);
|
||||
/**
|
||||
* 添加脚本 node
|
||||
*
|
||||
* @param nodeId 节点id
|
||||
* @param name 节点名称
|
||||
* @param nodeType 节点类型
|
||||
* @param script 脚本
|
||||
*/
|
||||
public static void addScriptNode(String nodeId, String name, NodeTypeEnum nodeType, String script) {
|
||||
addNode(nodeId, name, nodeType, ScriptComponent.ScriptComponentClassMap.get(nodeType), script);
|
||||
}
|
||||
|
||||
private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz, String script) {
|
||||
|
@ -206,7 +144,7 @@ public class FlowBus {
|
|||
//判断此类是否是声明式的组件,如果是声明式的组件,就用动态代理生成实例
|
||||
//如果不是声明式的,就用传统的方式进行判断
|
||||
List<NodeComponent> cmpInstances = new ArrayList<>();
|
||||
if (LiteFlowProxyUtil.isDeclareCmp(cmpClazz)){
|
||||
if (LiteFlowProxyUtil.isDeclareCmp(cmpClazz)) {
|
||||
//这里的逻辑要仔细看下
|
||||
//如果是spring体系,把原始的类往spring上下文中进行注册,那么会走到ComponentScanner中
|
||||
//由于ComponentScanner中已经对原始类进行了动态代理,出来的对象已经变成了动态代理类,所以这时候的bean已经是NodeComponent的子类了
|
||||
|
@ -215,16 +153,16 @@ public class FlowBus {
|
|||
//这里用ContextAware的spi机制来判断是否spring体系
|
||||
ContextAware contextAware = ContextAwareHolder.loadContextAware();
|
||||
Object bean = ContextAwareHolder.loadContextAware().registerBean(nodeId, cmpClazz);
|
||||
if (LocalContextAware.class.isAssignableFrom(contextAware.getClass())){
|
||||
if (LocalContextAware.class.isAssignableFrom(contextAware.getClass())) {
|
||||
cmpInstances = LiteFlowProxyUtil.proxy2NodeComponent(bean, nodeId);
|
||||
}else {
|
||||
} else {
|
||||
cmpInstances = ListUtil.toList((NodeComponent) bean);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
//以node方式配置,本质上是为了适配无spring的环境,如果有spring环境,其实不用这么配置
|
||||
//这里的逻辑是判断是否能从spring上下文中取到,如果没有spring,则就是new instance了
|
||||
//如果是script类型的节点,因为class只有一个,所以也不能注册进spring上下文,注册的时候需要new Instance
|
||||
if (!type.isScript()){
|
||||
if (!type.isScript()) {
|
||||
cmpInstances = ListUtil.toList((NodeComponent) ContextAwareHolder.loadContextAware().registerOrGet(nodeId, cmpClazz));
|
||||
}
|
||||
// 去除null元素
|
||||
|
@ -235,7 +173,7 @@ public class FlowBus {
|
|||
cmpInstances.add(cmpInstance);
|
||||
}
|
||||
}
|
||||
//进行初始化
|
||||
//进行初始化component
|
||||
cmpInstances = cmpInstances.stream()
|
||||
.map(cmpInstance -> ComponentInitializer.loadInstance().initComponent(
|
||||
cmpInstance,
|
||||
|
@ -244,7 +182,7 @@ public class FlowBus {
|
|||
cmpInstance.getNodeId() == null ? nodeId : cmpInstance.getNodeId())
|
||||
).collect(Collectors.toList());
|
||||
|
||||
//初始化Node
|
||||
//初始化Node,把component放到Node里去
|
||||
List<Node> nodes = cmpInstances.stream().map(Node::new).collect(Collectors.toList());
|
||||
|
||||
|
||||
|
@ -252,11 +190,11 @@ public class FlowBus {
|
|||
Node node = nodes.get(i);
|
||||
NodeComponent cmpInstance = cmpInstances.get(i);
|
||||
//如果是脚本节点,则还要加载script脚本
|
||||
if (type.isScript()){
|
||||
if (StrUtil.isNotBlank(script)){
|
||||
if (type.isScript()) {
|
||||
if (StrUtil.isNotBlank(script)) {
|
||||
node.setScript(script);
|
||||
((ScriptComponent)cmpInstance).loadScript(script);
|
||||
}else{
|
||||
((ScriptComponent) cmpInstance).loadScript(script);
|
||||
} else {
|
||||
String errorMsg = StrUtil.format("script for node[{}] is empty", nodeId);
|
||||
throw new ScriptLoadException(errorMsg);
|
||||
}
|
||||
|
@ -267,8 +205,8 @@ public class FlowBus {
|
|||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
String error = StrUtil.format("component[{}] register error", StrUtil.isEmpty(name)?nodeId:StrUtil.format("{}({})",nodeId,name));
|
||||
LOG.error(error);
|
||||
String error = StrUtil.format("component[{}] register error", StrUtil.isEmpty(name) ? nodeId : StrUtil.format("{}({})", nodeId, name));
|
||||
LOG.error(e.getMessage());
|
||||
throw new ComponentCannotRegisterException(error);
|
||||
}
|
||||
}
|
||||
|
@ -281,19 +219,19 @@ public class FlowBus {
|
|||
//那condNodeMap共用有关系么,原则上没有关系。但是从设计理念上,以后应该要分开
|
||||
//tag和condNodeMap这2个属性不属于全局概念,属于每个chain范围的属性
|
||||
public static Node copyNode(String nodeId) {
|
||||
try{
|
||||
try {
|
||||
Node node = nodeMap.get(nodeId);
|
||||
return node.copy();
|
||||
}catch (Exception e){
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, Node> getNodeMap(){
|
||||
public static Map<String, Node> getNodeMap() {
|
||||
return nodeMap;
|
||||
}
|
||||
|
||||
public static Map<String, Chain> getChainMap(){
|
||||
public static Map<String, Chain> getChainMap() {
|
||||
return chainMap;
|
||||
}
|
||||
|
||||
|
@ -305,12 +243,13 @@ public class FlowBus {
|
|||
|
||||
public static void cleanScriptCache() {
|
||||
//如果引入了脚本组件SPI,则还需要清理脚本的缓存
|
||||
try{
|
||||
try {
|
||||
ScriptExecutor scriptExecutor = ScriptExecutorFactory.loadInstance().getScriptExecutor();
|
||||
if (ObjectUtil.isNotNull(scriptExecutor)){
|
||||
if (ObjectUtil.isNotNull(scriptExecutor)) {
|
||||
scriptExecutor.cleanCache();
|
||||
}
|
||||
}catch (ScriptSpiException ignored){}
|
||||
} catch (ScriptSpiException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void refreshFlowMetaData(FlowParserTypeEnum type, String content) throws Exception {
|
||||
|
@ -323,14 +262,18 @@ public class FlowBus {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean removeChain(String chainId){
|
||||
if (containChain(chainId)){
|
||||
public static boolean removeChain(String chainId) {
|
||||
if (containChain(chainId)) {
|
||||
chainMap.remove(chainId);
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
String errMsg = StrUtil.format("cannot find the chain[{}]", chainId);
|
||||
LOG.error(errMsg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeChain(String... chainIds) {
|
||||
Arrays.stream(chainIds).forEach(FlowBus::removeChain);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,24 +29,18 @@ public class Chain implements Executable {
|
|||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Chain.class);
|
||||
|
||||
private String chainName;
|
||||
private String chainId;
|
||||
|
||||
private List<Condition> conditionList = new ArrayList<>();
|
||||
|
||||
//前置处理Condition,用来区别主体的Condition
|
||||
private List<Condition> preConditionList = new ArrayList<>();
|
||||
|
||||
//后置处理Condition,用来区别主体的Condition
|
||||
private List<Condition> finallyConditionList = new ArrayList<>();
|
||||
|
||||
public Chain(String chainName){
|
||||
this.chainName = chainName;
|
||||
this.chainId = chainName;
|
||||
}
|
||||
|
||||
public Chain(){}
|
||||
|
||||
public Chain(String chainName, List<Condition> conditionList) {
|
||||
this.chainName = chainName;
|
||||
this.chainId = chainName;
|
||||
this.conditionList = conditionList;
|
||||
}
|
||||
|
||||
|
@ -58,29 +52,44 @@ public class Chain implements Executable {
|
|||
this.conditionList = conditionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 请使用{@link #getChainId()}
|
||||
*/
|
||||
@Deprecated
|
||||
public String getChainName() {
|
||||
return chainName;
|
||||
return chainId;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param chainName
|
||||
* @deprecated 请使用 {@link #setChainId(String)}
|
||||
*/
|
||||
public void setChainName(String chainName) {
|
||||
this.chainName = chainName;
|
||||
this.chainId = chainName;
|
||||
}
|
||||
|
||||
public String getChainId() {
|
||||
return chainId;
|
||||
}
|
||||
|
||||
public void setChainId(String chainId) {
|
||||
this.chainId = chainId;
|
||||
}
|
||||
|
||||
//执行chain的主方法
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
if (CollUtil.isEmpty(conditionList)) {
|
||||
throw new FlowSystemException("no conditionList in this chain[" + chainName + "]");
|
||||
throw new FlowSystemException("no conditionList in this chain[" + chainId + "]");
|
||||
}
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
try {
|
||||
//设置主ChainName
|
||||
slot.setChainName(chainName);
|
||||
//执行前置
|
||||
this.executePre(slotIndex);
|
||||
slot.setChainId(chainId);
|
||||
//执行主体Condition
|
||||
for (Condition condition : conditionList) {
|
||||
condition.setCurrChainName(chainName);
|
||||
condition.setCurrChainId(chainId);
|
||||
condition.execute(slotIndex);
|
||||
}
|
||||
}catch (ChainEndException e){
|
||||
|
@ -89,29 +98,12 @@ public class Chain implements Executable {
|
|||
throw e;
|
||||
}catch (Exception e){
|
||||
//这里事先取到exception set到slot里,为了方便finally取到exception
|
||||
if (slot.isSubChain(chainName)){
|
||||
slot.setSubException(chainName, e);
|
||||
if (slot.isSubChain(chainId)){
|
||||
slot.setSubException(chainId, e);
|
||||
}else{
|
||||
slot.setException(e);
|
||||
}
|
||||
throw e;
|
||||
}finally {
|
||||
//执行后置
|
||||
this.executeFinally(slotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// 执行pre节点
|
||||
private void executePre(Integer slotIndex) throws Exception {
|
||||
for (Condition condition : this.preConditionList){
|
||||
condition.execute(slotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
//执行后置
|
||||
private void executeFinally(Integer slotIndex) throws Exception {
|
||||
for (Condition condition : this.finallyConditionList){
|
||||
condition.execute(slotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,22 +113,7 @@ public class Chain implements Executable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getExecuteName() {
|
||||
return chainName;
|
||||
}
|
||||
public List<Condition> getPreConditionList() {
|
||||
return preConditionList;
|
||||
}
|
||||
|
||||
public void setPreConditionList(List<Condition> preConditionList) {
|
||||
this.preConditionList = preConditionList;
|
||||
}
|
||||
|
||||
public List<Condition> getFinallyConditionList() {
|
||||
return finallyConditionList;
|
||||
}
|
||||
|
||||
public void setFinallyConditionList(List<Condition> finallyConditionList) {
|
||||
this.finallyConditionList = finallyConditionList;
|
||||
public String getExecuteId() {
|
||||
return chainId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,28 @@ public interface Executable{
|
|||
|
||||
ExecuteTypeEnum getExecuteType();
|
||||
|
||||
String getExecuteName();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* @deprecated 请使用 {@link #getExecuteId()}
|
||||
*/
|
||||
@Deprecated
|
||||
default String getExecuteName() {
|
||||
return getExecuteId();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param currentChainName
|
||||
* @deprecated 请使用 {@link #setCurrChainId(String)}
|
||||
*/
|
||||
default void setCurrChainName(String currentChainName){
|
||||
setCurrChainId(currentChainName);
|
||||
}
|
||||
|
||||
String getExecuteId();
|
||||
|
||||
default void setCurrChainId(String currentChainId){
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.text.MessageFormat;
|
|||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
|
@ -28,6 +29,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
/**
|
||||
* Node节点,实现可执行器
|
||||
* Node节点并不是单例的,每构建一次都会copy出一个新的实例
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class Node implements Executable,Cloneable{
|
||||
|
@ -50,6 +52,10 @@ public class Node implements Executable,Cloneable{
|
|||
|
||||
private String cmpData;
|
||||
|
||||
private String currChainId;
|
||||
|
||||
private TransmittableThreadLocal<Integer> loopIndexTL = new TransmittableThreadLocal<>();
|
||||
|
||||
public Node(){
|
||||
|
||||
}
|
||||
|
@ -106,8 +112,7 @@ public class Node implements Executable,Cloneable{
|
|||
try {
|
||||
//把线程属性赋值给组件对象
|
||||
instance.setSlotIndex(slotIndex);
|
||||
instance.setTag(tag);
|
||||
instance.setCmpData(cmpData);
|
||||
instance.setRefNode(this);
|
||||
|
||||
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
|
||||
|
||||
|
@ -148,9 +153,8 @@ public class Node implements Executable,Cloneable{
|
|||
//移除threadLocal里的信息
|
||||
instance.removeSlotIndex();
|
||||
instance.removeIsEnd();
|
||||
instance.removeTag();
|
||||
instance.removeCurrChainName();
|
||||
instance.removeCmpData();
|
||||
instance.removeRefNode();
|
||||
removeLoopIndex();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +164,9 @@ public class Node implements Executable,Cloneable{
|
|||
//详情见这个issue:https://gitee.com/dromara/liteFlow/issues/I4XRBA
|
||||
@Override
|
||||
public boolean isAccess(Integer slotIndex) throws Exception {
|
||||
//把线程属性赋值给组件对象
|
||||
instance.setSlotIndex(slotIndex);
|
||||
instance.setRefNode(this);
|
||||
return instance.isAccess();
|
||||
}
|
||||
|
||||
|
@ -179,7 +185,7 @@ public class Node implements Executable,Cloneable{
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getExecuteName() {
|
||||
public String getExecuteId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -207,11 +213,6 @@ public class Node implements Executable,Cloneable{
|
|||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrChainName(String currentChainName) {
|
||||
instance.setCurrChainName(currentChainName);
|
||||
}
|
||||
|
||||
public String getCmpData() {
|
||||
return cmpData;
|
||||
}
|
||||
|
@ -219,4 +220,25 @@ public class Node implements Executable,Cloneable{
|
|||
public void setCmpData(String cmpData) {
|
||||
this.cmpData = cmpData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrChainId(String currentChainId) {
|
||||
this.currChainId = currentChainId;
|
||||
}
|
||||
|
||||
public String getCurrChainId() {
|
||||
return currChainId;
|
||||
}
|
||||
|
||||
public void setLoopIndex(int index){
|
||||
this.loopIndexTL.set(index);
|
||||
}
|
||||
|
||||
public Integer getLoopIndex(){
|
||||
return this.loopIndexTL.get();
|
||||
}
|
||||
|
||||
public void removeLoopIndex(){
|
||||
this.loopIndexTL.remove();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
package com.yomahub.liteflow.flow.element.condition;
|
||||
|
||||
import com.yomahub.liteflow.common.LocalDefaultFlowConstant;
|
||||
import com.yomahub.liteflow.enums.ExecuteTypeEnum;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.enums.ConditionTypeEnum;
|
||||
|
@ -23,14 +22,17 @@ public abstract class Condition implements Executable{
|
|||
|
||||
private String id;
|
||||
|
||||
//可执行元素的集合
|
||||
/**
|
||||
* 可执行元素的集合
|
||||
*/
|
||||
private List<Executable> executableList = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
//当前所在的ChainName
|
||||
//如果对于子流程来说,那这个就是子流程所在的Chain
|
||||
private String currChainName;
|
||||
/**
|
||||
* 当前所在的ChainName
|
||||
* 如果对于子流程来说,那这个就是子流程所在的Chain
|
||||
*/
|
||||
private String currChainId;
|
||||
|
||||
@Override
|
||||
public ExecuteTypeEnum getExecuteType() {
|
||||
|
@ -38,7 +40,7 @@ public abstract class Condition implements Executable{
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getExecuteName() {
|
||||
public String getExecuteId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
|
@ -64,12 +66,22 @@ public abstract class Condition implements Executable{
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* @deprecated 请使用 {@link #setCurrChainId(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public String getCurrChainName() {
|
||||
return currChainName;
|
||||
return currChainId;
|
||||
}
|
||||
|
||||
public String getCurrChainId() {
|
||||
return currChainId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrChainName(String currChainName) {
|
||||
this.currChainName = currChainName;
|
||||
public void setCurrChainId(String currChainId) {
|
||||
this.currChainId = currChainId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ public class FinallyCondition extends Condition {
|
|||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
for(Executable executableItem : this.getExecutableList()){
|
||||
executableItem.setCurrChainName(this.getCurrChainName());
|
||||
executableItem.setCurrChainId(this.getCurrChainId());
|
||||
executableItem.execute(slotIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class ForCondition extends LoopCondition{
|
|||
}
|
||||
|
||||
//执行forCount组件
|
||||
forNode.setCurrChainName(this.getCurrChainName());
|
||||
forNode.setCurrChainId(this.getCurrChainId());
|
||||
forNode.execute(slotIndex);
|
||||
|
||||
//这里可能会有spring代理过的bean,所以拿到user原始的class
|
||||
|
@ -42,10 +42,13 @@ public class ForCondition extends LoopCondition{
|
|||
|
||||
//循环执行
|
||||
for (int i = 0; i < forCount; i++) {
|
||||
executableItem.setCurrChainId(this.getCurrChainId());
|
||||
//设置循环index
|
||||
setLoopIndex(executableItem, i);
|
||||
executableItem.execute(slotIndex);
|
||||
//如果break组件不为空,则去执行
|
||||
if (ObjectUtil.isNotNull(breakNode)){
|
||||
breakNode.setCurrChainName(this.getCurrChainName());
|
||||
breakNode.setCurrChainId(this.getCurrChainId());
|
||||
breakNode.execute(slotIndex);
|
||||
Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(this.breakNode.getInstance().getClass());
|
||||
boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
|
||||
|
@ -54,7 +57,6 @@ public class ForCondition extends LoopCondition{
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -28,7 +28,7 @@ public class IfCondition extends Condition {
|
|||
public void execute(Integer slotIndex) throws Exception {
|
||||
if (ListUtil.toList(NodeTypeEnum.IF, NodeTypeEnum.IF_SCRIPT).contains(getIfNode().getType())){
|
||||
//先执行IF节点
|
||||
this.getIfNode().setCurrChainName(this.getCurrChainName());
|
||||
this.getIfNode().setCurrChainId(this.getCurrChainId());
|
||||
this.getIfNode().execute(slotIndex);
|
||||
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
|
@ -63,7 +63,7 @@ public class IfCondition extends Condition {
|
|||
}
|
||||
|
||||
//执行falseCaseExecutableItem
|
||||
falseCaseExecutableItem.setCurrChainName(this.getCurrChainName());
|
||||
falseCaseExecutableItem.setCurrChainId(this.getCurrChainId());
|
||||
falseCaseExecutableItem.execute(slotIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.yomahub.liteflow.flow.element.condition;
|
||||
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
|
||||
/**
|
||||
|
@ -20,4 +22,14 @@ public abstract class LoopCondition extends Condition {
|
|||
public void setBreakNode(Node breakNode) {
|
||||
this.breakNode = breakNode;
|
||||
}
|
||||
|
||||
protected void setLoopIndex(Executable executableItem, int index){
|
||||
if (executableItem instanceof Chain){
|
||||
((Chain)executableItem).getConditionList().forEach(condition -> setLoopIndex(condition, index));
|
||||
}else if(executableItem instanceof Condition){
|
||||
((Condition)executableItem).getExecutableList().forEach(executable -> setLoopIndex(executable, index));
|
||||
}else if(executableItem instanceof Node){
|
||||
((Node)executableItem).setLoopIndex(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ public class PreCondition extends Condition {
|
|||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
for(Executable executableItem : this.getExecutableList()){
|
||||
executableItem.setCurrChainName(this.getCurrChainName());
|
||||
executableItem.setCurrChainId(this.getCurrChainId());
|
||||
executableItem.execute(slotIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.yomahub.liteflow.flow.element.condition;
|
|||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.core.proxy.ComponentProxy;
|
||||
import com.yomahub.liteflow.enums.ConditionTypeEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.exception.NoSwitchTargetNodeException;
|
||||
|
@ -15,10 +14,8 @@ import com.yomahub.liteflow.slot.DataBus;
|
|||
import com.yomahub.liteflow.slot.Slot;
|
||||
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 选择Condition
|
||||
|
@ -27,15 +24,20 @@ import java.util.function.Predicate;
|
|||
*/
|
||||
public class SwitchCondition extends Condition{
|
||||
|
||||
private final Map<String, Executable> targetMap = new HashMap<>();
|
||||
|
||||
private final String TAG_PREFIX = "tag:";
|
||||
private final List<Executable> targetList = new ArrayList<>();
|
||||
|
||||
private final String TAG_PREFIX = "tag";
|
||||
private final String TAG_FLAG = ":";
|
||||
|
||||
private Executable defaultExecutor;
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
if (ListUtil.toList(NodeTypeEnum.SWITCH, NodeTypeEnum.SWITCH_SCRIPT).contains(this.getSwitchNode().getType())){
|
||||
//先执行switch节点
|
||||
this.getSwitchNode().setCurrChainName(this.getCurrChainName());
|
||||
this.getSwitchNode().setCurrChainId(this.getCurrChainId());
|
||||
this.getSwitchNode().execute(slotIndex);
|
||||
|
||||
//根据switch节点执行出来的结果选择
|
||||
|
@ -46,31 +48,42 @@ public class SwitchCondition extends Condition{
|
|||
if (StrUtil.isNotBlank(targetId)) {
|
||||
Executable targetExecutor;
|
||||
|
||||
//这里要判断是否跳转到tag
|
||||
if (targetId.startsWith(TAG_PREFIX)){
|
||||
String targetTag = targetId.replaceAll(TAG_PREFIX, "");
|
||||
targetExecutor = targetMap.values().stream().filter(executable -> {
|
||||
//这里要判断是否使用tag模式跳转
|
||||
if (targetId.contains(TAG_FLAG)){
|
||||
String[] target = targetId.split(TAG_FLAG, 2);
|
||||
String _targetId = target[0];
|
||||
String _targetTag = target[1];
|
||||
targetExecutor = targetList.stream().filter(executable -> {
|
||||
if (executable instanceof Node){
|
||||
Node node = (Node) executable;
|
||||
return targetTag.equals(node.getTag());
|
||||
return (StrUtil.startWith(_targetId, TAG_PREFIX) && _targetTag.equals(node.getTag())) || ((StrUtil.isEmpty(_targetId) || _targetId.equals(node.getId())) && (StrUtil.isEmpty(_targetTag) || _targetTag.equals(node.getTag())));
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}).findFirst().orElse(null);
|
||||
}else{
|
||||
targetExecutor = targetMap.get(targetId);
|
||||
targetExecutor = targetList.stream().filter(
|
||||
executable -> executable.getExecuteId().equals(targetId)
|
||||
).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
if (ObjectUtil.isNull(targetExecutor)) {
|
||||
//没有匹配到执行节点,则走默认的执行节点
|
||||
targetExecutor = defaultExecutor;
|
||||
}
|
||||
|
||||
if (ObjectUtil.isNotNull(targetExecutor)) {
|
||||
//switch的目标不能是Pre节点或者Finally节点
|
||||
if (targetExecutor instanceof PreCondition || targetExecutor instanceof FinallyCondition){
|
||||
String errorInfo = StrUtil.format("[{}]:switch component[{}] error, switch target node cannot be pre or finally", slot.getRequestId(), this.getSwitchNode().getInstance().getDisplayName());
|
||||
String errorInfo = StrUtil.format("[{}]:switch component[{}] error, switch target node cannot be pre or finally",
|
||||
slot.getRequestId(), this.getSwitchNode().getInstance().getDisplayName());
|
||||
throw new SwitchTargetCannotBePreOrFinallyException(errorInfo);
|
||||
}
|
||||
targetExecutor.setCurrChainName(this.getCurrChainName());
|
||||
targetExecutor.setCurrChainId(this.getCurrChainId());
|
||||
targetExecutor.execute(slotIndex);
|
||||
}else{
|
||||
String errorInfo = StrUtil.format("[{}]:no target node find for the component[{}]", slot.getRequestId(), this.getSwitchNode().getInstance().getDisplayName());
|
||||
String errorInfo = StrUtil.format("[{}]:no target node find for the component[{}],target str is [{}]",
|
||||
slot.getRequestId(), this.getSwitchNode().getInstance().getDisplayName(), targetId);
|
||||
throw new NoSwitchTargetNodeException(errorInfo);
|
||||
}
|
||||
}
|
||||
|
@ -85,18 +98,26 @@ public class SwitchCondition extends Condition{
|
|||
}
|
||||
|
||||
public void addTargetItem(Executable executable){
|
||||
this.targetMap.put(executable.getExecuteName(), executable);
|
||||
this.targetList.add(executable);
|
||||
}
|
||||
|
||||
public void setSwitchNode(Node switchNode) {
|
||||
this.getExecutableList().add(switchNode);
|
||||
}
|
||||
|
||||
public Map<String, Executable> getTargetMap() {
|
||||
return targetMap;
|
||||
public List<Executable> getTargetList(){
|
||||
return targetList;
|
||||
}
|
||||
|
||||
public Node getSwitchNode(){
|
||||
return (Node) this.getExecutableList().get(0);
|
||||
}
|
||||
|
||||
public Executable getDefaultExecutor() {
|
||||
return defaultExecutor;
|
||||
}
|
||||
|
||||
public void setDefaultExecutor(Executable defaultExecutor) {
|
||||
this.defaultExecutor = defaultExecutor;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,30 @@
|
|||
package com.yomahub.liteflow.flow.element.condition;
|
||||
|
||||
import com.yomahub.liteflow.enums.ConditionTypeEnum;
|
||||
import com.yomahub.liteflow.exception.ChainEndException;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 串行器
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class ThenCondition extends Condition {
|
||||
|
||||
/**
|
||||
* 前置处理Condition
|
||||
*/
|
||||
private final List<PreCondition> preConditionList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 后置处理Condition
|
||||
*/
|
||||
private final List<FinallyCondition> finallyConditionList = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public ConditionTypeEnum getConditionType() {
|
||||
return ConditionTypeEnum.TYPE_THEN;
|
||||
|
@ -22,13 +39,46 @@ public class ThenCondition extends Condition {
|
|||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
for (Executable executableItem : this.getExecutableList()) {
|
||||
//前置和后置组不执行,因为在build的时候会抽出来放在chain里面
|
||||
if (executableItem instanceof PreCondition || executableItem instanceof FinallyCondition){
|
||||
continue;
|
||||
try{
|
||||
for (PreCondition preCondition : preConditionList){
|
||||
preCondition.setCurrChainId(this.getCurrChainId());
|
||||
preCondition.execute(slotIndex);
|
||||
}
|
||||
executableItem.setCurrChainName(this.getCurrChainName());
|
||||
executableItem.execute(slotIndex);
|
||||
|
||||
for (Executable executableItem : this.getExecutableList()) {
|
||||
executableItem.setCurrChainId(this.getCurrChainId());
|
||||
executableItem.execute(slotIndex);
|
||||
}
|
||||
}catch (ChainEndException e){
|
||||
//这里单独catch ChainEndException是因为ChainEndException是用户自己setIsEnd抛出的异常
|
||||
//是属于正常逻辑,所以会在FlowExecutor中判断。这里不作为异常处理
|
||||
throw e;
|
||||
}catch (Exception e){
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
String chainId = this.getCurrChainId();
|
||||
//这里事先取到exception set到slot里,为了方便finally取到exception
|
||||
if (slot.isSubChain(chainId)){
|
||||
slot.setSubException(chainId, e);
|
||||
}else{
|
||||
slot.setException(e);
|
||||
}
|
||||
throw e;
|
||||
}finally {
|
||||
for (FinallyCondition finallyCondition : finallyConditionList){
|
||||
finallyCondition.setCurrChainId(this.getCurrChainId());
|
||||
finallyCondition.execute(slotIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addExecutable(Executable executable) {
|
||||
if (executable instanceof PreCondition){
|
||||
preConditionList.add((PreCondition) executable);
|
||||
}else if (executable instanceof FinallyCondition){
|
||||
finallyConditionList.add((FinallyCondition) executable);
|
||||
}else{
|
||||
super.addExecutable(executable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ public class WhenCondition extends Condition {
|
|||
private boolean errorResume = false;
|
||||
|
||||
//只在when类型下有效,用于不同node进行同组合并,相同的组会进行合并,不同的组不会进行合并
|
||||
//此属性已弃用
|
||||
private String group = LocalDefaultFlowConstant.DEFAULT;
|
||||
|
||||
//只在when类型下有效,为true的话说明在多个并行节点下,任意一个成功,整个when就成功
|
||||
|
@ -64,7 +65,7 @@ public class WhenCondition extends Condition {
|
|||
private void executeAsyncCondition(Integer slotIndex) throws Exception{
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
|
||||
String currChainName = this.getCurrChainName();
|
||||
String currChainName = this.getCurrChainId();
|
||||
|
||||
//此方法其实只会初始化一次Executor,不会每次都会初始化。Executor是唯一的
|
||||
ExecutorService parallelExecutor = ExecutorHelper.loadInstance().buildWhenExecutor(this.getThreadExecutorClass());
|
||||
|
@ -92,7 +93,7 @@ public class WhenCondition extends Condition {
|
|||
return false;
|
||||
}
|
||||
}).map(executable -> CompletableFutureTimeout.completeOnTimeout(
|
||||
WhenFutureObj.timeOut(executable.getExecuteName()),
|
||||
WhenFutureObj.timeOut(executable.getExecuteId()),
|
||||
CompletableFuture.supplyAsync(new ParallelSupplier(executable, currChainName, slotIndex), parallelExecutor),
|
||||
liteflowConfig.getWhenMaxWaitSeconds(),
|
||||
TimeUnit.SECONDS
|
||||
|
|
|
@ -32,11 +32,14 @@ public class WhileCondition extends LoopCondition{
|
|||
Executable executableItem = this.getDoExecutor();
|
||||
|
||||
//循环执行
|
||||
int index = 0;
|
||||
while(getWhileResult(slotIndex)){
|
||||
executableItem.setCurrChainId(this.getCurrChainId());
|
||||
setLoopIndex(executableItem, index++);
|
||||
executableItem.execute(slotIndex);
|
||||
//如果break组件不为空,则去执行
|
||||
if (ObjectUtil.isNotNull(breakNode)){
|
||||
breakNode.setCurrChainName(this.getCurrChainName());
|
||||
breakNode.setCurrChainId(this.getCurrChainId());
|
||||
breakNode.execute(slotIndex);
|
||||
Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(this.breakNode.getInstance().getClass());
|
||||
boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
|
||||
|
|
|
@ -19,7 +19,11 @@ import java.util.List;
|
|||
public abstract class NodeExecutor {
|
||||
protected final Logger LOG = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
//执行器执行入口-若需要更大维度的执行方式可以重写该方法
|
||||
/**
|
||||
* 执行器执行入口-若需要更大维度的执行方式可以重写该方法
|
||||
* @param instance
|
||||
* @throws Exception
|
||||
*/
|
||||
public void execute(NodeComponent instance) throws Exception {
|
||||
int retryCount = instance.getRetryCount();
|
||||
List<Class<? extends Exception>> forExceptions = Arrays.asList(instance.getRetryForExceptions());
|
||||
|
@ -47,7 +51,12 @@ public abstract class NodeExecutor {
|
|||
}
|
||||
}
|
||||
|
||||
//执行重试逻辑 - 子类通过实现该方法进行重试逻辑的控制
|
||||
/**
|
||||
* 执行重试逻辑 - 子类通过实现该方法进行重试逻辑的控制
|
||||
* @param instance
|
||||
* @param currentRetryCount
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void retry(NodeComponent instance, int currentRetryCount) throws Exception {
|
||||
Slot slot = DataBus.getSlot(instance.getSlotIndex());
|
||||
LOG.info("[{}]:component[{}] performs {} retry", slot.getRequestId(),instance.getDisplayName(), currentRetryCount + 1);
|
||||
|
|
|
@ -13,19 +13,26 @@ import java.util.Map;
|
|||
* @since 2.6.9
|
||||
*/
|
||||
public class NodeExecutorHelper {
|
||||
//此处使用Map缓存线程池信息
|
||||
/**
|
||||
* 此处使用Map缓存线程池信息
|
||||
*/
|
||||
private final Map<Class<? extends NodeExecutor>, NodeExecutor> nodeExecutorMap;
|
||||
|
||||
private NodeExecutorHelper() {
|
||||
nodeExecutorMap = MapUtil.newConcurrentHashMap();
|
||||
}
|
||||
|
||||
//使用静态内部类实现单例模式
|
||||
/**
|
||||
* 使用静态内部类实现单例模式
|
||||
*/
|
||||
private static class Holder {
|
||||
static final NodeExecutorHelper INSTANCE = new NodeExecutorHelper();
|
||||
}
|
||||
|
||||
//获取帮助者的实例
|
||||
/**
|
||||
* 获取帮助者的实例
|
||||
* @return
|
||||
*/
|
||||
public static NodeExecutorHelper loadInstance() {
|
||||
// 外围类能直接访问内部类(不管是否是静态的)的私有变量
|
||||
return Holder.INSTANCE;
|
||||
|
|
|
@ -29,11 +29,11 @@ public class ParallelSupplier implements Supplier<WhenFutureObj> {
|
|||
@Override
|
||||
public WhenFutureObj get() {
|
||||
try {
|
||||
executableItem.setCurrChainName(currChainName);
|
||||
executableItem.setCurrChainId(currChainName);
|
||||
executableItem.execute(slotIndex);
|
||||
return WhenFutureObj.success(executableItem.getExecuteName());
|
||||
return WhenFutureObj.success(executableItem.getExecuteId());
|
||||
} catch (Exception e){
|
||||
return WhenFutureObj.fail(executableItem.getExecuteName(), e);
|
||||
return WhenFutureObj.fail(executableItem.getExecuteId(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,8 @@ public abstract class BaseJsonFlowParser implements FlowParser {
|
|||
JsonNode flowJsonNode = JsonUtil.parseObject(content);
|
||||
jsonObjectList.add(flowJsonNode);
|
||||
}
|
||||
ParserHelper.parseJsonNode(jsonObjectList, CHAIN_NAME_SET, this::parseOneChain);
|
||||
ParserHelper.parseNodeJson(jsonObjectList);
|
||||
ParserHelper.parseChainJson(jsonObjectList, CHAIN_NAME_SET, this::parseOneChain);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,8 +36,8 @@ public abstract class BaseXmlFlowParser implements FlowParser {
|
|||
documentList.add(document);
|
||||
}
|
||||
|
||||
Consumer<Element> parseOneChainConsumer = this::parseOneChain;
|
||||
ParserHelper.parseDocument(documentList, CHAIN_NAME_SET, parseOneChainConsumer);
|
||||
ParserHelper.parseNodeDocument(documentList);
|
||||
ParserHelper.parseChainDocument(documentList, CHAIN_NAME_SET, this::parseOneChain);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,7 +39,8 @@ public abstract class BaseYmlFlowParser implements FlowParser {
|
|||
}
|
||||
|
||||
Consumer<JsonNode> parseOneChainConsumer = this::parseOneChain;
|
||||
ParserHelper.parseJsonNode(jsonObjectList, CHAIN_NAME_SET,parseOneChainConsumer);
|
||||
ParserHelper.parseNodeJson(jsonObjectList);
|
||||
ParserHelper.parseChainJson(jsonObjectList, CHAIN_NAME_SET, parseOneChainConsumer);
|
||||
}
|
||||
|
||||
protected JsonNode convertToJson(String yamlString) {
|
||||
|
|
|
@ -133,12 +133,12 @@ public class FlowParserProvider {
|
|||
* 统一管理类的常量
|
||||
*/
|
||||
protected static class ConfigRegexConstant {
|
||||
public static final String LOCAL_XML_CONFIG_REGEX = "^[\\w\\:\\-\\@\\/\\\\\\*]+\\.xml$";
|
||||
public static final String LOCAL_JSON_CONFIG_REGEX = "^[\\w\\:\\-\\@\\/\\\\\\*]+\\.json$";
|
||||
public static final String LOCAL_YML_CONFIG_REGEX = "^[\\w\\:\\-\\@\\/\\\\\\*]+\\.yml$";
|
||||
public static final String LOCAL_EL_XML_CONFIG_REGEX = "^[\\w\\:\\-\\@\\/\\\\\\*]+\\.el\\.xml$";
|
||||
public static final String LOCAL_EL_JSON_CONFIG_REGEX = "^[\\w\\:\\-\\@\\/\\\\\\*]+\\.el\\.json$";
|
||||
public static final String LOCAL_EL_YML_CONFIG_REGEX = "^[\\w\\:\\-\\@\\/\\\\\\*]+\\.el\\.yml$";
|
||||
public static final String LOCAL_XML_CONFIG_REGEX = "^[\\w\\:\\-\\.\\@\\/\\\\\\*]+\\.xml$";
|
||||
public static final String LOCAL_JSON_CONFIG_REGEX = "^[\\w\\:\\-\\.\\@\\/\\\\\\*]+\\.json$";
|
||||
public static final String LOCAL_YML_CONFIG_REGEX = "^[\\w\\:\\-\\.\\@\\/\\\\\\*]+\\.yml$";
|
||||
public static final String LOCAL_EL_XML_CONFIG_REGEX = "^[\\w\\:\\-\\.\\@\\/\\\\\\*]+\\.el\\.xml$";
|
||||
public static final String LOCAL_EL_JSON_CONFIG_REGEX = "^[\\w\\:\\-\\.\\@\\/\\\\\\*]+\\.el\\.json$";
|
||||
public static final String LOCAL_EL_YML_CONFIG_REGEX = "^[\\w\\:\\-\\.\\@\\/\\\\\\*]+\\.el\\.yml$";
|
||||
public static final String PREFIX_FORMAT_CONFIG_REGEX = "xml:|json:|yml:|el_xml:|el_json:|el_yml:";
|
||||
public static final String CLASS_CONFIG_REGEX = "^(xml:|json:|yml:|el_xml:|el_json:|el_yml:)?\\w+(\\.\\w+)*$";
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package com.yomahub.liteflow.parser.helper;
|
||||
|
||||
import cn.hutool.core.annotation.AnnotationUtil;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.yomahub.liteflow.annotation.*;
|
||||
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.builder.prop.NodePropBean;
|
||||
|
@ -87,35 +85,13 @@ public class ParserHelper {
|
|||
|
||||
/**
|
||||
* xml 形式的主要解析过程
|
||||
*
|
||||
* @param documentList documentList
|
||||
* @param chainNameSet 用于去重
|
||||
* @param parseOneChainConsumer parseOneChain 函数
|
||||
*/
|
||||
public static void parseDocument(List<Document> documentList, Set<String> chainNameSet, Consumer<Element> parseOneChainConsumer) {
|
||||
//先在元数据里放上chain
|
||||
//先放有一个好处,可以在parse的时候先映射到FlowBus的chainMap,然后再去解析
|
||||
//这样就不用去像之前的版本那样回归调用
|
||||
//同时也解决了不能循环依赖的问题
|
||||
documentList.forEach(document -> {
|
||||
// 解析chain节点
|
||||
List<Element> chainList = document.getRootElement().elements(CHAIN);
|
||||
|
||||
//先在元数据里放上chain
|
||||
chainList.forEach(e -> {
|
||||
//校验加载的 chainName 是否有重复的
|
||||
//TODO 这里是否有个问题,当混合格式加载的时候,2个同名的Chain在不同的文件里,就不行了
|
||||
String chainName = e.attributeValue(NAME);
|
||||
if (!chainNameSet.add(chainName)) {
|
||||
throw new ChainDuplicateException(String.format("[chain name duplicate] chainName=%s", chainName));
|
||||
}
|
||||
|
||||
FlowBus.addChain(chainName);
|
||||
});
|
||||
});
|
||||
// 清空
|
||||
chainNameSet.clear();
|
||||
|
||||
/**
|
||||
* xml 形式的主要解析过程
|
||||
* @param documentList documentList
|
||||
*/
|
||||
public static void parseNodeDocument(List<Document> documentList) {
|
||||
for (Document document : documentList) {
|
||||
Element rootElement = document.getRootElement();
|
||||
Element nodesElement = rootElement.element(NODES);
|
||||
|
@ -128,7 +104,7 @@ public class ParserHelper {
|
|||
name = e.attributeValue(NAME);
|
||||
clazz = e.attributeValue(_CLASS);
|
||||
type = e.attributeValue(TYPE);
|
||||
script = e.getTextTrim();
|
||||
script = e.getText();
|
||||
file = e.attributeValue(FILE);
|
||||
|
||||
// 构建 node
|
||||
|
@ -143,37 +119,42 @@ public class ParserHelper {
|
|||
ParserHelper.buildNode(nodePropBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void parseChainDocument(List<Document> documentList, Set<String> chainNameSet, Consumer<Element> parseOneChainConsumer){
|
||||
//先在元数据里放上chain
|
||||
//先放有一个好处,可以在parse的时候先映射到FlowBus的chainMap,然后再去解析
|
||||
//这样就不用去像之前的版本那样回归调用
|
||||
//同时也解决了不能循环依赖的问题
|
||||
documentList.forEach(document -> {
|
||||
// 解析chain节点
|
||||
List<Element> chainList = document.getRootElement().elements(CHAIN);
|
||||
|
||||
//解析每一个chain
|
||||
//先在元数据里放上chain
|
||||
chainList.forEach(e -> {
|
||||
//校验加载的 chainName 是否有重复的
|
||||
//TODO 这里是否有个问题,当混合格式加载的时候,2个同名的Chain在不同的文件里,就不行了
|
||||
String chainName = Optional.ofNullable(e.attributeValue(ID)).orElse(e.attributeValue(NAME));
|
||||
if (!chainNameSet.add(chainName)) {
|
||||
throw new ChainDuplicateException(String.format("[chain name duplicate] chainName=%s", chainName));
|
||||
}
|
||||
|
||||
FlowBus.addChain(chainName);
|
||||
});
|
||||
});
|
||||
// 清空
|
||||
chainNameSet.clear();
|
||||
|
||||
//解析每一个chain
|
||||
for (Document document : documentList) {
|
||||
Element rootElement = document.getRootElement();
|
||||
List<Element> chainList = rootElement.elements(CHAIN);
|
||||
chainList.forEach(parseOneChainConsumer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void parseJsonNode(List<JsonNode> flowJsonObjectList, Set<String> chainNameSet, Consumer<JsonNode> parseOneChainConsumer) {
|
||||
//先在元数据里放上chain
|
||||
//先放有一个好处,可以在parse的时候先映射到FlowBus的chainMap,然后再去解析
|
||||
//这样就不用去像之前的版本那样回归调用
|
||||
//同时也解决了不能循环依赖的问题
|
||||
flowJsonObjectList.forEach(jsonObject -> {
|
||||
// 解析chain节点
|
||||
Iterator<JsonNode> iterator = jsonObject.get(FLOW).get(CHAIN).elements();
|
||||
//先在元数据里放上chain
|
||||
while (iterator.hasNext()) {
|
||||
JsonNode innerJsonObject = iterator.next();
|
||||
//校验加载的 chainName 是否有重复的
|
||||
// TODO 这里是否有个问题,当混合格式加载的时候,2个同名的Chain在不同的文件里,就不行了
|
||||
String chainName = innerJsonObject.get(NAME).textValue();
|
||||
if (!chainNameSet.add(chainName)) {
|
||||
throw new ChainDuplicateException(String.format("[chain name duplicate] chainName=%s", chainName));
|
||||
}
|
||||
|
||||
FlowBus.addChain(innerJsonObject.get(NAME).textValue());
|
||||
}
|
||||
});
|
||||
// 清空
|
||||
chainNameSet.clear();
|
||||
|
||||
public static void parseNodeJson(List<JsonNode> flowJsonObjectList) {
|
||||
for (JsonNode flowJsonNode : flowJsonObjectList) {
|
||||
// 当存在<nodes>节点定义时,解析node节点
|
||||
if (flowJsonNode.get(FLOW).has(NODES)) {
|
||||
|
@ -200,7 +181,34 @@ public class ParserHelper {
|
|||
ParserHelper.buildNode(nodePropBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void parseChainJson(List<JsonNode> flowJsonObjectList, Set<String> chainNameSet, Consumer<JsonNode> parseOneChainConsumer){
|
||||
//先在元数据里放上chain
|
||||
//先放有一个好处,可以在parse的时候先映射到FlowBus的chainMap,然后再去解析
|
||||
//这样就不用去像之前的版本那样回归调用
|
||||
//同时也解决了不能循环依赖的问题
|
||||
flowJsonObjectList.forEach(jsonObject -> {
|
||||
// 解析chain节点
|
||||
Iterator<JsonNode> iterator = jsonObject.get(FLOW).get(CHAIN).elements();
|
||||
//先在元数据里放上chain
|
||||
while (iterator.hasNext()) {
|
||||
JsonNode innerJsonObject = iterator.next();
|
||||
//校验加载的 chainName 是否有重复的
|
||||
// TODO 这里是否有个问题,当混合格式加载的时候,2个同名的Chain在不同的文件里,就不行了
|
||||
String chainName = Optional.ofNullable(innerJsonObject.get(ID)).orElse(innerJsonObject.get(NAME)).textValue();
|
||||
if (!chainNameSet.add(chainName)) {
|
||||
throw new ChainDuplicateException(String.format("[chain name duplicate] chainName=%s", chainName));
|
||||
}
|
||||
|
||||
FlowBus.addChain(chainName);
|
||||
}
|
||||
});
|
||||
// 清空
|
||||
chainNameSet.clear();
|
||||
|
||||
for (JsonNode flowJsonNode : flowJsonObjectList) {
|
||||
//解析每一个chain
|
||||
Iterator<JsonNode> chainIterator = flowJsonNode.get(FLOW).get(CHAIN).elements();
|
||||
while (chainIterator.hasNext()) {
|
||||
|
@ -217,9 +225,9 @@ public class ParserHelper {
|
|||
*/
|
||||
public static void parseOneChainEl(JsonNode chainNode) {
|
||||
//构建chainBuilder
|
||||
String chainName = chainNode.get(NAME).textValue();
|
||||
String chainId = Optional.ofNullable(chainNode.get(ID)).orElse(chainNode.get(NAME)).textValue();
|
||||
String el = chainNode.get(VALUE).textValue();
|
||||
LiteFlowChainELBuilder chainELBuilder = LiteFlowChainELBuilder.createChain().setChainName(chainName);
|
||||
LiteFlowChainELBuilder chainELBuilder = LiteFlowChainELBuilder.createChain().setChainId(chainId);
|
||||
chainELBuilder.setEL(el).build();
|
||||
}
|
||||
|
||||
|
@ -230,10 +238,10 @@ public class ParserHelper {
|
|||
*/
|
||||
public static void parseOneChainEl(Element e) {
|
||||
//构建chainBuilder
|
||||
String chainName = e.attributeValue(NAME);
|
||||
String chainId = Optional.ofNullable(e.attributeValue(ID)).orElse(e.attributeValue(NAME));
|
||||
String text = e.getText();
|
||||
String el = RegexUtil.removeComments(text);
|
||||
LiteFlowChainELBuilder chainELBuilder = LiteFlowChainELBuilder.createChain().setChainName(chainName);
|
||||
LiteFlowChainELBuilder chainELBuilder = LiteFlowChainELBuilder.createChain().setChainId(chainId);
|
||||
chainELBuilder.setEL(el).build();
|
||||
}
|
||||
|
||||
|
@ -253,15 +261,10 @@ public class ParserHelper {
|
|||
return elStr;
|
||||
}
|
||||
|
||||
String text = Pattern.compile(REGEX_COMMENT)
|
||||
return Pattern.compile(REGEX_COMMENT)
|
||||
.matcher(elStr)
|
||||
//移除注释
|
||||
.replaceAll(CharSequenceUtil.EMPTY)
|
||||
//移除字符串中的空格
|
||||
.replaceAll(CharSequenceUtil.SPACE, CharSequenceUtil.EMPTY);
|
||||
|
||||
// 移除所有换行符
|
||||
return StrUtil.removeAllLineBreaks(text);
|
||||
.replaceAll(CharSequenceUtil.EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue