diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml index 6dc00fbcda76..5164d860cd29 100644 --- a/dubbo-all/pom.xml +++ b/dubbo-all/pom.xml @@ -485,6 +485,13 @@ compile true + + org.apache.dubbo + dubbo-metadata-report-nacos + ${project.version} + compile + true + @@ -613,6 +620,7 @@ org.apache.dubbo:dubbo-metadata-report-zookeeper org.apache.dubbo:dubbo-metadata-report-consul org.apache.dubbo:dubbo-metadata-report-etcd + org.apache.dubbo:dubbo-metadata-report-nacos org.apache.dubbo:dubbo-serialization-native-hession org.apache.dubbo:dubbo-rpc-native-thrift diff --git a/dubbo-bom/pom.xml b/dubbo-bom/pom.xml index 2b1e5feb2f62..e6f6eb8c011e 100644 --- a/dubbo-bom/pom.xml +++ b/dubbo-bom/pom.xml @@ -382,6 +382,11 @@ dubbo-metadata-report-etcd ${project.version} + + org.apache.dubbo + dubbo-metadata-report-nacos + ${project.version} + org.apache.dubbo dubbo-configcenter-api diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/pom.xml b/dubbo-metadata-report/dubbo-metadata-report-nacos/pom.xml new file mode 100644 index 000000000000..d324d5c49c18 --- /dev/null +++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/pom.xml @@ -0,0 +1,41 @@ + + + + + + dubbo-metadata-report + org.apache.dubbo + ${revision} + + 4.0.0 + + dubbo-metadata-report-nacos + + + + org.apache.dubbo + dubbo-metadata-report-api + ${project.parent.version} + + + com.alibaba.nacos + nacos-client + + + + 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 new file mode 100644 index 000000000000..03bdeb8f9585 --- /dev/null +++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java @@ -0,0 +1,125 @@ +/* + * 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.metadata.store.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.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.metadata.identifier.MetadataIdentifier; +import org.apache.dubbo.metadata.support.AbstractMetadataReport; +import org.apache.dubbo.rpc.RpcException; + +import java.util.Properties; + +import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR; +import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY; +import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY; +import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT; +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.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; + + public NacosMetadataReport(URL url) { + super(url); + this.configService = buildConfigService(url); + } + + public ConfigService buildConfigService(URL url) { + Properties nacosProperties = buildNacosProperties(url); + try { + configService = NacosFactory.createConfigService(nacosProperties); + } catch (NacosException e) { + if (logger.isErrorEnabled()) { + logger.error(e.getErrMsg(), e); + } + throw new IllegalStateException(e); + } + return configService; + } + + private Properties buildNacosProperties(URL url) { + Properties properties = new Properties(); + setServerAddr(url, properties); + setProperties(url, properties); + return properties; + } + + private void setServerAddr(URL url, Properties properties) { + StringBuilder serverAddrBuilder = + new StringBuilder(url.getHost()) // Host + .append(":") + .append(url.getPort()); // Port + // Append backup parameter as other servers + String backup = url.getParameter(BACKUP_KEY); + if (backup != null) { + serverAddrBuilder.append(",").append(backup); + } + String serverAddr = serverAddrBuilder.toString(); + properties.put(SERVER_ADDR, serverAddr); + } + + private void setProperties(URL url, Properties properties) { + putPropertyIfAbsent(url, properties, NAMESPACE); + putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME); + putPropertyIfAbsent(url, properties, ENDPOINT); + putPropertyIfAbsent(url, properties, ACCESS_KEY); + putPropertyIfAbsent(url, properties, SECRET_KEY); + putPropertyIfAbsent(url, properties, CLUSTER_NAME); + } + + private void putPropertyIfAbsent(URL url, Properties properties, String propertyName) { + String propertyValue = url.getParameter(propertyName); + if (StringUtils.isNotEmpty(propertyValue)) { + properties.setProperty(propertyName, propertyValue); + } + } + + @Override + protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) { + this.storeMetadata(providerMetadataIdentifier, serviceDefinitions); + } + + @Override + protected void doStoreConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, String value) { + this.storeMetadata(consumerMetadataIdentifier, value); + } + + private void storeMetadata(MetadataIdentifier identifier, String value) { + try { + boolean publishResult = configService.publishConfig(identifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), identifier.getGroup(), value); + if (!publishResult) { + throw new RuntimeException("publish nacos metadata failed"); + } + } catch (Throwable t) { + logger.error("Failed to put " + identifier + " to nacos " + value + ", cause: " + t.getMessage(), t); + throw new RpcException("Failed to put " + identifier + " to nacos " + value + ", cause: " + t.getMessage(), t); + } + } +} diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java new file mode 100644 index 000000000000..b882042281c5 --- /dev/null +++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java @@ -0,0 +1,32 @@ +/* + * 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.metadata.store.nacos; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.metadata.store.MetadataReport; +import org.apache.dubbo.metadata.support.AbstractMetadataReportFactory; + +/** + * metadata report factory impl for nacos + */ +public class NacosMetadataReportFactory extends AbstractMetadataReportFactory { + @Override + protected MetadataReport createMetadataReport(URL url) { + return new NacosMetadataReport(url); + } +} diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory new file mode 100644 index 000000000000..de3b50a4b415 --- /dev/null +++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory @@ -0,0 +1 @@ +nacos=org.apache.dubbo.metadata.store.nacos.NacosMetadataReportFactory diff --git a/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadata4TstService.java b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadata4TstService.java new file mode 100644 index 000000000000..e84efc529caa --- /dev/null +++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadata4TstService.java @@ -0,0 +1,28 @@ +/* + * 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.metadata.store.nacos; + +/** + * Test interface for Nacos metadata report + */ +public interface NacosMetadata4TstService { + + int getCounter(); + + void printResult(String var); +} 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 new file mode 100644 index 000000000000..c90809c3d51c --- /dev/null +++ b/dubbo-metadata-report/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportTest.java @@ -0,0 +1,115 @@ +/* + * 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.metadata.store.nacos; + +import com.alibaba.nacos.api.config.ConfigService; +import com.google.gson.Gson; +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder; +import org.apache.dubbo.metadata.definition.model.FullServiceDefinition; +import org.apache.dubbo.metadata.identifier.MetadataIdentifier; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Disabled; + +import java.util.HashMap; +import java.util.Map; + +import static org.apache.dubbo.common.constants.RegistryConstants.SESSION_TIMEOUT_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; +import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE; + +@Disabled +public class NacosMetadataReportTest { + private static final String TEST_SERVICE = "org.apache.dubbo.metadata.store.nacos.NacosMetadata4TstService"; + private NacosMetadataReport nacosMetadataReport; + private NacosMetadataReportFactory nacosMetadataReportFactory; + private ConfigService configService; + + @BeforeEach + public void setUp() { + // timeout in 15 seconds. + URL url = URL.valueOf("nacos://127.0.0.1:8848") + .addParameter(SESSION_TIMEOUT_KEY, 15000); + nacosMetadataReportFactory = new NacosMetadataReportFactory(); + this.nacosMetadataReport = (NacosMetadataReport) nacosMetadataReportFactory.createMetadataReport(url); + this.configService = nacosMetadataReport.buildConfigService(url); + } + + @AfterEach + public void tearDown() throws Exception { + } + + @Test + public void testStoreProvider() throws Exception { + String version = "1.0.0"; + String group = null; + 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); + Assertions.assertNotNull(serverContent); + + Gson gson = new Gson(); + FullServiceDefinition fullServiceDefinition = gson.fromJson(serverContent, FullServiceDefinition.class); + Assertions.assertEquals(fullServiceDefinition.getParameters().get("paramTest"), "nacosTest"); + } + + @Test + public void testStoreConsumer() throws Exception { + String version = "1.0.0"; + String group = null; + 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); + Assertions.assertNotNull(serverContent); + Assertions.assertEquals(serverContent, "{\"paramConsumerTest\":\"nacosConsumer\"}"); + } + + private MetadataIdentifier storeProvider(NacosMetadataReport nacosMetadataReport, String interfaceName, String version, + String group, String application) + throws ClassNotFoundException, InterruptedException { + URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":4444/" + interfaceName + + "?paramTest=nacosTest&version=" + version + "&application=" + + application + (group == null ? "" : "&group=" + group)); + + MetadataIdentifier providerMetadataIdentifier = + new MetadataIdentifier(interfaceName, version, group, PROVIDER_SIDE, application); + Class interfaceClass = Class.forName(interfaceName); + FullServiceDefinition fullServiceDefinition = + ServiceDefinitionBuilder.buildFullDefinition(interfaceClass, url.getParameters()); + + nacosMetadataReport.storeProviderMetadata(providerMetadataIdentifier, fullServiceDefinition); + Thread.sleep(1000); + return providerMetadataIdentifier; + } + + private MetadataIdentifier storeConsumer(NacosMetadataReport nacosMetadataReport, String interfaceName, + String version, String group, String application) throws InterruptedException { + MetadataIdentifier consumerIdentifier = new MetadataIdentifier(interfaceName, version, group, CONSUMER_SIDE, application); + Map tmp = new HashMap<>(); + tmp.put("paramConsumerTest", "nacosConsumer"); + nacosMetadataReport.storeConsumerMetadata(consumerIdentifier, tmp); + Thread.sleep(1000); + return consumerIdentifier; + } +} diff --git a/dubbo-metadata-report/pom.xml b/dubbo-metadata-report/pom.xml index 3cb254afb961..5e0fb1a42877 100644 --- a/dubbo-metadata-report/pom.xml +++ b/dubbo-metadata-report/pom.xml @@ -31,6 +31,7 @@ dubbo-metadata-definition dubbo-metadata-report-consul dubbo-metadata-report-etcd + dubbo-metadata-report-nacos