From 3e30e788181d1f7b41fd35dd228a151d1a9742f3 Mon Sep 17 00:00:00 2001 From: gaibu <1016771049@qq.com> Date: Tue, 10 Jan 2023 21:14:44 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat=20#I69VAR=20=E4=BC=98=E5=8C=96=20node?= =?UTF-8?q?=20chain=20=E4=B8=8D=E5=AD=98=E5=9C=A8=E6=97=B6=E5=80=99?= =?UTF-8?q?=E7=9A=84=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../builder/el/LiteFlowChainELBuilder.java | 81 ++++++++++++++++--- 1 file changed, 71 insertions(+), 10 deletions(-) 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 0b0f720a0..e1ce28689 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 @@ -1,18 +1,43 @@ package com.yomahub.liteflow.builder.el; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import com.ql.util.express.DefaultContext; import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; import com.ql.util.express.exception.QLException; -import com.yomahub.liteflow.builder.el.operator.*; +import com.ql.util.express.instruction.detail.Instruction; +import com.ql.util.express.instruction.detail.InstructionLoadAttr; +import com.yomahub.liteflow.builder.el.operator.AnyOperator; +import com.yomahub.liteflow.builder.el.operator.BreakOperator; +import com.yomahub.liteflow.builder.el.operator.DataOperator; +import com.yomahub.liteflow.builder.el.operator.DefaultOperator; +import com.yomahub.liteflow.builder.el.operator.DoOperator; +import com.yomahub.liteflow.builder.el.operator.ElifOperator; +import com.yomahub.liteflow.builder.el.operator.ElseOperator; +import com.yomahub.liteflow.builder.el.operator.FinallyOperator; +import com.yomahub.liteflow.builder.el.operator.ForOperator; +import com.yomahub.liteflow.builder.el.operator.IdOperator; +import com.yomahub.liteflow.builder.el.operator.IfOperator; +import com.yomahub.liteflow.builder.el.operator.IgnoreErrorOperator; +import com.yomahub.liteflow.builder.el.operator.NodeOperator; +import com.yomahub.liteflow.builder.el.operator.PreOperator; +import com.yomahub.liteflow.builder.el.operator.SwitchOperator; +import com.yomahub.liteflow.builder.el.operator.TagOperator; +import com.yomahub.liteflow.builder.el.operator.ThenOperator; +import com.yomahub.liteflow.builder.el.operator.ThreadPoolOperator; +import com.yomahub.liteflow.builder.el.operator.ToOperator; +import com.yomahub.liteflow.builder.el.operator.WhenOperator; +import com.yomahub.liteflow.builder.el.operator.WhileOperator; import com.yomahub.liteflow.common.ChainConstant; import com.yomahub.liteflow.exception.DataNofFoundException; import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.exception.FlowSystemException; 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.Node; +import com.yomahub.liteflow.flow.element.condition.Condition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -152,7 +177,9 @@ public class LiteFlowChainELBuilder { } catch (QLException e) { // EL 底层会包装异常,这里是曲线处理 if (Objects.equals(e.getCause().getMessage(), DataNofFoundException.MSG)) { - throw new ELParseException(String.format("[node/chain is not exist or node/chain not register]elStr=%s", elStr)); + // 构建错误信息 + String msg = buildDataNofFoundExceptionMsg(elStr); + throw new ELParseException(msg); } throw new ELParseException(e.getCause().getMessage()); } catch (Exception e) { @@ -160,19 +187,53 @@ public class LiteFlowChainELBuilder { } } + /** + * 解析 EL 表达式,查找未定义的 id 并构建错误信息 + * + * @param elStr el 表达式 + */ + private static String buildDataNofFoundExceptionMsg(String elStr) { + String msg = String.format("[node/chain is not exist or node/chain not register]\n elStr=%s", StrUtil.trim(elStr)); + try { + InstructionSet parseResult = EXPRESS_RUNNER.getInstructionSetFromLocalCache(elStr); + if (parseResult == null) { + return msg; + } + + Object o = ReflectUtil.getFieldValue(parseResult, "instructionList"); + if (o == null){ + return msg; + } + Instruction[] instructionList = (Instruction[]) o; + List chainIds = CollUtil.map(FlowBus.getChainMap().values(), Chain::getChainId, true); + List nodeIds = CollUtil.map(FlowBus.getNodeMap().values(), Node::getId, true); + for (Instruction instruction : instructionList) { + String attrName = ((InstructionLoadAttr) instruction).getAttrName(); + if (!chainIds.contains(attrName) && !nodeIds.contains(attrName)) { + msg = String.format("[node/chain is not exist or node/chain not register]\n id=%s \n elStr=%s", attrName, StrUtil.trim(elStr)); + break; + } + } + } catch (Exception ex) { + // ignore + } + return msg; + } + /** * EL表达式校验 + * * @param elStr EL表达式 * @return true 校验成功 false 校验失败 */ public static boolean validate(String elStr) { - try { - LiteFlowChainELBuilder.createChain().setEL(elStr); - return Boolean.TRUE; - } catch (ELParseException e) { - LOG.error(e.getMessage()); - } - return Boolean.FALSE; + try { + LiteFlowChainELBuilder.createChain().setEL(elStr); + return Boolean.TRUE; + } catch (ELParseException e) { + LOG.error(e.getMessage()); + } + return Boolean.FALSE; } public void build() { From b7bbaf549331f7ccdc84f8a16526384af55be5d4 Mon Sep 17 00:00:00 2001 From: gaibu <1016771049@qq.com> Date: Tue, 10 Jan 2023 21:21:41 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat=20#I69VAR=20=E4=BC=98=E5=8C=96=20node?= =?UTF-8?q?=20chain=20=E4=B8=8D=E5=AD=98=E5=9C=A8=E6=97=B6=E5=80=99?= =?UTF-8?q?=E7=9A=84=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../builder/el/LiteFlowChainELBuilder.java | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) 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 e1ce28689..d34fcd57b 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 @@ -187,39 +187,6 @@ public class LiteFlowChainELBuilder { } } - /** - * 解析 EL 表达式,查找未定义的 id 并构建错误信息 - * - * @param elStr el 表达式 - */ - private static String buildDataNofFoundExceptionMsg(String elStr) { - String msg = String.format("[node/chain is not exist or node/chain not register]\n elStr=%s", StrUtil.trim(elStr)); - try { - InstructionSet parseResult = EXPRESS_RUNNER.getInstructionSetFromLocalCache(elStr); - if (parseResult == null) { - return msg; - } - - Object o = ReflectUtil.getFieldValue(parseResult, "instructionList"); - if (o == null){ - return msg; - } - Instruction[] instructionList = (Instruction[]) o; - List chainIds = CollUtil.map(FlowBus.getChainMap().values(), Chain::getChainId, true); - List nodeIds = CollUtil.map(FlowBus.getNodeMap().values(), Node::getId, true); - for (Instruction instruction : instructionList) { - String attrName = ((InstructionLoadAttr) instruction).getAttrName(); - if (!chainIds.contains(attrName) && !nodeIds.contains(attrName)) { - msg = String.format("[node/chain is not exist or node/chain not register]\n id=%s \n elStr=%s", attrName, StrUtil.trim(elStr)); - break; - } - } - } catch (Exception ex) { - // ignore - } - return msg; - } - /** * EL表达式校验 * @@ -244,6 +211,8 @@ public class LiteFlowChainELBuilder { FlowBus.addChain(this.chain); } + //#region private method + /** * build 前简单校验 */ @@ -256,4 +225,38 @@ public class LiteFlowChainELBuilder { throw new RuntimeException(CollUtil.join(errorList, ",", "[", "]")); } } + + /** + * 解析 EL 表达式,查找未定义的 id 并构建错误信息 + * + * @param elStr el 表达式 + */ + private String buildDataNofFoundExceptionMsg(String elStr) { + String msg = String.format("[node/chain is not exist or node/chain not register]\n elStr=%s", StrUtil.trim(elStr)); + try { + InstructionSet parseResult = EXPRESS_RUNNER.getInstructionSetFromLocalCache(elStr); + if (parseResult == null) { + return msg; + } + + Object o = ReflectUtil.getFieldValue(parseResult, "instructionList"); + if (o == null) { + return msg; + } + Instruction[] instructionList = (Instruction[]) o; + List chainIds = CollUtil.map(FlowBus.getChainMap().values(), Chain::getChainId, true); + List nodeIds = CollUtil.map(FlowBus.getNodeMap().values(), Node::getId, true); + for (Instruction instruction : instructionList) { + String attrName = ((InstructionLoadAttr) instruction).getAttrName(); + if (!chainIds.contains(attrName) && !nodeIds.contains(attrName)) { + msg = String.format("[node/chain is not exist or node/chain not register]\n id=%s \n elStr=%s", attrName, StrUtil.trim(elStr)); + break; + } + } + } catch (Exception ex) { + // ignore + } + return msg; + } + //#endregion } From 0f46146e119eafc99f2165fe016dae4f73ddd3cd Mon Sep 17 00:00:00 2001 From: gaibu <1016771049@qq.com> Date: Tue, 10 Jan 2023 21:27:28 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat=20#I69VAR=20=E4=BC=98=E5=8C=96=20node?= =?UTF-8?q?=20chain=20=E4=B8=8D=E5=AD=98=E5=9C=A8=E6=97=B6=E5=80=99?= =?UTF-8?q?=E7=9A=84=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../liteflow/builder/el/LiteFlowChainELBuilder.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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 d34fcd57b..e6ddbd2f2 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 @@ -247,10 +247,12 @@ public class LiteFlowChainELBuilder { List chainIds = CollUtil.map(FlowBus.getChainMap().values(), Chain::getChainId, true); List nodeIds = CollUtil.map(FlowBus.getNodeMap().values(), Node::getId, true); for (Instruction instruction : instructionList) { - String attrName = ((InstructionLoadAttr) instruction).getAttrName(); - if (!chainIds.contains(attrName) && !nodeIds.contains(attrName)) { - msg = String.format("[node/chain is not exist or node/chain not register]\n id=%s \n elStr=%s", attrName, StrUtil.trim(elStr)); - break; + if (instruction instanceof InstructionLoadAttr) { + String attrName = ((InstructionLoadAttr) instruction).getAttrName(); + if (!chainIds.contains(attrName) && !nodeIds.contains(attrName)) { + msg = String.format("[node/chain is not exist or node/chain not register]\n id=%s \n elStr=%s", attrName, StrUtil.trim(elStr)); + break; + } } } } catch (Exception ex) { From 56761c44c8390915bd7acf0b52140e45c69e2ebe Mon Sep 17 00:00:00 2001 From: gaibu <1016771049@qq.com> Date: Fri, 13 Jan 2023 11:29:11 +0800 Subject: [PATCH 4/5] =?UTF-8?q?fix=20#I69VAR=20=E4=BF=AE=E6=94=B9=E5=8D=95?= =?UTF-8?q?=E8=AF=8D=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../liteflow/builder/el/LiteFlowChainELBuilder.java | 8 ++++---- .../liteflow/builder/el/operator/base/OperatorHelper.java | 4 ++-- ...aNofFoundException.java => DataNotFoundException.java} | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) rename liteflow-core/src/main/java/com/yomahub/liteflow/exception/{DataNofFoundException.java => DataNotFoundException.java} (67%) 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 e6ddbd2f2..0ef5f6af8 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 @@ -31,7 +31,7 @@ import com.yomahub.liteflow.builder.el.operator.ToOperator; import com.yomahub.liteflow.builder.el.operator.WhenOperator; import com.yomahub.liteflow.builder.el.operator.WhileOperator; import com.yomahub.liteflow.common.ChainConstant; -import com.yomahub.liteflow.exception.DataNofFoundException; +import com.yomahub.liteflow.exception.DataNotFoundException; import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.exception.FlowSystemException; import com.yomahub.liteflow.flow.FlowBus; @@ -176,9 +176,9 @@ public class LiteFlowChainELBuilder { return this; } catch (QLException e) { // EL 底层会包装异常,这里是曲线处理 - if (Objects.equals(e.getCause().getMessage(), DataNofFoundException.MSG)) { + if (Objects.equals(e.getCause().getMessage(), DataNotFoundException.MSG)) { // 构建错误信息 - String msg = buildDataNofFoundExceptionMsg(elStr); + String msg = buildDataNotFoundExceptionMsg(elStr); throw new ELParseException(msg); } throw new ELParseException(e.getCause().getMessage()); @@ -231,7 +231,7 @@ public class LiteFlowChainELBuilder { * * @param elStr el 表达式 */ - private String buildDataNofFoundExceptionMsg(String elStr) { + private String buildDataNotFoundExceptionMsg(String elStr) { String msg = String.format("[node/chain is not exist or node/chain not register]\n elStr=%s", StrUtil.trim(elStr)); try { InstructionSet parseResult = EXPRESS_RUNNER.getInstructionSetFromLocalCache(elStr); 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 401254036..88f60764b 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 @@ -2,7 +2,7 @@ package com.yomahub.liteflow.builder.el.operator.base; import cn.hutool.core.util.StrUtil; import com.ql.util.express.exception.QLException; -import com.yomahub.liteflow.exception.DataNofFoundException; +import com.yomahub.liteflow.exception.DataNotFoundException; import com.yomahub.liteflow.flow.element.Node; import java.util.Objects; @@ -156,7 +156,7 @@ public class OperatorHelper { public static void checkNodeAndChainExist(Object[] objects) throws QLException { for (Object object : objects) { if (Objects.isNull(object)) { - throw new QLException(DataNofFoundException.MSG); + throw new QLException(DataNotFoundException.MSG); } } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNofFoundException.java b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNotFoundException.java similarity index 67% rename from liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNofFoundException.java rename to liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNotFoundException.java index c31111517..cb2f65ad6 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNofFoundException.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/exception/DataNotFoundException.java @@ -4,8 +4,8 @@ package com.yomahub.liteflow.exception; * 未找到数据异常 * @author tangkc */ -public class DataNofFoundException extends RuntimeException { - public static final String MSG = "DataNofFoundException"; +public class DataNotFoundException extends RuntimeException { + public static final String MSG = "DataNotFoundException"; private static final long serialVersionUID = 1L; @@ -14,11 +14,11 @@ public class DataNofFoundException extends RuntimeException { */ private String message; - public DataNofFoundException() { + public DataNotFoundException() { this.message = MSG; } - public DataNofFoundException(String message) { + public DataNotFoundException(String message) { this.message = message; } From 062302af1a4267696c3d1f155568d5c70f75aea5 Mon Sep 17 00:00:00 2001 From: gaibu <1016771049@qq.com> Date: Fri, 13 Jan 2023 14:01:51 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat=20#I69VAR=20=E4=BC=98=E5=8C=96=20node?= =?UTF-8?q?=20chain=20=E4=B8=8D=E5=AD=98=E5=9C=A8=E6=97=B6=E5=80=99?= =?UTF-8?q?=E7=9A=84=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../builder/el/LiteFlowChainELBuilder.java | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) 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 0ef5f6af8..723d36b07 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 @@ -1,14 +1,13 @@ package com.yomahub.liteflow.builder.el; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.StrUtil; import com.ql.util.express.DefaultContext; import com.ql.util.express.ExpressRunner; import com.ql.util.express.InstructionSet; import com.ql.util.express.exception.QLException; -import com.ql.util.express.instruction.detail.Instruction; -import com.ql.util.express.instruction.detail.InstructionLoadAttr; import com.yomahub.liteflow.builder.el.operator.AnyOperator; import com.yomahub.liteflow.builder.el.operator.BreakOperator; import com.yomahub.liteflow.builder.el.operator.DataOperator; @@ -232,27 +231,45 @@ public class LiteFlowChainELBuilder { * @param elStr el 表达式 */ private String buildDataNotFoundExceptionMsg(String elStr) { - String msg = String.format("[node/chain is not exist or node/chain not register]\n elStr=%s", StrUtil.trim(elStr)); + String msg = String.format("[node/chain is not exist or node/chain not register]\n EL: %s", StrUtil.trim(elStr)); try { InstructionSet parseResult = EXPRESS_RUNNER.getInstructionSetFromLocalCache(elStr); if (parseResult == null) { return msg; } - Object o = ReflectUtil.getFieldValue(parseResult, "instructionList"); - if (o == null) { + String[] outAttrNames = parseResult.getOutAttrNames(); + if (ArrayUtil.isEmpty(outAttrNames)) { return msg; } - Instruction[] instructionList = (Instruction[]) o; + List chainIds = CollUtil.map(FlowBus.getChainMap().values(), Chain::getChainId, true); List nodeIds = CollUtil.map(FlowBus.getNodeMap().values(), Node::getId, true); - for (Instruction instruction : instructionList) { - if (instruction instanceof InstructionLoadAttr) { - String attrName = ((InstructionLoadAttr) instruction).getAttrName(); - if (!chainIds.contains(attrName) && !nodeIds.contains(attrName)) { - msg = String.format("[node/chain is not exist or node/chain not register]\n id=%s \n elStr=%s", attrName, StrUtil.trim(elStr)); - break; + for (String attrName : outAttrNames) { + if (!chainIds.contains(attrName) && !nodeIds.contains(attrName)) { + msg = String.format("[%s] is not exist or [%s] is not registered, you need to define a node or chain with id [%s] and register it \n EL: ", attrName, attrName, attrName); + + // 去除 EL 表达式中的空格和换行符 + String sourceEl = StrUtil.removeAll(elStr, CharUtil.SPACE, CharUtil.LF, CharUtil.CR); + // 这里需要注意的是,nodeId 和 chainId 可能是关键字的一部分,如果直接 indexOf(attrName) 会出现误判 + // 所以需要判断 attrName 前后是否有 "," + int commaRightIndex = sourceEl.indexOf(attrName + StrUtil.COMMA); + if (commaRightIndex != -1) { + // 需要加上 "EL: " 的长度 4,再加上 "^" 的长度 1,indexOf 从 0 开始,所以还需要加 1 + msg = msg + sourceEl + "\n" + StrUtil.fill("^", CharUtil.SPACE, commaRightIndex + 6, true); } + int commaLeftIndex = sourceEl.indexOf(StrUtil.COMMA + attrName); + if (commaLeftIndex != -1) { + // 需要加上 "EL: " 的长度 4,再加上 "^" 的长度 1,再加上 "," 的长度 1,indexOf 从 0 开始,所以还需要加 1 + msg = msg + sourceEl + "\n" + StrUtil.fill("^", CharUtil.SPACE, commaLeftIndex + 7, true); + } + // 还有一种特殊情况,就是 EL 表达式中的节点使用 node("a") + int nodeIndex = sourceEl.indexOf(String.format("node(\"%s\")", attrName)); + if (nodeIndex != -1) { + // 需要加上 "EL: " 的长度 4,再加上 “node("” 长度 6,再加上 "^" 的长度 1,indexOf 从 0 开始,所以还需要加 1 + msg = msg + sourceEl + "\n" + StrUtil.fill("^", CharUtil.SPACE, commaLeftIndex + 12, true); + } + break; } } } catch (Exception ex) {