diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/SwitchCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/SwitchCondition.java index a04fe39ad..f8b5a779c 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/SwitchCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/SwitchCondition.java @@ -1,5 +1,7 @@ package com.yomahub.liteflow.flow.element.condition; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.lang.Pair; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.enums.ConditionTypeEnum; @@ -11,7 +13,8 @@ import com.yomahub.liteflow.flow.element.Node; import com.yomahub.liteflow.slot.DataBus; import com.yomahub.liteflow.slot.Slot; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * 选择Condition @@ -25,6 +28,8 @@ public class SwitchCondition extends Condition { private final String TAG_FLAG = ":"; + private static final String MULTI_TARGET_SPLITTER = ","; + @Override public void executeCondition(Integer slotIndex) throws Exception { // 获取switch node @@ -46,6 +51,18 @@ public class SwitchCondition extends Condition { // 拿到switch节点的结果 String targetId = switchNode.getItemResultMetaValue(slotIndex); + String[] split = targetId.split(MULTI_TARGET_SPLITTER); + if (split.length == 1) { + // 只有一个目标节点 + this.findSwitchTargetAndExecute(slotIndex, targetId, targetList); + } else { + // 多个目标节点,执行多路选择 + List targetIds = Arrays.stream(split).map(String::trim).collect(Collectors.toList()); + this.findMultiSwitchTargetsAndExecute(slotIndex, targetIds, targetList); + } + } + + private void findSwitchTargetAndExecute(Integer slotIndex, String targetId, List targetList) throws Exception { Slot slot = DataBus.getSlot(slotIndex); Executable targetExecutor = null; @@ -61,9 +78,9 @@ public class SwitchCondition extends Condition { } else { targetExecutor = targetList.stream() - .filter(executable -> ObjectUtil.equal(executable.getId(),targetId) ) - .findFirst() - .orElse(null); + .filter(executable -> ObjectUtil.equal(executable.getId(),targetId) ) + .findFirst() + .orElse(null); } } @@ -90,7 +107,87 @@ public class SwitchCondition extends Condition { } } - @Override + private void findMultiSwitchTargetsAndExecute(Integer slotIndex, List targetIds, List targetList) throws Exception { + Slot slot = DataBus.getSlot(slotIndex); + + List matchedExecutors = null; + if (CollectionUtil.isNotEmpty(targetIds)) { + // 存储最终目标执行器的 set 集合 + Set resultSet = new HashSet<>(); + + // 普通 id + Set normalIds = new HashSet<>(); + // tag 模式的目标,id & tag + List> tagTargets = new ArrayList<>(); + + // 1. 分离 targetIds 中的普通 ID 和 Tag 模式 ID + for (String targetId : targetIds) { + if (StrUtil.isNotBlank(targetId)) { + if (targetId.contains(TAG_FLAG)) { + String[] target = targetId.split(TAG_FLAG, 2); + String _targetId = target[0]; + String _targetTag = target[1]; + tagTargets.add(Pair.of(_targetId, _targetTag)); + } else { + normalIds.add(targetId); + } + } + } + + // 2. 根据普通 ID 筛选目标 + if (!normalIds.isEmpty()) { + targetList.stream() + .filter(executable -> normalIds.contains(executable.getId())) + .forEach(resultSet::add); + } + + // 3. 根据 Tag 模式筛选目标 + if (!tagTargets.isEmpty()) { + for (Pair target : tagTargets) { + String _targetId = target.getKey(); + String _targetTag = target.getValue(); + targetList.stream() + .filter(executable -> + (StrUtil.startWith(_targetId, TAG_PREFIX) && ObjectUtil.equal(_targetTag, executable.getTag())) + || ((StrUtil.isEmpty(_targetId) || _targetId.equals(executable.getId())) + && (StrUtil.isEmpty(_targetTag) || _targetTag.equals(executable.getTag())))) + .forEach(resultSet::add); + } + } + matchedExecutors = resultSet.stream() + .sorted(Comparator.comparing(Executable::getId)) + .collect(Collectors.toList()); + } + + if (CollectionUtil.isEmpty(matchedExecutors)) { + // 未匹配到,则走默认节点 + Executable defaultExecutor = this.getDefaultExecutor(); + matchedExecutors = Optional.ofNullable(defaultExecutor) + .map(CollectionUtil::newArrayList) + .orElse(null); + } + + if (CollectionUtil.isNotEmpty(matchedExecutors)) { + // TODO 实现并行 + for (Executable targetExecutor : matchedExecutors) { + // switch的目标不能是Pre节点或者Finally节点 + if (targetExecutor instanceof PreCondition || targetExecutor instanceof FinallyCondition) { + String errorInfo = StrUtil.format( + "[{}]:switch component[{}] error, switch target node cannot be pre or finally", + slot.getRequestId(), this.getSwitchNode().getInstance().getDisplayName()); + throw new SwitchTargetCannotBePreOrFinallyException(errorInfo); + } + targetExecutor.setCurrChainId(this.getCurrChainId()); + targetExecutor.execute(slotIndex); + } + } else { + String errorInfo = StrUtil.format("[{}]:no target node find for the component[{}],targetIds are {}", + slot.getRequestId(), this.getSwitchNode().getInstance().getDisplayName(), targetIds); + throw new NoSwitchTargetNodeException(errorInfo); + } + } + + @Override public ConditionTypeEnum getConditionType() { return ConditionTypeEnum.TYPE_SWITCH; } diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchTest.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchTest.java index f4065f214..fbe259351 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/SwitchTest.java @@ -55,4 +55,31 @@ public class SwitchTest extends BaseTest { Assertions.assertEquals("a==>h==>b", response.getExecuteStepStr()); } + @Test + public void testMultiSwitch1() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg"); + Assertions.assertTrue(response.isSuccess()); + Assertions.assertEquals("a==>i==>a==>b==>c", response.getExecuteStepStr()); + } + + @Test + public void testMultiSwitch2() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg"); + Assertions.assertTrue(response.isSuccess()); + Assertions.assertEquals("a==>j==>a==>b==>d", response.getExecuteStepStr()); + } + + @Test + public void testMultiSwitch3() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain8", "arg"); + Assertions.assertTrue(response.isSuccess()); + Assertions.assertEquals("a==>k==>a", response.getExecuteStepStr()); + } + + @Test + public void testMultiSwitch4() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain9", "arg"); + Assertions.assertTrue(response.isSuccess()); + Assertions.assertEquals("a==>l==>a==>b==>d", response.getExecuteStepStr()); + } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/IMultiSwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/IMultiSwitchCmp.java new file mode 100644 index 000000000..d10436eaf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/IMultiSwitchCmp.java @@ -0,0 +1,11 @@ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; + +public class IMultiSwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "a, b, c"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/JMultiSwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/JMultiSwitchCmp.java new file mode 100644 index 000000000..f6d1d0934 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/JMultiSwitchCmp.java @@ -0,0 +1,11 @@ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; + +public class JMultiSwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "tag:tag1, tag:tag2, d"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/KMultiSwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/KMultiSwitchCmp.java new file mode 100644 index 000000000..7afaec147 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/KMultiSwitchCmp.java @@ -0,0 +1,11 @@ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; + +public class KMultiSwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return "e, f, g, h"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/LMultiSwitchCmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/LMultiSwitchCmp.java new file mode 100644 index 000000000..f6be949ea --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/switchcase/cmp/LMultiSwitchCmp.java @@ -0,0 +1,11 @@ +package com.yomahub.liteflow.test.switchcase.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; + +public class LMultiSwitchCmp extends NodeSwitchComponent { + + @Override + public String processSwitch() throws Exception { + return ":td, a"; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/switchcase/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/switchcase/flow.el.xml index bce9c1770..f1b6492e0 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/switchcase/flow.el.xml +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/switchcase/flow.el.xml @@ -9,6 +9,10 @@ + + + + @@ -46,4 +50,32 @@ SWITCH(h).to(b.tag("td"), d.tag("td")) ); + + + THEN( + a, + SWITCH(i).to(a, b, c, d) + ); + + + + THEN( + a, + SWITCH(j).to(a.tag("tag1"), b.tag("tag2"), c, d) + ); + + + + THEN( + a, + SWITCH(k).to(a, b, c, d).DEFAULT(a) + ) + + + + THEN( + a, + SWITCH(l).to(b.tag("td"), d.tag("td"), a, c) + ); + \ No newline at end of file