From 9b8902c01cc5650c0262c5f03b605c3b9e98b271 Mon Sep 17 00:00:00 2001 From: "everywhere.z" Date: Wed, 6 Mar 2024 14:03:11 +0800 Subject: [PATCH] =?UTF-8?q?feature=20#I96A33=20=E4=B8=BALF=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=86=B3=E7=AD=96=E8=A1=A8=E7=89=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../builder/el/LiteFlowChainELBuilder.java | 46 ++++++++++++ .../liteflow/common/ChainConstant.java | 4 + .../yomahub/liteflow/flow/element/Chain.java | 10 +++ .../liteflow/parser/helper/ParserHelper.java | 73 +++++++++++-------- .../src/main/resources/dtd/liteflow.dtd | 4 +- .../test/route/RouteSpringbootTest.java | 42 +++++++++++ .../yomahub/liteflow/test/route/cmp/ACmp.java | 20 +++++ .../yomahub/liteflow/test/route/cmp/BCmp.java | 21 ++++++ .../yomahub/liteflow/test/route/cmp/R1.java | 12 +++ .../yomahub/liteflow/test/route/cmp/R2.java | 12 +++ .../resources/route/application.properties | 1 + .../src/test/resources/route/flow.el.xml | 21 ++++++ 12 files changed, 236 insertions(+), 30 deletions(-) create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/RouteSpringbootTest.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/ACmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/BCmp.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/R1.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/R2.java create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/route/application.properties create mode 100644 liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/route/flow.el.xml 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 6de02fb00..91431715d 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 @@ -21,6 +21,7 @@ import com.yomahub.liteflow.exception.ParseException; import com.yomahub.liteflow.flow.FlowBus; import com.yomahub.liteflow.flow.element.Chain; import com.yomahub.liteflow.flow.element.Condition; +import com.yomahub.liteflow.flow.element.Executable; import com.yomahub.liteflow.flow.element.Node; import com.yomahub.liteflow.log.LFLog; import com.yomahub.liteflow.log.LFLoggerManager; @@ -44,6 +45,11 @@ public class LiteFlowChainELBuilder { private Chain chain; + /** + * 这是route EL的文本 + */ + private Executable route; + /** * 这是主体的Condition //声明这个变量,而不是用chain.getConditionList的目的,是为了辅助平滑加载 * 虽然FlowBus里面的map都是CopyOnWrite类型的,但是在buildCondition的时候,为了平滑加载,所以不能事先把chain.getConditionList给设为空List @@ -130,6 +136,45 @@ public class LiteFlowChainELBuilder { return this; } + public LiteFlowChainELBuilder setRoute(String routeEl){ + if (StrUtil.isBlank(routeEl)) { + String errMsg = StrUtil.format("You have defined the label but there is no content in the chain[{}].", chain.getChainId()); + throw new FlowSystemException(errMsg); + } + List errorList = new ArrayList<>(); + try { + DefaultContext context = new DefaultContext<>(); + + // 往上下文里放入所有的node,使得el表达式可以直接引用到nodeId + FlowBus.getNodeMap().keySet().forEach(nodeId -> context.put(nodeId, FlowBus.getNode(nodeId))); + + // 解析route el成为一个executable + Executable routeExecutable = (Executable) EXPRESS_RUNNER.execute(routeEl, context, errorList, true, true); + + if (Objects.isNull(routeExecutable)){ + throw new QLException(StrUtil.format("parse route el fail,el:[{}]", routeEl)); + } + + // 把主要的condition加入 + this.route = routeExecutable; + return this; + } catch (QLException e) { + // EL 底层会包装异常,这里是曲线处理 + if (ObjectUtil.isNotNull(e.getCause()) && Objects.equals(e.getCause().getMessage(), DataNotFoundException.MSG)) { + // 构建错误信息 + String msg = buildDataNotFoundExceptionMsg(routeEl); + throw new ELParseException(msg); + }else if (ObjectUtil.isNotNull(e.getCause())){ + throw new ELParseException(e.getCause().getMessage()); + }else{ + throw new ELParseException(e.getMessage()); + } + } catch (Exception e) { + String errMsg = StrUtil.format("parse el fail in this chain[{}];\r\n", chain.getChainId()); + throw new ELParseException(errMsg + e.getMessage()); + } + } + public LiteFlowChainELBuilder setEL(String elStr) { if (StrUtil.isBlank(elStr)) { String errMsg = StrUtil.format("no content in this chain[{}]", chain.getChainId()); @@ -197,6 +242,7 @@ public class LiteFlowChainELBuilder { } public void build() { + this.chain.setRouteItem(this.route); this.chain.setConditionList(this.conditionList); //暂且去掉循环依赖检测,因为有发现循环依赖检测在对大的EL进行检测的时候,会导致CPU飙升,也或许是jackson低版本的问题 diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java b/liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java index c90600165..149aaa64d 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/common/ChainConstant.java @@ -10,6 +10,10 @@ public interface ChainConstant { String CHAIN = "chain"; + String ROUTE = "route"; + + String BODY = "body"; + String FLOW = "flow"; String NODES = "nodes"; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Chain.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Chain.java index 16cc12546..04cada75d 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Chain.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Chain.java @@ -30,6 +30,8 @@ public class Chain implements Executable{ private String chainId; + private Executable routeItem; + private List conditionList = new ArrayList<>(); public Chain(String chainName) { @@ -133,4 +135,12 @@ public class Chain implements Executable{ public String getTag() { return null; } + + public Executable getRouteItem() { + return routeItem; + } + + public void setRouteItem(Executable routeItem) { + this.routeItem = routeItem; + } } 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 49ab1bf63..cf5f560be 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 @@ -8,12 +8,7 @@ import com.yomahub.liteflow.builder.LiteFlowNodeBuilder; import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder; import com.yomahub.liteflow.builder.prop.NodePropBean; import com.yomahub.liteflow.enums.NodeTypeEnum; -import com.yomahub.liteflow.exception.ChainDuplicateException; -import com.yomahub.liteflow.exception.ChainNotFoundException; -import com.yomahub.liteflow.exception.NodeClassNotFoundException; -import com.yomahub.liteflow.exception.NodeTypeCanNotGuessException; -import com.yomahub.liteflow.exception.NodeTypeNotSupportException; -import com.yomahub.liteflow.exception.ParseException; +import com.yomahub.liteflow.exception.*; import com.yomahub.liteflow.flow.FlowBus; import com.yomahub.liteflow.flow.element.Chain; import com.yomahub.liteflow.flow.element.condition.AbstractCondition; @@ -30,18 +25,7 @@ import java.util.Optional; import java.util.Set; import java.util.function.Consumer; -import static com.yomahub.liteflow.common.ChainConstant.CHAIN; -import static com.yomahub.liteflow.common.ChainConstant.EXTENDS; -import static com.yomahub.liteflow.common.ChainConstant.FILE; -import static com.yomahub.liteflow.common.ChainConstant.FLOW; -import static com.yomahub.liteflow.common.ChainConstant.ID; -import static com.yomahub.liteflow.common.ChainConstant.LANGUAGE; -import static com.yomahub.liteflow.common.ChainConstant.NAME; -import static com.yomahub.liteflow.common.ChainConstant.NODE; -import static com.yomahub.liteflow.common.ChainConstant.NODES; -import static com.yomahub.liteflow.common.ChainConstant.TYPE; -import static com.yomahub.liteflow.common.ChainConstant.VALUE; -import static com.yomahub.liteflow.common.ChainConstant._CLASS; +import static com.yomahub.liteflow.common.ChainConstant.*; /** * Parser 通用 Helper @@ -296,11 +280,27 @@ public class ParserHelper { public static void parseOneChainEl(JsonNode chainNode) { // 构建chainBuilder String chainId = Optional.ofNullable(chainNode.get(ID)).orElse(chainNode.get(NAME)).textValue(); - String el = chainNode.get(VALUE).textValue(); - LiteFlowChainELBuilder.createChain() - .setChainId(chainId) - .setEL(el) - .build(); + + JsonNode routeJsonNode = chainNode.get(ROUTE); + + LiteFlowChainELBuilder builder = LiteFlowChainELBuilder.createChain().setChainId(chainId); + + // 如果有route这个标签,说明是决策表chain + // 决策表链路必须有route和body这两个标签 + if (routeJsonNode != null){ + builder.setRoute(routeJsonNode.textValue()); + + JsonNode bodyJsonNode = chainNode.get(BODY); + if (bodyJsonNode == null){ + String errMsg = StrUtil.format("If you have defined the field route, then you must define the field body in chain[{}]", chainId); + throw new FlowSystemException(errMsg); + } + builder.setEL(bodyJsonNode.textValue()); + }else{ + builder.setEL(chainNode.get(VALUE).textValue()); + } + + builder.build(); } /** @@ -310,12 +310,27 @@ public class ParserHelper { public static void parseOneChainEl(Element e) { // 构建chainBuilder String chainId = Optional.ofNullable(e.attributeValue(ID)).orElse(e.attributeValue(NAME)); - String text = e.getText(); - String el = ElRegexUtil.removeComments(text); - LiteFlowChainELBuilder.createChain() - .setChainId(chainId) - .setEL(el) - .build(); + + Element routeElement = e.element(ROUTE); + + LiteFlowChainELBuilder builder = LiteFlowChainELBuilder.createChain().setChainId(chainId); + + // 如果有route这个标签,说明是决策表chain + // 决策表链路必须有route和body这两个标签 + if (routeElement != null){ + builder.setRoute(ElRegexUtil.removeComments(routeElement.getText())); + + Element bodyElement = e.element(BODY); + if (bodyElement == null){ + String errMsg = StrUtil.format("If you have defined the tag , then you must define the tag in chain[{}]", chainId); + throw new FlowSystemException(errMsg); + } + builder.setEL(ElRegexUtil.removeComments(bodyElement.getText())); + }else{ + builder.setEL(ElRegexUtil.removeComments(e.getText())); + } + + builder.build(); } /** diff --git a/liteflow-core/src/main/resources/dtd/liteflow.dtd b/liteflow-core/src/main/resources/dtd/liteflow.dtd index 7312b9230..1e12d37e7 100644 --- a/liteflow-core/src/main/resources/dtd/liteflow.dtd +++ b/liteflow-core/src/main/resources/dtd/liteflow.dtd @@ -3,7 +3,9 @@ - + + + Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.route.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/BCmp.java new file mode 100644 index 000000000..2f71f619d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.route.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/R1.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/R1.java new file mode 100644 index 000000000..e74b21ba7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/R1.java @@ -0,0 +1,12 @@ +package com.yomahub.liteflow.test.route.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeBooleanComponent; + +@LiteflowComponent("r1") +public class R1 extends NodeBooleanComponent { + @Override + public boolean processBoolean() throws Exception { + return true; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/R2.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/R2.java new file mode 100644 index 000000000..2faee1887 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/route/cmp/R2.java @@ -0,0 +1,12 @@ +package com.yomahub.liteflow.test.route.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeBooleanComponent; + +@LiteflowComponent("r2") +public class R2 extends NodeBooleanComponent { + @Override + public boolean processBoolean() throws Exception { + return false; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/route/application.properties b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/route/application.properties new file mode 100644 index 000000000..0a81040f7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/route/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=route/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/route/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/route/flow.el.xml new file mode 100644 index 000000000..f752f2f1f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/route/flow.el.xml @@ -0,0 +1,21 @@ + + + + + + r1 + + + THEN(a,b); + + + + + + OR(r1,r2) + + + THEN(a,b); + + + \ No newline at end of file