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 440e5b1ad..0b7568746 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 @@ -66,6 +66,7 @@ public class LiteFlowChainELBuilder { expressRunner.addFunctionAndClassMethod("id", Object.class, new IdOperator()); expressRunner.addFunctionAndClassMethod("ignoreError", Object.class, new IgnoreErrorOperator()); expressRunner.addFunctionAndClassMethod("threadPool", Object.class, new ThreadPoolOperator()); + expressRunner.addFunction("node", new NodeOperator()); } //在parser中chain的build是2段式的,因为涉及到依赖问题,以前是递归parser diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/NodeOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/NodeOperator.java new file mode 100644 index 000000000..88b61f073 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/NodeOperator.java @@ -0,0 +1,65 @@ +package com.yomahub.liteflow.builder.el.operator; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.ql.util.express.Operator; +import com.yomahub.liteflow.flow.FlowBus; +import com.yomahub.liteflow.flow.element.Node; +import com.yomahub.liteflow.property.LiteflowConfig; +import com.yomahub.liteflow.property.LiteflowConfigGetter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.function.Predicate; + +/** + * EL规则中的node的操作符 + * @author Bryan.Zhang + * @since 2.8.3 + */ +public class NodeOperator extends Operator { + + private final Logger LOG = LoggerFactory.getLogger(this.getClass()); + + @Override + public Object executeInner(Object[] objects) throws Exception { + if (ArrayUtil.isEmpty(objects)){ + throw new Exception(); + } + + if (objects.length != 1){ + LOG.error("parameter error"); + throw new Exception(); + } + + String nodeId; + if (objects[0] instanceof String){ + nodeId = (String) objects[0]; + }else{ + LOG.error("The value must be Node item!"); + throw new Exception(); + } + + if (FlowBus.containNode(nodeId)){ + return FlowBus.getNode(nodeId); + }else{ + LiteflowConfig liteflowConfig = LiteflowConfigGetter.get(); + if (StrUtil.isNotBlank(liteflowConfig.getSubstituteCmpClass())){ + Node substituteNode = FlowBus.getNodeMap().values().stream().filter(node + -> node.getInstance().getClass().getName().equals(liteflowConfig.getSubstituteCmpClass())).findFirst().orElse(null); + if (ObjectUtil.isNotNull(substituteNode)){ + return substituteNode; + }else{ + String error = StrUtil.format("This node[{}] cannot be found", nodeId); + LOG.error(error); + throw new Exception(); + } + }else{ + String error = StrUtil.format("This node[{}] cannot be found, or you can configure an substitute node", nodeId); + LOG.error(error); + throw new Exception(); + } + } + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java b/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java index f320c6d3a..f50d8f46c 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java @@ -87,6 +87,9 @@ public class LiteflowConfig { //是否打印执行中的日志 private Boolean printExecutionLog; + //替补组件class路径 + private String substituteCmpClass; + public Boolean getEnable() { if (ObjectUtil.isNull(enable)) { return Boolean.TRUE; @@ -333,4 +336,12 @@ public class LiteflowConfig { public void setPrintExecutionLog(Boolean printExecutionLog) { this.printExecutionLog = printExecutionLog; } + + public String getSubstituteCmpClass() { + return substituteCmpClass; + } + + public void setSubstituteCmpClass(String substituteCmpClass) { + this.substituteCmpClass = substituteCmpClass; + } } diff --git a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java index 9fb6cd20b..1ad21adcc 100644 --- a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java +++ b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java @@ -62,6 +62,9 @@ public class LiteflowProperty { //是否打印执行过程中的日志 private boolean printExecutionLog; + //替补组件的class路径 + private String substituteCmpClass; + public boolean isEnable() { return enable; } @@ -197,4 +200,12 @@ public class LiteflowProperty { public void setRequestIdGeneratorClass(String requestIdGeneratorClass) { this.requestIdGeneratorClass = requestIdGeneratorClass; } + + public String getSubstituteCmpClass() { + return substituteCmpClass; + } + + public void setSubstituteCmpClass(String substituteCmpClass) { + this.substituteCmpClass = substituteCmpClass; + } } diff --git a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java index eaca85a5f..80986b4bf 100644 --- a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java +++ b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java @@ -45,6 +45,7 @@ public class LiteflowPropertyAutoConfiguration { liteflowConfig.setMainExecutorWorks(property.getMainExecutorWorks()); liteflowConfig.setMainExecutorClass(property.getMainExecutorClass()); liteflowConfig.setPrintExecutionLog(property.isPrintExecutionLog()); + liteflowConfig.setSubstituteCmpClass(property.getSubstituteCmpClass()); return liteflowConfig; } } diff --git a/liteflow-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/liteflow-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 3cdaf349e..51b0a3324 100644 --- a/liteflow-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/liteflow-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -119,6 +119,13 @@ "sourceType": "com.yomahub.liteflow.springboot.LiteflowProperty", "defaultValue": true }, + { + "name": "liteflow.substitute-cmp-class", + "type": "java.lang.String", + "description": "substitute component class.", + "sourceType": "com.yomahub.liteflow.springboot.LiteflowProperty", + "defaultValue": "" + }, { "name": "liteflow.monitor.enable-log", "type": "java.lang.Boolean", diff --git a/liteflow-spring-boot-starter/src/main/resources/META-INF/liteflow-default.properties b/liteflow-spring-boot-starter/src/main/resources/META-INF/liteflow-default.properties index 582418ad2..50264318f 100644 --- a/liteflow-spring-boot-starter/src/main/resources/META-INF/liteflow-default.properties +++ b/liteflow-spring-boot-starter/src/main/resources/META-INF/liteflow-default.properties @@ -14,6 +14,7 @@ liteflow.retry-count=0 liteflow.support-multiple-type=false liteflow.node-executor-class=com.yomahub.liteflow.flow.executor.DefaultNodeExecutor liteflow.print-execution-log=true +liteflow.substitute-cmp-class= liteflow.monitor.enable-log=false liteflow.monitor.queue-limit=200 liteflow.monitor.delay=300000 diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/substituteNode/SubstituteSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/substituteNode/SubstituteSpringbootTest.java new file mode 100644 index 000000000..bdec0acd9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/substituteNode/SubstituteSpringbootTest.java @@ -0,0 +1,44 @@ +package com.yomahub.liteflow.test.substituteNode; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; + +/** + * springboot环境EL替补节点的测试 + * @author Bryan.Zhang + */ +@RunWith(SpringRunner.class) +@TestPropertySource(value = "classpath:/substituteNode/application.properties") +@SpringBootTest(classes = SubstituteSpringbootTest.class) +@EnableAutoConfiguration +@ComponentScan({"com.yomahub.liteflow.test.substituteNode.cmp"}) +public class SubstituteSpringbootTest extends BaseTest { + + @Resource + private FlowExecutor flowExecutor; + + //最简单的情况 + @Test + public void testSub1() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //有替补节点 + @Test + public void testSub2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/ACmp.java new file mode 100644 index 000000000..5b95b6d3b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

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

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.substituteNode.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/substituteNode/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/BCmp.java new file mode 100644 index 000000000..495db7ac3 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/substituteNode/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.substituteNode.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/substituteNode/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/CCmp.java new file mode 100644 index 000000000..dca6da62a --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/substituteNode/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

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

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

Title: liteflow

+ *

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

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.substituteNode.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("sub") +public class SubCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("SubCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/substituteNode/application.properties b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/substituteNode/application.properties new file mode 100644 index 000000000..35bdc3a1e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/substituteNode/application.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=substituteNode/flow.el.xml +liteflow.substitute-cmp-class=com.yomahub.liteflow.test.substituteNode.cmp.SubCmp \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/substituteNode/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/substituteNode/flow.el.xml new file mode 100644 index 000000000..2ac202b9b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/substituteNode/flow.el.xml @@ -0,0 +1,10 @@ + + + + THEN(node("a"), node("b"), node("c")); + + + + THEN(node("a"), node("b"), node("93-nodeTEST")); + + \ No newline at end of file