mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-06-12 11:51:04 +08:00
Feat: Multi-Switch 初步实现
This commit is contained in:
@@ -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<String> targetIds = Arrays.stream(split).map(String::trim).collect(Collectors.toList());
|
||||
this.findMultiSwitchTargetsAndExecute(slotIndex, targetIds, targetList);
|
||||
}
|
||||
}
|
||||
|
||||
private void findSwitchTargetAndExecute(Integer slotIndex, String targetId, List<Executable> 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<String> targetIds, List<Executable> targetList) throws Exception {
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
|
||||
List<Executable> matchedExecutors = null;
|
||||
if (CollectionUtil.isNotEmpty(targetIds)) {
|
||||
// 存储最终目标执行器的 set 集合
|
||||
Set<Executable> resultSet = new HashSet<>();
|
||||
|
||||
// 普通 id
|
||||
Set<String> normalIds = new HashSet<>();
|
||||
// tag 模式的目标,id & tag
|
||||
List<Pair<String, String>> 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<String, String> 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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,10 @@
|
||||
<node id="f" class="com.yomahub.liteflow.test.switchcase.cmp.FSwitchCmp"/>
|
||||
<node id="g" class="com.yomahub.liteflow.test.switchcase.cmp.GSwitchCmp"/>
|
||||
<node id="h" class="com.yomahub.liteflow.test.switchcase.cmp.HSwitchCmp"/>
|
||||
<node id="i" class="com.yomahub.liteflow.test.switchcase.cmp.IMultiSwitchCmp"/>
|
||||
<node id="j" class="com.yomahub.liteflow.test.switchcase.cmp.JMultiSwitchCmp"/>
|
||||
<node id="k" class="com.yomahub.liteflow.test.switchcase.cmp.KMultiSwitchCmp"/>
|
||||
<node id="l" class="com.yomahub.liteflow.test.switchcase.cmp.LMultiSwitchCmp"/>
|
||||
</nodes>
|
||||
|
||||
<chain name="chain1">
|
||||
@@ -46,4 +50,32 @@
|
||||
SWITCH(h).to(b.tag("td"), d.tag("td"))
|
||||
);
|
||||
</chain>
|
||||
|
||||
<chain name="chain6">
|
||||
THEN(
|
||||
a,
|
||||
SWITCH(i).to(a, b, c, d)
|
||||
);
|
||||
</chain>
|
||||
|
||||
<chain name="chain7">
|
||||
THEN(
|
||||
a,
|
||||
SWITCH(j).to(a.tag("tag1"), b.tag("tag2"), c, d)
|
||||
);
|
||||
</chain>
|
||||
|
||||
<chain name="chain8">
|
||||
THEN(
|
||||
a,
|
||||
SWITCH(k).to(a, b, c, d).DEFAULT(a)
|
||||
)
|
||||
</chain>
|
||||
|
||||
<chain name="chain9">
|
||||
THEN(
|
||||
a,
|
||||
SWITCH(l).to(b.tag("td"), d.tag("td"), a, c)
|
||||
);
|
||||
</chain>
|
||||
</flow>
|
||||
Reference in New Issue
Block a user