Merge branch '2.7.2-release' of github.com:apache/dubbo into 2.7.2-release
diff --git a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
index 96bec25..fa04c00 100644
--- a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
+++ b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
@@ -46,9 +46,6 @@
 import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
 import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
 import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPERATOR;
-import static org.apache.dubbo.common.constants.CommonConstants.PROPERTIES_CHAR_SEPERATOR;
-import static org.apache.dubbo.configcenter.Constants.CONFIG_NAMESPACE_KEY;
 import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;
 
 /**
@@ -57,11 +54,10 @@
 public class NacosDynamicConfiguration implements DynamicConfiguration {
 
     private final Logger logger = LoggerFactory.getLogger(getClass());
-
     /**
-     * The final root path would be: /$NAME_SPACE/config
+     * the default timeout in millis to get config from nacos
      */
-    private String rootPath;
+    private static final long DEFAULT_TIMEOUT = 5000L;
 
     /**
      * The nacos configService
@@ -75,7 +71,6 @@
     private final ConcurrentMap<String, NacosConfigListener> watchListenerMap;
 
     NacosDynamicConfiguration(URL url) {
-        rootPath = url.getParameter(CONFIG_NAMESPACE_KEY, DEFAULT_GROUP) + "-config";
         buildConfigService(url);
         watchListenerMap = new ConcurrentHashMap<>();
     }
@@ -93,24 +88,6 @@
         return configService;
     }
 
-    public void publishNacosConfig(String key, String value) {
-        try {
-            String[] keyAndGroup = getKeyAndGroup(key);
-            configService.publishConfig(keyAndGroup[0], keyAndGroup[1], value);
-        } catch (NacosException e) {
-            logger.error(e.getErrMsg());
-        }
-    }
-
-    private String[] getKeyAndGroup(String key) {
-        int i = key.lastIndexOf(GROUP_CHAR_SEPERATOR);
-        if (i < 0) {
-            return new String[]{key, null};
-        } else {
-            return new String[]{key.substring(0, i), key.substring(i+1)};
-        }
-    }
-
     private Properties buildNacosProperties(URL url) {
         Properties properties = new Properties();
         setServerAddr(url, properties);
@@ -162,43 +139,70 @@
         return configListener;
     }
 
+
+    /**
+     * FIXME: 2019-05-30 to remove this function
+     * Nacos server does not support * as valid character of data-id.
+     * If a Dubbo service specifies group. For example:
+     *
+     *  <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService"
+     *      version="1.0.0.test" group="test"/>
+     *
+     * The key passed to NacosDynamicConfiguration will be sth. like:
+     *   test*org.apache.dubbo.demo.DemoService:1.0.0.test.configurators
+     *
+     * See logic in org.apache.dubbo.common.URL#getEncodedServiceKey()
+     *
+     * The purpose of this function is to convert the * into :, to keep align with
+     * the implementation in NacosRegistry.
+     *
+     * In the future this logic should be removed if Dubbo core can handle this.
+     * @param key
+     * @return
+     */
+    private String normalizedKey(String key) {
+        return key.replaceFirst("\\*", ":");
+    }
+
     @Override
     public void addListener(String key, String group, ConfigurationListener listener) {
-        String[] keyAndGroup = getKeyAndGroup(key);
-        if (keyAndGroup[1] != null) {
-            group = keyAndGroup[1];
-        }
-        String finalGroup = group;
-        NacosConfigListener nacosConfigListener = watchListenerMap.computeIfAbsent(generateKey(key, group), k -> createTargetListener(key, finalGroup));
-        String keyInNacos = rootPath + PROPERTIES_CHAR_SEPERATOR + key;
+        String normalizedKey = normalizedKey(key);
+        NacosConfigListener nacosConfigListener = watchListenerMap.computeIfAbsent(normalizedKey, k -> createTargetListener(normalizedKey, group));
         nacosConfigListener.addListener(listener);
         try {
-            configService.addListener(keyInNacos, group, nacosConfigListener);
-            System.out.println("1");
+            configService.addListener(normalizedKey, group, nacosConfigListener);
         } catch (NacosException e) {
             logger.error(e.getMessage());
         }
     }
 
-    private String generateKey(String key, String group) {
-        if (StringUtils.isNotEmpty(group)) {
-            key = key + GROUP_CHAR_SEPERATOR + group;
-        }
-        return key;
-    }
-
     @Override
     public void removeListener(String key, String group, ConfigurationListener listener) {
-        NacosConfigListener eventListener = watchListenerMap.get(generateKey(key, group));
+        String normalizedKey = normalizedKey(key);
+        NacosConfigListener eventListener = watchListenerMap.get(normalizedKey);
         if (eventListener != null) {
             eventListener.removeListener(listener);
         }
     }
 
+    /**
+     * FIXME the model of Zookeeper and Nacos is inconsistent, need to remove this function in next release.
+     */
+    @Override
+    public String getConfig(String key) {
+        return getConfig(key, DEFAULT_GROUP, -1L);
+    }
+
     @Override
     public String getConfig(String key, String group, long timeout) throws IllegalStateException {
-        key = generateKey(key, group);
-        return (String) getInternalProperty(rootPath + PROPERTIES_CHAR_SEPERATOR + key);
+        try {
+            String normalizedKey = normalizedKey(key);
+            long nacosTimeout = timeout < 0 ?  DEFAULT_TIMEOUT : timeout;
+            return configService.getConfig(normalizedKey, group, nacosTimeout);
+        } catch (NacosException e) {
+            logger.error(e.getMessage());
+        }
+        return null;
     }
 
     @Override
@@ -209,8 +213,8 @@
     @Override
     public Object getInternalProperty(String key) {
         try {
-            String[] keyAndGroup = getKeyAndGroup(key);
-            return configService.getConfig(keyAndGroup[0], keyAndGroup[1], 5000L);
+            String normalizedKey = normalizedKey(key);
+            return configService.getConfig(normalizedKey, DEFAULT_GROUP, DEFAULT_TIMEOUT);
         } catch (NacosException e) {
             logger.error(e.getMessage());
         }
diff --git a/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java b/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java
index ff785b9..28fa234 100644
--- a/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java
+++ b/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java
@@ -17,10 +17,14 @@
 
 package org.apache.dubbo.configcenter.support.nacos;
 
+import com.alibaba.nacos.api.NacosFactory;
+import com.alibaba.nacos.api.config.ConfigService;
+import com.alibaba.nacos.api.exception.NacosException;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.configcenter.ConfigChangeEvent;
 import org.apache.dubbo.configcenter.ConfigurationListener;
 
+import org.apache.dubbo.configcenter.DynamicConfiguration;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -42,15 +46,22 @@
 
     private static NacosDynamicConfiguration config;
 
+    /**
+     * A test client to put data to Nacos server for testing purpose
+     */
+    private static ConfigService nacosClient;
+
     @Test
     public void testGetConfig() throws Exception {
-
-        put("dubbo-config-org.apache.dubbo.nacos.testService.configurators", "hello");
+        put("org.apache.dubbo.nacos.testService.configurators", "hello");
         Thread.sleep(200);
-        put("dubbo-config-dubbo.properties:test", "aaa=bbb");
+        put("dubbo.properties", "test", "aaa=bbb");
+        Thread.sleep(200);
+        put("xxxx:org.apache.dubbo.demo.DemoService:1.0.0.test.configurators", "helloworld");
         Thread.sleep(200);
         Assertions.assertEquals("hello", config.getConfig("org.apache.dubbo.nacos.testService.configurators"));
         Assertions.assertEquals("aaa=bbb", config.getConfig("dubbo.properties", "test"));
+        Assertions.assertEquals("helloworld", config.getConfig("xxxx*org.apache.dubbo.demo.DemoService:1.0.0.test.configurators"));
     }
 
     @Test
@@ -67,19 +78,19 @@
         config.addListener("testapp.tagrouters", listener3);
         config.addListener("testapp.tagrouters", listener4);
 
-        put("dubbo-config-AService.configurators", "new value1");
+        put("AService.configurators", "new value1");
         Thread.sleep(200);
-        put("dubbo-config-testapp.tagrouters", "new value2");
+        put("testapp.tagrouters", "new value2");
         Thread.sleep(200);
-        put("dubbo-config-testapp", "new value3");
+        put("testapp", "new value3");
         Thread.sleep(5000);
 
         latch.await();
 
-        Assertions.assertEquals(1, listener1.getCount("dubbo-config-AService.configurators"));
-        Assertions.assertEquals(1, listener2.getCount("dubbo-config-AService.configurators"));
-        Assertions.assertEquals(1, listener3.getCount("dubbo-config-testapp.tagrouters"));
-        Assertions.assertEquals(1, listener4.getCount("dubbo-config-testapp.tagrouters"));
+        Assertions.assertEquals(1, listener1.getCount("AService.configurators"));
+        Assertions.assertEquals(1, listener2.getCount("AService.configurators"));
+        Assertions.assertEquals(1, listener3.getCount("testapp.tagrouters"));
+        Assertions.assertEquals(1, listener4.getCount("testapp.tagrouters"));
 
         Assertions.assertEquals("new value1", listener1.getValue());
         Assertions.assertEquals("new value1", listener2.getValue());
@@ -89,8 +100,12 @@
     }
 
     private void put(String key, String value) {
+        put(key, DynamicConfiguration.DEFAULT_GROUP, value);
+    }
+
+    private void put(String key, String group, String value) {
         try {
-            config.publishNacosConfig(key, value);
+            nacosClient.publishConfig(key, group, value);
         } catch (Exception e) {
             System.out.println("Error put value to nacos.");
         }
@@ -103,10 +118,18 @@
         URL url = URL.valueOf(urlForDubbo)
                 .addParameter(SESSION_TIMEOUT_KEY, 15000);
         config = new NacosDynamicConfiguration(url);
+
+
+        try {
+            nacosClient = NacosFactory.createConfigService("127.0.0.1:8848");
+        } catch (NacosException e) {
+            e.printStackTrace();
+        }
     }
 
     @AfterAll
     public static void tearDown() {
+
     }
 
     private class TestListener implements ConfigurationListener {
@@ -121,7 +144,7 @@
         @Override
         public void process(ConfigChangeEvent event) {
             System.out.println(this + ": " + event);
-            Integer count = countMap.computeIfAbsent(event.getKey(), k -> new Integer(0));
+            Integer count = countMap.computeIfAbsent(event.getKey(), k -> 0);
             countMap.put(event.getKey(), ++count);
             value = event.getValue();
             latch.countDown();
diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
index 03bdeb8..b12e4f0 100644
--- a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
+++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
@@ -37,18 +37,28 @@
 import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
 import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
 import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME;
+import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
 import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;
 
 /**
  * metadata report impl for nacos
  */
 public class NacosMetadataReport extends AbstractMetadataReport {
+
     private static final Logger logger = LoggerFactory.getLogger(NacosMetadataReport.class);
+
     private ConfigService configService;
 
+    /**
+     * The group used to store metadata in Nacos
+     */
+    private String group;
+
+
     public NacosMetadataReport(URL url) {
         super(url);
         this.configService = buildConfigService(url);
+        group = url.getParameter(GROUP_KEY, DEFAULT_ROOT);
     }
 
     public ConfigService buildConfigService(URL url) {
@@ -113,7 +123,7 @@
 
     private void storeMetadata(MetadataIdentifier identifier, String value) {
         try {
-            boolean publishResult = configService.publishConfig(identifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), identifier.getGroup(), value);
+            boolean publishResult = configService.publishConfig(identifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), group, value);
             if (!publishResult) {
                 throw new RuntimeException("publish nacos metadata failed");
             }
diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportTest.java b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportTest.java
index 07d6f8b..a6cf8f5 100644
--- a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportTest.java
+++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportTest.java
@@ -45,10 +45,12 @@
     private NacosMetadataReportFactory nacosMetadataReportFactory;
     private ConfigService configService;
 
+    private static final String NACOS_GROUP = "zzz";
+
     @BeforeEach
     public void setUp() {
         // timeout in 15 seconds.
-        URL url = URL.valueOf("nacos://127.0.0.1:8848")
+        URL url = URL.valueOf("nacos://127.0.0.1:8848?group=" + NACOS_GROUP)
                 .addParameter(SESSION_TIMEOUT_KEY, 15000);
         nacosMetadataReportFactory = new NacosMetadataReportFactory();
         this.nacosMetadataReport = (NacosMetadataReport) nacosMetadataReportFactory.createMetadataReport(url);
@@ -66,7 +68,7 @@
         String application = "nacos-metdata-report-test";
         MetadataIdentifier providerIdentifier =
                 storeProvider(nacosMetadataReport, TEST_SERVICE, version, group, application);
-        String serverContent = configService.getConfig(providerIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), group, 5000L);
+        String serverContent = configService.getConfig(providerIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP, 5000L);
         Assertions.assertNotNull(serverContent);
 
         Gson gson = new Gson();
@@ -81,7 +83,7 @@
         String application = "nacos-metadata-report-consumer-test";
         MetadataIdentifier consumerIdentifier = storeConsumer(nacosMetadataReport, TEST_SERVICE, version, group, application);
 
-        String serverContent = configService.getConfig(consumerIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), group, 5000L);
+        String serverContent = configService.getConfig(consumerIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP, 5000L);
         Assertions.assertNotNull(serverContent);
         Assertions.assertEquals(serverContent, "{\"paramConsumerTest\":\"nacosConsumer\"}");
     }
diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java
index 6639962..5483052 100644
--- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java
+++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java
@@ -383,7 +383,7 @@
      */
     private String[] getCategories(URL url) {
         return ANY_VALUE.equals(url.getServiceInterface()) ?
-                ALL_SUPPORTED_CATEGORIES : of(DEFAULT_CATEGORY);
+                ALL_SUPPORTED_CATEGORIES : url.getParameter(CATEGORY_KEY,new String[]{DEFAULT_CATEGORY});
     }
 
     private URL buildURL(Instance instance) {