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"));
+ }
}