support consul metadata center implementation (#405)
diff --git a/dubbo-admin-server/pom.xml b/dubbo-admin-server/pom.xml
index 44c6828..02115b0 100644
--- a/dubbo-admin-server/pom.xml
+++ b/dubbo-admin-server/pom.xml
@@ -139,6 +139,16 @@
</dependency>
<dependency>
+ <groupId>com.ecwid.consul</groupId>
+ <artifactId>consul-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.pszymczyk.consul</groupId>
+ <artifactId>embedded-consul</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/metadata/impl/ConsulMetaDataCollector.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/metadata/impl/ConsulMetaDataCollector.java
new file mode 100644
index 0000000..fa5a225
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/metadata/impl/ConsulMetaDataCollector.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.dubbo.admin.registry.metadata.impl;
+
+
+import org.apache.dubbo.admin.registry.metadata.MetaDataCollector;
+
+import com.ecwid.consul.v1.ConsulClient;
+import com.ecwid.consul.v1.Response;
+import com.ecwid.consul.v1.kv.model.GetValue;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
+
+import java.util.Objects;
+
+
+public class ConsulMetaDataCollector implements MetaDataCollector {
+ private static final Logger LOG = LoggerFactory.getLogger(ConsulMetaDataCollector.class);
+ private static final int DEFAULT_PORT = 8500;
+ private URL url;
+ private ConsulClient client;
+
+ @Override
+ public URL getUrl() {
+ return this.url;
+ }
+
+ @Override
+ public void setUrl(URL url) {
+ this.url = url;
+ }
+
+ @Override
+ public void init() {
+ Objects.requireNonNull(this.url, "metadataUrl require not null");
+ String host = this.url.getHost();
+ int port = this.url.getPort() != 0 ? url.getPort() : DEFAULT_PORT;
+ this.client = new ConsulClient(host, port);
+ }
+
+ @Override
+ public String getProviderMetaData(MetadataIdentifier key) {
+ return doGetMetaData(key);
+ }
+
+ @Override
+ public String getConsumerMetaData(MetadataIdentifier key) {
+ return doGetMetaData(key);
+ }
+
+ private String doGetMetaData(MetadataIdentifier key) {
+ try {
+ Response<GetValue> response = this.client.getKVValue(key.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY));
+ return response.getValue().getDecodedValue();
+ } catch (Exception e) {
+ LOG.error(String.format("Failed to fetch metadata for %s from consul, cause: %s",
+ key.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), e.getMessage()), e);
+ }
+ return null;
+ }
+
+ //just for test
+ ConsulClient getClient() {
+ return this.client;
+ }
+}
diff --git a/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.metadata.MetaDataCollector b/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.metadata.MetaDataCollector
index d9e532d..fc4c855 100644
--- a/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.metadata.MetaDataCollector
+++ b/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.metadata.MetaDataCollector
@@ -1,3 +1,4 @@
zookeeper=org.apache.dubbo.admin.registry.metadata.impl.ZookeeperMetaDataCollector
redis=org.apache.dubbo.admin.registry.metadata.impl.RedisMetaDataCollector
+consul=org.apache.dubbo.admin.registry.metadata.impl.ConsulMetaDataCollector
nacos=org.apache.dubbo.admin.registry.metadata.impl.NacosMetaDataCollector
\ No newline at end of file
diff --git a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/registry/metadata/impl/ConsulMetaDataCollectorTest.java b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/registry/metadata/impl/ConsulMetaDataCollectorTest.java
new file mode 100644
index 0000000..5cf93d4
--- /dev/null
+++ b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/registry/metadata/impl/ConsulMetaDataCollectorTest.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.dubbo.admin.registry.metadata.impl;
+
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.pszymczyk.consul.ConsulProcess;
+import com.pszymczyk.consul.ConsulStarterBuilder;
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder;
+import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
+import org.apache.dubbo.metadata.definition.model.MethodDefinition;
+import org.apache.dubbo.metadata.definition.util.ClassUtils;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class ConsulMetaDataCollectorTest {
+
+ private final Gson gson = new Gson();
+ private ConsulProcess consul;
+ private ConsulMetaDataCollector consulMetaDataCollector;
+
+ @Before
+ public void setUp() {
+ consul = ConsulStarterBuilder.consulStarter().build().start();
+ consulMetaDataCollector = new ConsulMetaDataCollector();
+ consulMetaDataCollector.setUrl(URL.valueOf("consul://127.0.0.1:" + consul.getHttpPort()));
+ consulMetaDataCollector.init();
+ }
+
+ @After
+ public void tearDown() {
+ consul.close();
+ consulMetaDataCollector = null;
+ }
+
+ @Test
+ public void testGetProviderMetaData() {
+ MetadataIdentifier identifier = buildIdentifier(true);
+
+ Map<String, String> params = new HashMap<>();
+ params.put("key1", "value1");
+ params.put("key2", "true");
+
+ FullServiceDefinition definition = ServiceDefinitionBuilder.buildFullDefinition(ServiceA.class, params);
+
+ String metadata = gson.toJson(definition);
+ consulMetaDataCollector.getClient().setKVValue(identifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), metadata);
+
+ String providerMetaData = consulMetaDataCollector.getProviderMetaData(identifier);
+ Assert.assertEquals(metadata, providerMetaData);
+
+ FullServiceDefinition retDef = gson.fromJson(providerMetaData, FullServiceDefinition.class);
+ Assert.assertEquals(ServiceA.class.getCanonicalName(), retDef.getCanonicalName());
+ Assert.assertEquals(ClassUtils.getCodeSource(ServiceA.class), retDef.getCodeSource());
+ Assert.assertEquals(params, retDef.getParameters());
+
+ //method def assertions
+ Assert.assertNotNull(retDef.getMethods());
+ Assert.assertEquals(3, retDef.getMethods().size());
+ List<String> methodNames = retDef.getMethods().stream().map(MethodDefinition::getName).sorted().collect(Collectors.toList());
+ Assert.assertEquals("method1", methodNames.get(0));
+ Assert.assertEquals("method2", methodNames.get(1));
+ Assert.assertEquals("method3", methodNames.get(2));
+ }
+
+
+ @Test
+ public void testGetConsumerMetaData() {
+ MetadataIdentifier identifier = buildIdentifier(false);
+
+ Map<String, String> consumerParams = new HashMap<>();
+ consumerParams.put("k1", "v1");
+ consumerParams.put("k2", "1");
+ consumerParams.put("k3", "true");
+ String metadata = gson.toJson(consumerParams);
+ consulMetaDataCollector.getClient().setKVValue(identifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), metadata);
+
+ String consumerMetaData = consulMetaDataCollector.getConsumerMetaData(identifier);
+ Map<String, String> retParams = gson.fromJson(consumerMetaData, new TypeToken<Map<String, String>>() {
+ }.getType());
+ Assert.assertEquals(consumerParams, retParams);
+ }
+
+
+ private MetadataIdentifier buildIdentifier(boolean isProducer) {
+ MetadataIdentifier identifier = new MetadataIdentifier();
+ identifier.setApplication(String.format("metadata-%s-test", isProducer ? "provider" : "consumer"));
+ identifier.setGroup("group");
+ identifier.setServiceInterface(ServiceA.class.getName());
+ identifier.setSide(isProducer ? Constants.PROVIDER_SIDE : Constants.CONSUMER_SIDE);
+ identifier.setVersion("1.0.0");
+ return identifier;
+ }
+
+
+ interface ServiceA {
+ void method1();
+
+ void method2() throws IOException;
+
+ String method3();
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index 869873f..0ad8425 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,7 +64,9 @@
<netty-version>4.1.30.Final</netty-version>
<jacoco-version>0.8.2</jacoco-version>
<jedis-version>2.9.0</jedis-version>
- <apollo-version>1.2.0</apollo-version>
+ <apollo-version>1.2.0</apollo-version>
+ <consul-version>1.4.2</consul-version>
+ <consul-embedded-version>2.0.0</consul-embedded-version>
<nacos-version>1.0.0</nacos-version>
<guava-version>20.0</guava-version>
<snakeyaml-version>1.24</snakeyaml-version>
@@ -173,11 +175,21 @@
</dependency>
<dependency>
+ <groupId>com.ecwid.consul</groupId>
+ <artifactId>consul-api</artifactId>
+ <version>${consul-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.pszymczyk.consul</groupId>
+ <artifactId>embedded-consul</artifactId>
+ <version>${consul-embedded-version}</version>
+ </dependency>
+
+ <dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava-version}</version>
</dependency>
-
</dependencies>
</dependencyManagement>