From 195bf5c1a542cda8f4d0dcf75732a169cf43499e Mon Sep 17 00:00:00 2001 From: "everywhere.z" Date: Thu, 27 Nov 2025 01:42:43 +0800 Subject: [PATCH] =?UTF-8?q?enhancement=20#ID8XF9=20=E5=AF=B9QLExpress4?= =?UTF-8?q?=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- liteflow-core/pom.xml | 2 +- .../builder/el/LiteFlowChainELBuilder.java | 63 +++++++++----- .../builder/el/operator/DoOperator.java | 4 +- .../builder/el/operator/FinallyOperator.java | 2 +- .../builder/el/operator/ForOperator.java | 4 +- .../el/operator/IgnoreErrorOperator.java | 2 +- .../builder/el/operator/IteratorOperator.java | 2 +- .../el/operator/MaxWaitTimeOperator.java | 4 +- .../el/operator/PercentageOperator.java | 4 +- .../builder/el/operator/SwitchOperator.java | 2 +- .../builder/el/operator/TagOperator.java | 2 +- .../el/operator/ThreadPoolOperator.java | 4 +- .../el/operator/base/BaseOperator.java | 14 ++-- .../el/operator/base/OperatorHelper.java | 84 +++++++++---------- .../core/proxy/DeclComponentProxy.java | 6 +- .../BaseNodeInstanceIdManageSpi.java | 10 +-- .../DefaultNodeInstanceIdManageSpiImpl.java | 6 +- .../util/LiteflowContextRegexMatcher.java | 36 ++++---- .../yomahub/liteflow/util/QlExpressUtils.java | 81 +++++++++--------- .../parser/sql/read/impl/InstanceIdRead.java | 3 +- .../liteflow-script-qlexpress/pom.xml | 2 +- .../qlexpress/QLExpressScriptExecutor.java | 38 +++++---- .../src/test/resources/base/flow.el.xml | 48 +---------- pom.xml | 4 +- 25 files changed, 202 insertions(+), 228 deletions(-) diff --git a/.gitignore b/.gitignore index 1f56396cc..aacc4f0ae 100644 --- a/.gitignore +++ b/.gitignore @@ -80,4 +80,5 @@ atlassian-ide-plugin.xml /logs */logs -.flattened-pom.xml \ No newline at end of file +.flattened-pom.xml +/.vscode/settings.json diff --git a/liteflow-core/pom.xml b/liteflow-core/pom.xml index d650fa682..63fc7d6ba 100644 --- a/liteflow-core/pom.xml +++ b/liteflow-core/pom.xml @@ -54,7 +54,7 @@ com.alibaba - QLExpress + qlexpress4 commons-beanutils 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 426315c8b..16b4ae264 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 @@ -8,10 +8,13 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.digest.MD5; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; -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.alibaba.qlexpress4.Express4Runner; +import com.alibaba.qlexpress4.QLOptions; +import com.alibaba.qlexpress4.QLResult; +import com.alibaba.qlexpress4.exception.QLException; + +import java.util.HashMap; +import java.util.Map; import com.yomahub.liteflow.builder.el.operator.*; import com.yomahub.liteflow.common.ChainConstant; import com.yomahub.liteflow.common.entity.ValidationResp; @@ -70,7 +73,7 @@ public class LiteFlowChainELBuilder { /** * EL解析引擎 */ - private final static ExpressRunner EXPRESS_RUNNER = QlExpressUtils.getInstance(); + private final static Express4Runner EXPRESS_RUNNER = QlExpressUtils.getInstance(); public static LiteFlowChainELBuilder createChain() { return new LiteFlowChainELBuilder(); @@ -131,15 +134,17 @@ public class LiteFlowChainELBuilder { String msg = buildDataNotFoundExceptionMsg(routeEl); throw new ELParseException(msg); }else if (ObjectUtil.isNotNull(e.getCause())){ - throw new ELParseException(e.getCause().getMessage()); + String causeMsg = e.getCause().getMessage(); + throw new ELParseException(StrUtil.isNotBlank(causeMsg) ? causeMsg : e.getMessage()); }else{ - throw new ELParseException(e.getMessage()); + throw new ELParseException(StrUtil.isNotBlank(e.getMessage()) ? e.getMessage() : "Unknown EL parse error"); } }catch (RouteELInvalidException e){ throw e; }catch (Exception e) { String errMsg = StrUtil.format("parse el fail in this chain[{}];\r\n", chain.getChainId()); - throw new ELParseException(errMsg + e.getMessage()); + String exMsg = e.getMessage(); + throw new ELParseException(errMsg + (StrUtil.isNotBlank(exMsg) ? exMsg : e.getClass().getSimpleName())); } } @@ -166,7 +171,7 @@ public class LiteFlowChainELBuilder { Condition condition = compile(elStr, errorList, true); if (Objects.isNull(condition)){ - throw new QLException(StrUtil.format("parse el fail,el:[{}]", elStr)); + throw new ELParseException(StrUtil.format("parse el fail,el:[{}]", elStr)); } if (liteflowConfig.getEnableNodeInstanceId()) { @@ -183,13 +188,15 @@ public class LiteFlowChainELBuilder { String msg = buildDataNotFoundExceptionMsg(elStr); throw new ELParseException(msg); }else if (ObjectUtil.isNotNull(e.getCause())){ - throw new ELParseException(e.getCause().getMessage()); + String causeMsg = e.getCause().getMessage(); + throw new ELParseException(StrUtil.isNotBlank(causeMsg) ? causeMsg : e.getMessage()); }else{ - throw new ELParseException(e.getMessage()); + throw new ELParseException(StrUtil.isNotBlank(e.getMessage()) ? e.getMessage() : "Unknown EL parse error"); } } catch (Exception e) { String errMsg = StrUtil.format("parse el fail in this chain[{}];\r\n", chain.getChainId()); - throw new ELParseException(errMsg + e.getMessage()); + String exMsg = e.getMessage(); + throw new ELParseException(errMsg + (StrUtil.isNotBlank(exMsg) ? exMsg : e.getClass().getSimpleName())); } } @@ -283,6 +290,12 @@ public class LiteFlowChainELBuilder { String msg = String.format("[node/chain is not exist or node/chain not register]\n EL: %s", StrUtil.trim(elStr)); try { + // QLExpress4 暂时不支持 getInstructionSetFromLocalCache 方法 + // 这里简化处理,直接返回基本错误信息 + // TODO: 等待 QLExpress4 提供相应的 API 后再完善此功能 + return msg; + + /* 旧版本的代码,等待 QLExpress4 支持后再启用 InstructionSet parseResult = EXPRESS_RUNNER.getInstructionSetFromLocalCache(elStr); if (parseResult == null) { return msg; @@ -325,6 +338,7 @@ public class LiteFlowChainELBuilder { } } } + */ } catch (Exception ex) { // ignore } @@ -342,9 +356,8 @@ public class LiteFlowChainELBuilder { return; } - List errorList = new ArrayList<>(); try { - DefaultContext context = new DefaultContext<>(); + Map context = new HashMap<>(); // 这里一定要先放chain,再放node,因为node优先于chain,所以当重名时,node会覆盖掉chain // 往上下文里放入所有的chain,是的el表达式可以直接引用到chain @@ -361,6 +374,9 @@ public class LiteFlowChainELBuilder { // 那么会有一种级联的情况:这个EL中含有其他的chain,如果这时候不先解析其他chain,就到导致诸如循环场景无法设置index或者obj的情况 // 所以这里要判断表达式里有没有其他的chain,如果有,进行先行解析 + // TODO: QLExpress4 暂时没有 getOutVarNames 方法,这里先注释掉级联解析逻辑 + // 等待 QLExpress4 提供相应的 API 后再恢复 + /* String[] itemArray = EXPRESS_RUNNER.getOutVarNames(chain.getEl()); Arrays.stream(itemArray).forEach(item -> { if (FlowBus.containChain(item) && !chain.getChainId().equals(item)) { @@ -370,14 +386,16 @@ public class LiteFlowChainELBuilder { } } }); + */ // 解析el成为一个Condition // 为什么这里只是一个Condition,而不是一个List呢 // 这里无论多复杂的,外面必定有一个最外层的Condition,所以这里只有一个,内部可以嵌套很多层,这点和以前的不太一样 - Condition condition = (Condition) EXPRESS_RUNNER.execute(chain.getEl(), context, errorList, true, true); + QLResult expressResult = EXPRESS_RUNNER.execute(chain.getEl(), context, QLOptions.DEFAULT_OPTIONS); + Condition condition = (Condition) expressResult.getResult(); if (Objects.isNull(condition)){ - throw new QLException(StrUtil.format("parse el fail,el:[{}]", chain.getEl())); + throw new ELParseException(StrUtil.format("parse el fail,el:[{}]", chain.getEl())); } // 设置实例id @@ -400,19 +418,21 @@ public class LiteFlowChainELBuilder { String msg = buildDataNotFoundExceptionMsg(chain.getEl()); throw new ELParseException(msg); }else if (ObjectUtil.isNotNull(e.getCause())){ - throw new ELParseException(e.getCause().getMessage()); + String causeMsg = e.getCause().getMessage(); + throw new ELParseException(StrUtil.isNotBlank(causeMsg) ? causeMsg : e.getMessage()); }else{ - throw new ELParseException(e.getMessage()); + throw new ELParseException(StrUtil.isNotBlank(e.getMessage()) ? e.getMessage() : "Unknown EL parse error"); } } catch (Exception e) { String errMsg = StrUtil.format("parse el fail in this chain[{}];\r\n", chain.getChainId()); - throw new ELParseException(errMsg + e.getMessage()); + String exMsg = e.getMessage(); + throw new ELParseException(errMsg + (StrUtil.isNotBlank(exMsg) ? exMsg : e.getClass().getSimpleName())); } } @SuppressWarnings("unchecked") private T compile(String elStr, List errorList, boolean putChain2Context) throws Exception{ - DefaultContext context = new DefaultContext<>(); + Map context = new HashMap<>(); if (putChain2Context){ // 这里一定要先放chain,再放node,因为node优先于chain,所以当重名时,node会覆盖掉chain @@ -432,7 +452,8 @@ public class LiteFlowChainELBuilder { // 为什么这里只是一个Condition,而不是一个List呢 // 这里无论多复杂的,外面必定有一个最外层的Condition,所以这里只有一个,内部可以嵌套很多层,这点和以前的不太一样 - return (T) EXPRESS_RUNNER.execute(elStr, context, errorList, true, true); + QLResult expressResult = EXPRESS_RUNNER.execute(elStr, context, QLOptions.DEFAULT_OPTIONS); + return (T) expressResult.getResult(); } } 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 index c6b3a5f4a..98e840c5d 100644 --- 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 @@ -1,6 +1,6 @@ package com.yomahub.liteflow.builder.el.operator; -import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.exception.ELParseException; 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; @@ -41,7 +41,7 @@ public class DoOperator extends BaseOperator { } else { String errorMsg = "The caller must be LoopCondition or CatchCondition item"; - throw new QLException(errorMsg); + throw new ELParseException(errorMsg); } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/FinallyOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/FinallyOperator.java index b759b6cac..fc5f3cc0a 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/FinallyOperator.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/FinallyOperator.java @@ -1,6 +1,6 @@ package com.yomahub.liteflow.builder.el.operator; -import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.exception.ELParseException; 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; 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 index a5abc57f0..393986a9b 100644 --- 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 @@ -3,7 +3,7 @@ package com.yomahub.liteflow.builder.el.operator; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; -import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; import com.yomahub.liteflow.core.NodeComponent; @@ -46,7 +46,7 @@ public class ForOperator extends BaseOperator { node.setId(nodeForComponent.getNodeId()); } else { - throw new QLException("The parameter must be Node item"); + throw new ELParseException("The parameter must be Node item"); } ForCondition forCondition = new ForCondition(); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IgnoreErrorOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IgnoreErrorOperator.java index b140dce46..dfb36fa4e 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IgnoreErrorOperator.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IgnoreErrorOperator.java @@ -1,6 +1,6 @@ package com.yomahub.liteflow.builder.el.operator; -import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; import com.yomahub.liteflow.flow.element.condition.WhenCondition; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IteratorOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IteratorOperator.java index 0d29a7f07..f35ecb5a8 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IteratorOperator.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/IteratorOperator.java @@ -1,7 +1,7 @@ package com.yomahub.liteflow.builder.el.operator; import cn.hutool.core.collection.ListUtil; -import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; import com.yomahub.liteflow.enums.NodeTypeEnum; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/MaxWaitTimeOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/MaxWaitTimeOperator.java index 6ca3fd3ec..37d586f3a 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/MaxWaitTimeOperator.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/MaxWaitTimeOperator.java @@ -2,7 +2,7 @@ package com.yomahub.liteflow.builder.el.operator; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.text.StrFormatter; -import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; import com.yomahub.liteflow.flow.element.Condition; @@ -42,7 +42,7 @@ public abstract class MaxWaitTimeOperator extends BaseOperator { } else if (executable instanceof FinallyCondition) { // FINALLY,报错 String errorMsg = StrFormatter.format("The caller [{}] cannot use the keyword \"{}'\"", executable.toString(), operatorName()); - throw new QLException(errorMsg); + throw new ELParseException(errorMsg); } else if (containsFinally(executable)) { // 处理 THEN 中的 FINALLY ThenCondition thenCondition = OperatorHelper.convert(executable, ThenCondition.class); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/PercentageOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/PercentageOperator.java index 0bb172f3a..100d127bc 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/PercentageOperator.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/PercentageOperator.java @@ -1,6 +1,6 @@ package com.yomahub.liteflow.builder.el.operator; -import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; import com.yomahub.liteflow.enums.ParallelStrategyEnum; @@ -24,7 +24,7 @@ public class PercentageOperator extends BaseOperator { Double percentage = OperatorHelper.convert2Double(objects[1]); if (percentage > 1 || percentage < 0) { - throw new QLException("The percentage must be between 0 and 1."); + throw new ELParseException("The percentage must be between 0 and 1."); } whenCondition.setParallelStrategy(ParallelStrategyEnum.PERCENTAGE); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/SwitchOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/SwitchOperator.java index c1d0ad3d9..693368663 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/SwitchOperator.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/SwitchOperator.java @@ -1,7 +1,7 @@ package com.yomahub.liteflow.builder.el.operator; import cn.hutool.core.collection.ListUtil; -import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; import com.yomahub.liteflow.enums.NodeTypeEnum; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/TagOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/TagOperator.java index 2d61e59b3..451328e89 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/TagOperator.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/TagOperator.java @@ -1,7 +1,7 @@ package com.yomahub.liteflow.builder.el.operator; import cn.hutool.core.collection.ListUtil; -import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; import com.yomahub.liteflow.flow.FlowBus; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ThreadPoolOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ThreadPoolOperator.java index 69f444fcb..963e1233f 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ThreadPoolOperator.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ThreadPoolOperator.java @@ -1,6 +1,6 @@ package com.yomahub.liteflow.builder.el.operator; -import com.ql.util.express.exception.QLException; +import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.builder.el.operator.base.BaseOperator; import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper; import com.yomahub.liteflow.flow.element.Condition; @@ -37,7 +37,7 @@ public class ThreadPoolOperator extends BaseOperator { return condition; } else { String errorMsg = "The caller must be WhenCondition or LoopCondition item"; - throw new QLException(errorMsg); + throw new ELParseException(errorMsg); } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/BaseOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/BaseOperator.java index b0a02eea9..f61db65dc 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/BaseOperator.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/base/BaseOperator.java @@ -1,23 +1,23 @@ package com.yomahub.liteflow.builder.el.operator.base; -import com.ql.util.express.Operator; -import com.ql.util.express.exception.QLException; +import com.alibaba.qlexpress4.api.QLFunctionalVarargs; +import com.alibaba.qlexpress4.exception.QLException; import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.flow.element.Executable; /** - * BaseOperator 为了强化 executeInner 方法,会捕获抛出的 QLException 错误,输出友好的错误提示 + * BaseOperator 为了强化 call 方法,会捕获抛出的 QLException 错误,输出友好的错误提示 * * @author gaibu * @since 2.8.6 */ -public abstract class BaseOperator extends Operator { +public abstract class BaseOperator implements QLFunctionalVarargs { @Override - public T executeInner(Object[] objects) throws Exception { + public T call(Object... parameters) { try { - OperatorHelper.checkItemNotNull(objects); - return build(objects); + OperatorHelper.checkItemNotNull(parameters); + return build(parameters); } catch (QLException e) { throw e; 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 31107a9d9..d1d9bf41f 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,11 +2,11 @@ package com.yomahub.liteflow.builder.el.operator.base; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.StrUtil; -import com.ql.util.express.exception.QLException; import com.yomahub.liteflow.enums.ConditionTypeEnum; import com.yomahub.liteflow.enums.ExecuteableTypeEnum; import com.yomahub.liteflow.enums.NodeTypeEnum; import com.yomahub.liteflow.exception.DataNotFoundException; +import com.yomahub.liteflow.exception.ELParseException; import com.yomahub.liteflow.flow.element.Condition; import com.yomahub.liteflow.flow.element.Executable; import com.yomahub.liteflow.flow.element.Node; @@ -25,50 +25,50 @@ public class OperatorHelper { /** * 检查参数数量,大于 0 * @param objects objects - * @throws QLException QLException + * @throws ELParseException ELParseException */ - public static void checkObjectSizeGtZero(Object[] objects) throws QLException { + public static void checkObjectSizeGtZero(Object[] objects) throws ELParseException { if (objects.length == 0) { - throw new QLException("parameter is empty"); + throw new ELParseException("parameter is empty"); } } /** * 检查参数数量,大于等于 2 * @param objects objects - * @throws QLException QLException + * @throws ELParseException ELParseException */ - public static void checkObjectSizeGteTwo(Object[] objects) throws QLException { + public static void checkObjectSizeGteTwo(Object[] objects) throws ELParseException { checkObjectSizeGtZero(objects); if (objects.length < 2) { - throw new QLException("parameter size error"); + throw new ELParseException("parameter size error"); } } /** * 检查参数数量,等于 1 * @param objects objects - * @throws QLException QLException + * @throws ELParseException ELParseException */ - public static void checkObjectSizeEqOne(Object[] objects) throws QLException { + public static void checkObjectSizeEqOne(Object[] objects) throws ELParseException { checkObjectSizeEq(objects, 1); } /** * 检查参数数量,等于 2 * @param objects objects - * @throws QLException QLException + * @throws ELParseException ELParseException */ - public static void checkObjectSizeEqTwo(Object[] objects) throws QLException { + public static void checkObjectSizeEqTwo(Object[] objects) throws ELParseException { checkObjectSizeEq(objects, 2); } /** * 检查参数数量,等于 3 * @param objects objects - * @throws QLException QLException + * @throws ELParseException ELParseException */ - public static void checkObjectSizeEqThree(Object[] objects) throws QLException { + public static void checkObjectSizeEqThree(Object[] objects) throws ELParseException { checkObjectSizeEq(objects, 3); } @@ -76,13 +76,13 @@ public class OperatorHelper { * 检查参数数量,等于 size * @param objects objects * @param size 参数数量 - * @throws QLException QLException + * @throws ELParseException ELParseException */ - public static void checkObjectSizeEq(Object[] objects, int size) throws QLException { + public static void checkObjectSizeEq(Object[] objects, int size) throws ELParseException { checkObjectSizeGtZero(objects); if (objects.length != size) { - throw new QLException("parameter size error"); + throw new ELParseException("parameter size error"); } } @@ -91,13 +91,13 @@ public class OperatorHelper { * @param objects objects * @param size1 参数数量1 * @param size2 参数数量2 - * @throws QLException QLException + * @throws ELParseException ELParseException */ - public static void checkObjectSizeEq(Object[] objects, int size1, int size2) throws QLException { + public static void checkObjectSizeEq(Object[] objects, int size1, int size2) throws ELParseException { checkObjectSizeGtZero(objects); if (objects.length != size1 && objects.length != size2) { - throw new QLException("parameter size error"); + throw new ELParseException("parameter size error"); } } @@ -105,12 +105,12 @@ public class OperatorHelper { * 转换 object 为指定的类型 如果是Node类型的则进行copy * 为什么要进行copy呢?因为原先的Node都是存放在FlowBus的NodeMap中的。有些属性在EL中不是全局的,属于当前这个chain的。 所以要进行copy动作 */ - public static T convert(Object object, Class clazz) throws QLException { + public static T convert(Object object, Class clazz) throws ELParseException { String errorMsg = StrUtil.format("The parameter must be {} item", clazz.getSimpleName()); return convert(object, clazz, errorMsg); } - public static Double convert2Double(Object object) throws QLException { + public static Double convert2Double(Object object) throws ELParseException { if (object instanceof Number) { // 对 float 特别处理,避免精度问题 if (object instanceof Float) { @@ -119,14 +119,14 @@ public class OperatorHelper { } return ((Number) object).doubleValue(); } - throw new QLException(StrUtil.format("Unsupported type: {}, it must be numeric type.", object.getClass().getName())); + throw new ELParseException(StrUtil.format("Unsupported type: {}, it must be numeric type.", object.getClass().getName())); } /** * 转换 object 为指定的类型,自定义错误信息 如果是Node类型的则进行copy */ @SuppressWarnings("unchecked") - public static T convert(Object object, Class clazz, String errorMsg) throws QLException { + public static T convert(Object object, Class clazz, String errorMsg) throws ELParseException { try { if (clazz.isAssignableFrom(object.getClass())) { if (object instanceof Node) { @@ -139,16 +139,16 @@ public class OperatorHelper { } } catch (Exception e) { - throw new QLException("An error occurred while copying an object"); + throw new ELParseException("An error occurred while copying an object"); } - throw new QLException(errorMsg); + throw new ELParseException(errorMsg); } - public static void checkItemNotNull(Object[] objects) throws QLException { + public static void checkItemNotNull(Object[] objects) throws ELParseException { for (Object object : objects) { if (Objects.isNull(object)) { - throw new QLException(DataNotFoundException.MSG); + throw new ELParseException(DataNotFoundException.MSG); } } } @@ -159,13 +159,13 @@ public class OperatorHelper { */ public static void checkObjMustBeCommonTypeItem(Object object) throws Exception{ if (!(object instanceof Executable)){ - throw new QLException("The parameter must be Executable item."); + throw new ELParseException("The parameter must be Executable item."); } Executable item = (Executable) object; if (item.getExecuteType().equals(ExecuteableTypeEnum.NODE)){ Node node = (Node) item; if (!ListUtil.toList(NodeTypeEnum.COMMON, NodeTypeEnum.SCRIPT, NodeTypeEnum.FALLBACK).contains(node.getType())){ - throw new QLException(StrUtil.format("The node[{}] must be a common type component", node.getId())); + throw new ELParseException(StrUtil.format("The node[{}] must be a common type component", node.getId())); } } } @@ -178,7 +178,7 @@ public class OperatorHelper { */ public static void checkObjMustBeBooleanTypeItem(Object object) throws Exception{ if (!(object instanceof Executable)){ - throw new QLException("The parameter must be Executable item."); + throw new ELParseException("The parameter must be Executable item."); } Executable item = (Executable) object; if (item.getExecuteType().equals(ExecuteableTypeEnum.NODE)){ @@ -186,21 +186,21 @@ public class OperatorHelper { if (!ListUtil.toList(NodeTypeEnum.BOOLEAN, NodeTypeEnum.BOOLEAN_SCRIPT, NodeTypeEnum.FALLBACK).contains(node.getType())){ - throw new QLException(StrUtil.format("The node[{}] must be boolean type Node.", node.getId())); + throw new ELParseException(StrUtil.format("The node[{}] must be boolean type Node.", node.getId())); } }else if(item.getExecuteType().equals(ExecuteableTypeEnum.CONDITION)){ Condition condition = (Condition) item; if (!ListUtil.toList(ConditionTypeEnum.TYPE_AND_OR_OPT, ConditionTypeEnum.TYPE_NOT_OPT).contains(condition.getConditionType())){ - throw new QLException(StrUtil.format("The condition[{}] must be boolean type Condition.", condition.getId())); + throw new ELParseException(StrUtil.format("The condition[{}] must be boolean type Condition.", condition.getId())); } }else{ - throw new QLException("The parameter error."); + throw new ELParseException("The parameter error."); } } public static void checkObjMustBeForTypeItem(Object object) throws Exception{ if (!(object instanceof Executable)){ - throw new QLException("The parameter must be Executable item."); + throw new ELParseException("The parameter must be Executable item."); } Executable item = (Executable) object; if (item.getExecuteType().equals(ExecuteableTypeEnum.NODE)){ @@ -208,32 +208,32 @@ public class OperatorHelper { if (!ListUtil.toList(NodeTypeEnum.FOR, NodeTypeEnum.FOR_SCRIPT, NodeTypeEnum.FALLBACK).contains(node.getType())){ - throw new QLException(StrUtil.format("The node[{}] must be For type Node.", node.getId())); + throw new ELParseException(StrUtil.format("The node[{}] must be For type Node.", node.getId())); } }else{ - throw new QLException("The parameter error."); + throw new ELParseException("The parameter error."); } } public static void checkObjMustBeIteratorTypeItem(Object object) throws Exception{ if (!(object instanceof Executable)){ - throw new QLException("The parameter must be Executable item."); + throw new ELParseException("The parameter must be Executable item."); } Executable item = (Executable) object; if (item.getExecuteType().equals(ExecuteableTypeEnum.NODE)){ Node node = (Node) item; if (!ListUtil.toList(NodeTypeEnum.ITERATOR, NodeTypeEnum.FALLBACK).contains(node.getType())){ - throw new QLException(StrUtil.format("The node[{}] must be Iterator type Node.", node.getId())); + throw new ELParseException(StrUtil.format("The node[{}] must be Iterator type Node.", node.getId())); } }else{ - throw new QLException("The parameter error."); + throw new ELParseException("The parameter error."); } } public static void checkObjMustBeSwitchTypeItem(Object object) throws Exception{ if (!(object instanceof Executable)){ - throw new QLException("The parameter must be Executable item."); + throw new ELParseException("The parameter must be Executable item."); } Executable item = (Executable) object; if (item.getExecuteType().equals(ExecuteableTypeEnum.NODE)){ @@ -241,10 +241,10 @@ public class OperatorHelper { if (!ListUtil.toList(NodeTypeEnum.SWITCH, NodeTypeEnum.SWITCH_SCRIPT, NodeTypeEnum.FALLBACK).contains(node.getType())){ - throw new QLException(StrUtil.format("The node[{}] must be Switch type Node.", node.getId())); + throw new ELParseException(StrUtil.format("The node[{}] must be Switch type Node.", node.getId())); } }else{ - throw new QLException("The parameter error."); + throw new ELParseException("The parameter error."); } } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/DeclComponentProxy.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/DeclComponentProxy.java index 905d89847..8104ec8ea 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/DeclComponentProxy.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/DeclComponentProxy.java @@ -6,9 +6,9 @@ import cn.hutool.core.lang.Tuple; import cn.hutool.core.util.ArrayUtil; 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.alibaba.qlexpress4.Express4Runner; +import com.alibaba.qlexpress4.QLResult; +import com.alibaba.qlexpress4.QLOptions; import com.yomahub.liteflow.annotation.LiteflowMethod; import com.yomahub.liteflow.annotation.LiteflowRetry; import com.yomahub.liteflow.core.NodeComponent; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/BaseNodeInstanceIdManageSpi.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/BaseNodeInstanceIdManageSpi.java index b18ef6467..38415a34c 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/BaseNodeInstanceIdManageSpi.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/BaseNodeInstanceIdManageSpi.java @@ -1,13 +1,13 @@ package com.yomahub.liteflow.flow.instanceId; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; 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.entity.InstanceInfoDto; import com.yomahub.liteflow.util.JsonUtil; -import org.apache.commons.lang.StringUtils; import java.util.*; @@ -26,7 +26,7 @@ public abstract class BaseNodeInstanceIdManageSpi implements NodeInstanceIdManag */ @Override public Node getNodeByIdAndInstanceId(String chainId, String instanceId) { - if (StringUtils.isBlank(chainId) || StringUtils.isBlank(instanceId)) { + if (StrUtil.isBlank(chainId) || StrUtil.isBlank(instanceId)) { return null; } Chain chain = FlowBus.getChain(chainId); @@ -45,7 +45,7 @@ public abstract class BaseNodeInstanceIdManageSpi implements NodeInstanceIdManag */ @Override public Node getNodeByIdAndIndex(String chainId, String nodeId, Integer index) { - if (StringUtils.isBlank(chainId) || index == null) { + if (StrUtil.isBlank(chainId) || index == null) { return null; } Chain chain = FlowBus.getChain(chainId); @@ -64,7 +64,7 @@ public abstract class BaseNodeInstanceIdManageSpi implements NodeInstanceIdManag */ @Override public List getNodeInstanceIds(String chainId, String nodeId) { - if (StringUtils.isBlank(chainId) || StringUtils.isBlank(nodeId)) { + if (StrUtil.isBlank(chainId) || StrUtil.isBlank(nodeId)) { return Collections.emptyList(); } // 第一行为elMd5 第二行为实例id json格式信息 @@ -133,7 +133,7 @@ public abstract class BaseNodeInstanceIdManageSpi implements NodeInstanceIdManag */ @Override public int getNodeLocationById(String chainId, String instanceId) { - if (StringUtils.isBlank(chainId) || StringUtils.isBlank(instanceId)) { + if (StrUtil.isBlank(chainId) || StrUtil.isBlank(instanceId)) { return -1; } // 第一行为elMd5 第二行为实例id json格式信息 diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/DefaultNodeInstanceIdManageSpiImpl.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/DefaultNodeInstanceIdManageSpiImpl.java index cc94e8185..da8ed5dca 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/DefaultNodeInstanceIdManageSpiImpl.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/instanceId/DefaultNodeInstanceIdManageSpiImpl.java @@ -3,9 +3,9 @@ package com.yomahub.liteflow.flow.instanceId; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; import com.yomahub.liteflow.flow.entity.InstanceInfoDto; import com.yomahub.liteflow.util.JsonUtil; -import org.apache.commons.lang.StringUtils; import java.io.File; import java.util.*; @@ -23,7 +23,7 @@ public class DefaultNodeInstanceIdManageSpiImpl extends BaseNodeInstanceIdManage @Override public List readInstanceIdFile(String chainId) { - if (StringUtils.isBlank(chainId)) { + if (StrUtil.isBlank(chainId)) { return Collections.emptyList(); } @@ -36,7 +36,7 @@ public class DefaultNodeInstanceIdManageSpiImpl extends BaseNodeInstanceIdManage @Override public void writeInstanceIdFile(List instanceIdList, String elMd5, String chainId) { - if (StringUtils.isBlank(chainId) || CollUtil.isEmpty(instanceIdList)) { + if (StrUtil.isBlank(chainId) || CollUtil.isEmpty(instanceIdList)) { return; } File nodeDir = new File(basePath + chainId); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteflowContextRegexMatcher.java b/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteflowContextRegexMatcher.java index a626caecd..605bf011e 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteflowContextRegexMatcher.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteflowContextRegexMatcher.java @@ -4,12 +4,14 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Tuple; import cn.hutool.core.util.BooleanUtil; 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.alibaba.qlexpress4.Express4Runner; +import com.alibaba.qlexpress4.QLResult; +import com.alibaba.qlexpress4.InitOptions; +import com.alibaba.qlexpress4.QLOptions; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -26,7 +28,7 @@ import java.util.stream.IntStream; */ public class LiteflowContextRegexMatcher { - private static final ExpressRunner expressRunner = new ExpressRunner(); + private static final Express4Runner expressRunner = new Express4Runner(InitOptions.DEFAULT_OPTIONS); public static Object searchContext(List contextList, String regPattern){ // 把上下文数据转换成map形式的,key为别名,value为上下文 @@ -34,16 +36,14 @@ public class LiteflowContextRegexMatcher { Collectors.toMap(tuple -> tuple.get(0), tuple -> tuple.get(1)) ); - List errorList = new ArrayList<>(); - Object result = null; // 根据表达式去上下文里搜索相匹配的数据 for(Map.Entry entry : contextMap.entrySet()){ try{ - InstructionSet instructionSet = expressRunner.getInstructionSetFromLocalCache(entry.getKey() + "." + regPattern); - DefaultContext context = new DefaultContext<>(); + Map context = new HashMap<>(); context.put(entry.getKey(), entry.getValue()); - result = expressRunner.execute(instructionSet, context, errorList, false, false); + QLResult expressResult = expressRunner.execute(entry.getKey() + "." + regPattern, context, QLOptions.DEFAULT_OPTIONS); + result = expressResult.getResult(); if (result != null){ break; } @@ -53,10 +53,10 @@ public class LiteflowContextRegexMatcher { if (result == null){ try{ // 如果没有搜到,那么尝试推断表达式是指定的上下文,按照指定上下文的方式去再获取 - InstructionSet instructionSet = expressRunner.getInstructionSetFromLocalCache("contextMap." + regPattern); - DefaultContext context = new DefaultContext<>(); + Map context = new HashMap<>(); context.put("contextMap", contextMap); - result = expressRunner.execute(instructionSet, context, errorList, false, false); + QLResult expressResult = expressRunner.execute("contextMap." + regPattern, context, QLOptions.DEFAULT_OPTIONS); + result = expressResult.getResult(); }catch (Exception ignore){} } @@ -69,8 +69,6 @@ public class LiteflowContextRegexMatcher { Collectors.toMap(tuple -> tuple.get(0), tuple -> tuple.get(1)) ); - List errorList = new ArrayList<>(); - boolean flag = false; String argStr = IntStream.range(0, args.length).mapToObj( @@ -83,11 +81,10 @@ public class LiteflowContextRegexMatcher { for(Map.Entry entry : contextMap.entrySet()){ try{ - InstructionSet instructionSet = expressRunner.getInstructionSetFromLocalCache(StrUtil.format("{}.{}({})", entry.getKey(), methodExpress, argStr)); - DefaultContext context = new DefaultContext<>(); + Map context = new HashMap<>(); context.put(entry.getKey(), entry.getValue()); tupleList.forEach(tuple -> context.put(tuple.getA(), args[tuple.getB()])); - expressRunner.execute(instructionSet, context, errorList, false, false); + expressRunner.execute(StrUtil.format("{}.{}({})", entry.getKey(), methodExpress, argStr), context, QLOptions.DEFAULT_OPTIONS); flag = true; break; }catch (Exception ignore){} @@ -97,11 +94,10 @@ public class LiteflowContextRegexMatcher { if (BooleanUtil.isFalse(flag)){ try{ // 如果没有搜到,那么尝试推断表达式是指定的上下文,按照指定上下文的方式去再获取 - InstructionSet instructionSet = expressRunner.getInstructionSetFromLocalCache(StrUtil.format("contextMap.{}({})", methodExpress, argStr)); - DefaultContext context = new DefaultContext<>(); + Map context = new HashMap<>(); context.put("contextMap", contextMap); tupleList.forEach(tuple -> context.put(tuple.getA(), args[tuple.getB()])); - expressRunner.execute(instructionSet, context, errorList, false, false); + expressRunner.execute(StrUtil.format("contextMap.{}({})", methodExpress, argStr), context, QLOptions.DEFAULT_OPTIONS); }catch (Exception ignore){} } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/util/QlExpressUtils.java b/liteflow-core/src/main/java/com/yomahub/liteflow/util/QlExpressUtils.java index 0dac32a61..05a14d8fe 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/util/QlExpressUtils.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/util/QlExpressUtils.java @@ -1,6 +1,7 @@ package com.yomahub.liteflow.util; -import com.ql.util.express.ExpressRunner; +import com.alibaba.qlexpress4.Express4Runner; +import com.alibaba.qlexpress4.InitOptions; import com.yomahub.liteflow.builder.el.operator.*; import com.yomahub.liteflow.common.ChainConstant; @@ -15,54 +16,54 @@ public class QlExpressUtils { /** * EL解析引擎 */ - private final static ExpressRunner EXPRESS_RUNNER = new ExpressRunner(); + private final static Express4Runner EXPRESS_RUNNER = new Express4Runner(InitOptions.DEFAULT_OPTIONS); static { // 初始化QLExpress的Runner - EXPRESS_RUNNER.addFunction(ChainConstant.THEN, new ThenOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.WHEN, new WhenOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.SER, new ThenOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.PAR, new WhenOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.SWITCH, new SwitchOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.PRE, new PreOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.FINALLY, new FinallyOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.IF, new IfOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.NODE.toUpperCase(), new NodeOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.NODE, new NodeOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.FOR, new ForOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.WHILE, new WhileOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.ITERATOR, new IteratorOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.CATCH, new CatchOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.AND, new AndOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.OR, new OrOperator()); - EXPRESS_RUNNER.addFunction(ChainConstant.NOT, new NotOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELSE, Object.class, new ElseOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELIF, Object.class, new ElifOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO, Object.class, new ToOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO.toLowerCase(), Object.class, new ToOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DEFAULT, Object.class, new DefaultOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TAG, Object.class, new TagOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ANY, Object.class, new AnyOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MUST, Object.class, new MustOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.PERCENTAGE, Object.class, new PercentageOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ID, Object.class, new IdOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.IGNORE_ERROR, Object.class, new IgnoreErrorOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.THREAD_POOL, Object.class, new ThreadPoolOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DO, Object.class, new DoOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BREAK, Object.class, new BreakOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DATA, Object.class, new DataOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MAX_WAIT_SECONDS, Object.class, new MaxWaitSecondsOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MAX_WAIT_MILLISECONDS, Object.class, new MaxWaitMillisecondsOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.PARALLEL, Object.class, new ParallelOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.RETRY, Object.class, new RetryOperator()); - EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BIND, Object.class, new BindOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.THEN, new ThenOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.WHEN, new WhenOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.SER, new ThenOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.PAR, new WhenOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.SWITCH, new SwitchOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.PRE, new PreOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.FINALLY, new FinallyOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.IF, new IfOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.NODE.toUpperCase(), new NodeOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.NODE, new NodeOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.FOR, new ForOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.WHILE, new WhileOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.ITERATOR, new IteratorOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.CATCH, new CatchOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.AND, new AndOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.OR, new OrOperator()); + EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.NOT, new NotOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.ELSE, Object.class, new ElseOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.ELIF, Object.class, new ElifOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.TO, Object.class, new ToOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.TO.toLowerCase(), Object.class, new ToOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.DEFAULT, Object.class, new DefaultOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.TAG, Object.class, new TagOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.ANY, Object.class, new AnyOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.MUST, Object.class, new MustOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.PERCENTAGE, Object.class, new PercentageOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.ID, Object.class, new IdOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.IGNORE_ERROR, Object.class, new IgnoreErrorOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.THREAD_POOL, Object.class, new ThreadPoolOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.DO, Object.class, new DoOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.BREAK, Object.class, new BreakOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.DATA, Object.class, new DataOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.MAX_WAIT_SECONDS, Object.class, new MaxWaitSecondsOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.MAX_WAIT_MILLISECONDS, Object.class, new MaxWaitMillisecondsOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.PARALLEL, Object.class, new ParallelOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.RETRY, Object.class, new RetryOperator()); + EXPRESS_RUNNER.addExtendFunction(ChainConstant.BIND, Object.class, new BindOperator()); } /** * 获取QLExpress的实例 */ - public static ExpressRunner getInstance() { + public static Express4Runner getInstance() { return EXPRESS_RUNNER; } diff --git a/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/InstanceIdRead.java b/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/InstanceIdRead.java index 3aa48f3f4..866898819 100644 --- a/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/InstanceIdRead.java +++ b/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/InstanceIdRead.java @@ -7,7 +7,6 @@ import com.yomahub.liteflow.parser.sql.exception.ELSQLException; import com.yomahub.liteflow.parser.sql.read.AbstractSqlRead; import com.yomahub.liteflow.parser.sql.read.vo.InstanceIdVO; import com.yomahub.liteflow.parser.sql.vo.SQLParserVO; -import org.apache.commons.lang.StringUtils; import java.sql.ResultSet; import java.sql.SQLException; @@ -59,7 +58,7 @@ public class InstanceIdRead extends AbstractSqlRead { String instanceIdApplicationNameField = super.config.getInstanceIdApplicationNameField(); String applicationName = super.config.getApplicationName(); - if (StringUtils.isEmpty(chainId)) { + if (StrUtil.isEmpty(chainId)) { throw new IllegalArgumentException("You did not define the chainId"); } return StrUtil.format(SqlReadConstant.SQL_PATTERN_WITH_CHAIN_ID, tableName, instanceIdApplicationNameField diff --git a/liteflow-script-plugin/liteflow-script-qlexpress/pom.xml b/liteflow-script-plugin/liteflow-script-qlexpress/pom.xml index 7580d4316..2708be582 100644 --- a/liteflow-script-plugin/liteflow-script-qlexpress/pom.xml +++ b/liteflow-script-plugin/liteflow-script-qlexpress/pom.xml @@ -23,7 +23,7 @@ com.alibaba - QLExpress + qlexpress4 \ No newline at end of file diff --git a/liteflow-script-plugin/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java b/liteflow-script-plugin/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java index 66a86beac..1961e590f 100644 --- a/liteflow-script-plugin/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java +++ b/liteflow-script-plugin/liteflow-script-qlexpress/src/main/java/com/yomahub/liteflow/script/qlexpress/QLExpressScriptExecutor.java @@ -2,10 +2,10 @@ package com.yomahub.liteflow.script.qlexpress; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; -import com.ql.util.express.DefaultContext; -import com.ql.util.express.ExpressLoader; -import com.ql.util.express.ExpressRunner; -import com.ql.util.express.InstructionSet; +import com.alibaba.qlexpress4.Express4Runner; +import com.alibaba.qlexpress4.QLResult; +import com.alibaba.qlexpress4.InitOptions; +import com.alibaba.qlexpress4.QLOptions; import com.yomahub.liteflow.enums.ScriptTypeEnum; import com.yomahub.liteflow.script.ScriptExecuteWrap; import com.yomahub.liteflow.script.ScriptExecutor; @@ -17,6 +17,7 @@ import org.slf4j.LoggerFactory; import javax.script.ScriptException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,13 +31,13 @@ public class QLExpressScriptExecutor extends ScriptExecutor { private final Logger log = LoggerFactory.getLogger(this.getClass()); - private ExpressRunner expressRunner; + private Express4Runner expressRunner; - private final Map compiledScriptMap = new CopyOnWriteHashMap<>(); + private final Map compiledScriptMap = new CopyOnWriteHashMap<>(); @Override public ScriptExecutor init() { - expressRunner = new ExpressRunner(true, false); + expressRunner = new Express4Runner(InitOptions.DEFAULT_OPTIONS); //如果有生命周期则执行相应生命周期实现 super.lifeCycle(expressRunner); return this; @@ -45,7 +46,8 @@ public class QLExpressScriptExecutor extends ScriptExecutor { @Override public void load(String nodeId, String script) { try { - compiledScriptMap.put(nodeId, (InstructionSet) compile(script)); + // QLExpress4 不需要预编译,直接存储脚本内容 + compiledScriptMap.put(nodeId, script); } catch (Exception e) { String errorMsg = StrUtil.format("script loading error for node[{}],error msg:{}", nodeId, e.getMessage()); @@ -65,24 +67,21 @@ public class QLExpressScriptExecutor extends ScriptExecutor { @Override public Object executeScript(ScriptExecuteWrap wrap) throws Exception { - List errorList = new ArrayList<>(); try { if (!compiledScriptMap.containsKey(wrap.getNodeId())) { String errorMsg = StrUtil.format("script for node[{}] is not loaded", wrap.getNodeId()); throw new ScriptLoadException(errorMsg); } - InstructionSet instructionSet = compiledScriptMap.get(wrap.getNodeId()); - DefaultContext context = new DefaultContext<>(); + String script = compiledScriptMap.get(wrap.getNodeId()); + Map context = new HashMap<>(); bindParam(wrap, context::put, context::putIfAbsent); - return expressRunner.execute(instructionSet, context, errorList, true, false); + QLResult expressResult = expressRunner.execute(script, context, QLOptions.DEFAULT_OPTIONS); + return expressResult.getResult(); } catch (Exception e) { - for (String scriptErrorMsg : errorList) { - log.error("\n{}", scriptErrorMsg); - } throw e; } } @@ -90,8 +89,10 @@ public class QLExpressScriptExecutor extends ScriptExecutor { @Override public void cleanCache() { compiledScriptMap.clear(); - expressRunner.clearExpressCache(); - ReflectUtil.setFieldValue(expressRunner, "loader", new ExpressLoader(expressRunner)); + // QLExpress4 没有 clearExpressCache 方法,重新初始化 runner + expressRunner = new Express4Runner(InitOptions.DEFAULT_OPTIONS); + //如果有生命周期则执行相应生命周期实现 + super.lifeCycle(expressRunner); } @Override @@ -101,7 +102,8 @@ public class QLExpressScriptExecutor extends ScriptExecutor { @Override public Object compile(String script) throws Exception { - return expressRunner.getInstructionSetFromLocalCache(script); + // QLExpress4 不支持预编译,返回 null + return null; } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/base/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/base/flow.el.xml index aab117311..5bed8ab83 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/base/flow.el.xml +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/base/flow.el.xml @@ -2,53 +2,7 @@ - THEN(a,b,b,a); + THEN(a,b,b,a,SWITCH(e).TO(d,b)) - - THEN( - a,b, - SWITCH(e).to(d,f) - ); - - - - THEN( - a, - WHEN( - c, - SWITCH(g).to(b, d, THEN(h,i).id("then_1001")) - ) - ); - - - - THEN( - a,b, - WHEN( - THEN(c, WHEN(j,k)), - d, - THEN(h, i) - ), - SWITCH(x).to( - m, - n, - WHEN(q, THEN(p, r)).id("w01") - ), - z - ); - - - - t1 = THEN(c, WHEN(j,k)); - w1 = WHEN(q, THEN(p, r)).id("w01"); - t2 = THEN(h, i); - - THEN( - a,b, - WHEN(t1, d, t2 ), - SWITCH(x).to(m, n, w1), - z - ); - \ No newline at end of file diff --git a/pom.xml b/pom.xml index 55a54b112..822e38718 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 0.10 0.7.3 1.4.4 - 3.3.4 + 4.0.5 3.0.25 22.0.0 1.17.7 @@ -227,7 +227,7 @@ com.alibaba - QLExpress + qlexpress4 ${qlexpress.version}