From 443b1b51bcd8437eddd9a68bc3849a0d5c403e08 Mon Sep 17 00:00:00 2001 From: gaibu <1016771049@qq.com> Date: Sun, 14 Jan 2024 22:56:03 +0800 Subject: [PATCH] =?UTF-8?q?enhancement=20#I61D1N=20=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20enable=20=E9=80=BB=E8=BE=91,=E5=AE=8C?= =?UTF-8?q?=E6=88=90=20apollo=20=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../parser/helper/NodeConvertHelper.java | 24 ++++ .../liteflow/util/RuleParsePluginUtil.java | 108 +++++++++++++++++ .../parser/apollo/util/ApolloParseHelper.java | 109 +++++------------- .../apollo/ApolloWithXmlELSpringbootTest.java | 64 +++++----- 4 files changed, 199 insertions(+), 106 deletions(-) create mode 100644 liteflow-core/src/main/java/com/yomahub/liteflow/util/RuleParsePluginUtil.java diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/NodeConvertHelper.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/NodeConvertHelper.java index b4309eaa9..7b5d9105b 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/NodeConvertHelper.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/NodeConvertHelper.java @@ -59,6 +59,10 @@ public class NodeConvertHelper { nodeSimpleVO.setLanguage(matchItemList.get(3)); } + if (matchItemList.size() > 4) { + nodeSimpleVO.setEnable(Boolean.TRUE.toString().equalsIgnoreCase(matchItemList.get(4))); + } + return nodeSimpleVO; } @@ -73,6 +77,10 @@ public class NodeConvertHelper { private String language; + private Boolean enable = Boolean.TRUE; + + private String script; + public String getNodeId() { return nodeId; } @@ -104,5 +112,21 @@ public class NodeConvertHelper { public void setLanguage(String language) { this.language = language; } + + public Boolean getEnable() { + return enable; + } + + public void setEnable(Boolean enable) { + this.enable = enable; + } + + public String getScript() { + return script; + } + + public void setScript(String script) { + this.script = script; + } } } \ No newline at end of file diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/util/RuleParsePluginUtil.java b/liteflow-core/src/main/java/com/yomahub/liteflow/util/RuleParsePluginUtil.java new file mode 100644 index 000000000..96f661163 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/util/RuleParsePluginUtil.java @@ -0,0 +1,108 @@ +package com.yomahub.liteflow.util; + +import cn.hutool.core.lang.Pair; +import cn.hutool.core.text.StrPool; +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.parser.helper.NodeConvertHelper; + +/** + * 插件通用工具类 + * + * @author gaibu + */ +public class RuleParsePluginUtil { + + private static final String CHAIN_XML_PATTERN = "{}"; + private static final String NODE_ITEM_XML_PATTERN = ""; + private static final String NODE_ITEM_WITH_LANGUAGE_XML_PATTERN = ""; + + public static ChainDto parseChainKey(String chainKey) { + String[] chainProp = chainKey.split(StrPool.COLON); + if (chainProp.length == 2) { + return new ChainDto(chainProp[0], chainProp[1]); + } + return new ChainDto(chainKey); + } + + public static String toScriptXml(NodeConvertHelper.NodeSimpleVO simpleVO) { + if (StrUtil.isNotBlank(simpleVO.getLanguage())) { + return StrUtil.format(NODE_ITEM_WITH_LANGUAGE_XML_PATTERN, + simpleVO.getNodeId(), + simpleVO.getName(), + simpleVO.getType(), + simpleVO.getLanguage(), + simpleVO.getEnable(), + simpleVO.getScript() + ); + } else { + return StrUtil.format(NODE_ITEM_XML_PATTERN, + simpleVO.getNodeId(), + simpleVO.getName(), + simpleVO.getType(), + simpleVO.getEnable(), + simpleVO.getScript() + ); + } + } + + public static Pair parseIdKey(String idKey) { + String[] idProp = idKey.split(StrPool.COLON); + if (idProp.length == 2) { + String id = idProp[0]; + String enableStr = idProp[1]; + return new Pair<>(Boolean.TRUE.toString().equalsIgnoreCase(enableStr), id); + } + return new Pair<>(Boolean.TRUE, idKey); + } + + public static class ChainDto { + /** + * chain id + */ + private String id; + + /** + * chain 启用状态,默认启用 + */ + private String enable = Boolean.TRUE.toString(); + + public boolean isDisable() { + return !isEnable(); + } + + public boolean isEnable() { + return Boolean.TRUE.toString().equalsIgnoreCase(enable); + } + + public ChainDto(String chainId) { + ChainDto chainDto = new ChainDto(chainId, null); + this.enable = chainDto.getEnable(); + this.id = chainDto.getId(); + } + + public ChainDto(String chainId, String enable) { + this.id = chainId; + if (StrUtil.isBlank(enable)) { + this.enable = Boolean.TRUE.toString(); + return; + } + if (Boolean.TRUE.toString().equalsIgnoreCase(enable)) { + this.enable = Boolean.TRUE.toString(); + return; + } + this.enable = Boolean.FALSE.toString(); + } + + public String getId() { + return id; + } + + public String getEnable() { + return enable; + } + + public String toElXml(String elContent) { + return StrUtil.format(CHAIN_XML_PATTERN, id, enable, elContent); + } + } +} diff --git a/liteflow-rule-plugin/liteflow-rule-apollo/src/main/java/com/yomahub/liteflow/parser/apollo/util/ApolloParseHelper.java b/liteflow-rule-plugin/liteflow-rule-apollo/src/main/java/com/yomahub/liteflow/parser/apollo/util/ApolloParseHelper.java index cfb981469..197a0dc1a 100644 --- a/liteflow-rule-plugin/liteflow-rule-apollo/src/main/java/com/yomahub/liteflow/parser/apollo/util/ApolloParseHelper.java +++ b/liteflow-rule-plugin/liteflow-rule-apollo/src/main/java/com/yomahub/liteflow/parser/apollo/util/ApolloParseHelper.java @@ -2,8 +2,8 @@ package com.yomahub.liteflow.parser.apollo.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.lang.Pair; import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.ConfigService; @@ -17,6 +17,7 @@ import com.yomahub.liteflow.parser.apollo.exception.ApolloException; import com.yomahub.liteflow.parser.apollo.vo.ApolloParserConfigVO; import com.yomahub.liteflow.parser.helper.NodeConvertHelper; import com.yomahub.liteflow.spi.holder.ContextAwareHolder; +import com.yomahub.liteflow.util.RuleParsePluginUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,12 +36,8 @@ public class ApolloParseHelper { private static final Logger LOG = LoggerFactory.getLogger(ApolloParseHelper.class); - private final String CHAIN_XML_PATTERN = "{}"; - private final String NODE_XML_PATTERN = "{}"; - private final String NODE_ITEM_XML_PATTERN = ""; - private final String XML_PATTERN = "{}{}"; private final ApolloParserConfigVO apolloParserConfigVO; @@ -81,7 +78,7 @@ public class ApolloParseHelper { // 1. handle chain Set propertyNames = chainConfig.getPropertyNames(); List chainItemContentList = propertyNames.stream() - .map(item -> StrUtil.format(CHAIN_XML_PATTERN, item, chainConfig.getProperty(item, StrUtil.EMPTY))) + .map(item -> RuleParsePluginUtil.parseChainKey(item).toElXml(chainConfig.getProperty(item, StrUtil.EMPTY))) .collect(Collectors.toList()); // merge all chain content String chainAllContent = CollUtil.join(chainItemContentList, StrUtil.EMPTY); @@ -95,8 +92,7 @@ public class ApolloParseHelper { List scriptItemContentList = scriptNamespaces.stream() .map(item -> convert(item, scriptConfig.getProperty(item, StrUtil.EMPTY))) .filter(Objects::nonNull) - .map(item -> StrUtil.format(NODE_ITEM_XML_PATTERN, item.getNodeId(), item.getName(), item.getType(), - item.getScript())) + .map(RuleParsePluginUtil::toScriptXml) .collect(Collectors.toList()); scriptAllContent = StrUtil.format(NODE_XML_PATTERN, @@ -118,16 +114,25 @@ public class ApolloParseHelper { ConfigChange configChange = changeEvent.getChange(changeKey); String newValue = configChange.getNewValue(); PropertyChangeType changeType = configChange.getChangeType(); + Pair pair = RuleParsePluginUtil.parseIdKey(changeKey); + String id = pair.getValue(); switch (changeType) { case ADDED: case MODIFIED: LOG.info("starting reload flow config... {} key={} value={},", changeType.name(), changeKey, newValue); - LiteFlowChainELBuilder.createChain().setChainId(changeKey).setEL(newValue).build(); + // 如果是启用,就正常更新 + if (pair.getKey()) { + LiteFlowChainELBuilder.createChain().setChainId(id).setEL(newValue).build(); + } + // 如果是禁用,就删除 + else { + FlowBus.removeChain(id); + } break; case DELETED: LOG.info("starting reload flow config... delete key={}", changeKey); - FlowBus.removeChain(changeKey); + FlowBus.removeChain(id); break; default: } @@ -142,7 +147,7 @@ public class ApolloParseHelper { if (DELETED.equals(changeType)) { newValue = null; } - NodeSimpleVO nodeSimpleVO = convert(changeKey, newValue); + NodeConvertHelper.NodeSimpleVO nodeSimpleVO = convert(changeKey, newValue); if (Objects.isNull(nodeSimpleVO)) { // key不符合规范的时候,直接忽略 LOG.error("key={} is not a valid node config, ignore it", changeKey); @@ -154,12 +159,19 @@ public class ApolloParseHelper { LOG.info("starting reload flow config... {} key={} value={},", changeType.name(), changeKey, newValue); - LiteFlowNodeBuilder.createScriptNode() - .setId(nodeSimpleVO.getNodeId()) - .setType(NodeTypeEnum.getEnumByCode(nodeSimpleVO.getType())) - .setName(nodeSimpleVO.getName()) - .setScript(nodeSimpleVO.getScript()) - .build(); + // 启用就正常更新 + if (nodeSimpleVO.getEnable()) { + LiteFlowNodeBuilder.createScriptNode() + .setId(nodeSimpleVO.getNodeId()) + .setType(NodeTypeEnum.getEnumByCode(nodeSimpleVO.getType())) + .setName(nodeSimpleVO.getName()) + .setScript(nodeSimpleVO.getScript()) + .build(); + } + // 禁用就删除 + else { + FlowBus.getNodeMap().remove(nodeSimpleVO.getNodeId()); + } break; case DELETED: LOG.info("starting reload flow config... delete key={}", changeKey); @@ -171,72 +183,13 @@ public class ApolloParseHelper { } } - private NodeSimpleVO convert(String key, String value) { - // 不需要去理解这串正则,就是一个匹配冒号的 - // 一定得是a:b,或是a:b:c...这种完整类型的字符串的 - List matchItemList = ReUtil.findAllGroup0("(?<=[^:]:)[^:]+|[^:]+(?=:[^:])", key); - if (CollUtil.isEmpty(matchItemList)) { - return null; - } - - NodeSimpleVO nodeSimpleVO = new NodeSimpleVO(); - if (matchItemList.size() > 1) { - nodeSimpleVO.setNodeId(matchItemList.get(0)); - nodeSimpleVO.setType(matchItemList.get(1)); - } - - if (matchItemList.size() > 2) { - nodeSimpleVO.setName(matchItemList.get(2)); - } - + private NodeConvertHelper.NodeSimpleVO convert(String key, String value) { + NodeConvertHelper.NodeSimpleVO nodeSimpleVO = NodeConvertHelper.convert(key); // set script nodeSimpleVO.setScript(value); return nodeSimpleVO; } - private static class NodeSimpleVO { - - private String nodeId; - - private String type; - - private String name = StrUtil.EMPTY; - - private String script; - - public String getNodeId() { - return nodeId; - } - - public void setNodeId(String nodeId) { - this.nodeId = nodeId; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getScript() { - return script; - } - - public void setScript(String script) { - this.script = script; - } - - } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-apollo-springboot/src/test/java/com/yomahub/liteflow/test/apollo/ApolloWithXmlELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-apollo-springboot/src/test/java/com/yomahub/liteflow/test/apollo/ApolloWithXmlELSpringbootTest.java index d41153647..886f922f7 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-apollo-springboot/src/test/java/com/yomahub/liteflow/test/apollo/ApolloWithXmlELSpringbootTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-apollo-springboot/src/test/java/com/yomahub/liteflow/test/apollo/ApolloWithXmlELSpringbootTest.java @@ -3,10 +3,10 @@ package com.yomahub.liteflow.test.apollo; import com.ctrip.framework.apollo.Config; import com.google.common.collect.Sets; import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.exception.ChainNotFoundException; import com.yomahub.liteflow.flow.FlowBus; import com.yomahub.liteflow.flow.LiteflowResponse; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -16,13 +16,12 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.ComponentScan; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.event.annotation.AfterTestClass; -import org.springframework.test.context.event.annotation.BeforeTestClass; import org.springframework.test.context.junit.jupiter.SpringExtension; + import javax.annotation.Resource; import java.util.Set; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.when; /** * @Description: @@ -33,35 +32,44 @@ import static org.mockito.Mockito.*; @TestPropertySource(value = "classpath:/apollo/application-xml.properties") @SpringBootTest(classes = ApolloWithXmlELSpringbootTest.class) @EnableAutoConfiguration -@ComponentScan({ "com.yomahub.liteflow.test.apollo.cmp" }) +@ComponentScan({"com.yomahub.liteflow.test.apollo.cmp"}) public class ApolloWithXmlELSpringbootTest { - @MockBean(name = "chainConfig") - private Config chainConfig; + @MockBean(name = "chainConfig") + private Config chainConfig; - @MockBean(name = "scriptConfig") - private Config scriptConfig; + @MockBean(name = "scriptConfig") + private Config scriptConfig; - @Resource - private FlowExecutor flowExecutor; + @Resource + private FlowExecutor flowExecutor; - @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); - } - @Test - public void testApolloWithXml1() { - Set chainNameList = Sets.newHashSet("chain1"); - Set scriptNodeValueList = Sets.newHashSet("s1:script:脚本s1"); - when(chainConfig.getPropertyNames()).thenReturn(chainNameList); - when(scriptConfig.getPropertyNames()).thenReturn(scriptNodeValueList); + @BeforeEach + public void setUp() { + MockitoAnnotations.initMocks(this); + } - String chain1Data = "THEN(a, b, c, s1);"; - String scriptNodeValue = "defaultContext.setData(\"test\",\"hello\");"; - when(chainConfig.getProperty(anyString(), anyString())).thenReturn(chain1Data); - when(scriptConfig.getProperty(anyString(), anyString())).thenReturn(scriptNodeValue); + @Test + public void testApolloWithXml1() { + Set chainNameList = Sets.newHashSet("chain1", "chain2:false"); + Set scriptNodeValueList = Sets.newHashSet("s1:script:脚本s1", "s2:script:脚本s1:groovy:false"); + when(chainConfig.getPropertyNames()).thenReturn(chainNameList); + when(scriptConfig.getPropertyNames()).thenReturn(scriptNodeValueList); - LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); - Assertions.assertEquals("a==>b==>c==>s1[脚本s1]", response.getExecuteStepStrWithoutTime()); - } + when(chainConfig.getProperty("chain1", "")).thenReturn("THEN(a, b, c, s1);"); + when(chainConfig.getProperty("chain2:false", "")).thenReturn("THEN(a, b, c, s1);"); + when(scriptConfig.getProperty("s1:script:脚本s1", "")).thenReturn("defaultContext.setData(\"test\",\"hello\");"); + when(scriptConfig.getProperty("s2:script:脚本s1:groovy:false", "")).thenReturn("defaultContext.setData(\"test\",\"hello\");"); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assertions.assertEquals("a==>b==>c==>s1[脚本s1]", response.getExecuteStepStrWithoutTime()); + + // 测试 chain 停用 + Assertions.assertThrows(ChainNotFoundException.class, () -> { + throw flowExecutor.execute2Resp("chain2", "arg").getCause(); + }); + + // 测试 script 停用 + Assertions.assertTrue(!FlowBus.getNodeMap().containsKey("s2")); + } }