diff --git a/.gitignore b/.gitignore index 76b3603cf..9a8ec89b0 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,5 @@ atlassian-ide-plugin.xml */logs .flattened-pom.xml - .claude .vscode \ No newline at end of file diff --git a/liteflow-benchmark/liteflow-benchmark-common-example/pom.xml b/liteflow-benchmark/liteflow-benchmark-common-example/pom.xml index 821e4a241..d7358da76 100644 --- a/liteflow-benchmark/liteflow-benchmark-common-example/pom.xml +++ b/liteflow-benchmark/liteflow-benchmark-common-example/pom.xml @@ -16,7 +16,7 @@ com.yomahub liteflow-script-javax-pro - ${revision} + ${liteflow-version} test diff --git a/liteflow-benchmark/liteflow-benchmark-common/pom.xml b/liteflow-benchmark/liteflow-benchmark-common/pom.xml index df0661fd8..fb62c3524 100644 --- a/liteflow-benchmark/liteflow-benchmark-common/pom.xml +++ b/liteflow-benchmark/liteflow-benchmark-common/pom.xml @@ -16,7 +16,7 @@ com.yomahub liteflow-script-javax - ${revision} + ${liteflow-version} test diff --git a/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/CommonBenchmark.java b/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/CommonBenchmark.java index 275683423..43c9b1d55 100644 --- a/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/CommonBenchmark.java +++ b/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/CommonBenchmark.java @@ -1,10 +1,13 @@ package com.yomahub.liteflow.benchmark; import cn.hutool.core.io.resource.ResourceUtil; +import com.yomahub.liteflow.benchmark.cmp.TestContext; import com.yomahub.liteflow.builder.LiteFlowNodeBuilder; import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder; import com.yomahub.liteflow.core.FlowExecutor; import com.yomahub.liteflow.flow.FlowBus; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; @@ -42,7 +45,12 @@ public class CommonBenchmark { @Benchmark public void test1(){ - flowExecutor.execute2Resp("chain1"); + TestContext context = new TestContext(); + context.setName("tom"); + context.setAge(21); + DefaultContext defaultContext = new DefaultContext(); + + flowExecutor.execute2Resp("chain1", null, context,defaultContext); } public static void main(String[] args) throws RunnerException { diff --git a/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/CommonTest.java b/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/CommonTest.java new file mode 100644 index 000000000..f8869ab68 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/CommonTest.java @@ -0,0 +1,41 @@ +package com.yomahub.liteflow.benchmark; + +import cn.hutool.core.io.resource.ResourceUtil; +import com.yomahub.liteflow.benchmark.cmp.TestContext; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.util.JsonUtil; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +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.junit.jupiter.SpringExtension; + +import javax.annotation.Resource; + +@ExtendWith(SpringExtension.class) +@TestPropertySource(value = "classpath:application.properties") +@SpringBootTest(classes = CommonTest.class) +@EnableAutoConfiguration +@ComponentScan({ "com.yomahub.liteflow.benchmark.cmp" }) +public class CommonTest { + + @Resource + private FlowExecutor flowExecutor; + + @Test + public void test1() throws Exception { + TestContext context = new TestContext(); + context.setName("tom"); + context.setAge(21); + DefaultContext defaultContext = new DefaultContext(); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1", null, context,defaultContext); + if (!response.isSuccess()){ + throw response.getCause(); + } + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/cmp/ACmp.java b/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/cmp/ACmp.java index 4611110de..0ff485aa2 100644 --- a/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/cmp/ACmp.java +++ b/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/cmp/ACmp.java @@ -22,7 +22,7 @@ public class ACmp extends NodeComponent { public void process() { int v1 = 2; int v2 = 3; - DefaultContext ctx = this.getFirstContextBean(); + DefaultContext ctx = this.getContextBean(DefaultContext.class); ctx.setData("s1", v1 * v2); TestDomain domain = ContextAwareHolder.loadContextAware().getBean(TestDomain.class); diff --git a/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/cmp/CmpConfig.java b/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/cmp/CmpConfig.java new file mode 100644 index 000000000..b31896602 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/cmp/CmpConfig.java @@ -0,0 +1,21 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.annotation.LiteflowFact; +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; + +@LiteflowComponent +public class CmpConfig { + + @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "b") + public void processA(NodeComponent bindCmp, @LiteflowFact("name") String name) { +// System.out.println(name); + } + + @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "c") + public void processB(NodeComponent bindCmp, @LiteflowFact("age") int age) { +// System.out.println(age); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/cmp/TestContext.java b/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/cmp/TestContext.java new file mode 100644 index 000000000..df6f9430a --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-common/src/test/java/com/yomahub/liteflow/benchmark/cmp/TestContext.java @@ -0,0 +1,24 @@ +package com.yomahub.liteflow.benchmark.cmp; + +public class TestContext { + + private String name; + + private int age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-common/src/test/resources/flow.xml b/liteflow-benchmark/liteflow-benchmark-common/src/test/resources/flow.xml index 41259eb42..45589ebd2 100644 --- a/liteflow-benchmark/liteflow-benchmark-common/src/test/resources/flow.xml +++ b/liteflow-benchmark/liteflow-benchmark-common/src/test/resources/flow.xml @@ -2,6 +2,6 @@ - THEN(a); + THEN(a,b,c); \ No newline at end of file diff --git a/liteflow-benchmark/liteflow-benchmark-compile/pom.xml b/liteflow-benchmark/liteflow-benchmark-compile/pom.xml new file mode 100644 index 000000000..63151a499 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + liteflow-benchmark + com.yomahub + ${revision} + ../pom.xml + + + liteflow-benchmark-compile + + + \ No newline at end of file diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/TestCompile.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/TestCompile.java new file mode 100644 index 000000000..7d9118790 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/TestCompile.java @@ -0,0 +1,79 @@ +package com.yomahub.liteflow.benchmark; + +import cn.hutool.core.date.StopWatch; +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +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.junit.jupiter.SpringExtension; + +import javax.annotation.Resource; + +@ExtendWith(SpringExtension.class) +@TestPropertySource(value = "classpath:application.properties") +@SpringBootTest(classes = TestCompile.class) +@EnableAutoConfiguration +@ComponentScan({ "com.yomahub.liteflow.benchmark.cmp" }) +public class TestCompile { + + @Resource + private FlowExecutor flowExecutor; + + @Test + public void test1() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("channelSenderChain", null, BatchMessageResultContext.class); + BatchMessageResultContext context = response.getFirstContextBean(); + if (response.isSuccess()){ + System.out.println("执行成功,最终选择的渠道是:" + context.getFinalResultChannel()); + }else{ + System.out.println("执行失败:" + response.getCause()); + } + } + + //每个el都一样,走QL的缓存 + @Test + public void test2() throws Exception { + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + String el = "selectBestChannel = THEN(WHEN(channel1Query, channel2Query, channel3Query,channel4Query, channel5Query, channel6Query),channelSelector).id(\"branch1\");\n" + + " selectBizChannel = THEN(biz1,SWITCH(if_2).to(channel3,channel4,SWITCH(if_3).to(channel5, channel6).id(\"s3\")).id(\"s2\")).id(\"branch2\");\n" + + " THEN(packageData,SWITCH(if_1).to(channel1,channel2,selectBestChannel,selectBizChannel),batchSender);"; + + for (int i = 1; i <= 20000; i++) { + LiteFlowChainELBuilder.createChain().setChainId("chain_build_"+i).setEL(el).build(); + } + + stopWatch.stop(); + + System.out.println(StrUtil.format("耗时:{}",stopWatch.getTotalTimeMillis())); + + } + + //每个el都不一样,不走QL的缓存 + @Test + public void test3() throws Exception { + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + String el = "selectBestChannel = THEN(WHEN(channel1Query, channel2Query, channel3Query,channel4Query, channel5Query, channel6Query),channelSelector).id(\"branch1\");\n" + + " selectBizChannel = THEN(biz1,SWITCH(if_2).to(channel3,channel4,SWITCH(if_3).to(channel5, channel6).id(\"s3\")).id(\"s2\")).id(\"branch2\");\n" + + " THEN(packageData.tag(\"{}\"),SWITCH(if_1).to(channel1,channel2,selectBestChannel,selectBizChannel),batchSender);"; + + for (int i = 1; i <= 20000; i++) { + LiteFlowChainELBuilder.createChain().setChainId("chain_build_"+i).setEL(StrUtil.format(el,i)).build(); + } + + stopWatch.stop(); + + System.out.println(StrUtil.format("耗时:{}",stopWatch.getTotalTimeMillis())); + + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/BatchSenderCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/BatchSenderCmp.java new file mode 100644 index 000000000..98aabc9ef --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/BatchSenderCmp.java @@ -0,0 +1,21 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.core.NodeComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Random; + +@LiteflowComponent(id = "batchSender", name = "批量发送器") +public class BatchSenderCmp extends NodeComponent { + + private static final Logger log = LoggerFactory.getLogger(BatchSenderCmp.class); + + @Override + public void process() throws Exception { + BatchMessageResultContext context = this.getFirstContextBean(); + log.info("最终获取到的渠道为:[{}]", context.getFinalResultChannel()); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Biz1Cmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Biz1Cmp.java new file mode 100644 index 000000000..74853a246 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Biz1Cmp.java @@ -0,0 +1,13 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +import java.util.Random; + +@LiteflowComponent(id = "biz1", name = "获取业务动态值") +public class Biz1Cmp extends NodeComponent { + @Override + public void process() throws Exception { + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel1Cmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel1Cmp.java new file mode 100644 index 000000000..34c8b04ed --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel1Cmp.java @@ -0,0 +1,14 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent(id = "channel1", name = "返回渠道1") +public class Channel1Cmp extends NodeComponent { + @Override + public void process() throws Exception { + BatchMessageResultContext context = this.getFirstContextBean(); + context.setFinalResultChannel("channel1"); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel1QueryCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel1QueryCmp.java new file mode 100644 index 000000000..0eaf3ac1f --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel1QueryCmp.java @@ -0,0 +1,18 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.benchmark.vo.QueryVO; +import com.yomahub.liteflow.core.NodeComponent; + +import java.util.Random; + +@LiteflowComponent(id = "channel1Query", name = "获取渠道1剩余量") +public class Channel1QueryCmp extends NodeComponent { + @Override + public void process() throws Exception { + //mock下渠道1有2w条剩余量 + BatchMessageResultContext context = this.getFirstContextBean(); + context.addQueryVO(new QueryVO("channel1", 20000)); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel2Cmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel2Cmp.java new file mode 100644 index 000000000..8a326a0ec --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel2Cmp.java @@ -0,0 +1,14 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent(id = "channel2", name = "返回渠道2") +public class Channel2Cmp extends NodeComponent { + @Override + public void process() throws Exception { + BatchMessageResultContext context = this.getFirstContextBean(); + context.setFinalResultChannel("channel2"); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel2QueryCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel2QueryCmp.java new file mode 100644 index 000000000..308d1339a --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel2QueryCmp.java @@ -0,0 +1,19 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.benchmark.vo.QueryVO; +import com.yomahub.liteflow.core.NodeComponent; + +import java.util.Random; + +@LiteflowComponent(id = "channel2Query", name = "获取渠道2剩余量") +public class Channel2QueryCmp extends NodeComponent { + @Override + public void process() throws Exception { + + //mock下渠道2有1w条剩余量 + BatchMessageResultContext context = this.getFirstContextBean(); + context.addQueryVO(new QueryVO("channel2", 10000)); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel3Cmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel3Cmp.java new file mode 100644 index 000000000..c32d667e9 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel3Cmp.java @@ -0,0 +1,14 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent(id = "channel3", name = "返回渠道3") +public class Channel3Cmp extends NodeComponent { + @Override + public void process() throws Exception { + BatchMessageResultContext context = this.getFirstContextBean(); + context.setFinalResultChannel("channel3"); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel3QueryCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel3QueryCmp.java new file mode 100644 index 000000000..eb1765bf6 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel3QueryCmp.java @@ -0,0 +1,19 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.benchmark.vo.QueryVO; +import com.yomahub.liteflow.core.NodeComponent; + +import java.util.Random; + +@LiteflowComponent(id = "channel3Query", name = "获取渠道3剩余量") +public class Channel3QueryCmp extends NodeComponent { + @Override + public void process() throws Exception { + + //mock下渠道3有10w条剩余量 + BatchMessageResultContext context = this.getFirstContextBean(); + context.addQueryVO(new QueryVO("channel3", 100000)); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel4Cmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel4Cmp.java new file mode 100644 index 000000000..53232a4b0 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel4Cmp.java @@ -0,0 +1,14 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent(id = "channel4", name = "返回渠道4") +public class Channel4Cmp extends NodeComponent { + @Override + public void process() throws Exception { + BatchMessageResultContext context = this.getFirstContextBean(); + context.setFinalResultChannel("channel4"); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel4QueryCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel4QueryCmp.java new file mode 100644 index 000000000..d886e3bd2 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel4QueryCmp.java @@ -0,0 +1,18 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.benchmark.vo.QueryVO; +import com.yomahub.liteflow.core.NodeComponent; + +import java.util.Random; + +@LiteflowComponent(id = "channel4Query", name = "获取渠道4剩余量") +public class Channel4QueryCmp extends NodeComponent { + @Override + public void process() throws Exception { + //mock下渠道4有7w条剩余量 + BatchMessageResultContext context = this.getFirstContextBean(); + context.addQueryVO(new QueryVO("channel4", 70000)); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel5Cmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel5Cmp.java new file mode 100644 index 000000000..42553cee3 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel5Cmp.java @@ -0,0 +1,14 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent(id = "channel5", name = "返回渠道5") +public class Channel5Cmp extends NodeComponent { + @Override + public void process() throws Exception { + BatchMessageResultContext context = this.getFirstContextBean(); + context.setFinalResultChannel("channel5"); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel5QueryCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel5QueryCmp.java new file mode 100644 index 000000000..e2c39c202 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel5QueryCmp.java @@ -0,0 +1,18 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.benchmark.vo.QueryVO; +import com.yomahub.liteflow.core.NodeComponent; + +import java.util.Random; + +@LiteflowComponent(id = "channel5Query", name = "获取渠道5剩余量") +public class Channel5QueryCmp extends NodeComponent { + @Override + public void process() throws Exception { + //mock下渠道5有5000条剩余量 + BatchMessageResultContext context = this.getFirstContextBean(); + context.addQueryVO(new QueryVO("channel5", 5000)); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel6Cmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel6Cmp.java new file mode 100644 index 000000000..6b870690f --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel6Cmp.java @@ -0,0 +1,14 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent(id = "channel6", name = "返回渠道6") +public class Channel6Cmp extends NodeComponent { + @Override + public void process() throws Exception { + BatchMessageResultContext context = this.getFirstContextBean(); + context.setFinalResultChannel("channel6"); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel6QueryCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel6QueryCmp.java new file mode 100644 index 000000000..52c57fdf3 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/Channel6QueryCmp.java @@ -0,0 +1,17 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.benchmark.vo.QueryVO; +import com.yomahub.liteflow.core.NodeComponent; + +@LiteflowComponent(id = "channel6Query", name = "获取渠道6剩余量") +public class Channel6QueryCmp extends NodeComponent { + @Override + public void process() throws Exception { + + //mock下渠道6有3w条剩余量 + BatchMessageResultContext context = this.getFirstContextBean(); + context.addQueryVO(new QueryVO("channel6", 30000)); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/ChannelSelectorCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/ChannelSelectorCmp.java new file mode 100644 index 000000000..9e8bee369 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/ChannelSelectorCmp.java @@ -0,0 +1,24 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.benchmark.context.BatchMessageResultContext; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.benchmark.vo.QueryVO; +import com.yomahub.liteflow.core.NodeComponent; + +import java.util.List; + +@LiteflowComponent(id = "channelSelector", name = "渠道余量最大选择器") +public class ChannelSelectorCmp extends NodeComponent { + @Override + public void process() throws Exception { + BatchMessageResultContext context = this.getFirstContextBean(); + + List queryList = context.getQueryResultList(); + + //选择渠道余量最大的 + QueryVO vo = queryList.stream().min((o1, o2) -> o2.getAvailCount() - o1.getAvailCount()).orElse(null); + + assert vo != null; + context.setFinalResultChannel(vo.getChannel()); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/IF1SwitchCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/IF1SwitchCmp.java new file mode 100644 index 000000000..8b505aad5 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/IF1SwitchCmp.java @@ -0,0 +1,15 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeSwitchComponent; + +import java.util.Random; + +@LiteflowComponent(id = "if_1", name = "业务判断1") +public class IF1SwitchCmp extends NodeSwitchComponent { + @Override + public String processSwitch() throws Exception { + //这里写死跳到并行获取剩余量那条分支,你可以改成其他分支测试 + return "branch1"; + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/IF2SwitchCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/IF2SwitchCmp.java new file mode 100644 index 000000000..d026238a8 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/IF2SwitchCmp.java @@ -0,0 +1,15 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeSwitchComponent; + +import java.util.Random; + +@LiteflowComponent(id = "if_2", name = "业务判断2") +public class IF2SwitchCmp extends NodeSwitchComponent { + @Override + public String processSwitch() throws Exception { + //这里写死,你可以改成其他分支 + return "s3"; + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/IF3SwitchCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/IF3SwitchCmp.java new file mode 100644 index 000000000..b2a27da52 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/IF3SwitchCmp.java @@ -0,0 +1,16 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeSwitchComponent; + +import java.util.Random; + +@LiteflowComponent(id = "if_3", name = "业务判断3") +public class IF3SwitchCmp extends NodeSwitchComponent { + @Override + public String processSwitch() throws Exception { + + //这里写死,你可以改成其他 + return "channel5"; + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/PackageDataCmp.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/PackageDataCmp.java new file mode 100644 index 000000000..e1648a420 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/cmp/PackageDataCmp.java @@ -0,0 +1,13 @@ +package com.yomahub.liteflow.benchmark.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.core.NodeComponent; + +import java.util.Random; + +@LiteflowComponent(id = "packageData", name = "组装数据") +public class PackageDataCmp extends NodeComponent { + @Override + public void process() throws Exception { + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/context/BatchMessageResultContext.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/context/BatchMessageResultContext.java new file mode 100644 index 000000000..b53142a6b --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/context/BatchMessageResultContext.java @@ -0,0 +1,37 @@ +package com.yomahub.liteflow.benchmark.context; + + +import com.yomahub.liteflow.benchmark.vo.QueryVO; + +import java.util.ArrayList; +import java.util.List; + +public class BatchMessageResultContext { + + private List queryResultList; + + private String finalResultChannel; + + public List getQueryResultList() { + return queryResultList; + } + + public void setQueryResultList(List queryResultList) { + this.queryResultList = queryResultList; + } + + public String getFinalResultChannel() { + return finalResultChannel; + } + + public void setFinalResultChannel(String finalResultChannel) { + this.finalResultChannel = finalResultChannel; + } + + public void addQueryVO(QueryVO queryVO){ + if (queryResultList == null){ + queryResultList = new ArrayList<>(); + } + queryResultList.add(queryVO); + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/vo/QueryVO.java b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/vo/QueryVO.java new file mode 100644 index 000000000..53096cba9 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/java/com/yomahub/liteflow/benchmark/vo/QueryVO.java @@ -0,0 +1,31 @@ +package com.yomahub.liteflow.benchmark.vo; + +public class QueryVO { + + //渠道名称 + private String channel; + + //剩余短信包数量 + private int availCount; + + public QueryVO(String channel, int availCount) { + this.channel = channel; + this.availCount = availCount; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public int getAvailCount() { + return availCount; + } + + public void setAvailCount(int availCount) { + this.availCount = availCount; + } +} diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/resources/application.properties b/liteflow-benchmark/liteflow-benchmark-compile/src/test/resources/application.properties new file mode 100644 index 000000000..c1d4f7007 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/resources/application.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=flow.xml +liteflow.fast-load=true \ No newline at end of file diff --git a/liteflow-benchmark/liteflow-benchmark-compile/src/test/resources/flow.xml b/liteflow-benchmark/liteflow-benchmark-compile/src/test/resources/flow.xml new file mode 100644 index 000000000..c8564c4b7 --- /dev/null +++ b/liteflow-benchmark/liteflow-benchmark-compile/src/test/resources/flow.xml @@ -0,0 +1,8 @@ + + + + selectBestChannel = THEN(WHEN(channel1Query, channel2Query, channel3Query,channel4Query, channel5Query, channel6Query),channelSelector).id("branch1"); + selectBizChannel = THEN(biz1,SWITCH(if_2).to(channel3,channel4,SWITCH(if_3).to(channel5, channel6).id("s3")).id("s2")).id("branch2"); + THEN(packageData,SWITCH(if_1).to(channel1,channel2,selectBestChannel,selectBizChannel),batchSender); + + \ No newline at end of file diff --git a/liteflow-benchmark/liteflow-benchmark-script-groovy/pom.xml b/liteflow-benchmark/liteflow-benchmark-script-groovy/pom.xml index b2e0ea09a..441950941 100644 --- a/liteflow-benchmark/liteflow-benchmark-script-groovy/pom.xml +++ b/liteflow-benchmark/liteflow-benchmark-script-groovy/pom.xml @@ -16,7 +16,7 @@ com.yomahub liteflow-script-groovy - ${revision} + ${liteflow-version} test diff --git a/liteflow-benchmark/liteflow-benchmark-script-java/pom.xml b/liteflow-benchmark/liteflow-benchmark-script-java/pom.xml index 139f0c987..8b4d9c8d6 100644 --- a/liteflow-benchmark/liteflow-benchmark-script-java/pom.xml +++ b/liteflow-benchmark/liteflow-benchmark-script-java/pom.xml @@ -16,7 +16,7 @@ com.yomahub liteflow-script-java - ${revision} + ${liteflow-version} test diff --git a/liteflow-benchmark/liteflow-benchmark-script-javax-pro/pom.xml b/liteflow-benchmark/liteflow-benchmark-script-javax-pro/pom.xml index a2ef8108b..63f7e85ab 100644 --- a/liteflow-benchmark/liteflow-benchmark-script-javax-pro/pom.xml +++ b/liteflow-benchmark/liteflow-benchmark-script-javax-pro/pom.xml @@ -16,7 +16,7 @@ com.yomahub liteflow-script-javax-pro - ${revision} + ${liteflow-version} test diff --git a/liteflow-benchmark/liteflow-benchmark-script-javax/pom.xml b/liteflow-benchmark/liteflow-benchmark-script-javax/pom.xml index 30405bb4c..5e3cc15f5 100644 --- a/liteflow-benchmark/liteflow-benchmark-script-javax/pom.xml +++ b/liteflow-benchmark/liteflow-benchmark-script-javax/pom.xml @@ -16,7 +16,7 @@ com.yomahub liteflow-script-javax - ${revision} + ${liteflow-version} test diff --git a/liteflow-benchmark/pom.xml b/liteflow-benchmark/pom.xml index 4a57df63d..6cfbb2133 100644 --- a/liteflow-benchmark/pom.xml +++ b/liteflow-benchmark/pom.xml @@ -16,13 +16,14 @@ 1.37 + ${revision} com.yomahub liteflow-spring-boot-starter - ${revision} + ${liteflow-version} org.springframework.boot @@ -48,5 +49,6 @@ liteflow-benchmark-script-groovy liteflow-benchmark-common liteflow-benchmark-common-example + liteflow-benchmark-compile \ No newline at end of file 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..f495a4840 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,20 @@ package com.yomahub.liteflow.builder.el; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.ObjectUtil; 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.yomahub.liteflow.builder.el.operator.*; +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.common.ChainConstant; import com.yomahub.liteflow.common.entity.ValidationResp; import com.yomahub.liteflow.enums.ParseModeEnum; @@ -34,9 +36,9 @@ import com.yomahub.liteflow.util.ElRegexUtil; import com.yomahub.liteflow.util.QlExpressUtils; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.Set; /** @@ -70,7 +72,7 @@ public class LiteFlowChainELBuilder { /** * EL解析引擎 */ - private final static ExpressRunner EXPRESS_RUNNER = QlExpressUtils.getInstance(); + private final static Express4Runner EXPRESS_RUNNER = QlExpressUtils.getELExpressRunner(); public static LiteFlowChainELBuilder createChain() { return new LiteFlowChainELBuilder(); @@ -131,15 +133,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 +170,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()) { @@ -178,18 +182,17 @@ public class LiteFlowChainELBuilder { return this; } catch (QLException e) { // EL 底层会包装异常,这里是曲线处理 - if (ObjectUtil.isNotNull(e.getCause()) && Objects.equals(e.getCause().getMessage(), DataNotFoundException.MSG)) { + if (ObjectUtil.isNotNull(e.getCause())) { // 构建错误信息 String msg = buildDataNotFoundExceptionMsg(elStr); throw new ELParseException(msg); - }else if (ObjectUtil.isNotNull(e.getCause())){ - throw new ELParseException(e.getCause().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,19 +286,15 @@ public class LiteFlowChainELBuilder { 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; - } - - String[] outAttrNames = parseResult.getOutAttrNames(); - if (ArrayUtil.isEmpty(outAttrNames)) { + // 使用 QLExpress4 的 getOutVarNames 方法获取脚本中使用的所有外部变量 + Set outVarNames = EXPRESS_RUNNER.getOutVarNames(elStr); + if (CollUtil.isEmpty(outVarNames)) { return msg; } List chainIds = CollUtil.map(FlowBus.getChainMap().values(), Chain::getChainId, true); List nodeIds = CollUtil.map(FlowBus.getNodeMap().values(), Node::getId, true); - for (String attrName : outAttrNames) { + for (String attrName : outVarNames) { 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: ", @@ -319,7 +318,7 @@ public class LiteFlowChainELBuilder { // 还有一种特殊情况,就是 EL 表达式中的节点使用 node("a") int nodeIndex = sourceEl.indexOf(String.format("node(\"%s\")", attrName)); if (nodeIndex != -1) { - // 需要加上 "EL: " 的长度 4,再加上 “node("” 长度 6,再加上 "^" 的长度 1,indexOf 从 0 + // 需要加上 "EL: " 的长度 4,再加上 "node("" 长度 6,再加上 "^" 的长度 1,indexOf 从 0 // 开始,所以还需要加 1 return msg + sourceEl + "\n" + StrUtil.fill("^", CharUtil.SPACE, commaLeftIndex + 12, true); } @@ -342,9 +341,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 @@ -360,9 +358,8 @@ public class LiteFlowChainELBuilder { // 只有当PARSE_ONE_ON_FIRST_EXEC时才会执行这个方法 // 那么会有一种级联的情况:这个EL中含有其他的chain,如果这时候不先解析其他chain,就到导致诸如循环场景无法设置index或者obj的情况 // 所以这里要判断表达式里有没有其他的chain,如果有,进行先行解析 - - String[] itemArray = EXPRESS_RUNNER.getOutVarNames(chain.getEl()); - Arrays.stream(itemArray).forEach(item -> { + Set itemSet = EXPRESS_RUNNER.getOutVarNames(chain.getEl()); + itemSet.stream().forEach(item -> { if (FlowBus.containChain(item) && !chain.getChainId().equals(item)) { Chain itemChain = FlowBus.getChain(item); if (!itemChain.isCompiled()){ @@ -374,10 +371,11 @@ 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.builder().cache(true).build()); + 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 +398,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 @@ -431,8 +431,8 @@ public class LiteFlowChainELBuilder { // 解析el成为一个Condition // 为什么这里只是一个Condition,而不是一个List呢 // 这里无论多复杂的,外面必定有一个最外层的Condition,所以这里只有一个,内部可以嵌套很多层,这点和以前的不太一样 - - return (T) EXPRESS_RUNNER.execute(elStr, context, errorList, true, true); + QLResult expressResult = EXPRESS_RUNNER.execute(elStr, context, QLOptions.builder().cache(true).build()); + 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..1ba6e11b9 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 = QlExpressUtils.getContextSearchExpressRunner(); 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.builder().cache(true).build()); + 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.builder().cache(true).build()); + 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.builder().cache(true).build()); 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.builder().cache(true).build()); }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..8828d99c2 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,9 @@ package com.yomahub.liteflow.util; -import com.ql.util.express.ExpressRunner; +import com.alibaba.qlexpress4.Express4Runner; +import com.alibaba.qlexpress4.InitOptions; +import com.alibaba.qlexpress4.aparser.InterpolationMode; +import com.alibaba.qlexpress4.security.QLSecurityStrategy; import com.yomahub.liteflow.builder.el.operator.*; import com.yomahub.liteflow.common.ChainConstant; @@ -14,58 +17,72 @@ public class QlExpressUtils { /** * EL解析引擎 + * InterpolationMode.DISABLE意思是不对插值表达式进行处理 */ - private final static ExpressRunner EXPRESS_RUNNER = new ExpressRunner(); + private final static Express4Runner EXPRESS_RUNNER = new Express4Runner(InitOptions.builder().interpolationMode(InterpolationMode.DISABLE).build()); + + /** + * 上下文搜索解析引擎 + * QLSecurityStrategy.open()意思是将安全策略设置为开放 + */ + private final static Express4Runner CONTEXT_SEARCH_EXPRESS_RUNNER = new Express4Runner(InitOptions.builder().securityStrategy(QLSecurityStrategy.open()).build()); 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 getELExpressRunner() { return EXPRESS_RUNNER; } + /** + * 获取上下文搜索的QLExpress实例 + */ + public static Express4Runner getContextSearchExpressRunner() { + return CONTEXT_SEARCH_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-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/ScriptRead.java b/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/ScriptRead.java index 7d9d474d2..d88051f6b 100644 --- a/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/ScriptRead.java +++ b/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/read/impl/ScriptRead.java @@ -8,7 +8,6 @@ import com.yomahub.liteflow.parser.sql.read.AbstractSqlRead; import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO; import com.yomahub.liteflow.parser.sql.util.LiteFlowJdbcUtil; import com.yomahub.liteflow.parser.sql.vo.SQLParserVO; -import org.apache.commons.lang.StringUtils; import java.sql.Connection; import java.sql.ResultSet; @@ -56,7 +55,7 @@ public class ScriptRead extends AbstractSqlRead { @Override public String buildQuerySql() { - if (StringUtils.isNotBlank(super.config.getScriptCustomSql())) { + if (StrUtil.isNotBlank(super.config.getScriptCustomSql())) { return super.config.getScriptCustomSql(); } @@ -72,7 +71,7 @@ public class ScriptRead extends AbstractSqlRead { @Override public String buildQuerySql(String scriptNodeId) { - if (StringUtils.isNotBlank(super.config.getScriptCustomSql())) { + if (StrUtil.isNotBlank(super.config.getScriptCustomSql())) { return super.config.getScriptCustomSql(); } diff --git a/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/util/JDBCHelper.java b/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/util/JDBCHelper.java index 0594cf076..3b514d002 100644 --- a/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/util/JDBCHelper.java +++ b/liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/util/JDBCHelper.java @@ -16,7 +16,6 @@ import com.yomahub.liteflow.parser.sql.read.SqlReadFactory; import com.yomahub.liteflow.parser.sql.read.vo.ChainVO; import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO; import com.yomahub.liteflow.parser.sql.vo.SQLParserVO; -import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -116,7 +115,7 @@ public class JDBCHelper { String language = scriptVO.getLanguage(); String elData = scriptVO.getScript(); - if (StringUtils.isNotBlank(scriptVO.getLanguage())) { + if (StrUtil.isNotBlank(scriptVO.getLanguage())) { scriptList.add(StrUtil.format(NODE_ITEM_WITH_LANGUAGE_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, language, elData)); } else { scriptList.add(StrUtil.format(NODE_ITEM_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, elData)); 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..c0150d87b 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 @@ -1,11 +1,11 @@ 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.alibaba.qlexpress4.security.QLSecurityStrategy; import com.yomahub.liteflow.enums.ScriptTypeEnum; import com.yomahub.liteflow.script.ScriptExecuteWrap; import com.yomahub.liteflow.script.ScriptExecutor; @@ -13,10 +13,8 @@ import com.yomahub.liteflow.script.exception.ScriptLoadException; import com.yomahub.liteflow.util.CopyOnWriteHashMap; import org.slf4j.Logger; 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 +28,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.builder().securityStrategy(QLSecurityStrategy.open()).build()); //如果有生命周期则执行相应生命周期实现 super.lifeCycle(expressRunner); return this; @@ -45,7 +43,8 @@ public class QLExpressScriptExecutor extends ScriptExecutor { @Override public void load(String nodeId, String script) { try { - compiledScriptMap.put(nodeId, (InstructionSet) compile(script)); + expressRunner.parseToDefinitionWithCache(script); + compiledScriptMap.put(nodeId, script); } catch (Exception e) { String errorMsg = StrUtil.format("script loading error for node[{}],error msg:{}", nodeId, e.getMessage()); @@ -65,24 +64,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.builder().cache(true).build()); + return expressResult.getResult(); } catch (Exception e) { - for (String scriptErrorMsg : errorList) { - log.error("\n{}", scriptErrorMsg); - } throw e; } } @@ -90,8 +86,9 @@ public class QLExpressScriptExecutor extends ScriptExecutor { @Override public void cleanCache() { compiledScriptMap.clear(); - expressRunner.clearExpressCache(); - ReflectUtil.setFieldValue(expressRunner, "loader", new ExpressLoader(expressRunner)); + expressRunner.clearCompileCache(); + //如果有生命周期则执行相应生命周期实现 + super.lifeCycle(expressRunner); } @Override @@ -101,7 +98,7 @@ public class QLExpressScriptExecutor extends ScriptExecutor { @Override public Object compile(String script) throws Exception { - return expressRunner.getInstructionSetFromLocalCache(script); + return expressRunner.parseToDefinitionWithCache(script); } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/parent/ParentDeclMultiSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/parent/ParentDeclMultiSpringbootTest.java new file mode 100644 index 000000000..f4b58b558 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/parent/ParentDeclMultiSpringbootTest.java @@ -0,0 +1,38 @@ +package com.yomahub.liteflow.test.parent; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +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.junit.jupiter.SpringExtension; + +import javax.annotation.Resource; + +/** + * springboot环境最普通的例子测试 + * + * @author Bryan.Zhang + * @since 2.6.4 + */ +@ExtendWith(SpringExtension.class) +@TestPropertySource(value = "classpath:/parent/application.properties") +@SpringBootTest(classes = ParentDeclMultiSpringbootTest.class) +@EnableAutoConfiguration +@ComponentScan({ "com.yomahub.liteflow.test.parent.cmp" }) +public class ParentDeclMultiSpringbootTest extends BaseTest { + + @Resource + private FlowExecutor flowExecutor; + + @Test + public void testP1() throws Exception { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assertions.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/parent/cmp/CmpConfig.java b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/parent/cmp/CmpConfig.java new file mode 100644 index 000000000..ef686a6b5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/parent/cmp/CmpConfig.java @@ -0,0 +1,31 @@ +package com.yomahub.liteflow.test.parent.cmp; + +import com.yomahub.liteflow.annotation.LiteflowComponent; +import com.yomahub.liteflow.annotation.LiteflowMethod; +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.enums.LiteFlowMethodEnum; +import com.yomahub.liteflow.test.base.cmp.TestDomain; + +import javax.annotation.Resource; + +@LiteflowComponent +public class CmpConfig extends ParentClass{ + + @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "a") + public void processA(NodeComponent bindCmp) { + this.setName("jack"); + System.out.println(this.sayHi()); + } + + @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "b") + public void processB(NodeComponent bindCmp) { + this.setName("tom"); + System.out.println(this.sayHi()); + } + + @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "c") + public void processC(NodeComponent bindCmp) { + this.setName("jerry"); + System.out.println(this.sayHi()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/parent/cmp/ParentClass.java b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/parent/cmp/ParentClass.java new file mode 100644 index 000000000..322689371 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/parent/cmp/ParentClass.java @@ -0,0 +1,14 @@ +package com.yomahub.liteflow.test.parent.cmp; + +public class ParentClass { + + private String name; + + public void setName(String name) { + this.name = name; + } + + public String sayHi() { + return "hello " + name; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/parent/application.properties b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/parent/application.properties new file mode 100644 index 000000000..03350a714 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/parent/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=parent/flow.el.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/parent/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/parent/flow.el.xml new file mode 100644 index 000000000..98c3cbae6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/parent/flow.el.xml @@ -0,0 +1,7 @@ + + + + THEN(a, b, c); + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java index 4e600df2a..e2803f0f1 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java @@ -97,8 +97,17 @@ public class BaseELSpringbootTest extends BaseTest { // 应返回 chain2 Assertions.assertEquals("chain2", response.getChainId()); - LiteflowResponse response1 = flowExecutor.execute2RespWithEL("t1=THEN(c, WHEN(j,k));w1 = WHEN(q, THEN(p, r)).id('w01');t2 = THEN(h, i);\n" + - "THEN(a,b,WHEN(t1, d, t2 ),SWITCH(x).to(m, n, w1),z);"); + LiteflowResponse response1 = flowExecutor.execute2RespWithEL("t1 = THEN(c, WHEN(j,k));\n" + + " w1 = WHEN(q, THEN(p, r)).id(\"w01\");\n" + + " t2 = THEN(h, i);\n" + + "\n" + + " THEN(\n" + + " a,b,\n" + + " WHEN(t1, d, t2 ),\n" + + " SWITCH(x).to(m, n, w1),\n" + + " z\n" + + " );\n" + + " THEN(a,b,b,a,SWITCH(e).TO(d,b));"); Assertions.assertTrue(response1.isSuccess()); // 应返回 chain5 Assertions.assertEquals("chain5", response1.getChainId()); 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..2e5c582d4 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 @@ -50,5 +50,7 @@ SWITCH(x).to(m, n, w1), z ); + THEN(a,b,b,a,SWITCH(e).TO(d,b)) - \ No newline at end of file + + diff --git a/pom.xml b/pom.xml index 55a54b112..76f8fce6a 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ - 2.15.1 + 2.15.2 UTF-8 UTF-8 8 @@ -58,7 +58,7 @@ 0.10 0.7.3 1.4.4 - 3.3.4 + 4.0.6-SNAPSHOT 3.0.25 22.0.0 1.17.7 @@ -227,7 +227,7 @@ com.alibaba - QLExpress + qlexpress4 ${qlexpress.version}