!219 修复了ApolloParse可能存在的空指针问题和命名规范问题

Merge pull request !219 from 韩华锋/fix_null_problem_230914
This commit is contained in:
铂赛东
2023-09-25 08:18:43 +00:00
committed by Gitee
2 changed files with 177 additions and 170 deletions

View File

@@ -14,20 +14,20 @@ import java.util.function.BooleanSupplier;
*/
public class FlowInitHook {
private static final List<BooleanSupplier> supplierList = new ArrayList<>();
private static final List<BooleanSupplier> SUPPLIER_LIST = new ArrayList<>();
public static void executeHook() {
if (CollUtil.isNotEmpty(supplierList)) {
supplierList.forEach(BooleanSupplier::getAsBoolean);
if (CollUtil.isNotEmpty(SUPPLIER_LIST)) {
SUPPLIER_LIST.forEach(BooleanSupplier::getAsBoolean);
}
}
public static void addHook(BooleanSupplier hookSupplier) {
supplierList.add(hookSupplier);
SUPPLIER_LIST.add(hookSupplier);
}
public static void cleanHook() {
supplierList.clear();
SUPPLIER_LIST.clear();
}
}

View File

@@ -25,215 +25,222 @@ import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static com.ctrip.framework.apollo.enums.PropertyChangeType.DELETED;
/**
* @author zhanghua
* @since 2.9.5
*/
public class ApolloParseHelper {
private static final Logger LOG = LoggerFactory.getLogger(ApolloParseHelper.class);
private static final Logger LOG = LoggerFactory.getLogger(ApolloParseHelper.class);
private final String CHAIN_XML_PATTERN = "<chain name=\"{}\">{}</chain>";
private final String CHAIN_XML_PATTERN = "<chain name=\"{}\">{}</chain>";
private final String NODE_XML_PATTERN = "<nodes>{}</nodes>";
private final String NODE_XML_PATTERN = "<nodes>{}</nodes>";
private final String NODE_ITEM_XML_PATTERN = "<node id=\"{}\" name=\"{}\" type=\"{}\"><![CDATA[{}]]></node>";
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 String XML_PATTERN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow>{}{}</flow>";
private final ApolloParserConfigVO apolloParserConfigVO;
private final ApolloParserConfigVO apolloParserConfigVO;
private Config chainConfig;
private Config chainConfig;
private Config scriptConfig;
private Config scriptConfig;
public ApolloParseHelper(ApolloParserConfigVO apolloParserConfigVO) {
this.apolloParserConfigVO = apolloParserConfigVO;
public ApolloParseHelper(ApolloParserConfigVO apolloParserConfigVO) {
this.apolloParserConfigVO = apolloParserConfigVO;
try {
try {
// 这里本身对于程序运行来说没有什么意义拿到的永远是null
// 其实config对象也没有注入到spring容器中
// 这里这样写的目的是为了单测中的mockito当有@MockBean的时候这里就能拿到了
this.chainConfig = ContextAwareHolder.loadContextAware().getBean("chainConfig");
this.scriptConfig = ContextAwareHolder.loadContextAware().getBean("scriptConfig");
}
catch (Exception ignored) {
}
try {
try {
// 这里本身对于程序运行来说没有什么意义拿到的永远是null
// 其实config对象也没有注入到spring容器中
// 这里这样写的目的是为了单测中的mockito当有@MockBean的时候这里就能拿到了
this.chainConfig = ContextAwareHolder.loadContextAware().getBean("chainConfig");
this.scriptConfig = ContextAwareHolder.loadContextAware().getBean("scriptConfig");
} catch (Exception ignored) {
}
if (ObjectUtil.isNull(chainConfig)) {
chainConfig = ConfigService.getConfig(apolloParserConfigVO.getChainNamespace());
String scriptNamespace;
// scriptConfig is optional
if (StrUtil.isNotBlank(scriptNamespace = apolloParserConfigVO.getScriptNamespace())) {
scriptConfig = ConfigService.getConfig(scriptNamespace);
}
}
}
catch (Exception e) {
throw new ApolloException(e.getMessage());
}
}
if (ObjectUtil.isNull(chainConfig)) {
chainConfig = ConfigService.getConfig(apolloParserConfigVO.getChainNamespace());
String scriptNamespace;
// scriptConfig is optional
if (StrUtil.isNotBlank(scriptNamespace = apolloParserConfigVO.getScriptNamespace())) {
scriptConfig = ConfigService.getConfig(scriptNamespace);
}
}
} catch (Exception e) {
throw new ApolloException(e.getMessage());
}
}
public String getContent() {
public String getContent() {
try {
// 1. handle chain
Set<String> propertyNames = chainConfig.getPropertyNames();
if (CollectionUtil.isEmpty(propertyNames)) {
throw new ApolloException(StrUtil.format("There are no chains in namespace : {}",
apolloParserConfigVO.getChainNamespace()));
}
List<String> chainItemContentList = propertyNames.stream()
.map(item -> StrUtil.format(CHAIN_XML_PATTERN, item, chainConfig.getProperty(item, StrUtil.EMPTY)))
.collect(Collectors.toList());
// merge all chain content
String chainAllContent = CollUtil.join(chainItemContentList, StrUtil.EMPTY);
try {
// 1. handle chain
Set<String> propertyNames = chainConfig.getPropertyNames();
if (CollectionUtil.isEmpty(propertyNames)) {
throw new ApolloException(StrUtil.format("There are no chains in namespace : {}",
apolloParserConfigVO.getChainNamespace()));
}
List<String> chainItemContentList = propertyNames.stream()
.map(item -> StrUtil.format(CHAIN_XML_PATTERN, item, chainConfig.getProperty(item, StrUtil.EMPTY)))
.collect(Collectors.toList());
// merge all chain content
String chainAllContent = CollUtil.join(chainItemContentList, StrUtil.EMPTY);
// 2. handle script if needed
String scriptAllContent = StrUtil.EMPTY;
Set<String> scriptNamespaces;
if (Objects.nonNull(scriptConfig)
&& CollectionUtil.isNotEmpty(scriptNamespaces = scriptConfig.getPropertyNames())) {
// 2. handle script if needed
String scriptAllContent = StrUtil.EMPTY;
Set<String> scriptNamespaces;
if (Objects.nonNull(scriptConfig)
&& CollectionUtil.isNotEmpty(scriptNamespaces = scriptConfig.getPropertyNames())) {
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()))
.collect(Collectors.toList());
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()))
.collect(Collectors.toList());
scriptAllContent = StrUtil.format(NODE_XML_PATTERN,
CollUtil.join(scriptItemContentList, StrUtil.EMPTY));
}
scriptAllContent = StrUtil.format(NODE_XML_PATTERN,
CollUtil.join(scriptItemContentList, StrUtil.EMPTY));
}
return StrUtil.format(XML_PATTERN, scriptAllContent, chainAllContent);
}
catch (Exception e) {
throw new ApolloException(e.getMessage());
}
}
return StrUtil.format(XML_PATTERN, scriptAllContent, chainAllContent);
} catch (Exception e) {
throw new ApolloException(e.getMessage());
}
}
/**
* listen apollo config change
*/
public void listenApollo() {
/**
* listen apollo config change
*/
public void listenApollo() {
// chain
chainConfig.addChangeListener(changeEvent -> changeEvent.changedKeys().forEach(changeKey -> {
ConfigChange configChange = changeEvent.getChange(changeKey);
String newValue = configChange.getNewValue();
PropertyChangeType changeType = configChange.getChangeType();
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();
break;
case DELETED:
LOG.info("starting reload flow config... delete key={}", changeKey);
FlowBus.removeChain(changeKey);
break;
default:
}
}));
// chain
chainConfig.addChangeListener(changeEvent -> changeEvent.changedKeys().forEach(changeKey -> {
ConfigChange configChange = changeEvent.getChange(changeKey);
String newValue = configChange.getNewValue();
PropertyChangeType changeType = configChange.getChangeType();
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();
break;
case DELETED:
LOG.info("starting reload flow config... delete key={}", changeKey);
FlowBus.removeChain(changeKey);
if (StrUtil.isNotBlank(apolloParserConfigVO.getScriptNamespace())) {
scriptConfig.addChangeListener(changeEvent -> changeEvent.changedKeys().forEach(changeKey -> {
ConfigChange configChange = changeEvent.getChange(changeKey);
String newValue = configChange.getNewValue();
}
}));
PropertyChangeType changeType = configChange.getChangeType();
if (DELETED.equals(changeType)) {
newValue = null;
}
NodeSimpleVO nodeSimpleVO = convert(changeKey, newValue);
if (Objects.isNull(nodeSimpleVO)) {
// key不符合规范的时候直接忽略
LOG.error("key={} is not a valid node config, ignore it", changeKey);
return;
}
switch (changeType) {
case ADDED:
case MODIFIED:
LOG.info("starting reload flow config... {} key={} value={},", changeType.name(), changeKey,
newValue);
if (StrUtil.isNotBlank(apolloParserConfigVO.getScriptNamespace())) {
scriptConfig.addChangeListener(changeEvent -> changeEvent.changedKeys().forEach(changeKey -> {
ConfigChange configChange = changeEvent.getChange(changeKey);
String newValue = configChange.getNewValue();
LiteFlowNodeBuilder.createScriptNode()
.setId(nodeSimpleVO.getNodeId())
.setType(NodeTypeEnum.getEnumByCode(nodeSimpleVO.getType()))
.setName(nodeSimpleVO.getName())
.setScript(nodeSimpleVO.getScript())
.build();
break;
case DELETED:
LOG.info("starting reload flow config... delete key={}", changeKey);
FlowBus.getNodeMap().remove(nodeSimpleVO.getNodeId());
break;
default:
}
}));
}
}
PropertyChangeType changeType = configChange.getChangeType();
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;
switch (changeType) {
case ADDED:
case MODIFIED:
LOG.info("starting reload flow config... {} key={} value={},", changeType.name(), changeKey,
newValue);
nodeSimpleVO = convert(changeKey, newValue);
LiteFlowNodeBuilder.createScriptNode()
.setId(nodeSimpleVO.getNodeId())
.setType(NodeTypeEnum.getEnumByCode(nodeSimpleVO.getType()))
.setName(nodeSimpleVO.getName())
.setScript(nodeSimpleVO.getScript())
.build();
break;
case DELETED:
LOG.info("starting reload flow config... delete key={}", changeKey);
nodeSimpleVO = convert(changeKey, null);
FlowBus.getNodeMap().remove(nodeSimpleVO.getNodeId());
}
}));
}
}
NodeSimpleVO nodeSimpleVO = new NodeSimpleVO();
if (matchItemList.size() > 1) {
nodeSimpleVO.setNodeId(matchItemList.get(0));
nodeSimpleVO.setType(matchItemList.get(1));
}
private NodeSimpleVO convert(String key, String value) {
// 不需要去理解这串正则,就是一个匹配冒号的
// 一定得是a:b或是a:b:c...这种完整类型的字符串的
List<String> matchItemList = ReUtil.findAllGroup0("(?<=[^:]:)[^:]+|[^:]+(?=:[^:])", key);
if (CollUtil.isEmpty(matchItemList)) {
return null;
}
if (matchItemList.size() > 2) {
nodeSimpleVO.setName(matchItemList.get(2));
}
NodeSimpleVO nodeSimpleVO = new NodeSimpleVO();
if (matchItemList.size() > 1) {
nodeSimpleVO.setNodeId(matchItemList.get(0));
nodeSimpleVO.setType(matchItemList.get(1));
}
// set script
nodeSimpleVO.setScript(value);
if (matchItemList.size() > 2) {
nodeSimpleVO.setName(matchItemList.get(2));
}
return nodeSimpleVO;
}
// set script
nodeSimpleVO.setScript(value);
private static class NodeSimpleVO {
return nodeSimpleVO;
}
private String nodeId;
private static class NodeSimpleVO {
private String type;
private String nodeId;
private String name = StrUtil.EMPTY;
private String type;
private String script;
private String name = StrUtil.EMPTY;
public String getNodeId() {
return nodeId;
}
private String script;
public void setNodeId(String nodeId) {
this.nodeId = nodeId;
}
public String getNodeId() {
return nodeId;
}
public String getType() {
return type;
}
public void setNodeId(String nodeId) {
this.nodeId = nodeId;
}
public void setType(String type) {
this.type = type;
}
public String getType() {
return type;
}
public String getName() {
return name;
}
public void setType(String type) {
this.type = type;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getScript() {
return script;
}
public void setName(String name) {
this.name = name;
}
public void setScript(String script) {
this.script = script;
}
public String getScript() {
return script;
}
public void setScript(String script) {
this.script = script;
}
}
}
}