From 480f91eea1a435621467bcf41f0205a55025235e Mon Sep 17 00:00:00 2001 From: luoyi <972849752@qq.com> Date: Fri, 12 Jul 2024 22:42:29 +0800 Subject: [PATCH 1/3] =?UTF-8?q?enhancement=20#I9T6PB=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=BF=AD=E4=BB=A3=E5=BE=AA=E7=8E=AF=E7=BB=84=E4=BB=B6=20DO=20?= =?UTF-8?q?=E4=B8=AD=E5=BE=85=E6=89=A7=E8=A1=8C=20Node=20=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=E7=88=B6=E5=B1=82=E8=BF=AD=E4=BB=A3=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yomahub/liteflow/core/NodeComponent.java | 21 ++++++++++++ .../yomahub/liteflow/flow/element/Node.java | 16 ++++++++++ .../element/condition/IteratorCondition.java | 9 +++++- .../flow/element/condition/LoopCondition.java | 32 ++++++++++++++++++- .../iterator/IteratorELSpringbootTest.java | 16 ++++++++++ .../liteflow/test/iterator/cmp/Br1Cmp.java | 17 ++++++++++ .../liteflow/test/iterator/cmp/DCmp.java | 16 ++++++++++ .../liteflow/test/iterator/cmp/X3Cmp.java | 17 ++++++++++ .../src/test/resources/iterator/flow.xml | 28 ++++++++++++++++ 9 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/Br1Cmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/DCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X3Cmp.java diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java index 02140db44..bf83b0d15 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java @@ -8,6 +8,7 @@ package com.yomahub.liteflow.core; import cn.hutool.core.date.StopWatch; +import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.ttl.TransmittableThreadLocal; @@ -30,6 +31,7 @@ import com.yomahub.liteflow.util.JsonUtil; import java.lang.reflect.Method; import java.util.Date; +import java.util.Optional; /** * 普通组件抽象类 @@ -415,6 +417,25 @@ public abstract class NodeComponent{ return this.refNodeTL.get().getCurrLoopObject(); } + private Optional getParentLoopObj(Node iteratorObject, int currentLayer, int targetLayer) { + if (ObjUtil.isNull(iteratorObject)) { + return Optional.empty(); + } + Node parentIteratorObject = iteratorObject.getParentIteratorObj(); + if (currentLayer >= targetLayer || ObjUtil.isNull(parentIteratorObject)) { + return Optional.ofNullable(iteratorObject.getCurrLoopObject()); + } + return getParentLoopObj(parentIteratorObject, currentLayer + 1, targetLayer); + } + + public Optional getParentLoopObj(int loopLayer) { + return getParentLoopObj(this.refNodeTL.get().getParentIteratorObj(), 1, loopLayer); + } + + public Optional getParentLoopObj() { + return getParentLoopObj(1); + } + @Deprecated public void invoke(String chainId, Object param) throws Exception { FlowExecutorHolder.loadInstance().invoke(chainId, param, this.getSlotIndex()); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java index 3659586e8..01ab2c47a 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java @@ -74,6 +74,9 @@ public class Node implements Executable, Cloneable, Rollbackable{ // isContinueOnError 结果 private TransmittableThreadLocal isContinueOnErrorResult = new TransmittableThreadLocal<>(); + // 主要用于 ITERATOR 关键字获取父循环的对象 + private TransmittableThreadLocal parentIteratorNodeTL = new TransmittableThreadLocal<>(); + public Node() { } @@ -290,6 +293,18 @@ public class Node implements Executable, Cloneable, Rollbackable{ this.isContinueOnErrorResult.remove(); } + public Node getParentIteratorObj() { + return parentIteratorNodeTL.get(); + } + + public void setParentIteratorObj(Node iteratorObj) { + this.parentIteratorNodeTL.set(iteratorObj); + } + + public void removeParentIteratorObj() { + this.parentIteratorNodeTL.remove(); + } + public void setLoopIndex(int index) { this.loopIndexTL.set(index); } @@ -360,6 +375,7 @@ public class Node implements Executable, Cloneable, Rollbackable{ node.slotIndexTL = new TransmittableThreadLocal<>(); node.isEndTL = new TransmittableThreadLocal<>(); node.isContinueOnErrorResult = new TransmittableThreadLocal<>(); + node.parentIteratorNodeTL = new TransmittableThreadLocal<>(); return node; } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java index 2a2a640b0..6988e59a9 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java @@ -60,6 +60,8 @@ public class IteratorCondition extends LoopCondition { setLoopIndex(executableItem, index); // 设置循环迭代器对象 setCurrLoopObject(executableItem, itObj); + // 设置 DO 执行对象中当前所属的 Iterator 对象 + setParentLoopObject(executableItem, iteratorNode); // 执行可执行对象 executableItem.execute(slotIndex); // 如果break组件不为空,则去执行 @@ -67,6 +69,8 @@ public class IteratorCondition extends LoopCondition { breakItem.setCurrChainId(this.getCurrChainId()); setLoopIndex(breakItem, index); setCurrLoopObject(breakItem, itObj); + // 设置 DO 执行对象中当前所属的 Iterator 对象 + setParentLoopObject(breakItem, iteratorNode); breakItem.execute(slotIndex); boolean isBreak = breakItem.getItemResultMetaValue(slotIndex); if (isBreak) { @@ -85,13 +89,15 @@ public class IteratorCondition extends LoopCondition { Object itObj = it.next(); //提交异步任务 CompletableFuture future = - CompletableFuture.supplyAsync(new LoopParallelSupplier(executableItem, this.getCurrChainId(), slotIndex, index, itObj), parallelExecutor); + CompletableFuture.supplyAsync(new LoopParallelSupplier(executableItem, this.getCurrChainId(), slotIndex, index, itObj, iteratorNode), parallelExecutor); futureList.add(future); //break判断 if (ObjectUtil.isNotNull(breakItem)) { breakItem.setCurrChainId(this.getCurrChainId()); setLoopIndex(breakItem, index); setCurrLoopObject(breakItem, itObj); + // 设置 DO 执行对象中当前所属的 Iterator 对象 + setParentLoopObject(breakItem, iteratorNode); breakItem.execute(slotIndex); boolean isBreak = breakItem.getItemResultMetaValue(slotIndex); if (isBreak) { @@ -106,6 +112,7 @@ public class IteratorCondition extends LoopCondition { } finally { removeLoopIndex(executableItem); removeCurrLoopObject(executableItem); + removeParentLoopObject(executableItem); } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java index 0355ffd3a..278e0e103 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java @@ -14,6 +14,7 @@ import java.util.function.Supplier; * 循环Condition的抽象类 主要继承对象有ForCondition和WhileCondition * * @author Bryan.Zhang + * @author luo yi * @since 2.9.0 */ public abstract class LoopCondition extends Condition { @@ -58,6 +59,17 @@ public abstract class LoopCondition extends Condition { } } + protected void setParentLoopObject(Executable executableItem, Node iteratorObj) { + if (executableItem instanceof Chain) { + ((Chain) executableItem).getConditionList().forEach(condition -> setParentLoopObject(condition, iteratorObj)); + } else if (executableItem instanceof Condition) { + ((Condition) executableItem).getExecutableGroup() + .forEach((key, value) -> value.forEach(executable -> setParentLoopObject(executable, iteratorObj))); + } else if (executableItem instanceof Node) { + ((Node) executableItem).setParentIteratorObj(iteratorObj); + } + } + protected void removeLoopIndex(Executable executableItem) { if (executableItem instanceof Chain) { ((Chain) executableItem).getConditionList().forEach(this::removeLoopIndex); @@ -80,6 +92,17 @@ public abstract class LoopCondition extends Condition { } } + protected void removeParentLoopObject(Executable executableItem) { + if (executableItem instanceof Chain) { + ((Chain) executableItem).getConditionList().forEach(this::removeParentLoopObject); + } else if (executableItem instanceof Condition) { + ((Condition) executableItem).getExecutableGroup() + .forEach((key, value) -> value.forEach(this::removeParentLoopObject)); + } else if (executableItem instanceof Node) { + ((Node) executableItem).removeParentIteratorObj(); + } + } + public boolean isParallel() { return parallel; } @@ -108,6 +131,7 @@ public abstract class LoopCondition extends Condition { private final Integer slotIndex; private final Integer loopIndex; private final Object itObj; + private final Node iteratorNode; public LoopParallelSupplier(Executable executableItem, String currChainId, Integer slotIndex, Integer loopIndex) { this.executableItem = executableItem; @@ -115,14 +139,16 @@ public abstract class LoopCondition extends Condition { this.slotIndex = slotIndex; this.loopIndex = loopIndex; this.itObj = null; + this.iteratorNode = null; } - public LoopParallelSupplier(Executable executableItem, String currChainId, Integer slotIndex, Integer loopIndex, Object itObj) { + public LoopParallelSupplier(Executable executableItem, String currChainId, Integer slotIndex, Integer loopIndex, Object itObj, Node iteratorNode) { this.executableItem = executableItem; this.currChainId = currChainId; this.slotIndex = slotIndex; this.loopIndex = loopIndex; this.itObj = itObj; + this.iteratorNode = iteratorNode; } @@ -136,6 +162,10 @@ public abstract class LoopCondition extends Condition { if(itObj != null){ setCurrLoopObject(executableItem, itObj); } + // 设置 DO 执行对象中当前所属的 Iterator 对象 + if (iteratorNode != null) { + setParentLoopObject(executableItem, iteratorNode); + } executableItem.execute(slotIndex); return LoopFutureObj.success(executableItem.getId()); } catch (Exception e) { diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringbootTest.java index cdeb448d0..915d2ecb7 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringbootTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringbootTest.java @@ -11,6 +11,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.ComponentScan; import org.springframework.test.context.TestPropertySource; + import javax.annotation.Resource; import java.util.List; @@ -56,4 +57,19 @@ public class IteratorELSpringbootTest extends BaseTest { LiteflowResponse response = flowExecutor.execute2Resp("chain3"); Assertions.assertTrue(response.isSuccess()); } + + // 多层迭代测试,获取顶层循环对象 + @Test + public void testIt4() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain4"); + Assertions.assertTrue(response.isSuccess()); + } + + // 多层迭代并行测试,获取顶层循环对象 + @Test + public void testIt5() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain5"); + Assertions.assertTrue(response.isSuccess()); + } + } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/Br1Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/Br1Cmp.java new file mode 100644 index 000000000..ce29d394e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/Br1Cmp.java @@ -0,0 +1,17 @@ +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeBooleanComponent; + +@LiteflowComponent("br1") +public class Br1Cmp extends NodeBooleanComponent { + + @Override + public boolean processBoolean() throws Exception { + System.out.println("breakCmp get current iterator object : " + this.getCurrLoopObj().toString()); + System.out.println("breakCmp get first layer parent iterator object : " + this.getParentLoopObj().toString()); + System.out.println("breakCmp get second layer parent iterator object : " + this.getParentLoopObj(2).toString()); + return false; + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/DCmp.java new file mode 100644 index 000000000..a8b0aad0a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/DCmp.java @@ -0,0 +1,16 @@ + +package com.yomahub.liteflow.test.iterator.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() throws Exception { + System.out.println("get current iterator object : " + this.getCurrLoopObj().toString()); + System.out.println("get first layer parent iterator object : " + this.getParentLoopObj().toString()); + System.out.println("get second layer parent iterator object : " + this.getParentLoopObj(2).toString()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X3Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X3Cmp.java new file mode 100644 index 000000000..61208ddf3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X3Cmp.java @@ -0,0 +1,17 @@ +package com.yomahub.liteflow.test.iterator.cmp; + +import cn.hutool.core.collection.ListUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeIteratorComponent; + +import java.util.Iterator; +import java.util.List; + +@LiteflowComponent("x3") +public class X3Cmp extends NodeIteratorComponent { + @Override + public Iterator processIterator() throws Exception { + List list = ListUtil.toList("-"); + return list.iterator(); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/iterator/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/iterator/flow.xml index a6015d40f..67fab6cb7 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/iterator/flow.xml +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/iterator/flow.xml @@ -18,4 +18,32 @@ ); + + + ITERATOR(x1).DO( + THEN( + c, + ITERATOR(x2).DO( + THEN( + c, + ITERATOR(x3).DO(d).BREAK(br1) + ) + ) + ) + ); + + + + ITERATOR(x1).DO( + THEN( + c, + ITERATOR(x2).parallel(true).DO( + THEN( + c, + ITERATOR(x3).DO(d).BREAK(br1) + ) + ) + ) + ); + \ No newline at end of file -- Gitee From 25cffd2a0bc83c5030e9bea7a06ab79f5962adf8 Mon Sep 17 00:00:00 2001 From: luoyi <972849752@qq.com> Date: Sat, 13 Jul 2024 01:10:02 +0800 Subject: [PATCH 2/3] =?UTF-8?q?enhancement=20#I9T6PB=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E4=B8=BA=E9=99=90=E5=88=B6=E8=8E=B7=E5=8F=96=E6=9C=80=E5=A4=96?= =?UTF-8?q?=E5=B1=82=E8=BF=AD=E4=BB=A3=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/yomahub/liteflow/core/NodeComponent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java index bf83b0d15..69a43f828 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java @@ -422,7 +422,7 @@ public abstract class NodeComponent{ return Optional.empty(); } Node parentIteratorObject = iteratorObject.getParentIteratorObj(); - if (currentLayer >= targetLayer || ObjUtil.isNull(parentIteratorObject)) { + if (currentLayer >= targetLayer || ObjUtil.isNull(parentIteratorObject) || ObjUtil.isNull(parentIteratorObject.getCurrLoopObject())) { return Optional.ofNullable(iteratorObject.getCurrLoopObject()); } return getParentLoopObj(parentIteratorObject, currentLayer + 1, targetLayer); -- Gitee From f86ff698b4fa341cdf38cf9cf5ee5f42153c8a70 Mon Sep 17 00:00:00 2001 From: luoyi <972849752@qq.com> Date: Sun, 4 Aug 2024 23:30:24 +0800 Subject: [PATCH 3/3] =?UTF-8?q?enhancement=20#I9T6PB=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=BE=AA=E7=8E=AF=E7=BB=84=E4=BB=B6=20DO=20=E4=B8=AD=E5=BE=85?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=20Node=20=E8=AE=BF=E9=97=AE=E7=88=B6?= =?UTF-8?q?=E5=B1=82=E8=BF=AD=E4=BB=A3=E5=AF=B9=E8=B1=A1=E6=88=96=E4=B8=8B?= =?UTF-8?q?=E6=A0=87=E7=B4=A2=E5=BC=95=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yomahub/liteflow/core/NodeComponent.java | 23 ++++- .../yomahub/liteflow/flow/element/Node.java | 3 +- .../flow/element/condition/ForCondition.java | 11 ++- .../element/condition/IteratorCondition.java | 4 + .../flow/element/condition/LoopCondition.java | 16 ++-- .../element/condition/WhileCondition.java | 89 +++++++++++-------- .../liteflow/test/iterator/cmp/Br1Cmp.java | 3 + .../liteflow/test/iterator/cmp/DCmp.java | 3 + .../test/loop/LoopELSpringbootTest.java | 9 ++ .../liteflow/test/loop/cmp/Br1Cmp.java | 17 ++++ .../yomahub/liteflow/test/loop/cmp/GCmp.java | 16 ++++ .../src/test/resources/loop/flow.xml | 9 ++ 12 files changed, 155 insertions(+), 48 deletions(-) create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/cmp/Br1Cmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/cmp/GCmp.java diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java index 69a43f828..998bd8e41 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java @@ -417,7 +417,7 @@ public abstract class NodeComponent{ return this.refNodeTL.get().getCurrLoopObject(); } - private Optional getParentLoopObj(Node iteratorObject, int currentLayer, int targetLayer) { + private Optional getParentLoopObj(Node iteratorObject, int currentLayer, int targetLayer) { if (ObjUtil.isNull(iteratorObject)) { return Optional.empty(); } @@ -428,14 +428,33 @@ public abstract class NodeComponent{ return getParentLoopObj(parentIteratorObject, currentLayer + 1, targetLayer); } + private Optional getParentLoopIndex(Node iteratorObject, int currentLayer, int targetLayer) { + if (ObjUtil.isNull(iteratorObject)) { + return Optional.empty(); + } + Node parentIteratorObject = iteratorObject.getParentIteratorObj(); + if (currentLayer >= targetLayer || ObjUtil.isNull(parentIteratorObject) || ObjUtil.isNull(parentIteratorObject.getLoopIndex())) { + return Optional.ofNullable(iteratorObject.getLoopIndex()); + } + return getParentLoopIndex(parentIteratorObject, currentLayer + 1, targetLayer); + } + public Optional getParentLoopObj(int loopLayer) { - return getParentLoopObj(this.refNodeTL.get().getParentIteratorObj(), 1, loopLayer); + return getParentLoopObj(this.refNodeTL.get().getParentIteratorObj(), 0, loopLayer); } public Optional getParentLoopObj() { return getParentLoopObj(1); } + public Optional getParentLoopIndex(int loopLayer) { + return getParentLoopIndex(this.refNodeTL.get().getParentIteratorObj(), 0, loopLayer); + } + + public Optional getParentLoopIndex() { + return getParentLoopIndex(1); + } + @Deprecated public void invoke(String chainId, Object param) throws Exception { FlowExecutorHolder.loadInstance().invoke(chainId, param, this.getSlotIndex()); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java index 01ab2c47a..f3c7055c6 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java @@ -189,7 +189,8 @@ public class Node implements Executable, Cloneable, Rollbackable{ this.getInstance().removeRefNode(); removeSlotIndex(); removeIsEnd(); - removeLoopIndex(); + // 注释掉该方法,避免在 loopCondition 无法正常获取 index,同时其他 condition 无 loop 相关对象设置,只有循环相关 condition 会进行赋值,并且 LoopCondition 执行结束也会执行该方法 +// removeLoopIndex(); removeAccessResult(); removeIsContinueOnErrorResult(); } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java index 50f0a56e3..868da630e 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java @@ -60,11 +60,17 @@ public class ForCondition extends LoopCondition { executableItem.setCurrChainId(this.getCurrChainId()); // 设置循环index setLoopIndex(executableItem, i); + // 为当前迭代器设置 index + setLoopIndex(forNode, i); + // 设置 DO 执行对象中当前所属的 Iterator 对象 + setParentLoopObject(executableItem, forNode); executableItem.execute(slotIndex); // 如果break组件不为空,则去执行 if (ObjectUtil.isNotNull(breakItem)) { breakItem.setCurrChainId(this.getCurrChainId()); setLoopIndex(breakItem, i); + // 设置 DO 执行对象中当前所属的 Iterator 对象 + setParentLoopObject(breakItem, forNode); breakItem.execute(slotIndex); boolean isBreak = breakItem.getItemResultMetaValue(slotIndex); if (isBreak) { @@ -81,11 +87,13 @@ public class ForCondition extends LoopCondition { for (int i = 0; i < forCount; i++){ //提交异步任务 CompletableFuture future = - CompletableFuture.supplyAsync(new LoopParallelSupplier(executableItem, this.getCurrChainId(), slotIndex, i), parallelExecutor); + CompletableFuture.supplyAsync(new LoopParallelSupplier(executableItem, this.getCurrChainId(), slotIndex, i, null, forNode), parallelExecutor); futureList.add(future); if (ObjectUtil.isNotNull(breakItem)) { breakItem.setCurrChainId(this.getCurrChainId()); setLoopIndex(breakItem, i); + // 设置 DO 执行对象中当前所属的 Iterator 对象 + setParentLoopObject(breakItem, forNode); breakItem.execute(slotIndex); boolean isBreak = breakItem.getItemResultMetaValue(slotIndex); if (isBreak) { @@ -98,6 +106,7 @@ public class ForCondition extends LoopCondition { } } finally { removeLoopIndex(executableItem); + removeParentLoopObject(executableItem); } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java index 6988e59a9..5f2ca62ec 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java @@ -60,6 +60,10 @@ public class IteratorCondition extends LoopCondition { setLoopIndex(executableItem, index); // 设置循环迭代器对象 setCurrLoopObject(executableItem, itObj); + // 为当前迭代器设置 index + setLoopIndex(iteratorNode, index); + // 为当前迭代器设置对象 + setCurrLoopObject(iteratorNode, itObj); // 设置 DO 执行对象中当前所属的 Iterator 对象 setParentLoopObject(executableItem, iteratorNode); // 执行可执行对象 diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java index 278e0e103..88d2b5e2c 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java @@ -131,7 +131,7 @@ public abstract class LoopCondition extends Condition { private final Integer slotIndex; private final Integer loopIndex; private final Object itObj; - private final Node iteratorNode; + private final Node loopNode; public LoopParallelSupplier(Executable executableItem, String currChainId, Integer slotIndex, Integer loopIndex) { this.executableItem = executableItem; @@ -139,16 +139,16 @@ public abstract class LoopCondition extends Condition { this.slotIndex = slotIndex; this.loopIndex = loopIndex; this.itObj = null; - this.iteratorNode = null; + this.loopNode = null; } - public LoopParallelSupplier(Executable executableItem, String currChainId, Integer slotIndex, Integer loopIndex, Object itObj, Node iteratorNode) { + public LoopParallelSupplier(Executable executableItem, String currChainId, Integer slotIndex, Integer loopIndex, Object itObj, Node loopNode) { this.executableItem = executableItem; this.currChainId = currChainId; this.slotIndex = slotIndex; this.loopIndex = loopIndex; this.itObj = itObj; - this.iteratorNode = iteratorNode; + this.loopNode = loopNode; } @@ -158,13 +158,17 @@ public abstract class LoopCondition extends Condition { executableItem.setCurrChainId(this.currChainId); // 设置循环index setLoopIndex(executableItem, loopIndex); + // 为当前迭代器设置 index + setLoopIndex(loopNode, loopIndex); //IteratorCondition的情况下,需要设置当前循环对象 if(itObj != null){ + // 为当前迭代器设置 object + setCurrLoopObject(loopNode, itObj); setCurrLoopObject(executableItem, itObj); } // 设置 DO 执行对象中当前所属的 Iterator 对象 - if (iteratorNode != null) { - setParentLoopObject(executableItem, iteratorNode); + if (loopNode != null) { + setParentLoopObject(executableItem, loopNode); } executableItem.execute(slotIndex); return LoopFutureObj.success(executableItem.getId()); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java index 0e00e761f..dd8a11837 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java @@ -3,6 +3,7 @@ package com.yomahub.liteflow.flow.element.condition; import cn.hutool.core.util.ObjectUtil; import com.yomahub.liteflow.enums.ConditionTypeEnum; import com.yomahub.liteflow.flow.element.Executable; +import com.yomahub.liteflow.flow.element.Node; import com.yomahub.liteflow.flow.parallel.LoopFutureObj; import com.yomahub.liteflow.thread.ExecutorHelper; @@ -15,6 +16,7 @@ import java.util.concurrent.ExecutorService; * 循环条件Condition * * @author Bryan.Zhang + * @author luo yi * @since 2.9.0 */ public class WhileCondition extends LoopCondition { @@ -37,49 +39,60 @@ public class WhileCondition extends LoopCondition { // 获取Break节点 Executable breakItem = this.getBreakItem(); - // 循环执行 - int index = 0; - if(!this.isParallel()){ - //串行循环 - while (getWhileResult(slotIndex, index)) { - executableItem.setCurrChainId(this.getCurrChainId()); - setLoopIndex(executableItem, index); - executableItem.execute(slotIndex); - // 如果break组件不为空,则去执行 - if (ObjectUtil.isNotNull(breakItem)) { - breakItem.setCurrChainId(this.getCurrChainId()); - setLoopIndex(breakItem, index); - breakItem.execute(slotIndex); - boolean isBreak = breakItem.getItemResultMetaValue(slotIndex); - if (isBreak) { - break; + try { + // 循环执行 + int index = 0; + if (!this.isParallel()) { + //串行循环 + while (getWhileResult(slotIndex, index)) { + executableItem.setCurrChainId(this.getCurrChainId()); + setLoopIndex(executableItem, index); + // 设置 DO 执行对象中当前所属的 Iterator 对象 + setParentLoopObject(executableItem, (Node) whileItem); + executableItem.execute(slotIndex); + // 如果break组件不为空,则去执行 + if (ObjectUtil.isNotNull(breakItem)) { + breakItem.setCurrChainId(this.getCurrChainId()); + setLoopIndex(breakItem, index); + // 设置 DO 执行对象中当前所属的 Iterator 对象 + setParentLoopObject(breakItem, (Node) whileItem); + breakItem.execute(slotIndex); + boolean isBreak = breakItem.getItemResultMetaValue(slotIndex); + if (isBreak) { + break; + } } + index++; } - index++; - } - }else{ - //并行循环逻辑 - List> futureList = new ArrayList<>(); - //获取并行循环的线程池 - ExecutorService parallelExecutor = ExecutorHelper.loadInstance().buildLoopParallelExecutor(); - while (getWhileResult(slotIndex, index)){ - CompletableFuture future = - CompletableFuture.supplyAsync(new LoopParallelSupplier(executableItem, this.getCurrChainId(), slotIndex, index), parallelExecutor); - futureList.add(future); - //break判断 - if (ObjectUtil.isNotNull(breakItem)) { - breakItem.setCurrChainId(this.getCurrChainId()); - setLoopIndex(breakItem, index); - breakItem.execute(slotIndex); - boolean isBreak = breakItem.getItemResultMetaValue(slotIndex); - if (isBreak) { - break; + } else { + //并行循环逻辑 + List> futureList = new ArrayList<>(); + //获取并行循环的线程池 + ExecutorService parallelExecutor = ExecutorHelper.loadInstance().buildLoopParallelExecutor(); + while (getWhileResult(slotIndex, index)) { + CompletableFuture future = + CompletableFuture.supplyAsync(new LoopParallelSupplier(executableItem, this.getCurrChainId(), slotIndex, index, null, (Node) whileItem), parallelExecutor); + futureList.add(future); + //break判断 + if (ObjectUtil.isNotNull(breakItem)) { + breakItem.setCurrChainId(this.getCurrChainId()); + setLoopIndex(breakItem, index); + // 设置 DO 执行对象中当前所属的 Iterator 对象 + setParentLoopObject(breakItem, (Node) whileItem); + breakItem.execute(slotIndex); + boolean isBreak = breakItem.getItemResultMetaValue(slotIndex); + if (isBreak) { + break; + } } + index++; } - index++; + //等待所有的异步执行完毕 + handleFutureList(futureList); } - //等待所有的异步执行完毕 - handleFutureList(futureList); + } finally { + removeLoopIndex(executableItem); + removeParentLoopObject(executableItem); } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/Br1Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/Br1Cmp.java index ce29d394e..e220fd600 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/Br1Cmp.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/Br1Cmp.java @@ -11,6 +11,9 @@ public class Br1Cmp extends NodeBooleanComponent { System.out.println("breakCmp get current iterator object : " + this.getCurrLoopObj().toString()); System.out.println("breakCmp get first layer parent iterator object : " + this.getParentLoopObj().toString()); System.out.println("breakCmp get second layer parent iterator object : " + this.getParentLoopObj(2).toString()); + System.out.println("breakCmp get current iterator index : " + this.getLoopIndex().toString()); + System.out.println("breakCmp get first layer parent iterator index : " + this.getParentLoopIndex().toString()); + System.out.println("breakCmp get second layer parent iterator index : " + this.getParentLoopIndex(2).toString()); return false; } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/DCmp.java index a8b0aad0a..ad20914fa 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/DCmp.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/DCmp.java @@ -12,5 +12,8 @@ public class DCmp extends NodeComponent { System.out.println("get current iterator object : " + this.getCurrLoopObj().toString()); System.out.println("get first layer parent iterator object : " + this.getParentLoopObj().toString()); System.out.println("get second layer parent iterator object : " + this.getParentLoopObj(2).toString()); + System.out.println("get current iterator index : " + this.getLoopIndex().toString()); + System.out.println("get first layer parent iterator index : " + this.getParentLoopIndex().toString()); + System.out.println("get second layer parent iterator index : " + this.getParentLoopIndex(2).toString()); } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/LoopELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/LoopELSpringbootTest.java index ac5916b09..b33b013c3 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/LoopELSpringbootTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/LoopELSpringbootTest.java @@ -11,6 +11,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.ComponentScan; import org.springframework.test.context.TestPropertySource; + import javax.annotation.Resource; import java.util.List; @@ -108,4 +109,12 @@ public class LoopELSpringbootTest extends BaseTest { LiteflowResponse response = flowExecutor.execute2Resp("chain9", "arg"); Assertions.assertTrue(response.isSuccess()); } + + // 嵌套循环测试,获取顶层循环下标 + @Test + public void testLoop10() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain10", "arg"); + Assertions.assertTrue(response.isSuccess()); + } + } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/cmp/Br1Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/cmp/Br1Cmp.java new file mode 100644 index 000000000..eb48dde0b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/cmp/Br1Cmp.java @@ -0,0 +1,17 @@ +package com.yomahub.liteflow.test.loop.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeBooleanComponent; + +@LiteflowComponent("br1") +public class Br1Cmp extends NodeBooleanComponent { + + @Override + public boolean processBoolean() throws Exception { + System.out.println("breakCmp get current loop index : " + this.getLoopIndex().toString()); + System.out.println("breakCmp get first layer parent loop index : " + this.getParentLoopIndex().toString()); + System.out.println("breakCmp get second layer parent loop index : " + this.getParentLoopIndex(2).toString()); + return false; + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/cmp/GCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/cmp/GCmp.java new file mode 100644 index 000000000..b24e3c365 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/loop/cmp/GCmp.java @@ -0,0 +1,16 @@ + +package com.yomahub.liteflow.test.loop.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("g") +public class GCmp extends NodeComponent { + + @Override + public void process() throws Exception { + System.out.println("get current loop index : " + this.getLoopIndex().toString()); + System.out.println("get first layer parent loop index : " + this.getParentLoopIndex().toString()); + System.out.println("get second layer parent loop index : " + this.getParentLoopIndex(2).toString()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/loop/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/loop/flow.xml index 6dcdb59e4..2afcc3f93 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/loop/flow.xml +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/loop/flow.xml @@ -52,4 +52,13 @@ FOR(2).DO(THEN(c, c, c)); + + + FOR(2).DO( + WHILE(z).DO( + FOR(x).DO(THEN(c, g)).BREAK(br1) + ) + ); + + \ No newline at end of file -- Gitee