diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java index afc7b2cc1..08f1c8eaf 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java @@ -4,6 +4,7 @@ import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.yomahub.liteflow.builder.LiteFlowNodeBuilder; import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder; import com.yomahub.liteflow.builder.prop.NodePropBean; @@ -215,6 +216,10 @@ public class ParserHelper { public static void parseChainJson(List flowJsonObjectList, Set chainNameSet, Consumer parseOneChainConsumer) { + //用于存放抽象chain的map + Map abstratChainMap = new HashMap<>(); + //用于存放已经解析过的实现chain + Set implChainSet = new HashSet<>(); // 先在元数据里放上chain // 先放有一个好处,可以在parse的时候先映射到FlowBus的chainMap,然后再去解析 // 这样就不用去像之前的版本那样回归调用 @@ -237,6 +242,10 @@ public class ParserHelper { } FlowBus.addChain(chainName); + + if(innerJsonObject.hasNonNull(ABSTRACT) && innerJsonObject.get(ABSTRACT).asBoolean()) { + abstratChainMap.put(chainName,innerJsonObject); + } } }); // 清空 @@ -246,8 +255,21 @@ public class ParserHelper { // 解析每一个chain Iterator chainIterator = flowJsonNode.get(FLOW).get(CHAIN).elements(); while (chainIterator.hasNext()) { - JsonNode jsonNode = chainIterator.next(); - parseOneChainConsumer.accept(jsonNode); + JsonNode chainNode = chainIterator.next(); + //首先需要对继承自抽象Chain的chain进行字符串替换 + if(chainNode.hasNonNull(EXTENDS)){ + String baseChainId = chainNode.get(EXTENDS).textValue(); + if(abstratChainMap.containsKey(baseChainId)) { + JsonNode baseChain = abstratChainMap.get(baseChainId); + parseImplChain(baseChain,chainNode,abstratChainMap,implChainSet); + }else{ + throw new ChainNotFoundException(String.format("[abstract chain not found] chainName=%s", baseChainId)); + } + } + //如果一个chain不为抽象chain,则进行解析 + if(chainNode.get(ABSTRACT) == null || !chainNode.get(ABSTRACT).asBoolean()){ + parseOneChainConsumer.accept(chainNode); + } } } } @@ -289,7 +311,38 @@ public class ParserHelper { } /** - * 解析一个继承自baseChain的implChain + * 解析一个继承自baseChain的implChain,xml格式 + * @param baseChain 父Chain + * @param implChain 实现Chain + * @param abstractChainMap 所有的抽象Chain + * @param implChainSet 已经解析过的实现Chain + */ + private static void parseImplChain(JsonNode baseChain,JsonNode implChain,Map abstractChainMap,Set implChainSet) { + //如果已经解析过了,就不再解析 + if(implChainSet.contains(implChain)) return; + //如果baseChainId也是继承自其他的chain,需要递归解析 + if(baseChain.get(EXTENDS)!=null){ + String pBaseChainId = baseChain.get(EXTENDS).textValue(); + if(abstractChainMap.containsKey(pBaseChainId)) { + JsonNode pBaseChain = abstractChainMap.get(pBaseChainId); + parseImplChain(pBaseChain, baseChain, abstractChainMap, implChainSet); + }else{ + throw new ChainNotFoundException(String.format("[abstract chain not found] chainName=%s", pBaseChainId)); + } + } + //否则根据baseChainId解析implChainId + String implChainEl = implChain.get(VALUE).textValue(); + String baseChainEl = baseChain.get(VALUE).textValue(); + //替换baseChainId中的implChainId + // 使用正则表达式匹配占位符并替换 + String parsedEl = RegexUtil.replaceAbstractChain(baseChainEl,implChainEl); + ObjectNode objectNode = (ObjectNode) implChain; + objectNode.put(VALUE,parsedEl); + implChainSet.add(implChain); + } + + /** + * 解析一个继承自baseChain的implChain,json格式 * @param baseChain 父Chain * @param implChain 实现Chain * @param abstractChainMap 所有的抽象Chain diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/abstractChain/AbstractChainJsonELSpringBootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/abstractChain/AbstractChainJsonELSpringBootTest.java new file mode 100644 index 000000000..47856b191 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/abstractChain/AbstractChainJsonELSpringBootTest.java @@ -0,0 +1,37 @@ +package com.yomahub.liteflow.test.abstractChain; + +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.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.context.TestPropertySource; + +import javax.annotation.Resource; + +/** + * 测试显示调用子流程(json) 单元测试 + * + * @author justin.xu + */ +@TestPropertySource(value = "classpath:/abstractChain/application-json.properties") +@SpringBootTest(classes = AbstractChainJsonELSpringBootTest.class) +@EnableAutoConfiguration +@ComponentScan({ "com.yomahub.liteflow.test.abstractChain.cmp" }) +public class AbstractChainJsonELSpringBootTest extends BaseTest { + + @Resource + private FlowExecutor flowExecutor; + + // 是否按照流程定义配置执行 + @Test + public void testExplicitSubFlow() { + LiteflowResponse response = flowExecutor.execute2Resp("implA", "it's a request"); + Assertions.assertTrue(response.isSuccess()); + Assertions.assertEquals("a==>b==>c==>d==>f==>j", response.getExecuteStepStrWithoutTime()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/abstractChain/AbstractChainELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/abstractChain/AbstractChainXMLELSpringbootTest.java similarity index 89% rename from liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/abstractChain/AbstractChainELSpringbootTest.java rename to liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/abstractChain/AbstractChainXMLELSpringbootTest.java index 29fc14ca9..9799ea12f 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/abstractChain/AbstractChainELSpringbootTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/abstractChain/AbstractChainXMLELSpringbootTest.java @@ -18,10 +18,10 @@ import javax.annotation.Resource; * @author Bryan.Zhang */ @TestPropertySource(value = "classpath:/abstractChain/application.properties") -@SpringBootTest(classes = AbstractChainELSpringbootTest.class) +@SpringBootTest(classes = AbstractChainXMLELSpringbootTest.class) @EnableAutoConfiguration @ComponentScan({ "com.yomahub.liteflow.test.abstractChain.cmp" }) -public class AbstractChainELSpringbootTest extends BaseTest { +public class AbstractChainXMLELSpringbootTest extends BaseTest { @Resource private FlowExecutor flowExecutor; diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/abstractChain/application-json.properties b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/abstractChain/application-json.properties new file mode 100644 index 000000000..bd27c1b99 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/abstractChain/application-json.properties @@ -0,0 +1 @@ +liteflow.rule-source=abstractChain/flow.el.json \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/abstractChain/flow.el.json b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/abstractChain/flow.el.json new file mode 100644 index 000000000..759672bb7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/abstractChain/flow.el.json @@ -0,0 +1,16 @@ +{ + "flow": { + "chain": [ + { + "name": "base", + "abstract": true, + "value": "THEN(a, b, {0}, {1});" + }, + { + "name": "implA", + "extends": "base", + "value": "{0}=IF(c, d, e);\n {1}=SWITCH(f).to(j,k);" + } + ] + } +} \ No newline at end of file