From 1c2b75e08dc1b525f262c70c0d3b8847f1a0f8dc Mon Sep 17 00:00:00 2001 From: "everywhere.z" Date: Thu, 29 Sep 2022 01:04:05 +0800 Subject: [PATCH] =?UTF-8?q?feature=20#I5RV5D=20=E5=BE=AA=E7=8E=AF=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=E7=89=B9=E6=80=A7=E7=9A=84=E5=A2=9E=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/LiteflowBreakCmpDefine.java | 10 +++ .../annotation/LiteflowForCmpDefine.java | 10 +++ .../annotation/LiteflowWhileCmpDefine.java | 10 +++ .../liteflow/builder/LiteFlowNodeBuilder.java | 36 +++++++++ .../builder/el/LiteFlowChainELBuilder.java | 4 + .../builder/el/operator/BreakOperator.java | 54 +++++++++++++ .../builder/el/operator/DoOperator.java | 50 +++++++++++++ .../builder/el/operator/ForOperator.java | 46 ++++++++++++ .../builder/el/operator/WhileOperator.java | 36 +++++++++ .../el/operator/base/OperatorHelper.java | 2 +- .../liteflow/core/ComponentInitializer.java | 10 +-- .../liteflow/core/NodeBreakComponent.java | 21 ++++++ .../liteflow/core/NodeForComponent.java | 22 ++++++ .../liteflow/core/NodeWhileComponent.java | 21 ++++++ .../liteflow/core/ScriptBreakComponent.java | 19 +++++ .../liteflow/core/ScriptForComponent.java | 19 +++++ .../liteflow/core/ScriptWhileComponent.java | 20 +++++ .../liteflow/core/proxy/ComponentProxy.java | 5 +- .../enums/AnnotationNodeTypeEnum.java | 14 +++- .../liteflow/enums/ConditionTypeEnum.java | 6 +- .../liteflow/enums/LiteFlowMethodEnum.java | 3 + .../yomahub/liteflow/enums/NodeTypeEnum.java | 72 ++++++++++++++++-- .../exception/NoForNodeException.java | 25 +++++++ .../exception/NoWhileNodeException.java | 25 +++++++ .../com/yomahub/liteflow/flow/FlowBus.java | 66 +++++++++++++--- .../flow/element/condition/ForCondition.java | 75 +++++++++++++++++++ .../flow/element/condition/IfCondition.java | 2 +- .../flow/element/condition/LoopCondition.java | 23 ++++++ .../element/condition/WhileCondition.java | 74 ++++++++++++++++++ .../liteflow/parser/helper/ParserHelper.java | 39 +++++++--- .../java/com/yomahub/liteflow/slot/Slot.java | 30 ++++++++ .../yomahub/liteflow/util/LOGOPrinter.java | 2 + .../liteflow/util/LiteFlowProxyUtil.java | 29 +++++-- .../script/groovy/GroovyScriptExecutor.java | 2 +- 34 files changed, 832 insertions(+), 50 deletions(-) create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowBreakCmpDefine.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowForCmpDefine.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowWhileCmpDefine.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/BreakOperator.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/DoOperator.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ForOperator.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/WhileOperator.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeBreakComponent.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeForComponent.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeWhileComponent.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptBreakComponent.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptForComponent.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptWhileComponent.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/exception/NoForNodeException.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/exception/NoWhileNodeException.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowBreakCmpDefine.java b/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowBreakCmpDefine.java new file mode 100644 index 000000000..18f35c903 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowBreakCmpDefine.java @@ -0,0 +1,10 @@ +package com.yomahub.liteflow.annotation; + +import java.lang.annotation.*; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface LiteflowBreakCmpDefine { +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowForCmpDefine.java b/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowForCmpDefine.java new file mode 100644 index 000000000..ae8d5f220 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowForCmpDefine.java @@ -0,0 +1,10 @@ +package com.yomahub.liteflow.annotation; + +import java.lang.annotation.*; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface LiteflowForCmpDefine { +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowWhileCmpDefine.java b/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowWhileCmpDefine.java new file mode 100644 index 000000000..e7d0ff67c --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowWhileCmpDefine.java @@ -0,0 +1,10 @@ +package com.yomahub.liteflow.annotation; + +import java.lang.annotation.*; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface LiteflowWhileCmpDefine { +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java index e4720e29e..befa91137 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java @@ -36,6 +36,18 @@ public class LiteFlowNodeBuilder { return new LiteFlowNodeBuilder(NodeTypeEnum.IF); } + public static LiteFlowNodeBuilder createForNode() { + return new LiteFlowNodeBuilder(NodeTypeEnum.FOR); + } + + public static LiteFlowNodeBuilder createWhileNode() { + return new LiteFlowNodeBuilder(NodeTypeEnum.WHILE); + } + + public static LiteFlowNodeBuilder createBreakNode() { + return new LiteFlowNodeBuilder(NodeTypeEnum.BREAK); + } + public static LiteFlowNodeBuilder createScriptNode() { return new LiteFlowNodeBuilder(NodeTypeEnum.SCRIPT); } @@ -48,6 +60,18 @@ public class LiteFlowNodeBuilder { return new LiteFlowNodeBuilder(NodeTypeEnum.IF_SCRIPT); } + public static LiteFlowNodeBuilder createScriptForNode() { + return new LiteFlowNodeBuilder(NodeTypeEnum.FOR_SCRIPT); + } + + public static LiteFlowNodeBuilder createScriptWhileNode() { + return new LiteFlowNodeBuilder(NodeTypeEnum.WHILE_SCRIPT); + } + + public static LiteFlowNodeBuilder createScriptBreakNode() { + return new LiteFlowNodeBuilder(NodeTypeEnum.BREAK_SCRIPT); + } + public LiteFlowNodeBuilder() { this.node = new Node(); } @@ -114,12 +138,24 @@ public class LiteFlowNodeBuilder { FlowBus.addSwitchNode(this.node.getId(), this.node.getName(), this.node.getClazz()); } else if (this.node.getType().equals(NodeTypeEnum.IF)) { FlowBus.addIfNode(this.node.getId(), this.node.getName(), this.node.getClazz()); + } else if (this.node.getType().equals(NodeTypeEnum.FOR)) { + FlowBus.addForNode(this.node.getId(), this.node.getName(), this.node.getClazz()); + } else if (this.node.getType().equals(NodeTypeEnum.WHILE)) { + FlowBus.addWhileNode(this.node.getId(), this.node.getName(), this.node.getClazz()); + } else if (this.node.getType().equals(NodeTypeEnum.BREAK)) { + FlowBus.addBreakNode(this.node.getId(), this.node.getName(), this.node.getClazz()); } else if (this.node.getType().equals(NodeTypeEnum.SCRIPT)) { FlowBus.addCommonScriptNode(this.node.getId(), this.node.getName(), this.node.getScript()); } else if (this.node.getType().equals(NodeTypeEnum.SWITCH_SCRIPT)) { FlowBus.addSwitchScriptNode(this.node.getId(), this.node.getName(), this.node.getScript()); } else if (this.node.getType().equals(NodeTypeEnum.IF_SCRIPT)) { FlowBus.addIfScriptNode(this.node.getId(), this.node.getName(), this.node.getScript()); + } else if (this.node.getType().equals(NodeTypeEnum.FOR_SCRIPT)) { + FlowBus.addForScriptNode(this.node.getId(), this.node.getName(), this.node.getScript()); + } else if (this.node.getType().equals(NodeTypeEnum.WHILE_SCRIPT)) { + FlowBus.addWhileScriptNode(this.node.getId(), this.node.getName(), this.node.getScript()); + } else if (this.node.getType().equals(NodeTypeEnum.BREAK_SCRIPT)) { + FlowBus.addBreakScriptNode(this.node.getId(), this.node.getName(), this.node.getScript()); } } catch (Exception e) { String errMsg = StrUtil.format("An exception occurred while building the node[{}],{}", this.node.getId(),e.getMessage()); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java index 18afa290d..c0bd0c650 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java @@ -61,6 +61,10 @@ public class LiteFlowChainELBuilder { EXPRESS_RUNNER.addFunctionAndClassMethod("ignoreError", Object.class, new IgnoreErrorOperator()); EXPRESS_RUNNER.addFunctionAndClassMethod("threadPool", Object.class, new ThreadPoolOperator()); EXPRESS_RUNNER.addFunction("node", new NodeOperator()); + EXPRESS_RUNNER.addFunction("FOR", new ForOperator()); + + EXPRESS_RUNNER.addFunctionAndClassMethod("DO", Object.class, new DoOperator()); + EXPRESS_RUNNER.addFunctionAndClassMethod("BREAK", Object.class, new BreakOperator()); } public static LiteFlowChainELBuilder createChain() { diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/BreakOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/BreakOperator.java new file mode 100644 index 000000000..1165a73c1 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/BreakOperator.java @@ -0,0 +1,54 @@ +package com.yomahub.liteflow.builder.el.operator; + +import cn.hutool.core.collection.ListUtil; +import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; +import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; +import com.yomahub.liteflow.enums.NodeTypeEnum; +import com.yomahub.liteflow.flow.element.Node; +import com.yomahub.liteflow.flow.element.condition.Condition; +import com.yomahub.liteflow.flow.element.condition.ForCondition; +import com.yomahub.liteflow.flow.element.condition.LoopCondition; +import com.yomahub.liteflow.flow.element.condition.WhileCondition; + +/** + * EL规则中的BREAK的操作符 + * 有两种用法 + * FOR...DO...BREAK + * WHILE...DO...BREAK + * + * @author Bryan.Zhang + * @since 2.9.0 + */ +public class BreakOperator extends BaseOperator { + @Override + public LoopCondition build(Object[] objects) throws Exception { + OperatorHelper.checkObjectSizeEqTwo(objects); + + //由于BREAK关键字有可能用在FOR后面,也有可能用于WHILE后面,所以这里要进行判断 + LoopCondition condition; + if (objects[0] instanceof ForCondition){ + //获得caller,也就是ForCondition + condition = OperatorHelper.convert(objects[0], ForCondition.class); + }else if(objects[0] instanceof WhileCondition){ + //获得caller,也就是WhileCondition + condition = OperatorHelper.convert(objects[0], WhileCondition.class); + }else{ + throw new QLException("The caller must be ForCondition or WhileCondition item"); + } + + //获得需要执行的可执行表达式 + if (objects[1] instanceof Node){ + Node breakNode = OperatorHelper.convert(objects[1], Node.class); + + if (ListUtil.toList(NodeTypeEnum.BREAK, NodeTypeEnum.BREAK_SCRIPT).contains(breakNode.getType())){ + condition.setBreakNode(breakNode); + }else{ + throw new QLException("The parameter must be node-break item"); + } + }else{ + throw new QLException("The parameter must be Node item"); + } + return condition; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/DoOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/DoOperator.java new file mode 100644 index 000000000..2f368cf8c --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/DoOperator.java @@ -0,0 +1,50 @@ +package com.yomahub.liteflow.builder.el.operator; + +import cn.hutool.core.collection.ListUtil; +import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; +import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; +import com.yomahub.liteflow.flow.element.Executable; +import com.yomahub.liteflow.flow.element.condition.Condition; +import com.yomahub.liteflow.flow.element.condition.ForCondition; +import com.yomahub.liteflow.flow.element.condition.LoopCondition; +import com.yomahub.liteflow.flow.element.condition.WhileCondition; + +/** + * EL规则中的DO的操作符 + * 有两种用法 + * FOR...DO...BREAK + * WHILE...DO...BREAK + * + * @author Bryan.Zhang + * @since 2.9.0 + */ +public class DoOperator extends BaseOperator { + @Override + public LoopCondition build(Object[] objects) throws Exception { + OperatorHelper.checkObjectSizeEqTwo(objects); + + //由于DO关键字有可能用在FOR后面,也有可能用于WHILE后面,所以这里要进行判断 + LoopCondition condition; + if (objects[0] instanceof ForCondition){ + //获得caller,也就是ForCondition + condition = OperatorHelper.convert(objects[0], ForCondition.class); + }else if(objects[0] instanceof WhileCondition){ + //获得caller,也就是WhileCondition + condition = OperatorHelper.convert(objects[0], WhileCondition.class); + }else{ + throw new QLException("The caller must be ForCondition or WhileCondition item"); + } + + //获得需要执行的可执行表达式 + if (objects[1] instanceof Executable){ + Executable doExecutableItem = OperatorHelper.convert(objects[1], Executable.class); + + condition.setExecutableList(ListUtil.toList(doExecutableItem)); + }else{ + throw new QLException("The parameter must be Executable item"); + } + + return condition; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ForOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ForOperator.java new file mode 100644 index 000000000..ea937cb3d --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ForOperator.java @@ -0,0 +1,46 @@ +package com.yomahub.liteflow.builder.el.operator; + +import cn.hutool.core.collection.ListUtil; +import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; +import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; +import com.yomahub.liteflow.core.NodeForComponent; +import com.yomahub.liteflow.enums.NodeTypeEnum; +import com.yomahub.liteflow.flow.element.Node; +import com.yomahub.liteflow.flow.element.condition.ForCondition; + +/** + * EL规则中的FOR的操作符 + * + * @author Bryan.Zhang + * @since 2.9.0 + */ +public class ForOperator extends BaseOperator { + @Override + public ForCondition build(Object[] objects) throws Exception { + OperatorHelper.checkObjectSizeEq(objects, 1); + + Node node; + if (objects[0] instanceof Node) { + node = (Node) objects[0]; + if (!ListUtil.toList(NodeTypeEnum.FOR, NodeTypeEnum.FOR_SCRIPT).contains(node.getType())) { + throw new QLException("The parameter must be for-node item"); + } + }else if(objects[0] instanceof Integer){ + Integer forCount = (Integer) objects[0]; + node = new Node(); + node.setInstance(new NodeForComponent() { + @Override + public int processFor(){ + return forCount; + } + }); + }else{ + throw new QLException("The parameter must be Node item"); + } + + ForCondition forCondition = new ForCondition(); + forCondition.setForNode(node); + return forCondition; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/WhileOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/WhileOperator.java new file mode 100644 index 000000000..bc61dd551 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/WhileOperator.java @@ -0,0 +1,36 @@ +package com.yomahub.liteflow.builder.el.operator; + +import cn.hutool.core.collection.ListUtil; +import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; +import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; +import com.yomahub.liteflow.enums.NodeTypeEnum; +import com.yomahub.liteflow.flow.element.Node; +import com.yomahub.liteflow.flow.element.condition.WhileCondition; + +/** + * EL规则中的WHILE的操作符 + * + * @author Bryan.Zhang + * @since 2.9.0 + */ +public class WhileOperator extends BaseOperator { + @Override + public WhileCondition build(Object[] objects) throws Exception { + OperatorHelper.checkObjectSizeEq(objects, 1); + + Node node; + if (objects[0] instanceof Node){ + node = (Node) objects[0]; + if (!ListUtil.toList(NodeTypeEnum.WHILE, NodeTypeEnum.WHILE_SCRIPT).contains(node.getType())) { + throw new QLException("The parameter must be while-node item"); + } + }else{ + throw new QLException("The parameter must be Node item"); + } + + WhileCondition whileCondition = new WhileCondition(); + whileCondition.setWhileNode(node); + return whileCondition; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/OperatorHelper.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/OperatorHelper.java index 4fe837d11..e38af4d28 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/OperatorHelper.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/OperatorHelper.java @@ -126,7 +126,7 @@ public class OperatorHelper { return (T) object; } - throw new QLException("The caller must be " + tClass.getName() + " item"); + throw new QLException("The parameter must be " + tClass.getName() + " item"); } /** diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ComponentInitializer.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ComponentInitializer.java index a27e1e014..5155e1442 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ComponentInitializer.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ComponentInitializer.java @@ -29,7 +29,7 @@ public class ComponentInitializer { return instance; } - public NodeComponent initComponent(NodeComponent nodeComponent, NodeTypeEnum type, String desc, String nodeId){ + public NodeComponent initComponent(NodeComponent nodeComponent, NodeTypeEnum type, String name, String nodeId){ nodeComponent.setNodeId(nodeId); nodeComponent.setSelf(nodeComponent); nodeComponent.setType(type); @@ -42,11 +42,9 @@ public class ComponentInitializer { //先取传进来的name值(配置文件中配置的),再看有没有配置@LiteflowComponent标注 //@LiteflowComponent标注只在spring体系下生效,这里用了spi机制取到相应环境下的实现类 - nodeComponent.setName(desc); - if (ListUtil.toList(NodeTypeEnum.COMMON, NodeTypeEnum.SWITCH, NodeTypeEnum.IF).contains(type) - && StrUtil.isBlank(nodeComponent.getName())){ - String name = LiteflowComponentSupportHolder.loadLiteflowComponentSupport().getCmpName(nodeComponent); - nodeComponent.setName(name); + nodeComponent.setName(name); + if (!type.isScript() && StrUtil.isBlank(nodeComponent.getName())){ + nodeComponent.setName(LiteflowComponentSupportHolder.loadLiteflowComponentSupport().getCmpName(nodeComponent)); } //先从组件上取@RetryCount标注,如果没有,则看全局配置,全局配置如果不配置的话,默认是0 diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeBreakComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeBreakComponent.java new file mode 100644 index 000000000..75bbcdd8a --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeBreakComponent.java @@ -0,0 +1,21 @@ +package com.yomahub.liteflow.core; + +import com.yomahub.liteflow.slot.Slot; +import com.yomahub.liteflow.util.LiteFlowProxyUtil; + +/** + * 循环跳出节点逻辑抽象类 + * @author Bryan.Zhang + * @since 2.9.0 + */ +public abstract class NodeBreakComponent extends NodeComponent{ + @Override + public void process() throws Exception { + boolean breakFlag = processBreak(); + Slot slot = this.getSlot(); + Class originalClass = LiteFlowProxyUtil.getUserClass(this.getClass()); + slot.setBreakResult(originalClass.getName(), breakFlag); + } + + public abstract boolean processBreak() throws Exception; +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeForComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeForComponent.java new file mode 100644 index 000000000..0c8b4d458 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeForComponent.java @@ -0,0 +1,22 @@ +package com.yomahub.liteflow.core; + +import com.yomahub.liteflow.slot.Slot; +import com.yomahub.liteflow.util.LiteFlowProxyUtil; + +/** + * FOR计数节点抽象类 + * @author Bryan.Zhang + * @since 2.9.0 + */ +public abstract class NodeForComponent extends NodeComponent{ + + @Override + public void process() throws Exception { + int forCount = processFor(); + Slot slot = this.getSlot(); + Class originalClass = LiteFlowProxyUtil.getUserClass(this.getClass()); + slot.setForResult(originalClass.getName(), forCount); + } + + public abstract int processFor() throws Exception; +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeWhileComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeWhileComponent.java new file mode 100644 index 000000000..1aa4216a5 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeWhileComponent.java @@ -0,0 +1,21 @@ +package com.yomahub.liteflow.core; + +import com.yomahub.liteflow.slot.Slot; +import com.yomahub.liteflow.util.LiteFlowProxyUtil; + +/** + * WHILE条件节点抽象类 + * @author Bryan.Zhang + * @since 2.9.0 + */ +public abstract class NodeWhileComponent extends NodeComponent{ + @Override + public void process() throws Exception { + boolean whileFlag = processWhile(); + Slot slot = this.getSlot(); + Class originalClass = LiteFlowProxyUtil.getUserClass(this.getClass()); + slot.setWhileResult(originalClass.getName(), whileFlag); + } + + public abstract boolean processWhile() throws Exception; +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptBreakComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptBreakComponent.java new file mode 100644 index 000000000..7e47d3115 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptBreakComponent.java @@ -0,0 +1,19 @@ +package com.yomahub.liteflow.core; + +import com.yomahub.liteflow.script.ScriptExecutorFactory; + +/** + * 脚本BREAK节点 + * @author Bryan.Zhang + * @since 2.9.0 + */ +public class ScriptBreakComponent extends NodeBreakComponent{ + @Override + public boolean processBreak() throws Exception { + return (boolean) ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(this.getCurrChainName(), getNodeId(), getSlotIndex()); + } + + public void loadScript(String script) { + ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptForComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptForComponent.java new file mode 100644 index 000000000..6b52308e1 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptForComponent.java @@ -0,0 +1,19 @@ +package com.yomahub.liteflow.core; + +import com.yomahub.liteflow.script.ScriptExecutorFactory; + +/** + * 脚本FOR节点 + * @author Bryan.Zhang + * @since 2.9.0 + */ +public class ScriptForComponent extends NodeForComponent{ + @Override + public int processFor() throws Exception { + return (int) ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(this.getCurrChainName(), getNodeId(), getSlotIndex()); + } + + public void loadScript(String script) { + ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptWhileComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptWhileComponent.java new file mode 100644 index 000000000..8c43d4d0f --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/ScriptWhileComponent.java @@ -0,0 +1,20 @@ +package com.yomahub.liteflow.core; + +import com.yomahub.liteflow.script.ScriptExecutorFactory; + +/** + * 脚本WHILE节点 + * @author Bryan.Zhang + * @since 2.9.0 + */ +public class ScriptWhileComponent extends NodeWhileComponent{ + + @Override + public boolean processWhile() throws Exception { + return (boolean) ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(this.getCurrChainName(), getNodeId(), getSlotIndex()); + } + + public void loadScript(String script) { + ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ComponentProxy.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ComponentProxy.java index d643664e6..19639dad3 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ComponentProxy.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ComponentProxy.java @@ -105,7 +105,10 @@ public class ComponentProxy { boolean existRetry = liteflowRetry != null; boolean isProcess = liteflowMethod.value().equals(LiteFlowMethodEnum.PROCESS) || liteflowMethod.value().equals(LiteFlowMethodEnum.PROCESS_IF) - || liteflowMethod.value().equals(LiteFlowMethodEnum.PROCESS_SWITCH); + || liteflowMethod.value().equals(LiteFlowMethodEnum.PROCESS_SWITCH) + || liteflowMethod.value().equals(LiteFlowMethodEnum.PROCESS_FOR) + || liteflowMethod.value().equals(LiteFlowMethodEnum.PROCESS_WHILE) + || liteflowMethod.value().equals(LiteFlowMethodEnum.PROCESS_BREAK); // 如果是再Process方法上的liteflowRetry注解,则默认为真实节点。 if (isProcess && existRetry) { liteflowRetryAtomicReference.set(liteflowRetry); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/AnnotationNodeTypeEnum.java b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/AnnotationNodeTypeEnum.java index e6ad007a2..0c4ccf29a 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/AnnotationNodeTypeEnum.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/AnnotationNodeTypeEnum.java @@ -1,8 +1,6 @@ package com.yomahub.liteflow.enums; -import com.yomahub.liteflow.core.NodeComponent; -import com.yomahub.liteflow.core.NodeIfComponent; -import com.yomahub.liteflow.core.NodeSwitchComponent; +import com.yomahub.liteflow.core.*; /** * 注解节点类型枚举 @@ -22,7 +20,15 @@ public enum AnnotationNodeTypeEnum { /** * 条件节点 */ - IF("条件", NodeIfComponent.class),; + IF("条件", NodeIfComponent.class), + + FOR("计数循环",NodeForComponent.class), + + WHILE("条件循环", NodeWhileComponent.class), + + BREAK("跳出循环", NodeBreakComponent.class) + ; + /** * 描述 */ diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ConditionTypeEnum.java b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ConditionTypeEnum.java index 6ac4e227a..bbee526cd 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ConditionTypeEnum.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/ConditionTypeEnum.java @@ -7,7 +7,11 @@ public enum ConditionTypeEnum { TYPE_IF("if", "if"), TYPE_PRE("pre","pre"), - TYPE_FINALLY("finally","finally") + TYPE_FINALLY("finally","finally"), + + TYPE_FOR("for", "for"), + + TYPE_WHILE("while", "while") ; private String type; private String name; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/LiteFlowMethodEnum.java b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/LiteFlowMethodEnum.java index 8a447a96a..446e4b673 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/LiteFlowMethodEnum.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/LiteFlowMethodEnum.java @@ -4,6 +4,9 @@ public enum LiteFlowMethodEnum { PROCESS("process"), PROCESS_SWITCH("processSwitch"), PROCESS_IF("processIf"), + PROCESS_FOR("processFor"), + PROCESS_WHILE("processWhile"), + PROCESS_BREAK("processBreak"), IS_ACCESS("isAccess"), IS_END("isEnd"), diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/NodeTypeEnum.java b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/NodeTypeEnum.java index 213ec9a7f..01514f735 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/enums/NodeTypeEnum.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/enums/NodeTypeEnum.java @@ -1,5 +1,8 @@ package com.yomahub.liteflow.enums; +import cn.hutool.core.util.ClassUtil; +import com.yomahub.liteflow.core.*; + /** * 节点类型枚举 * @author Bryan.Zhang @@ -7,22 +10,41 @@ package com.yomahub.liteflow.enums; */ public enum NodeTypeEnum { - COMMON("common","普通"), + COMMON("common","普通", false, NodeComponent.class), - SWITCH("switch", "选择"), + SWITCH("switch", "选择", false, NodeSwitchComponent.class), - IF("if", "条件"), - SCRIPT("script","脚本"), - SWITCH_SCRIPT("switch_script","选择脚本"), + IF("if", "条件", false, NodeIfComponent.class), - IF_SCRIPT("if_script", "条件脚本") + FOR("for","循环次数", false, NodeForComponent.class), + + WHILE("while", "循环条件", false, NodeWhileComponent.class), + + BREAK("break", "循环跳出", false, NodeBreakComponent.class), + SCRIPT("script","脚本", true, ScriptComponent.class), + + SWITCH_SCRIPT("switch_script", "选择脚本", true, ScriptSwitchComponent.class), + + IF_SCRIPT("if_script", "条件脚本", true, ScriptIfComponent.class), + + FOR_SCRIPT("for_script", "循环次数脚本", true, ScriptForComponent.class), + + WHILE_SCRIPT("while_script", "循环条件脚本", true, ScriptWhileComponent.class), + + BREAK_SCRIPT("break_script", "循环跳出脚本", true, ScriptBreakComponent.class) ; private String code; private String name; - NodeTypeEnum(String code, String name) { + private boolean isScript; + + private Class mappingClazz; + + NodeTypeEnum(String code, String name, boolean isScript, Class mappingClazz) { this.code = code; this.name = name; + this.isScript = isScript; + this.mappingClazz = mappingClazz; } public String getCode() { @@ -41,6 +63,22 @@ public enum NodeTypeEnum { this.name = name; } + public boolean isScript() { + return isScript; + } + + public void setScript(boolean script) { + isScript = script; + } + + public Class getMappingClazz() { + return mappingClazz; + } + + public void setMappingClazz(Class mappingClazz) { + this.mappingClazz = mappingClazz; + } + public static NodeTypeEnum getEnumByCode(String code) { for (NodeTypeEnum e : NodeTypeEnum.values()) { if (e.getCode().equals(code)) { @@ -49,4 +87,24 @@ public enum NodeTypeEnum { } return null; } + + public static NodeTypeEnum guessTypeByClazz(Class clazz){ + Class superClazz = clazz; + while(true){ + superClazz = superClazz.getSuperclass(); + if (superClazz.getPackage().getName().startsWith("com.yomahub.liteflow.core")){ + break; + } + if(superClazz.equals(Object.class)){ + return null; + } + } + + for (NodeTypeEnum e : NodeTypeEnum.values()) { + if (e.getMappingClazz().equals(superClazz)) { + return e; + } + } + return null; + } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NoForNodeException.java b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NoForNodeException.java new file mode 100644 index 000000000..026f553a0 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NoForNodeException.java @@ -0,0 +1,25 @@ +package com.yomahub.liteflow.exception; + +public class NoForNodeException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * 异常信息 + */ + private String message; + + public NoForNodeException(String message) { + this.message = message; + } + + @Override + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NoWhileNodeException.java b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NoWhileNodeException.java new file mode 100644 index 000000000..239870d45 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/NoWhileNodeException.java @@ -0,0 +1,25 @@ +package com.yomahub.liteflow.exception; + +public class NoWhileNodeException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * 异常信息 + */ + private String message; + + public NoWhileNodeException(String message) { + this.message = message; + } + + @Override + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java index 6abdf700d..b00450087 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java @@ -86,14 +86,8 @@ public class FlowBus { } public static void addSpringScanNode(String nodeId, NodeComponent nodeComponent) { - NodeTypeEnum type = null; - if (nodeComponent instanceof NodeSwitchComponent){ - type = NodeTypeEnum.SWITCH; - } else if(nodeComponent instanceof NodeIfComponent){ - type = NodeTypeEnum.IF; - }else if(nodeComponent instanceof NodeComponent) { - type = NodeTypeEnum.COMMON; - } + //根据class来猜测类型 + NodeTypeEnum type = NodeTypeEnum.guessTypeByClazz(nodeComponent.getClass()); if (type == null){ throw new NullNodeTypeException(StrUtil.format("node type is null for node[{}]", nodeId)); @@ -144,6 +138,48 @@ public class FlowBus { addNode(nodeId, name, NodeTypeEnum.IF, cmpClazz, null); } + public static void addForNode(String nodeId, String name, String cmpClazzStr){ + Class cmpClazz; + try{ + cmpClazz = Class.forName(cmpClazzStr); + }catch (Exception e){ + throw new ComponentCannotRegisterException(e.getMessage()); + } + addNode(nodeId, name, NodeTypeEnum.FOR, cmpClazz, null); + } + + public static void addForNode(String nodeId, String name, Class cmpClazz){ + addNode(nodeId, name, NodeTypeEnum.FOR, cmpClazz, null); + } + + public static void addWhileNode(String nodeId, String name, String cmpClazzStr){ + Class cmpClazz; + try{ + cmpClazz = Class.forName(cmpClazzStr); + }catch (Exception e){ + throw new ComponentCannotRegisterException(e.getMessage()); + } + addNode(nodeId, name, NodeTypeEnum.WHILE, cmpClazz, null); + } + + public static void addWhileNode(String nodeId, String name, Class cmpClazz){ + addNode(nodeId, name, NodeTypeEnum.WHILE, cmpClazz, null); + } + + public static void addBreakNode(String nodeId, String name, String cmpClazzStr){ + Class cmpClazz; + try{ + cmpClazz = Class.forName(cmpClazzStr); + }catch (Exception e){ + throw new ComponentCannotRegisterException(e.getMessage()); + } + addNode(nodeId, name, NodeTypeEnum.BREAK, cmpClazz, null); + } + + public static void addBreakNode(String nodeId, String name, Class cmpClazz){ + addNode(nodeId, name, NodeTypeEnum.BREAK, cmpClazz, null); + } + public static void addCommonScriptNode(String nodeId, String name, String script){ addNode(nodeId, name, NodeTypeEnum.SCRIPT, ScriptComponent.class, script); } @@ -156,6 +192,18 @@ public class FlowBus { addNode(nodeId, name, NodeTypeEnum.IF_SCRIPT, ScriptIfComponent.class, script); } + public static void addForScriptNode(String nodeId, String name, String script){ + addNode(nodeId, name, NodeTypeEnum.FOR_SCRIPT, ScriptIfComponent.class, script); + } + + public static void addWhileScriptNode(String nodeId, String name, String script){ + addNode(nodeId, name, NodeTypeEnum.WHILE_SCRIPT, ScriptIfComponent.class, script); + } + + public static void addBreakScriptNode(String nodeId, String name, String script){ + addNode(nodeId, name, NodeTypeEnum.BREAK_SCRIPT, ScriptIfComponent.class, script); + } + private static void addNode(String nodeId, String name, NodeTypeEnum type, Class cmpClazz, String script) { try { //判断此类是否是声明式的组件,如果是声明式的组件,就用动态代理生成实例 @@ -179,7 +227,7 @@ public class FlowBus { //以node方式配置,本质上是为了适配无spring的环境,如果有spring环境,其实不用这么配置 //这里的逻辑是判断是否能从spring上下文中取到,如果没有spring,则就是new instance了 //如果是script类型的节点,因为class只有一个,所以也不能注册进spring上下文,注册的时候需要new Instance - if (!CollectionUtil.newArrayList(NodeTypeEnum.SCRIPT, NodeTypeEnum.SWITCH_SCRIPT, NodeTypeEnum.IF_SCRIPT).contains(type)){ + if (!type.isScript()){ cmpInstances = ListUtil.toList((NodeComponent) ContextAwareHolder.loadContextAware().registerOrGet(nodeId, cmpClazz)); } // 去除null元素 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 new file mode 100644 index 000000000..f590683ce --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/ForCondition.java @@ -0,0 +1,75 @@ +package com.yomahub.liteflow.flow.element.condition; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.enums.ConditionTypeEnum; +import com.yomahub.liteflow.exception.NoForNodeException; +import com.yomahub.liteflow.flow.element.Executable; +import com.yomahub.liteflow.flow.element.Node; +import com.yomahub.liteflow.slot.DataBus; +import com.yomahub.liteflow.slot.Slot; +import com.yomahub.liteflow.util.LiteFlowProxyUtil; + +/** + * 循环次数Condition + * + * @author Bryan.Zhang + * @since 2.9.0 + */ +public class ForCondition extends LoopCondition{ + + private Node forNode; + + @Override + public void execute(Integer slotIndex) throws Exception { + Slot slot = DataBus.getSlot(slotIndex); + if (ObjectUtil.isNull(forNode)){ + String errorInfo = StrUtil.format("[{}]:no for-node found", slot.getRequestId()); + throw new NoForNodeException(errorInfo); + } + + //执行forCount组件 + forNode.setCurrChainName(this.getCurrChainName()); + forNode.execute(slotIndex); + + //这里可能会有spring代理过的bean,所以拿到user原始的class + Class originalForCountClass = LiteFlowProxyUtil.getUserClass(this.forNode.getClass()); + //获得循环次数 + int forCount = slot.getForResult(originalForCountClass.getName()); + + //获得要循环的可执行对象 + Executable executableItem = this.getDoExecutor(); + + //循环执行 + for (int i = 0; i < forCount; i++) { + executableItem.execute(slotIndex); + //如果break组件不为空,则去执行 + if (ObjectUtil.isNotNull(breakNode)){ + breakNode.setCurrChainName(this.getCurrChainName()); + Class originalBreakClass = LiteFlowProxyUtil.getUserClass(this.breakNode.getClass()); + boolean isBreak = slot.getBreakResult(originalBreakClass.getName()); + if (isBreak){ + break; + } + } + } + + } + + @Override + public ConditionTypeEnum getConditionType() { + return ConditionTypeEnum.TYPE_FOR; + } + + public Executable getDoExecutor() { + return this.getExecutableList().get(0); + } + + public Node getForNode() { + return forNode; + } + + public void setForNode(Node forNode) { + this.forNode = forNode; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IfCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IfCondition.java index edcdbba18..503600df0 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IfCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IfCondition.java @@ -74,7 +74,7 @@ public class IfCondition extends Condition { @Override public ConditionTypeEnum getConditionType() { - return null; + return ConditionTypeEnum.TYPE_IF; } public Executable getTrueCaseExecutableItem() { 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 new file mode 100644 index 000000000..6435e118f --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/LoopCondition.java @@ -0,0 +1,23 @@ +package com.yomahub.liteflow.flow.element.condition; + +import com.yomahub.liteflow.flow.element.Node; + +/** + * 循环Condition的抽象类 + * 主要继承对象有ForCondition和WhileCondition + * + * @author Bryan.Zhang + * @since 2.9.0 + */ +public abstract class LoopCondition extends Condition { + + protected Node breakNode; + + public Node getBreakNode() { + return breakNode; + } + + public void setBreakNode(Node breakNode) { + this.breakNode = breakNode; + } +} 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 new file mode 100644 index 000000000..a6f260852 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhileCondition.java @@ -0,0 +1,74 @@ +package com.yomahub.liteflow.flow.element.condition; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.enums.ConditionTypeEnum; +import com.yomahub.liteflow.exception.NoWhileNodeException; +import com.yomahub.liteflow.flow.element.Executable; +import com.yomahub.liteflow.flow.element.Node; +import com.yomahub.liteflow.slot.DataBus; +import com.yomahub.liteflow.slot.Slot; +import com.yomahub.liteflow.util.LiteFlowProxyUtil; + +/** + * 循环条件Condition + * + * @author Bryan.Zhang + * @since 2.9.0 + */ +public class WhileCondition extends LoopCondition{ + + private Node whileNode; + + @Override + public void execute(Integer slotIndex) throws Exception { + Slot slot = DataBus.getSlot(slotIndex); + if (ObjectUtil.isNull(whileNode)){ + String errorInfo = StrUtil.format("[{}]:no while-node found", slot.getRequestId()); + throw new NoWhileNodeException(errorInfo); + } + + //获得要循环的可执行对象 + Executable executableItem = this.getDoExecutor(); + + //循环执行 + while(getWhileResult(slotIndex)){ + executableItem.execute(slotIndex); + //如果break组件不为空,则去执行 + if (ObjectUtil.isNotNull(breakNode)){ + breakNode.setCurrChainName(this.getCurrChainName()); + Class originalBreakClass = LiteFlowProxyUtil.getUserClass(this.breakNode.getClass()); + boolean isBreak = slot.getBreakResult(originalBreakClass.getName()); + if (isBreak){ + break; + } + } + } + } + + private boolean getWhileResult(Integer slotIndex) throws Exception{ + Slot slot = DataBus.getSlot(slotIndex); + //执行while组件 + whileNode.setCurrChainName(this.getCurrChainName()); + whileNode.execute(slotIndex); + Class originalWhileClass = LiteFlowProxyUtil.getUserClass(this.whileNode.getClass()); + return slot.getWhileResult(originalWhileClass.getName()); + } + + public Executable getDoExecutor() { + return this.getExecutableList().get(0); + } + + @Override + public ConditionTypeEnum getConditionType() { + return ConditionTypeEnum.TYPE_WHILE; + } + + public Node getWhileNode() { + return whileNode; + } + + public void setWhileNode(Node whileNode) { + this.whileNode = whileNode; + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java index 6d18e2d9e..2234940b9 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java @@ -6,9 +6,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import com.fasterxml.jackson.databind.JsonNode; -import com.yomahub.liteflow.annotation.LiteflowCmpDefine; -import com.yomahub.liteflow.annotation.LiteflowIfCmpDefine; -import com.yomahub.liteflow.annotation.LiteflowSwitchCmpDefine; +import com.yomahub.liteflow.annotation.*; import com.yomahub.liteflow.builder.LiteFlowChainBuilder; import com.yomahub.liteflow.builder.LiteFlowConditionBuilder; import com.yomahub.liteflow.builder.LiteFlowNodeBuilder; @@ -61,18 +59,16 @@ public class ParserHelper { String type = nodePropBean.getType(); String file = nodePropBean.getFile(); - //先尝试自动推断类型 + //clazz有值的,基本都不是脚本节点 + //脚本节点,都必须配置type + //非脚本节点的先尝试自动推断类型 if (StrUtil.isNotBlank(clazz)) { try { //先尝试从继承的类型中推断 Class c = Class.forName(clazz); - Object o = ReflectUtil.newInstanceIfPossible(c); - if (o instanceof NodeSwitchComponent) { - type = NodeTypeEnum.SWITCH.getCode(); - }else if(o instanceof NodeIfComponent){ - type = NodeTypeEnum.IF.getCode(); - }else if (o instanceof NodeComponent) { - type = NodeTypeEnum.COMMON.getCode(); + NodeTypeEnum nodeType = NodeTypeEnum.guessTypeByClazz(c); + if (nodeType != null){ + type = nodeType.getCode(); } //再尝试声明式组件这部分的推断 @@ -96,6 +92,27 @@ public class ParserHelper { type = NodeTypeEnum.IF.getCode(); } } + + if (type == null) { + LiteflowForCmpDefine liteflowForCmpDefine = AnnotationUtil.getAnnotation(c, LiteflowForCmpDefine.class); + if (liteflowForCmpDefine != null) { + type = NodeTypeEnum.FOR.getCode(); + } + } + + if (type == null) { + LiteflowWhileCmpDefine liteflowWhileCmpDefine = AnnotationUtil.getAnnotation(c, LiteflowWhileCmpDefine.class); + if (liteflowWhileCmpDefine != null) { + type = NodeTypeEnum.WHILE.getCode(); + } + } + + if (type == null) { + LiteflowBreakCmpDefine liteflowBreakCmpDefine = AnnotationUtil.getAnnotation(c, LiteflowBreakCmpDefine.class); + if (liteflowBreakCmpDefine != null) { + type = NodeTypeEnum.BREAK.getCode(); + } + } } catch (Exception e) { throw new NodeClassNotFoundException(StrUtil.format("cannot find the node[{}]", clazz)); } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/slot/Slot.java b/liteflow-core/src/main/java/com/yomahub/liteflow/slot/Slot.java index c63c3e80d..37096f875 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/slot/Slot.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/slot/Slot.java @@ -46,6 +46,12 @@ public class Slot{ private static final String IF_NODE_PREFIX = "_if_"; + private static final String FOR_PREFIX = "_for_"; + + private static final String WHILE_PREFIX = "_while_"; + + private static final String BREAK_PREFIX = "_break_"; + private static final String NODE_INPUT_PREFIX = "_input_"; private static final String NODE_OUTPUT_PREFIX = "_output_"; @@ -204,6 +210,30 @@ public class Slot{ return (boolean) metaDataMap.get(IF_NODE_PREFIX + key); } + public void setForResult(String key, int forCount){ + putMetaDataMap(FOR_PREFIX + key, forCount); + } + + public int getForResult(String key){ + return (int) metaDataMap.get(FOR_PREFIX + key); + } + + public void setWhileResult(String key, boolean whileFlag){ + putMetaDataMap(WHILE_PREFIX + key, whileFlag); + } + + public boolean getWhileResult(String key){ + return (boolean) metaDataMap.get(WHILE_PREFIX + key); + } + + public void setBreakResult(String key, boolean breakFlag){ + putMetaDataMap(BREAK_PREFIX + key, breakFlag); + } + + public boolean getBreakResult(String key){ + return (boolean) metaDataMap.get(BREAK_PREFIX + key); + } + public void setChainName(String chainName) { if (!hasMetaData(CHAIN_NAME)){ this.putMetaDataMap(CHAIN_NAME, chainName); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/util/LOGOPrinter.java b/liteflow-core/src/main/java/com/yomahub/liteflow/util/LOGOPrinter.java index 50f4ea2de..dc6e6c5d0 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/util/LOGOPrinter.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/util/LOGOPrinter.java @@ -3,6 +3,8 @@ package com.yomahub.liteflow.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Optional; + /** * logo打印器 * @author Bryan.Zhang diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteFlowProxyUtil.java b/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteFlowProxyUtil.java index 8328cfc86..a647da127 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteFlowProxyUtil.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteFlowProxyUtil.java @@ -2,13 +2,8 @@ package com.yomahub.liteflow.util; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import com.yomahub.liteflow.annotation.LiteflowCmpDefine; -import com.yomahub.liteflow.annotation.LiteflowIfCmpDefine; -import com.yomahub.liteflow.annotation.LiteflowMethod; -import com.yomahub.liteflow.annotation.LiteflowSwitchCmpDefine; -import com.yomahub.liteflow.core.NodeComponent; -import com.yomahub.liteflow.core.NodeIfComponent; -import com.yomahub.liteflow.core.NodeSwitchComponent; +import com.yomahub.liteflow.annotation.*; +import com.yomahub.liteflow.core.*; import com.yomahub.liteflow.core.proxy.ComponentProxy; import com.yomahub.liteflow.exception.ComponentProxyErrorException; import com.yomahub.liteflow.exception.LiteFlowException; @@ -50,6 +45,9 @@ public class LiteFlowProxyUtil { LiteflowCmpDefine liteflowCmpDefine = bean.getClass().getAnnotation(LiteflowCmpDefine.class); LiteflowSwitchCmpDefine liteflowSwitchCmpDefine = bean.getClass().getAnnotation(LiteflowSwitchCmpDefine.class); LiteflowIfCmpDefine liteflowIfCmpDefine = bean.getClass().getAnnotation(LiteflowIfCmpDefine.class); + LiteflowForCmpDefine liteflowForCmpDefine = bean.getClass().getAnnotation(LiteflowForCmpDefine.class); + LiteflowWhileCmpDefine liteflowWhileCmpDefine = bean.getClass().getAnnotation(LiteflowWhileCmpDefine.class); + LiteflowBreakCmpDefine liteflowBreakCmpDefine = bean.getClass().getAnnotation(LiteflowBreakCmpDefine.class); ComponentProxy proxy; if (ObjectUtil.isNotNull(liteflowCmpDefine)){ @@ -66,7 +64,22 @@ public class LiteFlowProxyUtil { proxy = new ComponentProxy(nodeId, bean, NodeIfComponent.class); return proxy.getProxyList(); } - return new ComponentProxy(nodeId, bean, NodeIfComponent.class).getProxyList(); + + if (ObjectUtil.isNotNull(liteflowForCmpDefine)){ + proxy = new ComponentProxy(nodeId, bean, NodeForComponent.class); + return proxy.getProxyList(); + } + + if (ObjectUtil.isNotNull(liteflowWhileCmpDefine)){ + proxy = new ComponentProxy(nodeId, bean, NodeWhileComponent.class); + return proxy.getProxyList(); + } + + if (ObjectUtil.isNotNull(liteflowBreakCmpDefine)){ + proxy = new ComponentProxy(nodeId, bean, NodeBreakComponent.class); + return proxy.getProxyList(); + } + return new ComponentProxy(nodeId, bean, NodeComponent.class).getProxyList(); }catch (LiteFlowException liteFlowException){ throw liteFlowException; } diff --git a/liteflow-script-plugin/liteflow-script-groovy/src/main/java/com/yomahub/liteflow/script/groovy/GroovyScriptExecutor.java b/liteflow-script-plugin/liteflow-script-groovy/src/main/java/com/yomahub/liteflow/script/groovy/GroovyScriptExecutor.java index f6e07db94..217855dcb 100644 --- a/liteflow-script-plugin/liteflow-script-groovy/src/main/java/com/yomahub/liteflow/script/groovy/GroovyScriptExecutor.java +++ b/liteflow-script-plugin/liteflow-script-groovy/src/main/java/com/yomahub/liteflow/script/groovy/GroovyScriptExecutor.java @@ -71,7 +71,7 @@ public class GroovyScriptExecutor implements ScriptExecutor { Slot slot = DataBus.getSlot(slotIndex); bindings.put("requestData", slot.getRequestData()); - //如果有隐试流程,则放入隐式流程的流程参数 + //如果有隐式流程,则放入隐式流程的流程参数 Object subRequestData = slot.getChainReqData(currChainName); if (ObjectUtil.isNotNull(subRequestData)){ bindings.put("subRequestData", subRequestData);