enhancement #I62NEK EL解析方式PRE、FINALLY在嵌套子链中不生效
This commit is contained in:
parent
ffa29a9330
commit
92a2d017a6
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue