enhancement #I62NEK EL解析方式PRE、FINALLY在嵌套子链中不生效

This commit is contained in:
everywhere.z 2022-12-09 17:31:32 +08:00
parent ffa29a9330
commit 92a2d017a6
7 changed files with 84 additions and 198 deletions

View File

@ -1,131 +0,0 @@
package com.yomahub.liteflow.builder;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.flow.element.Chain;
import com.yomahub.liteflow.flow.element.condition.Condition;
import com.yomahub.liteflow.flow.element.condition.ThenCondition;
import com.yomahub.liteflow.flow.element.condition.WhenCondition;
import java.util.ArrayList;
import java.util.List;
/**
* Chain基于代码形式的组装器
*
* @author Bryan.Zhang
* @since 2.6.8
*/
public class LiteFlowChainBuilder {
private Chain chain;
//这是主体的Condition不包含前置和后置
//声明这个变量而不是用chain.getConditionList的目的是为了辅助平滑加载
//虽然FlowBus里面的map都是CopyOnWrite类型的但是在buildCondition的时候为了平滑加载所以不能事先把chain.getConditionList给设为空List
//所以在这里做一个缓存等conditionList全部build完毕后再去一次性替换chain里面的conditionList
private final List<Condition> conditionList;
//前置处理Condition用来区别主体的Condition
private final List<Condition> preConditionList;
//后置处理Condition用来区别主体的Condition
private final List<Condition> finallyConditionList;
public static LiteFlowChainBuilder createChain() {
return new LiteFlowChainBuilder();
}
public LiteFlowChainBuilder() {
chain = new Chain();
conditionList = new ArrayList<>();
preConditionList = new ArrayList<>();
finallyConditionList = new ArrayList<>();
}
//在parser中chain的build是2段式的因为涉及到依赖问题以前是递归parser
//2.6.8之后取消了递归的模式两段式组装先把带有chainName的chain对象放进去第二段再组装chain里面的condition
//所以这里setChainName的时候需要判断下
/**
*
* @param chainName
* @return
* @deprecated 请使用 {@link #setChainId(String)}
*/
@Deprecated
public LiteFlowChainBuilder setChainName(String chainName) {
if (FlowBus.containChain(chainName)) {
this.chain = FlowBus.getChain(chainName);
} else {
this.chain.setChainName(chainName);
}
return this;
}
public LiteFlowChainBuilder setChainId(String chainId) {
if (FlowBus.containChain(chainId)) {
this.chain = FlowBus.getChain(chainId);
} else {
this.chain.setChainId(chainId);
}
return this;
}
public LiteFlowChainBuilder setCondition(Condition condition) {
//这里把condition组装进conditionList
buildConditions(condition);
return this;
}
public void build() {
this.chain.setConditionList(this.conditionList);
this.chain.setPreConditionList(this.preConditionList);
this.chain.setFinallyConditionList(this.finallyConditionList);
checkBuild();
FlowBus.addChain(this.chain);
}
/**
* build 前简单校验
*/
private void checkBuild() {
List<String> errorList = new ArrayList<>();
if (StrUtil.isBlank(this.chain.getChainName())) {
errorList.add("name is blank");
}
if (CollUtil.isNotEmpty(errorList)) {
throw new RuntimeException(CollUtil.join(errorList, ",", "[", "]"));
}
}
private void buildConditions(Condition condition) {
//这里进行合并逻辑
//对于then来说相邻的2个then会合并成一个condition
//对于when来说相同组的when会合并成一个condition不同组的when还是会拆开
if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_PRE)) {
this.preConditionList.add(condition);
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_FINALLY)) {
this.finallyConditionList.add(condition);
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_THEN)) {
if (this.conditionList.size() >= 1 &&
CollectionUtil.getLast(this.conditionList) instanceof ThenCondition) {
CollectionUtil.getLast(this.conditionList).getExecutableList().addAll(condition.getExecutableList());
} else {
this.conditionList.add(condition);
}
} else if (condition.getConditionType().equals(ConditionTypeEnum.TYPE_WHEN)) {
if (this.conditionList.size() >= 1 &&
CollectionUtil.getLast(this.conditionList) instanceof WhenCondition &&
((WhenCondition)CollectionUtil.getLast(this.conditionList)).getGroup().equals(((WhenCondition)condition).getGroup())) {
CollectionUtil.getLast(this.conditionList).getExecutableList().addAll(condition.getExecutableList());
} else {
this.conditionList.add(condition);
}
}
}
}

View File

@ -12,7 +12,6 @@ import com.yomahub.liteflow.exception.ELParseException;
import com.yomahub.liteflow.exception.FlowSystemException;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.flow.element.Chain;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.condition.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -36,23 +35,13 @@ public class LiteFlowChainELBuilder {
private Chain chain;
/**
* //这是主体的Condition不包含前置和后置
* //这是主体的Condition
* //声明这个变量而不是用chain.getConditionList的目的是为了辅助平滑加载
* //虽然FlowBus里面的map都是CopyOnWrite类型的但是在buildCondition的时候为了平滑加载所以不能事先把chain.getConditionList给设为空List
* //所以在这里做一个缓存等conditionList全部build完毕后再去一次性替换chain里面的conditionList
*/
private final List<Condition> conditionList;
/**
* 前置处理Condition用来区别主体的Condition
*/
private final List<Condition> preConditionList;
/**
* 后置处理Condition用来区别主体的Condition
*/
private final List<Condition> finallyConditionList;
/**
* EL解析引擎
*/
@ -91,8 +80,6 @@ public class LiteFlowChainELBuilder {
public LiteFlowChainELBuilder() {
chain = new Chain();
conditionList = new ArrayList<>();
preConditionList = new ArrayList<>();
finallyConditionList = new ArrayList<>();
}
//在parser中chain的build是2段式的因为涉及到依赖问题以前是递归parser
@ -150,13 +137,13 @@ public class LiteFlowChainELBuilder {
//为什么只寻找第一层而不往下寻找了呢
//因为这是一个规范如果在后面的层级中出现pre和finally语义上也不好理解所以pre和finally只能定义在第一层
//如果硬是要在后面定义则执行的时候会忽略相关代码已做了判断
for (Executable executable : condition.getExecutableList()) {
/*for (Executable executable : condition.getExecutableList()) {
if (executable instanceof PreCondition) {
this.preConditionList.add((PreCondition) executable);
} else if (executable instanceof FinallyCondition) {
this.finallyConditionList.add((FinallyCondition) executable);
}
}
}*/
//把主要的condition加入
this.conditionList.add(condition);
@ -189,8 +176,6 @@ public class LiteFlowChainELBuilder {
public void build() {
this.chain.setConditionList(this.conditionList);
this.chain.setPreConditionList(this.preConditionList);
this.chain.setFinallyConditionList(this.finallyConditionList);
checkBuild();

View File

@ -33,12 +33,6 @@ public class Chain implements Executable {
private List<Condition> conditionList = new ArrayList<>();
//前置处理Condition用来区别主体的Condition
private List<Condition> preConditionList = new ArrayList<>();
//后置处理Condition用来区别主体的Condition
private List<Condition> finallyConditionList = new ArrayList<>();
public Chain(String chainName){
this.chainId = chainName;
}
@ -93,11 +87,9 @@ public class Chain implements Executable {
try {
//设置主ChainName
slot.setChainId(chainId);
//执行前置
this.executePre(slotIndex);
//执行主体Condition
for (Condition condition : conditionList) {
condition.setCurrChainName(chainId);
condition.setCurrChainId(chainId);
condition.execute(slotIndex);
}
}catch (ChainEndException e){
@ -112,23 +104,6 @@ public class Chain implements Executable {
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);
}
}
@ -141,19 +116,4 @@ public class Chain implements Executable {
public String getExecuteId() {
return chainId;
}
public List<Condition> getPreConditionList() {
return preConditionList;
}
public void setPreConditionList(List<Condition> preConditionList) {
this.preConditionList = preConditionList;
}
public List<Condition> getFinallyConditionList() {
return finallyConditionList;
}
public void setFinallyConditionList(List<Condition> finallyConditionList) {
this.finallyConditionList = finallyConditionList;
}
}

View File

@ -8,13 +8,30 @@
package com.yomahub.liteflow.flow.element.condition;
import com.yomahub.liteflow.enums.ConditionTypeEnum;
import com.yomahub.liteflow.exception.ChainEndException;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
import java.util.ArrayList;
import java.util.List;
/**
* 串行器
* @author Bryan.Zhang
*/
public class ThenCondition extends Condition {
/**
* 前置处理Condition
*/
private final List<PreCondition> preConditionList = new ArrayList<>();
/**
* 后置处理Condition
*/
private final List<FinallyCondition> finallyConditionList = new ArrayList<>();
@Override
public ConditionTypeEnum getConditionType() {
return ConditionTypeEnum.TYPE_THEN;
@ -22,13 +39,44 @@ public class ThenCondition extends Condition {
@Override
public void execute(Integer slotIndex) throws Exception {
for (Executable executableItem : this.getExecutableList()) {
//前置和后置组不执行因为在build的时候会抽出来放在chain里面
if (executableItem instanceof PreCondition || executableItem instanceof FinallyCondition){
continue;
try{
for (PreCondition preCondition : preConditionList){
preCondition.execute(slotIndex);
}
executableItem.setCurrChainId(this.getCurrChainId());
executableItem.execute(slotIndex);
for (Executable executableItem : this.getExecutableList()) {
executableItem.setCurrChainId(this.getCurrChainId());
executableItem.execute(slotIndex);
}
}catch (ChainEndException e){
//这里单独catch ChainEndException是因为ChainEndException是用户自己setIsEnd抛出的异常
//是属于正常逻辑所以会在FlowExecutor中判断这里不作为异常处理
throw e;
}catch (Exception e){
Slot slot = DataBus.getSlot(slotIndex);
String chainId = this.getCurrChainId();
//这里事先取到exception set到slot里为了方便finally取到exception
if (slot.isSubChain(chainId)){
slot.setSubException(chainId, e);
}else{
slot.setException(e);
}
throw e;
}finally {
for (FinallyCondition finallyCondition : finallyConditionList){
finallyCondition.execute(slotIndex);
}
}
}
@Override
public void addExecutable(Executable executable) {
if (executable instanceof PreCondition){
preConditionList.add((PreCondition) executable);
}else if (executable instanceof FinallyCondition){
finallyConditionList.add((FinallyCondition) executable);
}else{
super.addExecutable(executable);
}
}
}

View File

@ -1,6 +1,6 @@
package com.yomahub.liteflow.test.exception;
import com.yomahub.liteflow.builder.LiteFlowChainBuilder;
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.core.FlowExecutorHolder;
import com.yomahub.liteflow.exception.ChainNotFoundException;
@ -43,7 +43,7 @@ public class Exception2Test extends BaseTest {
@Test(expected = FlowSystemException.class)
public void testNoConditionInChainException() throws Throwable {
LiteFlowChainBuilder.createChain().setChainName("chain2").build();
LiteFlowChainELBuilder.createChain().setChainId("chain2").build();
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "test");
Assert.assertFalse(response.isSuccess());
Assert.assertEquals("no conditionList in this chain[chain2]", response.getMessage());

View File

@ -70,4 +70,19 @@ public class PreAndFinallyELSpringbootTest extends BaseTest {
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("p1==>p2==>p1==>p2==>a==>b==>c==>f1==>f2==>f1", response.getExecuteStepStrWithoutTime());
}
//测试变量结构pre和finally是否在各自的chain里打出
@Test
public void testPreAndFinally6() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("p1==>p2==>p1==>p2==>a==>b==>c==>f1==>f2==>f1", response.getExecuteStepStrWithoutTime());
}
//测试el整体结构的多重pre和finally
@Test
public void testPreAndFinally7() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
Assert.assertTrue(response.isSuccess());
}
}

View File

@ -19,4 +19,13 @@
<chain name="chain5">
THEN(PRE(p1, p2), chain1, FINALLY(f1));
</chain>
<chain name="chain6">
c1 = THEN(PRE(p1, p2), THEN(a, b, c), FINALLY(f1, f2));
THEN(PRE(p1, p2), c1, FINALLY(f1));
</chain>
<chain name="chain7">
THEN(a, b, THEN(PRE(p1), FINALLY(f1), c), PRE(p2), FINALLY(f2));
</chain>
</flow>