diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowChainBuilder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowChainBuilder.java index 16d3b931e..ed904adcd 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowChainBuilder.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowChainBuilder.java @@ -3,8 +3,8 @@ package com.yomahub.liteflow.builder; import cn.hutool.core.collection.CollectionUtil; import com.yomahub.liteflow.enums.ConditionTypeEnum; import com.yomahub.liteflow.flow.FlowBus; -import com.yomahub.liteflow.flow.condition.*; import com.yomahub.liteflow.flow.element.Chain; +import com.yomahub.liteflow.flow.element.condition.*; import java.util.ArrayList; import java.util.List; @@ -18,11 +18,18 @@ public class LiteFlowChainBuilder { private Chain chain; + //这是主体的Condition,不包含前置和后置 //声明这个变量,而不是用chain.getConditionList的目的,是为了辅助平滑加载 //虽然FlowBus里面的map都是CopyOnWrite类型的,但是在buildCondition的时候,为了平滑加载,所以不能事先把chain.getConditionList给设为空List //所以在这里做一个缓存,等conditionList全部build完毕后,再去一次性替换chain里面的conditionList private final List conditionList; + //前置处理Condition,用来区别主体的Condition + private final List preConditionList; + + //后置处理Condition,用来区别主体的Condition + private final List finallyConditionList; + public static LiteFlowChainBuilder createChain(){ return new LiteFlowChainBuilder(); } @@ -30,6 +37,8 @@ public class LiteFlowChainBuilder { public LiteFlowChainBuilder(){ chain = new Chain(); conditionList = new ArrayList<>(); + preConditionList = new ArrayList<>(); + finallyConditionList = new ArrayList<>(); } //在parser中chain的build是2段式的,因为涉及到依赖问题,以前是递归parser @@ -52,6 +61,8 @@ public class LiteFlowChainBuilder { public void build(){ this.chain.setConditionList(this.conditionList); + this.chain.setPreConditionList(this.preConditionList); + this.chain.setFinallyConditionList(this.finallyConditionList); FlowBus.addChain(this.chain); } @@ -60,35 +71,24 @@ public class LiteFlowChainBuilder { //对于then来说,相邻的2个then会合并成一个condition //对于when来说,相同组的when会合并成一个condition,不同组的when还是会拆开 if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_PRE)) { - this.conditionList.add(new PreCondition(condition)); + 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).getNodeList().addAll(condition.getNodeList()); } else { - this.conditionList.add(new ThenCondition(condition)); + this.conditionList.add(condition); } } else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_WHEN)) { - if (this.conditionList.size() > 1 && + 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.conditionList.add(new WhenCondition(condition)); + this.conditionList.add(condition); } - } else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY)) { - this.conditionList.add(new FinallyCondition(condition)); } - - //每一次build之后,对conditionList进行排序,pre最前面,finally最后 - //这里为什么要排序,因为在声明的时候,哪怕有人不把pre放最前,finally放最后,但最终也要确保是正确的顺序 - 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)){ - return 1; - } - return 0; - }); } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowConditionBuilder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowConditionBuilder.java index 2899fa9fb..ae92a68f6 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowConditionBuilder.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowConditionBuilder.java @@ -5,7 +5,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.flow.element.Chain; -import com.yomahub.liteflow.flow.condition.Condition; +import com.yomahub.liteflow.flow.element.condition.*; import com.yomahub.liteflow.builder.entity.ExecutableEntity; import com.yomahub.liteflow.flow.element.Node; import com.yomahub.liteflow.enums.ConditionTypeEnum; @@ -28,29 +28,38 @@ public class LiteFlowConditionBuilder { protected Condition condition; public static LiteFlowConditionBuilder createCondition(ConditionTypeEnum conditionType){ - return new LiteFlowConditionBuilder(conditionType); + switch (conditionType){ + case TYPE_THEN: + return createThenCondition(); + case TYPE_WHEN: + return createWhenCondition(); + case TYPE_PRE: + return createPreCondition(); + case TYPE_FINALLY: + return createFinallyCondition(); + default: + return null; + } } public static LiteFlowConditionBuilder createThenCondition(){ - return new LiteFlowConditionBuilder(ConditionTypeEnum.TYPE_THEN); + return new LiteFlowConditionBuilder(new ThenCondition()); } public static LiteFlowWhenConditionBuilder createWhenCondition(){ - return new LiteFlowWhenConditionBuilder(ConditionTypeEnum.TYPE_WHEN); + return new LiteFlowWhenConditionBuilder(new WhenCondition()); } public static LiteFlowConditionBuilder createPreCondition(){ - return new LiteFlowConditionBuilder(ConditionTypeEnum.TYPE_PRE); + return new LiteFlowConditionBuilder(new PreCondition()); } public static LiteFlowConditionBuilder createFinallyCondition(){ - return new LiteFlowConditionBuilder(ConditionTypeEnum.TYPE_FINALLY); + return new LiteFlowConditionBuilder(new FinallyCondition()); } - public LiteFlowConditionBuilder(ConditionTypeEnum conditionType){ - this.condition = new Condition(); - this.condition.setConditionType(conditionType); - this.condition.setNodeList(new ArrayList<>()); + public LiteFlowConditionBuilder(Condition condition){ + this.condition = condition; } public LiteFlowConditionBuilder setValue(String value){ diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowWhenConditionBuilder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowWhenConditionBuilder.java index 5e71ec8dd..c1215c150 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowWhenConditionBuilder.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowWhenConditionBuilder.java @@ -3,6 +3,7 @@ package com.yomahub.liteflow.builder; import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.common.LocalDefaultFlowConstant; import com.yomahub.liteflow.enums.ConditionTypeEnum; +import com.yomahub.liteflow.flow.element.condition.Condition; /** * WhenCondition基于代码形式的组装器 @@ -12,8 +13,8 @@ import com.yomahub.liteflow.enums.ConditionTypeEnum; */ public class LiteFlowWhenConditionBuilder extends LiteFlowConditionBuilder{ - public LiteFlowWhenConditionBuilder(ConditionTypeEnum conditionType) { - super(conditionType); + public LiteFlowWhenConditionBuilder(Condition condition) { + super(condition); } public LiteFlowWhenConditionBuilder setErrorResume(boolean errorResume){ diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/prop/ChainPropBean.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/prop/ChainPropBean.java new file mode 100644 index 000000000..2d8165069 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/prop/ChainPropBean.java @@ -0,0 +1,93 @@ +package com.yomahub.liteflow.builder.prop; + +import com.yomahub.liteflow.enums.ConditionTypeEnum; + +/** + * 构建 chain 的中间属性 + */ +public class ChainPropBean { + + /** + * 执行规则 + */ + String condValueStr; + + /** + * 分组 + */ + String group; + + /** + * 是否抛出异常 + */ + String errorResume; + + /** + * 满足任意条件,执行完成 + */ + String any; + + /** + * 指定线程池 + */ + String threadExecutorClass; + + /** + * chain 类型 + */ + ConditionTypeEnum conditionType; + + public String getCondValueStr() { + return condValueStr; + } + + public ChainPropBean setCondValueStr(String condValueStr) { + this.condValueStr = condValueStr; + return this; + } + + public String getGroup() { + return group; + } + + public ChainPropBean setGroup(String group) { + this.group = group; + return this; + } + + public String getErrorResume() { + return errorResume; + } + + public ChainPropBean setErrorResume(String errorResume) { + this.errorResume = errorResume; + return this; + } + + public String getAny() { + return any; + } + + public ChainPropBean setAny(String any) { + this.any = any; + return this; + } + + public String getThreadExecutorClass() { + return threadExecutorClass; + } + + public ChainPropBean setThreadExecutorClass(String threadExecutorClass) { + this.threadExecutorClass = threadExecutorClass; + return this; + } + + public ConditionTypeEnum getConditionType() { + return conditionType; + } + + public ChainPropBean setConditionType(ConditionTypeEnum conditionType) { + this.conditionType = conditionType; + return this; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/prop/NodePropBean.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/prop/NodePropBean.java new file mode 100644 index 000000000..ac674c2c5 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/prop/NodePropBean.java @@ -0,0 +1,91 @@ +package com.yomahub.liteflow.builder.prop; + +/** + * 构建 node 的中间属性 + */ +public class NodePropBean { + + /** + * id + */ + String id; + + /** + * 名称 + */ + String name; + + /** + * 类 + */ + String clazz; + + /** + * 脚本 + */ + String script; + + /** + * 类型 + */ + String type; + + /** + * 脚本存放位置 + */ + String file; + + public String getId() { + return id; + } + + public NodePropBean setId(String id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public NodePropBean setName(String name) { + this.name = name; + return this; + } + + public String getClazz() { + return clazz; + } + + public NodePropBean setClazz(String clazz) { + this.clazz = clazz; + return this; + } + + public String getScript() { + return script; + } + + public NodePropBean setScript(String script) { + this.script = script; + return this; + } + + public String getType() { + return type; + } + + public NodePropBean setType(String type) { + this.type = type; + return this; + } + + public String getFile() { + return file; + } + + public NodePropBean setFile(String file) { + this.file = file; + return this; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java b/liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java new file mode 100644 index 000000000..768f1c37b --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java @@ -0,0 +1,39 @@ +package com.yomahub.liteflow.common; + +/** + * Chain 常量 + * + * @author tangkc + */ +public interface ChainConstant { + + String CHAIN = "chain"; + + String FLOW = "flow"; + + String NODES = "nodes"; + + String NODE = "node"; + + String ID = "id"; + + String _CLASS = "class"; + + String FILE = "file"; + + String NAME = "name"; + + String VALUE = "value"; + + String ERROR_RESUME = "errorResume"; + + String GROUP = "group"; + + String ANY = "any"; + + String THREAD_EXECUTOR_CLASS = "threadExecutorClass"; + + String CONDITION = "condition"; + + String TYPE = "type"; +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java index 74c5b1554..d716bc8e3 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java @@ -385,8 +385,6 @@ public class FlowExecutor { String errorMsg = StrUtil.format("[{}]:couldn't find chain with the id[{}]", slot.getRequestId(), chainId); throw new ChainNotFoundException(errorMsg); } - // 执行前置 - chain.executePre(slotIndex); // 执行chain chain.execute(slotIndex); } catch (ChainEndException e) { @@ -401,15 +399,6 @@ public class FlowExecutor { } slot.setException(e); } finally { - try{ - if (ObjectUtil.isNotNull(chain)){ - chain.executeFinally(slotIndex); - } - }catch (Exception e){ - String errMsg = StrUtil.format("[{}]:an exception occurred during the finally Component execution in chain[{}]", slot.getRequestId(), chain.getChainName()); - LOG.error(errMsg, e); - } - if (!isInnerChain) { slot.printStep(); DataBus.releaseSlot(slotIndex); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java index 4588d7386..65003e0ec 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java @@ -18,6 +18,7 @@ import com.yomahub.liteflow.enums.NodeTypeEnum; import com.yomahub.liteflow.property.LiteflowConfig; import com.yomahub.liteflow.property.LiteflowConfigGetter; import com.yomahub.liteflow.spi.holder.CmpAroundAspectHolder; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -303,4 +304,12 @@ public abstract class NodeComponent{ public String getChainName(){ return getSlot().getChainName(); } + + public String getDisplayName(){ + if(StringUtils.isEmpty(this.name)){ + return this.nodeId; + }else { + return this.nodeId + "(" + this.name + ")"; + } + } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptComponent.java index 7ceb8572c..9e8aa1405 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptComponent.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptComponent.java @@ -19,7 +19,7 @@ public class ScriptComponent extends NodeComponent{ } public void loadScript(String script) { - log.info("load script for component[{}]", getNodeId()); + log.info("load script for component[{}][{}]", getNodeId(),getDisplayName()); ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script); } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ExecuteTypeEnum.java b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ExecuteTypeEnum.java index 64285ee58..78ca48683 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ExecuteTypeEnum.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ExecuteTypeEnum.java @@ -12,5 +12,5 @@ package com.yomahub.liteflow.enums; * @author Bryan.Zhang */ public enum ExecuteTypeEnum { - CHAIN,NODE + CHAIN,CONDITION,NODE } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java index 56a4728c1..2a1c886d2 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java @@ -33,6 +33,7 @@ import com.yomahub.liteflow.spi.holder.ContextAwareHolder; import com.yomahub.liteflow.spi.local.LocalContextAware; import com.yomahub.liteflow.util.CopyOnWriteHashMap; import com.yomahub.liteflow.util.LiteFlowProxyUtil; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -160,7 +161,7 @@ public class FlowBus { nodeMap.put(nodeId, node); } catch (Exception e) { - String error = StrUtil.format("component[{}] register error", cmpClazz.getName()); + String error = StrUtil.format("component[{}][{}] register error", cmpClazz.getName(), StringUtils.isEmpty(name)?nodeId:nodeId+"("+name+")"); LOG.error(error, e); throw new ComponentCannotRegisterException(error); } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/FinallyCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/FinallyCondition.java deleted file mode 100644 index af4f04d75..000000000 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/FinallyCondition.java +++ /dev/null @@ -1,21 +0,0 @@ -/** - *

Title: liteflow

- *

Description: 轻量级的组件式流程框架

- * @author Bryan.Zhang - * @email weenyc31@163.com - * @Date 2020/4/1 - */ -package com.yomahub.liteflow.flow.condition; - -/** - * 前置Condition - * @author Bryan.Zhang - * @since 2.6.4 - */ -public class FinallyCondition extends Condition { - - public FinallyCondition(Condition condition){ - super(condition.getNodeList()); - super.setConditionType(condition.getConditionType()); - } -} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/PreCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/PreCondition.java deleted file mode 100644 index 2ede59f73..000000000 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/PreCondition.java +++ /dev/null @@ -1,21 +0,0 @@ -/** - *

Title: liteflow

- *

Description: 轻量级的组件式流程框架

- * @author Bryan.Zhang - * @email weenyc31@163.com - * @Date 2020/4/1 - */ -package com.yomahub.liteflow.flow.condition; - -/** - * 前置Condition - * @author Bryan.Zhang - * @since 2.6.4 - */ -public class PreCondition extends Condition { - - public PreCondition(Condition condition){ - super(condition.getNodeList()); - super.setConditionType(condition.getConditionType()); - } -} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/ThenCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/ThenCondition.java deleted file mode 100644 index 9d327118a..000000000 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/ThenCondition.java +++ /dev/null @@ -1,20 +0,0 @@ -/** - *

Title: liteflow

- *

Description: 轻量级的组件式流程框架

- * @author Bryan.Zhang - * @email weenyc31@163.com - * @Date 2020/4/1 - */ -package com.yomahub.liteflow.flow.condition; - -/** - * 串行器 - * @author Bryan.Zhang - */ -public class ThenCondition extends Condition { - - public ThenCondition(Condition condition){ - super(condition.getNodeList()); - super.setConditionType(condition.getConditionType()); - } -} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/WhenCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/WhenCondition.java deleted file mode 100644 index 6a61ea69f..000000000 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/WhenCondition.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - *

Title: liteflow

- *

Description: 轻量级的组件式流程框架

- * @author Bryan.Zhang - * @email weenyc31@163.com - * @Date 2020/4/1 - */ -package com.yomahub.liteflow.flow.condition; - -/** - * 并行器 - * @author Bryan.Zhang - */ -public class WhenCondition extends Condition { - - public WhenCondition(Condition condition) { - super(condition.getNodeList()); - super.setConditionType(condition.getConditionType()); - super.setGroup(condition.getGroup()); - super.setErrorResume(condition.isErrorResume()); - super.setAny(condition.isAny()); - super.setThreadExecutorClass(condition.getThreadExecutorClass()); - } - -} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Chain.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Chain.java index 529eec75f..5bce26970 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Chain.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Chain.java @@ -9,33 +9,16 @@ package com.yomahub.liteflow.flow.element; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.exception.ChainEndException; import com.yomahub.liteflow.slot.DataBus; import com.yomahub.liteflow.slot.Slot; -import com.yomahub.liteflow.flow.parallel.CompletableFutureTimeout; -import com.yomahub.liteflow.flow.parallel.ParallelSupplier; -import com.yomahub.liteflow.flow.parallel.WhenFutureObj; -import com.yomahub.liteflow.enums.ConditionTypeEnum; import com.yomahub.liteflow.enums.ExecuteTypeEnum; import com.yomahub.liteflow.exception.FlowSystemException; -import com.yomahub.liteflow.exception.WhenExecuteException; -import com.yomahub.liteflow.flow.condition.Condition; -import com.yomahub.liteflow.flow.condition.ThenCondition; -import com.yomahub.liteflow.flow.condition.WhenCondition; -import com.yomahub.liteflow.property.LiteflowConfig; -import com.yomahub.liteflow.property.LiteflowConfigGetter; -import com.yomahub.liteflow.thread.ExecutorHelper; +import com.yomahub.liteflow.flow.element.condition.Condition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.function.Predicate; -import java.util.stream.Collectors; /** * chain对象,实现可执行器 @@ -48,8 +31,15 @@ public class Chain implements Executable { private String chainName; + //主体Condition private List conditionList = new ArrayList<>(); + //前置处理Condition,用来区别主体的Condition + private List preConditionList = new ArrayList<>(); + + //后置处理Condition,用来区别主体的Condition + private List finallyConditionList = new ArrayList<>(); + public Chain(String chainName){ this.chainName = chainName; } @@ -61,6 +51,57 @@ public class Chain implements Executable { this.conditionList = conditionList; } + //执行chain的主方法 + @Override + public void execute(Integer slotIndex) throws Exception { + if (CollUtil.isEmpty(conditionList)) { + throw new FlowSystemException("no conditionList in this chain[" + chainName + "]"); + } + try { + //执行前置 + this.executePre(slotIndex); + //执行主体Condition + for (Condition condition : conditionList) { + condition.execute(slotIndex); + } + }catch (ChainEndException e){ + //这里单独catch ChainEndException是因为ChainEndException是用户自己setIsEnd抛出的异常 + //是属于正常逻辑,所以会在FlowExecutor中判断。这里不作为异常处理 + throw e; + }catch (Exception e){ + //这里事先取到exception set到slot里,为了方便finally取到exception + Slot slot = DataBus.getSlot(slotIndex); + 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); + } + } + + @Override + public ExecuteTypeEnum getExecuteType() { + return ExecuteTypeEnum.CHAIN; + } + + @Override + public String getExecuteName() { + return chainName; + } + public List getConditionList() { return conditionList; } @@ -77,160 +118,19 @@ public class Chain implements Executable { this.chainName = chainName; } - //执行chain的主方法 - @Override - public void execute(Integer slotIndex) throws Exception { - if (CollUtil.isEmpty(conditionList)) { - throw new FlowSystemException("no conditionList in this chain[" + chainName + "]"); - } - for (Condition condition : conditionList) { - if (condition instanceof ThenCondition) { - for (Executable executableItem : condition.getNodeList()) { - executableItem.execute(slotIndex); - } - } else if (condition instanceof WhenCondition) { - executeAsyncCondition((WhenCondition) condition, slotIndex); - } - } + public List getPreConditionList() { + return preConditionList; } - // 执行pre节点 - public void executePre(Integer slotIndex) throws Exception { - doExecuteForPointConditionType(slotIndex, ConditionTypeEnum.TYPE_PRE); + public void setPreConditionList(List preConditionList) { + this.preConditionList = preConditionList; } - public void executeFinally(Integer slotIndex) throws Exception { - doExecuteForPointConditionType(slotIndex, ConditionTypeEnum.TYPE_FINALLY); + public List getFinallyConditionList() { + return finallyConditionList; } - // 执行指定的conditionType的节点 - private void doExecuteForPointConditionType(Integer slotIndex, ConditionTypeEnum conditionTypeEnum) throws Exception { - //先把指定condition类型的节点过滤出来 - List conditions =filterCondition(conditionTypeEnum); - for (Condition condition : conditions){ - for(Executable executableItem : condition.getNodeList()){ - executableItem.execute(slotIndex); - } - } - } - - // 根据节点condition类型过去出节点列表 - private List filterCondition(ConditionTypeEnum conditionTypeEnum) { - assert conditionTypeEnum != null; - return conditionList.stream().filter(condition -> - condition.getConditionType().equals(conditionTypeEnum)).collect(Collectors.toList()); - } - - @Override - public ExecuteTypeEnum getExecuteType() { - return ExecuteTypeEnum.CHAIN; - } - - @Override - public String getExecuteName() { - return chainName; - } - - //使用线程池执行when并发流程 - //这块涉及到挺多的多线程逻辑,所以注释比较详细,看到这里的童鞋可以仔细阅读 - private void executeAsyncCondition(WhenCondition condition, Integer slotIndex) throws Exception{ - Slot slot = DataBus.getSlot(slotIndex); - - //此方法其实只会初始化一次Executor,不会每次都会初始化。Executor是唯一的 - ExecutorService parallelExecutor = ExecutorHelper.loadInstance().buildWhenExecutor(condition.getThreadExecutorClass()); - - //获得liteflow的参数 - LiteflowConfig liteflowConfig = LiteflowConfigGetter.get(); - - //定义是否中断参数 - //这里为什么要定义成数组呢,因为后面lambda要用到,根据final不能修改引用的原则,这里用了数组对象 - final boolean[] interrupted = {false}; - - //这里主要是做了封装CompletableFuture对象,用lumbda表达式做了很多事情,这句代码要仔细理清 - //1.根据condition.getNodeList()的集合进行流处理,用map进行把executable对象转换成List> - //2.在转的过程中,套入CompletableFutureTimeout方法进行超时判断,如果超时则用WhenFutureObj.timeOut返回超时的对象 - //3.第2个参数是主要的本体CompletableFuture,传入了ParallelSupplier和线程池对象 - List> completableFutureList = condition.getNodeList().stream().filter(executable -> { - try { - return executable.isAccess(slotIndex); - }catch (Exception e){ - LOG.error("there was an error when executing the when component isAccess",e); - return false; - } - }).map(executable -> CompletableFutureTimeout.completeOnTimeout( - WhenFutureObj.timeOut(executable.getExecuteName()), - CompletableFuture.supplyAsync(new ParallelSupplier(executable, slotIndex), parallelExecutor), - liteflowConfig.getWhenMaxWaitSeconds(), - TimeUnit.SECONDS - )).collect(Collectors.toList()); - - - CompletableFuture resultCompletableFuture; - - //这里判断执行方式 - //如果any为false,说明这些异步任务全部执行好或者超时,才返回 - //如果any为true,说明这些异步任务只要任意一个执行完成,就返回 - if(condition.isAny()){ - //把这些CompletableFuture通过anyOf合成一个CompletableFuture - resultCompletableFuture = CompletableFuture.anyOf(completableFutureList.toArray(new CompletableFuture[]{})); - }else{ - //把这些CompletableFuture通过allOf合成一个CompletableFuture - resultCompletableFuture = CompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[]{})); - } - - try { - //进行执行,这句执行完后,就意味着所有的任务要么执行完毕,要么超时返回 - resultCompletableFuture.get(); - } catch (InterruptedException | ExecutionException e) { - LOG.error("there was an error when executing the CompletableFuture",e); - interrupted[0] = true; - } - - //拿到已经完成的CompletableFuture - //如果any为false,那么所有任务都已经完成 - //如果any为true,那么这里拿到的是第一个完成的任务 - //这里过滤和转换一起用lumbda做了 - List allCompletableWhenFutureObjList = completableFutureList.stream().filter(f -> { - //过滤出已经完成的,没完成的就直接终止 - if (f.isDone()){ - return true; - }else{ - f.cancel(true); - return false; - } - }).map(f -> { - try { - return f.get(); - } catch (InterruptedException | ExecutionException e) { - interrupted[0] = true; - return null; - } - }).collect(Collectors.toList()); - - //判断超时,上面已经拿到了所有已经完成的CompletableFuture - //那我们只要过滤出超时的CompletableFuture - List timeOutWhenFutureObjList = allCompletableWhenFutureObjList.stream().filter(WhenFutureObj::isTimeout).collect(Collectors.toList()); - - //输出超时信息 - timeOutWhenFutureObjList.forEach(whenFutureObj -> - LOG.warn("requestId [{}] executing thread has reached max-wait-seconds, thread canceled.Execute-item: [{}]", slot.getRequestId(), whenFutureObj.getExecutorName())); - - //当配置了errorResume = false,出现interrupted或者!f.get()的情况,将抛出WhenExecuteException - if (!condition.isErrorResume()) { - if (interrupted[0]) { - throw new WhenExecuteException(StrUtil.format("requestId [{}] when execute interrupted. errorResume [false].", slot.getRequestId())); - } - - //循环判断CompletableFuture的返回值,如果异步执行失败,则抛出相应的业务异常 - for(WhenFutureObj whenFutureObj : allCompletableWhenFutureObjList){ - if (!whenFutureObj.isSuccess()){ - LOG.info(StrUtil.format("requestId [{}] when-executor[{}] execute failed. errorResume [false].", whenFutureObj.getExecutorName(), slot.getRequestId())); - throw whenFutureObj.getEx(); - } - } - } else if (interrupted[0]) { - // 这里由于配置了errorResume,所以只打印warn日志 - LOG.warn("requestId [{}] executing when condition timeout , but ignore with errorResume.", slot.getRequestId()); - } + public void setFinallyConditionList(List finallyConditionList) { + this.finallyConditionList = finallyConditionList; } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java index 1114b67f2..b5246068d 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java @@ -126,7 +126,7 @@ public class Node implements Executable,Cloneable{ if (instance.isAccess()) { //根据配置判断是否打印执行中的日志 if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())){ - LOG.info("[{}]:[O]start component[{}] execution",slot.getRequestId(),instance.getClass().getSimpleName()); + LOG.info("[{}]:[O]start component[{}][{}] execution",slot.getRequestId(),instance.getClass().getSimpleName(),instance.getDisplayName()); } //这里开始进行重试的逻辑和主逻辑的运行 @@ -135,12 +135,12 @@ public class Node implements Executable,Cloneable{ nodeExecutor.execute(instance); //如果组件覆盖了isEnd方法,或者在在逻辑中主要调用了setEnd(true)的话,流程就会立马结束 if (instance.isEnd()) { - String errorInfo = StrUtil.format("[{}]:component[{}] lead the chain to end", slot.getRequestId(), instance.getClass().getSimpleName()); + String errorInfo = StrUtil.format("[{}]:[{}] lead the chain to end", slot.getRequestId(), instance.getClass().getSimpleName(),instance.getDisplayName()); throw new ChainEndException(errorInfo); } } else { if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())){ - LOG.info("[{}]:[X]skip component[{}] execution", slot.getRequestId(), instance.getClass().getSimpleName()); + LOG.info("[{}]:[X]skip component[{}][{}] execution", slot.getRequestId(), instance.getClass().getSimpleName(),instance.getDisplayName()); } } } catch (ChainEndException e){ diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/Condition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/Condition.java similarity index 74% rename from liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/Condition.java rename to liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/Condition.java index 8b945432c..95fdf12ff 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/condition/Condition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/Condition.java @@ -5,24 +5,25 @@ * @email weenyc31@163.com * @Date 2020/4/1 */ -package com.yomahub.liteflow.flow.condition; +package com.yomahub.liteflow.flow.element.condition; +import cn.hutool.core.collection.CollUtil; import com.yomahub.liteflow.common.LocalDefaultFlowConstant; +import com.yomahub.liteflow.enums.ExecuteTypeEnum; +import com.yomahub.liteflow.exception.FlowSystemException; import com.yomahub.liteflow.flow.element.Executable; import com.yomahub.liteflow.enums.ConditionTypeEnum; +import java.util.ArrayList; import java.util.List; /** * 里面包含了when或者then * @author Bryan.Zhang */ -public class Condition { +public abstract class Condition implements Executable{ - //condition 类型 参数:ConditionTypeEnum 包含:then when - private ConditionTypeEnum conditionType; - - private List nodeList; + private List nodeList = new ArrayList<>(); //只在when类型下有效,以区分当when调用链调用失败时是否继续往下执行 默认false不继续执行 private boolean errorResume = false; @@ -32,13 +33,18 @@ public class Condition { //只在when类型下有效,为true的话说明在多个并行节点下,任意一个成功,整个when就成功 private boolean any = false; + // when单独的线程池名称 private String threadExecutorClass; - public Condition(List nodeList) { - this.nodeList = nodeList; + @Override + public ExecuteTypeEnum getExecuteType() { + return ExecuteTypeEnum.CONDITION; } - public Condition() { + + @Override + public String getExecuteName() { + return this.getExecuteType().name(); } public List getNodeList() { @@ -65,13 +71,7 @@ public class Condition { this.group = group; } - public ConditionTypeEnum getConditionType() { - return conditionType; - } - - public void setConditionType(ConditionTypeEnum conditionType) { - this.conditionType = conditionType; - } + public abstract ConditionTypeEnum getConditionType(); public boolean isAny() { return any; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/FinallyCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/FinallyCondition.java new file mode 100644 index 000000000..0aff46229 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/FinallyCondition.java @@ -0,0 +1,31 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.flow.element.condition; + +import com.yomahub.liteflow.enums.ConditionTypeEnum; +import com.yomahub.liteflow.flow.element.Executable; + +/** + * 前置Condition + * @author Bryan.Zhang + * @since 2.6.4 + */ +public class FinallyCondition extends Condition { + + @Override + public void execute(Integer slotIndex) throws Exception { + for(Executable executableItem : this.getNodeList()){ + executableItem.execute(slotIndex); + } + } + + @Override + public ConditionTypeEnum getConditionType() { + return ConditionTypeEnum.TYPE_FINALLY; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/PreCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/PreCondition.java new file mode 100644 index 000000000..0579445b3 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/PreCondition.java @@ -0,0 +1,31 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.flow.element.condition; + +import com.yomahub.liteflow.enums.ConditionTypeEnum; +import com.yomahub.liteflow.flow.element.Executable; + +/** + * 前置Condition + * @author Bryan.Zhang + * @since 2.6.4 + */ +public class PreCondition extends Condition { + + @Override + public void execute(Integer slotIndex) throws Exception { + for(Executable executableItem : this.getNodeList()){ + executableItem.execute(slotIndex); + } + } + + @Override + public ConditionTypeEnum getConditionType() { + return ConditionTypeEnum.TYPE_PRE; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ThenCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ThenCondition.java new file mode 100644 index 000000000..bf8e1b77d --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ThenCondition.java @@ -0,0 +1,29 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.flow.element.condition; + +import com.yomahub.liteflow.enums.ConditionTypeEnum; +import com.yomahub.liteflow.flow.element.Executable; + +/** + * 串行器 + * @author Bryan.Zhang + */ +public class ThenCondition extends Condition { + @Override + public ConditionTypeEnum getConditionType() { + return ConditionTypeEnum.TYPE_THEN; + } + + @Override + public void execute(Integer slotIndex) throws Exception { + for (Executable executableItem : this.getNodeList()) { + executableItem.execute(slotIndex); + } + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java new file mode 100644 index 000000000..ec0660a5e --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java @@ -0,0 +1,151 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.flow.element.condition; + +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.enums.ConditionTypeEnum; +import com.yomahub.liteflow.exception.WhenExecuteException; +import com.yomahub.liteflow.flow.parallel.CompletableFutureTimeout; +import com.yomahub.liteflow.flow.parallel.ParallelSupplier; +import com.yomahub.liteflow.flow.parallel.WhenFutureObj; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.slot.DataBus; +import com.yomahub.liteflow.slot.Slot; +import com.yomahub.liteflow.thread.ExecutorHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * 并行器 + * @author Bryan.Zhang + */ +public class WhenCondition extends Condition { + + private final Logger LOG = LoggerFactory.getLogger(this.getClass()); + + + @Override + public void execute(Integer slotIndex) throws Exception { + executeAsyncCondition(slotIndex); + } + + @Override + public ConditionTypeEnum getConditionType() { + return ConditionTypeEnum.TYPE_WHEN; + } + + //使用线程池执行when并发流程 + //这块涉及到挺多的多线程逻辑,所以注释比较详细,看到这里的童鞋可以仔细阅读 + private void executeAsyncCondition(Integer slotIndex) throws Exception{ + Slot slot = DataBus.getSlot(slotIndex); + + //此方法其实只会初始化一次Executor,不会每次都会初始化。Executor是唯一的 + ExecutorService parallelExecutor = ExecutorHelper.loadInstance().buildWhenExecutor(this.getThreadExecutorClass()); + + //获得liteflow的参数 + LiteflowConfig liteflowConfig = LiteflowConfigGetter.get(); + + //定义是否中断参数 + //这里为什么要定义成数组呢,因为后面lambda要用到,根据final不能修改引用的原则,这里用了数组对象 + final boolean[] interrupted = {false}; + + //这里主要是做了封装CompletableFuture对象,用lumbda表达式做了很多事情,这句代码要仔细理清 + //1.根据condition.getNodeList()的集合进行流处理,用map进行把executable对象转换成List> + //2.在转的过程中,套入CompletableFutureTimeout方法进行超时判断,如果超时则用WhenFutureObj.timeOut返回超时的对象 + //3.第2个参数是主要的本体CompletableFuture,传入了ParallelSupplier和线程池对象 + List> completableFutureList = this.getNodeList().stream().filter(executable -> { + try { + return executable.isAccess(slotIndex); + }catch (Exception e){ + LOG.error("there was an error when executing the when component isAccess",e); + return false; + } + }).map(executable -> CompletableFutureTimeout.completeOnTimeout( + WhenFutureObj.timeOut(executable.getExecuteName()), + CompletableFuture.supplyAsync(new ParallelSupplier(executable, slotIndex), parallelExecutor), + liteflowConfig.getWhenMaxWaitSeconds(), + TimeUnit.SECONDS + )).collect(Collectors.toList()); + + + CompletableFuture resultCompletableFuture; + + //这里判断执行方式 + //如果any为false,说明这些异步任务全部执行好或者超时,才返回 + //如果any为true,说明这些异步任务只要任意一个执行完成,就返回 + if(this.isAny()){ + //把这些CompletableFuture通过anyOf合成一个CompletableFuture + resultCompletableFuture = CompletableFuture.anyOf(completableFutureList.toArray(new CompletableFuture[]{})); + }else{ + //把这些CompletableFuture通过allOf合成一个CompletableFuture + resultCompletableFuture = CompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[]{})); + } + + try { + //进行执行,这句执行完后,就意味着所有的任务要么执行完毕,要么超时返回 + resultCompletableFuture.get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("there was an error when executing the CompletableFuture",e); + interrupted[0] = true; + } + + //拿到已经完成的CompletableFuture + //如果any为false,那么所有任务都已经完成 + //如果any为true,那么这里拿到的是第一个完成的任务 + //这里过滤和转换一起用lumbda做了 + List allCompletableWhenFutureObjList = completableFutureList.stream().filter(f -> { + //过滤出已经完成的,没完成的就直接终止 + if (f.isDone()){ + return true; + }else{ + f.cancel(true); + return false; + } + }).map(f -> { + try { + return f.get(); + } catch (InterruptedException | ExecutionException e) { + interrupted[0] = true; + return null; + } + }).collect(Collectors.toList()); + + //判断超时,上面已经拿到了所有已经完成的CompletableFuture + //那我们只要过滤出超时的CompletableFuture + List timeOutWhenFutureObjList = allCompletableWhenFutureObjList.stream().filter(WhenFutureObj::isTimeout).collect(Collectors.toList()); + + //输出超时信息 + timeOutWhenFutureObjList.forEach(whenFutureObj -> + LOG.warn("requestId [{}] executing thread has reached max-wait-seconds, thread canceled.Execute-item: [{}]", slot.getRequestId(), whenFutureObj.getExecutorName())); + + //当配置了errorResume = false,出现interrupted或者!f.get()的情况,将抛出WhenExecuteException + if (!this.isErrorResume()) { + if (interrupted[0]) { + throw new WhenExecuteException(StrUtil.format("requestId [{}] when execute interrupted. errorResume [false].", slot.getRequestId())); + } + + //循环判断CompletableFuture的返回值,如果异步执行失败,则抛出相应的业务异常 + for(WhenFutureObj whenFutureObj : allCompletableWhenFutureObjList){ + if (!whenFutureObj.isSuccess()){ + LOG.info(StrUtil.format("requestId [{}] when-executor[{}] execute failed. errorResume [false].", whenFutureObj.getExecutorName(), slot.getRequestId())); + throw whenFutureObj.getEx(); + } + } + } else if (interrupted[0]) { + // 这里由于配置了errorResume,所以只打印warn日志 + LOG.warn("requestId [{}] executing when condition timeout , but ignore with errorResume.", slot.getRequestId()); + } + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/executor/NodeExecutor.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/executor/NodeExecutor.java index 4f863b05a..f8b211cce 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/executor/NodeExecutor.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/executor/NodeExecutor.java @@ -50,7 +50,7 @@ public abstract class NodeExecutor { //执行重试逻辑 - 子类通过实现该方法进行重试逻辑的控制 protected void retry(NodeComponent instance, int currentRetryCount) throws Exception { Slot slot = DataBus.getSlot(instance.getSlotIndex()); - LOG.info("[{}]:component[{}] performs {} retry", slot.getRequestId(), instance.getNodeId(), currentRetryCount + 1); + LOG.info("[{}]:component[{}][{}] performs {} retry", slot.getRequestId(), instance.getNodeId(),instance.getDisplayName(), currentRetryCount + 1); //执行业务逻辑的主要入口 instance.execute(); } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/BaseFlowParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/BaseFlowParser.java new file mode 100644 index 000000000..064c643f3 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/BaseFlowParser.java @@ -0,0 +1,94 @@ +package com.yomahub.liteflow.parser; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.builder.LiteFlowChainBuilder; +import com.yomahub.liteflow.builder.LiteFlowConditionBuilder; +import com.yomahub.liteflow.builder.LiteFlowNodeBuilder; +import com.yomahub.liteflow.builder.prop.ChainPropBean; +import com.yomahub.liteflow.builder.prop.NodePropBean; +import com.yomahub.liteflow.enums.ConditionTypeEnum; +import com.yomahub.liteflow.enums.NodeTypeEnum; +import com.yomahub.liteflow.exception.EmptyConditionValueException; +import com.yomahub.liteflow.exception.NodeTypeNotSupportException; +import com.yomahub.liteflow.exception.NotSupportConditionException; + +/** + * 基类,用于存放通用方法 + * + * @author tangkc + */ +public abstract class BaseFlowParser implements FlowParser { + + /** + * 构建 node + * + * @param nodePropBean 构建 node 的中间属性 + */ + public void buildNode(NodePropBean nodePropBean) { + String id = nodePropBean.getId(); + String name = nodePropBean.getName(); + String clazz = nodePropBean.getClazz(); + String script = nodePropBean.getScript(); + String type = nodePropBean.getType(); + String file = nodePropBean.getFile(); + + //初始化type + if (StrUtil.isBlank(type)) { + type = NodeTypeEnum.COMMON.getCode(); + } + + //检查nodeType是不是规定的类型 + NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getEnumByCode(type); + if (ObjectUtil.isNull(nodeTypeEnum)) { + throw new NodeTypeNotSupportException(StrUtil.format("type [{}] is not support", type)); + } + + //进行node的build过程 + LiteFlowNodeBuilder.createNode().setId(id).setName(name).setClazz(clazz).setType(nodeTypeEnum).setScript(script).setFile(file).build(); + } + + + /** + * 构建 chain + * + * @param chainPropBean 构建 chain 的中间属性 + * @param chainBuilder chainBuilder + */ + public void buildChain(ChainPropBean chainPropBean + , LiteFlowChainBuilder chainBuilder) { + String condValueStr = chainPropBean.getCondValueStr(); + String group = chainPropBean.getGroup(); + String errorResume = chainPropBean.getErrorResume(); + String any = chainPropBean.getAny(); + String threadExecutorClass = chainPropBean.getThreadExecutorClass(); + ConditionTypeEnum conditionType = chainPropBean.getConditionType(); + + if (ObjectUtil.isNull(conditionType)) { + throw new NotSupportConditionException("ConditionType is not supported"); + } + + if (StrUtil.isBlank(condValueStr)) { + throw new EmptyConditionValueException("Condition value cannot be empty"); + } + + //如果是when类型的话,有特殊化参数要设置,只针对于when的 + if (conditionType.equals(ConditionTypeEnum.TYPE_WHEN)) { + chainBuilder.setCondition( + LiteFlowConditionBuilder.createWhenCondition() + .setErrorResume(errorResume) + .setGroup(group) + .setAny(any) + .setThreadExecutorClass(threadExecutorClass) + .setValue(condValueStr) + .build() + ).build(); + } else { + chainBuilder.setCondition( + LiteFlowConditionBuilder.createCondition(conditionType) + .setValue(condValueStr) + .build() + ).build(); + } + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/JsonFlowParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/JsonFlowParser.java index 8a95c1c79..e102ff4e7 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/JsonFlowParser.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/JsonFlowParser.java @@ -2,24 +2,35 @@ package com.yomahub.liteflow.parser; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.Feature; import com.yomahub.liteflow.builder.LiteFlowChainBuilder; -import com.yomahub.liteflow.builder.LiteFlowConditionBuilder; -import com.yomahub.liteflow.builder.LiteFlowNodeBuilder; +import com.yomahub.liteflow.builder.prop.ChainPropBean; +import com.yomahub.liteflow.builder.prop.NodePropBean; import com.yomahub.liteflow.enums.ConditionTypeEnum; -import com.yomahub.liteflow.enums.NodeTypeEnum; -import com.yomahub.liteflow.exception.EmptyConditionValueException; -import com.yomahub.liteflow.exception.NodeTypeNotSupportException; -import com.yomahub.liteflow.exception.NotSupportConditionException; import com.yomahub.liteflow.flow.FlowBus; import com.yomahub.liteflow.spi.holder.ContextCmpInitHolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; + +import java.util.List; + +import static com.yomahub.liteflow.common.ChainConstant.ANY; +import static com.yomahub.liteflow.common.ChainConstant.CHAIN; +import static com.yomahub.liteflow.common.ChainConstant.CONDITION; +import static com.yomahub.liteflow.common.ChainConstant.ERROR_RESUME; +import static com.yomahub.liteflow.common.ChainConstant.FILE; +import static com.yomahub.liteflow.common.ChainConstant.FLOW; +import static com.yomahub.liteflow.common.ChainConstant.GROUP; +import static com.yomahub.liteflow.common.ChainConstant.ID; +import static com.yomahub.liteflow.common.ChainConstant.NAME; +import static com.yomahub.liteflow.common.ChainConstant.NODE; +import static com.yomahub.liteflow.common.ChainConstant.NODES; +import static com.yomahub.liteflow.common.ChainConstant.THREAD_EXECUTOR_CLASS; +import static com.yomahub.liteflow.common.ChainConstant.TYPE; +import static com.yomahub.liteflow.common.ChainConstant.VALUE; +import static com.yomahub.liteflow.common.ChainConstant._CLASS; /** * Json格式解析器 @@ -27,148 +38,123 @@ import java.util.*; * @author guodongqing * @since 2.5.0 */ -public abstract class JsonFlowParser implements FlowParser { +public abstract class JsonFlowParser extends BaseFlowParser { - private final Logger LOG = LoggerFactory.getLogger(JsonFlowParser.class); + private final Logger LOG = LoggerFactory.getLogger(JsonFlowParser.class); - public void parse(String content) throws Exception { - parse(ListUtil.toList(content)); - } + public void parse(String content) throws Exception { + parse(ListUtil.toList(content)); + } - @Override - public void parse(List contentList) throws Exception { - if (CollectionUtil.isEmpty(contentList)) { - return; - } + @Override + public void parse(List contentList) throws Exception { + if (CollectionUtil.isEmpty(contentList)) { + return; + } - List jsonObjectList = ListUtil.toList(); - for (String content : contentList) { - //把字符串原生转换为json对象,如果不加第二个参数OrderedField,会无序 - JSONObject flowJsonObject = JSONObject.parseObject(content, Feature.OrderedField); - jsonObjectList.add(flowJsonObject); - } + List jsonObjectList = ListUtil.toList(); + for (String content : contentList) { + //把字符串原生转换为json对象,如果不加第二个参数OrderedField,会无序 + JSONObject flowJsonObject = JSONObject.parseObject(content, Feature.OrderedField); + jsonObjectList.add(flowJsonObject); + } - parseJsonObject(jsonObjectList); - } + parseJsonObject(jsonObjectList); + } - //json格式,解析过程 - public void parseJsonObject(List flowJsonObjectList) throws Exception { - //在相应的环境下进行节点的初始化工作 - //在spring体系下会获得spring扫描后的节点,接入元数据 - //在非spring体系下是一个空实现,等于不做此步骤 - ContextCmpInitHolder.loadContextCmpInit().initCmp(); + //json格式,解析过程 + public void parseJsonObject(List flowJsonObjectList) throws Exception { + //在相应的环境下进行节点的初始化工作 + //在spring体系下会获得spring扫描后的节点,接入元数据 + //在非spring体系下是一个空实现,等于不做此步骤 + ContextCmpInitHolder.loadContextCmpInit().initCmp(); - //先在元数据里放上chain - //先放有一个好处,可以在parse的时候先映射到FlowBus的chainMap,然后再去解析 - //这样就不用去像之前的版本那样回归调用 - //同时也解决了不能循环依赖的问题 - flowJsonObjectList.forEach(jsonObject -> { - // 解析chain节点 - JSONArray chainArray = jsonObject.getJSONObject("flow").getJSONArray("chain"); + //先在元数据里放上chain + //先放有一个好处,可以在parse的时候先映射到FlowBus的chainMap,然后再去解析 + //这样就不用去像之前的版本那样回归调用 + //同时也解决了不能循环依赖的问题 + flowJsonObjectList.forEach(jsonObject -> { + // 解析chain节点 + JSONArray chainArray = jsonObject.getJSONObject(FLOW).getJSONArray(CHAIN); - //先在元数据里放上chain - chainArray.forEach(o -> { - JSONObject innerJsonObject = (JSONObject)o; - FlowBus.addChain(innerJsonObject.getString("name")); - }); - }); + //先在元数据里放上chain + chainArray.forEach(o -> { + JSONObject innerJsonObject = (JSONObject) o; + FlowBus.addChain(innerJsonObject.getString(NAME)); + }); + }); - for (JSONObject flowJsonObject : flowJsonObjectList) { - // 当存在节点定义时,解析node节点 - if (flowJsonObject.getJSONObject("flow").containsKey("nodes")){ - JSONArray nodeArrayList = flowJsonObject.getJSONObject("flow").getJSONObject("nodes").getJSONArray("node"); - String id, name, clazz, script, type, file; - for (int i = 0; i < nodeArrayList.size(); i++) { - JSONObject nodeObject = nodeArrayList.getJSONObject(i); - id = nodeObject.getString("id"); - name = nodeObject.getString("name"); - clazz = nodeObject.getString("class"); - type = nodeObject.getString("type"); - script = nodeObject.getString("value"); - file = nodeObject.getString("file"); + for (JSONObject flowJsonObject : flowJsonObjectList) { + // 当存在节点定义时,解析node节点 + if (flowJsonObject.getJSONObject(FLOW).containsKey(NODES)) { + JSONArray nodeArrayList = flowJsonObject.getJSONObject(FLOW).getJSONObject(NODES).getJSONArray(NODE); + String id, name, clazz, script, type, file; + for (int i = 0; i < nodeArrayList.size(); i++) { + JSONObject nodeObject = nodeArrayList.getJSONObject(i); + id = nodeObject.getString(ID); + name = nodeObject.getString(NAME); + clazz = nodeObject.getString(_CLASS); + type = nodeObject.getString(TYPE); + script = nodeObject.getString(VALUE); + file = nodeObject.getString(FILE); - //初始化type - if (StrUtil.isBlank(type)){ - type = NodeTypeEnum.COMMON.getCode(); - } + // 构建 node + NodePropBean nodePropBean = new NodePropBean() + .setId(id) + .setName(name) + .setClazz(clazz) + .setScript(script) + .setType(type) + .setFile(file); - //检查nodeType是不是规定的类型 - NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getEnumByCode(type); - if (ObjectUtil.isNull(nodeTypeEnum)){ - throw new NodeTypeNotSupportException(StrUtil.format("type [{}] is not support", type)); - } + buildNode(nodePropBean); + } + } - //进行node的build过程 - LiteFlowNodeBuilder.createNode().setId(id) - .setName(name) - .setClazz(clazz) - .setType(nodeTypeEnum) - .setScript(script) - .setFile(file) - .build(); - } - } - - //解析每一个chain - JSONArray chainArray = flowJsonObject.getJSONObject("flow").getJSONArray("chain"); - chainArray.forEach(o -> { - JSONObject jsonObject = (JSONObject)o; - parseOneChain(jsonObject); - }); - } - } - - /** - * 解析一个chain的过程 - */ - private void parseOneChain(JSONObject chainObject){ - String condValueStr; - ConditionTypeEnum conditionType; - String group; - String errorResume; - String any; - String threadExecutorClass; - - //构建chainBuilder - String chainName = chainObject.getString("name"); - LiteFlowChainBuilder chainBuilder = LiteFlowChainBuilder.createChain().setChainName(chainName); - - for (Object o : chainObject.getJSONArray("condition")) { - JSONObject condObject = (JSONObject) o; - conditionType = ConditionTypeEnum.getEnumByCode(condObject.getString("type")); - condValueStr = condObject.getString("value"); - errorResume = condObject.getString("errorResume"); - group = condObject.getString("group"); - any = condObject.getString("any"); - threadExecutorClass = condObject.getString("threadExecutorClass"); - - if (ObjectUtil.isNull(conditionType)){ - throw new NotSupportConditionException("ConditionType is not supported"); - } - - if (StrUtil.isBlank(condValueStr)) { - throw new EmptyConditionValueException("Condition value cannot be empty"); - } + //解析每一个chain + JSONArray chainArray = flowJsonObject.getJSONObject(FLOW).getJSONArray(CHAIN); + chainArray.forEach(o -> { + JSONObject jsonObject = (JSONObject) o; + parseOneChain(jsonObject); + }); + } + } - //如果是when类型的话,有特殊化参数要设置,只针对于when的 - if (conditionType.equals(ConditionTypeEnum.TYPE_WHEN)){ - chainBuilder.setCondition( - LiteFlowConditionBuilder.createWhenCondition() - .setErrorResume(errorResume) - .setGroup(group) - .setAny(any) - .setThreadExecutorClass(threadExecutorClass) - .setValue(condValueStr) - .build() - ).build(); - }else{ - chainBuilder.setCondition( - LiteFlowConditionBuilder.createCondition(conditionType) - .setValue(condValueStr) - .build() - ).build(); - } - } - } + /** + * 解析一个chain的过程 + */ + private void parseOneChain(JSONObject chainObject) { + String condValueStr; + ConditionTypeEnum conditionType; + String group; + String errorResume; + String any; + String threadExecutorClass; + + //构建chainBuilder + String chainName = chainObject.getString(NAME); + LiteFlowChainBuilder chainBuilder = LiteFlowChainBuilder.createChain().setChainName(chainName); + + for (Object o : chainObject.getJSONArray(CONDITION)) { + JSONObject condObject = (JSONObject) o; + conditionType = ConditionTypeEnum.getEnumByCode(condObject.getString(TYPE)); + condValueStr = condObject.getString(VALUE); + errorResume = condObject.getString(ERROR_RESUME); + group = condObject.getString(GROUP); + any = condObject.getString(ANY); + threadExecutorClass = condObject.getString(THREAD_EXECUTOR_CLASS); + + ChainPropBean chainPropBean = new ChainPropBean() + .setCondValueStr(condValueStr) + .setGroup(group) + .setErrorResume(errorResume) + .setAny(any) + .setThreadExecutorClass(threadExecutorClass) + .setConditionType(conditionType); + + // 构建 chain + buildChain(chainPropBean, chainBuilder); + } + } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java index 0388374fd..6bc8c6e49 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/XmlFlowParser.java @@ -3,13 +3,10 @@ package com.yomahub.liteflow.parser; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.builder.LiteFlowChainBuilder; -import com.yomahub.liteflow.builder.LiteFlowConditionBuilder; -import com.yomahub.liteflow.builder.LiteFlowNodeBuilder; +import com.yomahub.liteflow.builder.prop.ChainPropBean; +import com.yomahub.liteflow.builder.prop.NodePropBean; import com.yomahub.liteflow.enums.ConditionTypeEnum; -import com.yomahub.liteflow.enums.NodeTypeEnum; -import com.yomahub.liteflow.exception.*; import com.yomahub.liteflow.flow.FlowBus; import com.yomahub.liteflow.spi.holder.ContextCmpInitHolder; import org.dom4j.Document; @@ -17,14 +14,32 @@ import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import java.util.Iterator; import java.util.List; +import static com.yomahub.liteflow.common.ChainConstant.ANY; +import static com.yomahub.liteflow.common.ChainConstant.CHAIN; +import static com.yomahub.liteflow.common.ChainConstant.ERROR_RESUME; +import static com.yomahub.liteflow.common.ChainConstant.FILE; +import static com.yomahub.liteflow.common.ChainConstant.GROUP; +import static com.yomahub.liteflow.common.ChainConstant.ID; +import static com.yomahub.liteflow.common.ChainConstant.NAME; +import static com.yomahub.liteflow.common.ChainConstant.NODE; +import static com.yomahub.liteflow.common.ChainConstant.NODES; +import static com.yomahub.liteflow.common.ChainConstant.THREAD_EXECUTOR_CLASS; +import static com.yomahub.liteflow.common.ChainConstant.TYPE; +import static com.yomahub.liteflow.common.ChainConstant.VALUE; +import static com.yomahub.liteflow.common.ChainConstant._CLASS; + +; + /** * xml形式的解析器 + * * @author Bryan.Zhang */ -public abstract class XmlFlowParser implements FlowParser { +public abstract class XmlFlowParser extends BaseFlowParser { private final Logger LOG = LoggerFactory.getLogger(XmlFlowParser.class); @@ -32,6 +47,7 @@ public abstract class XmlFlowParser implements FlowParser { parse(ListUtil.toList(content)); } + @Override public void parse(List contentList) throws Exception { if (CollectionUtil.isEmpty(contentList)) { return; @@ -57,51 +73,42 @@ public abstract class XmlFlowParser implements FlowParser { //同时也解决了不能循环依赖的问题 documentList.forEach(document -> { // 解析chain节点 - List chainList = document.getRootElement().elements("chain"); + List chainList = document.getRootElement().elements(CHAIN); //先在元数据里放上chain - chainList.forEach(e -> FlowBus.addChain(e.attributeValue("name"))); + chainList.forEach(e -> FlowBus.addChain(e.attributeValue(NAME))); }); for (Document document : documentList) { Element rootElement = document.getRootElement(); - Element nodesElement = rootElement.element("nodes"); + Element nodesElement = rootElement.element(NODES); // 当存在节点定义时,解析node节点 - if (ObjectUtil.isNotNull(nodesElement)){ - List nodeList = nodesElement.elements("node"); + if (ObjectUtil.isNotNull(nodesElement)) { + List nodeList = nodesElement.elements(NODE); String id, name, clazz, type, script, file; for (Element e : nodeList) { - id = e.attributeValue("id"); - name = e.attributeValue("name"); - clazz = e.attributeValue("class"); - type = e.attributeValue("type"); + id = e.attributeValue(ID); + name = e.attributeValue(NAME); + clazz = e.attributeValue(_CLASS); + type = e.attributeValue(TYPE); script = e.getTextTrim(); - file = e.attributeValue("file"); + file = e.attributeValue(FILE); - //初始化type - if (StrUtil.isBlank(type)){ - type = NodeTypeEnum.COMMON.getCode(); - } - - //检查nodeType是不是规定的类型 - NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getEnumByCode(type); - if (ObjectUtil.isNull(nodeTypeEnum)){ - throw new NodeTypeNotSupportException(StrUtil.format("type [{}] is not support", type)); - } - - //进行node的build过程 - LiteFlowNodeBuilder.createNode().setId(id) + // 构建 node + NodePropBean nodePropBean = new NodePropBean() + .setId(id) .setName(name) .setClazz(clazz) - .setType(nodeTypeEnum) .setScript(script) - .setFile(file) - .build(); + .setType(type) + .setFile(file); + + buildNode(nodePropBean); } } //解析每一个chain - List chainList = rootElement.elements("chain"); + List chainList = rootElement.elements(CHAIN); chainList.forEach(this::parseOneChain); } } @@ -118,44 +125,29 @@ public abstract class XmlFlowParser implements FlowParser { ConditionTypeEnum conditionType; //构建chainBuilder - String chainName = e.attributeValue("name"); + String chainName = e.attributeValue(NAME); LiteFlowChainBuilder chainBuilder = LiteFlowChainBuilder.createChain().setChainName(chainName); for (Iterator it = e.elementIterator(); it.hasNext(); ) { Element condE = it.next(); conditionType = ConditionTypeEnum.getEnumByCode(condE.getName()); - condValueStr = condE.attributeValue("value"); - errorResume = condE.attributeValue("errorResume"); - group = condE.attributeValue("group"); - any = condE.attributeValue("any"); - threadExecutorClass = condE.attributeValue("threadExecutorClass"); + condValueStr = condE.attributeValue(VALUE); + errorResume = condE.attributeValue(ERROR_RESUME); + group = condE.attributeValue(GROUP); + any = condE.attributeValue(ANY); + threadExecutorClass = condE.attributeValue(THREAD_EXECUTOR_CLASS); - if (ObjectUtil.isNull(conditionType)){ - throw new NotSupportConditionException("ConditionType is not supported"); - } + ChainPropBean chainPropBean = new ChainPropBean() + .setCondValueStr(condValueStr) + .setGroup(group) + .setErrorResume(errorResume) + .setAny(any) + .setThreadExecutorClass(threadExecutorClass) + .setConditionType(conditionType); - if (StrUtil.isBlank(condValueStr)) { - throw new EmptyConditionValueException("Condition value cannot be empty"); - } - - //如果是when类型的话,有特殊化参数要设置,只针对于when的 - if (conditionType.equals(ConditionTypeEnum.TYPE_WHEN)){ - chainBuilder.setCondition( - LiteFlowConditionBuilder.createWhenCondition() - .setErrorResume(errorResume) - .setGroup(group) - .setAny(any) - .setThreadExecutorClass(threadExecutorClass) - .setValue(condValueStr) - .build() - ).build(); - }else{ - chainBuilder.setCondition( - LiteFlowConditionBuilder.createCondition(conditionType) - .setValue(condValueStr) - .build() - ).build(); - } + // 构建 chain + buildChain(chainPropBean, chainBuilder); } } + } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/YmlFlowParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/YmlFlowParser.java index 19fd5666b..f285a5e0f 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/YmlFlowParser.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/YmlFlowParser.java @@ -20,6 +20,7 @@ public abstract class YmlFlowParser extends JsonFlowParser{ private final Logger LOG = LoggerFactory.getLogger(YmlFlowParser.class); + @Override public void parse(String content) throws Exception{ parse(ListUtil.toList(content)); } diff --git a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/CmpExtendSpringbootTest.java b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/CmpExtendSpringbootTest.java new file mode 100644 index 000000000..f13627bd7 --- /dev/null +++ b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/CmpExtendSpringbootTest.java @@ -0,0 +1,39 @@ +package com.yomahub.liteflow.test.extend; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +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.7.1 + */ +@RunWith(SpringRunner.class) +@TestPropertySource(value = "classpath:/extend/application.properties") +@SpringBootTest(classes = CmpExtendSpringbootTest.class) +@EnableAutoConfiguration +@ComponentScan({"com.yomahub.liteflow.test.extend.cmp"}) +public class CmpExtendSpringbootTest extends BaseTest { + + @Resource + private FlowExecutor flowExecutor; + + @Test + public void testExtend() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + } + +} diff --git a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/ACmp.java b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/ACmp.java new file mode 100644 index 000000000..58ee70a52 --- /dev/null +++ b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/ACmp.java @@ -0,0 +1,24 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.extend.cmp; + +import com.yomahub.liteflow.annotation.LiteflowCmpDefine; +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import org.springframework.stereotype.Component; + +@Component("a") +@LiteflowCmpDefine +public class ACmp{ + + @LiteflowMethod(LiteFlowMethodEnum.PROCESS) + public void process(NodeComponent bindCmp) { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/BCmp.java b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/BCmp.java new file mode 100644 index 000000000..a2bcb708b --- /dev/null +++ b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/BCmp.java @@ -0,0 +1,26 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.extend.cmp; + +import com.yomahub.liteflow.annotation.LiteflowCmpDefine; +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import org.springframework.stereotype.Component; + +@Component("b") +@LiteflowCmpDefine +public class BCmp extends ParentCmp{ + + @LiteflowMethod(LiteFlowMethodEnum.PROCESS) + public void process(NodeComponent bindCmp) { + System.out.println("BCmp executed!"); + System.out.println(this.sayHi("jack")); + } + +} diff --git a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/CCmp.java b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/CCmp.java new file mode 100644 index 000000000..c95125f64 --- /dev/null +++ b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/CCmp.java @@ -0,0 +1,25 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.extend.cmp; + +import com.yomahub.liteflow.annotation.LiteflowCmpDefine; +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import org.springframework.stereotype.Component; + +@Component("c") +@LiteflowCmpDefine +public class CCmp{ + + @LiteflowMethod(LiteFlowMethodEnum.PROCESS) + public void process(NodeComponent bindCmp) { + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/ParentCmp.java b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/ParentCmp.java new file mode 100644 index 000000000..a739a2620 --- /dev/null +++ b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/extend/cmp/ParentCmp.java @@ -0,0 +1,10 @@ +package com.yomahub.liteflow.test.extend.cmp; + +import cn.hutool.core.util.StrUtil; + +public class ParentCmp { + + protected String sayHi(String name){ + return StrUtil.format("hi,{}",name); + } +} diff --git a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/LiteflowComponentSpringbootTest.java b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentSpringbootTest.java similarity index 86% rename from liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/LiteflowComponentSpringbootTest.java rename to liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentSpringbootTest.java index 0409ab133..43fa6a188 100644 --- a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/LiteflowComponentSpringbootTest.java +++ b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentSpringbootTest.java @@ -1,4 +1,4 @@ -package com.yomahub.liteflow.test.liteflowcomponent; +package com.yomahub.liteflow.test.lfCmpAnno; import com.yomahub.liteflow.core.FlowExecutor; import com.yomahub.liteflow.flow.LiteflowResponse; @@ -21,10 +21,10 @@ import org.springframework.test.context.junit4.SpringRunner; * @since 2.5.10 */ @RunWith(SpringRunner.class) -@TestPropertySource(value = "classpath:/liteflowComponent/application.properties") +@TestPropertySource(value = "classpath:/lfCmpAnno/application.properties") @SpringBootTest(classes = LiteflowComponentSpringbootTest.class) @EnableAutoConfiguration -@ComponentScan({"com.yomahub.liteflow.test.liteflowcomponent.cmp"}) +@ComponentScan({"com.yomahub.liteflow.test.lfCmpAnno.cmp"}) public class LiteflowComponentSpringbootTest extends BaseTest { @Autowired diff --git a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/ACmp.java b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java similarity index 92% rename from liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/ACmp.java rename to liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java index cbb4d4381..8081c7084 100644 --- a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/ACmp.java +++ b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java @@ -5,7 +5,7 @@ * @email weenyc31@163.com * @Date 2020/4/1 */ -package com.yomahub.liteflow.test.liteflowcomponent.cmp; +package com.yomahub.liteflow.test.lfCmpAnno.cmp; import com.yomahub.liteflow.annotation.LiteflowCmpDefine; import com.yomahub.liteflow.annotation.LiteflowComponent; diff --git a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/BCmp.java b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java similarity index 92% rename from liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/BCmp.java rename to liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java index dfab6f34b..30a7e689e 100644 --- a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/BCmp.java +++ b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java @@ -5,7 +5,7 @@ * @email weenyc31@163.com * @Date 2020/4/1 */ -package com.yomahub.liteflow.test.liteflowcomponent.cmp; +package com.yomahub.liteflow.test.lfCmpAnno.cmp; import com.yomahub.liteflow.annotation.LiteflowCmpDefine; import com.yomahub.liteflow.annotation.LiteflowComponent; diff --git a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/CCmp.java b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java similarity index 92% rename from liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/CCmp.java rename to liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java index 1f4fdd22f..6090b44fc 100644 --- a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/CCmp.java +++ b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java @@ -5,7 +5,7 @@ * @email weenyc31@163.com * @Date 2020/4/1 */ -package com.yomahub.liteflow.test.liteflowcomponent.cmp; +package com.yomahub.liteflow.test.lfCmpAnno.cmp; import com.yomahub.liteflow.annotation.LiteflowCmpDefine; import com.yomahub.liteflow.annotation.LiteflowComponent; diff --git a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/DCmp.java b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java similarity index 91% rename from liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/DCmp.java rename to liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java index 9f338fa01..967f00f33 100644 --- a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/liteflowComponent/cmp/DCmp.java +++ b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java @@ -5,7 +5,7 @@ * @email weenyc31@163.com * @Date 2020/4/1 */ -package com.yomahub.liteflow.test.liteflowcomponent.cmp; +package com.yomahub.liteflow.test.lfCmpAnno.cmp; import com.yomahub.liteflow.annotation.LiteflowCmpDefine; import com.yomahub.liteflow.annotation.LiteflowComponent; diff --git a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringbootTest.java b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringbootTest.java index 2fec1619b..35b109f2a 100644 --- a/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringbootTest.java +++ b/liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringbootTest.java @@ -61,4 +61,11 @@ public class PreAndFinallySpringbootTest extends BaseTest { Assert.assertFalse(response.isSuccess()); Assert.assertTrue(response.getContextBean().getData("hasEx")); } + + @Test + public void testPreAndFinally5() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg"); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals("p1==>p2==>p1==>p2==>a==>b==>c==>f1==>f2==>f1", response.getExecuteStepStrWithoutTime()); + } } diff --git a/liteflow-testcase-declare-component/src/test/resources/extend/application.properties b/liteflow-testcase-declare-component/src/test/resources/extend/application.properties new file mode 100644 index 000000000..7904a5796 --- /dev/null +++ b/liteflow-testcase-declare-component/src/test/resources/extend/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=extend/flow.xml \ No newline at end of file diff --git a/liteflow-testcase-declare-component/src/test/resources/extend/flow.xml b/liteflow-testcase-declare-component/src/test/resources/extend/flow.xml new file mode 100644 index 000000000..22870d94f --- /dev/null +++ b/liteflow-testcase-declare-component/src/test/resources/extend/flow.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/liteflow-testcase-declare-component/src/test/resources/lfCmpAnno/application.properties b/liteflow-testcase-declare-component/src/test/resources/lfCmpAnno/application.properties new file mode 100644 index 000000000..1085d3200 --- /dev/null +++ b/liteflow-testcase-declare-component/src/test/resources/lfCmpAnno/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=lfCmpAnno/flow.xml \ No newline at end of file diff --git a/liteflow-testcase-declare-component/src/test/resources/liteflowComponent/flow.xml b/liteflow-testcase-declare-component/src/test/resources/lfCmpAnno/flow.xml similarity index 100% rename from liteflow-testcase-declare-component/src/test/resources/liteflowComponent/flow.xml rename to liteflow-testcase-declare-component/src/test/resources/lfCmpAnno/flow.xml diff --git a/liteflow-testcase-declare-component/src/test/resources/liteflowComponent/application.properties b/liteflow-testcase-declare-component/src/test/resources/liteflowComponent/application.properties deleted file mode 100644 index 62a916d4a..000000000 --- a/liteflow-testcase-declare-component/src/test/resources/liteflowComponent/application.properties +++ /dev/null @@ -1 +0,0 @@ -liteflow.rule-source=liteflowComponent/flow.xml \ No newline at end of file diff --git a/liteflow-testcase-declare-component/src/test/resources/preAndFinally/flow.xml b/liteflow-testcase-declare-component/src/test/resources/preAndFinally/flow.xml index 5dac9fb0a..78e263d19 100644 --- a/liteflow-testcase-declare-component/src/test/resources/preAndFinally/flow.xml +++ b/liteflow-testcase-declare-component/src/test/resources/preAndFinally/flow.xml @@ -23,4 +23,10 @@ + + +
+        
+        
+    
 
\ No newline at end of file
diff --git a/liteflow-testcase-nospring/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallyTest.java b/liteflow-testcase-nospring/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallyTest.java
index b9db2d65c..8f3794068 100644
--- a/liteflow-testcase-nospring/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallyTest.java
+++ b/liteflow-testcase-nospring/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallyTest.java
@@ -57,4 +57,11 @@ public class PreAndFinallyTest extends BaseTest {
         Assert.assertFalse(response.isSuccess());
         Assert.assertTrue(response.getContextBean().getData("hasEx"));
     }
+
+    @Test
+    public void testPreAndFinally5() throws Exception{
+        LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("p1==>p2==>p1==>p2==>a==>b==>c==>f1==>f2==>f1", response.getExecuteStepStrWithoutTime());
+    }
 }
diff --git a/liteflow-testcase-nospring/src/test/resources/preAndFinally/flow.xml b/liteflow-testcase-nospring/src/test/resources/preAndFinally/flow.xml
index f3ba3ba4a..e4ba3fa89 100644
--- a/liteflow-testcase-nospring/src/test/resources/preAndFinally/flow.xml
+++ b/liteflow-testcase-nospring/src/test/resources/preAndFinally/flow.xml
@@ -35,4 +35,10 @@
         
         
     
+
+    
+        
+        
+        
+    
 
\ No newline at end of file
diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/LiteflowComponentSpringbootTest.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentSpringbootTest.java
similarity index 86%
rename from liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/LiteflowComponentSpringbootTest.java
rename to liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentSpringbootTest.java
index 0409ab133..43fa6a188 100644
--- a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/LiteflowComponentSpringbootTest.java
+++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentSpringbootTest.java
@@ -1,4 +1,4 @@
-package com.yomahub.liteflow.test.liteflowcomponent;
+package com.yomahub.liteflow.test.lfCmpAnno;
 
 import com.yomahub.liteflow.core.FlowExecutor;
 import com.yomahub.liteflow.flow.LiteflowResponse;
@@ -21,10 +21,10 @@ import org.springframework.test.context.junit4.SpringRunner;
  * @since 2.5.10
  */
 @RunWith(SpringRunner.class)
-@TestPropertySource(value = "classpath:/liteflowComponent/application.properties")
+@TestPropertySource(value = "classpath:/lfCmpAnno/application.properties")
 @SpringBootTest(classes = LiteflowComponentSpringbootTest.class)
 @EnableAutoConfiguration
-@ComponentScan({"com.yomahub.liteflow.test.liteflowcomponent.cmp"})
+@ComponentScan({"com.yomahub.liteflow.test.lfCmpAnno.cmp"})
 public class LiteflowComponentSpringbootTest extends BaseTest {
 
     @Autowired
diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/ACmp.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java
similarity index 88%
rename from liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/ACmp.java
rename to liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java
index 96ec64d8f..6c4fc23ad 100644
--- a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/ACmp.java
+++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java
@@ -5,7 +5,7 @@
  * @email weenyc31@163.com
  * @Date 2020/4/1
  */
-package com.yomahub.liteflow.test.liteflowcomponent.cmp;
+package com.yomahub.liteflow.test.lfCmpAnno.cmp;
 
 import com.yomahub.liteflow.annotation.LiteflowComponent;
 import com.yomahub.liteflow.core.NodeComponent;
diff --git a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/BCmp.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java
similarity index 88%
rename from liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/BCmp.java
rename to liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java
index 9d1c0b233..991003cc4 100644
--- a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/BCmp.java
+++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java
@@ -5,7 +5,7 @@
  * @email weenyc31@163.com
  * @Date 2020/4/1
  */
-package com.yomahub.liteflow.test.liteflowcomponent.cmp;
+package com.yomahub.liteflow.test.lfCmpAnno.cmp;
 
 import com.yomahub.liteflow.annotation.LiteflowComponent;
 import com.yomahub.liteflow.core.NodeComponent;
diff --git a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/CCmp.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java
similarity index 88%
rename from liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/CCmp.java
rename to liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java
index f01e577d6..1fbea2522 100644
--- a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/CCmp.java
+++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java
@@ -5,7 +5,7 @@
  * @email weenyc31@163.com
  * @Date 2020/4/1
  */
-package com.yomahub.liteflow.test.liteflowcomponent.cmp;
+package com.yomahub.liteflow.test.lfCmpAnno.cmp;
 
 import com.yomahub.liteflow.annotation.LiteflowComponent;
 import com.yomahub.liteflow.core.NodeComponent;
diff --git a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/DCmp.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java
similarity index 87%
rename from liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/DCmp.java
rename to liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java
index 06d4d268f..42efc228b 100644
--- a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/DCmp.java
+++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java
@@ -5,7 +5,7 @@
  * @email weenyc31@163.com
  * @Date 2020/4/1
  */
-package com.yomahub.liteflow.test.liteflowcomponent.cmp;
+package com.yomahub.liteflow.test.lfCmpAnno.cmp;
 
 import com.yomahub.liteflow.annotation.LiteflowComponent;
 import com.yomahub.liteflow.core.NodeComponent;
diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringbootTest.java b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringbootTest.java
index 2fec1619b..579b41dfc 100644
--- a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringbootTest.java
+++ b/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringbootTest.java
@@ -61,4 +61,12 @@ public class PreAndFinallySpringbootTest extends BaseTest {
         Assert.assertFalse(response.isSuccess());
         Assert.assertTrue(response.getContextBean().getData("hasEx"));
     }
+
+    //测试嵌套结构pre和finally是否在各自的chain里打出
+    @Test
+    public void testPreAndFinally5() throws Exception{
+        LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("p1==>p2==>p1==>p2==>a==>b==>c==>f1==>f2==>f1", response.getExecuteStepStrWithoutTime());
+    }
 }
diff --git a/liteflow-testcase-springboot/src/test/resources/lfCmpAnno/application.properties b/liteflow-testcase-springboot/src/test/resources/lfCmpAnno/application.properties
new file mode 100644
index 000000000..1085d3200
--- /dev/null
+++ b/liteflow-testcase-springboot/src/test/resources/lfCmpAnno/application.properties
@@ -0,0 +1 @@
+liteflow.rule-source=lfCmpAnno/flow.xml
\ No newline at end of file
diff --git a/liteflow-testcase-springboot/src/test/resources/liteflowComponent/flow.xml b/liteflow-testcase-springboot/src/test/resources/lfCmpAnno/flow.xml
similarity index 100%
rename from liteflow-testcase-springboot/src/test/resources/liteflowComponent/flow.xml
rename to liteflow-testcase-springboot/src/test/resources/lfCmpAnno/flow.xml
diff --git a/liteflow-testcase-springboot/src/test/resources/liteflowComponent/application.properties b/liteflow-testcase-springboot/src/test/resources/liteflowComponent/application.properties
deleted file mode 100644
index 62a916d4a..000000000
--- a/liteflow-testcase-springboot/src/test/resources/liteflowComponent/application.properties
+++ /dev/null
@@ -1 +0,0 @@
-liteflow.rule-source=liteflowComponent/flow.xml
\ No newline at end of file
diff --git a/liteflow-testcase-springboot/src/test/resources/preAndFinally/flow.xml b/liteflow-testcase-springboot/src/test/resources/preAndFinally/flow.xml
index 5dac9fb0a..78e263d19 100644
--- a/liteflow-testcase-springboot/src/test/resources/preAndFinally/flow.xml
+++ b/liteflow-testcase-springboot/src/test/resources/preAndFinally/flow.xml
@@ -23,4 +23,10 @@
         
         
     
+
+    
+        
+        
+        
+    
 
\ No newline at end of file
diff --git a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/LiteflowComponentSpringTest.java b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentSpringTest.java
similarity index 89%
rename from liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/LiteflowComponentSpringTest.java
rename to liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentSpringTest.java
index 5b898e760..fab5b4758 100644
--- a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/LiteflowComponentSpringTest.java
+++ b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/LiteflowComponentSpringTest.java
@@ -1,4 +1,4 @@
-package com.yomahub.liteflow.test.liteflowcomponent;
+package com.yomahub.liteflow.test.lfCmpAnno;
 
 import com.yomahub.liteflow.core.FlowExecutor;
 import com.yomahub.liteflow.flow.LiteflowResponse;
@@ -18,7 +18,7 @@ import org.springframework.test.context.junit4.SpringRunner;
  * @since 2.5.10
  */
 @RunWith(SpringRunner.class)
-@ContextConfiguration("classpath:/liteflowcomponent/application.xml")
+@ContextConfiguration("classpath:/lfCmpAnno/application.xml")
 public class LiteflowComponentSpringTest extends BaseTest {
 
     @Autowired
diff --git a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/ACmp.java b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java
similarity index 88%
rename from liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/ACmp.java
rename to liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java
index 96ec64d8f..6c4fc23ad 100644
--- a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/ACmp.java
+++ b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/ACmp.java
@@ -5,7 +5,7 @@
  * @email weenyc31@163.com
  * @Date 2020/4/1
  */
-package com.yomahub.liteflow.test.liteflowcomponent.cmp;
+package com.yomahub.liteflow.test.lfCmpAnno.cmp;
 
 import com.yomahub.liteflow.annotation.LiteflowComponent;
 import com.yomahub.liteflow.core.NodeComponent;
diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/BCmp.java b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java
similarity index 88%
rename from liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/BCmp.java
rename to liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java
index 9d1c0b233..991003cc4 100644
--- a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/BCmp.java
+++ b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/BCmp.java
@@ -5,7 +5,7 @@
  * @email weenyc31@163.com
  * @Date 2020/4/1
  */
-package com.yomahub.liteflow.test.liteflowcomponent.cmp;
+package com.yomahub.liteflow.test.lfCmpAnno.cmp;
 
 import com.yomahub.liteflow.annotation.LiteflowComponent;
 import com.yomahub.liteflow.core.NodeComponent;
diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/CCmp.java b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java
similarity index 88%
rename from liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/CCmp.java
rename to liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java
index f01e577d6..1fbea2522 100644
--- a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/CCmp.java
+++ b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/CCmp.java
@@ -5,7 +5,7 @@
  * @email weenyc31@163.com
  * @Date 2020/4/1
  */
-package com.yomahub.liteflow.test.liteflowcomponent.cmp;
+package com.yomahub.liteflow.test.lfCmpAnno.cmp;
 
 import com.yomahub.liteflow.annotation.LiteflowComponent;
 import com.yomahub.liteflow.core.NodeComponent;
diff --git a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/DCmp.java b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java
similarity index 87%
rename from liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/DCmp.java
rename to liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java
index 06d4d268f..42efc228b 100644
--- a/liteflow-testcase-springboot/src/test/java/com/yomahub/liteflow/test/liteflowcomponent/cmp/DCmp.java
+++ b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/lfCmpAnno/cmp/DCmp.java
@@ -5,7 +5,7 @@
  * @email weenyc31@163.com
  * @Date 2020/4/1
  */
-package com.yomahub.liteflow.test.liteflowcomponent.cmp;
+package com.yomahub.liteflow.test.lfCmpAnno.cmp;
 
 import com.yomahub.liteflow.annotation.LiteflowComponent;
 import com.yomahub.liteflow.core.NodeComponent;
diff --git a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringTest.java b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringTest.java
index 662fd7607..a60abf765 100644
--- a/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringTest.java
+++ b/liteflow-testcase-springnative/src/test/java/com/yomahub/liteflow/test/preAndFinally/PreAndFinallySpringTest.java
@@ -55,4 +55,12 @@ public class PreAndFinallySpringTest extends BaseTest {
         Assert.assertFalse(response.isSuccess());
         Assert.assertTrue(response.getContextBean().getData("hasEx"));
     }
+
+    //测试嵌套结构pre和finally是否在各自的chain里打出
+    @Test
+    public void testPreAndFinally5() throws Exception{
+        LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("p1==>p2==>p1==>p2==>a==>b==>c==>f1==>f2==>f1", response.getExecuteStepStrWithoutTime());
+    }
 }
diff --git a/liteflow-testcase-springnative/src/test/resources/liteflowcomponent/application.xml b/liteflow-testcase-springnative/src/test/resources/lfCmpAnno/application.xml
similarity index 90%
rename from liteflow-testcase-springnative/src/test/resources/liteflowcomponent/application.xml
rename to liteflow-testcase-springnative/src/test/resources/lfCmpAnno/application.xml
index 1755cf3ac..50dc6c909 100644
--- a/liteflow-testcase-springnative/src/test/resources/liteflowcomponent/application.xml
+++ b/liteflow-testcase-springnative/src/test/resources/lfCmpAnno/application.xml
@@ -7,14 +7,14 @@
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 
-    
+    
 
     
 
     
 
     
-        
+        
     
 
     
diff --git a/liteflow-testcase-springnative/src/test/resources/liteflowcomponent/flow.xml b/liteflow-testcase-springnative/src/test/resources/lfCmpAnno/flow.xml
similarity index 100%
rename from liteflow-testcase-springnative/src/test/resources/liteflowcomponent/flow.xml
rename to liteflow-testcase-springnative/src/test/resources/lfCmpAnno/flow.xml
diff --git a/liteflow-testcase-springnative/src/test/resources/preAndFinally/flow.xml b/liteflow-testcase-springnative/src/test/resources/preAndFinally/flow.xml
index 5dac9fb0a..78e263d19 100644
--- a/liteflow-testcase-springnative/src/test/resources/preAndFinally/flow.xml
+++ b/liteflow-testcase-springnative/src/test/resources/preAndFinally/flow.xml
@@ -23,4 +23,10 @@
         
         
     
+
+    
+        
+        
+        
+    
 
\ No newline at end of file