diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceBuilder.java b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceBuilder.java index 3f9549e7..1b615d70 100644 --- a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceBuilder.java +++ b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceBuilder.java @@ -16,7 +16,6 @@ package com.alibaba.cloud.nacos.client; -import java.io.StringReader; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; @@ -25,11 +24,10 @@ import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; -import org.springframework.core.io.ByteArrayResource; import org.springframework.util.StringUtils; import com.alibaba.cloud.nacos.NacosPropertySourceRepository; +import com.alibaba.cloud.nacos.parser.NacosDataParserHandler; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.exception.NacosException; @@ -84,24 +82,18 @@ public class NacosPropertySourceBuilder { try { data = configService.getConfig(dataId, group, timeout); if (StringUtils.isEmpty(data)) { + log.warn( + "Ignore the empty nacos configuration and get it based on dataId[{}] & group[{}]", + dataId, group); return EMPTY_PROPERTIES; } + log.info(String.format( + "Loading nacos data, dataId: '%s', group: '%s', data: %s", dataId, + group, data)); - log.info(String.format("Loading nacos data, dataId: '%s', group: '%s'", - dataId, group)); - - if ("properties".equalsIgnoreCase(fileExtension)) { - Properties properties = new Properties(); - - properties.load(new StringReader(data)); - return properties; - } - else if ("yaml".equalsIgnoreCase(fileExtension) - || "yml".equalsIgnoreCase(fileExtension)) { - YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean(); - yamlFactory.setResources(new ByteArrayResource(data.getBytes())); - return yamlFactory.getObject(); - } + Properties properties = NacosDataParserHandler.getInstance() + .parseNacosData(data, fileExtension); + return properties == null ? EMPTY_PROPERTIES : properties; } catch (NacosException e) { log.error("get data from Nacos error,dataId:{}, ", dataId, e); diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceLocator.java b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceLocator.java index 0a83dfc2..10a48cd8 100644 --- a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceLocator.java +++ b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceLocator.java @@ -16,7 +16,6 @@ package com.alibaba.cloud.nacos.client; -import java.util.Arrays; import java.util.List; import com.alibaba.cloud.nacos.NacosConfigManager; @@ -32,6 +31,7 @@ import org.springframework.util.StringUtils; import com.alibaba.cloud.nacos.NacosConfigProperties; import com.alibaba.cloud.nacos.NacosPropertySourceRepository; +import com.alibaba.cloud.nacos.parser.NacosDataParserHandler; import com.alibaba.cloud.nacos.refresh.NacosContextRefresher; import com.alibaba.nacos.api.config.ConfigService; @@ -48,8 +48,6 @@ public class NacosPropertySourceLocator implements PropertySourceLocator { private static final String SEP1 = "-"; private static final String DOT = "."; private static final String SHARED_CONFIG_SEPARATOR_CHAR = "[,]"; - private static final List SUPPORT_FILE_EXTENSION = Arrays.asList("properties", - "yaml", "yml"); private NacosPropertySourceBuilder nacosPropertySourceBuilder; @@ -131,7 +129,7 @@ public class NacosPropertySourceLocator implements PropertySourceLocator { for (NacosConfigProperties.Config config : extConfigs) { String dataId = config.getDataId(); - String fileExtension = dataId.substring(dataId.lastIndexOf(".") + 1); + String fileExtension = dataId.substring(dataId.lastIndexOf(DOT) + 1); loadNacosDataIfPresent(compositePropertySource, dataId, config.getGroup(), fileExtension, config.isRefresh()); } @@ -189,24 +187,11 @@ public class NacosPropertySourceLocator implements PropertySourceLocator { } private static void checkDataIdFileExtension(String[] dataIdArray) { - StringBuilder stringBuilder = new StringBuilder(); - - for (String dataId : dataIdArray) { - if (!canLoadFileExtension(dataId)) { - stringBuilder.append(dataId).append(","); - } + if (dataIdArray == null || dataIdArray.length < 1) { + throw new IllegalStateException("The dataId cannot be empty"); } - - if (stringBuilder.length() > 0) { - String result = stringBuilder.substring(0, stringBuilder.length() - 1); - throw new IllegalStateException(String.format( - "[%s] must end file extension with properties|yaml|yml", result)); - } - } - - private static boolean canLoadFileExtension(String dataId) { - return SUPPORT_FILE_EXTENSION.stream().anyMatch( - (fileExtension) -> StringUtils.endsWithIgnoreCase(dataId, fileExtension)); + // Just decide that the current dataId must have a suffix + NacosDataParserHandler.getInstance().checkDataId(dataIdArray); } private boolean checkDataIdIsRefreshable(String refreshDataIds, String sharedDataId) { diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/AbstractNacosDataParser.java b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/AbstractNacosDataParser.java new file mode 100644 index 00000000..42f49bbb --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/AbstractNacosDataParser.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.nacos.parser; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import com.alibaba.nacos.client.utils.StringUtils; + +/** + * @author zkz + */ +public abstract class AbstractNacosDataParser { + + protected static final String DOT = "."; + protected static final String VALUE = "value"; + + private String extension; + private AbstractNacosDataParser nextParser; + + protected AbstractNacosDataParser(String extension) { + if (StringUtils.isEmpty(extension)) { + throw new IllegalArgumentException("extension cannot be empty"); + } + this.extension = extension.toLowerCase(); + } + + /** Verify file extensions */ + public final boolean checkFileExtension(String extension) { + if (this.isLegal(extension.toLowerCase())) { + return true; + } + if (this.nextParser == null) { + return false; + } + return this.nextParser.checkFileExtension(extension); + + } + + /** Parsing nacos configuration content */ + public final Properties parseNacosData(String data, String extension) + throws IOException { + if (extension == null || extension.length() < 1) { + throw new IllegalStateException("The file extension cannot be empty"); + } + if (this.isLegal(extension.toLowerCase())) { + return this.doParse(data); + } + if (this.nextParser == null) { + throw new IllegalStateException(getTips(extension)); + } + return this.nextParser.parseNacosData(data, extension); + } + + /** Core logic for parsing */ + protected abstract Properties doParse(String data) throws IOException; + + protected AbstractNacosDataParser setNextParser(AbstractNacosDataParser nextParser) { + this.nextParser = nextParser; + return this; + } + + /** add the next parser */ + public AbstractNacosDataParser addNextParser(AbstractNacosDataParser nextParser) { + if (this.nextParser == null) { + this.nextParser = nextParser; + } + else { + this.nextParser.addNextParser(nextParser); + } + return this; + } + + protected boolean isLegal(String extension) { + return this.extension.equalsIgnoreCase(extension) + || this.extension.contains(extension); + } + + /** + * Generate key-value pairs from the map + */ + protected Properties generateProperties(Map map) { + if (null == map || map.isEmpty()) { + return null; + } + Properties properties = new Properties(); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + if (StringUtils.isBlank(key)) { + continue; + } + key = key.startsWith(DOT) ? key.replaceFirst("\\.", "") : key; + properties.put(key, entry.getValue()); + } + return properties; + } + + /** + * Reload the key ending in `value`,if you need + */ + protected Map reloadMap(Map map) { + if (map == null || map.isEmpty()) { + return null; + } + Map result = new HashMap<>(map); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + if (key.contains(DOT)) { + int idx = key.lastIndexOf(DOT); + String suffix = key.substring(idx + 1); + if (VALUE.equalsIgnoreCase(suffix)) { + result.put(key.substring(0, idx), entry.getValue()); + } + } + } + return result; + } + + public static String getTips(String fileName) { + return String.format( + "[%s] must contains file extension with properties|yaml|yml|xml|json", + fileName); + } + +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataJsonParser.java b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataJsonParser.java new file mode 100644 index 00000000..8e500e33 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataJsonParser.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.nacos.parser; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import com.alibaba.nacos.client.utils.StringUtils; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * @author zkz + */ +public class NacosDataJsonParser extends AbstractNacosDataParser { + protected NacosDataJsonParser() { + super("json"); + } + + @Override + protected Properties doParse(String data) throws IOException { + if (StringUtils.isEmpty(data)) { + return null; + } + Map map = parseJSON2Map(data); + return this.generateProperties(this.reloadMap(map)); + } + + /** + * JSON to Map + */ + public static Map parseJSON2Map(String json) throws IOException { + Map map = new HashMap<>(32); + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode = mapper.readTree(json); + if (null == jsonNode) { + return map; + } + parseJsonNode(map, jsonNode, ""); + return map; + } + + private static void parseJsonNode(Map jsonMap, JsonNode jsonNode, + String parentKey) { + Iterator fieldNames = jsonNode.fieldNames(); + while (fieldNames.hasNext()) { + String name = fieldNames.next(); + String fullKey = StringUtils.isEmpty(parentKey) ? name + : parentKey + DOT + name; + JsonNode resultValue = jsonNode.findValue(name); + if (null == resultValue) { + continue; + } + if (resultValue.isArray()) { + Iterator iterator = resultValue.elements(); + while (iterator != null && iterator.hasNext()) { + JsonNode next = iterator.next(); + if (null == next) { + continue; + } + parseJsonNode(jsonMap, next, fullKey); + } + continue; + } + if (resultValue.isObject()) { + parseJsonNode(jsonMap, resultValue, fullKey); + continue; + } + jsonMap.put(fullKey, resultValue.asText()); + } + } + +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataParserHandler.java b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataParserHandler.java new file mode 100644 index 00000000..e3168c91 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataParserHandler.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.nacos.parser; + +import java.io.IOException; +import java.util.Properties; + +/** + * @author zkz + */ +public class NacosDataParserHandler { + + private static final NacosDataParserHandler HANDLER = new NacosDataParserHandler(); + + private AbstractNacosDataParser parser; + + private NacosDataParserHandler() { + parser = this.createParser(); + } + + /** Parsing nacos configuration content */ + public Properties parseNacosData(String data, String extension) throws IOException { + if (null == parser) { + parser = this.createParser(); + } + return parser.parseNacosData(data, extension); + } + + /** check the validity of file extensions in dataid */ + public boolean checkDataId(String... dataIdAry) { + StringBuilder stringBuilder = new StringBuilder(); + for (String dataId : dataIdAry) { + int idx = dataId.lastIndexOf(AbstractNacosDataParser.DOT); + if (idx > 0 && idx < dataId.length() - 1) { + String extension = dataId.substring(idx + 1); + if (parser.checkFileExtension(extension)) { + break; + } + } + // add tips + stringBuilder.append(dataId).append(","); + } + if (stringBuilder.length() > 0) { + String result = stringBuilder.substring(0, stringBuilder.length() - 1); + throw new IllegalStateException(AbstractNacosDataParser.getTips(result)); + } + return true; + } + + private AbstractNacosDataParser createParser() { + return new NacosDataPropertiesParser().addNextParser(new NacosDataYamlParser()) + .addNextParser(new NacosDataXmlParser()) + .addNextParser(new NacosDataJsonParser()); + } + + public static NacosDataParserHandler getInstance() { + return HANDLER; + } + +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataPropertiesParser.java b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataPropertiesParser.java new file mode 100644 index 00000000..f0599bd2 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataPropertiesParser.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.nacos.parser; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Properties; + +/** + * @author zkz + */ +public class NacosDataPropertiesParser extends AbstractNacosDataParser { + + public NacosDataPropertiesParser() { + super("properties"); + } + + @Override + protected Properties doParse(String data) throws IOException { + Properties properties = new Properties(); + properties.load(new StringReader(data)); + return properties; + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataXmlParser.java b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataXmlParser.java new file mode 100644 index 00000000..e9431ba4 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataXmlParser.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.nacos.parser; + +import java.io.IOException; +import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import com.alibaba.nacos.client.utils.StringUtils; + +/** + * With relatively few usage scenarios, only simple parsing is performed to reduce jar + * dependencies + * + * @author zkz + */ +public class NacosDataXmlParser extends AbstractNacosDataParser { + + public NacosDataXmlParser() { + super("xml"); + } + + @Override + protected Properties doParse(String data) throws IOException { + if (StringUtils.isEmpty(data)) { + return null; + } + Map map = parseXml2Map(data); + return this.generateProperties(this.reloadMap(map)); + } + + private Map parseXml2Map(String xml) throws IOException { + xml = xml.replaceAll("\\r", "") + .replaceAll("\\n", "") + .replaceAll("\\t", ""); + Map map = new HashMap<>(32); + try { + DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance() + .newDocumentBuilder(); + Document document = documentBuilder + .parse(new InputSource(new StringReader(xml))); + if (null == document) { + return null; + } + parseNodeList(document.getChildNodes(), map, ""); + } + catch (Exception e) { + throw new IOException("The xml content parse error.", e.getCause()); + } + return map; + } + + private void parseNodeList(NodeList nodeList, Map map, + String parentKey) { + if (nodeList == null || nodeList.getLength() < 1) { + return; + } + parentKey = parentKey == null ? "" : parentKey; + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + String value = node.getNodeValue(); + value = value == null ? "" : value.trim(); + String name = node.getNodeName(); + name = name == null ? "" : name.trim(); + + if (StringUtils.isEmpty(name)) { + continue; + } + + String key = StringUtils.isEmpty(parentKey) ? name : parentKey + DOT + name; + NamedNodeMap nodeMap = node.getAttributes(); + parseNodeAttr(nodeMap, map, key); + if (node.getNodeType() == Node.ELEMENT_NODE && node.hasChildNodes()) { + parseNodeList(node.getChildNodes(), map, key); + continue; + } + if (value.length() < 1) { + continue; + } + map.put(parentKey, value); + } + } + + private void parseNodeAttr(NamedNodeMap nodeMap, Map map, + String parentKey) { + if (null == nodeMap || nodeMap.getLength() < 1) { + return; + } + for (int i = 0; i < nodeMap.getLength(); i++) { + Node node = nodeMap.item(i); + if (null == node) { + continue; + } + if (node.getNodeType() == Node.ATTRIBUTE_NODE) { + if (StringUtils.isEmpty(node.getNodeName())) { + continue; + } + if (StringUtils.isEmpty(node.getNodeValue())) { + continue; + } + map.put(String.join(DOT, parentKey, node.getNodeName()), + node.getNodeValue()); + } + } + } + +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataYamlParser.java b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataYamlParser.java new file mode 100644 index 00000000..74898027 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/parser/NacosDataYamlParser.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.nacos.parser; + +import java.util.Properties; + +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.io.ByteArrayResource; + +/** + * @author zkz + */ +public class NacosDataYamlParser extends AbstractNacosDataParser { + + public NacosDataYamlParser() { + super(",yml,yaml,"); + } + + @Override + protected Properties doParse(String data) { + YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean(); + yamlFactory.setResources(new ByteArrayResource(data.getBytes())); + return yamlFactory.getObject(); + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/test/java/com/alibaba/cloud/nacos/NacosConfigurationXmlJsonTest.java b/spring-cloud-alibaba-nacos-config/src/test/java/com/alibaba/cloud/nacos/NacosConfigurationXmlJsonTest.java new file mode 100644 index 00000000..019ebd7e --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/test/java/com/alibaba/cloud/nacos/NacosConfigurationXmlJsonTest.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.nacos; + +import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator; +import com.alibaba.cloud.nacos.endpoint.NacosConfigEndpoint; +import com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration; +import com.alibaba.cloud.nacos.refresh.NacosRefreshHistory; +import com.alibaba.nacos.client.config.NacosConfigService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.api.support.MethodProxy; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.modules.junit4.PowerMockRunnerDelegate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE; + +/** + * @author zkz + */ + +@RunWith(PowerMockRunner.class) +@PowerMockIgnore("javax.management.*") +@PowerMockRunnerDelegate(SpringRunner.class) +@PrepareForTest({ NacosConfigService.class }) +@SpringBootTest(classes = NacosConfigurationXmlJsonTest.TestConfig.class, properties = { + "spring.application.name=xmlApp", "spring.profiles.active=dev" + ,"spring.cloud.nacos.config.server-addr=127.0.0.1:8848" + ,"spring.cloud.nacos.config.namespace=test-namespace" + ,"spring.cloud.nacos.config.encode=utf-8" + ,"spring.cloud.nacos.config.timeout=1000" + ,"spring.cloud.nacos.config.group=test-group" + ,"spring.cloud.nacos.config.name=test-name" + ,"spring.cloud.nacos.config.cluster-name=test-cluster" + ,"spring.cloud.nacos.config.file-extension=xml" + ,"spring.cloud.nacos.config.contextPath=test-contextpath" + ,"spring.cloud.nacos.config.ext-config[0].data-id=ext-json-test.json" + ,"spring.cloud.nacos.config.ext-config[1].data-id=ext-common02.properties" + ,"spring.cloud.nacos.config.ext-config[1].group=GLOBAL_GROUP" + ,"spring.cloud.nacos.config.shared-dataids=shared-data1.properties" + ,"spring.cloud.nacos.config.accessKey=test-accessKey" + ,"spring.cloud.nacos.config.secretKey=test-secretKey" +}, webEnvironment = NONE) +public class NacosConfigurationXmlJsonTest { + + static { + + try { + + Method method = PowerMockito.method(NacosConfigService.class, "getConfig", + String.class, String.class, long.class); + MethodProxy.proxy(method, new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + + if ("xmlApp.xml".equals(args[0]) && "test-group".equals(args[1])) { + return "\n" + + " one\n" + + " \n" + + " three\n" + + " \n" + + ""; + } + if ("test-name.xml".equals(args[0]) && "test-group".equals(args[1])) { + return " \n" + + " \n" + + " \n" + + " 开启服务 \n" + + " 初始化一下 \n" + + " \n" + + " \n" + + " one\n" + + " \n" + + " three\n" + + " \n" + + " \n" + + " \n" + + " 销毁一下 \n" + + " 关闭服务 \n" + + " \n" + + " \n" + + " "; + } + + if ("test-name-dev.xml".equals(args[0]) && "test-group".equals(args[1])) { + return "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + } + + if ("ext-json-test.json".equals(args[0]) && "DEFAULT_GROUP".equals(args[1])) { + return "{\n" + + " \"people\":{\n" + + " \"firstName\":\"Brett\",\n" + + " \"lastName\":\"McLaughlin\"\n" + + " }\n" + + "}"; + } + + if ("ext-config-common02.properties".equals(args[0]) && "GLOBAL_GROUP".equals(args[1])) { + return "global-ext-config=global-config-value-2"; + } + + + if ("shared-data1.properties".equals(args[0]) && "DEFAULT_GROUP".equals(args[1])) { + return "shared-name=shared-value-1"; + } + + return ""; + } + }); + + } + catch (Exception ignore) { + ignore.printStackTrace(); + + } + } + + @Autowired + private NacosPropertySourceLocator locator; + + @Autowired + private NacosConfigProperties properties; + + @Autowired + private NacosRefreshHistory refreshHistory; + + @Test + public void contextLoads() throws Exception { + + assertNotNull("NacosPropertySourceLocator was not created", locator); + assertNotNull("NacosConfigProperties was not created", properties); + + checkoutNacosConfigServerAddr(); + checkoutNacosConfigNamespace(); + checkoutNacosConfigClusterName(); + checkoutNacosConfigAccessKey(); + checkoutNacosConfigSecrectKey(); + checkoutNacosConfigName(); + checkoutNacosConfigGroup(); + checkoutNacosConfigContextPath(); + checkoutNacosConfigFileExtension(); + checkoutNacosConfigTimeout(); + checkoutNacosConfigEncode(); + + checkoutEndpoint(); + + } + + private void checkoutNacosConfigServerAddr() { + assertEquals("NacosConfigProperties server address is wrong", "127.0.0.1:8848", + properties.getServerAddr()); + } + + private void checkoutNacosConfigNamespace() { + assertEquals("NacosConfigProperties namespace is wrong", "test-namespace", + properties.getNamespace()); + } + + private void checkoutNacosConfigClusterName() { + assertEquals("NacosConfigProperties' cluster is wrong", "test-cluster", + properties.getClusterName()); + } + + private void checkoutNacosConfigAccessKey() { + assertEquals("NacosConfigProperties' is access key is wrong", "test-accessKey", + properties.getAccessKey()); + } + + private void checkoutNacosConfigSecrectKey() { + assertEquals("NacosConfigProperties' is secret key is wrong", "test-secretKey", + properties.getSecretKey()); + } + + private void checkoutNacosConfigContextPath() { + assertEquals("NacosConfigProperties' context path is wrong", "test-contextpath", + properties.getContextPath()); + } + + private void checkoutNacosConfigName() { + assertEquals("NacosConfigProperties' name is wrong", "test-name", + properties.getName()); + } + + private void checkoutNacosConfigGroup() { + assertEquals("NacosConfigProperties' group is wrong", "test-group", + properties.getGroup()); + } + + private void checkoutNacosConfigFileExtension() { + assertEquals("NacosConfigProperties' file extension is wrong", "xml", + properties.getFileExtension()); + } + + private void checkoutNacosConfigTimeout() { + assertEquals("NacosConfigProperties' timeout is wrong", 1000, + properties.getTimeout()); + } + + private void checkoutNacosConfigEncode() { + assertEquals("NacosConfigProperties' encode is wrong", "utf-8", + properties.getEncode()); + } + + + private void checkoutEndpoint() throws Exception { + NacosConfigEndpoint nacosConfigEndpoint = new NacosConfigEndpoint(properties, + refreshHistory); + Map map = nacosConfigEndpoint.invoke(); + assertEquals(map.get("NacosConfigProperties"), properties); + assertEquals(map.get("RefreshHistory"), refreshHistory.getRecords()); + } + + @Configuration + @EnableAutoConfiguration + @ImportAutoConfiguration({ NacosConfigEndpointAutoConfiguration.class, + NacosConfigAutoConfiguration.class, NacosConfigBootstrapConfiguration.class }) + public static class TestConfig { + } +}