diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml index be5a2e3fd7..d8c8949c13 100644 --- a/dubbo-all/pom.xml +++ b/dubbo-all/pom.xml @@ -282,6 +282,13 @@ compile true + + org.apache.dubbo + dubbo-registry-multiple + ${project.version} + compile + true + org.apache.dubbo dubbo-monitor-api @@ -596,6 +603,7 @@ org.apache.dubbo:dubbo-registry-etcd3 org.apache.dubbo:dubbo-registry-nacos org.apache.dubbo:dubbo-registry-sofa + org.apache.dubbo:dubbo-registry-multiple org.apache.dubbo:dubbo-monitor-api org.apache.dubbo:dubbo-monitor-default org.apache.dubbo:dubbo-config-api diff --git a/dubbo-registry/dubbo-registry-multiple/pom.xml b/dubbo-registry/dubbo-registry-multiple/pom.xml new file mode 100644 index 0000000000..e62e2fe21b --- /dev/null +++ b/dubbo-registry/dubbo-registry-multiple/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + org.apache.dubbo + dubbo-registry + ${revision} + + dubbo-registry-multiple + jar + ${project.artifactId} + The multiple registry module of dubbo project + + false + + + + org.apache.dubbo + dubbo-registry-api + ${project.parent.version} + + + org.apache.dubbo + dubbo-registry-zookeeper + ${project.parent.version} + test + + + org.apache.dubbo + dubbo-registry-redis + ${project.parent.version} + test + + + org.apache.curator + curator-test + test + + + com.github.kstyrc + embedded-redis + test + + + diff --git a/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistry.java b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistry.java new file mode 100644 index 0000000000..ea5948151d --- /dev/null +++ b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistry.java @@ -0,0 +1,314 @@ +/* + * 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.registry.multiple; + + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.registry.NotifyListener; +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.RegistryFactory; +import org.apache.dubbo.registry.support.AbstractRegistry; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL; + +/** + * MultipleRegistry + */ +public class MultipleRegistry extends AbstractRegistry { + + public static final String REGISTRY_FOR_SERVICE = "service-registry"; + public static final String REGISTRY_FOR_REFERENCE = "reference-registry"; + + protected RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); + private final Map serviceRegistries = new ConcurrentHashMap<>(4); + private final Map referenceRegistries = new ConcurrentHashMap(4); + private final Map multipleNotifyListenerMap = new ConcurrentHashMap(32); + protected List origServiceRegistryURLs; + protected List origReferenceRegistryURLs; + protected List effectServiceRegistryURLs; + protected List effectReferenceRegistryURLs; + private URL registryUrl; + private String applicationName; + + + public MultipleRegistry(URL url) { + super(url); + this.registryUrl = url; + this.applicationName = url.getParameter(CommonConstants.APPLICATION_KEY); + init(); + checkApplicationName(this.applicationName); + // This urls contain parameter and it donot inherit from the parameter of url in MultipleRegistry + origServiceRegistryURLs = url.getParameter(REGISTRY_FOR_SERVICE, new ArrayList()); + origReferenceRegistryURLs = url.getParameter(REGISTRY_FOR_REFERENCE, new ArrayList()); + effectServiceRegistryURLs = this.filterServiceRegistry(origServiceRegistryURLs); + effectReferenceRegistryURLs = this.filterReferenceRegistry(origReferenceRegistryURLs); + + boolean defaultRegistry = url.getParameter(CommonConstants.DEFAULT_KEY, true); + if (defaultRegistry && effectServiceRegistryURLs.isEmpty() && effectReferenceRegistryURLs.isEmpty()) { + throw new IllegalArgumentException("Illegal registry url. You need to configure parameter " + + REGISTRY_FOR_SERVICE + " or " + REGISTRY_FOR_REFERENCE); + } + Set allURLs = new HashSet(effectServiceRegistryURLs); + allURLs.addAll(effectReferenceRegistryURLs); + Map tmpMap = new HashMap(4); + for (String tmpUrl : allURLs) { + tmpMap.put(tmpUrl, registryFactory.getRegistry(URL.valueOf(tmpUrl))); + } + for (String serviceRegistyURL : effectServiceRegistryURLs) { + serviceRegistries.put(serviceRegistyURL, tmpMap.get(serviceRegistyURL)); + } + for (String referenceReigstyURL : effectReferenceRegistryURLs) { + referenceRegistries.put(referenceReigstyURL, tmpMap.get(referenceReigstyURL)); + } + } + + + @Override + public URL getUrl() { + return registryUrl; + } + + @Override + public boolean isAvailable() { + boolean available = serviceRegistries.isEmpty() ? true : false; + for (Registry serviceRegistry : serviceRegistries.values()) { + if (serviceRegistry.isAvailable()) { + available = true; + } + } + if (!available) { + return false; + } + + available = referenceRegistries.isEmpty() ? true : false; + for (Registry referenceRegistry : referenceRegistries.values()) { + if (referenceRegistry.isAvailable()) { + available = true; + } + } + if (!available) { + return false; + } + return true; + } + + @Override + public void destroy() { + Set registries = new HashSet(serviceRegistries.values()); + registries.addAll(referenceRegistries.values()); + for (Registry registry : registries) { + registry.destroy(); + } + } + + @Override + public void register(URL url) { + super.register(url); + for (Registry registry : serviceRegistries.values()) { + registry.register(url); + } + } + + @Override + public void unregister(URL url) { + super.unregister(url); + for (Registry registry : serviceRegistries.values()) { + registry.unregister(url); + } + } + + @Override + public void subscribe(URL url, NotifyListener listener) { + MultipleNotifyListenerWrapper multipleNotifyListenerWrapper = new MultipleNotifyListenerWrapper(listener); + multipleNotifyListenerMap.put(listener, multipleNotifyListenerWrapper); + for (Registry registry : referenceRegistries.values()) { + SingleNotifyListener singleNotifyListener = new SingleNotifyListener(multipleNotifyListenerWrapper, registry); + multipleNotifyListenerWrapper.putRegistryMap(registry.getUrl(), singleNotifyListener); + registry.subscribe(url, singleNotifyListener); + } + super.subscribe(url, multipleNotifyListenerWrapper); + } + + @Override + public void unsubscribe(URL url, NotifyListener listener) { + MultipleNotifyListenerWrapper notifyListener = multipleNotifyListenerMap.remove(listener); + for (Registry registry : referenceRegistries.values()) { + SingleNotifyListener singleNotifyListener = notifyListener.registryMap.get(registry.getUrl()); + registry.unsubscribe(url, singleNotifyListener); + } + + if (notifyListener != null) { + super.unsubscribe(url, notifyListener); + notifyListener.destroy(); + } + } + + @Override + public List lookup(URL url) { + List urls = new ArrayList(); + for (Registry registry : referenceRegistries.values()) { + List tmpUrls = registry.lookup(url); + if (!CollectionUtils.isEmpty(tmpUrls)) { + urls.addAll(tmpUrls); + } + } + return urls; + } + + protected void init() { + } + + protected List filterServiceRegistry(List serviceRegistryURLs) { + return serviceRegistryURLs; + } + + protected List filterReferenceRegistry(List referenceRegistryURLs) { + return referenceRegistryURLs; + } + + + protected void checkApplicationName(String applicationName) { + } + + protected String getApplicationName() { + return applicationName; + } + + public Map getServiceRegistries() { + return serviceRegistries; + } + + public Map getReferenceRegistries() { + return referenceRegistries; + } + + public List getOrigServiceRegistryURLs() { + return origServiceRegistryURLs; + } + + public List getOrigReferenceRegistryURLs() { + return origReferenceRegistryURLs; + } + + public List getEffectServiceRegistryURLs() { + return effectServiceRegistryURLs; + } + + public List getEffectReferenceRegistryURLs() { + return effectReferenceRegistryURLs; + } + + static protected class MultipleNotifyListenerWrapper implements NotifyListener { + + Map registryMap = new ConcurrentHashMap(4); + NotifyListener sourceNotifyListener; + + public MultipleNotifyListenerWrapper(NotifyListener sourceNotifyListener) { + this.sourceNotifyListener = sourceNotifyListener; + } + + public void putRegistryMap(URL registryURL, SingleNotifyListener singleNotifyListener) { + this.registryMap.put(registryURL, singleNotifyListener); + } + + public void destroy() { + for (SingleNotifyListener singleNotifyListener : registryMap.values()) { + if (singleNotifyListener != null) { + singleNotifyListener.destroy(); + } + } + registryMap.clear(); + sourceNotifyListener = null; + } + + public synchronized void notifySourceListener() { + List notifyURLs = new ArrayList(); + URL emptyURL = null; + for (SingleNotifyListener singleNotifyListener : registryMap.values()) { + List tmpUrls = singleNotifyListener.getUrlList(); + if (CollectionUtils.isEmpty(tmpUrls)) { + continue; + } + // empty protocol + if (tmpUrls.size() == 1 + && tmpUrls.get(0) != null + && EMPTY_PROTOCOL.equals(tmpUrls.get(0).getProtocol())) { + // if only one empty + if (emptyURL == null) { + emptyURL = tmpUrls.get(0); + } + continue; + } + notifyURLs.addAll(tmpUrls); + } + // if no notify URL, add empty protocol URL + if (emptyURL != null && notifyURLs.isEmpty()) { + notifyURLs.add(emptyURL); + } + this.notify(notifyURLs); + } + + @Override + public void notify(List urls) { + sourceNotifyListener.notify(urls); + } + + public Map getRegistryMap() { + return registryMap; + } + } + + static protected class SingleNotifyListener implements NotifyListener { + + MultipleNotifyListenerWrapper multipleNotifyListenerWrapper; + Registry registry; + volatile List urlList; + + public SingleNotifyListener(MultipleNotifyListenerWrapper multipleNotifyListenerWrapper, Registry registry) { + this.registry = registry; + this.multipleNotifyListenerWrapper = multipleNotifyListenerWrapper; + } + + @Override + public synchronized void notify(List urls) { + this.urlList = urls; + if (multipleNotifyListenerWrapper != null) { + this.multipleNotifyListenerWrapper.notifySourceListener(); + } + } + + public void destroy() { + this.multipleNotifyListenerWrapper = null; + this.registry = null; + } + + public List getUrlList() { + return urlList; + } + } +} diff --git a/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistryFactory.java b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistryFactory.java new file mode 100644 index 0000000000..69d695b235 --- /dev/null +++ b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleRegistryFactory.java @@ -0,0 +1,33 @@ +/* + * 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.registry.multiple; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.support.AbstractRegistryFactory; + +/** + * MultipleRegistryFactory + */ +public class MultipleRegistryFactory extends AbstractRegistryFactory { + + @Override + protected Registry createRegistry(URL url) { + return new MultipleRegistry(url); + } + +} diff --git a/dubbo-registry/dubbo-registry-multiple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory b/dubbo-registry/dubbo-registry-multiple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory new file mode 100644 index 0000000000..defb7a27a0 --- /dev/null +++ b/dubbo-registry/dubbo-registry-multiple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory @@ -0,0 +1 @@ +multiple=org.apache.dubbo.registry.multiple.MultipleRegistryFactory diff --git a/dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistry2S2RTest.java b/dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistry2S2RTest.java new file mode 100644 index 0000000000..cfc15b2df9 --- /dev/null +++ b/dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistry2S2RTest.java @@ -0,0 +1,206 @@ +/* + * 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.registry.multiple; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.registry.NotifyListener; +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.redis.RedisRegistry; +import org.apache.dubbo.registry.zookeeper.ZookeeperRegistry; +import org.apache.dubbo.remoting.zookeeper.ZookeeperClient; +import org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient; + +import org.apache.curator.test.TestingServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import redis.embedded.RedisServer; + +import java.util.ArrayList; +import java.util.List; + +/** + * 2019-04-30 + */ +public class MultipleRegistry2S2RTest { + + private static final String SERVICE_NAME = "org.apache.dubbo.registry.MultipleService2S2R"; + private static final String SERVICE2_NAME = "org.apache.dubbo.registry.MultipleService2S2R2"; + + private static TestingServer zkServer; + private static RedisServer redisServer; + static int zkServerPort; + static int redisServerPort; + + private static String zookeeperRegistryURLStr; + private static String redisRegistryURLStr; + + private static MultipleRegistry multipleRegistry; + // for test content + private static ZookeeperClient zookeeperClient; + + private static ZookeeperRegistry zookeeperRegistry; + private static RedisRegistry redisRegistry; + + + @BeforeAll + public static void setUp() throws Exception { + zkServerPort = NetUtils.getAvailablePort(); + zkServer = new TestingServer(zkServerPort, true); + zookeeperRegistryURLStr = "zookeeper://127.0.0.1:" + zkServerPort; + + redisServerPort = NetUtils.getAvailablePort(); + redisServer = new RedisServer(redisServerPort); + redisServer.start(); + redisRegistryURLStr = "redis://127.0.0.1:" + redisServerPort; + + + URL url = URL.valueOf("multiple://127.0.0.1?application=vic&" + + MultipleRegistry.REGISTRY_FOR_SERVICE + "=" + zookeeperRegistryURLStr + "," + redisRegistryURLStr + "&" + + MultipleRegistry.REGISTRY_FOR_REFERENCE + "=" + zookeeperRegistryURLStr + "," + redisRegistryURLStr); + multipleRegistry = (MultipleRegistry) new MultipleRegistryFactory().createRegistry(url); + + // for test validation + zookeeperClient = new CuratorZookeeperClient(URL.valueOf(zookeeperRegistryURLStr)); + zookeeperRegistry = MultipleRegistryTestUtil.getZookeeperRegistry(multipleRegistry.getServiceRegistries().values()); + redisRegistry = MultipleRegistryTestUtil.getRedisRegistry(multipleRegistry.getServiceRegistries().values()); + } + + @AfterAll + public static void tearDown() throws Exception { + zkServer.stop(); + redisServer.stop(); + } + + @Test + public void testParamConfig() { + + Assertions.assertTrue(multipleRegistry.origReferenceRegistryURLs.size() == 2); + Assertions.assertTrue(multipleRegistry.origReferenceRegistryURLs.contains(zookeeperRegistryURLStr)); + Assertions.assertTrue(multipleRegistry.origReferenceRegistryURLs.contains(redisRegistryURLStr)); + + Assertions.assertTrue(multipleRegistry.origServiceRegistryURLs.size() == 2); + Assertions.assertTrue(multipleRegistry.origServiceRegistryURLs.contains(zookeeperRegistryURLStr)); + Assertions.assertTrue(multipleRegistry.origServiceRegistryURLs.contains(redisRegistryURLStr)); + + Assertions.assertTrue(multipleRegistry.effectReferenceRegistryURLs.size() == 2); + Assertions.assertTrue(multipleRegistry.effectReferenceRegistryURLs.contains(zookeeperRegistryURLStr)); + Assertions.assertTrue(multipleRegistry.effectReferenceRegistryURLs.contains(redisRegistryURLStr)); + + Assertions.assertTrue(multipleRegistry.effectServiceRegistryURLs.size() == 2); + Assertions.assertTrue(multipleRegistry.effectServiceRegistryURLs.contains(zookeeperRegistryURLStr)); + Assertions.assertTrue(multipleRegistry.effectServiceRegistryURLs.contains(redisRegistryURLStr)); + + Assertions.assertTrue(multipleRegistry.getServiceRegistries().containsKey(zookeeperRegistryURLStr)); + Assertions.assertTrue(multipleRegistry.getServiceRegistries().containsKey(redisRegistryURLStr)); + Assertions.assertTrue(multipleRegistry.getServiceRegistries().values().size() == 2); +// java.util.Iterator registryIterable = multipleRegistry.getServiceRegistries().values().iterator(); +// Registry firstRegistry = registryIterable.next(); +// Registry secondRegistry = registryIterable.next(); + Assertions.assertNotNull(MultipleRegistryTestUtil.getZookeeperRegistry(multipleRegistry.getServiceRegistries().values())); + Assertions.assertNotNull(MultipleRegistryTestUtil.getRedisRegistry(multipleRegistry.getServiceRegistries().values())); + Assertions.assertNotNull(MultipleRegistryTestUtil.getZookeeperRegistry(multipleRegistry.getReferenceRegistries().values())); + Assertions.assertNotNull(MultipleRegistryTestUtil.getRedisRegistry(multipleRegistry.getReferenceRegistries().values())); + + Assertions.assertEquals(MultipleRegistryTestUtil.getZookeeperRegistry(multipleRegistry.getServiceRegistries().values()), + MultipleRegistryTestUtil.getZookeeperRegistry(multipleRegistry.getReferenceRegistries().values())); + + Assertions.assertEquals(MultipleRegistryTestUtil.getRedisRegistry(multipleRegistry.getServiceRegistries().values()), + MultipleRegistryTestUtil.getRedisRegistry(multipleRegistry.getReferenceRegistries().values())); + + Assertions.assertEquals(multipleRegistry.getApplicationName(), "vic"); + + Assertions.assertTrue(multipleRegistry.isAvailable()); + } + + @Test + public void testRegistryAndUnRegistry() throws InterruptedException { + URL serviceUrl = URL.valueOf("http2://multiple/" + SERVICE_NAME + "?notify=false&methods=test1,test2&category=providers"); +// URL serviceUrl2 = URL.valueOf("http2://multiple2/" + SERVICE_NAME + "?notify=false&methods=test1,test2&category=providers"); + multipleRegistry.register(serviceUrl); + + String path = "/dubbo/" + SERVICE_NAME + "/providers"; + List providerList = zookeeperClient.getChildren(path); + Assertions.assertTrue(!providerList.isEmpty()); + System.out.println(providerList.get(0)); + + Assertions.assertNotNull(MultipleRegistryTestUtil.getRedisHashContent(redisServerPort, path, serviceUrl.toFullString())); + + final List list = new ArrayList(); + multipleRegistry.subscribe(serviceUrl, new NotifyListener() { + @Override + public void notify(List urls) { + System.out.println("invoke notify: " + urls); + list.clear(); + list.addAll(urls); + } + }); + Thread.sleep(1500); + Assertions.assertTrue(list.size() == 2); + + multipleRegistry.unregister(serviceUrl); + Thread.sleep(1500); + Assertions.assertTrue(list.size() == 1); + List urls = MultipleRegistryTestUtil.getProviderURLsFromNotifyURLS(list); + Assertions.assertTrue(list.size() == 1); + Assertions.assertTrue("empty".equals(list.get(0).getProtocol())); + } + + @Test + public void testSubscription() throws InterruptedException { + URL serviceUrl = URL.valueOf("http2://multiple/" + SERVICE2_NAME + "?notify=false&methods=test1,test2&category=providers"); +// URL serviceUrl2 = URL.valueOf("http2://multiple2/" + SERVICE_NAME + "?notify=false&methods=test1,test2&category=providers"); + multipleRegistry.register(serviceUrl); + + String path = "/dubbo/" + SERVICE2_NAME + "/providers"; + List providerList = zookeeperClient.getChildren(path); + Assertions.assertTrue(!providerList.isEmpty()); + System.out.println(providerList.get(0)); + + Assertions.assertNotNull(MultipleRegistryTestUtil.getRedisHashContent(redisServerPort, path, serviceUrl.toFullString())); + + final List list = new ArrayList(); + multipleRegistry.subscribe(serviceUrl, new NotifyListener() { + @Override + public void notify(List urls) { + System.out.println("invoke notify: " + urls); + list.clear(); + list.addAll(urls); + } + }); + Thread.sleep(1500); + Assertions.assertTrue(list.size() == 2); + + List serviceRegistries = new ArrayList(multipleRegistry.getServiceRegistries().values()); + serviceRegistries.get(0).unregister(serviceUrl); + Thread.sleep(1500); + Assertions.assertTrue(list.size() == 1); + List urls = MultipleRegistryTestUtil.getProviderURLsFromNotifyURLS(list); + Assertions.assertTrue(list.size() == 1); + Assertions.assertTrue(!"empty".equals(list.get(0).getProtocol())); + + serviceRegistries.get(1).unregister(serviceUrl); + Thread.sleep(1500); + Assertions.assertTrue(list.size() == 1); + urls = MultipleRegistryTestUtil.getProviderURLsFromNotifyURLS(list); + Assertions.assertTrue(list.size() == 1); + Assertions.assertTrue("empty".equals(list.get(0).getProtocol())); + } + +} diff --git a/dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistryTestUtil.java b/dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistryTestUtil.java new file mode 100644 index 0000000000..2c70a83355 --- /dev/null +++ b/dubbo-registry/dubbo-registry-multiple/src/test/java/org/apache/dubbo/registry/multiple/MultipleRegistryTestUtil.java @@ -0,0 +1,138 @@ +/* + * 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.registry.multiple; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.common.utils.UrlUtils; +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.redis.RedisRegistry; +import org.apache.dubbo.registry.zookeeper.ZookeeperRegistry; +import org.apache.dubbo.rpc.RpcException; + +import redis.clients.jedis.Jedis; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.apache.dubbo.common.constants.RegistryConstants.APP_DYNAMIC_CONFIGURATORS_CATEGORY; +import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.COMPATIBLE_CONFIG_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY; +import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY; +import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_CONFIGURATORS_CATEGORY; +import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY; +import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY; +import static org.apache.dubbo.common.constants.RegistryConstants.ROUTE_PROTOCOL; + +/** + * 2019-05-13 + */ +public class MultipleRegistryTestUtil { + public static ZookeeperRegistry getZookeeperRegistry(Collection registryCollection) { + for (Registry registry : registryCollection) { + if (registry instanceof ZookeeperRegistry) { + return (ZookeeperRegistry) registry; + } + } + return null; + } + + public static RedisRegistry getRedisRegistry(Collection registryCollection) { + for (Registry registry : registryCollection) { + if (registry instanceof RedisRegistry) { + return (RedisRegistry) registry; + } + } + return null; + } + + public static String getRedisContent(int port, String key) { + Jedis jedis = null; + try { + jedis = new Jedis("127.0.0.1", port); + return jedis.get(key); + } catch (Throwable e) { + throw new RpcException("Failed to put to redis . cause: " + e.getMessage(), e); + } finally { + if (jedis != null) { + jedis.close(); + } + } + } + + public static String getRedisHashContent(int port, String key, String field) { + Jedis jedis = null; + try { + jedis = new Jedis("127.0.0.1", port); + return jedis.hget(key, field); + } catch (Throwable e) { + throw new RpcException("Failed to put to redis . cause: " + e.getMessage(), e); + } finally { + if (jedis != null) { + jedis.close(); + } + } + } + + /** + * copy from @org.apache.dubbo.registry.integration.RegistryDirectory#notify(java.util.List) + * + * @param urls + * @return + */ + public static List getProviderURLsFromNotifyURLS(List urls) { + Map> categoryUrls = urls.stream() + .filter(Objects::nonNull) + .filter(MultipleRegistryTestUtil::isValidCategory) + .filter(MultipleRegistryTestUtil::isNotCompatibleFor26x) + .collect(Collectors.groupingBy(url -> { + if (UrlUtils.isConfigurator(url)) { + return CONFIGURATORS_CATEGORY; + } else if (UrlUtils.isRoute(url)) { + return ROUTERS_CATEGORY; + } else if (UrlUtils.isProvider(url)) { + return PROVIDERS_CATEGORY; + } + return ""; + })); + + // providers + List providerURLs = categoryUrls.getOrDefault(PROVIDERS_CATEGORY, Collections.emptyList()); + return providerURLs; + + } + + private static boolean isValidCategory(URL url) { + String category = url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY); + if ((ROUTERS_CATEGORY.equals(category) || ROUTE_PROTOCOL.equals(url.getProtocol())) || + PROVIDERS_CATEGORY.equals(category) || + CONFIGURATORS_CATEGORY.equals(category) || DYNAMIC_CONFIGURATORS_CATEGORY.equals(category) || + APP_DYNAMIC_CONFIGURATORS_CATEGORY.equals(category)) { + return true; + } + return false; + } + + private static boolean isNotCompatibleFor26x(URL url) { + return StringUtils.isEmpty(url.getParameter(COMPATIBLE_CONFIG_KEY)); + } +} diff --git a/dubbo-registry/pom.xml b/dubbo-registry/pom.xml index 962148b354..32db5d495a 100644 --- a/dubbo-registry/pom.xml +++ b/dubbo-registry/pom.xml @@ -37,6 +37,7 @@ dubbo-registry-consul dubbo-registry-etcd3 dubbo-registry-nacos + dubbo-registry-multiple dubbo-registry-sofa