From ca9449f531036fb572284dd1e1820e077e931759 Mon Sep 17 00:00:00 2001 From: luoyi <972849752@qq.com> Date: Fri, 22 Sep 2023 23:38:58 +0800 Subject: [PATCH] =?UTF-8?q?enhancement=20#I821F1=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=A1=88=E4=BE=8B=EF=BC=8C=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yomahub/liteflow/core/FlowExecutor.java | 30 +++++++++- .../FlowInDifferentConfigTest.java | 31 ++++++++++ .../subflow/endlessLopp/FlowJsonTest.java | 29 ++++++++++ .../test/subflow/endlessLopp/FlowXMLTest.java | 29 ++++++++++ .../test/subflow/endlessLopp/FlowYMLTest.java | 29 ++++++++++ .../subflow/endlessLoop/flow-main.el.xml | 17 ++++++ .../subflow/endlessLoop/flow-sub1.el.xml | 6 ++ .../subflow/endlessLoop/flow.el.json | 58 +++++++++++++++++++ .../resources/subflow/endlessLoop/flow.el.xml | 25 ++++++++ .../resources/subflow/endlessLoop/flow.el.yml | 28 +++++++++ 10 files changed, 279 insertions(+), 3 deletions(-) create mode 100644 liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowInDifferentConfigTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowJsonTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowXMLTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowYMLTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow-main.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow-sub1.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.json create mode 100644 liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.xml create mode 100644 liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.yml 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 f333a384e..fea85b472 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 @@ -216,53 +216,77 @@ public class FlowExecutor { } /** - * 检查 chain 的有效性,同时重新构建 FlowBus 的 chain,将调用的子 chain 连起来 + * 检查 chain 的有效性,同时重新构建 FlowBus 的 chain,将其子 chain 引用连起来 * @throws CyclicDependencyException */ private void checkValidOfChain() { + // 存储已经构建完的有效的 chain 对应 Id Set validChainIdSet = new HashSet<>(); + // 遍历所有解析的 chain for (Chain rootChain : FlowBus.getChainMap().values()) { + // 不存在 validChainIdSet 中的 chain,说明还未检查 if (!validChainIdSet.contains(rootChain.getChainId())) { + // 与 rootChain 相关联的 chain 的 ID Set associatedChainIdSet = new HashSet<>(); + // 检查 chain 的有效性,是否存在死循环情况 checkValidOfChain(rootChain, associatedChainIdSet); + // 检查完当前 chain 后,能走到这里说明当前相关的 chain 是有效的 validChainIdSet.addAll(associatedChainIdSet); + } } + } /** * 检查 chain 的有效性 * @param currentChain 当前遍历到的 chain 节点 + * @param associatedChainIdSet 与 rootChain 相关联的 chainId 集合 * @throws CyclicDependencyException */ private void checkValidOfChain(Chain currentChain, Set associatedChainIdSet) { - // 判断 completedChainIdSet 中是否已经存在对应的 chain + + // 判断 associatedChainIdSet 中是否已经存在对应的 chain if (associatedChainIdSet.add(currentChain.getChainId())) { + // Set 中不存在则说明可能是父 chain 或者子 chain 未引用自身,又或者子 chain 未引用其父 chain,继续判断其子 chain for (Condition condition : currentChain.getConditionList()) { + // 遍历所有 executable 列表 for (Executable executable : condition.getExecutableList()) { + // 只需判断 chain,因为只有 chain 才会存在死循环依赖情况 if (executable instanceof Chain) { + // 能执行到此处,必能从 FlowBus 中获取到对应的 chain,故无需做非空判断 Chain childrenChain = FlowBus.getChainMap().get(executable.getId()); + // 递归检查 chain 有效性 checkValidOfChain(childrenChain, associatedChainIdSet); + // 重新构建 chain 的 condition 列表 ((Chain) executable).setConditionList(childrenChain.getConditionList()); + } } } } else { + + String errorMessage = StrUtil.format("There is a circular dependency in the chain[{}], please check carefully.", currentChain.getChainId()); + + LOG.error(errorMessage); + // chain 重复,说明子 chain 中引用了自身或其父 chain,存在死循环情况 - throw new CyclicDependencyException(StrUtil.format("There is a circular dependency in the chain[{}], please check carefully.", currentChain.getChainId())); + throw new CyclicDependencyException(errorMessage); + } + } // 此方法就是从原有的配置源主动拉取新的进行刷新 diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowInDifferentConfigTest.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowInDifferentConfigTest.java new file mode 100644 index 000000000..24d21cc48 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowInDifferentConfigTest.java @@ -0,0 +1,31 @@ + +package com.yomahub.liteflow.test.subflow.endlessLopp; + +import com.yomahub.liteflow.core.FlowExecutorHolder; +import com.yomahub.liteflow.exception.CyclicDependencyException; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + + +/** + * 测试多文件情况下 chain 死循环逻辑 + * + * @author luo yi + * @since 2.11.1 + */ +public class FlowInDifferentConfigTest extends BaseTest { + + // 测试 chain 死循环 + @Test + public void testChainEndlessLoop() { + Assertions.assertThrows(CyclicDependencyException.class, () -> { + LiteflowConfig config = LiteflowConfigGetter.get(); + config.setRuleSource("subflow/endlessLoop/flow-main.el.xml,subflow/endlessLoop/flow-sub1.el.xml"); + FlowExecutorHolder.loadInstance(config); + }); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowJsonTest.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowJsonTest.java new file mode 100644 index 000000000..12b6f8c42 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowJsonTest.java @@ -0,0 +1,29 @@ +package com.yomahub.liteflow.test.subflow.endlessLopp; + +import com.yomahub.liteflow.core.FlowExecutorHolder; +import com.yomahub.liteflow.exception.CyclicDependencyException; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * 测试 json 文件情况下 chain 死循环逻辑 + * + * @author luo yi + * @since 2.11.1 + */ +public class FlowJsonTest extends BaseTest { + + // 测试 chain 死循环 + @Test + public void testChainEndlessLoop() { + Assertions.assertThrows(CyclicDependencyException.class, () -> { + LiteflowConfig config = LiteflowConfigGetter.get(); + config.setRuleSource("subflow/endlessLoop/flow.el.json"); + FlowExecutorHolder.loadInstance(config); + }); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowXMLTest.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowXMLTest.java new file mode 100644 index 000000000..465c4b4f2 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowXMLTest.java @@ -0,0 +1,29 @@ +package com.yomahub.liteflow.test.subflow.endlessLopp; + +import com.yomahub.liteflow.core.FlowExecutorHolder; +import com.yomahub.liteflow.exception.CyclicDependencyException; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * 测试 xml 文件情况下 chain 死循环逻辑 + * + * @author luo yi + * @since 2.11.1 + */ +public class FlowXMLTest extends BaseTest { + + // 测试 chain 死循环 + @Test + public void testChainEndlessLoop() { + Assertions.assertThrows(CyclicDependencyException.class, () -> { + LiteflowConfig config = LiteflowConfigGetter.get(); + config.setRuleSource("subflow/endlessLoop/flow.el.xml"); + FlowExecutorHolder.loadInstance(config); + }); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowYMLTest.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowYMLTest.java new file mode 100644 index 000000000..e586b7d8e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/subflow/endlessLopp/FlowYMLTest.java @@ -0,0 +1,29 @@ +package com.yomahub.liteflow.test.subflow.endlessLopp; + +import com.yomahub.liteflow.core.FlowExecutorHolder; +import com.yomahub.liteflow.exception.CyclicDependencyException; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * 测试 yml 文件情况下 chain 死循环逻辑 + * + * @author luo yi + * @since 2.11.1 + */ +public class FlowYMLTest extends BaseTest { + + // 测试 chain 死循环 + @Test + public void testChainEndlessLoop() { + Assertions.assertThrows(CyclicDependencyException.class, () -> { + LiteflowConfig config = LiteflowConfigGetter.get(); + config.setRuleSource("subflow/endlessLoop/flow.el.yml"); + FlowExecutorHolder.loadInstance(config); + }); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow-main.el.xml b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow-main.el.xml new file mode 100644 index 000000000..4f479f6e5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow-main.el.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + THEN(a, b, chain2); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow-sub1.el.xml b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow-sub1.el.xml new file mode 100644 index 000000000..39b89324e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow-sub1.el.xml @@ -0,0 +1,6 @@ + + + + THEN(b, a, chain1); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.json b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.json new file mode 100644 index 000000000..e1012cc73 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.json @@ -0,0 +1,58 @@ +{ + "flow": { + "nodes": { + "node": [ + { + "id": "a", + "class": "com.yomahub.liteflow.test.subflow.cmp1.ACmp" + }, + { + "id": "b", + "class": "com.yomahub.liteflow.test.subflow.cmp1.BCmp" + }, + { + "id": "c", + "class": "com.yomahub.liteflow.test.subflow.cmp1.CCmp" + }, + { + "id": "d", + "class": "com.yomahub.liteflow.test.subflow.cmp1.DCmp" + }, + { + "id": "e", + "class": "com.yomahub.liteflow.test.subflow.cmp1.ECmp" + }, + { + "id": "f", + "class": "com.yomahub.liteflow.test.subflow.cmp2.FCmp" + }, + { + "id": "g", + "class": "com.yomahub.liteflow.test.subflow.cmp2.GCmp" + }, + { + "id": "h", + "class": "com.yomahub.liteflow.test.subflow.cmp2.HCmp" + }, + { + "id": "M", + "class": "com.yomahub.liteflow.test.subflow.cmp2.MCmp" + } + ] + }, + "chain": [ + { + "name": "chain7", + "value": "THEN(a, chain8);" + }, + { + "name": "chain8", + "value": "THEN(b, chain9);" + }, + { + "name": "chain9", + "value": "WHEN(c, chain7);" + } + ] + } +} \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.xml new file mode 100644 index 000000000..38120c94f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + THEN(a, chain2); + + + + THEN(b, chain3); + + + + THEN(c, chain1); + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.yml b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.yml new file mode 100644 index 000000000..efdf7b431 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/subflow/endlessLoop/flow.el.yml @@ -0,0 +1,28 @@ +flow: + nodes: + node: + - id: a + class: com.yomahub.liteflow.test.subflow.cmp1.ACmp + - id: b + class: com.yomahub.liteflow.test.subflow.cmp1.BCmp + - id: c + class: com.yomahub.liteflow.test.subflow.cmp1.CCmp + - id: d + class: com.yomahub.liteflow.test.subflow.cmp1.DCmp + - id: e + class: com.yomahub.liteflow.test.subflow.cmp1.ECmp + - id: f + class: com.yomahub.liteflow.test.subflow.cmp2.FCmp + - id: g + class: com.yomahub.liteflow.test.subflow.cmp2.GCmp + - id: h + class: com.yomahub.liteflow.test.subflow.cmp2.HCmp + - id: h + class: com.yomahub.liteflow.test.subflow.cmp2.MCmp + chain: + - name: chain4 + value: "THEN(a, chain5);" + - name: chain5 + value: "THEN(b, chain6);" + - name: chain6 + value: "THEN(c, chain5);" \ No newline at end of file