mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-05-14 12:12:08 +08:00
enhancement #I61D1N 解析增加 enable 逻辑,完成 apollo 改造
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 = "<chain id=\"{}\" enable=\"{}\">{}</chain>";
|
||||
private static final String NODE_ITEM_XML_PATTERN = "<node id=\"{}\" name=\"{}\" type=\"{}\" enable=\"{}\"><![CDATA[{}]]></node>";
|
||||
private static final String NODE_ITEM_WITH_LANGUAGE_XML_PATTERN = "<node id=\"{}\" name=\"{}\" type=\"{}\" language=\"{}\" enable=\"{}\"><![CDATA[{}]]></node>";
|
||||
|
||||
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<Boolean/*启停*/, String/*id*/> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 = "<chain name=\"{}\">{}</chain>";
|
||||
|
||||
private final String NODE_XML_PATTERN = "<nodes>{}</nodes>";
|
||||
|
||||
private final String NODE_ITEM_XML_PATTERN = "<node id=\"{}\" name=\"{}\" type=\"{}\"><![CDATA[{}]]></node>";
|
||||
|
||||
private final String XML_PATTERN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow>{}{}</flow>";
|
||||
|
||||
private final ApolloParserConfigVO apolloParserConfigVO;
|
||||
@@ -81,7 +78,7 @@ public class ApolloParseHelper {
|
||||
// 1. handle chain
|
||||
Set<String> propertyNames = chainConfig.getPropertyNames();
|
||||
List<String> 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<String> 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<Boolean/*启停*/, String/*id*/> 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<String> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String> chainNameList = Sets.newHashSet("chain1");
|
||||
Set<String> 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<String> chainNameList = Sets.newHashSet("chain1", "chain2:false");
|
||||
Set<String> 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"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user