mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-05-14 12:12:08 +08:00
Merge tag 'v2.6.8' of https://gitee.com/sikadai/liteFlow into v2.6.8
This commit is contained in:
@@ -17,14 +17,23 @@ public class LiteFlowChainBuilder {
|
||||
|
||||
private Chain chain;
|
||||
|
||||
//声明这个变量,而不是用chain.getConditionList的目的,是为了辅助平滑加载
|
||||
//虽然FlowBus里面的map都是CopyOnWrite类型的,但是在buildCondition的时候,为了平滑加载,所以不能事先把chain.getConditionList给设为空List
|
||||
//所以在这里做一个缓存,等conditionList全部build完毕后,再去一次性替换chain里面的conditionList
|
||||
private final List<Condition> conditionList;
|
||||
|
||||
public static LiteFlowChainBuilder createChain(){
|
||||
return new LiteFlowChainBuilder();
|
||||
}
|
||||
|
||||
public LiteFlowChainBuilder(){
|
||||
chain = new Chain();
|
||||
conditionList = 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);
|
||||
@@ -41,6 +50,7 @@ public class LiteFlowChainBuilder {
|
||||
}
|
||||
|
||||
public void build(){
|
||||
this.chain.setConditionList(this.conditionList);
|
||||
FlowBus.addChain(this.chain);
|
||||
}
|
||||
|
||||
@@ -49,29 +59,29 @@ public class LiteFlowChainBuilder {
|
||||
//对于then来说,相邻的2个then会合并成一个condition
|
||||
//对于when来说,相同组的when会合并成一个condition,不同组的when还是会拆开
|
||||
if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_PRE)) {
|
||||
this.chain.getConditionList().add(new PreCondition(condition));
|
||||
this.conditionList.add(new PreCondition(condition));
|
||||
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_THEN)) {
|
||||
if (this.chain.getConditionList().size() >= 1 &&
|
||||
CollectionUtil.getLast(this.chain.getConditionList()) instanceof ThenCondition) {
|
||||
CollectionUtil.getLast(this.chain.getConditionList()).getNodeList().addAll(condition.getNodeList());
|
||||
if (this.conditionList.size() >= 1 &&
|
||||
CollectionUtil.getLast(this.conditionList) instanceof ThenCondition) {
|
||||
CollectionUtil.getLast(this.conditionList).getNodeList().addAll(condition.getNodeList());
|
||||
} else {
|
||||
this.chain.getConditionList().add(new ThenCondition(condition));
|
||||
this.conditionList.add(new ThenCondition(condition));
|
||||
}
|
||||
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_WHEN)) {
|
||||
if (this.chain.getConditionList().size() > 1 &&
|
||||
CollectionUtil.getLast(this.chain.getConditionList()) instanceof WhenCondition &&
|
||||
CollectionUtil.getLast(this.chain.getConditionList()).getGroup().equals(condition.getGroup())) {
|
||||
CollectionUtil.getLast(this.chain.getConditionList()).getNodeList().addAll(condition.getNodeList());
|
||||
if (this.conditionList.size() > 1 &&
|
||||
CollectionUtil.getLast(this.conditionList) instanceof WhenCondition &&
|
||||
CollectionUtil.getLast(this.conditionList).getGroup().equals(condition.getGroup())) {
|
||||
CollectionUtil.getLast(this.conditionList).getNodeList().addAll(condition.getNodeList());
|
||||
} else {
|
||||
this.chain.getConditionList().add(new WhenCondition(condition));
|
||||
this.conditionList.add(new WhenCondition(condition));
|
||||
}
|
||||
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY)) {
|
||||
this.chain.getConditionList().add(new FinallyCondition(condition));
|
||||
this.conditionList.add(new FinallyCondition(condition));
|
||||
}
|
||||
|
||||
//每一次build之后,对conditionList进行排序,pre最前面,finally最后
|
||||
//这里为什么要排序,因为在声明的时候,哪怕有人不把pre放最前,finally放最后,但最终也要确保是正确的顺序
|
||||
CollectionUtil.sort(this.chain.getConditionList(), (o1, o2) -> {
|
||||
CollectionUtil.sort(this.conditionList, (o1, o2) -> {
|
||||
if (o1.getConditionType().equals(ConditionTypeEnum.TYPE_PRE) || o2.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY)){
|
||||
return -1;
|
||||
} else if (o2.getConditionType().equals(ConditionTypeEnum.TYPE_PRE) || o1.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY)){
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.yomahub.liteflow.builder;
|
||||
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.entity.data.DataBus;
|
||||
import com.yomahub.liteflow.entity.flow.Node;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.exception.NodeBuildException;
|
||||
@@ -19,10 +20,31 @@ public class LiteFlowNodeBuilder {
|
||||
return new LiteFlowNodeBuilder();
|
||||
}
|
||||
|
||||
public static LiteFlowNodeBuilder createCommonNode(){
|
||||
return new LiteFlowNodeBuilder(NodeTypeEnum.COMMON);
|
||||
}
|
||||
|
||||
public static LiteFlowNodeBuilder createCommonCondNode(){
|
||||
return new LiteFlowNodeBuilder(NodeTypeEnum.COMMON);
|
||||
}
|
||||
|
||||
public static LiteFlowNodeBuilder createScriptNode(){
|
||||
return new LiteFlowNodeBuilder(NodeTypeEnum.SCRIPT);
|
||||
}
|
||||
|
||||
public static LiteFlowNodeBuilder createScriptCondNode(){
|
||||
return new LiteFlowNodeBuilder(NodeTypeEnum.COND_SCRIPT);
|
||||
}
|
||||
|
||||
public LiteFlowNodeBuilder() {
|
||||
this.node = new Node();
|
||||
}
|
||||
|
||||
public LiteFlowNodeBuilder(NodeTypeEnum type) {
|
||||
this.node = new Node();
|
||||
this.node.setType(type);
|
||||
}
|
||||
|
||||
public LiteFlowNodeBuilder setId(String nodeId) {
|
||||
this.node.setId(nodeId);
|
||||
return this;
|
||||
@@ -57,6 +79,11 @@ public class LiteFlowNodeBuilder {
|
||||
}
|
||||
|
||||
public void build() {
|
||||
//这里也是一个防御性编程
|
||||
//如果单独用builder进行构建的话,那么flow.xml不一定存在,不存在则不会进行FlowExecutor的init,也就不会进行DataBus.init
|
||||
//所以这里多加一步,DataBus.init()事实上只会执行一遍,不会因为之前执行了,重复执行。因为里面有判断
|
||||
DataBus.init();
|
||||
|
||||
try {
|
||||
if (this.node.getType().equals(NodeTypeEnum.COMMON)) {
|
||||
FlowBus.addCommonNode(this.node.getId(), this.node.getName(), this.node.getClazz());
|
||||
|
||||
@@ -64,9 +64,14 @@ public class FlowExecutor {
|
||||
* FlowExecutor的初始化化方式,主要用于parse规则文件
|
||||
*/
|
||||
public void init() {
|
||||
if (ObjectUtil.isNull(liteflowConfig) || StrUtil.isBlank(liteflowConfig.getRuleSource())) {
|
||||
if (ObjectUtil.isNull(liteflowConfig)) {
|
||||
throw new ConfigErrorException("config error, please check liteflow config property");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(liteflowConfig.getRuleSource())){
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> sourceRulePathList = Lists.newArrayList(liteflowConfig.getRuleSource().split(",|;"));
|
||||
|
||||
FlowParser parser = null;
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.yomahub.liteflow.script.ScriptExecutorFactory;
|
||||
import com.yomahub.liteflow.script.exception.ScriptSpiException;
|
||||
import com.yomahub.liteflow.util.CopyOnWriteHashMap;
|
||||
import com.yomahub.liteflow.util.SpringAware;
|
||||
import org.checkerframework.checker.units.qual.C;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.SerializationUtils;
|
||||
@@ -61,14 +62,18 @@ public class FlowBus {
|
||||
return chainMap.get(id);
|
||||
}
|
||||
|
||||
public static void addChain(Chain chain) {
|
||||
if (chainMap.containsKey(chain.getChainName()) && CollectionUtil.isEmpty(chain.getConditionList())){
|
||||
chainMap.get(chain.getChainName()).setConditionList(chain.getConditionList());
|
||||
}else{
|
||||
chainMap.put(chain.getChainName(), chain);
|
||||
//这一方法主要用于第一阶段chain的预装载
|
||||
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);
|
||||
}
|
||||
|
||||
public static boolean containChain(String chainId) {
|
||||
return chainMap.containsKey(chainId);
|
||||
}
|
||||
@@ -172,7 +177,6 @@ public class FlowBus {
|
||||
}catch (ScriptSpiException ignored){}
|
||||
}
|
||||
|
||||
//目前这种方式刷新不完全平滑
|
||||
public static void refreshFlowMetaData(FlowParserTypeEnum type, String content) throws Exception {
|
||||
if (type.equals(FlowParserTypeEnum.TYPE_XML)) {
|
||||
new LocalXmlFlowParser().parse(content);
|
||||
|
||||
@@ -78,7 +78,7 @@ public abstract class JsonFlowParser extends FlowParser {
|
||||
//先在元数据里放上chain
|
||||
chainArray.forEach(o -> {
|
||||
JSONObject innerJsonObject = (JSONObject)o;
|
||||
FlowBus.addChain(new Chain(innerJsonObject.getString("name")));
|
||||
FlowBus.addChain(innerJsonObject.getString("name"));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ public abstract class XmlFlowParser extends FlowParser {
|
||||
List<Element> chainList = document.getRootElement().elements("chain");
|
||||
|
||||
//先在元数据里放上chain
|
||||
chainList.forEach(e -> FlowBus.addChain(new Chain(e.attributeValue("name"))));
|
||||
chainList.forEach(e -> FlowBus.addChain(e.attributeValue("name")));
|
||||
});
|
||||
|
||||
for (Document document : documentList) {
|
||||
|
||||
@@ -45,6 +45,8 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
@@ -56,27 +58,25 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
*
|
||||
* @author Paul.Sandoz@Oracle.Com
|
||||
* @author pavel.bucek@oracle.com
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class CopyOnWriteHashMap<K,V> implements Map<K,V> {
|
||||
volatile Map<K, V> view;
|
||||
public class CopyOnWriteHashMap<K,V> extends ConcurrentHashMap<K,V> {
|
||||
|
||||
private Map<K, V> duplicate(Map<K, V> original) {
|
||||
Map<K, V> result = new HashMap();
|
||||
volatile ConcurrentHashMap<K, V> view;
|
||||
|
||||
private ConcurrentHashMap<K, V> duplicate(ConcurrentHashMap<K, V> original) {
|
||||
// SUBTLETY: note that original.entrySet() grabs the entire contents of the original Map in a
|
||||
// single call. This means that if the original map is Thread-safe or another CopyOnWriteHashMap,
|
||||
// we can safely iterate over the list of entries.
|
||||
for (Map.Entry<K, V> entry : original.entrySet()) {
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return result;
|
||||
return new ConcurrentHashMap<>(original);
|
||||
}
|
||||
|
||||
public CopyOnWriteHashMap(Map<K, V> that) {
|
||||
public CopyOnWriteHashMap(ConcurrentHashMap<K, V> that) {
|
||||
this.view = duplicate(that);
|
||||
}
|
||||
|
||||
public CopyOnWriteHashMap() {
|
||||
this(new HashMap<K, V>());
|
||||
this(new ConcurrentHashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,7 +114,7 @@ public class CopyOnWriteHashMap<K,V> implements Map<K,V> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
public KeySetView<K,V> keySet() {
|
||||
return view.keySet();
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ public class CopyOnWriteHashMap<K,V> implements Map<K,V> {
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
synchronized (this) {
|
||||
Map<K, V> newCore = duplicate(view);
|
||||
ConcurrentHashMap<K, V> newCore = duplicate(view);
|
||||
V result = newCore.put(key, value);
|
||||
view = newCore; // volatile write
|
||||
return result;
|
||||
@@ -159,18 +159,17 @@ public class CopyOnWriteHashMap<K,V> implements Map<K,V> {
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
synchronized (this) {
|
||||
Map<K, V> newCore = duplicate(view);
|
||||
ConcurrentHashMap<K, V> newCore = duplicate(view);
|
||||
V result = newCore.remove(key);
|
||||
view = newCore; // volatile write
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> t) {
|
||||
synchronized (this) {
|
||||
Map<K, V> newCore = duplicate(view);
|
||||
ConcurrentHashMap<K, V> newCore = duplicate(view);
|
||||
newCore.putAll(t);
|
||||
view = newCore; // volatile write
|
||||
}
|
||||
@@ -179,8 +178,7 @@ public class CopyOnWriteHashMap<K,V> implements Map<K,V> {
|
||||
@Override
|
||||
public void clear() {
|
||||
synchronized (this) {
|
||||
Map<K, V> newCore = new HashMap<K, V>();
|
||||
view = newCore; // volatile write
|
||||
view = new ConcurrentHashMap<>(); // volatile write
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
@@ -25,15 +26,16 @@ import java.util.concurrent.ExecutorService;
|
||||
@Import(SpringAware.class)
|
||||
public class LiteflowExecutorAutoConfiguration {
|
||||
|
||||
//这里参数加上这2个为了先行注入
|
||||
@Bean("whenExecutors")
|
||||
public ExecutorService executorService(LiteflowConfig liteflowConfig) {
|
||||
public ExecutorService executorService(SpringAware springAware, LiteflowConfig liteflowConfig) {
|
||||
return ExecutorHelper.loadInstance().buildExecutor();
|
||||
}
|
||||
|
||||
//为什么要注释掉这个@Bean?
|
||||
//LiteFlowExecutorPoolShutdown这个类会在spring上下文移除这个bean的时候执行,也就是应用被停止或者kill的时候
|
||||
//这个类主要用于卸载掉线程池,会等待线程池中的线程执行完,再卸载掉,相当于一个钩子
|
||||
//但这段代码在实际中并没有太多用户,就算结束掉应用进程时很多公司也会优雅停机。就显得这段代码很鸡肋
|
||||
//但这段代码在实际中并没有太多用处,就算结束掉应用进程时很多公司也会优雅停机。就显得这段代码很鸡肋
|
||||
//之所以注释掉,是因为在单元测试中,每一个testcase结束时都会调这个方法。
|
||||
//当异步线程配置超时的时候。由于这个方法会去关闭掉线程池,会导致单元测试在所有一起运行时(单个运行没有问题)会出错
|
||||
//按理说这个方法会等待线程池里的全部线程执行完再销毁,但是事实上在单元测试中的确会报错。具体原因还没深究,由于这个类比较鸡肋,就干脆不注册了。
|
||||
|
||||
@@ -35,13 +35,9 @@ public class LiteflowMainAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public FlowExecutor flowExecutor(LiteflowConfig liteflowConfig) {
|
||||
if (StrUtil.isNotBlank(liteflowConfig.getRuleSource())) {
|
||||
FlowExecutor flowExecutor = new FlowExecutor();
|
||||
flowExecutor.setLiteflowConfig(liteflowConfig);
|
||||
return flowExecutor;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
FlowExecutor flowExecutor = new FlowExecutor();
|
||||
flowExecutor.setLiteflowConfig(liteflowConfig);
|
||||
return flowExecutor;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
liteflow.enable=true
|
||||
liteflow.print-banner=true
|
||||
liteflow.rule-source=config/flow.xml
|
||||
liteflow.zk-node=/lite-flow/flow
|
||||
liteflow.slot-size=1024
|
||||
liteflow.thread-executor-class=com.yomahub.liteflow.thread.LiteFlowDefaultExecutorBuilder
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* springboot环境下pre节点和finally节点的测试
|
||||
* springboot环境最普通的例子测试
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.4
|
||||
*/
|
||||
@@ -30,9 +30,8 @@ public class BaseSpringbootTest extends BaseTest {
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
//测试普通的pre和finally节点
|
||||
@Test
|
||||
public void testPreAndFinally1() throws Exception{
|
||||
public void testBase() throws Exception{
|
||||
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.yomahub.liteflow.test.builder;
|
||||
|
||||
import com.yomahub.liteflow.builder.LiteFlowChainBuilder;
|
||||
import com.yomahub.liteflow.builder.LiteFlowConditionBuilder;
|
||||
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.entity.data.DefaultSlot;
|
||||
import com.yomahub.liteflow.entity.data.LiteflowResponse;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
//基于builder模式的单元测试
|
||||
//这里只是最基本的builder模式的测试,只是为了验证在springboot模式下的正常性
|
||||
//更详细的builder模式测试用例会单独拉testcase去做
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = BuilderSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.builder.cmp"})
|
||||
public class BuilderSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
//基于普通组件的builder模式测试
|
||||
@Test
|
||||
public void testBuilder() throws Exception{
|
||||
LiteFlowNodeBuilder.createNode().setId("a")
|
||||
.setName("组件A")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp.ACmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("b")
|
||||
.setName("组件B")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp.BCmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("c")
|
||||
.setName("组件C")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp.CCmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("d")
|
||||
.setName("组件D")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp.DCmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("e")
|
||||
.setName("组件E")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp.ECmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("f")
|
||||
.setName("组件F")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp.FCmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("g")
|
||||
.setName("组件G")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp.GCmp")
|
||||
.build();
|
||||
|
||||
|
||||
LiteFlowChainBuilder.createChain().setChainName("chain2").setCondition(
|
||||
LiteFlowConditionBuilder.createThenCondition().setValue("c,d").build()
|
||||
).build();
|
||||
|
||||
LiteFlowChainBuilder.createChain().setChainName("chain1").setCondition(
|
||||
LiteFlowConditionBuilder.createThenCondition().setValue("a,b").build()
|
||||
).setCondition(
|
||||
LiteFlowConditionBuilder.createWhenCondition().setValue("e(f|g|chain2)").build()
|
||||
).build();
|
||||
|
||||
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
public class ACmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
public class BCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
public class CCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
public class DCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("DCmp executed!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeCondComponent;
|
||||
|
||||
public class ECmp extends NodeCondComponent {
|
||||
|
||||
@Override
|
||||
public String processCond() throws Exception {
|
||||
System.out.println("ECmp executed!");
|
||||
return "chain2";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
public class FCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("FCmp executed!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
public class GCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("GCmp executed!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -45,8 +45,7 @@ public class FlowExecutorSpringBootTest extends BaseTest {
|
||||
|
||||
@Test(expected = ConfigErrorException.class)
|
||||
public void testConfigErrorException() {
|
||||
LiteflowConfig config = context.getBean(LiteflowConfig.class);
|
||||
config.setRuleSource("");
|
||||
flowExecutor.setLiteflowConfig(null);
|
||||
flowExecutor.init();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.yomahub.liteflow.test.monitor;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.entity.data.DefaultSlot;
|
||||
import com.yomahub.liteflow.entity.data.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* springboot环境最普通的例子测试
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.4
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/monitor/application.properties")
|
||||
@SpringBootTest(classes = MonitorSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.monitor.cmp"})
|
||||
public class MonitorSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testMonitor() throws Exception{
|
||||
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
|
||||
Thread.sleep(20000);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.monitor.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@Component("a")
|
||||
public class ACmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(new Random().nextInt(2000));
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.monitor.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@Component("b")
|
||||
public class BCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(new Random().nextInt(2000));
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.monitor.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@Component("c")
|
||||
public class CCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
try {
|
||||
Thread.sleep(new Random().nextInt(2000));
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,10 +22,9 @@ import javax.annotation.Resource;
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/parser/application-json.properties")
|
||||
@SpringBootTest(classes = LFParserJsonSpringbootTest.class)
|
||||
@SpringBootTest(classes = JsonParserSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.parser.cmp"})
|
||||
public class LFParserJsonSpringbootTest extends BaseTest {
|
||||
public class JsonParserSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.yomahub.liteflow.test.parser;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.entity.data.DefaultSlot;
|
||||
import com.yomahub.liteflow.entity.data.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/parser/application-springEL.properties")
|
||||
@SpringBootTest(classes = SpringELSupportSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
public class SpringELSupportSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
//测试springEL的解析情况
|
||||
@Test
|
||||
public void testSpringELParser() {
|
||||
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
||||
@@ -22,10 +22,9 @@ import javax.annotation.Resource;
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/parser/application-xml.properties")
|
||||
@SpringBootTest(classes = LFParserXmlSpringbootTest.class)
|
||||
@SpringBootTest(classes = XmlParserSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.parser.cmp"})
|
||||
public class LFParserXmlSpringbootTest extends BaseTest {
|
||||
public class XmlParserSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
@@ -22,10 +22,9 @@ import javax.annotation.Resource;
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/parser/application-yml.properties")
|
||||
@SpringBootTest(classes = LFParserYmlSpringbootTest.class)
|
||||
@SpringBootTest(classes = YmlParserSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.parser.cmp"})
|
||||
public class LFParserYmlSpringbootTest extends BaseTest {
|
||||
public class YmlParserSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
@@ -17,10 +17,6 @@ public class ACmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
String str = this.getSlot().getRequestData();
|
||||
if(StrUtil.isNotBlank(str) && str.equals("exception")) {
|
||||
throw new FlowSystemException("chain execute execption");
|
||||
}
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
liteflow.rule-source=monitor/flow.xml
|
||||
liteflow.monitor.enable-log=true
|
||||
liteflow.monitor.queue-limit=200
|
||||
liteflow.monitor.delay=5000
|
||||
liteflow.monitor.period=5000
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<chain name="chain1">
|
||||
<then value="a"/>
|
||||
<when value="b,c"/>
|
||||
</chain>
|
||||
|
||||
</flow>
|
||||
@@ -0,0 +1 @@
|
||||
liteflow.rule-source=parser/**/*.xml
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<nodes>
|
||||
<node id="a" class="com.yomahub.liteflow.test.parser.cmp.ACmp"/>
|
||||
<node id="b" class="com.yomahub.liteflow.test.parser.cmp.BCmp"/>
|
||||
<node id="c" class="com.yomahub.liteflow.test.parser.cmp.CCmp"/>
|
||||
<node id="d" class="com.yomahub.liteflow.test.parser.cmp.DCmp"/>
|
||||
<node id="e" class="com.yomahub.liteflow.test.parser.cmp.ECmp"/>
|
||||
<node id="f" class="com.yomahub.liteflow.test.parser.cmp.FCmp"/>
|
||||
<node id="g" class="com.yomahub.liteflow.test.parser.cmp.GCmp"/>
|
||||
</nodes>
|
||||
|
||||
<chain name="chain1">
|
||||
<then value="a,c"/>
|
||||
<when value="b,d,e(f|g)"/>
|
||||
<then value="chain2"/>
|
||||
</chain>
|
||||
|
||||
<chain name="chain2">
|
||||
<then value="c,g,f"/>
|
||||
</chain>
|
||||
</flow>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
|
||||
<chain name="chain1">
|
||||
<then value="a,c"/>
|
||||
<when value="b,d,e(f|g)"/>
|
||||
<then value="chain2"/>
|
||||
</chain>
|
||||
</flow>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<chain name="chain2">
|
||||
<then value="c,g,f"/>
|
||||
</chain>
|
||||
</flow>
|
||||
Reference in New Issue
Block a user