diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml index 5c2936e7ccd..050ae247471 100644 --- a/dubbo-all/pom.xml +++ b/dubbo-all/pom.xml @@ -981,6 +981,14 @@ + + + + META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter + + + diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java index 436f0dce5b2..2a69f6efb5b 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java @@ -27,9 +27,9 @@ import java.util.Map; import java.util.Optional; -import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY; import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL; +import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY; /** * Configurator. (SPI, Prototype, ThreadSafe) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java index e605643b6a1..6ab3a897262 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java @@ -35,10 +35,12 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY; import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE; @@ -55,6 +57,8 @@ import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY; import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.common.convert.Converter.convertIfPossible; +import static org.apache.dubbo.common.utils.StringUtils.isBlank; /** * URL - Uniform Resource Locator (Immutable, ThreadSafe) @@ -566,6 +570,24 @@ public Map getParameters() { return parameters; } + /** + * Get the parameters to be selected(filtered) + * + * @param nameToSelect the {@link Predicate} to select the parameter name + * @return non-null {@link Map} + * @since 2.7.8 + */ + public Map getParameters(Predicate nameToSelect) { + Map selectedParameters = new LinkedHashMap<>(); + for (Map.Entry entry : getParameters().entrySet()) { + String name = entry.getKey(); + if (nameToSelect.test(name)) { + selectedParameters.put(name, entry.getValue()); + } + } + return Collections.unmodifiableMap(selectedParameters); + } + public Map> getMethodParameters() { return methodParameters; } @@ -601,6 +623,41 @@ public List getParameter(String key, List defaultValue) { return Arrays.asList(strArray); } + /** + * Get parameter + * + * @param key the key of parameter + * @param valueType the type of parameter value + * @param the type of parameter value + * @return get the parameter if present, or null + * @since 2.7.8 + */ + public T getParameter(String key, Class valueType) { + return getParameter(key, valueType, null); + } + + /** + * Get parameter + * + * @param key the key of parameter + * @param valueType the type of parameter value + * @param defaultValue the default value if parameter is absent + * @param the type of parameter value + * @return get the parameter if present, or defaultValue will be used. + * @since 2.7.8 + */ + public T getParameter(String key, Class valueType, T defaultValue) { + String value = getParameter(key); + T result = null; + if (!isBlank(value)) { + result = convertIfPossible(value, valueType); + } + if (result == null) { + result = defaultValue; + } + return result; + } + private Map getNumbers() { // concurrent initialization is tolerant if (numbers == null) { @@ -1415,7 +1472,7 @@ public String getColonSeparatedKey() { private void append(StringBuilder target, String parameterName, boolean first) { String parameterValue = this.getParameter(parameterName); - if (!StringUtils.isBlank(parameterValue)) { + if (!isBlank(parameterValue)) { if (!first) { target.append(":"); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfiguration.java index 6e85982a19d..31c3684fa3a 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfiguration.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfiguration.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.NamedThreadFactory; +import org.apache.dubbo.common.utils.StringUtils; import java.util.concurrent.Callable; import java.util.concurrent.Future; @@ -27,6 +28,9 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY; + /** * The abstract implementation of {@link DynamicConfiguration} * @@ -47,6 +51,20 @@ public abstract class AbstractDynamicConfiguration implements DynamicConfigurati */ public static final String THREAD_POOL_KEEP_ALIVE_TIME_PARAM_NAME = PARAM_NAME_PREFIX + "thread-pool.keep-alive-time"; + /** + * The parameter name of group for config-center + * + * @since 2.7.8 + */ + public static final String GROUP_PARAM_NAME = PARAM_NAME_PREFIX + GROUP_KEY; + + /** + * The parameter name of timeout for config-center + * + * @since 2.7.8 + */ + public static final String TIMEOUT_PARAM_NAME = PARAM_NAME_PREFIX + TIMEOUT_KEY; + public static final int DEFAULT_THREAD_POOL_SIZE = 1; /** @@ -64,28 +82,31 @@ public abstract class AbstractDynamicConfiguration implements DynamicConfigurati */ private final ThreadPoolExecutor workersThreadPool; - public AbstractDynamicConfiguration() { - this(DEFAULT_THREAD_POOL_PREFIX, DEFAULT_THREAD_POOL_SIZE, DEFAULT_THREAD_POOL_KEEP_ALIVE_TIME); - } + private final String group; + + private final long timeout; public AbstractDynamicConfiguration(URL url) { - this(getThreadPoolPrefixName(url), getThreadPoolSize(url), getThreadPoolKeepAliveTime(url)); + this(getThreadPoolPrefixName(url), getThreadPoolSize(url), getThreadPoolKeepAliveTime(url), getGroup(url), + getTimeout(url)); } public AbstractDynamicConfiguration(String threadPoolPrefixName, int threadPoolSize, - long keepAliveTime) { + long keepAliveTime, + String group, + long timeout) { this.workersThreadPool = initWorkersThreadPool(threadPoolPrefixName, threadPoolSize, keepAliveTime); + this.group = group; + this.timeout = timeout; } @Override public void addListener(String key, String group, ConfigurationListener listener) { - } @Override public void removeListener(String key, String group, ConfigurationListener listener) { - } @Override @@ -107,6 +128,29 @@ public final void close() throws Exception { } } + @Override + public boolean removeConfig(String key, String group) { + return execute(() -> doRemoveConfig(key, group), -1L); + } + + /** + * @return the default group + * @since 2.7.8 + */ + @Override + public String getDefaultGroup() { + return getGroup(); + } + + /** + * @return the default timeout + * @since 2.7.8 + */ + @Override + public long getDefaultTimeout() { + return getTimeout(); + } + /** * Get the content of configuration in the specified key and group * @@ -124,6 +168,17 @@ public final void close() throws Exception { */ protected abstract void doClose() throws Exception; + /** + * Remove the config in the specified key and group + * + * @param key the key + * @param group the group + * @return If successful, return true, or false + * @throws Exception + * @since 2.7.8 + */ + protected abstract boolean doRemoveConfig(String key, String group) throws Exception; + /** * Executes the {@link Runnable} with the specified timeout * @@ -181,7 +236,7 @@ protected ThreadPoolExecutor initWorkersThreadPool(String threadPoolPrefixName, int threadPoolSize, long keepAliveTime) { return new ThreadPoolExecutor(threadPoolSize, threadPoolSize, keepAliveTime, - TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory(threadPoolPrefixName)); + TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory(threadPoolPrefixName, true)); } protected static String getThreadPoolPrefixName(URL url) { @@ -216,4 +271,36 @@ protected static long getParameter(URL url, String name, long defaultValue) { } return defaultValue; } + + + protected String getGroup() { + return group; + } + + protected long getTimeout() { + return timeout; + } + + /** + * Get the group from {@link URL the specified connection URL} + * + * @param url {@link URL the specified connection URL} + * @return non-null + * @since 2.7.8 + */ + protected static String getGroup(URL url) { + String group = getParameter(url, GROUP_PARAM_NAME, null); + return StringUtils.isBlank(group) ? getParameter(url, GROUP_KEY, DEFAULT_GROUP) : group; + } + + /** + * Get the timeout from {@link URL the specified connection URL} + * + * @param url {@link URL the specified connection URL} + * @return non-null + * @since 2.7.8 + */ + protected static long getTimeout(URL url) { + return getParameter(url, TIMEOUT_PARAM_NAME, -1L); + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfigurationFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfigurationFactory.java index eb35b9bec04..db53e7317fb 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfigurationFactory.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfigurationFactory.java @@ -35,7 +35,7 @@ public abstract class AbstractDynamicConfigurationFactory implements DynamicConf @Override public final DynamicConfiguration getDynamicConfiguration(URL url) { - String key = url == null ? DEFAULT_KEY : url.getAddress(); + String key = url == null ? DEFAULT_KEY : url.toServiceString(); return dynamicConfigurations.computeIfAbsent(key, k -> createDynamicConfiguration(url)); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java index 5cda5bf428c..0b573966a1b 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java @@ -232,4 +232,14 @@ static DynamicConfiguration getDynamicConfiguration(URL connectionURL) { static String getRuleKey(URL url) { return url.getColonSeparatedKey(); } + + /** + * @param key the key to represent a configuration + * @param group the group where the key belongs to + * @return true if success, or false + * @since 2.7.8 + */ + default boolean removeConfig(String key, String group) { + return true; + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/TreePathDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/TreePathDynamicConfiguration.java new file mode 100644 index 00000000000..cbcb3a2f4e1 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/TreePathDynamicConfiguration.java @@ -0,0 +1,171 @@ +/* + * 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.common.config.configcenter; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfiguration; +import org.apache.dubbo.common.utils.PathUtils; +import org.apache.dubbo.common.utils.StringUtils; + +import java.util.Collection; +import java.util.SortedSet; +import java.util.TreeSet; + +import static java.util.Collections.emptySortedSet; +import static java.util.Collections.unmodifiableSortedSet; +import static org.apache.dubbo.common.config.configcenter.Constants.CONFIG_NAMESPACE_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR; +import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty; +import static org.apache.dubbo.common.utils.PathUtils.buildPath; + +/** + * An abstract implementation of {@link DynamicConfiguration} is like "tree-structure" path : + *
    + *
  • {@link FileSystemDynamicConfiguration "file"}
  • + *
  • {@link org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfiguration "zookeeper"}
  • + *
  • {@link org.apache.dubbo.configcenter.consul.ConsulDynamicConfiguration "consul"}
  • + *
+ * + * @see DynamicConfiguration + * @see AbstractDynamicConfiguration + * @since 2.7.8 + */ +public abstract class TreePathDynamicConfiguration extends AbstractDynamicConfiguration { + + /** + * The parameter name of URL for the config base path + */ + public static final String CONFIG_BASE_PATH_PARAM_NAME = PARAM_NAME_PREFIX + "base-path"; + + /** + * The default value of parameter of URL for the config base path + */ + public static final String DEFAULT_CONFIG_BASE_PATH = "/config"; + + private final String rootPath; + + public TreePathDynamicConfiguration(URL url) { + super(url); + this.rootPath = getRootPath(url); + } + + public TreePathDynamicConfiguration(String rootPath, + String threadPoolPrefixName, + int threadPoolSize, + long keepAliveTime, + String group, + long timeout) { + super(threadPoolPrefixName, threadPoolSize, keepAliveTime, group, timeout); + this.rootPath = rootPath; + } + + @Override + protected final String doGetConfig(String key, String group) throws Exception { + String pathKey = buildPathKey(group, key); + return doGetConfig(pathKey); + } + + @Override + public final boolean publishConfig(String key, String group, String content) { + String pathKey = buildPathKey(group, key); + return execute(() -> doPublishConfig(pathKey, content), getDefaultTimeout()); + } + + @Override + protected final boolean doRemoveConfig(String key, String group) throws Exception { + String pathKey = buildPathKey(group, key); + return doRemoveConfig(pathKey); + } + + @Override + public final void addListener(String key, String group, ConfigurationListener listener) { + String pathKey = buildPathKey(group, key); + doAddListener(pathKey, listener); + } + + @Override + public final void removeListener(String key, String group, ConfigurationListener listener) { + String pathKey = buildPathKey(group, key); + doRemoveListener(pathKey, listener); + } + + @Override + public final SortedSet getConfigKeys(String group) throws UnsupportedOperationException { + String groupPath = buildGroupPath(group); + Collection configKeys = doGetConfigKeys(groupPath); + return isEmpty(configKeys) ? emptySortedSet() : unmodifiableSortedSet(new TreeSet<>(configKeys)); + } + + protected abstract boolean doPublishConfig(String pathKey, String content) throws Exception; + + protected abstract String doGetConfig(String pathKey) throws Exception; + + protected abstract boolean doRemoveConfig(String pathKey) throws Exception; + + protected abstract Collection doGetConfigKeys(String groupPath); + + protected abstract void doAddListener(String pathKey, ConfigurationListener listener); + + protected abstract void doRemoveListener(String pathKey, ConfigurationListener listener); + + protected String buildGroupPath(String group) { + return buildPath(rootPath, group); + } + + protected String buildPathKey(String group, String key) { + return buildPath(buildGroupPath(group), key); + } + + /** + * Get the root path from the specified {@link URL connection URl} + * + * @param url the specified {@link URL connection URl} + * @return non-null + */ + protected String getRootPath(URL url) { + String rootPath = PATH_SEPARATOR + getConfigNamespace(url) + getConfigBasePath(url); + rootPath = PathUtils.normalize(rootPath); + if (rootPath.endsWith(PATH_SEPARATOR)) { + rootPath = rootPath.substring(0, rootPath.length() - 1); + } + return rootPath; + } + + /** + * Get the namespace from the specified {@link URL connection URl} + * + * @param url the specified {@link URL connection URl} + * @return non-null + */ + protected String getConfigNamespace(URL url) { + return url.getParameter(CONFIG_NAMESPACE_KEY, DEFAULT_GROUP); + } + + /** + * Get the config base path from the specified {@link URL connection URl} + * + * @param url the specified {@link URL connection URl} + * @return non-null + */ + protected String getConfigBasePath(URL url) { + String configBasePath = url.getParameter(CONFIG_BASE_PATH_PARAM_NAME, DEFAULT_CONFIG_BASE_PATH); + if (StringUtils.isNotEmpty(configBasePath) && !configBasePath.startsWith(PATH_SEPARATOR)) { + configBasePath = PATH_SEPARATOR + configBasePath; + } + return configBasePath; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java index 36fb61f913b..0c9178f359d 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java @@ -17,13 +17,14 @@ package org.apache.dubbo.common.config.configcenter.file; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration; import org.apache.dubbo.common.config.configcenter.ConfigChangeType; import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent; import org.apache.dubbo.common.config.configcenter.ConfigurationListener; import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; +import org.apache.dubbo.common.config.configcenter.TreePathDynamicConfiguration; import org.apache.dubbo.common.function.ThrowableConsumer; import org.apache.dubbo.common.function.ThrowableFunction; +import org.apache.dubbo.common.lang.ShutdownHookCallbacks; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.common.utils.StringUtils; @@ -39,6 +40,7 @@ import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; @@ -48,7 +50,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.Callable; import java.util.concurrent.SynchronousQueue; @@ -67,14 +68,13 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.apache.commons.io.FileUtils.readFileToString; -import static org.apache.dubbo.common.utils.StringUtils.isBlank; /** * File-System based {@link DynamicConfiguration} implementation * * @since 2.7.5 */ -public class FileSystemDynamicConfiguration extends AbstractDynamicConfiguration { +public class FileSystemDynamicConfiguration extends TreePathDynamicConfiguration { public static final String CONFIG_CENTER_DIR_PARAM_NAME = PARAM_NAME_PREFIX + "dir"; @@ -147,6 +147,7 @@ public class FileSystemDynamicConfiguration extends AbstractDynamicConfiguration MODIFIERS = initWatchEventModifiers(); DELAY = initDelay(MODIFIERS); WATCH_EVENTS_LOOP_THREAD_POOL = newWatchEventsLoopThreadPool(); + registerDubboShutdownHook(); } /** @@ -193,7 +194,7 @@ public FileSystemDynamicConfiguration(File rootDirectory, String encoding, String threadPoolPrefixName, int threadPoolSize, long keepAliveTime) { - super(threadPoolPrefixName, threadPoolSize, keepAliveTime); + super(rootDirectory.getAbsolutePath(), threadPoolPrefixName, threadPoolSize, keepAliveTime, DEFAULT_GROUP, -1L); this.rootDirectory = rootDirectory; this.encoding = encoding; this.processingDirectories = initProcessingDirectories(); @@ -209,47 +210,13 @@ private Set initProcessingDirectories() { return isBasedPoolingWatchService() ? new LinkedHashSet<>() : emptySet(); } - @Override - public void addListener(String key, String group, ConfigurationListener listener) { - doInListener(key, group, (configFilePath, listeners) -> { - - if (listeners.isEmpty()) { // If no element, it indicates watchService was registered before - ThrowableConsumer.execute(configFilePath, configFile -> { - FileUtils.forceMkdirParent(configFile); - // A rootDirectory to be watched - File configDirectory = configFile.getParentFile(); - if (configDirectory != null) { - // Register the configDirectory - configDirectory.toPath().register(watchService.get(), INTEREST_PATH_KINDS, MODIFIERS); - } - }); - } - - // Add into cache - listeners.add(listener); - }); - } - - @Override - public void removeListener(String key, String group, ConfigurationListener listener) { - doInListener(key, group, (file, listeners) -> { - // Remove into cache - listeners.remove(listener); - }); - } - - public File groupDirectory(String group) { - String actualGroup = isBlank(group) ? DEFAULT_GROUP : group; - return new File(rootDirectory, actualGroup); - } - public File configFile(String key, String group) { - return new File(groupDirectory(group), key); + return new File(buildPathKey(group, key)); } - private void doInListener(String key, String group, BiConsumer> consumer) { + private void doInListener(String configFilePath, BiConsumer> consumer) { watchService.ifPresent(watchService -> { - File configFile = configFile(key, group); + File configFile = new File(configFilePath); executeMutually(configFile.getParentFile(), () -> { // process the WatchEvents if not start if (!isProcessingWatchEvents()) { @@ -265,6 +232,24 @@ private void doInListener(String key, String group, BiConsumer { + watchService.ifPresent(w -> { + try { + w.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + getWatchEventsLoopThreadPool().shutdown(); + }); + } + private static boolean isProcessingWatchEvents() { return getWatchEventsLoopThreadPool().getActiveCount() > 0; } @@ -359,47 +344,78 @@ public Object getInternalProperty(String key) { } @Override - public boolean publishConfig(String key, String group, String content) { - return delay(key, group, configFile -> { + protected boolean doPublishConfig(String pathKey, String content) throws Exception { + return delay(pathKey, configFile -> { FileUtils.write(configFile, content, getEncoding()); return true; }); } @Override - public SortedSet getConfigKeys(String group) { - File[] files = groupDirectory(group).listFiles(File::isFile); + protected String doGetConfig(String pathKey) throws Exception { + File configFile = new File(pathKey); + return getConfig(configFile); + } + + @Override + protected boolean doRemoveConfig(String pathKey) throws Exception { + delay(pathKey, configFile -> { + String content = getConfig(configFile); + FileUtils.deleteQuietly(configFile); + return content; + }); + return true; + } + + @Override + protected Collection doGetConfigKeys(String groupPath) { + File[] files = new File(groupPath).listFiles(File::isFile); if (files == null) { return new TreeSet<>(); } else { return Stream.of(files) .map(File::getName) - .collect(TreeSet::new, Set::add, Set::addAll); + .collect(Collectors.toList()); } } - public String removeConfig(String key, String group) { - return delay(key, group, configFile -> { - - String content = getConfig(configFile); - - FileUtils.deleteQuietly(configFile); + @Override + protected void doAddListener(String pathKey, ConfigurationListener listener) { + doInListener(pathKey, (configFilePath, listeners) -> { + if (listeners.isEmpty()) { // If no element, it indicates watchService was registered before + ThrowableConsumer.execute(configFilePath, configFile -> { + FileUtils.forceMkdirParent(configFile); + // A rootDirectory to be watched + File configDirectory = configFile.getParentFile(); + if (configDirectory != null) { + // Register the configDirectory + configDirectory.toPath().register(watchService.get(), INTEREST_PATH_KINDS, MODIFIERS); + } + }); + } + // Add into cache + listeners.add(listener); + }); + } - return content; + @Override + protected void doRemoveListener(String pathKey, ConfigurationListener listener) { + doInListener(pathKey, (file, listeners) -> { + // Remove into cache + listeners.remove(listener); }); } /** * Delay action for {@link #configFile(String, String) config file} * - * @param key the key to represent a configuration - * @param group the group where the key belongs to - * @param function the customized {@link Function function} with {@link File} - * @param the computed value + * @param configFilePath the key to represent a configuration + * @param function the customized {@link Function function} with {@link File} + * @param the computed value * @return */ - protected V delay(String key, String group, ThrowableFunction function) { - File configFile = configFile(key, group); + protected V delay(String configFilePath, ThrowableFunction function) { + File configFile = new File(configFilePath); // Must be based on PoolingWatchService and has listeners under config file if (isBasedPoolingWatchService()) { File configDirectory = configFile.getParentFile(); @@ -410,8 +426,8 @@ protected V delay(String key, String group, ThrowableFunction funct // wait for delay in seconds long timeout = SECONDS.toMillis(delay); if (logger.isDebugEnabled()) { - logger.debug(format("The config[key : %s, group : %s] is about to delay in %d ms.", - key, group, timeout)); + logger.debug(format("The config[path : %s] is about to delay in %d ms.", + configFilePath, timeout)); } configDirectory.wait(timeout); } @@ -439,9 +455,9 @@ private boolean hasListeners(File configFile) { } /** - * Is processing on {@link #groupDirectory(String) config rootDirectory} + * Is processing on {@link #buildGroupPath(String) config rootDirectory} * - * @param configDirectory {@link #groupDirectory(String) config rootDirectory} + * @param configDirectory {@link #buildGroupPath(String) config rootDirectory} * @return if processing , return true, or false */ private boolean isProcessing(File configDirectory) { @@ -459,12 +475,6 @@ public Set getConfigGroups() { .collect(Collectors.toSet()); } - @Override - protected String doGetConfig(String key, String group) throws Exception { - File configFile = configFile(key, group); - return getConfig(configFile); - } - protected String getConfig(File configFile) { return ThrowableFunction.execute(configFile, file -> canRead(configFile) ? readFileToString(configFile, getEncoding()) : null); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java index eca3495d91d..657c1ab517b 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.URL; import java.net.NetworkInterface; +import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.regex.Pattern; @@ -44,6 +45,11 @@ public interface CommonConstants { String ANY_VALUE = "*"; + /** + * @since 2.7.8 + */ + char COMMA_SEPARATOR_CHAR = ','; + String COMMA_SEPARATOR = ","; String DOT_SEPARATOR = "."; @@ -187,6 +193,14 @@ public interface CommonConstants { String REMOTE_METADATA_STORAGE_TYPE = "remote"; + /** + * The composite metadata storage type includes {@link #DEFAULT_METADATA_STORAGE_TYPE "local"} and + * {@link #REMOTE_METADATA_STORAGE_TYPE "remote"}. + * + * @since 2.7.8 + */ + String COMPOSITE_METADATA_STORAGE_TYPE = "composite"; + /** * Consumer side 's proxy class */ @@ -315,4 +329,19 @@ public interface CommonConstants { String SSL_ENABLED_KEY = "ssl-enabled"; + + /** + * The parameter key for the class path of the ServiceNameMapping {@link Properties} file + * + * @since 2.7.8 + */ + String SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY = "service-name-mapping.properties-path"; + + /** + * The default class path of the ServiceNameMapping {@link Properties} file + * + * @since 2.7.8 + */ + String DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH = "META-INF/dubbo/service-name-mapping.properties"; + } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java index 465c7e35cb0..ce83136b06b 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java @@ -76,6 +76,8 @@ public interface RegistryConstants { /** * The parameter key of the subscribed service names for Service-Oriented Registry + *

+ * If there is a multiple-values, the "comma" is the separator. * * @since 2.7.5 */ diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java index 5bc2d4d809d..e36fdf2324c 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/Converter.java @@ -88,4 +88,21 @@ default Class getTargetType() { .findFirst() .orElse(null); } + + /** + * Convert the value of source to target-type value if possible + * + * @param source the value of source + * @param targetType the target type + * @param the target type + * @return null if can't be converted + * @since 2.7.8 + */ + static T convertIfPossible(Object source, Class targetType) { + Converter converter = getConverter(source.getClass(), targetType); + if (converter != null) { + return (T) converter.convert(source); + } + return null; + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/MultiValueConverter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/MultiValueConverter.java index 298b4594a9b..637d1a8f30e 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/MultiValueConverter.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/convert/multiple/MultiValueConverter.java @@ -16,11 +16,13 @@ */ package org.apache.dubbo.common.convert.multiple; +import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.common.lang.Prioritized; import java.util.Collection; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; import static org.apache.dubbo.common.utils.TypeUtils.findActualTypeArgument; /** @@ -61,4 +63,30 @@ default Class getSourceType() { return findActualTypeArgument(getClass(), MultiValueConverter.class, 0); } + /** + * Find the {@link MultiValueConverter} instance from {@link ExtensionLoader} with the specified source and target type + * + * @param sourceType the source type + * @param targetType the target type + * @return null if not found + * @see ExtensionLoader#getSupportedExtensionInstances() + * @since 2.7.8 + */ + static MultiValueConverter find(Class sourceType, Class targetType) { + return getExtensionLoader(MultiValueConverter.class) + .getSupportedExtensionInstances() + .stream() + .filter(converter -> converter.accept(sourceType, targetType)) + .findFirst() + .orElse(null); + } + + static T convertIfPossible(Object source, Class multiValueType, Class elementType) { + Class sourceType = source.getClass(); + MultiValueConverter converter = find(sourceType, multiValueType); + if (converter != null) { + return (T) converter.convert(source, multiValueType, elementType); + } + return null; + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PathUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PathUtils.java index 3e38ce14b8b..c291d792e65 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PathUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PathUtils.java @@ -63,7 +63,12 @@ static String normalize(String path) { if (index > -1) { normalizedPath = normalizedPath.substring(0, index); } - return replace(normalizedPath, "//", "/"); + + while (normalizedPath.contains("//")) { + normalizedPath = replace(normalizedPath, "//", "/"); + } + + return normalizedPath; } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringConstantFieldValuePredicate.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringConstantFieldValuePredicate.java new file mode 100644 index 00000000000..534a612bfdb --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringConstantFieldValuePredicate.java @@ -0,0 +1,67 @@ +/* + * 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.common.utils; + +import java.lang.reflect.Field; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.lang.reflect.Modifier.isFinal; +import static java.lang.reflect.Modifier.isPublic; +import static java.lang.reflect.Modifier.isStatic; +import static org.apache.dubbo.common.utils.FieldUtils.getFieldValue; + +/** + * The constant field value {@link Predicate} for the specified {@link Class} + * + * @see Predicate + * @since 2.7.8 + */ +public class StringConstantFieldValuePredicate implements Predicate { + + private final Set constantFieldValues; + + public StringConstantFieldValuePredicate(Class targetClass) { + this.constantFieldValues = getConstantFieldValues(targetClass); + } + + public static Predicate of(Class targetClass) { + return new StringConstantFieldValuePredicate(targetClass); + } + + private Set getConstantFieldValues(Class targetClass) { + return Stream.of(targetClass.getFields()) + .filter(f -> isStatic(f.getModifiers())) // static + .filter(f -> isPublic(f.getModifiers())) // public + .filter(f -> isFinal(f.getModifiers())) // final + .map(this::getConstantValue) + .filter(v -> v instanceof String) // filters String type + .map(String.class::cast) // Casts String type + .collect(Collectors.toSet()); + } + + @Override + public boolean test(String s) { + return constantFieldValues.contains(s); + } + + private Object getConstantValue(Field field) { + return getFieldValue(null, field); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java index 42ee05bbe5c..fc444750c57 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java @@ -28,13 +28,17 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import static java.lang.String.valueOf; +import static java.util.Collections.emptySet; +import static java.util.Collections.unmodifiableSet; import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR; import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN; import static org.apache.dubbo.common.constants.CommonConstants.DOT_REGEX; @@ -699,6 +703,45 @@ public static List splitToList(String str, char ch) { return splitToList0(str, ch); } + /** + * Split the specified value to be a {@link Set} + * + * @param value the content to be split + * @param separatorChar a char to separate + * @return non-null read-only {@link Set} + * @since 2.7.8 + */ + public static Set splitToSet(String value, char separatorChar) { + return splitToSet(value, separatorChar, false); + } + + /** + * Split the specified value to be a {@link Set} + * + * @param value the content to be split + * @param separatorChar a char to separate + * @param trimElements require to trim the elements or not + * @return non-null read-only {@link Set} + * @since 2.7.8 + */ + public static Set splitToSet(String value, char separatorChar, boolean trimElements) { + List values = splitToList(value, separatorChar); + int size = values.size(); + + if (size < 1) { // empty condition + return emptySet(); + } + + if (!trimElements) { // Do not require to trim the elements + return new LinkedHashSet(values); + } + + return unmodifiableSet(values + .stream() + .map(String::trim) + .collect(LinkedHashSet::new, Set::add, Set::addAll)); + } + /** * join string. * @@ -797,7 +840,7 @@ private static Map parseKeyValuePair(String str, String itemSepa } public static String getQueryStringValue(String qs, String key) { - Map map = StringUtils.parseQueryString(qs); + Map map = parseQueryString(qs); return map.get(key); } @@ -1051,4 +1094,16 @@ public static byte decodeHexByte(CharSequence s, int pos) { return (byte) ((hi << 4) + lo); } + /** + * Create the common-delimited {@link String} by one or more {@link String} members + * + * @param one one {@link String} + * @param others others {@link String} + * @return null if one or others is null + * @since 2.7.8 + */ + public static String toCommaDelimitedString(String one, String... others) { + String another = arrayToDelimitedString(others, COMMA_SEPARATOR); + return isEmpty(another) ? one : one + COMMA_SEPARATOR + another; + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/DubboReference.java b/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/DubboReference.java index eb1a2e6ead2..5492ac08d90 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/DubboReference.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/DubboReference.java @@ -16,6 +16,8 @@ */ package org.apache.dubbo.config.annotation; +import org.apache.dubbo.common.constants.RegistryConstants; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -279,4 +281,11 @@ * @since 2.7.3 */ String id() default ""; + + /** + * @return The service names that the Dubbo interface subscribed + * @see RegistryConstants#SUBSCRIBED_SERVICE_NAMES_KEY + * @since 2.7.8 + */ + String[] services() default {}; } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java index ed0188aa438..868fadcc973 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java @@ -67,10 +67,10 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt { public static final String NAME = "config"; - private final Map> configsCache = newMap(); - private final ReadWriteLock lock = new ReentrantReadWriteLock(); + final Map> configsCache = newMap(); + public ConfigManager() { } @@ -371,6 +371,15 @@ public void clear() { }); } + /** + * @throws IllegalStateException + * @since 2.7.8 + */ + @Override + public void destroy() throws IllegalStateException { + clear(); + } + /** * Add the dubbo {@link AbstractConfig config} * diff --git a/dubbo-common/src/main/java/org/apache/dubbo/event/EventListener.java b/dubbo-common/src/main/java/org/apache/dubbo/event/EventListener.java index 06c6f6afdf7..bb36c77607d 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/event/EventListener.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/event/EventListener.java @@ -56,7 +56,7 @@ public interface EventListener extends java.util.EventListener, * The comparison rule , refer to {@link #compareTo}. */ default int getPriority() { - return MIN_PRIORITY; + return NORMAL_PRIORITY; } /** diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java index db5f57b1c51..5ba606d5ad7 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java @@ -1,877 +1,900 @@ -/* - * 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.common; - -import org.apache.dubbo.common.utils.CollectionUtils; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.io.File; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import static org.hamcrest.CoreMatchers.anyOf; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -public class URLTest { - - @Test - public void test_valueOf_noProtocolAndHost() throws Exception { - URL url = URL.valueOf("/context/path?version=1.0.0&application=morgan"); - assertURLStrDecoder(url); - assertNull(url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertNull(url.getHost()); - assertNull(url.getAddress()); - assertEquals(0, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - - url = URL.valueOf("context/path?version=1.0.0&application=morgan"); - // ^^^^^^^ Caution , parse as host - assertURLStrDecoder(url); - assertNull(url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertEquals("context", url.getHost()); - assertEquals(0, url.getPort()); - assertEquals("path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - } - - private void assertURLStrDecoder(URL url) { - String fullURLStr = url.toFullString(); - URL newUrl = URLStrParser.parseEncodedStr(URL.encode(fullURLStr)); - assertEquals(URL.valueOf(fullURLStr), newUrl); - - URL newUrl2 = URLStrParser.parseDecodedStr(fullURLStr); - assertEquals(URL.valueOf(fullURLStr), newUrl2); - } - - @Test - public void test_valueOf_noProtocol() throws Exception { - URL url = URL.valueOf("10.20.130.230"); - assertURLStrDecoder(url); - assertNull(url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230", url.getAddress()); - assertEquals(0, url.getPort()); - assertNull(url.getPath()); - assertEquals(0, url.getParameters().size()); - - url = URL.valueOf("10.20.130.230:20880"); - assertURLStrDecoder(url); - assertNull(url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertNull(url.getPath()); - assertEquals(0, url.getParameters().size()); - - url = URL.valueOf("10.20.130.230/context/path"); - assertURLStrDecoder(url); - assertNull(url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230", url.getAddress()); - assertEquals(0, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(0, url.getParameters().size()); - - url = URL.valueOf("10.20.130.230:20880/context/path"); - assertURLStrDecoder(url); - assertNull(url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(0, url.getParameters().size()); - - url = URL.valueOf("admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); - assertURLStrDecoder(url); - assertNull(url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - } - - @Test - public void test_valueOf_noHost() throws Exception { - URL url = URL.valueOf("file:///home/user1/router.js"); - assertURLStrDecoder(url); - assertEquals("file", url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertNull(url.getHost()); - assertNull(url.getAddress()); - assertEquals(0, url.getPort()); - assertEquals("home/user1/router.js", url.getPath()); - assertEquals(0, url.getParameters().size()); - - // Caution!! - url = URL.valueOf("file://home/user1/router.js"); - // ^^ only tow slash! - assertURLStrDecoder(url); - assertEquals("file", url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertEquals("home", url.getHost()); - assertEquals(0, url.getPort()); - assertEquals("user1/router.js", url.getPath()); - assertEquals(0, url.getParameters().size()); - - - url = URL.valueOf("file:/home/user1/router.js"); - assertURLStrDecoder(url); - assertEquals("file", url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertNull(url.getHost()); - assertNull(url.getAddress()); - assertEquals(0, url.getPort()); - assertEquals("home/user1/router.js", url.getPath()); - assertEquals(0, url.getParameters().size()); - - url = URL.valueOf("file:///d:/home/user1/router.js"); - assertURLStrDecoder(url); - assertEquals("file", url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertNull(url.getHost()); - assertNull(url.getAddress()); - assertEquals(0, url.getPort()); - assertEquals("d:/home/user1/router.js", url.getPath()); - assertEquals(0, url.getParameters().size()); - - url = URL.valueOf("file:///home/user1/router.js?p1=v1&p2=v2"); - assertURLStrDecoder(url); - assertEquals("file", url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertNull(url.getHost()); - assertNull(url.getAddress()); - assertEquals(0, url.getPort()); - assertEquals("home/user1/router.js", url.getPath()); - assertEquals(2, url.getParameters().size()); - Map params = new HashMap(); - params.put("p1", "v1"); - params.put("p2", "v2"); - assertEquals(params, url.getParameters()); - - url = URL.valueOf("file:/home/user1/router.js?p1=v1&p2=v2"); - assertURLStrDecoder(url); - assertEquals("file", url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertNull(url.getHost()); - assertNull(url.getAddress()); - assertEquals(0, url.getPort()); - assertEquals("home/user1/router.js", url.getPath()); - assertEquals(2, url.getParameters().size()); - params = new HashMap(); - params.put("p1", "v1"); - params.put("p2", "v2"); - assertEquals(params, url.getParameters()); - } - - @Test - public void test_valueOf_WithProtocolHost() throws Exception { - URL url = URL.valueOf("dubbo://10.20.130.230"); - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230", url.getAddress()); - assertEquals(0, url.getPort()); - assertNull(url.getPath()); - assertEquals(0, url.getParameters().size()); - - url = URL.valueOf("dubbo://10.20.130.230:20880/context/path"); - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertNull(url.getUsername()); - assertNull(url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(0, url.getParameters().size()); - - url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880"); - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertNull(url.getPath()); - assertEquals(0, url.getParameters().size()); - - url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880?version=1.0.0"); - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertNull(url.getPath()); - assertEquals(1, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - - url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - - url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&noValue"); - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(3, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - assertEquals("noValue", url.getParameter("noValue")); - } - - // TODO Do not want to use spaces? See: DUBBO-502, URL class handles special conventions for special characters. - @Test - public void test_valueOf_spaceSafe() throws Exception { - URL url = URL.valueOf("http://1.2.3.4:8080/path?key=value1 value2"); - assertURLStrDecoder(url); - assertEquals("http://1.2.3.4:8080/path?key=value1 value2", url.toString()); - assertEquals("value1 value2", url.getParameter("key")); - } - - @Test - public void test_noValueKey() throws Exception { - URL url = URL.valueOf("http://1.2.3.4:8080/path?k0&k1=v1"); - - assertURLStrDecoder(url); - assertTrue(url.hasParameter("k0")); - - // If a Key has no corresponding Value, then the Key also used as the Value. - assertEquals("k0", url.getParameter("k0")); - } - - @Test - public void test_valueOf_Exception_noProtocol() throws Exception { - try { - URL.valueOf("://1.2.3.4:8080/path"); - fail(); - } catch (IllegalStateException expected) { - assertEquals("url missing protocol: \"://1.2.3.4:8080/path\"", expected.getMessage()); - } - - try { - String encodedURLStr = URL.encode("://1.2.3.4:8080/path"); - URLStrParser.parseEncodedStr(encodedURLStr); - fail(); - } catch (IllegalStateException expected) { - assertEquals("url missing protocol: \"://1.2.3.4:8080/path\"", URL.decode(expected.getMessage())); - } - - try { - URLStrParser.parseDecodedStr("://1.2.3.4:8080/path"); - fail(); - } catch (IllegalStateException expected) { - assertEquals("url missing protocol: \"://1.2.3.4:8080/path\"", expected.getMessage()); - } - } - - @Test - public void test_getAddress() throws Exception { - URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); - assertURLStrDecoder(url1); - assertEquals("10.20.130.230:20880", url1.getAddress()); - } - - @Test - public void test_getAbsolutePath() throws Exception { - URL url = new URL("p1", "1.2.2.2", 33); - assertURLStrDecoder(url); - assertNull(url.getAbsolutePath()); - - url = new URL("file", null, 90, "/home/user1/route.js"); - assertURLStrDecoder(url); - assertEquals("/home/user1/route.js", url.getAbsolutePath()); - } - - @Test - public void test_equals() throws Exception { - URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); - assertURLStrDecoder(url1); - - Map params = new HashMap(); - params.put("version", "1.0.0"); - params.put("application", "morgan"); - URL url2 = new URL("dubbo", "admin", "hello1234", "10.20.130.230", 20880, "context/path", params); - - assertURLStrDecoder(url2); - assertEquals(url1, url2); - } - - @Test - public void test_toString() throws Exception { - URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); - assertURLStrDecoder(url1); - assertThat(url1.toString(), anyOf( - equalTo("dubbo://10.20.130.230:20880/context/path?version=1.0.0&application=morgan"), - equalTo("dubbo://10.20.130.230:20880/context/path?application=morgan&version=1.0.0")) - ); - } - - @Test - public void test_toFullString() throws Exception { - URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); - assertURLStrDecoder(url1); - assertThat(url1.toFullString(), anyOf( - equalTo("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"), - equalTo("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&version=1.0.0")) - ); - } - - @Test - public void test_set_methods() throws Exception { - URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); - assertURLStrDecoder(url); - - url = url.setHost("host"); - - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("host", url.getHost()); - assertEquals("host:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - - url = url.setPort(1); - - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("host", url.getHost()); - assertEquals("host:1", url.getAddress()); - assertEquals(1, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - - url = url.setPath("path"); - - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("host", url.getHost()); - assertEquals("host:1", url.getAddress()); - assertEquals(1, url.getPort()); - assertEquals("path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - - url = url.setProtocol("protocol"); - - assertURLStrDecoder(url); - assertEquals("protocol", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("host", url.getHost()); - assertEquals("host:1", url.getAddress()); - assertEquals(1, url.getPort()); - assertEquals("path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - - url = url.setUsername("username"); - - assertURLStrDecoder(url); - assertEquals("protocol", url.getProtocol()); - assertEquals("username", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("host", url.getHost()); - assertEquals("host:1", url.getAddress()); - assertEquals(1, url.getPort()); - assertEquals("path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - - url = url.setPassword("password"); - - assertURLStrDecoder(url); - assertEquals("protocol", url.getProtocol()); - assertEquals("username", url.getUsername()); - assertEquals("password", url.getPassword()); - assertEquals("host", url.getHost()); - assertEquals("host:1", url.getAddress()); - assertEquals(1, url.getPort()); - assertEquals("path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - } - - @Test - public void test_removeParameters() throws Exception { - URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2"); - assertURLStrDecoder(url); - - url = url.removeParameter("version"); - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(3, url.getParameters().size()); - assertEquals("morgan", url.getParameter("application")); - assertEquals("v1", url.getParameter("k1")); - assertEquals("v2", url.getParameter("k2")); - assertNull(url.getParameter("version")); - - url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2"); - url = url.removeParameters("version", "application", "NotExistedKey"); - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("v1", url.getParameter("k1")); - assertEquals("v2", url.getParameter("k2")); - assertNull(url.getParameter("version")); - assertNull(url.getParameter("application")); - - url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2"); - url = url.removeParameters(Arrays.asList("version", "application")); - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("v1", url.getParameter("k1")); - assertEquals("v2", url.getParameter("k2")); - assertNull(url.getParameter("version")); - assertNull(url.getParameter("application")); - } - - @Test - public void test_addParameter() throws Exception { - URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); - url = url.addParameter("k1", "v1"); - - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("morgan", url.getParameter("application")); - assertEquals("v1", url.getParameter("k1")); - } - - @Test - public void test_addParameter_sameKv() throws Exception { - URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&k1=v1"); - URL newUrl = url.addParameter("k1", "v1"); - - assertURLStrDecoder(url); - assertSame(newUrl, url); - } - - - @Test - public void test_addParameters() throws Exception { - URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); - url = url.addParameters(CollectionUtils.toStringMap("k1", "v1", "k2", "v2")); - - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(3, url.getParameters().size()); - assertEquals("morgan", url.getParameter("application")); - assertEquals("v1", url.getParameter("k1")); - assertEquals("v2", url.getParameter("k2")); - - url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); - url = url.addParameters("k1", "v1", "k2", "v2", "application", "xxx"); - - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(3, url.getParameters().size()); - assertEquals("xxx", url.getParameter("application")); - assertEquals("v1", url.getParameter("k1")); - assertEquals("v2", url.getParameter("k2")); - - url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); - url = url.addParametersIfAbsent(CollectionUtils.toStringMap("k1", "v1", "k2", "v2", "application", "xxx")); - - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(3, url.getParameters().size()); - assertEquals("morgan", url.getParameter("application")); - assertEquals("v1", url.getParameter("k1")); - assertEquals("v2", url.getParameter("k2")); - - url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); - url = url.addParameter("k1", "v1"); - - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("morgan", url.getParameter("application")); - assertEquals("v1", url.getParameter("k1")); - - url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); - url = url.addParameter("application", "xxx"); - - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(1, url.getParameters().size()); - assertEquals("xxx", url.getParameter("application")); - } - - @Test - public void test_addParameters_SameKv() throws Exception { - { - URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&k1=v1"); - URL newUrl = url.addParameters(CollectionUtils.toStringMap("k1", "v1")); - - assertURLStrDecoder(url); - assertSame(url, newUrl); - } - { - URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&k1=v1&k2=v2"); - URL newUrl = url.addParameters(CollectionUtils.toStringMap("k1", "v1", "k2", "v2")); - - assertURLStrDecoder(url); - assertSame(newUrl, url); - } - } - - @Test - public void test_addParameterIfAbsent() throws Exception { - URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); - url = url.addParameterIfAbsent("application", "xxx"); - - assertURLStrDecoder(url); - assertEquals("dubbo", url.getProtocol()); - assertEquals("admin", url.getUsername()); - assertEquals("hello1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(1, url.getParameters().size()); - assertEquals("morgan", url.getParameter("application")); - } - - @Test - public void test_windowAbsolutePathBeginWithSlashIsValid() throws Exception { - final String osProperty = System.getProperties().getProperty("os.name"); - if (!osProperty.toLowerCase().contains("windows")) return; - - System.out.println("Test Windows valid path string."); - - File f0 = new File("C:/Windows"); - File f1 = new File("/C:/Windows"); - - File f2 = new File("C:\\Windows"); - File f3 = new File("/C:\\Windows"); - File f4 = new File("\\C:\\Windows"); - - assertEquals(f0, f1); - assertEquals(f0, f2); - assertEquals(f0, f3); - assertEquals(f0, f4); - } - - @Test - public void test_javaNetUrl() throws Exception { - java.net.URL url = new java.net.URL("http://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan#anchor1"); - - assertEquals("http", url.getProtocol()); - assertEquals("admin:hello1234", url.getUserInfo()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals(20880, url.getPort()); - assertEquals("/context/path", url.getPath()); - assertEquals("version=1.0.0&application=morgan", url.getQuery()); - assertEquals("anchor1", url.getRef()); - - assertEquals("admin:hello1234@10.20.130.230:20880", url.getAuthority()); - assertEquals("/context/path?version=1.0.0&application=morgan", url.getFile()); - } - - @Test - public void test_Anyhost() throws Exception { - URL url = URL.valueOf("dubbo://0.0.0.0:20880"); - assertURLStrDecoder(url); - assertEquals("0.0.0.0", url.getHost()); - assertTrue(url.isAnyHost()); - } - - @Test - public void test_Localhost() throws Exception { - URL url = URL.valueOf("dubbo://127.0.0.1:20880"); - assertURLStrDecoder(url); - assertEquals("127.0.0.1", url.getHost()); - assertEquals("127.0.0.1:20880", url.getAddress()); - assertTrue(url.isLocalHost()); - - url = URL.valueOf("dubbo://127.0.1.1:20880"); - assertURLStrDecoder(url); - assertEquals("127.0.1.1", url.getHost()); - assertEquals("127.0.1.1:20880", url.getAddress()); - assertTrue(url.isLocalHost()); - - url = URL.valueOf("dubbo://localhost:20880"); - assertURLStrDecoder(url); - assertEquals("localhost", url.getHost()); - assertEquals("localhost:20880", url.getAddress()); - assertTrue(url.isLocalHost()); - } - - @Test - public void test_Path() throws Exception { - URL url = new URL("dubbo", "localhost", 20880, "////path"); - assertURLStrDecoder(url); - assertEquals("path", url.getPath()); - } - - @Test - public void testAddParameters() throws Exception { - URL url = URL.valueOf("dubbo://127.0.0.1:20880"); - assertURLStrDecoder(url); - - Map parameters = new HashMap(); - parameters.put("version", null); - url.addParameters(parameters); - assertURLStrDecoder(url); - } - - @Test - public void testUserNamePasswordContainsAt() { - // Test username or password contains "@" - URL url = URL.valueOf("ad@min:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); - assertURLStrDecoder(url); - assertNull(url.getProtocol()); - assertEquals("ad@min", url.getUsername()); - assertEquals("hello@1234", url.getPassword()); - assertEquals("10.20.130.230", url.getHost()); - assertEquals("10.20.130.230:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - } - - - @Test - public void testIpV6Address() { - // Test username or password contains "@" - URL url = URL.valueOf("ad@min111:haha@1234@2001:0db8:85a3:08d3:1319:8a2e:0370:7344:20880/context/path?version=1.0.0&application=morgan"); - assertURLStrDecoder(url); - assertNull(url.getProtocol()); - assertEquals("ad@min111", url.getUsername()); - assertEquals("haha@1234", url.getPassword()); - assertEquals("2001:0db8:85a3:08d3:1319:8a2e:0370:7344", url.getHost()); - assertEquals("2001:0db8:85a3:08d3:1319:8a2e:0370:7344:20880", url.getAddress()); - assertEquals(20880, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - } - - @Test - public void testIpV6AddressWithScopeId() { - URL url = URL.valueOf("2001:0db8:85a3:08d3:1319:8a2e:0370:7344%5/context/path?version=1.0.0&application=morgan"); - assertURLStrDecoder(url); - assertNull(url.getProtocol()); - assertEquals("2001:0db8:85a3:08d3:1319:8a2e:0370:7344%5", url.getHost()); - assertEquals("2001:0db8:85a3:08d3:1319:8a2e:0370:7344%5", url.getAddress()); - assertEquals(0, url.getPort()); - assertEquals("context/path", url.getPath()); - assertEquals(2, url.getParameters().size()); - assertEquals("1.0.0", url.getParameter("version")); - assertEquals("morgan", url.getParameter("application")); - } - - @Test - public void testDefaultPort() { - Assertions.assertEquals("10.20.153.10:2181", URL.appendDefaultPort("10.20.153.10:0", 2181)); - Assertions.assertEquals("10.20.153.10:2181", URL.appendDefaultPort("10.20.153.10", 2181)); - } - - @Test - public void testGetServiceKey() { - URL url1 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName"); - assertURLStrDecoder(url1); - Assertions.assertEquals("org.apache.dubbo.test.interfaceName", url1.getServiceKey()); - - URL url2 = URL.valueOf("10.20.130.230:20880/org.apache.dubbo.test.interfaceName?interface=org.apache.dubbo.test.interfaceName"); - assertURLStrDecoder(url2); - Assertions.assertEquals("org.apache.dubbo.test.interfaceName", url2.getServiceKey()); - - URL url3 = URL.valueOf("10.20.130.230:20880/org.apache.dubbo.test.interfaceName?interface=org.apache.dubbo.test.interfaceName&group=group1&version=1.0.0"); - assertURLStrDecoder(url3); - Assertions.assertEquals("group1/org.apache.dubbo.test.interfaceName:1.0.0", url3.getServiceKey()); - - URL url4 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName"); - assertURLStrDecoder(url4); - Assertions.assertEquals("context/path", url4.getPathKey()); - - URL url5 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group1&version=1.0.0"); - assertURLStrDecoder(url5); - Assertions.assertEquals("group1/context/path:1.0.0", url5.getPathKey()); - } - - @Test - public void testGetColonSeparatedKey() { - URL url1 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group&version=1.0.0"); - assertURLStrDecoder(url1); - Assertions.assertEquals("org.apache.dubbo.test.interfaceName:1.0.0:group", url1.getColonSeparatedKey()); - - URL url2 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&version=1.0.0"); - assertURLStrDecoder(url2); - Assertions.assertEquals("org.apache.dubbo.test.interfaceName:1.0.0:", url2.getColonSeparatedKey()); - - URL url3 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group"); - assertURLStrDecoder(url3); - Assertions.assertEquals("org.apache.dubbo.test.interfaceName::group", url3.getColonSeparatedKey()); - - URL url4 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName"); - assertURLStrDecoder(url4); - Assertions.assertEquals("org.apache.dubbo.test.interfaceName::", url4.getColonSeparatedKey()); - - URL url5 = URL.valueOf("10.20.130.230:20880/org.apache.dubbo.test.interfaceName"); - assertURLStrDecoder(url5); - Assertions.assertEquals("org.apache.dubbo.test.interfaceName::", url5.getColonSeparatedKey()); - - URL url6 = URL.valueOf("10.20.130.230:20880/org.apache.dubbo.test.interfaceName?interface=org.apache.dubbo.test.interfaceName1"); - assertURLStrDecoder(url6); - Assertions.assertEquals("org.apache.dubbo.test.interfaceName1::", url6.getColonSeparatedKey()); - } - - @Test - public void testValueOf() { - URL url = URL.valueOf("10.20.130.230"); - assertURLStrDecoder(url); - - url = URL.valueOf("10.20.130.230:20880"); - assertURLStrDecoder(url); - - url = URL.valueOf("dubbo://10.20.130.230:20880"); - assertURLStrDecoder(url); - - url = URL.valueOf("dubbo://10.20.130.230:20880/path"); - assertURLStrDecoder(url); - } -} +/* + * 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.common; + +import org.apache.dubbo.common.utils.CollectionUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Predicate; + +import static org.hamcrest.CoreMatchers.anyOf; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class URLTest { + + @Test + public void test_valueOf_noProtocolAndHost() throws Exception { + URL url = URL.valueOf("/context/path?version=1.0.0&application=morgan"); + assertURLStrDecoder(url); + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertNull(url.getAddress()); + assertEquals(0, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = URL.valueOf("context/path?version=1.0.0&application=morgan"); + // ^^^^^^^ Caution , parse as host + assertURLStrDecoder(url); + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("context", url.getHost()); + assertEquals(0, url.getPort()); + assertEquals("path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + } + + private void assertURLStrDecoder(URL url) { + String fullURLStr = url.toFullString(); + URL newUrl = URLStrParser.parseEncodedStr(URL.encode(fullURLStr)); + assertEquals(URL.valueOf(fullURLStr), newUrl); + + URL newUrl2 = URLStrParser.parseDecodedStr(fullURLStr); + assertEquals(URL.valueOf(fullURLStr), newUrl2); + } + + @Test + public void test_valueOf_noProtocol() throws Exception { + URL url = URL.valueOf("10.20.130.230"); + assertURLStrDecoder(url); + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230", url.getAddress()); + assertEquals(0, url.getPort()); + assertNull(url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("10.20.130.230:20880"); + assertURLStrDecoder(url); + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertNull(url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("10.20.130.230/context/path"); + assertURLStrDecoder(url); + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230", url.getAddress()); + assertEquals(0, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("10.20.130.230:20880/context/path"); + assertURLStrDecoder(url); + assertNull(url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertURLStrDecoder(url); + assertNull(url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + } + + @Test + public void test_valueOf_noHost() throws Exception { + URL url = URL.valueOf("file:///home/user1/router.js"); + assertURLStrDecoder(url); + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertNull(url.getAddress()); + assertEquals(0, url.getPort()); + assertEquals("home/user1/router.js", url.getPath()); + assertEquals(0, url.getParameters().size()); + + // Caution!! + url = URL.valueOf("file://home/user1/router.js"); + // ^^ only tow slash! + assertURLStrDecoder(url); + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("home", url.getHost()); + assertEquals(0, url.getPort()); + assertEquals("user1/router.js", url.getPath()); + assertEquals(0, url.getParameters().size()); + + + url = URL.valueOf("file:/home/user1/router.js"); + assertURLStrDecoder(url); + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertNull(url.getAddress()); + assertEquals(0, url.getPort()); + assertEquals("home/user1/router.js", url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("file:///d:/home/user1/router.js"); + assertURLStrDecoder(url); + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertNull(url.getAddress()); + assertEquals(0, url.getPort()); + assertEquals("d:/home/user1/router.js", url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("file:///home/user1/router.js?p1=v1&p2=v2"); + assertURLStrDecoder(url); + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertNull(url.getAddress()); + assertEquals(0, url.getPort()); + assertEquals("home/user1/router.js", url.getPath()); + assertEquals(2, url.getParameters().size()); + Map params = new HashMap(); + params.put("p1", "v1"); + params.put("p2", "v2"); + assertEquals(params, url.getParameters()); + + url = URL.valueOf("file:/home/user1/router.js?p1=v1&p2=v2"); + assertURLStrDecoder(url); + assertEquals("file", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertNull(url.getHost()); + assertNull(url.getAddress()); + assertEquals(0, url.getPort()); + assertEquals("home/user1/router.js", url.getPath()); + assertEquals(2, url.getParameters().size()); + params = new HashMap(); + params.put("p1", "v1"); + params.put("p2", "v2"); + assertEquals(params, url.getParameters()); + } + + @Test + public void test_valueOf_WithProtocolHost() throws Exception { + URL url = URL.valueOf("dubbo://10.20.130.230"); + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230", url.getAddress()); + assertEquals(0, url.getPort()); + assertNull(url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("dubbo://10.20.130.230:20880/context/path"); + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertNull(url.getUsername()); + assertNull(url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880"); + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertNull(url.getPath()); + assertEquals(0, url.getParameters().size()); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880?version=1.0.0"); + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertNull(url.getPath()); + assertEquals(1, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&noValue"); + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(3, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + assertEquals("noValue", url.getParameter("noValue")); + } + + // TODO Do not want to use spaces? See: DUBBO-502, URL class handles special conventions for special characters. + @Test + public void test_valueOf_spaceSafe() throws Exception { + URL url = URL.valueOf("http://1.2.3.4:8080/path?key=value1 value2"); + assertURLStrDecoder(url); + assertEquals("http://1.2.3.4:8080/path?key=value1 value2", url.toString()); + assertEquals("value1 value2", url.getParameter("key")); + } + + @Test + public void test_noValueKey() throws Exception { + URL url = URL.valueOf("http://1.2.3.4:8080/path?k0&k1=v1"); + + assertURLStrDecoder(url); + assertTrue(url.hasParameter("k0")); + + // If a Key has no corresponding Value, then the Key also used as the Value. + assertEquals("k0", url.getParameter("k0")); + } + + @Test + public void test_valueOf_Exception_noProtocol() throws Exception { + try { + URL.valueOf("://1.2.3.4:8080/path"); + fail(); + } catch (IllegalStateException expected) { + assertEquals("url missing protocol: \"://1.2.3.4:8080/path\"", expected.getMessage()); + } + + try { + String encodedURLStr = URL.encode("://1.2.3.4:8080/path"); + URLStrParser.parseEncodedStr(encodedURLStr); + fail(); + } catch (IllegalStateException expected) { + assertEquals("url missing protocol: \"://1.2.3.4:8080/path\"", URL.decode(expected.getMessage())); + } + + try { + URLStrParser.parseDecodedStr("://1.2.3.4:8080/path"); + fail(); + } catch (IllegalStateException expected) { + assertEquals("url missing protocol: \"://1.2.3.4:8080/path\"", expected.getMessage()); + } + } + + @Test + public void test_getAddress() throws Exception { + URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertURLStrDecoder(url1); + assertEquals("10.20.130.230:20880", url1.getAddress()); + } + + @Test + public void test_getAbsolutePath() throws Exception { + URL url = new URL("p1", "1.2.2.2", 33); + assertURLStrDecoder(url); + assertNull(url.getAbsolutePath()); + + url = new URL("file", null, 90, "/home/user1/route.js"); + assertURLStrDecoder(url); + assertEquals("/home/user1/route.js", url.getAbsolutePath()); + } + + @Test + public void test_equals() throws Exception { + URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertURLStrDecoder(url1); + + Map params = new HashMap(); + params.put("version", "1.0.0"); + params.put("application", "morgan"); + URL url2 = new URL("dubbo", "admin", "hello1234", "10.20.130.230", 20880, "context/path", params); + + assertURLStrDecoder(url2); + assertEquals(url1, url2); + } + + @Test + public void test_toString() throws Exception { + URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertURLStrDecoder(url1); + assertThat(url1.toString(), anyOf( + equalTo("dubbo://10.20.130.230:20880/context/path?version=1.0.0&application=morgan"), + equalTo("dubbo://10.20.130.230:20880/context/path?application=morgan&version=1.0.0")) + ); + } + + @Test + public void test_toFullString() throws Exception { + URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertURLStrDecoder(url1); + assertThat(url1.toFullString(), anyOf( + equalTo("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"), + equalTo("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&version=1.0.0")) + ); + } + + @Test + public void test_set_methods() throws Exception { + URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertURLStrDecoder(url); + + url = url.setHost("host"); + + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals("host:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = url.setPort(1); + + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals("host:1", url.getAddress()); + assertEquals(1, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = url.setPath("path"); + + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals("host:1", url.getAddress()); + assertEquals(1, url.getPort()); + assertEquals("path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = url.setProtocol("protocol"); + + assertURLStrDecoder(url); + assertEquals("protocol", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals("host:1", url.getAddress()); + assertEquals(1, url.getPort()); + assertEquals("path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = url.setUsername("username"); + + assertURLStrDecoder(url); + assertEquals("protocol", url.getProtocol()); + assertEquals("username", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals("host:1", url.getAddress()); + assertEquals(1, url.getPort()); + assertEquals("path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + + url = url.setPassword("password"); + + assertURLStrDecoder(url); + assertEquals("protocol", url.getProtocol()); + assertEquals("username", url.getUsername()); + assertEquals("password", url.getPassword()); + assertEquals("host", url.getHost()); + assertEquals("host:1", url.getAddress()); + assertEquals(1, url.getPort()); + assertEquals("path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + } + + @Test + public void test_removeParameters() throws Exception { + URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2"); + assertURLStrDecoder(url); + + url = url.removeParameter("version"); + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(3, url.getParameters().size()); + assertEquals("morgan", url.getParameter("application")); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + assertNull(url.getParameter("version")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2"); + url = url.removeParameters("version", "application", "NotExistedKey"); + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + assertNull(url.getParameter("version")); + assertNull(url.getParameter("application")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&k1=v1&k2=v2"); + url = url.removeParameters(Arrays.asList("version", "application")); + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + assertNull(url.getParameter("version")); + assertNull(url.getParameter("application")); + } + + @Test + public void test_addParameter() throws Exception { + URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParameter("k1", "v1"); + + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("morgan", url.getParameter("application")); + assertEquals("v1", url.getParameter("k1")); + } + + @Test + public void test_addParameter_sameKv() throws Exception { + URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&k1=v1"); + URL newUrl = url.addParameter("k1", "v1"); + + assertURLStrDecoder(url); + assertSame(newUrl, url); + } + + + @Test + public void test_addParameters() throws Exception { + URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParameters(CollectionUtils.toStringMap("k1", "v1", "k2", "v2")); + + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(3, url.getParameters().size()); + assertEquals("morgan", url.getParameter("application")); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParameters("k1", "v1", "k2", "v2", "application", "xxx"); + + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(3, url.getParameters().size()); + assertEquals("xxx", url.getParameter("application")); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParametersIfAbsent(CollectionUtils.toStringMap("k1", "v1", "k2", "v2", "application", "xxx")); + + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(3, url.getParameters().size()); + assertEquals("morgan", url.getParameter("application")); + assertEquals("v1", url.getParameter("k1")); + assertEquals("v2", url.getParameter("k2")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParameter("k1", "v1"); + + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("morgan", url.getParameter("application")); + assertEquals("v1", url.getParameter("k1")); + + url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParameter("application", "xxx"); + + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(1, url.getParameters().size()); + assertEquals("xxx", url.getParameter("application")); + } + + @Test + public void test_addParameters_SameKv() throws Exception { + { + URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&k1=v1"); + URL newUrl = url.addParameters(CollectionUtils.toStringMap("k1", "v1")); + + assertURLStrDecoder(url); + assertSame(url, newUrl); + } + { + URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan&k1=v1&k2=v2"); + URL newUrl = url.addParameters(CollectionUtils.toStringMap("k1", "v1", "k2", "v2")); + + assertURLStrDecoder(url); + assertSame(newUrl, url); + } + } + + @Test + public void test_addParameterIfAbsent() throws Exception { + URL url = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?application=morgan"); + url = url.addParameterIfAbsent("application", "xxx"); + + assertURLStrDecoder(url); + assertEquals("dubbo", url.getProtocol()); + assertEquals("admin", url.getUsername()); + assertEquals("hello1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(1, url.getParameters().size()); + assertEquals("morgan", url.getParameter("application")); + } + + @Test + public void test_windowAbsolutePathBeginWithSlashIsValid() throws Exception { + final String osProperty = System.getProperties().getProperty("os.name"); + if (!osProperty.toLowerCase().contains("windows")) return; + + System.out.println("Test Windows valid path string."); + + File f0 = new File("C:/Windows"); + File f1 = new File("/C:/Windows"); + + File f2 = new File("C:\\Windows"); + File f3 = new File("/C:\\Windows"); + File f4 = new File("\\C:\\Windows"); + + assertEquals(f0, f1); + assertEquals(f0, f2); + assertEquals(f0, f3); + assertEquals(f0, f4); + } + + @Test + public void test_javaNetUrl() throws Exception { + java.net.URL url = new java.net.URL("http://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan#anchor1"); + + assertEquals("http", url.getProtocol()); + assertEquals("admin:hello1234", url.getUserInfo()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals(20880, url.getPort()); + assertEquals("/context/path", url.getPath()); + assertEquals("version=1.0.0&application=morgan", url.getQuery()); + assertEquals("anchor1", url.getRef()); + + assertEquals("admin:hello1234@10.20.130.230:20880", url.getAuthority()); + assertEquals("/context/path?version=1.0.0&application=morgan", url.getFile()); + } + + @Test + public void test_Anyhost() throws Exception { + URL url = URL.valueOf("dubbo://0.0.0.0:20880"); + assertURLStrDecoder(url); + assertEquals("0.0.0.0", url.getHost()); + assertTrue(url.isAnyHost()); + } + + @Test + public void test_Localhost() throws Exception { + URL url = URL.valueOf("dubbo://127.0.0.1:20880"); + assertURLStrDecoder(url); + assertEquals("127.0.0.1", url.getHost()); + assertEquals("127.0.0.1:20880", url.getAddress()); + assertTrue(url.isLocalHost()); + + url = URL.valueOf("dubbo://127.0.1.1:20880"); + assertURLStrDecoder(url); + assertEquals("127.0.1.1", url.getHost()); + assertEquals("127.0.1.1:20880", url.getAddress()); + assertTrue(url.isLocalHost()); + + url = URL.valueOf("dubbo://localhost:20880"); + assertURLStrDecoder(url); + assertEquals("localhost", url.getHost()); + assertEquals("localhost:20880", url.getAddress()); + assertTrue(url.isLocalHost()); + } + + @Test + public void test_Path() throws Exception { + URL url = new URL("dubbo", "localhost", 20880, "////path"); + assertURLStrDecoder(url); + assertEquals("path", url.getPath()); + } + + @Test + public void testAddParameters() throws Exception { + URL url = URL.valueOf("dubbo://127.0.0.1:20880"); + assertURLStrDecoder(url); + + Map parameters = new HashMap(); + parameters.put("version", null); + url.addParameters(parameters); + assertURLStrDecoder(url); + } + + @Test + public void testUserNamePasswordContainsAt() { + // Test username or password contains "@" + URL url = URL.valueOf("ad@min:hello@1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan"); + assertURLStrDecoder(url); + assertNull(url.getProtocol()); + assertEquals("ad@min", url.getUsername()); + assertEquals("hello@1234", url.getPassword()); + assertEquals("10.20.130.230", url.getHost()); + assertEquals("10.20.130.230:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + } + + + @Test + public void testIpV6Address() { + // Test username or password contains "@" + URL url = URL.valueOf("ad@min111:haha@1234@2001:0db8:85a3:08d3:1319:8a2e:0370:7344:20880/context/path?version=1.0.0&application=morgan"); + assertURLStrDecoder(url); + assertNull(url.getProtocol()); + assertEquals("ad@min111", url.getUsername()); + assertEquals("haha@1234", url.getPassword()); + assertEquals("2001:0db8:85a3:08d3:1319:8a2e:0370:7344", url.getHost()); + assertEquals("2001:0db8:85a3:08d3:1319:8a2e:0370:7344:20880", url.getAddress()); + assertEquals(20880, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + } + + @Test + public void testIpV6AddressWithScopeId() { + URL url = URL.valueOf("2001:0db8:85a3:08d3:1319:8a2e:0370:7344%5/context/path?version=1.0.0&application=morgan"); + assertURLStrDecoder(url); + assertNull(url.getProtocol()); + assertEquals("2001:0db8:85a3:08d3:1319:8a2e:0370:7344%5", url.getHost()); + assertEquals("2001:0db8:85a3:08d3:1319:8a2e:0370:7344%5", url.getAddress()); + assertEquals(0, url.getPort()); + assertEquals("context/path", url.getPath()); + assertEquals(2, url.getParameters().size()); + assertEquals("1.0.0", url.getParameter("version")); + assertEquals("morgan", url.getParameter("application")); + } + + @Test + public void testDefaultPort() { + Assertions.assertEquals("10.20.153.10:2181", URL.appendDefaultPort("10.20.153.10:0", 2181)); + Assertions.assertEquals("10.20.153.10:2181", URL.appendDefaultPort("10.20.153.10", 2181)); + } + + @Test + public void testGetServiceKey() { + URL url1 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName"); + assertURLStrDecoder(url1); + Assertions.assertEquals("org.apache.dubbo.test.interfaceName", url1.getServiceKey()); + + URL url2 = URL.valueOf("10.20.130.230:20880/org.apache.dubbo.test.interfaceName?interface=org.apache.dubbo.test.interfaceName"); + assertURLStrDecoder(url2); + Assertions.assertEquals("org.apache.dubbo.test.interfaceName", url2.getServiceKey()); + + URL url3 = URL.valueOf("10.20.130.230:20880/org.apache.dubbo.test.interfaceName?interface=org.apache.dubbo.test.interfaceName&group=group1&version=1.0.0"); + assertURLStrDecoder(url3); + Assertions.assertEquals("group1/org.apache.dubbo.test.interfaceName:1.0.0", url3.getServiceKey()); + + URL url4 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName"); + assertURLStrDecoder(url4); + Assertions.assertEquals("context/path", url4.getPathKey()); + + URL url5 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group1&version=1.0.0"); + assertURLStrDecoder(url5); + Assertions.assertEquals("group1/context/path:1.0.0", url5.getPathKey()); + } + + @Test + public void testGetColonSeparatedKey() { + URL url1 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group&version=1.0.0"); + assertURLStrDecoder(url1); + Assertions.assertEquals("org.apache.dubbo.test.interfaceName:1.0.0:group", url1.getColonSeparatedKey()); + + URL url2 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&version=1.0.0"); + assertURLStrDecoder(url2); + Assertions.assertEquals("org.apache.dubbo.test.interfaceName:1.0.0:", url2.getColonSeparatedKey()); + + URL url3 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group"); + assertURLStrDecoder(url3); + Assertions.assertEquals("org.apache.dubbo.test.interfaceName::group", url3.getColonSeparatedKey()); + + URL url4 = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName"); + assertURLStrDecoder(url4); + Assertions.assertEquals("org.apache.dubbo.test.interfaceName::", url4.getColonSeparatedKey()); + + URL url5 = URL.valueOf("10.20.130.230:20880/org.apache.dubbo.test.interfaceName"); + assertURLStrDecoder(url5); + Assertions.assertEquals("org.apache.dubbo.test.interfaceName::", url5.getColonSeparatedKey()); + + URL url6 = URL.valueOf("10.20.130.230:20880/org.apache.dubbo.test.interfaceName?interface=org.apache.dubbo.test.interfaceName1"); + assertURLStrDecoder(url6); + Assertions.assertEquals("org.apache.dubbo.test.interfaceName1::", url6.getColonSeparatedKey()); + } + + @Test + public void testValueOf() { + URL url = URL.valueOf("10.20.130.230"); + assertURLStrDecoder(url); + + url = URL.valueOf("10.20.130.230:20880"); + assertURLStrDecoder(url); + + url = URL.valueOf("dubbo://10.20.130.230:20880"); + assertURLStrDecoder(url); + + url = URL.valueOf("dubbo://10.20.130.230:20880/path"); + assertURLStrDecoder(url); + } + + + /** + * Test {@link URL#getParameters(Predicate)} method + * + * @since 2.7.8 + */ + @Test + public void testGetParameters() { + URL url = URL.valueOf("10.20.130.230:20880/context/path?interface=org.apache.dubbo.test.interfaceName&group=group&version=1.0.0"); + Map parameters = url.getParameters(i -> "version".equals(i)); + String version = parameters.get("version"); + assertEquals(1, parameters.size()); + assertEquals("1.0.0", version); + } + + @Test + public void testGetParameter() { + URL url = URL.valueOf("http://127.0.0.1:8080/path?i=1&b=false"); + assertEquals(Integer.valueOf(1), url.getParameter("i", Integer.class)); + assertEquals(Boolean.FALSE, url.getParameter("b", Boolean.class)); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfigurationTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfigurationTest.java index 4f2f700e8ba..7605a3c6184 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfigurationTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/AbstractDynamicConfigurationTest.java @@ -28,15 +28,17 @@ import static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.DEFAULT_THREAD_POOL_KEEP_ALIVE_TIME; import static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.DEFAULT_THREAD_POOL_PREFIX; import static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.DEFAULT_THREAD_POOL_SIZE; +import static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.GROUP_PARAM_NAME; import static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.PARAM_NAME_PREFIX; import static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.THREAD_POOL_KEEP_ALIVE_TIME_PARAM_NAME; import static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.THREAD_POOL_PREFIX_PARAM_NAME; import static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.THREAD_POOL_SIZE_PARAM_NAME; +import static org.apache.dubbo.common.config.configcenter.AbstractDynamicConfiguration.TIMEOUT_PARAM_NAME; +import static org.apache.dubbo.common.config.configcenter.DynamicConfiguration.DEFAULT_GROUP; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * {@link AbstractDynamicConfiguration} Test @@ -49,7 +51,7 @@ public class AbstractDynamicConfigurationTest { @BeforeEach public void init() { - configuration = new AbstractDynamicConfiguration() { + configuration = new AbstractDynamicConfiguration(null) { @Override protected String doGetConfig(String key, String group) throws Exception { return null; @@ -59,6 +61,11 @@ protected String doGetConfig(String key, String group) throws Exception { protected void doClose() throws Exception { } + + @Override + protected boolean doRemoveConfig(String key, String group) throws Exception { + return false; + } }; } @@ -71,6 +78,10 @@ public void testConstants() { assertEquals("dubbo.config-center.thread-pool.keep-alive-time", THREAD_POOL_KEEP_ALIVE_TIME_PARAM_NAME); assertEquals(1, DEFAULT_THREAD_POOL_SIZE); assertEquals(60 * 1000, DEFAULT_THREAD_POOL_KEEP_ALIVE_TIME); + + // @since 2.7.8 + assertEquals("dubbo.config-center.group", GROUP_PARAM_NAME); + assertEquals("dubbo.config-center.timeout", TIMEOUT_PARAM_NAME); } @Test @@ -91,6 +102,11 @@ protected String doGetConfig(String key, String group) throws Exception { protected void doClose() throws Exception { } + + @Override + protected boolean doRemoveConfig(String key, String group) throws Exception { + return false; + } }; ThreadPoolExecutor threadPoolExecutor = configuration.getWorkersThreadPool(); @@ -149,4 +165,42 @@ public void testRemoveListener() { public void testClose() throws Exception { configuration.close(); } + + /** + * Test {@link AbstractDynamicConfiguration#getGroup()} and + * {@link AbstractDynamicConfiguration#getDefaultGroup()} methods + * + * @since 2.7.8 + */ + @Test + public void testGetGroupAndGetDefaultGroup() { + assertEquals(configuration.getGroup(), configuration.getDefaultGroup()); + assertEquals(DEFAULT_GROUP, configuration.getDefaultGroup()); + } + + /** + * Test {@link AbstractDynamicConfiguration#getTimeout()} and + * {@link AbstractDynamicConfiguration#getDefaultTimeout()} methods + * + * @since 2.7.8 + */ + @Test + public void testGetTimeoutAndGetDefaultTimeout() { + assertEquals(configuration.getTimeout(), configuration.getDefaultTimeout()); + assertEquals(-1L, configuration.getDefaultTimeout()); + } + + /** + * Test {@link AbstractDynamicConfiguration#removeConfig(String, String)} and + * {@link AbstractDynamicConfiguration#doRemoveConfig(String, String)} methods + * + * @since 2.7.8 + */ + @Test + public void testRemoveConfigAndDoRemoveConfig() throws Exception { + String key = null; + String group = null; + assertEquals(configuration.removeConfig(key, group), configuration.doRemoveConfig(key, group)); + assertFalse(configuration.removeConfig(key, group)); + } } diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationTest.java index 1422ba63e88..80282c185c3 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationTest.java @@ -17,6 +17,8 @@ package org.apache.dubbo.common.config.configcenter.file; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.AfterEach; @@ -24,15 +26,17 @@ import org.junit.jupiter.api.Test; import java.io.File; +import java.util.TreeSet; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.atomic.AtomicBoolean; +import static java.util.Arrays.asList; import static org.apache.commons.io.FileUtils.deleteQuietly; import static org.apache.dubbo.common.URL.valueOf; import static org.apache.dubbo.common.config.configcenter.DynamicConfiguration.DEFAULT_GROUP; import static org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfiguration.CONFIG_CENTER_DIR_PARAM_NAME; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -41,6 +45,8 @@ */ public class FileSystemDynamicConfigurationTest { + private final Logger logger = LoggerFactory.getLogger(getClass()); + private FileSystemDynamicConfiguration configuration; private static final String KEY = "abc-def-ghi"; @@ -53,11 +59,11 @@ public void init() { rootDirectory.mkdirs(); URL url = valueOf("dubbo://127.0.0.1:20880").addParameter(CONFIG_CENTER_DIR_PARAM_NAME, rootDirectory.getAbsolutePath()); configuration = new FileSystemDynamicConfiguration(url); - deleteQuietly(configuration.getRootDirectory()); } @AfterEach public void destroy() throws Exception { + deleteQuietly(configuration.getRootDirectory()); configuration.close(); } @@ -73,9 +79,6 @@ public void testInit() { assertEquals(ThreadPoolExecutor.class, configuration.getWorkersThreadPool().getClass()); assertEquals(1, (configuration.getWorkersThreadPool()).getCorePoolSize()); assertEquals(1, (configuration.getWorkersThreadPool()).getMaximumPoolSize()); - assertNotNull(configuration.getWatchEventsLoopThreadPool()); - assertEquals(1, (configuration.getWatchEventsLoopThreadPool()).getCorePoolSize()); - assertEquals(1, (configuration.getWatchEventsLoopThreadPool()).getMaximumPoolSize()); if (configuration.isBasedPoolingWatchService()) { assertEquals(2, configuration.getDelay()); @@ -103,7 +106,7 @@ public void testAddAndRemoveListener() throws InterruptedException { processedEvent.set(true); assertEquals(KEY, event.getKey()); - System.out.printf("[%s] " + event + "\n", Thread.currentThread().getName()); + logger.info(String.format("[%s] " + event + "\n", Thread.currentThread().getName())); }); @@ -127,7 +130,7 @@ public void testAddAndRemoveListener() throws InterruptedException { configuration.addListener("test", "test", event -> { processedEvent.set(true); assertEquals("test", event.getKey()); - System.out.printf("[%s] " + event + "\n", Thread.currentThread().getName()); + logger.info(String.format("[%s] " + event + "\n", Thread.currentThread().getName())); }); processedEvent.set(false); configuration.publishConfig("test", "test", "TEST"); @@ -141,10 +144,36 @@ public void testAddAndRemoveListener() throws InterruptedException { processedEvent.set(false); - File keyFile = configuration.configFile(KEY, DEFAULT_GROUP); + configuration.getRootDirectory(); + File keyFile = new File(KEY, DEFAULT_GROUP); FileUtils.deleteQuietly(keyFile); while (!processedEvent.get()) { Thread.sleep(1 * 1000L); } } + + @Test + public void testRemoveConfig() throws Exception { + + assertTrue(configuration.publishConfig(KEY, DEFAULT_GROUP, "A")); + + assertEquals("A", FileUtils.readFileToString(configuration.configFile(KEY, DEFAULT_GROUP), configuration.getEncoding())); + + assertTrue(configuration.removeConfig(KEY, DEFAULT_GROUP)); + + assertFalse(configuration.configFile(KEY, DEFAULT_GROUP).exists()); + + } + + @Test + public void testGetConfigKeys() throws Exception { + + assertTrue(configuration.publishConfig("A", DEFAULT_GROUP, "A")); + + assertTrue(configuration.publishConfig("B", DEFAULT_GROUP, "B")); + + assertTrue(configuration.publishConfig("C", DEFAULT_GROUP, "C")); + + assertEquals(new TreeSet(asList("A", "B", "C")), configuration.getConfigKeys(DEFAULT_GROUP)); + } } diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/constants/CommonConstantsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/constants/CommonConstantsTest.java new file mode 100644 index 00000000000..bc85dfb3d50 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/constants/CommonConstantsTest.java @@ -0,0 +1,41 @@ +/* + * 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.common.constants; + +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR_CHAR; +import static org.apache.dubbo.common.constants.CommonConstants.COMPOSITE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH; +import static org.apache.dubbo.common.constants.CommonConstants.SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link CommonConstants} Test-Cases + * + * @since 2.7.8 + */ +public class CommonConstantsTest { + + @Test + public void test() { + assertEquals(',', COMMA_SEPARATOR_CHAR); + assertEquals("composite", COMPOSITE_METADATA_STORAGE_TYPE); + assertEquals("service-name-mapping.properties-path", SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY); + assertEquals("META-INF/dubbo/service-name-mapping.properties", DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/convert/ConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/ConverterTest.java new file mode 100644 index 00000000000..1f5a36cd94a --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/ConverterTest.java @@ -0,0 +1,49 @@ +/* + * 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.common.convert; + +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.convert.Converter.convertIfPossible; +import static org.apache.dubbo.common.convert.Converter.getConverter; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; + +/** + * {@link Converter} Test-Cases + * + * @since 2.7.8 + */ +public class ConverterTest { + + @Test + public void testGetConverter() { + getExtensionLoader(Converter.class) + .getSupportedExtensionInstances() + .forEach(converter -> { + assertSame(converter, getConverter(converter.getSourceType(), converter.getTargetType())); + }); + } + + @Test + public void testConvertIfPossible() { + assertEquals(Integer.valueOf(2), convertIfPossible("2", Integer.class)); + assertEquals(Boolean.FALSE, convertIfPossible("false", Boolean.class)); + assertEquals(Double.valueOf(1), convertIfPossible("1", Double.class)); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToBooleanConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToBooleanConverterTest.java similarity index 92% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/StringToBooleanConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToBooleanConverterTest.java index 3b1d75bb63a..e955fa9a417 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToBooleanConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToBooleanConverterTest.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert; - -import org.apache.dubbo.common.convert.Converter; -import org.apache.dubbo.common.convert.StringToBooleanConverter; +package org.apache.dubbo.common.convert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharArrayConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToCharArrayConverterTest.java similarity index 92% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharArrayConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToCharArrayConverterTest.java index 492a1299e4b..bc3a606ee58 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharArrayConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToCharArrayConverterTest.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert; - -import org.apache.dubbo.common.convert.Converter; -import org.apache.dubbo.common.convert.StringToCharArrayConverter; +package org.apache.dubbo.common.convert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharacterConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToCharacterConverterTest.java similarity index 92% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharacterConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToCharacterConverterTest.java index c9e88c24211..87f3367709b 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToCharacterConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToCharacterConverterTest.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert; - -import org.apache.dubbo.common.convert.Converter; -import org.apache.dubbo.common.convert.StringToCharacterConverter; +package org.apache.dubbo.common.convert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToDoubleConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToDoubleConverterTest.java similarity index 92% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/StringToDoubleConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToDoubleConverterTest.java index 668f3e6b80f..2c747360185 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToDoubleConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToDoubleConverterTest.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert; - -import org.apache.dubbo.common.convert.Converter; -import org.apache.dubbo.common.convert.StringToDoubleConverter; +package org.apache.dubbo.common.convert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToFloatConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToFloatConverterTest.java similarity index 92% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/StringToFloatConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToFloatConverterTest.java index aa1749948a9..b4b36f3f178 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToFloatConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToFloatConverterTest.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert; - -import org.apache.dubbo.common.convert.Converter; -import org.apache.dubbo.common.convert.StringToFloatConverter; +package org.apache.dubbo.common.convert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToIntegerConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToIntegerConverterTest.java similarity index 92% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/StringToIntegerConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToIntegerConverterTest.java index 9c7d24b6019..1ccebfd183e 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToIntegerConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToIntegerConverterTest.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert; - -import org.apache.dubbo.common.convert.Converter; -import org.apache.dubbo.common.convert.StringToIntegerConverter; +package org.apache.dubbo.common.convert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToLongConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToLongConverterTest.java similarity index 92% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/StringToLongConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToLongConverterTest.java index e14424a62b0..c7cd926262d 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToLongConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToLongConverterTest.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert; - -import org.apache.dubbo.common.convert.Converter; -import org.apache.dubbo.common.convert.StringToLongConverter; +package org.apache.dubbo.common.convert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToOptionalConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToOptionalConverterTest.java similarity index 92% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/StringToOptionalConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToOptionalConverterTest.java index 242ae6053e5..9cb79e20b50 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToOptionalConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToOptionalConverterTest.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert; - -import org.apache.dubbo.common.convert.Converter; -import org.apache.dubbo.common.convert.StringToOptionalConverter; +package org.apache.dubbo.common.convert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToShortConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToShortConverterTest.java similarity index 92% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/StringToShortConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToShortConverterTest.java index 3f1d4935a14..9ecdc207b75 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToShortConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToShortConverterTest.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert; - -import org.apache.dubbo.common.convert.Converter; -import org.apache.dubbo.common.convert.StringToShortConverter; +package org.apache.dubbo.common.convert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToStringConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToStringConverterTest.java similarity index 92% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/StringToStringConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToStringConverterTest.java index 57806c345a8..517585df778 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/StringToStringConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/StringToStringConverterTest.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert; - -import org.apache.dubbo.common.convert.Converter; -import org.apache.dubbo.common.convert.StringToStringConverter; +package org.apache.dubbo.common.convert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/MultiValueConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/MultiValueConverterTest.java new file mode 100644 index 00000000000..ea64628bd23 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/MultiValueConverterTest.java @@ -0,0 +1,72 @@ +/* + * 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.common.convert.multiple; + +import org.junit.jupiter.api.Test; + +import java.util.Collection; +import java.util.Deque; +import java.util.List; +import java.util.NavigableSet; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TransferQueue; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link MultiValueConverter} Test + * + * @since 2.7.8 + */ +public class MultiValueConverterTest { + + @Test + public void testFind() { + MultiValueConverter converter = MultiValueConverter.find(String.class, String[].class); + assertEquals(StringToArrayConverter.class, converter.getClass()); + + converter = MultiValueConverter.find(String.class, BlockingDeque.class); + assertEquals(StringToBlockingDequeConverter.class, converter.getClass()); + + converter = MultiValueConverter.find(String.class, BlockingQueue.class); + assertEquals(StringToBlockingQueueConverter.class, converter.getClass()); + + converter = MultiValueConverter.find(String.class, Collection.class); + assertEquals(StringToCollectionConverter.class, converter.getClass()); + + converter = MultiValueConverter.find(String.class, Deque.class); + assertEquals(StringToDequeConverter.class, converter.getClass()); + + converter = MultiValueConverter.find(String.class, List.class); + assertEquals(StringToListConverter.class, converter.getClass()); + + converter = MultiValueConverter.find(String.class, NavigableSet.class); + assertEquals(StringToNavigableSetConverter.class, converter.getClass()); + + converter = MultiValueConverter.find(String.class, Queue.class); + assertEquals(StringToQueueConverter.class, converter.getClass()); + + converter = MultiValueConverter.find(String.class, Set.class); + assertEquals(StringToSetConverter.class, converter.getClass()); + + converter = MultiValueConverter.find(String.class, TransferQueue.class); + assertEquals(StringToTransferQueueConverter.class, converter.getClass()); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToArrayConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToArrayConverterTest.java similarity index 95% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToArrayConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToArrayConverterTest.java index 17813566c71..8279e07b35a 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToArrayConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToArrayConverterTest.java @@ -14,9 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert.multiple; - -import org.apache.dubbo.common.convert.multiple.StringToArrayConverter; +package org.apache.dubbo.common.convert.multiple; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingDequeConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToBlockingDequeConverterTest.java similarity index 95% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingDequeConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToBlockingDequeConverterTest.java index 6f9597d7065..f0975ad6bfd 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingDequeConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToBlockingDequeConverterTest.java @@ -14,10 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert.multiple; +package org.apache.dubbo.common.convert.multiple; -import org.apache.dubbo.common.convert.multiple.MultiValueConverter; -import org.apache.dubbo.common.convert.multiple.StringToBlockingDequeConverter; import org.apache.dubbo.common.utils.CollectionUtils; import org.junit.jupiter.api.BeforeEach; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingQueueConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToBlockingQueueConverterTest.java similarity index 95% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingQueueConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToBlockingQueueConverterTest.java index 4fa7532a038..f1d8cb8b674 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToBlockingQueueConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToBlockingQueueConverterTest.java @@ -14,10 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert.multiple; +package org.apache.dubbo.common.convert.multiple; -import org.apache.dubbo.common.convert.multiple.MultiValueConverter; -import org.apache.dubbo.common.convert.multiple.StringToBlockingQueueConverter; import org.apache.dubbo.common.utils.CollectionUtils; import org.junit.jupiter.api.BeforeEach; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToCollectionConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToCollectionConverterTest.java similarity index 95% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToCollectionConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToCollectionConverterTest.java index f0b06ec19c3..564ece3384c 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToCollectionConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToCollectionConverterTest.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert.multiple; - -import org.apache.dubbo.common.convert.multiple.MultiValueConverter; -import org.apache.dubbo.common.convert.multiple.StringToCollectionConverter; +package org.apache.dubbo.common.convert.multiple; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToDequeConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToDequeConverterTest.java similarity index 95% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToDequeConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToDequeConverterTest.java index e8100920923..3d4b785f418 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToDequeConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToDequeConverterTest.java @@ -14,10 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert.multiple; +package org.apache.dubbo.common.convert.multiple; -import org.apache.dubbo.common.convert.multiple.MultiValueConverter; -import org.apache.dubbo.common.convert.multiple.StringToDequeConverter; import org.apache.dubbo.common.utils.CollectionUtils; import org.junit.jupiter.api.BeforeEach; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToListConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToListConverterTest.java similarity index 95% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToListConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToListConverterTest.java index af9ee91c48a..4258199e3d0 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToListConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToListConverterTest.java @@ -14,10 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert.multiple; +package org.apache.dubbo.common.convert.multiple; -import org.apache.dubbo.common.convert.multiple.MultiValueConverter; -import org.apache.dubbo.common.convert.multiple.StringToListConverter; import org.apache.dubbo.common.utils.CollectionUtils; import org.junit.jupiter.api.BeforeEach; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToNavigableSetConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToNavigableSetConverterTest.java similarity index 95% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToNavigableSetConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToNavigableSetConverterTest.java index face60dbfdf..e7e1660d813 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToNavigableSetConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToNavigableSetConverterTest.java @@ -14,10 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert.multiple; +package org.apache.dubbo.common.convert.multiple; -import org.apache.dubbo.common.convert.multiple.MultiValueConverter; -import org.apache.dubbo.common.convert.multiple.StringToListConverter; import org.apache.dubbo.common.utils.CollectionUtils; import org.junit.jupiter.api.BeforeEach; @@ -47,7 +45,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; /** - * {@link StringToListConverter} Test + * {@link StringToNavigableSetConverter} Test * * @since 2.7.6 */ diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToQueueConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToQueueConverterTest.java similarity index 97% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToQueueConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToQueueConverterTest.java index 539693adfd6..2933d04bdf8 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToQueueConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToQueueConverterTest.java @@ -14,9 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert.multiple; +package org.apache.dubbo.common.convert.multiple; -import org.apache.dubbo.common.convert.multiple.StringToQueueConverter; import org.apache.dubbo.common.utils.CollectionUtils; import org.junit.jupiter.api.BeforeEach; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSetConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToSetConverterTest.java similarity index 97% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSetConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToSetConverterTest.java index 269d709a66b..5925cec226e 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSetConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToSetConverterTest.java @@ -14,9 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert.multiple; +package org.apache.dubbo.common.convert.multiple; -import org.apache.dubbo.common.convert.multiple.StringToSetConverter; import org.apache.dubbo.common.utils.CollectionUtils; import org.junit.jupiter.api.BeforeEach; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSortedSetConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToSortedSetConverterTest.java similarity index 95% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSortedSetConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToSortedSetConverterTest.java index 6af8f9de9ee..2ed12526cee 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToSortedSetConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToSortedSetConverterTest.java @@ -14,10 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert.multiple; +package org.apache.dubbo.common.convert.multiple; -import org.apache.dubbo.common.convert.multiple.MultiValueConverter; -import org.apache.dubbo.common.convert.multiple.StringToListConverter; import org.apache.dubbo.common.utils.CollectionUtils; import org.junit.jupiter.api.BeforeEach; @@ -47,7 +45,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; /** - * {@link StringToListConverter} Test + * {@link StringToSortedSetConverter} Test * * @since 2.7.6 */ diff --git a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToTransferQueueConverterTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToTransferQueueConverterTest.java similarity index 95% rename from dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToTransferQueueConverterTest.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToTransferQueueConverterTest.java index 4d8d66b7db4..e4cc101b910 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/convert/multiple/StringToTransferQueueConverterTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/convert/multiple/StringToTransferQueueConverterTest.java @@ -14,10 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.convert.multiple; +package org.apache.dubbo.common.convert.multiple; -import org.apache.dubbo.common.convert.multiple.MultiValueConverter; -import org.apache.dubbo.common.convert.multiple.StringToListConverter; import org.apache.dubbo.common.utils.CollectionUtils; import org.junit.jupiter.api.BeforeEach; @@ -48,7 +46,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; /** - * {@link StringToListConverter} Test + * {@link StringToTransferQueueConverter} Test * * @since 2.7.6 */ diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java index 014405959f0..24cb292104d 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/PojoUtilsTest.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.common.utils; -import com.alibaba.fastjson.JSONObject; import org.apache.dubbo.common.model.Person; import org.apache.dubbo.common.model.SerializablePerson; import org.apache.dubbo.common.model.User; @@ -26,6 +25,7 @@ import org.apache.dubbo.common.model.person.PersonStatus; import org.apache.dubbo.common.model.person.Phone; +import com.alibaba.fastjson.JSONObject; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringConstantFieldValuePredicateTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringConstantFieldValuePredicateTest.java new file mode 100644 index 00000000000..061854296f5 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringConstantFieldValuePredicateTest.java @@ -0,0 +1,47 @@ +/* + * 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.common.utils; + +import org.junit.jupiter.api.Test; + +import java.util.function.Predicate; + +import static org.apache.dubbo.common.utils.StringConstantFieldValuePredicate.of; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link StringConstantFieldValuePredicate} Test + * + * @since 2.7.8 + */ +public class StringConstantFieldValuePredicateTest { + + public static final String S1 = "1"; + + public static final Object O1 = "2"; + + public static final Object O2 = 3; + + @Test + public void test() { + Predicate predicate = of(getClass()); + assertTrue(predicate.test("1")); + assertTrue(predicate.test("2")); + assertFalse(predicate.test("3")); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java index 736e9d84338..0d38e6c8c54 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java @@ -18,19 +18,33 @@ import org.junit.jupiter.api.Test; -import java.util.*; - +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static java.util.Arrays.asList; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.common.utils.CollectionUtils.ofSet; +import static org.apache.dubbo.common.utils.StringUtils.splitToList; +import static org.apache.dubbo.common.utils.StringUtils.splitToSet; +import static org.apache.dubbo.common.utils.StringUtils.toCommaDelimitedString; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.isEmptyOrNullString; import static org.hamcrest.Matchers.nullValue; -import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class StringUtilsTest { @Test @@ -234,16 +248,32 @@ public void testSplit() throws Exception { public void testSplitToList() throws Exception { String str = "d,1,2,4"; - assertEquals(4, StringUtils.splitToList(str, ',').size()); - assertEquals(Arrays.asList(str.split(",")), StringUtils.splitToList(str, ',')); + assertEquals(4, splitToList(str, ',').size()); + assertEquals(asList(str.split(",")), splitToList(str, ',')); - assertEquals(1, StringUtils.splitToList(str, 'a').size()); - assertEquals(Arrays.asList(str.split("a")), StringUtils.splitToList(str, 'a')); + assertEquals(1, splitToList(str, 'a').size()); + assertEquals(asList(str.split("a")), splitToList(str, 'a')); - assertEquals(0, StringUtils.splitToList("", 'a').size()); - assertEquals(0, StringUtils.splitToList(null, 'a').size()); + assertEquals(0, splitToList("", 'a').size()); + assertEquals(0, splitToList(null, 'a').size()); } + /** + * Test {@link StringUtils#splitToSet(String, char, boolean)} + * + * @since 2.7.8 + */ + @Test + public void testSplitToSet() { + String value = "1# 2#3 #4#3"; + Set values = splitToSet(value, '#', false); + assertEquals(ofSet("1", " 2", "3 ", "4", "3"), values); + + values = splitToSet(value, '#', true); + assertEquals(ofSet("1", "2", "3", "4"), values); + } + + @Test public void testTranslate() throws Exception { String s = "16314"; @@ -363,4 +393,29 @@ public void testParseParameters() { assertEquals(0, illegalMap.size()); } + /** + * Test {@link StringUtils#toCommaDelimitedString(String, String...)} + * @since 2.7.8 + */ + @Test + public void testToCommaDelimitedString() { + String value = toCommaDelimitedString(null); + assertNull(value); + + value = toCommaDelimitedString(null, null); + assertNull(value); + + value = toCommaDelimitedString(""); + assertEquals("", value); + + value = toCommaDelimitedString("one"); + assertEquals("one", value); + + value = toCommaDelimitedString("one", "two"); + assertEquals("one,two", value); + + value = toCommaDelimitedString("one", "two", "three"); + assertEquals("one,two,three", value); + } + } diff --git a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java index 58fc3cccdd3..24c4f0028cf 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java @@ -49,7 +49,12 @@ public class ConfigManagerTest { @BeforeEach public void init() { - configManager.clear(); + configManager.destroy(); + } + + @Test + public void testDestroy() { + assertTrue(configManager.configsCache.isEmpty()); } @Test diff --git a/dubbo-common/src/test/java/org/apache/dubbo/event/EchoEventListener2.java b/dubbo-common/src/test/java/org/apache/dubbo/event/EchoEventListener2.java index 18e7cf90aeb..0d27802d15f 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/event/EchoEventListener2.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/event/EchoEventListener2.java @@ -41,7 +41,7 @@ public void onEvent(Event event) { @Override public int getPriority() { - return 0; + return -1; } public int getEventOccurs() { diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/config/ConfigTest.java b/dubbo-compatible/src/test/java/org/apache/dubbo/config/ConfigTest.java index 95608d76c23..9ce219193a1 100644 --- a/dubbo-compatible/src/test/java/org/apache/dubbo/config/ConfigTest.java +++ b/dubbo-compatible/src/test/java/org/apache/dubbo/config/ConfigTest.java @@ -35,14 +35,14 @@ public class ConfigTest { @AfterEach public void tearDown() { - ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); } @BeforeEach public void setup() { // In IDE env, make sure adding the following argument to VM options System.setProperty("java.net.preferIPv4Stack", "true"); - ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); } @Test diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java b/dubbo-compatible/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java index d30f632fb1f..883dc12cbce 100644 --- a/dubbo-compatible/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java +++ b/dubbo-compatible/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java @@ -38,12 +38,12 @@ public class ReferenceConfigTest { @BeforeEach public void setUp() { - ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); } @AfterEach public void tearDown() { - ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); } @Test diff --git a/dubbo-config/dubbo-config-api/pom.xml b/dubbo-config/dubbo-config-api/pom.xml index 89580bd5347..4ccfd67a36c 100644 --- a/dubbo-config/dubbo-config-api/pom.xml +++ b/dubbo-config/dubbo-config-api/pom.xml @@ -135,6 +135,12 @@ dubbo-registry-eureka ${project.parent.version} test + + + com.google.guava + guava + + @@ -156,6 +162,12 @@ dubbo-metadata-report-zookeeper ${project.parent.version} test + + + com.google.guava + guava + + @@ -170,6 +182,19 @@ dubbo-metadata-report-nacos ${project.parent.version} test + + + com.google.guava + guava + + + + + + org.apache.dubbo + dubbo-metadata-report-consul + ${project.parent.version} + test @@ -191,6 +216,12 @@ dubbo-configcenter-nacos ${project.parent.version} test + + + com.google.guava + guava + + diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java index df9eed242c3..570f7a49f0e 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.Version; import org.apache.dubbo.common.bytecode.Wrapper; +import org.apache.dubbo.common.constants.RegistryConstants; import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -31,10 +32,10 @@ import org.apache.dubbo.config.bootstrap.DubboBootstrap; import org.apache.dubbo.config.event.ReferenceConfigDestroyedEvent; import org.apache.dubbo.config.event.ReferenceConfigInitializedEvent; +import org.apache.dubbo.config.support.Parameter; import org.apache.dubbo.config.utils.ConfigValidationUtils; import org.apache.dubbo.event.Event; import org.apache.dubbo.event.EventDispatcher; -import org.apache.dubbo.metadata.WritableMetadataService; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Protocol; import org.apache.dubbo.rpc.ProxyFactory; @@ -57,25 +58,25 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE; import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY; import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR; +import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR_CHAR; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE; -import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE; -import static org.apache.dubbo.common.constants.CommonConstants.METADATA_KEY; import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY; import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROXY_CLASS_REF; -import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.SEMICOLON_SPLIT_PATTERN; import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY; import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost; +import static org.apache.dubbo.common.utils.StringUtils.splitToSet; import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY; -import static org.apache.dubbo.registry.Constants.CONSUMER_PROTOCOL; import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY; import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL; import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY; @@ -140,6 +141,13 @@ public class ReferenceConfig extends ReferenceConfigBase { private DubboBootstrap bootstrap; + /** + * The service names that the Dubbo interface subscribed. + * + * @since 2.7.8 + */ + private String services; + public ReferenceConfig() { super(); this.repository = ApplicationModel.getServiceRepository(); @@ -150,6 +158,40 @@ public ReferenceConfig(Reference reference) { this.repository = ApplicationModel.getServiceRepository(); } + /** + * Get a string presenting the service names that the Dubbo interface subscribed. + * If it is a multiple-values, the content will be a comma-delimited String. + * + * @return non-null + * @see RegistryConstants#SUBSCRIBED_SERVICE_NAMES_KEY + * @since 2.7.8 + */ + @Parameter(key = SUBSCRIBED_SERVICE_NAMES_KEY) + public String getServices() { + return services; + } + + /** + * It's an alias method for {@link #getServices()}, but the more convenient. + * + * @return the String {@link List} presenting the Dubbo interface subscribed + * @since 2.7.8 + */ + @Parameter(excluded = true) + public Set getSubscribedServices() { + return splitToSet(getServices(), COMMA_SEPARATOR_CHAR); + } + + /** + * Set the service names that the Dubbo interface subscribed. + * + * @param services If it is a multiple-values, the content will be a comma-delimited String. + * @since 2.7.8 + */ + public void setServices(String services) { + this.services = services; + } + public synchronized T get() { if (destroyed) { throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!"); @@ -221,10 +263,6 @@ public synchronized void init() { // appendParameters(map, consumer, Constants.DEFAULT_KEY); AbstractConfig.appendParameters(map, consumer); AbstractConfig.appendParameters(map, this); - MetadataReportConfig metadataReportConfig = getMetadataReportConfig(); - if (metadataReportConfig != null && metadataReportConfig.isValid()) { - map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE); - } Map attributes = null; if (CollectionUtils.isNotEmpty(getMethods())) { attributes = new HashMap<>(); @@ -355,16 +393,6 @@ private T createProxy(Map map) { if (logger.isInfoEnabled()) { logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl()); } - /** - * @since 2.7.0 - * ServiceData Store - */ - String metadata = map.get(METADATA_KEY); - WritableMetadataService metadataService = WritableMetadataService.getExtension(metadata == null ? DEFAULT_METADATA_STORAGE_TYPE : metadata); - if (metadataService != null) { - URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map); - metadataService.publishServiceDefinition(consumerURL); - } // create service proxy return (T) PROXY_FACTORY.getProxy(invoker, ProtocolUtils.isGeneric(generic)); } @@ -469,7 +497,7 @@ public void setBootstrap(DubboBootstrap bootstrap) { } private void postProcessConfig() { - List configPostProcessors =ExtensionLoader.getExtensionLoader(ConfigPostProcessor.class) + List configPostProcessors = ExtensionLoader.getExtensionLoader(ConfigPostProcessor.class) .getActivateExtension(URL.valueOf("configPostProcessor://"), (String[]) null); configPostProcessors.forEach(component -> component.postProcessReferConfig(this)); } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java index 3ad4545f382..5173bf71ced 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java @@ -37,7 +37,6 @@ import org.apache.dubbo.config.utils.ConfigValidationUtils; import org.apache.dubbo.event.Event; import org.apache.dubbo.event.EventDispatcher; -import org.apache.dubbo.metadata.WritableMetadataService; import org.apache.dubbo.rpc.Exporter; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Protocol; @@ -68,16 +67,13 @@ import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY; import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE; -import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND; import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE; -import static org.apache.dubbo.common.constants.CommonConstants.METADATA_KEY; import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY; import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; import static org.apache.dubbo.common.constants.CommonConstants.REGISTER_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY; @@ -187,7 +183,7 @@ public synchronized void export() { if (bootstrap == null) { bootstrap = DubboBootstrap.getInstance(); - bootstrap.init(); + bootstrap.initialize(); } checkAndUpdateSubConfigs(); @@ -344,10 +340,6 @@ private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List r AbstractConfig.appendParameters(map, provider); AbstractConfig.appendParameters(map, protocolConfig); AbstractConfig.appendParameters(map, this); - MetadataReportConfig metadataReportConfig = getMetadataReportConfig(); - if (metadataReportConfig != null && metadataReportConfig.isValid()) { - map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE); - } if (CollectionUtils.isNotEmpty(getMethods())) { for (MethodConfig method : getMethods()) { AbstractConfig.appendParameters(map, method, method.getName()); @@ -502,14 +494,6 @@ private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List r Exporter exporter = PROTOCOL.export(wrapperInvoker); exporters.add(exporter); } - /** - * @since 2.7.0 - * ServiceData Store - */ - WritableMetadataService metadataService = WritableMetadataService.getExtension(url.getParameter(METADATA_KEY, DEFAULT_METADATA_STORAGE_TYPE)); - if (metadataService != null) { - metadataService.publishServiceDefinition(url); - } } } this.urls.add(url); diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java index cd92fe5e52c..10dd4f209f7 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java @@ -52,7 +52,6 @@ import org.apache.dubbo.config.bootstrap.builders.RegistryBuilder; import org.apache.dubbo.config.bootstrap.builders.ServiceBuilder; import org.apache.dubbo.config.context.ConfigManager; -import org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter; import org.apache.dubbo.config.utils.ConfigValidationUtils; import org.apache.dubbo.config.utils.ReferenceConfigCache; import org.apache.dubbo.event.EventDispatcher; @@ -66,6 +65,7 @@ import org.apache.dubbo.registry.client.ServiceDiscovery; import org.apache.dubbo.registry.client.ServiceDiscoveryRegistry; import org.apache.dubbo.registry.client.ServiceInstance; +import org.apache.dubbo.registry.client.ServiceInstanceCustomizer; import org.apache.dubbo.registry.support.AbstractRegistryFactory; import org.apache.dubbo.rpc.model.ApplicationModel; @@ -93,17 +93,17 @@ import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SPLIT_PATTERN; import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; import static org.apache.dubbo.common.function.ThrowableAction.execute; import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; -import static org.apache.dubbo.metadata.WritableMetadataService.getExtension; import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.setMetadataStorageType; import static org.apache.dubbo.remoting.Constants.CLIENT_KEY; /** * See {@link ApplicationModel} and {@link ExtensionLoader} for why this class is designed to be singleton. - * + *

* The bootstrap class of Dubbo - * + *

* Get singleton instance by calling static method {@link #getInstance()}. * Designed as singleton because some classes inside Dubbo, such as ExtensionLoader, are designed only for one instance per process. * @@ -141,7 +141,7 @@ public class DubboBootstrap extends GenericEventListener { private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension(); - private final ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension(); + private final ExecutorRepository executorRepository = getExtensionLoader(ExecutorRepository.class).getDefaultExtension(); private final ConfigManager configManager; @@ -165,7 +165,7 @@ public class DubboBootstrap extends GenericEventListener { private volatile MetadataService metadataService; - private volatile MetadataServiceExporter metadataServiceExporter; + private volatile Set metadataServiceExporters; private List> exportedServices = new ArrayList<>(); @@ -500,7 +500,7 @@ public void init() { /** * Initialize */ - private void initialize() { + public void initialize() { if (!initialized.compareAndSet(false, true)) { return; } @@ -509,14 +509,17 @@ private void initialize() { startConfigCenter(); - useRegistryAsConfigCenterIfNecessary(); - loadRemoteConfigs(); checkGlobalConfigs(); + // @since 2.7.8 + startMetadataCenter(); + initMetadataService(); + initMetadataServiceExports(); + initEventListener(); if (logger.isInfoEnabled()) { @@ -583,6 +586,9 @@ private void checkGlobalConfigs() { } private void startConfigCenter() { + + useRegistryAsConfigCenterIfNecessary(); + Collection configCenters = configManager.getConfigCenters(); // check Config Center @@ -610,7 +616,10 @@ private void startConfigCenter() { configManager.refreshAll(); } - private void startMetadataReport() { + private void startMetadataCenter() { + + useRegistryAsMetadataCenterIfNecessary(); + ApplicationConfig applicationConfig = getApplication(); String metadataType = applicationConfig.getMetadataType(); @@ -646,33 +655,87 @@ private void useRegistryAsConfigCenterIfNecessary() { return; } - configManager.getDefaultRegistries().stream() - .filter(registryConfig -> registryConfig.getUseAsConfigCenter() == null || registryConfig.getUseAsConfigCenter()) - .forEach(registryConfig -> { - String protocol = registryConfig.getProtocol(); - String id = "config-center-" + protocol + "-" + registryConfig.getPort(); - ConfigCenterConfig cc = new ConfigCenterConfig(); - cc.setId(id); - if (cc.getParameters() == null) { - cc.setParameters(new HashMap<>()); - } - if (registryConfig.getParameters() != null) { - cc.getParameters().putAll(registryConfig.getParameters()); - } - cc.getParameters().put(CLIENT_KEY, registryConfig.getClient()); - cc.setProtocol(registryConfig.getProtocol()); - cc.setPort(registryConfig.getPort()); - cc.setAddress(getRegistryCompatibleAddress(registryConfig.getAddress())); - cc.setNamespace(registryConfig.getGroup()); - cc.setUsername(registryConfig.getUsername()); - cc.setPassword(registryConfig.getPassword()); - if (registryConfig.getTimeout() != null) { - cc.setTimeout(registryConfig.getTimeout().longValue()); - } - cc.setHighestPriority(false); - configManager.addConfigCenter(cc); - }); - startConfigCenter(); + configManager + .getDefaultRegistries() + .stream() + .filter(this::isUsedRegistryAsConfigCenter) + .map(this::registryAsConfigCenter) + .forEach(configManager::addConfigCenter); + } + + private boolean isUsedRegistryAsConfigCenter(RegistryConfig registryConfig) { + // TODO: confirm ? registryConfig.getUseAsConfigCenter() == null || registryConfig.getUseAsConfigCenter() + return Boolean.TRUE.equals(registryConfig.getUseAsConfigCenter()); + } + + private ConfigCenterConfig registryAsConfigCenter(RegistryConfig registryConfig) { + String protocol = registryConfig.getProtocol(); + Integer port = registryConfig.getPort(); + String id = "config-center-" + protocol + "-" + port; + ConfigCenterConfig cc = new ConfigCenterConfig(); + cc.setId(id); + if (cc.getParameters() == null) { + cc.setParameters(new HashMap<>()); + } + if (registryConfig.getParameters() != null) { + cc.getParameters().putAll(registryConfig.getParameters()); // copy the parameters + } + cc.getParameters().put(CLIENT_KEY, registryConfig.getClient()); + cc.setProtocol(protocol); + cc.setPort(port); + cc.setGroup(registryConfig.getGroup()); + cc.setAddress(getRegistryCompatibleAddress(registryConfig.getAddress())); + cc.setNamespace(registryConfig.getGroup()); + cc.setUsername(registryConfig.getUsername()); + cc.setPassword(registryConfig.getPassword()); + if (registryConfig.getTimeout() != null) { + cc.setTimeout(registryConfig.getTimeout().longValue()); + } + cc.setHighestPriority(false); + return cc; + } + + private void useRegistryAsMetadataCenterIfNecessary() { + + Collection metadataConfigs = configManager.getMetadataConfigs(); + + if (CollectionUtils.isNotEmpty(metadataConfigs)) { + return; + } + + configManager + .getDefaultRegistries() + .stream() + .filter(this::isUsedRegistryAsMetadataCenter) + .map(this::registryAsMetadataCenter) + .forEach(configManager::addMetadataReport); + + } + + private boolean isUsedRegistryAsMetadataCenter(RegistryConfig registryConfig) { + // TODO: confirm ? registryConfig.getUseAsMetadataCenter() == null || registryConfig.getUseAsMetadataCenter() + return Boolean.TRUE.equals(registryConfig.getUseAsMetadataCenter()); + } + + private MetadataReportConfig registryAsMetadataCenter(RegistryConfig registryConfig) { + String protocol = registryConfig.getProtocol(); + Integer port = registryConfig.getPort(); + String id = "metadata-center-" + protocol + "-" + port; + MetadataReportConfig metadataReportConfig = new MetadataReportConfig(); + metadataReportConfig.setId(id); + if (metadataReportConfig.getParameters() == null) { + metadataReportConfig.setParameters(new HashMap<>()); + } + if (registryConfig.getParameters() != null) { + metadataReportConfig.getParameters().putAll(registryConfig.getParameters()); // copy the parameters + } + metadataReportConfig.getParameters().put(CLIENT_KEY, registryConfig.getClient()); + metadataReportConfig.setGroup(registryConfig.getGroup()); + metadataReportConfig.setAddress(getRegistryCompatibleAddress(registryConfig.getAddress())); + metadataReportConfig.setUsername(registryConfig.getUsername()); + metadataReportConfig.setPassword(registryConfig.getPassword()); + metadataReportConfig.setTimeout(registryConfig.getTimeout()); + return metadataReportConfig; } private String getRegistryCompatibleAddress(String registryAddress) { @@ -719,12 +782,17 @@ private void loadRemoteConfigs() { /** - * Initialize {@link MetadataService} from {@link WritableMetadataService}'s extension + * Initialize {@link #metadataService WritableMetadataService} from {@link WritableMetadataService}'s extension */ private void initMetadataService() { - startMetadataReport(); - this.metadataService = getExtension(getMetadataType()); - this.metadataServiceExporter = new ConfigurableMetadataServiceExporter(metadataService); + this.metadataService = WritableMetadataService.getExtension(getMetadataType()); + } + + /** + * Initialize {@link #metadataServiceExporters MetadataServiceExporter} + */ + private void initMetadataServiceExports() { + this.metadataServiceExporters = getExtensionLoader(MetadataServiceExporter.class).getSupportedExtensionInstances(); } /** @@ -926,13 +994,21 @@ public DubboBootstrap addEventListener(EventListener listener) { * export {@link MetadataService} */ private void exportMetadataService() { - metadataServiceExporter.export(); + metadataServiceExporters + .stream() + .filter(this::supports) + .forEach(MetadataServiceExporter::export); } private void unexportMetadataService() { - if (metadataServiceExporter != null && metadataServiceExporter.isExported()) { - metadataServiceExporter.unexport(); - } + metadataServiceExporters + .stream() + .filter(this::supports) + .forEach(MetadataServiceExporter::unexport); + } + + private boolean supports(MetadataServiceExporter exporter) { + return exporter.supports(getMetadataType()); } private void exportServices() { @@ -1025,9 +1101,37 @@ private void registerServiceInstance() { ServiceInstance serviceInstance = createServiceInstance(serviceName, host, port); + preRegisterServiceInstance(serviceInstance); + getServiceDiscoveries().forEach(serviceDiscovery -> serviceDiscovery.register(serviceInstance)); } + /** + * Pre-register {@link ServiceInstance the service instance} + * + * @param serviceInstance {@link ServiceInstance the service instance} + * @since 2.7.8 + */ + private void preRegisterServiceInstance(ServiceInstance serviceInstance) { + customizeServiceInstance(serviceInstance); + } + + /** + * Customize {@link ServiceInstance the service instance} + * + * @param serviceInstance {@link ServiceInstance the service instance} + * @since 2.7.8 + */ + private void customizeServiceInstance(ServiceInstance serviceInstance) { + ExtensionLoader loader = + getExtensionLoader(ServiceInstanceCustomizer.class); + // FIXME, sort customizer before apply + loader.getSupportedExtensionInstances().forEach(customizer -> { + // customizes + customizer.customize(serviceInstance); + }); + } + private URL selectMetadataServiceExportedURL() { URL selectedURL = null; @@ -1118,7 +1222,7 @@ private void clearApplicationModel() { } private void clearConfigs() { - configManager.clear(); + configManager.destroy(); if (logger.isDebugEnabled()) { logger.debug(NAME + "'s configs have been clear."); } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilder.java index 69e798433bd..99af153c301 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilder.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilder.java @@ -24,6 +24,8 @@ import java.util.ArrayList; import java.util.List; +import static org.apache.dubbo.common.utils.StringUtils.toCommaDelimitedString; + /** * This is a builder for build {@link ReferenceConfigBase}. * @@ -65,6 +67,13 @@ public class ReferenceBuilder extends AbstractReferenceBuilder protocol(String protocol) { return getThis(); } + /** + * @param service one service name + * @param otherServices other service names + * @return {@link ReferenceBuilder} + * @since 2.7.8 + */ + public ReferenceBuilder services(String service, String... otherServices) { + this.services = toCommaDelimitedString(service, otherServices); + return getThis(); + } + public ReferenceConfig build() { ReferenceConfig reference = new ReferenceConfig<>(); super.build(reference); @@ -132,6 +152,8 @@ public ReferenceConfig build() { reference.setMethods(methods); reference.setConsumer(consumer); reference.setProtocol(protocol); + // @since 2.7.8 + reference.setServices(services); return reference; } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilder.java index f2ffab86e3a..d717aaaf66f 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilder.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilder.java @@ -285,6 +285,16 @@ public RegistryBuilder appendParameter(String key, String value) { return getThis(); } + /** + * @param name the parameter name + * @param value the parameter value + * @return {@link RegistryBuilder} + * @since 2.7.8 + */ + public RegistryBuilder parameter(String name, String value) { + return appendParameter(name, value); + } + public RegistryBuilder appendParameters(Map appendParameters) { this.parameters = appendParameters(parameters, appendParameters); return getThis(); diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/PublishingServiceDefinitionListener.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/PublishingServiceDefinitionListener.java new file mode 100644 index 00000000000..9731034c70a --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/PublishingServiceDefinitionListener.java @@ -0,0 +1,74 @@ +/* + * 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.config.event.listener; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.AbstractInterfaceConfig; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.MetadataReportConfig; +import org.apache.dubbo.config.event.ReferenceConfigInitializedEvent; +import org.apache.dubbo.config.event.ServiceConfigExportedEvent; +import org.apache.dubbo.event.EventListener; +import org.apache.dubbo.event.GenericEventListener; +import org.apache.dubbo.metadata.WritableMetadataService; + +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.metadata.WritableMetadataService.getExtension; + +/** + * An {@link EventListener} {@link WritableMetadataService#publishServiceDefinition(URL) publishs the service definition} + * when {@link ServiceConfigExportedEvent the event of the exported Dubbo service} and + * {@link ReferenceConfigInitializedEvent the event of the referenced Dubbo service} is raised. + * + * @see GenericEventListener + * @see ServiceConfigExportedEvent + * @see ReferenceConfigInitializedEvent + * @since 2.7.8 + */ +public class PublishingServiceDefinitionListener extends GenericEventListener { + + public void onEvent(ReferenceConfigInitializedEvent event) { + handleEvent(event.getReferenceConfig()); + } + + public void onEvent(ServiceConfigExportedEvent event) { + handleEvent(event.getServiceConfig()); + } + + private void handleEvent(AbstractInterfaceConfig config) { + String metadataType = getMetadataType(config); + for (URL exportedURL : config.getExportedUrls()) { + WritableMetadataService metadataService = getExtension(metadataType); + if (metadataService != null) { + metadataService.publishServiceDefinition(exportedURL); + } + } + } + + private String getMetadataType(AbstractInterfaceConfig config) { + ApplicationConfig applicationConfig = config.getApplication(); + String metadataType = applicationConfig.getMetadataType(); + if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) { + MetadataReportConfig metadataReportConfig = config.getMetadataReportConfig(); + if (metadataReportConfig == null || !metadataReportConfig.isValid()) { + metadataType = DEFAULT_METADATA_STORAGE_TYPE; + } + } + return metadataType; + } +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/ServiceNameMappingListener.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/ServiceNameMappingListener.java index 4dcfde3a94a..8607b51f37c 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/ServiceNameMappingListener.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/ServiceNameMappingListener.java @@ -24,8 +24,6 @@ import java.util.List; -import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; import static org.apache.dubbo.metadata.ServiceNameMapping.getDefaultExtension; /** @@ -45,11 +43,7 @@ public void onEvent(ServiceConfigExportedEvent event) { ServiceConfig serviceConfig = event.getServiceConfig(); List exportedURLs = serviceConfig.getExportedUrls(); exportedURLs.forEach(url -> { - String serviceInterface = url.getServiceInterface(); - String group = url.getParameter(GROUP_KEY); - String version = url.getParameter(VERSION_KEY); - String protocol = url.getProtocol(); - serviceNameMapping.map(serviceInterface, group, version, protocol); + serviceNameMapping.map(url); }); } } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/AbstractMetadataServiceExporter.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/AbstractMetadataServiceExporter.java new file mode 100644 index 00000000000..ce2b389c220 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/AbstractMetadataServiceExporter.java @@ -0,0 +1,150 @@ +/* + * 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.config.metadata; + +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.MetadataService; +import org.apache.dubbo.metadata.MetadataServiceExporter; +import org.apache.dubbo.metadata.MetadataServiceType; +import org.apache.dubbo.metadata.WritableMetadataService; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static java.util.EnumSet.of; +import static org.apache.dubbo.metadata.MetadataServiceType.getOrDefault; + +/** + * The abstract implementation of {@link MetadataServiceExporter} to provider the commons features for sub-types + * + * @see MetadataServiceExporter + * @see MetadataService + * @since 2.7.8 + */ +public abstract class AbstractMetadataServiceExporter implements MetadataServiceExporter { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + protected final WritableMetadataService metadataService; + + private final int priority; + + private final Set supportedMetadataServiceTypes; + + private volatile boolean exported = false; + + public AbstractMetadataServiceExporter(String metadataType, + int priority, + MetadataServiceType supportMetadataServiceType, + MetadataServiceType... otherSupportMetadataServiceTypes) { + this(metadataType, priority, of(supportMetadataServiceType, otherSupportMetadataServiceTypes)); + } + + public AbstractMetadataServiceExporter(String metadataType, + int priority, + Set supportedMetadataServiceTypes) { + this.metadataService = WritableMetadataService.getExtension(metadataType); + this.priority = priority; + this.supportedMetadataServiceTypes = supportedMetadataServiceTypes; + } + + @Override + public final MetadataServiceExporter export() { + if (!isExported()) { + try { + doExport(); + exported = true; + } catch (Exception e) { + if (logger.isErrorEnabled()) { + logger.error("Exporting the MetadataService fails", e); + } + exported = false; + } + } else { + if (logger.isWarnEnabled()) { + logger.warn("The MetadataService has been exported : " + getExportedURLs()); + } + } + return this; + } + + @Override + public final MetadataServiceExporter unexport() { + if (isExported()) { + try { + doUnexport(); + exported = false; + } catch (Exception e) { + if (logger.isErrorEnabled()) { + logger.error("UnExporting the MetadataService fails", e); + } + } + } + return this; + } + + @Override + public List getExportedURLs() { + return metadataService + .getExportedURLs() + .stream() + .map(URL::valueOf) + .collect(Collectors.toList()); + } + + @Override + public boolean isExported() { + return exported; + } + + @Override + public final boolean supports(String metadataType) { + MetadataServiceType metadataServiceType = getOrDefault(metadataType); + return supportedMetadataServiceTypes.contains(metadataServiceType); + } + + @Override + public int getPriority() { + return priority; + } + + /** + * Exports the {@link MetadataService} + * + * @throws Exception If some exception occurs + */ + protected abstract void doExport() throws Exception; + + /** + * Unexports the {@link MetadataService} + * + * @throws Exception If some exception occurs + */ + protected abstract void doUnexport() throws Exception; + + /** + * Get the underlying of {@link MetadataService} + * + * @return non-null + */ + public WritableMetadataService getMetadataService() { + return metadataService; + } +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java index fdb011f8953..d89fb7719fc 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java @@ -17,8 +17,6 @@ package org.apache.dubbo.config.metadata; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.RegistryConfig; @@ -26,12 +24,15 @@ import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.metadata.MetadataService; import org.apache.dubbo.metadata.MetadataServiceExporter; +import org.apache.dubbo.metadata.MetadataServiceType; import org.apache.dubbo.rpc.model.ApplicationModel; import java.util.ArrayList; import java.util.List; import static java.util.Collections.emptyList; +import static java.util.EnumSet.allOf; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO; /** @@ -49,56 +50,41 @@ * @see ConfigManager * @since 2.7.5 */ -public class ConfigurableMetadataServiceExporter implements MetadataServiceExporter { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final MetadataService metadataService; +public class ConfigurableMetadataServiceExporter extends AbstractMetadataServiceExporter { private volatile ServiceConfig serviceConfig; - public ConfigurableMetadataServiceExporter(MetadataService metadataService) { - this.metadataService = metadataService; + public ConfigurableMetadataServiceExporter() { + super(DEFAULT_METADATA_STORAGE_TYPE, MAX_PRIORITY, allOf(MetadataServiceType.class)); } @Override - public ConfigurableMetadataServiceExporter export() { - - if (!isExported()) { - - ServiceConfig serviceConfig = new ServiceConfig<>(); - serviceConfig.setApplication(getApplicationConfig()); - serviceConfig.setRegistries(getRegistries()); - serviceConfig.setProtocol(generateMetadataProtocol()); - serviceConfig.setInterface(MetadataService.class); - serviceConfig.setRef(metadataService); - serviceConfig.setGroup(getApplicationConfig().getName()); - serviceConfig.setVersion(metadataService.version()); - - // export - serviceConfig.export(); - - if (logger.isInfoEnabled()) { - logger.info("The MetadataService exports urls : " + serviceConfig.getExportedUrls()); - } - - this.serviceConfig = serviceConfig; - - } else { - if (logger.isWarnEnabled()) { - logger.warn("The MetadataService has been exported : " + serviceConfig.getExportedUrls()); - } + protected void doExport() throws Exception { + + ServiceConfig serviceConfig = new ServiceConfig<>(); + serviceConfig.setApplication(getApplicationConfig()); + serviceConfig.setRegistries(getRegistries()); + serviceConfig.setProtocol(generateMetadataProtocol()); + serviceConfig.setInterface(MetadataService.class); + serviceConfig.setRef(metadataService); + serviceConfig.setGroup(getApplicationConfig().getName()); + serviceConfig.setVersion(metadataService.version()); + + // export + serviceConfig.export(); + + if (logger.isInfoEnabled()) { + logger.info("The MetadataService exports urls : " + serviceConfig.getExportedUrls()); } - return this; + this.serviceConfig = serviceConfig; } @Override - public ConfigurableMetadataServiceExporter unexport() { - if (isExported()) { + protected void doUnexport() throws Exception { + if (serviceConfig != null) { serviceConfig.unexport(); } - return this; } @Override @@ -110,6 +96,11 @@ public boolean isExported() { return serviceConfig != null && serviceConfig.isExported(); } + @Override + public int getPriority() { + return MAX_PRIORITY; + } + private ApplicationConfig getApplicationConfig() { return ApplicationModel.getConfigManager().getApplication().get(); } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/RemoteMetadataServiceExporter.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/RemoteMetadataServiceExporter.java new file mode 100644 index 00000000000..6d4892101f7 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/RemoteMetadataServiceExporter.java @@ -0,0 +1,79 @@ +/* + * 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.config.metadata; + +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.metadata.MetadataServiceExporter; +import org.apache.dubbo.metadata.MetadataServiceType; +import org.apache.dubbo.metadata.URLRevisionResolver; +import org.apache.dubbo.metadata.WritableMetadataService; +import org.apache.dubbo.metadata.report.MetadataReport; +import org.apache.dubbo.metadata.report.MetadataReportInstance; +import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; + +import java.util.SortedSet; + +import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; + +/** + * The implementation of {@link MetadataServiceExporter} for + * {@link CommonConstants#REMOTE_METADATA_STORAGE_TYPE "remote" metadata storage type} + * + * @see MetadataServiceExporter + * @since 2.7.8 + */ +public class RemoteMetadataServiceExporter extends AbstractMetadataServiceExporter { + + private final URLRevisionResolver urlRevisionResolver; + + public RemoteMetadataServiceExporter() { + super(REMOTE_METADATA_STORAGE_TYPE, MIN_PRIORITY, MetadataServiceType.REMOTE, MetadataServiceType.COMPOSITE); + this.urlRevisionResolver = URLRevisionResolver.INSTANCE; + } + + @Override + protected void doExport() throws Exception { + WritableMetadataService metadataServiceDelegate = WritableMetadataService.getDefaultExtension(); + if (publishServiceMetadata(metadataServiceDelegate)) { + publicConsumerMetadata(metadataServiceDelegate); + } + } + + private boolean publishServiceMetadata(WritableMetadataService metadataServiceDelegate) { + String serviceName = metadataServiceDelegate.serviceName(); + SortedSet exportedURLs = metadataServiceDelegate.getExportedURLs(); + String revision = urlRevisionResolver.resolve(exportedURLs); + return getMetadataReport().saveExportedURLs(serviceName, revision, exportedURLs); + } + + private boolean publicConsumerMetadata(WritableMetadataService metadataServiceDelegate) { + String serviceName = metadataServiceDelegate.serviceName(); + SortedSet subscribedURLs = metadataServiceDelegate.getSubscribedURLs(); + String revision = urlRevisionResolver.resolve(subscribedURLs); + getMetadataReport().saveSubscribedData(new SubscriberMetadataIdentifier(serviceName, revision), subscribedURLs); + return true; + } + + private MetadataReport getMetadataReport() { + return MetadataReportInstance.getMetadataReport(true); + } + + @Override + protected void doUnexport() throws Exception { + // DOES NOTHING + } +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java index 2e46fa26024..8a91d1cce5e 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java @@ -223,10 +223,12 @@ public static URL loadMonitor(AbstractInterfaceConfig interfaceConfig, URL regis ApplicationConfig application = interfaceConfig.getApplication(); AbstractConfig.appendParameters(map, monitor); AbstractConfig.appendParameters(map, application); - String address = monitor.getAddress(); + String address = null; String sysaddress = System.getProperty("dubbo.monitor.address"); if (sysaddress != null && sysaddress.length() > 0) { address = sysaddress; + } else if (monitor != null) { + address = monitor.getAddress(); } if (ConfigUtils.isNotEmpty(address)) { if (!map.containsKey(PROTOCOL_KEY)) { @@ -237,7 +239,8 @@ public static URL loadMonitor(AbstractInterfaceConfig interfaceConfig, URL regis } } return UrlUtils.parseURL(address, map); - } else if ((REGISTRY_PROTOCOL.equals(monitor.getProtocol()) || SERVICE_REGISTRY_PROTOCOL.equals(monitor.getProtocol())) + } else if (monitor != null && + (REGISTRY_PROTOCOL.equals(monitor.getProtocol()) || SERVICE_REGISTRY_PROTOCOL.equals(monitor.getProtocol())) && registryURL != null) { return URLBuilder.from(registryURL) .setProtocol(DUBBO_PROTOCOL) diff --git a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener index db73041bd43..b1946c09f30 100644 --- a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener +++ b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener @@ -1,2 +1,4 @@ service-mapping=org.apache.dubbo.config.event.listener.ServiceNameMappingListener -config-logging=org.apache.dubbo.config.event.listener.LoggingEventListener \ No newline at end of file +config-logging=org.apache.dubbo.config.event.listener.LoggingEventListener +# since 2.7.8 +publishing-service-definition=org.apache.dubbo.config.event.listener.PublishingServiceDefinitionListener \ No newline at end of file diff --git a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter new file mode 100644 index 00000000000..1b843b6bbc7 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter @@ -0,0 +1,3 @@ +# since 2.7.8 +local = org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter +remote = org.apache.dubbo.config.metadata.RemoteMetadataServiceExporter \ No newline at end of file diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java index c992e48c0d9..775596c3fbe 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java @@ -21,6 +21,7 @@ import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.api.DemoService; import org.apache.dubbo.config.provider.impl.DemoServiceImpl; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -33,12 +34,12 @@ public class ReferenceConfigTest { @BeforeEach public void setUp() { -// ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); } @AfterEach public void tearDown() { -// ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); } @Test diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceConsumerBootstrap.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceConsumerBootstrap.java new file mode 100644 index 00000000000..824de82dae8 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceConsumerBootstrap.java @@ -0,0 +1,52 @@ +/* + * 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.config.bootstrap; + +import org.apache.dubbo.config.bootstrap.rest.UserService; + +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; + +/** + * Dubbo Provider Bootstrap + * + * @since 2.7.5 + */ +public class ConsulDubboServiceConsumerBootstrap { + + public static void main(String[] args) throws Exception { + + DubboBootstrap bootstrap = DubboBootstrap.getInstance() + .application("consul-dubbo-consumer", app -> app.metadata(DEFAULT_METADATA_STORAGE_TYPE)) + .registry("zookeeper", builder -> builder.address("consul://127.0.0.1:8500?registry-type=service&subscribed-services=consul-dubbo-provider") + .useAsConfigCenter(true) + .useAsMetadataCenter(true)) + .reference("echo", builder -> builder.interfaceClass(EchoService.class).protocol("dubbo")) + .reference("user", builder -> builder.interfaceClass(UserService.class).protocol("rest")) + .start(); + + EchoService echoService = bootstrap.getCache().get(EchoService.class); + UserService userService = bootstrap.getCache().get(UserService.class); + + for (int i = 0; i < 5; i++) { + Thread.sleep(2000L); + System.out.println(echoService.echo("Hello,World")); + System.out.println(userService.getUser(i * 1L)); + } + + bootstrap.stop(); + } +} diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceProviderBootstrap.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceProviderBootstrap.java new file mode 100644 index 00000000000..ef3894422e5 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceProviderBootstrap.java @@ -0,0 +1,42 @@ +/* + * 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.config.bootstrap; + +import org.apache.dubbo.config.bootstrap.rest.UserService; +import org.apache.dubbo.config.bootstrap.rest.UserServiceImpl; + +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; + +/** + * TODO + */ +public class ConsulDubboServiceProviderBootstrap { + + public static void main(String[] args) { + DubboBootstrap.getInstance() + .application("consul-dubbo-provider", app -> app.metadata(DEFAULT_METADATA_STORAGE_TYPE)) + .registry(builder -> builder.address("consul://127.0.0.1:8500?registry-type=service") + .useAsConfigCenter(true) + .useAsMetadataCenter(true)) + .protocol("dubbo", builder -> builder.port(-1).name("dubbo")) + .protocol("rest", builder -> builder.port(8081).name("rest")) + .service("echo", builder -> builder.interfaceClass(EchoService.class).ref(new EchoServiceImpl()).protocolIds("dubbo")) + .service("user", builder -> builder.interfaceClass(UserService.class).ref(new UserServiceImpl()).protocolIds("rest")) + .start() + .await(); + } +} diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceConsumerBootstrap.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceConsumerBootstrap.java index b91659d084a..37262e23c2e 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceConsumerBootstrap.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceConsumerBootstrap.java @@ -17,9 +17,10 @@ package org.apache.dubbo.config.bootstrap; import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.MetadataReportConfig; import org.apache.dubbo.config.bootstrap.rest.UserService; +import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; + /** * Dubbo Provider Bootstrap * @@ -30,21 +31,25 @@ public class NacosDubboServiceConsumerBootstrap { public static void main(String[] args) throws Exception { ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-nacos-consumer-demo"); -// applicationConfig.setMetadataType("remote"); + applicationConfig.setMetadataType(REMOTE_METADATA_STORAGE_TYPE); DubboBootstrap bootstrap = DubboBootstrap.getInstance() .application(applicationConfig) - // Zookeeper -// .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry.type=service&subscribed.services=dubbo-nacos-provider-demo")) -// .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry-type=service&subscribed-services=dubbo-nacos-provider-demo")) - .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry-type=service&subscribed-services=dubbo-nacos-provider-demo")) - .metadataReport(new MetadataReportConfig("nacos://127.0.0.1:8848")) + // Nacos in service registry type + .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry-type=service") + .useAsConfigCenter(true) + .useAsMetadataCenter(true)) + // Nacos in traditional registry type +// .registry("nacos-traditional", builder -> builder.address("nacos://127.0.0.1:8848")) + .reference("echo", builder -> builder.interfaceClass(EchoService.class).protocol("dubbo")) .reference("user", builder -> builder.interfaceClass(UserService.class).protocol("rest")) .start(); + EchoService echoService = bootstrap.getCache().get(EchoService.class); UserService userService = bootstrap.getCache().get(UserService.class); - for (int i = 0; i < 500; i++) { + for (int i = 0; i < 5; i++) { Thread.sleep(2000L); + System.out.println(echoService.echo("Hello,World")); System.out.println(userService.getUser(i * 1L)); } } diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceProviderBootstrap.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceProviderBootstrap.java index 35ed723e61c..f55790ac806 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceProviderBootstrap.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceProviderBootstrap.java @@ -17,10 +17,13 @@ package org.apache.dubbo.config.bootstrap; import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.MetadataReportConfig; import org.apache.dubbo.config.bootstrap.rest.UserService; import org.apache.dubbo.config.bootstrap.rest.UserServiceImpl; +import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE; + /** * Dubbo Provider Bootstrap * @@ -30,15 +33,16 @@ public class NacosDubboServiceProviderBootstrap { public static void main(String[] args) { ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-nacos-provider-demo"); -// applicationConfig.setMetadataType("remote"); + applicationConfig.setMetadataType(REMOTE_METADATA_STORAGE_TYPE); DubboBootstrap.getInstance() .application(applicationConfig) - // Zookeeper in service registry type - .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry-type=service").useAsConfigCenter(true)) - // Nacos -// .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry.type=service")) -// .registry(RegistryBuilder.newBuilder().address("etcd3://127.0.0.1:2379?registry.type=service").build()) - .metadataReport(new MetadataReportConfig("nacos://127.0.0.1:8848")) + // Nacos in service registry type + .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848") + .parameter(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE) + .useAsConfigCenter(true) + .useAsMetadataCenter(true)) + // Nacos in traditional registry type +// .registry("nacos-traditional", builder -> builder.address("nacos://127.0.0.1:8848")) .protocol("dubbo", builder -> builder.port(20885).name("dubbo")) .protocol("rest", builder -> builder.port(9090).name("rest")) .service(builder -> builder.id("echo").interfaceClass(EchoService.class).ref(new EchoServiceImpl()).protocolIds("dubbo")) diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceConsumerBootstrap.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceConsumerBootstrap.java index 9b0d866e12c..27f3eb98d46 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceConsumerBootstrap.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceConsumerBootstrap.java @@ -18,6 +18,10 @@ import org.apache.dubbo.config.bootstrap.rest.UserService; +import static org.apache.dubbo.common.constants.CommonConstants.COMPOSITE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE; + /** * Dubbo Provider Bootstrap * @@ -28,9 +32,12 @@ public class ZookeeperDubboServiceConsumerBootstrap { public static void main(String[] args) throws Exception { DubboBootstrap bootstrap = DubboBootstrap.getInstance() - .application("zookeeper-dubbo-consumer") - .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181?registry-type=service&subscribed-services=zookeeper-dubbo-provider")) - .reference("echo", builder -> builder.interfaceClass(EchoService.class).protocol("dubbo")) + .application("zookeeper-dubbo-consumer", app -> app.metadata(COMPOSITE_METADATA_STORAGE_TYPE)) + .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181") + .parameter(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE) + .useAsConfigCenter(true) + .useAsMetadataCenter(true)) + .reference("echo", builder -> builder.interfaceClass(EchoService.class).protocol("dubbo").services("zookeeper-dubbo-provider")) .reference("user", builder -> builder.interfaceClass(UserService.class).protocol("rest")) .start(); diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceProviderBootstrap.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceProviderBootstrap.java index c653fe70c3f..e9b946fe47c 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceProviderBootstrap.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceProviderBootstrap.java @@ -19,6 +19,10 @@ import org.apache.dubbo.config.bootstrap.rest.UserService; import org.apache.dubbo.config.bootstrap.rest.UserServiceImpl; +import static org.apache.dubbo.common.constants.CommonConstants.COMPOSITE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE; + /** * TODO */ @@ -26,8 +30,11 @@ public class ZookeeperDubboServiceProviderBootstrap { public static void main(String[] args) { DubboBootstrap.getInstance() - .application("zookeeper-dubbo-provider") - .registry(builder -> builder.address("zookeeper://127.0.0.1:2181?registry-type=service")) + .application("zookeeper-dubbo-provider", app -> app.metadata(COMPOSITE_METADATA_STORAGE_TYPE)) + .registry(builder -> builder.address("zookeeper://127.0.0.1:2181") + .parameter(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE) + .useAsConfigCenter(true) + .useAsMetadataCenter(true)) .protocol("dubbo", builder -> builder.port(-1).name("dubbo")) .protocol("rest", builder -> builder.port(8081).name("rest")) .service("echo", builder -> builder.interfaceClass(EchoService.class).ref(new EchoServiceImpl()).protocolIds("dubbo")) diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilderTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilderTest.java index 210d92e251a..4d11ef43149 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilderTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilderTest.java @@ -26,6 +26,8 @@ import java.util.Collections; +import static org.apache.dubbo.common.utils.CollectionUtils.ofSet; + class ReferenceBuilderTest { @Test @@ -95,8 +97,15 @@ void build() { MethodConfig method = new MethodConfig(); ReferenceBuilder builder = new ReferenceBuilder<>(); - builder.id("id").interfaceClass(DemoService.class).protocol("protocol").client("client").url("url") - .consumer(consumer).addMethod(method); + builder.id("id") + .interfaceClass(DemoService.class) + .protocol("protocol") + .client("client") + .url("url") + .consumer(consumer) + .addMethod(method) + // introduced since 2.7.8 + .services("test-service", "test-service2"); ReferenceConfig config = builder.build(); ReferenceConfig config2 = builder.build(); @@ -107,6 +116,8 @@ void build() { Assertions.assertEquals("client", config.getClient()); Assertions.assertEquals("url", config.getUrl()); Assertions.assertEquals(consumer, config.getConsumer()); + Assertions.assertEquals("test-service,test-service2", config.getServices()); + Assertions.assertEquals(ofSet("test-service", "test-service2"), config.getSubscribedServices()); Assertions.assertTrue(config.getMethods().contains(method)); Assertions.assertEquals(1, config.getMethods().size()); Assertions.assertNotSame(config, config2); diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilderTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilderTest.java index 24c4a4d02dc..b125547420e 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilderTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilderTest.java @@ -220,7 +220,7 @@ void build() { .transporter("transporter").server("server").client("client").cluster("cluster").group("group") .version("version").timeout(1000).session(2000).file("file").wait(Integer.valueOf(10)).isCheck(true) .isDynamic(false).register(true).subscribe(false).isDefault(true).simplified(false).extraKeys("A") - .appendParameter("default.num", "one").id("id").prefix("prefix"); + .parameter("default.num", "one").id("id").prefix("prefix"); RegistryConfig config = builder.build(); RegistryConfig config2 = builder.build(); diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/event/listener/PublishingServiceDefinitionListenerTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/event/listener/PublishingServiceDefinitionListenerTest.java new file mode 100644 index 00000000000..67a562d6687 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/event/listener/PublishingServiceDefinitionListenerTest.java @@ -0,0 +1,94 @@ +/* + * 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.config.event.listener; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ServiceConfig; +import org.apache.dubbo.config.bootstrap.EchoService; +import org.apache.dubbo.config.bootstrap.EchoServiceImpl; +import org.apache.dubbo.config.context.ConfigManager; +import org.apache.dubbo.config.event.ServiceConfigExportedEvent; +import org.apache.dubbo.metadata.WritableMetadataService; +import org.apache.dubbo.metadata.definition.model.FullServiceDefinition; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import com.google.gson.Gson; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY; +import static org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder.buildFullDefinition; +import static org.apache.dubbo.remoting.Constants.BIND_IP_KEY; +import static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link PublishingServiceDefinitionListener} Test-Cases + * + * @since 2.7.8 + */ +public class PublishingServiceDefinitionListenerTest { + + private WritableMetadataService writableMetadataService; + + @BeforeEach + public void init() { + String metadataType = DEFAULT_METADATA_STORAGE_TYPE; + ConfigManager configManager = ApplicationModel.getConfigManager(); + ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-demo-provider"); + applicationConfig.setMetadataType(metadataType); + configManager.setApplication(applicationConfig); + this.writableMetadataService = WritableMetadataService.getExtension(metadataType); + } + + @AfterEach + public void reset() { + ApplicationModel.reset(); + } + + /** + * Test {@link ServiceConfigExportedEvent} arising + */ + @Test + public void testOnServiceConfigExportedEvent() { + ServiceConfig serviceConfig = new ServiceConfig<>(); + serviceConfig.setInterface(EchoService.class); + serviceConfig.setRef(new EchoServiceImpl()); + serviceConfig.setRegistry(new RegistryConfig("N/A")); + serviceConfig.export(); + + String serviceDefinition = writableMetadataService.getServiceDefinition(EchoService.class.getName()); + + List exportedUrls = serviceConfig.getExportedUrls(); + + FullServiceDefinition fullServiceDefinition = buildFullDefinition( + serviceConfig.getInterfaceClass(), + exportedUrls.get(0) + .removeParameters(PID_KEY, TIMESTAMP_KEY, BIND_IP_KEY, BIND_PORT_KEY, TIMESTAMP_KEY) + .getParameters() + ); + + assertEquals(serviceDefinition, new Gson().toJson(fullServiceDefinition)); + } +} diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/RemoteMetadataServiceExporterTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/RemoteMetadataServiceExporterTest.java new file mode 100644 index 00000000000..e4d13a15289 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/RemoteMetadataServiceExporterTest.java @@ -0,0 +1,106 @@ +/* + * 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.config.metadata; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.metadata.MetadataServiceExporter; +import org.apache.dubbo.metadata.WritableMetadataService; +import org.apache.dubbo.metadata.report.MetadataReportInstance; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.service.EchoService; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static java.util.Arrays.asList; +import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.COMPOSITE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; +import static org.apache.dubbo.metadata.MetadataServiceExporter.getExtension; +import static org.apache.dubbo.metadata.report.support.Constants.SYNC_REPORT_KEY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link RemoteMetadataServiceExporter} Test-Cases + * + * @since 2.7.8 + */ +public class RemoteMetadataServiceExporterTest { + + private static final URL METADATA_REPORT_URL = URL.valueOf("file://") + .addParameter(APPLICATION_KEY, "test") + .addParameter(SYNC_REPORT_KEY, "true"); + + private static final Class INTERFACE_CLASS = EchoService.class; + + private static final String INTERFACE_NAME = INTERFACE_CLASS.getName(); + + private static final String APP_NAME = "test-service"; + + private static final URL BASE_URL = URL + .valueOf("dubbo://127.0.0.1:20880") + .setPath(INTERFACE_NAME) + .addParameter(APPLICATION_KEY, APP_NAME) + .addParameter(SIDE_KEY, "provider"); + + private final MetadataServiceExporter exporter = getExtension(REMOTE_METADATA_STORAGE_TYPE); + + private WritableMetadataService writableMetadataService; + + @BeforeEach + public void init() { + ApplicationModel.getConfigManager().setApplication(new ApplicationConfig(APP_NAME)); + MetadataReportInstance.init(METADATA_REPORT_URL); + writableMetadataService = WritableMetadataService.getDefaultExtension(); + writableMetadataService.exportURL(BASE_URL); + } + + @AfterEach + public void reset() { + ApplicationModel.reset(); + } + + @Test + public void testType() { + assertEquals(RemoteMetadataServiceExporter.class, exporter.getClass()); + } + + @Test + public void testSupports() { + assertTrue(exporter.supports(REMOTE_METADATA_STORAGE_TYPE)); + assertTrue(exporter.supports(COMPOSITE_METADATA_STORAGE_TYPE)); + assertFalse(exporter.supports(DEFAULT_METADATA_STORAGE_TYPE)); + } + + @Test + public void testExportAndUnexport() { + assertFalse(exporter.isExported()); + assertEquals(exporter, exporter.export()); + assertTrue(exporter.isExported()); + + assertEquals(asList(BASE_URL), exporter.getExportedURLs()); + + assertEquals(exporter, exporter.unexport()); + assertFalse(exporter.isExported()); + } +} diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java index e1fbfb4fda1..5c19d04151e 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; @@ -42,13 +43,13 @@ public static void start() { @BeforeEach public void setUp() { + ApplicationModel.reset(); initServConf(); -// ApplicationModel.getConfigManager().clear(); } @AfterEach() public void teardown() { -// ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); } @Test diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/metadata/MetadataServiceExporterTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/metadata/MetadataServiceExporterTest.java new file mode 100644 index 00000000000..8096276f19a --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/metadata/MetadataServiceExporterTest.java @@ -0,0 +1,42 @@ +/* + * 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; + +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.constants.CommonConstants.COMPOSITE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link MetadataServiceExporter} Test-Cases + * + * @since 2.7.8 + */ +public class MetadataServiceExporterTest { + + @Test + public void test() { + MetadataServiceExporter exporter = MetadataServiceExporter.getExtension(null); + assertEquals(exporter, MetadataServiceExporter.getDefaultExtension()); + assertTrue(exporter.supports(DEFAULT_METADATA_STORAGE_TYPE)); + assertTrue(exporter.supports(REMOTE_METADATA_STORAGE_TYPE)); + assertTrue(exporter.supports(COMPOSITE_METADATA_STORAGE_TYPE)); + } +} diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml index 74cc929a4d5..31bfcf4c149 100644 --- a/dubbo-config/dubbo-config-spring/pom.xml +++ b/dubbo-config/dubbo-config-spring/pom.xml @@ -142,6 +142,27 @@ test + + + org.apache.dubbo + dubbo-registry-zookeeper + ${project.parent.version} + test + + + + org.apache.dubbo + dubbo-metadata-report-zookeeper + ${project.parent.version} + test + + + com.google.guava + guava + + + + org.apache.dubbo diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java index 05c81394281..07de2ee6465 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java @@ -17,11 +17,11 @@ package org.apache.dubbo.config.spring.beans.factory.annotation; import org.apache.dubbo.config.annotation.DubboReference; +import org.apache.dubbo.config.annotation.DubboService; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.annotation.Service; import org.apache.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.config.spring.ServiceBean; -import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; import com.alibaba.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor; import org.springframework.beans.BeansException; @@ -31,12 +31,9 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ApplicationListener; import org.springframework.core.annotation.AnnotationAttributes; import java.lang.reflect.Field; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; @@ -46,7 +43,6 @@ import static com.alibaba.spring.util.AnnotationUtils.getAttribute; import static com.alibaba.spring.util.AnnotationUtils.getAttributes; -import static java.lang.reflect.Proxy.newProxyInstance; import static org.apache.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilder.create; import static org.springframework.util.StringUtils.hasText; @@ -60,7 +56,7 @@ * @since 2.5.7 */ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBeanPostProcessor implements - ApplicationContextAware, ApplicationListener { + ApplicationContextAware { /** * The bean name of {@link ReferenceAnnotationBeanPostProcessor} @@ -81,9 +77,6 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean private final ConcurrentMap> injectedMethodReferenceBeanCache = new ConcurrentHashMap<>(CACHE_SIZE); - private final ConcurrentMap referencedBeanInvocationHandlersCache = - new ConcurrentHashMap<>(); - private ApplicationContext applicationContext; /** @@ -142,11 +135,13 @@ protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, boolean localServiceBean = isLocalServiceBean(referencedBeanName, referenceBean, attributes); + prepareReferenceBean(referencedBeanName, referenceBean, localServiceBean); + registerReferenceBean(referencedBeanName, referenceBean, attributes, localServiceBean, injectedType); cacheInjectedReferenceBean(referenceBean, injectedElement); - return getOrCreateProxy(referencedBeanName, referenceBean, localServiceBean, injectedType); + return referenceBean.get(); } /** @@ -261,23 +256,19 @@ private boolean isRemoteReferenceBean(ReferenceBean referenceBean, AnnotationAtt } /** - * Get or Create a proxy of {@link ReferenceBean} for the specified the type of Dubbo service interface + * Prepare {@link ReferenceBean} * - * @param referencedBeanName The name of bean that annotated Dubbo's {@link Service @Service} in the Spring {@link ApplicationContext} - * @param referenceBean the instance of {@link ReferenceBean} - * @param localServiceBean Is Local Service bean or not - * @param serviceInterfaceType the type of Dubbo service interface - * @return non-null - * @since 2.7.4 + * @param referencedBeanName The name of bean that annotated Dubbo's {@link DubboService @DubboService} + * in the Spring {@link ApplicationContext} + * @param referenceBean the instance of {@link ReferenceBean} + * @param localServiceBean Is Local Service bean or not + * @since 2.7.8 */ - private Object getOrCreateProxy(String referencedBeanName, ReferenceBean referenceBean, boolean localServiceBean, - Class serviceInterfaceType) { - if (localServiceBean) { // If the local @Service Bean exists, build a proxy of Service - return newProxyInstance(getClassLoader(), new Class[]{serviceInterfaceType}, - newReferencedBeanInvocationHandler(referencedBeanName)); - } else { + private void prepareReferenceBean(String referencedBeanName, ReferenceBean referenceBean, boolean localServiceBean) { + // Issue : https://github.com/apache/dubbo/issues/6224 + if (localServiceBean) { // If the local @Service Bean exists + referenceBean.setInjvm(Boolean.TRUE); exportServiceBeanIfNecessary(referencedBeanName); // If the referenced ServiceBean exits, export it immediately - return referenceBean.get(); } } @@ -295,58 +286,6 @@ private ServiceBean getServiceBean(String referencedBeanName) { return applicationContext.getBean(referencedBeanName, ServiceBean.class); } - private InvocationHandler newReferencedBeanInvocationHandler(String referencedBeanName) { - return referencedBeanInvocationHandlersCache.computeIfAbsent(referencedBeanName, - ReferencedBeanInvocationHandler::new); - } - - /** - * The {@link InvocationHandler} class for the referenced Bean - */ - @Override - public void onApplicationEvent(ServiceBeanExportedEvent event) { - initReferencedBeanInvocationHandler(event.getServiceBean()); - } - - private void initReferencedBeanInvocationHandler(ServiceBean serviceBean) { - String serviceBeanName = serviceBean.getBeanName(); - referencedBeanInvocationHandlersCache.computeIfPresent(serviceBeanName, (name, handler) -> { - handler.init(); - return null; - }); - } - - private class ReferencedBeanInvocationHandler implements InvocationHandler { - - private final String referencedBeanName; - - private Object bean; - - private ReferencedBeanInvocationHandler(String referencedBeanName) { - this.referencedBeanName = referencedBeanName; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Object result = null; - try { - if (bean == null) { - init(); - } - result = method.invoke(bean, args); - } catch (InvocationTargetException e) { - // re-throws the actual Exception. - throw e.getTargetException(); - } - return result; - } - - private void init() { - ServiceBean serviceBean = applicationContext.getBean(referencedBeanName, ServiceBean.class); - this.bean = serviceBean.getRef(); - } - } - @Override protected String buildInjectedObjectCacheKey(AnnotationAttributes attributes, Object bean, String beanName, Class injectedType, InjectionMetadata.InjectedElement injectedElement) { @@ -402,7 +341,6 @@ public void setApplicationContext(ApplicationContext applicationContext) throws public void destroy() throws Exception { super.destroy(); this.referenceBeanCache.clear(); - this.referencedBeanInvocationHandlersCache.clear(); this.injectedFieldReferenceBeanCache.clear(); this.injectedMethodReferenceBeanCache.clear(); } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/AnnotationBeanDefinitionParser.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/AnnotationBeanDefinitionParser.java index bcc16bfe33d..05d9027edee 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/AnnotationBeanDefinitionParser.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/AnnotationBeanDefinitionParser.java @@ -25,7 +25,6 @@ import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; -import static org.apache.dubbo.config.spring.util.DubboBeanUtils.registerCommonBeans; import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; import static org.springframework.util.StringUtils.trimArrayElements; @@ -58,8 +57,13 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinit builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - // @since 2.7.6 Register the common beans - registerCommonBeans(parserContext.getRegistry()); + /** + * @since 2.7.6 Register the common beans + * @since 2.7.8 comment this code line, and migrated to + * @see DubboNamespaceHandler#parse(Element, ParserContext) + * @see https://github.com/apache/dubbo/issues/6174 + */ + // registerCommonBeans(parserContext.getRegistry()); } @Override diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java index 31b299ad21b..084479a83cd 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java @@ -29,14 +29,13 @@ import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.config.spring.ServiceBean; -import org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigAliasPostProcessor; import org.springframework.beans.PropertyValue; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.config.TypedStringValue; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.support.RootBeanDefinition; @@ -55,7 +54,6 @@ import java.util.Set; import java.util.regex.Pattern; -import static com.alibaba.spring.util.BeanRegistrar.registerInfrastructureBean; import static org.apache.dubbo.common.constants.CommonConstants.HIDE_KEY_PREFIX; /** @@ -80,7 +78,7 @@ public DubboBeanDefinitionParser(Class beanClass, boolean required) { } @SuppressWarnings("unchecked") - private static BeanDefinition parse(Element element, ParserContext parserContext, Class beanClass, boolean required) { + private static RootBeanDefinition parse(Element element, ParserContext parserContext, Class beanClass, boolean required) { RootBeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClass(beanClass); beanDefinition.setLazyInit(false); @@ -130,7 +128,7 @@ private static BeanDefinition parse(Element element, ParserContext parserContext parseProperties(element.getChildNodes(), classDefinition, parserContext); beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl")); } - } else if (ProviderConfig.class.equals(beanClass)) { + } else if (ProviderConfig.class.equals(beanClass)) { parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition); } else if (ConsumerConfig.class.equals(beanClass)) { parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition); @@ -350,11 +348,18 @@ private static void parseMethods(String id, NodeList nodeList, RootBeanDefinitio if (methods == null) { methods = new ManagedList(); } - BeanDefinition methodBeanDefinition = parse(element, + RootBeanDefinition methodBeanDefinition = parse(element, parserContext, MethodConfig.class, false); - String name = id + "." + methodName; + String beanName = id + "." + methodName; + + // If the PropertyValue named "id" can't be found, + // bean name will be taken as the "id" PropertyValue for MethodConfig + if (!hasPropertyValue(methodBeanDefinition, "id")) { + addPropertyValue(methodBeanDefinition, "id", beanName); + } + BeanDefinitionHolder methodBeanDefinitionHolder = new BeanDefinitionHolder( - methodBeanDefinition, name); + methodBeanDefinition, beanName); methods.add(methodBeanDefinitionHolder); } } @@ -363,6 +368,17 @@ private static void parseMethods(String id, NodeList nodeList, RootBeanDefinitio } } + private static boolean hasPropertyValue(AbstractBeanDefinition beanDefinition, String propertyName) { + return beanDefinition.getPropertyValues().contains(propertyName); + } + + private static void addPropertyValue(AbstractBeanDefinition beanDefinition, String propertyName, String propertyValue) { + if (StringUtils.isBlank(propertyName) || StringUtils.isBlank(propertyValue)) { + return; + } + beanDefinition.getPropertyValues().addPropertyValue(propertyName, propertyValue); + } + @SuppressWarnings("unchecked") private static void parseArguments(String id, NodeList nodeList, RootBeanDefinition beanDefinition, ParserContext parserContext) { @@ -395,22 +411,9 @@ private static void parseArguments(String id, NodeList nodeList, RootBeanDefinit @Override public BeanDefinition parse(Element element, ParserContext parserContext) { - // Register DubboConfigAliasPostProcessor - registerDubboConfigAliasPostProcessor(parserContext.getRegistry()); - return parse(element, parserContext, beanClass, required); } - /** - * Register {@link DubboConfigAliasPostProcessor} - * - * @param registry {@link BeanDefinitionRegistry} - * @since 2.7.5 [Feature] https://github.com/apache/dubbo/issues/5093 - */ - private void registerDubboConfigAliasPostProcessor(BeanDefinitionRegistry registry) { - registerInfrastructureBean(registry, DubboConfigAliasPostProcessor.BEAN_NAME, DubboConfigAliasPostProcessor.class); - } - private static String resolveAttribute(Element element, String attributeName, ParserContext parserContext) { String attributeValue = element.getAttribute(attributeName); Environment environment = parserContext.getReaderContext().getEnvironment(); diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd index bfaaf3ff469..b12d81563a3 100644 --- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd +++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd @@ -6,7 +6,8 @@ targetNamespace="http://dubbo.apache.org/schema/dubbo"> - + @@ -702,7 +703,8 @@ - + + @@ -945,7 +947,8 @@ - + + @@ -1011,6 +1014,14 @@ + + + + + + + diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java index 679d46d3562..598933d5495 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java @@ -22,11 +22,14 @@ import org.apache.dubbo.config.spring.api.DemoService; import org.apache.dubbo.config.spring.api.HelloService; import org.apache.dubbo.config.utils.ReferenceConfigCache; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -67,6 +70,16 @@ @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) public class ReferenceAnnotationBeanPostProcessorTest { + @Before + public void setUp() { + ApplicationModel.reset(); + } + + @After + public void tearDown() { + ApplicationModel.reset(); + } + private static final String AOP_SUFFIX = "(based on AOP)"; @Aspect diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java index 4395c392354..60837e274e8 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java @@ -17,15 +17,20 @@ package org.apache.dubbo.config.spring.beans.factory.annotation; +import org.apache.dubbo.config.annotation.DubboReference; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.ReferenceBean; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -33,6 +38,7 @@ import java.util.HashMap; import java.util.Map; +import static org.apache.dubbo.common.utils.CollectionUtils.ofSet; import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; import static org.springframework.util.ReflectionUtils.findField; @@ -40,6 +46,7 @@ * {@link ReferenceBeanBuilder} Test * * @see ReferenceBeanBuilder + * @see DubboReference * @see Reference * @since 2.6.4 */ @@ -47,7 +54,7 @@ @ContextConfiguration(classes = ReferenceBeanBuilderTest.class) public class ReferenceBeanBuilderTest { - @Reference( + @DubboReference( interfaceClass = CharSequence.class, interfaceName = "java.lang.CharSequence", version = "1.0.0", group = "TEST_GROUP", url = "dubbo://localhost:12345", @@ -62,17 +69,27 @@ public class ReferenceBeanBuilderTest { timeout = 3, cache = "cache", filter = {"echo", "generic", "accesslog"}, listener = {"deprecated"}, parameters = {"n1=v1 ", "n2 = v2 ", " n3 = v3 "}, application = "application", - module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry"} + module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry"}, + // @since 2.7.3 + id = "reference", + // @since 2.7.8 + services = {"service1", "service2", "service3", "service2", "service1"} ) private static final Object TEST_FIELD = new Object(); @Autowired private ApplicationContext context; + @Before + public void init() { + ApplicationModel.reset(); + } + @Test public void testBuild() throws Exception { - Reference reference = findAnnotation(findField(getClass(), "TEST_FIELD"), Reference.class); - ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder.create(reference, context.getClassLoader(), context); + DubboReference reference = findAnnotation(findField(getClass(), "TEST_FIELD"), DubboReference.class); + AnnotationAttributes attributes = AnnotationUtils.getAnnotationAttributes(reference, false, false); + ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder.create(attributes, context); beanBuilder.interfaceClass(CharSequence.class); ReferenceBean referenceBean = beanBuilder.build(); Assert.assertEquals(CharSequence.class, referenceBean.getInterfaceClass()); @@ -81,7 +98,7 @@ public void testBuild() throws Exception { Assert.assertEquals("dubbo://localhost:12345", referenceBean.getUrl()); Assert.assertEquals("client", referenceBean.getClient()); Assert.assertEquals(true, referenceBean.isGeneric()); - Assert.assertNull(referenceBean.isInjvm()); + Assert.assertTrue(referenceBean.isInjvm()); Assert.assertEquals(false, referenceBean.isCheck()); Assert.assertFalse(referenceBean.isInit()); Assert.assertEquals(true, referenceBean.getLazy()); @@ -108,6 +125,8 @@ public void testBuild() throws Exception { Assert.assertEquals("cache", referenceBean.getCache()); Assert.assertEquals("echo,generic,accesslog", referenceBean.getFilter()); Assert.assertEquals("deprecated", referenceBean.getListener()); + Assert.assertEquals("reference", referenceBean.getId()); + Assert.assertEquals(ofSet("service1", "service2", "service3"), referenceBean.getSubscribedServices()); // parameters Map parameters = new HashMap(); diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java index a509b43f418..171cda3217a 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java @@ -18,8 +18,11 @@ import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.api.HelloService; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -49,6 +52,16 @@ }) public class ServiceAnnotationBeanPostProcessorTest { + @Before + public void setUp() { + ApplicationModel.reset(); + } + + @After + public void tearDown() { + ApplicationModel.reset(); + } + @Autowired private ConfigurableListableBeanFactory beanFactory; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceClassPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceClassPostProcessorTest.java index 4422e75b5ee..e6c1d77e698 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceClassPostProcessorTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceClassPostProcessorTest.java @@ -18,8 +18,11 @@ import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.api.HelloService; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -49,6 +52,16 @@ }) public class ServiceClassPostProcessorTest { + @Before + public void setUp() { + ApplicationModel.reset(); + } + + @After + public void tearDown() { + ApplicationModel.reset(); + } + @Autowired private ConfigurableListableBeanFactory beanFactory; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/MultipleServicesWithMethodConfigsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/MultipleServicesWithMethodConfigsTest.java new file mode 100644 index 00000000000..d66c8c3e063 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/MultipleServicesWithMethodConfigsTest.java @@ -0,0 +1,42 @@ +/* + * 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.config.spring.beans.factory.config; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ImportResource; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = MultipleServicesWithMethodConfigsTest.class) +@ImportResource(locations = "classpath:/META-INF/spring/multiple-services-with-methods.xml") +public class MultipleServicesWithMethodConfigsTest { + + @Autowired + private ApplicationContext applicationContext; + + @Test + public void test() { +// Map methodConfigs = applicationContext.getBeansOfType(MethodConfig.class); +// assertEquals(2, methodConfigs.size()); + } +} + + diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java index 21163021b09..80a8d40b885 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java @@ -41,12 +41,12 @@ public class DubboComponentScanRegistrarTest { @BeforeEach public void setUp() { - ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); } @AfterEach public void tearDown() { - ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); } @Test diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java index 42fadfc6ab6..d9364d04c67 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java @@ -52,13 +52,13 @@ public class EnableDubboTest { @BeforeEach public void setUp() { - ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); context = new AnnotationConfigApplicationContext(); } @AfterEach public void tearDown() { - ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); context.close(); } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java index b5b0aa56be3..47e0d30751f 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java @@ -38,7 +38,10 @@ public class TestConsumerConfiguration { private static final String remoteURL = "dubbo://127.0.0.1:12345?version=2.5.7"; - @Reference(version = "2.5.7", url = remoteURL, application = "dubbo-demo-application") + @Reference(version = "2.5.7", + url = remoteURL, + application = "dubbo-demo-application", + filter = "mymock") private DemoService demoService; @Autowired diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java index aea9fb93374..2123b549e22 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java @@ -20,7 +20,10 @@ import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.junit.runner.RunWith; @@ -34,6 +37,16 @@ @ContextConfiguration(classes = DefaultDubboConfigBinder.class) public class DefaultDubboConfigBinderTest { + @Before + public void setUp() { + ApplicationModel.reset(); + } + + @After + public void tearDown() { + ApplicationModel.reset(); + } + @Autowired private DubboConfigBinder dubboConfigBinder; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/Issue6252Test.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/Issue6252Test.java new file mode 100644 index 00000000000..8c34e7e5cbe --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/Issue6252Test.java @@ -0,0 +1,50 @@ +/* + * 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.config.spring.issues; + +import org.apache.dubbo.config.spring.ReferenceBean; +import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig; + +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +/** + * The test-case for https://github.com/apache/dubbo/issues/6252 + * + * @since 2.7.8 + */ +@Configuration +@EnableDubboConfig +@PropertySource("classpath:/META-INF/issue-6252-test.properties") +public class Issue6252Test { + + @Bean + public static ReferenceBean referenceBean() { + return new ReferenceBean(); + } + + @Test + public void test() throws Exception { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Issue6252Test.class); + context.getBean(ReferenceBean.class); + context.close(); + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerBootstrap.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerBootstrap.java new file mode 100644 index 00000000000..4c567e5caca --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerBootstrap.java @@ -0,0 +1,53 @@ +/* + * 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.config.spring.samples; + +import org.apache.dubbo.config.annotation.DubboReference; +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +/** + * Zookeeper Dubbo Spring Provider Bootstrap + * + * @since 2.7.8 + */ +@EnableDubboConfig +@PropertySource("classpath:/META-INF/service-introspection/zookeeper-dubbb-consumer.properties") +public class ZookeeperDubboSpringConsumerBootstrap { + + @DubboReference(services = "${dubbo.provider.name},${dubbo.provider.name1},${dubbo.provider.name2}") + private DemoService demoService; + + public static void main(String[] args) throws Exception { + Class beanType = ZookeeperDubboSpringConsumerBootstrap.class; + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(beanType); + + ZookeeperDubboSpringConsumerBootstrap bootstrap = context.getBean(ZookeeperDubboSpringConsumerBootstrap.class); + + for (int i = 0; i < 100; i++) { + System.out.println(bootstrap.demoService.sayName("Hello")); + Thread.sleep(1000L); + } + + System.in.read(); + + context.close(); + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerXmlBootstrap.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerXmlBootstrap.java new file mode 100644 index 00000000000..08c14509ce0 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringConsumerXmlBootstrap.java @@ -0,0 +1,42 @@ +/* + * 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.config.spring.samples; + +import org.apache.dubbo.config.spring.api.DemoService; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Zookeeper Dubbo Spring Provider XML Bootstrap + * + * @since 2.7.8 + */ +public class ZookeeperDubboSpringConsumerXmlBootstrap { + + public static void main(String[] args) throws Exception { + String location = "classpath:/META-INF/service-introspection/zookeeper-dubbo-consumer.xml"; + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(location); + + DemoService demoService = context.getBean("demoService", DemoService.class); + + for (int i = 0; i < 100; i++) { + System.out.println(demoService.sayName("Hello")); + } + + context.close(); + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringProviderBootstrap.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringProviderBootstrap.java new file mode 100644 index 00000000000..ddd40109c3d --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/samples/ZookeeperDubboSpringProviderBootstrap.java @@ -0,0 +1,60 @@ +/* + * 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.config.spring.samples; + +import org.apache.dubbo.config.annotation.DubboService; +import org.apache.dubbo.config.spring.api.Box; +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.apache.dubbo.rpc.RpcContext; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +import static java.lang.String.format; + +/** + * Zookeeper Dubbo Spring Provider Bootstrap + * + * @since 2.7.8 + */ +@EnableDubbo +@PropertySource("classpath:/META-INF/service-introspection/zookeeper-dubbb-provider.properties") +public class ZookeeperDubboSpringProviderBootstrap { + + public static void main(String[] args) throws Exception { + AnnotationConfigApplicationContext context = + new AnnotationConfigApplicationContext(ZookeeperDubboSpringProviderBootstrap.class); + System.in.read(); + context.close(); + } +} + +@DubboService +class DefaultDemoService implements DemoService { + + @Override + public String sayName(String name) { + RpcContext rpcContext = RpcContext.getContext(); + return format("[%s:%s] Say - %s", rpcContext.getLocalHost(), rpcContext.getLocalPort(), name); + } + + @Override + public Box getBox() { + return null; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java index a7c733c2531..705b890ed48 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java @@ -49,12 +49,12 @@ public class DubboNamespaceHandlerTest { @BeforeEach public void setUp() { - ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); } @AfterEach public void tearDown() { - ApplicationModel.getConfigManager().clear(); + ApplicationModel.reset(); } @Configuration diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/GenericServiceTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/GenericServiceTest.java index 410e3e9bb50..6deb2abaf5f 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/GenericServiceTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/GenericServiceTest.java @@ -18,7 +18,10 @@ import org.apache.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.config.spring.ServiceBean; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -34,6 +37,16 @@ @ImportResource(locations = "classpath:/META-INF/spring/dubbo-generic-consumer.xml") public class GenericServiceTest { + @Before + public void setUp() { + ApplicationModel.reset(); + } + + @After + public void tearDown() { + ApplicationModel.reset(); + } + @Autowired @Qualifier("demoServiceRef") private ReferenceBean referenceBean; diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/issue-6252-test.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/issue-6252-test.properties new file mode 100644 index 00000000000..413806d52f3 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/issue-6252-test.properties @@ -0,0 +1,11 @@ +dubbo.application.name=demo-zk +dubbo.application.qos-enable=false +dubbo.protocol.name=dubbo +dubbo.protocol.port=-1 +dubbo.scan.basePackages=com.example.demo +dubbo.consumer.check=false +dubbo.registries.z214.address=zookeeper://192.168.99.214:2181 +dubbo.registries.z214.timeout=60000 +dubbo.registries.z214.subscribe=false +dubbo.registries.z205.address=zookeeper://192.168.99.205:2181 +dubbo.registries.z205.timeout=60000 \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbb-consumer.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbb-consumer.properties new file mode 100644 index 00000000000..1795afac935 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbb-consumer.properties @@ -0,0 +1,14 @@ +# Dubbo Consumer for Zookeeper + +dubbo.application.name = zookeeper-dubbo-spring-consumer + +dubbo.registry.address = zookeeper://127.0.0.1:2181?registry-type=service +dubbo.registry.useAsConfigCenter = true +dubbo.registry.useAsMetadataCenter = true + +dubbo.protocol.name = dubbo +dubbo.protocol.port = -1 + +dubbo.provider.name = zookeeper-dubbo-spring-provider +dubbo.provider.name1 = zookeeper-dubbo-spring-provider-1 +dubbo.provider.name2 = zookeeper-dubbo-spring-provider-2 \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbb-provider.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbb-provider.properties new file mode 100644 index 00000000000..1b977a57f99 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbb-provider.properties @@ -0,0 +1,10 @@ +# Dubbo Provider for Zookeeper + +dubbo.application.name = zookeeper-dubbo-spring-provider-1 + +dubbo.registry.address = zookeeper://127.0.0.1:2181?registry-type=service +dubbo.registry.useAsConfigCenter = true +dubbo.registry.useAsMetadataCenter = true + +dubbo.protocol.name = dubbo +dubbo.protocol.port = -1 \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbo-consumer.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbo-consumer.xml new file mode 100644 index 00000000000..92305f5ff49 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/service-introspection/zookeeper-dubbo-consumer.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/multiple-services-with-methods.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/multiple-services-with-methods.xml new file mode 100644 index 00000000000..848990dfca7 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/multiple-services-with-methods.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-configcenter/dubbo-configcenter-consul/src/main/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-consul/src/main/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfiguration.java index e0e9a86dda3..5bf8abed371 100644 --- a/dubbo-configcenter/dubbo-configcenter-consul/src/main/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfiguration.java +++ b/dubbo-configcenter/dubbo-configcenter-consul/src/main/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfiguration.java @@ -21,11 +21,10 @@ import org.apache.dubbo.common.config.configcenter.ConfigChangeType; import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent; import org.apache.dubbo.common.config.configcenter.ConfigurationListener; -import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; +import org.apache.dubbo.common.config.configcenter.TreePathDynamicConfiguration; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.common.utils.StringUtils; import com.google.common.base.Charsets; import com.google.common.net.HostAndPort; @@ -34,39 +33,36 @@ import com.orbitz.consul.cache.KVCache; import com.orbitz.consul.model.kv.Value; +import java.util.Collection; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import static org.apache.dubbo.common.config.configcenter.Constants.CONFIG_NAMESPACE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR; -import static org.apache.dubbo.common.utils.StringUtils.EMPTY_STRING; /** * config center implementation for consul */ -public class ConsulDynamicConfiguration implements DynamicConfiguration { +public class ConsulDynamicConfiguration extends TreePathDynamicConfiguration { private static final Logger logger = LoggerFactory.getLogger(ConsulDynamicConfiguration.class); private static final int DEFAULT_PORT = 8500; private static final int DEFAULT_WATCH_TIMEOUT = 60 * 1000; private static final String WATCH_TIMEOUT = "consul-watch-timeout"; - private URL url; - private String rootPath; private Consul client; + private KeyValueClient kvClient; + private ConcurrentMap watchers = new ConcurrentHashMap<>(); public ConsulDynamicConfiguration(URL url) { - this.url = url; - this.rootPath = PATH_SEPARATOR + url.getParameter(CONFIG_NAMESPACE_KEY, DEFAULT_GROUP) + PATH_SEPARATOR + "config"; + super(url); String host = url.getHost(); int port = url.getPort() != 0 ? url.getPort() : DEFAULT_PORT; client = Consul.builder().withHostAndPort(HostAndPort.fromParts(host, port)).build(); @@ -74,112 +70,69 @@ public ConsulDynamicConfiguration(URL url) { } @Override - public void addListener(String key, String group, ConfigurationListener listener) { - logger.info("register listener " + listener.getClass() + " for config with key: " + key + ", group: " + group); - String normalizedKey = convertKey(group, key); - ConsulListener watcher = watchers.computeIfAbsent(normalizedKey, k -> new ConsulListener(key, group)); - watcher.addListener(listener); + public String getInternalProperty(String key) { + logger.info("getting config from: " + key); + return kvClient.getValueAsString(key, Charsets.UTF_8).orElse(null); } @Override - public void removeListener(String key, String group, ConfigurationListener listener) { - logger.info("unregister listener " + listener.getClass() + " for config with key: " + key + ", group: " + group); - ConsulListener watcher = watchers.get(convertKey(group, key)); - if (watcher != null) { - watcher.removeListener(listener); - } + protected boolean doPublishConfig(String pathKey, String content) throws Exception { + return kvClient.putValue(pathKey, content); + } + + @Override + protected String doGetConfig(String pathKey) throws Exception { + return getInternalProperty(pathKey); } @Override - public String getConfig(String key, String group, long timeout) throws IllegalStateException { - return (String) getInternalProperty(convertKey(group, key)); + protected boolean doRemoveConfig(String pathKey) throws Exception { + kvClient.deleteKey(pathKey); + return true; } @Override - public SortedSet getConfigKeys(String group) throws UnsupportedOperationException { - SortedSet configKeys = new TreeSet<>(); - String normalizedKey = convertKey(group, EMPTY_STRING); - List keys = kvClient.getKeys(normalizedKey); + protected Collection doGetConfigKeys(String groupPath) { + List keys = kvClient.getKeys(groupPath); + List configKeys = new LinkedList<>(); if (CollectionUtils.isNotEmpty(keys)) { keys.stream() - .filter(k -> !k.equals(normalizedKey)) + .filter(k -> !k.equals(groupPath)) .map(k -> k.substring(k.lastIndexOf(PATH_SEPARATOR) + 1)) .forEach(configKeys::add); } return configKeys; -// SortedSet configKeys = new TreeSet<>(); -// String normalizedKey = convertKey(group, key); -// kvClient.getValueAsString(normalizedKey).ifPresent(v -> { -// Collections.addAll(configKeys, v.split(",")); -// }); -// return configKeys; } - /** - * @param key the key to represent a configuration - * @param group the group where the key belongs to - * @param content the content of configuration - * @return - * @throws UnsupportedOperationException - */ @Override - public boolean publishConfig(String key, String group, String content) throws UnsupportedOperationException { -// String normalizedKey = convertKey(group, key); -// Value value = kvClient.getValue(normalizedKey).orElseThrow(() -> new IllegalArgumentException(normalizedKey + " does not exit.")); -// Optional old = value.getValueAsString(); -// if (old.isPresent()) { -// content = old.get() + "," + content; -// } -// -// while (!kvClient.putValue(key, content, value.getModifyIndex())) { -// value = kvClient.getValue(normalizedKey).orElseThrow(() -> new IllegalArgumentException(normalizedKey + " does not exit.")); -// old = value.getValueAsString(); -// if (old.isPresent()) { -// content = old.get() + "," + content; -// } -// try { -// Thread.sleep(10); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// } -// return true; - String normalizedKey = convertKey(group, key); - return kvClient.putValue(normalizedKey, content); + protected void doAddListener(String pathKey, ConfigurationListener listener) { + logger.info("register listener " + listener.getClass() + " for config with key: " + pathKey); + ConsulListener watcher = watchers.computeIfAbsent(pathKey, k -> new ConsulListener(pathKey)); + watcher.addListener(listener); } @Override - public Object getInternalProperty(String key) { - logger.info("getting config from: " + key); - return kvClient.getValueAsString(key, Charsets.UTF_8).orElse(null); + protected void doRemoveListener(String pathKey, ConfigurationListener listener) { + logger.info("unregister listener " + listener.getClass() + " for config with key: " + pathKey); + ConsulListener watcher = watchers.get(pathKey); + if (watcher != null) { + watcher.removeListener(listener); + } } @Override - public void close() throws Exception { + protected void doClose() throws Exception { client.destroy(); } - private String buildPath(String group) { - String actualGroup = StringUtils.isEmpty(group) ? DEFAULT_GROUP : group; - return rootPath + PATH_SEPARATOR + actualGroup; - } - - private String convertKey(String group, String key) { - return buildPath(group) + PATH_SEPARATOR + key; - } - private class ConsulListener implements KVCache.Listener { private KVCache kvCache; private Set listeners = new LinkedHashSet<>(); - private String key; - private String group; private String normalizedKey; - public ConsulListener(String key, String group) { - this.key = key; - this.group = group; - this.normalizedKey = convertKey(group, key); + public ConsulListener(String normalizedKey) { + this.normalizedKey = normalizedKey; initKVCache(); } @@ -201,7 +154,7 @@ public void notify(Map newValues) { // Values are encoded in key/value store, decode it if needed Optional decodedValue = newValue.get().getValueAsString(); decodedValue.ifPresent(v -> listeners.forEach(l -> { - ConfigChangedEvent event = new ConfigChangedEvent(key, group, v, ConfigChangeType.MODIFIED); + ConfigChangedEvent event = new ConfigChangedEvent(normalizedKey, getGroup(), v, ConfigChangeType.MODIFIED); l.process(event); })); }); diff --git a/dubbo-configcenter/dubbo-configcenter-consul/src/test/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfigurationTest.java b/dubbo-configcenter/dubbo-configcenter-consul/src/test/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfigurationTest.java index d924c834e46..c54d1034143 100644 --- a/dubbo-configcenter/dubbo-configcenter-consul/src/test/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfigurationTest.java +++ b/dubbo-configcenter/dubbo-configcenter-consul/src/test/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfigurationTest.java @@ -30,7 +30,9 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import java.util.Arrays; import java.util.Optional; +import java.util.TreeSet; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -51,10 +53,10 @@ public static void setUp() throws Exception { consul = ConsulStarterBuilder.consulStarter() .build() .start(); - configCenterUrl = URL.valueOf("consul://localhost:" + consul.getHttpPort()); + configCenterUrl = URL.valueOf("consul://127.0.0.1:" + consul.getHttpPort()); configuration = new ConsulDynamicConfiguration(configCenterUrl); - client = Consul.builder().withHostAndPort(HostAndPort.fromParts("localhost", consul.getHttpPort())).build(); + client = Consul.builder().withHostAndPort(HostAndPort.fromParts("127.0.0.1", consul.getHttpPort())).build(); kvClient = client.keyValueClient(); } @@ -74,6 +76,14 @@ public void testGetConfig() { Assertions.assertNull(configuration.getConfig("not-exist", "dubbo")); } + @Test + public void testPublishConfig() { + configuration.publishConfig("value", "metadata", "1"); + // test equals + assertEquals("1", configuration.getConfig("value", "/metadata")); + assertEquals("1", kvClient.getValueAsString("/dubbo/config/metadata/value").get()); + } + @Test public void testAddListener() { KVCache cache = KVCache.newCache(kvClient, "/dubbo/config/dubbo/foo"); @@ -102,14 +112,12 @@ public void testAddListener() { System.out.println(kvClient.getValues("/dubbo/config/dubbo/foo")); } - @Test - public void testPublishConfig() { - configuration.publishConfig("foo", "value1"); - Assertions.assertEquals("value1", configuration.getString("/dubbo/config/dubbo/foo")); - } - @Test public void testGetConfigKeys() { - + configuration.publishConfig("v1", "metadata", "1"); + configuration.publishConfig("v2", "metadata", "2"); + configuration.publishConfig("v3", "metadata", "3"); + // test equals + assertEquals(new TreeSet(Arrays.asList("v1", "v2", "v3")), configuration.getConfigKeys("metadata")); } } 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 2227015b610..cca467f7bf2 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 @@ -30,6 +30,7 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.PropertyKeyConst; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.listener.AbstractSharedListener; import com.alibaba.nacos.api.exception.NacosException; @@ -50,31 +51,17 @@ import java.util.concurrent.Executor; import java.util.stream.Stream; -import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY; -import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME; -import static com.alibaba.nacos.api.PropertyKeyConst.CONFIG_LONG_POLL_TIMEOUT; -import static com.alibaba.nacos.api.PropertyKeyConst.CONFIG_RETRY_TIME; -import static com.alibaba.nacos.api.PropertyKeyConst.CONTEXT_PATH; -import static com.alibaba.nacos.api.PropertyKeyConst.ENABLE_REMOTE_SYNC_CONFIG; import static com.alibaba.nacos.api.PropertyKeyConst.ENCODE; -import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT; -import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT_PORT; -import static com.alibaba.nacos.api.PropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING; -import static com.alibaba.nacos.api.PropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE; -import static com.alibaba.nacos.api.PropertyKeyConst.MAX_RETRY; -import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE; -import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_CLIENT_BEAT_THREAD_COUNT; import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_LOAD_CACHE_AT_START; -import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_POLLING_THREAD_COUNT; -import static com.alibaba.nacos.api.PropertyKeyConst.RAM_ROLE_NAME; -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 java.util.Arrays.asList; import static java.util.Collections.emptyList; import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY; +import static org.apache.dubbo.common.utils.StringConstantFieldValuePredicate.of; import static org.apache.dubbo.common.utils.StringUtils.HYPHEN_CHAR; import static org.apache.dubbo.common.utils.StringUtils.SLASH_CHAR; +import static org.apache.dubbo.common.utils.StringUtils.isBlank; /** * The nacos implementation of {@link DynamicConfiguration} @@ -159,24 +146,13 @@ private void setServerAddr(URL url, Properties properties) { private static void setProperties(URL url, Properties properties) { putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME); - putPropertyIfAbsent(url, properties, IS_USE_CLOUD_NAMESPACE_PARSING); - putPropertyIfAbsent(url, properties, IS_USE_ENDPOINT_PARSING_RULE); - putPropertyIfAbsent(url, properties, ENDPOINT); - putPropertyIfAbsent(url, properties, ENDPOINT_PORT); - putPropertyIfAbsent(url, properties, NAMESPACE); - putPropertyIfAbsent(url, properties, ACCESS_KEY); - putPropertyIfAbsent(url, properties, SECRET_KEY); - putPropertyIfAbsent(url, properties, RAM_ROLE_NAME); - putPropertyIfAbsent(url, properties, CONTEXT_PATH); - putPropertyIfAbsent(url, properties, CLUSTER_NAME); - putPropertyIfAbsent(url, properties, ENCODE); - putPropertyIfAbsent(url, properties, CONFIG_LONG_POLL_TIMEOUT); - putPropertyIfAbsent(url, properties, CONFIG_RETRY_TIME); - putPropertyIfAbsent(url, properties, MAX_RETRY); - putPropertyIfAbsent(url, properties, ENABLE_REMOTE_SYNC_CONFIG); + + // Get the parameters from constants + Map parameters = url.getParameters(of(PropertyKeyConst.class)); + // Put all parameters + properties.putAll(parameters); + putPropertyIfAbsent(url, properties, NAMING_LOAD_CACHE_AT_START, "true"); - putPropertyIfAbsent(url, properties, NAMING_CLIENT_BEAT_THREAD_COUNT); - putPropertyIfAbsent(url, properties, NAMING_POLLING_THREAD_COUNT); } private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName) { @@ -260,13 +236,9 @@ public boolean publishConfig(String key, String group, String content) { boolean published = false; String resolvedGroup = resolveGroup(group); try { - String value = configService.getConfig(key, resolvedGroup, getDefaultTimeout()); - if (StringUtils.isNotEmpty(value)) { - content = value + "," + content; - } published = configService.publishConfig(key, resolvedGroup, content); } catch (NacosException e) { - logger.error(e.getErrMsg()); + logger.error(e.getErrMsg(), e); } return published; } @@ -279,7 +251,6 @@ public long getDefaultTimeout() { /** * TODO Nacos does not support atomic update of the value mapped to a key. * - * @param key * @param group the specified group * @return */ @@ -307,6 +278,19 @@ public SortedSet getConfigKeys(String group) { return keys; } + @Override + public boolean removeConfig(String key, String group) { + boolean removed = false; + try { + removed = configService.removeConfig(key, group); + } catch (NacosException e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + return removed; + } + private Stream toKeysStream(String content) { JSONObject jsonObject = JSON.parseObject(content); JSONArray pageItems = jsonObject.getJSONArray("pageItems"); @@ -376,6 +360,6 @@ protected String buildListenerKey(String key, String group) { } protected String resolveGroup(String group) { - return group.replace(SLASH_CHAR, HYPHEN_CHAR); + return isBlank(group) ? group : group.replace(SLASH_CHAR, HYPHEN_CHAR); } } diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java index 4bd65a92ff1..a96f8438f16 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java @@ -18,36 +18,21 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.configcenter.ConfigurationListener; -import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; +import org.apache.dubbo.common.config.configcenter.TreePathDynamicConfiguration; import org.apache.dubbo.common.utils.NamedThreadFactory; -import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.zookeeper.ZookeeperClient; import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; +import java.util.Collection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import static java.util.Collections.emptySortedSet; -import static java.util.Collections.unmodifiableSortedSet; -import static org.apache.dubbo.common.config.configcenter.Constants.CONFIG_NAMESPACE_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR; -import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty; -import static org.apache.dubbo.common.utils.StringUtils.EMPTY_STRING; - /** * */ -public class ZookeeperDynamicConfiguration implements DynamicConfiguration { - - private static final Logger logger = LoggerFactory.getLogger(ZookeeperDynamicConfiguration.class); +public class ZookeeperDynamicConfiguration extends TreePathDynamicConfiguration { private Executor executor; // The final root path would be: /configRootPath/"config" @@ -60,8 +45,9 @@ public class ZookeeperDynamicConfiguration implements DynamicConfiguration { ZookeeperDynamicConfiguration(URL url, ZookeeperTransporter zookeeperTransporter) { + super(url); this.url = url; - rootPath = PATH_SEPARATOR + url.getParameter(CONFIG_NAMESPACE_KEY, DEFAULT_GROUP) + "/config"; + rootPath = getRootPath(url); initializedLatch = new CountDownLatch(1); this.cacheListener = new CacheListener(rootPath, initializedLatch); @@ -87,52 +73,44 @@ public class ZookeeperDynamicConfiguration implements DynamicConfiguration { * @return */ @Override - public Object getInternalProperty(String key) { + public String getInternalProperty(String key) { return zkClient.getContent(key); } - /** - * For service governance, multi group is not supported by this implementation. So group is not used at present. - */ @Override - public void addListener(String key, String group, ConfigurationListener listener) { - cacheListener.addListener(getPathKey(group, key), listener); + protected void doClose() throws Exception { + zkClient.close(); } @Override - public void removeListener(String key, String group, ConfigurationListener listener) { - cacheListener.removeListener(getPathKey(group, key), listener); + protected boolean doPublishConfig(String pathKey, String content) throws Exception { + zkClient.create(pathKey, content, false); + return true; } @Override - public String getConfig(String key, String group, long timeout) throws IllegalStateException { - return (String) getInternalProperty(getPathKey(group, key)); + protected String doGetConfig(String pathKey) throws Exception { + return zkClient.getContent(pathKey); } @Override - public boolean publishConfig(String key, String group, String content) { - String path = getPathKey(group, key); - zkClient.create(path, content, false); + protected boolean doRemoveConfig(String pathKey) throws Exception { + zkClient.delete(pathKey); return true; } @Override - public SortedSet getConfigKeys(String group) { - String path = getPathKey(group, EMPTY_STRING); - List nodes = zkClient.getChildren(path); - return isEmpty(nodes) ? emptySortedSet() : unmodifiableSortedSet(new TreeSet<>(nodes)); + protected Collection doGetConfigKeys(String groupPath) { + return zkClient.getChildren(groupPath); } - private String buildPath(String group) { - String actualGroup = StringUtils.isEmpty(group) ? DEFAULT_GROUP : group; - return rootPath + PATH_SEPARATOR + actualGroup; + @Override + protected void doAddListener(String pathKey, ConfigurationListener listener) { + cacheListener.addListener(pathKey, listener); } - private String getPathKey(String group, String key) { - if (StringUtils.isEmpty(key)) { - return buildPath(group); - } - return buildPath(group) + PATH_SEPARATOR + key; + @Override + protected void doRemoveListener(String pathKey, ConfigurationListener listener) { + cacheListener.removeListener(pathKey, listener); } - } diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java index 3c06fbe6e3f..9d4a0c36d3f 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java @@ -58,7 +58,7 @@ public class ZookeeperDynamicConfigurationTest { public static void setUp() throws Exception { zkServer = new TestingServer(zkServerPort, true); - client = CuratorFrameworkFactory.newClient("localhost:" + zkServerPort, 60 * 1000, 60 * 1000, + client = CuratorFrameworkFactory.newClient("127.0.0.1:" + zkServerPort, 60 * 1000, 60 * 1000, new ExponentialBackoffRetry(1000, 3)); client.start(); @@ -73,7 +73,7 @@ public static void setUp() throws Exception { } - configUrl = URL.valueOf("zookeeper://localhost:" + zkServerPort); + configUrl = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort); configuration = ExtensionLoader.getExtensionLoader(DynamicConfigurationFactory.class).getExtension(configUrl.getProtocol()).getDynamicConfiguration(configUrl); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/CompositeServiceNameMapping.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/CompositeServiceNameMapping.java new file mode 100644 index 00000000000..9ad130b2768 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/CompositeServiceNameMapping.java @@ -0,0 +1,96 @@ +/* + * 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; + + +import org.apache.dubbo.common.URL; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import static java.util.Collections.emptySet; +import static java.util.Collections.unmodifiableSet; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty; + +/** + * The composite implementation of {@link ServiceNameMapping} + * + * @see ParameterizedServiceNameMapping + * @see PropertiesFileServiceNameMapping + * @see DynamicConfigurationServiceNameMapping + * @since 2.7.8 + */ +public class CompositeServiceNameMapping implements ServiceNameMapping { + + private volatile List serviceNameMappings; + + private List getServiceNameMappings() { + if (this.serviceNameMappings == null) { + synchronized (this) { + if (this.serviceNameMappings == null) { + Set serviceNameMappings = loadAllServiceNameMappings(); + + removeSelf(serviceNameMappings); + + this.serviceNameMappings = new LinkedList<>(serviceNameMappings); + } + } + } + return this.serviceNameMappings; + } + + private Set loadAllServiceNameMappings() { + return getExtensionLoader(ServiceNameMapping.class).getSupportedExtensionInstances(); + } + + private void removeSelf(Set serviceNameMappings) { + Iterator iterator = serviceNameMappings.iterator(); + while (iterator.hasNext()) { + ServiceNameMapping serviceNameMapping = iterator.next(); + if (this.getClass().equals(serviceNameMapping.getClass())) { + iterator.remove(); // Remove self + } + } + } + + @Override + public void map(URL exportedURL) { + List serviceNameMappings = getServiceNameMappings(); + serviceNameMappings.forEach(serviceNameMapping -> serviceNameMapping.map(exportedURL)); + } + + @Override + public Set get(URL subscribedURL) { + List serviceNameMappings = getServiceNameMappings(); + Set serviceNames = null; + for (ServiceNameMapping serviceNameMapping : serviceNameMappings) { + serviceNames = serviceNameMapping.get(subscribedURL); + if (isNotEmpty(serviceNames)) { + break; + } + } + return serviceNames == null ? emptySet() : unmodifiableSet(serviceNames); + } + + @Override + public int getPriority() { + return MIN_PRIORITY; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java index d84eba02b65..2a04cb79e2c 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.metadata; +import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -27,11 +28,17 @@ import static java.lang.String.valueOf; import static java.util.Arrays.asList; +import static org.apache.dubbo.common.config.configcenter.DynamicConfiguration.getDynamicConfiguration; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty; import static org.apache.dubbo.common.utils.StringUtils.SLASH; import static org.apache.dubbo.rpc.model.ApplicationModel.getName; /** * The {@link ServiceNameMapping} implementation based on {@link DynamicConfiguration} + * + * @since 2.7.5 */ public class DynamicConfigurationServiceNameMapping implements ServiceNameMapping { @@ -41,14 +48,24 @@ public class DynamicConfigurationServiceNameMapping implements ServiceNameMappin private final Logger logger = LoggerFactory.getLogger(getClass()); + /** + * The priority of {@link DynamicConfigurationServiceNameMapping} is + * lower than {@link ParameterizedServiceNameMapping} + */ + static final int PRIORITY = PropertiesFileServiceNameMapping.PRIORITY + 1; + @Override - public void map(String serviceInterface, String group, String version, String protocol) { + public void map(URL exportedURL) { + + String serviceInterface = exportedURL.getServiceInterface(); if (IGNORED_SERVICE_INTERFACES.contains(serviceInterface)) { return; } - DynamicConfiguration dynamicConfiguration = DynamicConfiguration.getDynamicConfiguration(); + String group = exportedURL.getParameter(GROUP_KEY); + String version = exportedURL.getParameter(VERSION_KEY); + String protocol = exportedURL.getProtocol(); // the Dubbo Service Key as group // the service(application) name as key @@ -56,7 +73,7 @@ public void map(String serviceInterface, String group, String version, String pr String key = getName(); String content = valueOf(System.currentTimeMillis()); execute(() -> { - dynamicConfiguration.publishConfig(key, buildGroup(serviceInterface, group, version, protocol), content); + getDynamicConfiguration().publishConfig(key, buildGroup(serviceInterface, group, version, protocol), content); if (logger.isInfoEnabled()) { logger.info(String.format("Dubbo service[%s] mapped to interface name[%s].", group, serviceInterface, group)); @@ -65,14 +82,19 @@ public void map(String serviceInterface, String group, String version, String pr } @Override - public Set get(String serviceInterface, String group, String version, String protocol) { + public Set get(URL subscribedURL) { - DynamicConfiguration dynamicConfiguration = DynamicConfiguration.getDynamicConfiguration(); + String serviceInterface = subscribedURL.getServiceInterface(); + String group = subscribedURL.getParameter(GROUP_KEY); + String version = subscribedURL.getParameter(VERSION_KEY); + String protocol = subscribedURL.getProtocol(); Set serviceNames = new LinkedHashSet<>(); execute(() -> { - Set keys = dynamicConfiguration.getConfigKeys(buildGroup(serviceInterface, group, version, protocol)); - serviceNames.addAll(keys); + Set keys = getDynamicConfiguration().getConfigKeys(buildGroup(serviceInterface, group, version, protocol)); + if (isNotEmpty(keys)) { + serviceNames.addAll(keys); + } }); return Collections.unmodifiableSet(serviceNames); } @@ -96,4 +118,9 @@ private void execute(Runnable runnable) { } } } + + @Override + public int getPriority() { + return PRIORITY; + } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataConstants.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataConstants.java index e03ddd6969a..d67008904ff 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataConstants.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataConstants.java @@ -16,11 +16,22 @@ */ package org.apache.dubbo.metadata; -public class MetadataConstants { - public static final String KEY_SEPARATOR = ":"; - public static final String DEFAULT_PATH_TAG = "metadata"; - public static final String KEY_REVISON_PREFIX = "revision"; - public static final String META_DATA_STORE_TAG = ".metaData"; - public static final String SERVICE_META_DATA_STORE_TAG = ".smd"; - public static final String CONSUMER_META_DATA_STORE_TAG = ".cmd"; +public interface MetadataConstants { + String KEY_SEPARATOR = ":"; + String DEFAULT_PATH_TAG = "metadata"; + String KEY_REVISON_PREFIX = "revision"; + String META_DATA_STORE_TAG = ".metaData"; + String SERVICE_META_DATA_STORE_TAG = ".smd"; + String CONSUMER_META_DATA_STORE_TAG = ".cmd"; + + /** + * @since 2.7.8 + */ + String EXPORTED_URLS_TAG = "exported-urls"; + + /** + * @since 2.7.8 + */ + String SUBSCRIBED_URLS_TAG = "subscribed-urls"; + } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java index 0780149523b..660ac4246a9 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java @@ -28,6 +28,7 @@ import static java.util.Collections.unmodifiableSortedSet; import static java.util.stream.StreamSupport.stream; +import static org.apache.dubbo.common.URL.buildKey; /** * A framework interface of Dubbo Metadata Service defines the contract of Dubbo Services registartion and subscription @@ -90,7 +91,7 @@ default String version() { * @see #toSortedStrings(Stream) * @see URL#toFullString() */ - default SortedSet getSubscribedURLs(){ + default SortedSet getSubscribedURLs() { throw new UnsupportedOperationException("This operation is not supported for consumer."); } @@ -165,7 +166,9 @@ default SortedSet getExportedURLs(String serviceInterface, String group, * * @return */ - String getServiceDefinition(String interfaceName, String version, String group); + default String getServiceDefinition(String interfaceName, String version, String group) { + return getServiceDefinition(buildKey(interfaceName, group, version)); + } /** * Interface definition. diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceExporter.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceExporter.java index 16d1e3bef4f..34d3b54e3f7 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceExporter.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceExporter.java @@ -17,9 +17,14 @@ package org.apache.dubbo.metadata; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.lang.Prioritized; import java.util.List; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; + /** * The exporter of {@link MetadataService} * @@ -28,7 +33,8 @@ * @see #unexport() * @since 2.7.5 */ -public interface MetadataServiceExporter { +@SPI(DEFAULT_METADATA_STORAGE_TYPE) +public interface MetadataServiceExporter extends Prioritized { /** * Exports the {@link MetadataService} as a Dubbo service @@ -57,5 +63,38 @@ public interface MetadataServiceExporter { * @return if {@link #export()} was executed, return true, or false */ boolean isExported(); + + /** + * Does current implementation support the specified metadata type? + * + * @param metadataType the specified metadata type + * @return If supports, return true, or false + * @since 2.7.8 + */ + default boolean supports(String metadataType) { + return true; + } + + /** + * Get the extension of {@link MetadataServiceExporter} by the type. + * If not found, return the default implementation + * + * @param metadataType the metadata type + * @return non-null + * @since 2.7.8 + */ + static MetadataServiceExporter getExtension(String metadataType) { + return getExtensionLoader(MetadataServiceExporter.class).getOrDefaultExtension(metadataType); + } + + /** + * Get the default extension of {@link MetadataServiceExporter} + * + * @return non-null + * @since 2.7.8 + */ + static MetadataServiceExporter getDefaultExtension() { + return getExtension(DEFAULT_METADATA_STORAGE_TYPE); + } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceType.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceType.java new file mode 100644 index 00000000000..3af6b38eb1f --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceType.java @@ -0,0 +1,72 @@ +/* + * 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; + +import static org.apache.dubbo.common.constants.CommonConstants.COMPOSITE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; + +/** + * The type enumerations of {@link MetadataService} + * + * @see MetadataService + * @since 2.7.8 + */ +public enum MetadataServiceType { + + /** + * The default type of {@link MetadataService} + */ + DEFAULT(DEFAULT_METADATA_STORAGE_TYPE), + + /** + * The remote type of {@link MetadataService} + */ + REMOTE(REMOTE_METADATA_STORAGE_TYPE), + + /** + * The composite type of {@link MetadataService} + */ + COMPOSITE(COMPOSITE_METADATA_STORAGE_TYPE); + + /** + * The {@link String} value of type + */ + private final String value; + + MetadataServiceType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static MetadataServiceType getOrDefault(String value) { + MetadataServiceType targetType = null; + for (MetadataServiceType type : values()) { + if (type.getValue().equals(value)) { + targetType = type; + break; + } + } + if (targetType == null) { + targetType = DEFAULT; + } + return targetType; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataUtil.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataUtil.java deleted file mode 100644 index 85ce30e8ccd..00000000000 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataUtil.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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; - -/** - * FIXME - * 2019-07-31 - */ -public class MetadataUtil { - -// public static String getMetadataKey(URL url, KeyTypeEnum keyType){ -// -// } -// -// private String getIdentifierKey() { -// return serviceInterface -// + KEY_SEPARATOR + (version == null ? "" : version) -// + KEY_SEPARATOR + (group == null ? "" : group) -// + KEY_SEPARATOR + (side == null ? "" : side) -// + KEY_SEPARATOR + application; -// } -// -// private String getFilePathKey() { -// return getFilePathKey(DEFAULT_PATH_TAG); -// } -// -// private String getFilePathKey(String pathTag) { -// return pathTag -// + (StringUtils.isEmpty(toServicePath()) ? "" : (PATH_SEPARATOR + toServicePath())) -// + (version == null ? "" : (PATH_SEPARATOR + version)) -// + (group == null ? "" : (PATH_SEPARATOR + group)) -// + (side == null ? "" : (PATH_SEPARATOR + side)) -// + (getApplication() == null ? "" : (PATH_SEPARATOR + getApplication())); -// } -} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ParameterizedServiceNameMapping.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ParameterizedServiceNameMapping.java new file mode 100644 index 00000000000..893a6f4137d --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ParameterizedServiceNameMapping.java @@ -0,0 +1,47 @@ +/* + * 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; + +import org.apache.dubbo.common.URL; + +import java.util.Set; + +import static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY; + +/** + * The parameterized implementation of {@link ServiceNameMapping} + * + * @see ReadOnlyServiceNameMapping + * @since 2.7.8 + */ +public class ParameterizedServiceNameMapping extends ReadOnlyServiceNameMapping { + + /** + * The priority of {@link PropertiesFileServiceNameMapping} + */ + static final int PRIORITY = MAX_PRIORITY + 99; + + @Override + public Set get(URL subscribedURL) { + return getValue(subscribedURL.getParameter(SUBSCRIBED_SERVICE_NAMES_KEY)); + } + + @Override + public int getPriority() { + return PRIORITY; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/PropertiesFileServiceNameMapping.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/PropertiesFileServiceNameMapping.java new file mode 100644 index 00000000000..7870895975a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/PropertiesFileServiceNameMapping.java @@ -0,0 +1,148 @@ +/* + * 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; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.Configuration; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.common.utils.ClassUtils; +import org.apache.dubbo.common.utils.PathUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +import static java.lang.String.format; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.common.utils.StringUtils.SLASH; +import static org.apache.dubbo.metadata.MetadataConstants.KEY_SEPARATOR; + +/** + * The externalized {@link Properties} file implementation of {@link ServiceNameMapping}, + * the default properties class path is + * {@link CommonConstants#DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH "/META-INF/dubbo/service-name-mapping.properties"}, + * whose format as following: + *

+ * dubbo\:com.acme.Interface1\:default = Service1
+ * thirft\:com.acme.InterfaceX = Service1,Service2
+ * rest\:com.acme.interfaceN = Service3
+ * 
+ *

+ * THe search path could be configured by the externalized property {@link CommonConstants#SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY} + * + * @see ReadOnlyServiceNameMapping + * @see ParameterizedServiceNameMapping + * @since 2.7.8 + */ +public class PropertiesFileServiceNameMapping extends ReadOnlyServiceNameMapping { + + /** + * The priority of {@link PropertiesFileServiceNameMapping} is + * lower than {@link ParameterizedServiceNameMapping} + */ + static final int PRIORITY = ParameterizedServiceNameMapping.PRIORITY + 1; + + + private final List propertiesList; + + public PropertiesFileServiceNameMapping() { + this.propertiesList = loadPropertiesList(); + } + + @Override + public Set get(URL subscribedURL) { + String propertyKey = getPropertyKey(subscribedURL); + String propertyValue = null; + + for (Properties properties : propertiesList) { + propertyValue = properties.getProperty(propertyKey); + if (propertyValue != null) { + break; + } + } + + return getValue(propertyValue); + } + + private String getPropertyKey(URL url) { + String protocol = url.getProtocol(); + String serviceInterface = url.getServiceInterface(); + // Optional + String group = url.getParameter(GROUP_KEY); + String version = url.getParameter(VERSION_KEY); + + StringBuilder propertyKeyBuilder = new StringBuilder(protocol) + .append(KEY_SEPARATOR) + .append(serviceInterface); + + appendIfPresent(propertyKeyBuilder, group); + appendIfPresent(propertyKeyBuilder, version); + + return propertyKeyBuilder.toString(); + } + + private void appendIfPresent(StringBuilder builder, String value) { + if (!StringUtils.isBlank(value)) { + builder.append(KEY_SEPARATOR).append(value); + } + } + + private List loadPropertiesList() { + List propertiesList = new LinkedList<>(); + String propertiesPath = getPropertiesPath(); + try { + Enumeration resources = ClassUtils.getClassLoader().getResources(propertiesPath); + while (resources.hasMoreElements()) { + java.net.URL resource = resources.nextElement(); + InputStream inputStream = resource.openStream(); + Properties properties = new Properties(); + properties.load(new InputStreamReader(inputStream, "UTF-8")); + propertiesList.add(properties); + } + } catch (IOException e) { + if (logger.isErrorEnabled()) { + logger.error(format("The path of ServiceNameMapping's Properties file[path : %s] can't be loaded", propertiesPath), e); + } + } + return propertiesList; + } + + private String getPropertiesPath() { + Configuration configuration = ApplicationModel.getEnvironment().getConfiguration(); + String propertyPath = configuration.getString(SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY, DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH); + propertyPath = PathUtils.normalize(propertyPath); + if (propertyPath.startsWith(SLASH)) { + propertyPath = propertyPath.substring(SLASH.length()); + } + return propertyPath; + } + + @Override + public int getPriority() { + return PRIORITY; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ReadOnlyServiceNameMapping.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ReadOnlyServiceNameMapping.java new file mode 100644 index 00000000000..58035d35316 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ReadOnlyServiceNameMapping.java @@ -0,0 +1,45 @@ +/* + * 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; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; + +import java.util.Set; + +import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR_CHAR; +import static org.apache.dubbo.common.utils.StringUtils.splitToSet; + +/** + * Read-Only implementation of {@link ServiceNameMapping} + * + * @since 2.7.8 + */ +public abstract class ReadOnlyServiceNameMapping implements ServiceNameMapping { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + @Override + public void map(URL exportedURL) { + // DO NOTING for mapping + } + + protected Set getValue(String rawValue) { + return splitToSet(rawValue, COMMA_SEPARATOR_CHAR, true); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMapping.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMapping.java index 74113f2dbdd..46f657d184e 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMapping.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMapping.java @@ -16,7 +16,9 @@ */ package org.apache.dubbo.metadata; +import org.apache.dubbo.common.URL; import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.lang.Prioritized; import java.util.Set; @@ -28,7 +30,7 @@ * @since 2.7.5 */ @SPI("default") -public interface ServiceNameMapping { +public interface ServiceNameMapping extends Prioritized { /** * Map the specified Dubbo service interface, group, version and protocol to current Dubbo service name @@ -37,8 +39,20 @@ public interface ServiceNameMapping { * @param group the group of Dubbo service interface (optional) * @param version the version of Dubbo service interface version (optional) * @param protocol the protocol of Dubbo service interface exported (optional) + * @deprecated 2.7.8 This method will be removed since 3.0 */ - void map(String serviceInterface, String group, String version, String protocol); + @Deprecated + default void map(String serviceInterface, String group, String version, String protocol) { + throw new UnsupportedOperationException("This method has been deprecated and should not be invoked!"); + } + + /** + * Map the specified Dubbo service {@link URL} to current Dubbo service name + * + * @param exportedURL the {@link URL} that the Dubbo Provider exported + * @since 2.7.8 + */ + void map(URL exportedURL); /** * Get the service names from the specified Dubbo service interface, group, version and protocol @@ -47,10 +61,22 @@ public interface ServiceNameMapping { * @param group the group of Dubbo service interface (optional) * @param version the version of Dubbo service interface version (optional) * @param protocol the protocol of Dubbo service interface exported (optional) - * @return + * @return non-null {@link Set} + * @deprecated 2.7.8 This method will be removed since 3.0 */ - Set get(String serviceInterface, String group, String version, String protocol); + @Deprecated + default Set get(String serviceInterface, String group, String version, String protocol) { + throw new UnsupportedOperationException("This method has been deprecated and should not be invoked!"); + } + /** + * Get the service names from the subscribed Dubbo service {@link URL} + * + * @param subscribedURL the {@link URL} that the Dubbo consumer subscribed + * @return non-null {@link Set} + * @since 2.7.8 + */ + Set get(URL subscribedURL); /** * Get the default extension of {@link ServiceNameMapping} diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/URLRevisionResolver.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/URLRevisionResolver.java similarity index 67% rename from dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/URLRevisionResolver.java rename to dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/URLRevisionResolver.java index 66f4dbf5f95..f3fe79c3cc5 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/URLRevisionResolver.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/URLRevisionResolver.java @@ -14,12 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.registry.client.metadata; +package org.apache.dubbo.metadata; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.compiler.support.ClassUtils; -import org.apache.dubbo.metadata.MetadataService; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -27,7 +27,9 @@ import java.util.SortedSet; import java.util.TreeSet; import java.util.stream.Collectors; +import java.util.stream.StreamSupport; +import static java.util.Collections.emptyList; import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY; import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY; import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty; @@ -35,29 +37,64 @@ /** * A class to resolve the version from {@link URL URLs} * + * @revised 2.7.8 repackage and refactor * @since 2.7.5 */ public class URLRevisionResolver { - public static final String NO_REVISION = "N/A"; + /** + * @since 2.7.8 + */ + public static final String UNKNOWN_REVISION = "X"; + + /** + * @since 2.7.8 + */ + public static final URLRevisionResolver INSTANCE = new URLRevisionResolver(); + + /** + * Resolve revision as {@link String} from the specified the {@link URL#toFullString() strings} presenting the {@link URL URLs}. + * + * @param url one {@link URL} + * @param others the others {@link URL} + * @return non-null + * @since 2.7.8 + */ + public String resolve(String url, String... others) { + List urls = new ArrayList<>(others.length + 1); + urls.add(url); + urls.addAll(Arrays.asList(others)); + return resolve(urls); + } /** * Resolve revision as {@link String} * * @param urls {@link URL#toFullString() strings} presenting the {@link URL URLs} * @return non-null + * @revised 2.7.8 refactor the parameter as the super interface (from Collection to Iterable) */ - public String resolve(Collection urls) { + public String resolve(Iterable urls) { + List urlsList = toURLsList(urls); + return resolve(urlsList); + } + + /** + * Resolve revision as {@link String} from the specified the {@link URL URLs}. + * + * @param urls the {@link URL URLs} + * @return non-null + * @since 2.7.8 + */ + public String resolve(Collection urls) { if (isEmpty(urls)) { - return NO_REVISION; + return UNKNOWN_REVISION; } - List urlsList = toURLsList(urls); - - SortedSet methodSignatures = resolveMethodSignatures(urlsList); + SortedSet methodSignatures = resolveMethodSignatures(urls); - SortedSet urlParameters = resolveURLParameters(urlsList); + SortedSet urlParameters = resolveURLParameters(urls); SortedSet values = new TreeSet<>(methodSignatures); @@ -66,18 +103,22 @@ public String resolve(Collection urls) { return values.stream() .map(this::hashCode) // generate Long hashCode .reduce(Long::sum) // sum hashCode - .map(String::valueOf) // Long to String - .orElse(NO_REVISION); // NO_REVISION as default + .map(Long::toHexString) // Using Hex for the shorten content + .orElse(UNKNOWN_REVISION); // NO_REVISION as default } - private List toURLsList(Collection urls) { - return urls.stream() + private List toURLsList(Iterable urls) { + if (urls == null) { + return emptyList(); + } + return StreamSupport. + stream(urls.spliterator(), false) .map(URL::valueOf) // String to URL .filter(url -> isNotMetadataService(url.getServiceInterface())) // filter not MetadataService interface .collect(Collectors.toList()); } - private SortedSet resolveMethodSignatures(List urls) { + private SortedSet resolveMethodSignatures(Collection urls) { return urls.stream() .map(URL::getServiceInterface) // get the service interface .map(ClassUtils::forName) // load business interface class diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/WritableMetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/WritableMetadataService.java index 3a17395972b..6cde356ee04 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/WritableMetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/WritableMetadataService.java @@ -20,10 +20,10 @@ import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.metadata.store.InMemoryWritableMetadataService; -import org.apache.dubbo.rpc.model.ApplicationModel; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.apache.dubbo.rpc.model.ApplicationModel.getName; /** * Local {@link MetadataService} that extends {@link MetadataService} and provides the modification, which is used for @@ -40,7 +40,7 @@ public interface WritableMetadataService extends MetadataService { */ @Override default String serviceName() { - return ApplicationModel.getApplication(); + return getName(); } /** @@ -63,7 +63,9 @@ default String serviceName() { * fresh Exports * * @return If success , return true + * @deprecated Recommend to use {@link MetadataServiceExporter} since 2.7.8 */ + @Deprecated default boolean refreshMetadata(String exportedRevision, String subscribedRevision) { return true; } @@ -84,7 +86,7 @@ default boolean refreshMetadata(String exportedRevision, String subscribedRevisi */ boolean unsubscribeURL(URL url); - void publishServiceDefinition(URL providerUrl); + void publishServiceDefinition(URL url); /** * Get {@link ExtensionLoader#getDefaultExtension() the defautl extension} of {@link WritableMetadataService} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReport.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReport.java index e5fc587c37d..068d3a040ed 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReport.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReport.java @@ -17,34 +17,144 @@ package org.apache.dubbo.metadata.report; -import java.util.List; -import java.util.Map; -import java.util.Set; - import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.metadata.URLRevisionResolver; import org.apache.dubbo.metadata.definition.model.ServiceDefinition; import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; +import com.google.gson.Gson; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptySortedSet; +import static org.apache.dubbo.rpc.model.ApplicationModel.getName; + /** + * The interface to report the metadata * + * @see AutoCloseable since 2.7.8 */ -public interface MetadataReport { +public interface MetadataReport extends AutoCloseable { void storeProviderMetadata(MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition); void storeConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, Map serviceParameterMap); - void saveServiceMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url); + /** + * @deprecated 2.7.8 + */ + @Deprecated + default void saveServiceMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) { + } - void removeServiceMetadata(ServiceMetadataIdentifier metadataIdentifier); + /** + * @deprecated 2.7.8 + */ + @Deprecated + default void removeServiceMetadata(ServiceMetadataIdentifier metadataIdentifier) { - List getExportedURLs(ServiceMetadataIdentifier metadataIdentifier); + } - void saveSubscribedData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, Set urls); + /** + * @deprecated 2.7.8 + */ + @Deprecated + default List getExportedURLs(ServiceMetadataIdentifier metadataIdentifier) { + return emptyList(); + } - List getSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier); + void saveSubscribedData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, Collection urls); + + Collection getSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier); String getServiceDefinition(MetadataIdentifier metadataIdentifier); -} + + /** + * Save the exported {@link URL#toFullString() strings} presenting the {@link URL URLs} in bulk. + * + * @param exportedURLs the exported {@link URL urls} + * @return If successful, return true, or false + * @since 2.7.8 + */ + default boolean saveExportedURLs(SortedSet exportedURLs) { + return saveExportedURLs(getName(), exportedURLs); + } + + /** + * Save the exported {@link URL#toFullString() strings} presenting the {@link URL URLs} in bulk. + * + * @param serviceName the specified Dubbo service name + * @param exportedURLs the exported {@link URL urls} + * @return If successful, return true, or false + * @since 2.7.8 + */ + default boolean saveExportedURLs(String serviceName, SortedSet exportedURLs) { + return saveExportedURLs(serviceName, new URLRevisionResolver().resolve(exportedURLs), exportedURLs); + } + + /** + * Save the exported {@link URL#toFullString() strings} presenting the {@link URL URLs} in bulk. + * + * @param serviceName the specified Dubbo service name + * @param exportedServicesRevision the revision of the exported Services + * @param exportedURLs the exported {@link URL urls} + * @return If successful, return true, or false + * @since 2.7.8 + */ + default boolean saveExportedURLs(String serviceName, String exportedServicesRevision, SortedSet exportedURLs) { + Gson gson = new Gson(); + String content = gson.toJson(exportedURLs); + return saveExportedURLs(serviceName, exportedServicesRevision, content); + } + + /** + * Save the exported {@link URL#toFullString() strings} presenting the {@link URL URLs} in bulk. + * + * @param serviceName the specified Dubbo service name + * @param exportedServicesRevision the revision of the exported Services + * @param exportedURLsContent the content of the exported {@link URL urls} + * @return If successful, return true, or false + * @since 2.7.8 + */ + default boolean saveExportedURLs(String serviceName, String exportedServicesRevision, String exportedURLsContent) { + return true; + } + + /** + * Get the {@link URL#toFullString() strings} presenting the {@link URL URLs} that were exported by the provider + * + * @param serviceName the specified Dubbo service name + * @param exportedServicesRevision the revision of the exported Services + * @return non-null + * @since 2.7.8 + */ + default SortedSet getExportedURLs(String serviceName, String exportedServicesRevision) { + String exportedURLsContent = getExportedURLsContent(serviceName, exportedServicesRevision); + if (StringUtils.isBlank(exportedURLsContent)) { + return emptySortedSet(); + } + Gson gson = new Gson(); + return gson.fromJson(exportedURLsContent, TreeSet.class); + } + + /** + * Get the {@link URL#toFullString() strings} presenting the {@link URL URLs} that were exported by the provider + * + * @param serviceName the specified Dubbo service name + * @param exportedServicesRevision the revision of the exported Services + * @return the content of the exported {@link URL urls} if found, or null + * @since 2.7.8 + */ + default String getExportedURLsContent(String serviceName, String exportedServicesRevision) { + return null; + } + +} \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/BaseApplicationMetadataIdentifier.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/BaseApplicationMetadataIdentifier.java index 9e6b76b3c2b..f70678b30d0 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/BaseApplicationMetadataIdentifier.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/BaseApplicationMetadataIdentifier.java @@ -17,6 +17,7 @@ package org.apache.dubbo.metadata.report.identifier; import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR; +import static org.apache.dubbo.common.utils.PathUtils.buildPath; import static org.apache.dubbo.metadata.MetadataConstants.DEFAULT_PATH_TAG; import static org.apache.dubbo.metadata.MetadataConstants.KEY_SEPARATOR; @@ -36,9 +37,7 @@ String getUniqueKey(KeyTypeEnum keyType, String... params) { } String getIdentifierKey(String... params) { - - return application - + joinParams(KEY_SEPARATOR, params); + return application + joinParams(KEY_SEPARATOR, params); } private String joinParams(String joinChar, String... params) { @@ -58,9 +57,7 @@ private String getFilePathKey(String... params) { } private String getFilePathKey(String pathTag, String... params) { - return pathTag - + application - + joinParams(PATH_SEPARATOR, params); + return buildPath(pathTag, application, joinParams(PATH_SEPARATOR, params)); } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/KeyTypeEnum.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/KeyTypeEnum.java index 2c0da572242..3253f85a73e 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/KeyTypeEnum.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/KeyTypeEnum.java @@ -16,9 +16,47 @@ */ package org.apache.dubbo.metadata.report.identifier; +import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR; +import static org.apache.dubbo.common.utils.PathUtils.buildPath; +import static org.apache.dubbo.common.utils.StringUtils.EMPTY_STRING; +import static org.apache.dubbo.common.utils.StringUtils.isBlank; +import static org.apache.dubbo.metadata.MetadataConstants.KEY_SEPARATOR; + /** * 2019-08-15 */ public enum KeyTypeEnum { - PATH, UNIQUE_KEY + + PATH(PATH_SEPARATOR) { + public String build(String one, String... others) { + return buildPath(one, others); + } + }, + + UNIQUE_KEY(KEY_SEPARATOR) { + public String build(String one, String... others) { + StringBuilder keyBuilder = new StringBuilder(one); + for (String other : others) { + keyBuilder.append(separator).append(isBlank(other) ? EMPTY_STRING : other); + } + return keyBuilder.toString(); + } + }; + + final String separator; + + KeyTypeEnum(String separator) { + this.separator = separator; + } + + /** + * Build Key + * + * @param one one + * @param others the others + * @return + * @since 2.7.8 + */ + public abstract String build(String one, String... others); + } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java index 1d394017447..f3b90db5e36 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java @@ -44,6 +44,7 @@ import java.nio.channels.FileLock; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -52,7 +53,6 @@ import java.util.SortedSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ThreadLocalRandom; @@ -61,11 +61,15 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import static java.util.concurrent.Executors.newScheduledThreadPool; +import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE; import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; +import static org.apache.dubbo.common.utils.StringUtils.replace; import static org.apache.dubbo.metadata.report.support.Constants.CYCLE_REPORT_KEY; import static org.apache.dubbo.metadata.report.support.Constants.DEFAULT_METADATA_REPORT_CYCLE_REPORT; import static org.apache.dubbo.metadata.report.support.Constants.DEFAULT_METADATA_REPORT_RETRY_PERIOD; @@ -86,24 +90,52 @@ public abstract class AbstractMetadataReport implements MetadataReport { // Log output protected final Logger logger = LoggerFactory.getLogger(getClass()); - // Local disk cache, where the special key value.registries records the list of metadata centers, and the others are the list of notified service providers - final Properties properties = new Properties(); - private final ExecutorService reportCacheExecutor = Executors.newFixedThreadPool(1, new NamedThreadFactory("DubboSaveMetadataReport", true)); + private final AtomicBoolean initialized = new AtomicBoolean(false); + final Map allMetadataReports = new ConcurrentHashMap<>(4); - private final AtomicLong lastCacheChanged = new AtomicLong(); final Map failedReports = new ConcurrentHashMap<>(4); + private URL reportURL; boolean syncReport; + // Local disk cache file - File file; - private AtomicBoolean initialized = new AtomicBoolean(false); - public MetadataReportRetry metadataReportRetry; + File localCacheFile; + // Local disk cache, where the special key value.registries records the list of metadata centers, and the others are the list of notified service providers + final Properties properties = new Properties(); + + private final AtomicLong lastCacheChanged = new AtomicLong(); + + // ThreadPoolExecutors + private final ExecutorService reportCacheExecutor; + + public final MetadataReportRetry metadataReportRetry; + + private final ScheduledExecutorService cycleReportExecutor; public AbstractMetadataReport(URL reportServerURL) { setUrl(reportServerURL); + + this.localCacheFile = initializeLocalCacheFile(reportServerURL); + loadProperties(); + syncReport = reportServerURL.getParameter(SYNC_REPORT_KEY, false); + metadataReportRetry = new MetadataReportRetry(reportServerURL.getParameter(RETRY_TIMES_KEY, DEFAULT_METADATA_REPORT_RETRY_TIMES), + reportServerURL.getParameter(RETRY_PERIOD_KEY, DEFAULT_METADATA_REPORT_RETRY_PERIOD)); + this.reportCacheExecutor = newSingleThreadExecutor(new NamedThreadFactory("DubboSaveMetadataReport", true)); + this.cycleReportExecutor = newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboMetadataReportTimer", true)); + // cycle report the data switch + if (reportServerURL.getParameter(CYCLE_REPORT_KEY, DEFAULT_METADATA_REPORT_CYCLE_REPORT)) { + cycleReportExecutor.scheduleAtFixedRate(this::publishAll, calculateStartTime(), ONE_DAY_IN_MILLISECONDS, TimeUnit.MILLISECONDS); + } + } + + private File initializeLocalCacheFile(URL reportServerURL) { // Start file save timer - String defaultFilename = System.getProperty("user.home") + "/.dubbo/dubbo-metadata-" + reportServerURL.getParameter(APPLICATION_KEY) + "-" + reportServerURL.getAddress().replaceAll(":", "-") + ".cache"; + String defaultFilename = System.getProperty("user.home") + + "/.dubbo/dubbo-metadata-" + + reportServerURL.getParameter(APPLICATION_KEY) + "-" + + replace(reportServerURL.getAddress(), ":", "-") + + ".cache"; String filename = reportServerURL.getParameter(FILE_KEY, defaultFilename); File file = null; if (ConfigUtils.isNotEmpty(filename)) { @@ -118,16 +150,7 @@ public AbstractMetadataReport(URL reportServerURL) { file.delete(); } } - this.file = file; - loadProperties(); - syncReport = reportServerURL.getParameter(SYNC_REPORT_KEY, false); - metadataReportRetry = new MetadataReportRetry(reportServerURL.getParameter(RETRY_TIMES_KEY, DEFAULT_METADATA_REPORT_RETRY_TIMES), - reportServerURL.getParameter(RETRY_PERIOD_KEY, DEFAULT_METADATA_REPORT_RETRY_PERIOD)); - // cycle report the data switch - if (reportServerURL.getParameter(CYCLE_REPORT_KEY, DEFAULT_METADATA_REPORT_CYCLE_REPORT)) { - ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboMetadataReportTimer", true)); - scheduler.scheduleAtFixedRate(this::publishAll, calculateStartTime(), ONE_DAY_IN_MILLISECONDS, TimeUnit.MILLISECONDS); - } + return file; } public URL getUrl() { @@ -145,12 +168,12 @@ private void doSaveProperties(long version) { if (version < lastCacheChanged.get()) { return; } - if (file == null) { + if (localCacheFile == null) { return; } // Save try { - File lockfile = new File(file.getAbsolutePath() + ".lock"); + File lockfile = new File(localCacheFile.getAbsolutePath() + ".lock"); if (!lockfile.exists()) { lockfile.createNewFile(); } @@ -158,14 +181,14 @@ private void doSaveProperties(long version) { FileChannel channel = raf.getChannel()) { FileLock lock = channel.tryLock(); if (lock == null) { - throw new IOException("Can not lock the metadataReport cache file " + file.getAbsolutePath() + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.metadata.file=xxx.properties"); + throw new IOException("Can not lock the metadataReport cache file " + localCacheFile.getAbsolutePath() + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.metadata.file=xxx.properties"); } // Save try { - if (!file.exists()) { - file.createNewFile(); + if (!localCacheFile.exists()) { + localCacheFile.createNewFile(); } - try (FileOutputStream outputFile = new FileOutputStream(file)) { + try (FileOutputStream outputFile = new FileOutputStream(localCacheFile)) { properties.store(outputFile, "Dubbo metadataReport Cache"); } } finally { @@ -183,20 +206,20 @@ private void doSaveProperties(long version) { } void loadProperties() { - if (file != null && file.exists()) { - try (InputStream in = new FileInputStream(file)) { + if (localCacheFile != null && localCacheFile.exists()) { + try (InputStream in = new FileInputStream(localCacheFile)) { properties.load(in); if (logger.isInfoEnabled()) { - logger.info("Load service store file " + file + ", data: " + properties); + logger.info("Load service store file " + localCacheFile + ", data: " + properties); } } catch (Throwable e) { - logger.warn("Failed to load service store file " + file, e); + logger.warn("Failed to load service store file " + localCacheFile, e); } } } private void saveProperties(MetadataIdentifier metadataIdentifier, String value, boolean add, boolean sync) { - if (file == null) { + if (localCacheFile == null) { return; } @@ -318,7 +341,7 @@ public List getExportedURLs(ServiceMetadataIdentifier metadataIdentifier } @Override - public void saveSubscribedData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, Set urls) { + public void saveSubscribedData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, Collection urls) { if (syncReport) { doSaveSubscriberData(subscriberMetadataIdentifier, new Gson().toJson(urls)); } else { @@ -328,7 +351,7 @@ public void saveSubscribedData(SubscriberMetadataIdentifier subscriberMetadataId @Override - public List getSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) { + public Set getSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) { String content = doGetSubscribedURLs(subscriberMetadataIdentifier); Type setType = new TypeToken>() { }.getType(); @@ -392,7 +415,7 @@ long calculateStartTime() { class MetadataReportRetry { protected final Logger logger = LoggerFactory.getLogger(getClass()); - final ScheduledExecutorService retryExecutor = Executors.newScheduledThreadPool(0, new NamedThreadFactory("DubboMetadataReportRetryTimer", true)); + final ScheduledExecutorService retryExecutor = newScheduledThreadPool(0, new NamedThreadFactory("DubboMetadataReportRetryTimer", true)); volatile ScheduledFuture retryScheduledFuture; final AtomicInteger retryCounter = new AtomicInteger(0); // retry task schedule period @@ -435,8 +458,10 @@ public void run() { } void cancelRetryTask() { - retryScheduledFuture.cancel(false); - retryExecutor.shutdown(); + if (retryScheduledFuture != null) { + retryScheduledFuture.cancel(false); + } + shutdown(retryExecutor); } } @@ -451,6 +476,13 @@ private void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadat doSaveSubscriberData(subscriberMetadataIdentifier, encodedUrlList); } + @Override + public final void close() throws Exception { + this.shutdownThreadPoolExecutors(); + this.clearCache(); + doClose(); + } + protected abstract void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions); protected abstract void doStoreConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, String serviceParameterString); @@ -465,4 +497,35 @@ private void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadat protected abstract String doGetSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier); + /** + * Close other resources + * + * @since 2.7.8 + */ + protected void doClose() throws Exception { + + } + + private void clearCache() { + this.properties.clear(); + this.allMetadataReports.clear(); + this.failedReports.clear(); + this.localCacheFile.delete(); + } + + private void shutdownThreadPoolExecutors() { + this.metadataReportRetry.cancelRetryTask(); + shutdown(this.reportCacheExecutor); + shutdown(cycleReportExecutor); + } + + private static void shutdown(ExecutorService executorService) { + if (executorService == null) { + return; + } + if (!executorService.isShutdown()) { + executorService.shutdown(); + } + } + } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/ConfigCenterBasedMetadataReport.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/ConfigCenterBasedMetadataReport.java new file mode 100644 index 00000000000..d962ca51872 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/ConfigCenterBasedMetadataReport.java @@ -0,0 +1,162 @@ +/* + * 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.report.support; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; +import org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory; +import org.apache.dubbo.metadata.report.MetadataReport; +import org.apache.dubbo.metadata.report.identifier.BaseMetadataIdentifier; +import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; +import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; +import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; +import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; + +import java.util.List; + +import static org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory.getDynamicConfigurationFactory; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.metadata.MetadataConstants.EXPORTED_URLS_TAG; + +/** + * The generic implementation of {@link MetadataReport} based on {@link DynamicConfiguration + * the config-center infrastructure} + * + * @see AbstractMetadataReport + * @since 2.7.8 + */ +public class ConfigCenterBasedMetadataReport extends AbstractMetadataReport { + + private final KeyTypeEnum keyType; + + private final String group; + + private final DynamicConfiguration dynamicConfiguration; + + public ConfigCenterBasedMetadataReport(URL reportServerURL, KeyTypeEnum keyTypeEnum) { + super(reportServerURL); + this.keyType = keyTypeEnum; + this.group = reportServerURL.getParameter(GROUP_KEY, DEFAULT_ROOT); + String extensionName = reportServerURL.getProtocol(); + DynamicConfigurationFactory dynamicConfigurationFactory = getDynamicConfigurationFactory(extensionName); + dynamicConfiguration = dynamicConfigurationFactory.getDynamicConfiguration(reportServerURL); + } + + + @Override + protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) { + saveMetadata(providerMetadataIdentifier, serviceDefinitions); + } + + @Override + protected void doStoreConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, String serviceParameterString) { + saveMetadata(consumerMetadataIdentifier, serviceParameterString); + } + + @Override + protected void doSaveMetadata(ServiceMetadataIdentifier metadataIdentifier, URL url) { + saveMetadata(metadataIdentifier, URL.encode(url.toFullString())); + } + + @Override + protected void doRemoveMetadata(ServiceMetadataIdentifier metadataIdentifier) { + removeMetadata(metadataIdentifier); + } + + @Override + protected List doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) { + throw new UnsupportedOperationException("doGetExportedURLs method will not be supported!"); + } + + @Override + protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urlListStr) { + saveMetadata(subscriberMetadataIdentifier, urlListStr); + } + + @Override + protected String doGetSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) { + return getMetadata(subscriberMetadataIdentifier); + } + + @Override + public String getServiceDefinition(MetadataIdentifier metadataIdentifier) { + return getMetadata(metadataIdentifier); + } + + @Override + public boolean saveExportedURLs(String serviceName, String exportedServicesRevision, String exportedURLsContent) { + String key = buildExportedURLsMetadataKey(serviceName, exportedServicesRevision); + return dynamicConfiguration.publishConfig(key, group, exportedURLsContent); + } + + @Override + public String getExportedURLsContent(String serviceName, String exportedServicesRevision) { + String key = buildExportedURLsMetadataKey(serviceName, exportedServicesRevision); + return dynamicConfiguration.getConfig(key, group); + } + + private String buildExportedURLsMetadataKey(String serviceName, String exportedServicesRevision) { + return keyType.build(EXPORTED_URLS_TAG, serviceName, exportedServicesRevision); + } + + protected void saveMetadata(BaseMetadataIdentifier metadataIdentifier, String value) { + String key = getKey(metadataIdentifier); + dynamicConfiguration.publishConfig(key, group, value); + } + + protected void saveMetadata(MetadataIdentifier metadataIdentifier, String value) { + String key = getKey(metadataIdentifier); + dynamicConfiguration.publishConfig(key, group, value); + } + + protected String getMetadata(ServiceMetadataIdentifier metadataIdentifier) { + String key = getKey(metadataIdentifier); + return dynamicConfiguration.getConfig(key, group); + } + + protected String getMetadata(MetadataIdentifier metadataIdentifier) { + String key = getKey(metadataIdentifier); + return dynamicConfiguration.getConfig(key, group); + } + + protected String getMetadata(SubscriberMetadataIdentifier metadataIdentifier) { + String key = getKey(metadataIdentifier); + return dynamicConfiguration.getConfig(key, group); + } + + protected void removeMetadata(MetadataIdentifier metadataIdentifier) { + String key = getKey(metadataIdentifier); + dynamicConfiguration.removeConfig(key, group); + } + + protected void removeMetadata(ServiceMetadataIdentifier metadataIdentifier) { + String key = getKey(metadataIdentifier); + dynamicConfiguration.removeConfig(key, group); + } + + protected String getKey(BaseMetadataIdentifier metadataIdentifier) { + return metadataIdentifier.getUniqueKey(keyType); + } + + protected String getKey(MetadataIdentifier metadataIdentifier) { + return metadataIdentifier.getUniqueKey(keyType); + } + + protected void doClose() throws Exception { + this.dynamicConfiguration.close(); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/ConfigCenterBasedMetadataReportFactory.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/ConfigCenterBasedMetadataReportFactory.java new file mode 100644 index 00000000000..5b0f780ff4e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/ConfigCenterBasedMetadataReportFactory.java @@ -0,0 +1,86 @@ +/* + * 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.report.support; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; +import org.apache.dubbo.metadata.report.MetadataReport; +import org.apache.dubbo.metadata.report.MetadataReportFactory; +import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static org.apache.dubbo.common.config.configcenter.TreePathDynamicConfiguration.CONFIG_BASE_PATH_PARAM_NAME; +import static org.apache.dubbo.metadata.MetadataConstants.DEFAULT_PATH_TAG; +import static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY; +import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY; + +/** + * The abstract implementation of {@link MetadataReportFactory} based on + * {@link DynamicConfiguration the config-center infrastructure} + * + * @see MetadataReportFactory + * @see MetadataReport + * @see DynamicConfiguration + * @since 2.7.8 + */ +public abstract class ConfigCenterBasedMetadataReportFactory implements MetadataReportFactory { + + /** + * org.apache.dubbo.metadata.report.MetadataReport + */ + private static final String URL_PATH = MetadataReport.class.getName(); + + // Registry Collection Map + private static final Map metadataReportCache = new ConcurrentHashMap(); + + private final KeyTypeEnum keyType; + + public ConfigCenterBasedMetadataReportFactory(KeyTypeEnum keyType) { + if (keyType == null) { + throw new NullPointerException("The keyType argument must not be null!"); + } + this.keyType = keyType; + } + + @Override + public ConfigCenterBasedMetadataReport getMetadataReport(URL url) { + + url = url.setPath(URL_PATH).removeParameters(EXPORT_KEY, REFER_KEY); + + final URL actualURL; + if (url.getParameter(CONFIG_BASE_PATH_PARAM_NAME) == null) { + actualURL = url.addParameter(CONFIG_BASE_PATH_PARAM_NAME, DEFAULT_PATH_TAG); + } else { + actualURL = url; + } + + String key = actualURL.toServiceString(); + // Lock the metadata access process to ensure a single instance of the metadata instance + return metadataReportCache.computeIfAbsent(key, k -> new ConfigCenterBasedMetadataReport(actualURL, keyType)); + } + + /** + * Get {@link KeyTypeEnum the key type} + * + * @return non-null + */ + protected KeyTypeEnum getKeyType() { + return keyType; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/file/FileSystemMetadataReportFactory.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/file/FileSystemMetadataReportFactory.java new file mode 100644 index 00000000000..c4cc4874b85 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/file/FileSystemMetadataReportFactory.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.metadata.report.support.file; + +import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; +import org.apache.dubbo.metadata.report.support.ConfigCenterBasedMetadataReportFactory; + +/** + * The implementation of {@link ConfigCenterBasedMetadataReportFactory} based on File System + * + * @see ConfigCenterBasedMetadataReportFactory + * @since 2.7.8 + */ +public class FileSystemMetadataReportFactory extends ConfigCenterBasedMetadataReportFactory { + + public FileSystemMetadataReportFactory() { + super(KeyTypeEnum.PATH); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/AbstractAbstractWritableMetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/AbstractAbstractWritableMetadataService.java new file mode 100644 index 00000000000..35054c9ecb1 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/AbstractAbstractWritableMetadataService.java @@ -0,0 +1,100 @@ +/* + * 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; + +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.WritableMetadataService; +import org.apache.dubbo.metadata.definition.model.ServiceDefinition; + +import com.google.gson.Gson; + +import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; +import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY; +import static org.apache.dubbo.common.utils.ClassUtils.forName; +import static org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder.buildFullDefinition; +import static org.apache.dubbo.remoting.Constants.BIND_IP_KEY; +import static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY; +import static org.apache.dubbo.rpc.Constants.GENERIC_KEY; +import static org.apache.dubbo.rpc.support.ProtocolUtils.isGeneric; + +/** + * The abstract implementation of {@link WritableMetadataService} + * + * @see WritableMetadataService + * @since 2.7.8 + */ +public abstract class AbstractAbstractWritableMetadataService implements WritableMetadataService { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + @Override + public void publishServiceDefinition(URL url) { + if (SERVICE_INTERFACE_NAME.equals(url.getServiceInterface())) { // Ignore the interface "MetadataService" + return; + } + + // Remove the useless parameters + url = url.removeParameters(PID_KEY, TIMESTAMP_KEY, BIND_IP_KEY, BIND_PORT_KEY, TIMESTAMP_KEY); + + String side = url.getParameter(SIDE_KEY); + if (PROVIDER_SIDE.equalsIgnoreCase(side)) { + publishProviderServiceDefinition(url); + } else { + publishConsumerParameters(url); + } + } + + protected void publishProviderServiceDefinition(URL url) { + String serviceDefinition = getServiceDefinition(url); + if (!StringUtils.isBlank(serviceDefinition)) { + publishServiceDefinition(url.getServiceKey(), serviceDefinition); + } + } + + protected String getServiceDefinition(URL exportedURL) { + String interfaceName = exportedURL.getParameter(INTERFACE_KEY); + String json = null; + try { + if (StringUtils.isNotEmpty(interfaceName) && !isGeneric(exportedURL.getParameter(GENERIC_KEY))) { + Class interfaceClass = forName(interfaceName); + ServiceDefinition serviceDefinition = buildFullDefinition(interfaceClass, exportedURL.getParameters()); + Gson gson = new Gson(); + json = gson.toJson(serviceDefinition); + } + } catch (ClassNotFoundException e) { + //ignore error + if (logger.isErrorEnabled()) { + logger.error("The interface class[name : " + interfaceName + "] can't be found , providerUrl: " + + exportedURL.toFullString()); + } + } + return json; + } + + protected void publishConsumerParameters(URL url) { + } + + protected void publishServiceDefinition(String key, String json) { + } + +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/BaseWritableMetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/BaseWritableMetadataService.java deleted file mode 100644 index 84fcd158b69..00000000000 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/BaseWritableMetadataService.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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; - -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.MetadataService; - -import java.util.Collection; -import java.util.Map; -import java.util.SortedSet; -import java.util.concurrent.ConcurrentNavigableMap; -import java.util.concurrent.ConcurrentSkipListMap; -import java.util.function.Consumer; - -public class BaseWritableMetadataService { - final Logger logger = LoggerFactory.getLogger(getClass()); - - // =================================== Registration =================================== // - - /** - * All exported {@link URL urls} {@link Map} whose key is the return value of {@link URL#getServiceKey()} method - * and value is the {@link SortedSet sorted set} of the {@link URL URLs} - */ - static ConcurrentNavigableMap> exportedServiceURLs = new ConcurrentSkipListMap<>(); - - // ==================================================================================== // - - // =================================== Subscription =================================== // - - /** - * The subscribed {@link URL urls} {@link Map} of {@link MetadataService}, - * whose key is the return value of {@link URL#getServiceKey()} method and value is - * the {@link SortedSet sorted set} of the {@link URL URLs} - */ - final static ConcurrentNavigableMap> SUBSCRIBED_SERVICE_URLS = new ConcurrentSkipListMap<>(); - - final static ConcurrentNavigableMap SERVICE_DEFINITIONS = new ConcurrentSkipListMap<>(); - - - boolean throwableAction(Consumer consumer, URL url) { - try { - consumer.accept(url); - } catch (Exception e) { - logger.error("Failed to remove url metadata to remote center, url is: " + url); - return false; - } - return true; - } - - public SortedSet getSubscribedURLs() { - return getAllUnmodifiableServiceURLs(SUBSCRIBED_SERVICE_URLS); - } - - static SortedSet getAllUnmodifiableServiceURLs(Map> serviceURLs) { - return MetadataService.toSortedStrings(serviceURLs.values().stream().flatMap(Collection::stream)); - } -} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataService.java index ee1e4d19770..a897d766b6c 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataService.java @@ -16,17 +16,11 @@ */ package org.apache.dubbo.metadata.store; +import org.apache.dubbo.common.BaseServiceMetadata; 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.MetadataService; import org.apache.dubbo.metadata.WritableMetadataService; -import org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder; import org.apache.dubbo.metadata.definition.model.ServiceDefinition; -import org.apache.dubbo.rpc.support.ProtocolUtils; - -import com.google.gson.Gson; import java.util.Comparator; import java.util.Map; @@ -39,12 +33,11 @@ import java.util.concurrent.locks.ReentrantLock; import static java.util.Collections.emptySortedSet; +import static java.util.Collections.unmodifiableSortedMap; import static java.util.Collections.unmodifiableSortedSet; import static org.apache.dubbo.common.URL.buildKey; -import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty; -import static org.apache.dubbo.rpc.Constants.GENERIC_KEY; /** * The {@link WritableMetadataService} implementation stores the metadata of Dubbo services in memory locally when they @@ -54,9 +47,7 @@ * @see WritableMetadataService * @since 2.7.5 */ -public class InMemoryWritableMetadataService implements WritableMetadataService { - - final Logger logger = LoggerFactory.getLogger(getClass()); +public class InMemoryWritableMetadataService extends AbstractAbstractWritableMetadataService { private final Lock lock = new ReentrantLock(); @@ -66,7 +57,7 @@ public class InMemoryWritableMetadataService implements WritableMetadataService * All exported {@link URL urls} {@link Map} whose key is the return value of {@link URL#getServiceKey()} method * and value is the {@link SortedSet sorted set} of the {@link URL URLs} */ - ConcurrentNavigableMap> exportedServiceURLs = new ConcurrentSkipListMap<>(); + private final ConcurrentNavigableMap> exportedServiceURLs = new ConcurrentSkipListMap<>(); // ==================================================================================== // @@ -77,9 +68,13 @@ public class InMemoryWritableMetadataService implements WritableMetadataService * whose key is the return value of {@link URL#getServiceKey()} method and value is * the {@link SortedSet sorted set} of the {@link URL URLs} */ - ConcurrentNavigableMap> subscribedServiceURLs = new ConcurrentSkipListMap<>(); + private final ConcurrentNavigableMap> subscribedServiceURLs = new ConcurrentSkipListMap<>(); - ConcurrentNavigableMap serviceDefinitions = new ConcurrentSkipListMap<>(); + /** + * The {@link Map} caches the json of {@link ServiceDefinition} with + * {@link BaseServiceMetadata#buildServiceKey(String, String, String) the service key} + */ + private final ConcurrentNavigableMap serviceDefinitions = new ConcurrentSkipListMap<>(); @Override public SortedSet getSubscribedURLs() { @@ -131,33 +126,25 @@ public boolean unsubscribeURL(URL url) { } @Override - public void publishServiceDefinition(URL providerUrl) { - try { - String interfaceName = providerUrl.getParameter(INTERFACE_KEY); - if (StringUtils.isNotEmpty(interfaceName) - && !ProtocolUtils.isGeneric(providerUrl.getParameter(GENERIC_KEY))) { - Class interfaceClass = Class.forName(interfaceName); - ServiceDefinition serviceDefinition = ServiceDefinitionBuilder.build(interfaceClass); - Gson gson = new Gson(); - String data = gson.toJson(serviceDefinition); - serviceDefinitions.put(providerUrl.getServiceKey(), data); - return; - } - logger.error("publishProvider interfaceName is empty . providerUrl: " + providerUrl.toFullString()); - } catch (Throwable t) { - //ignore error - logger.error("publishProvider getServiceDescriptor error. providerUrl: " + providerUrl.toFullString(), t.getCause()); - } + protected void publishServiceDefinition(String key, String json) { + serviceDefinitions.put(key, json); } @Override - public String getServiceDefinition(String interfaceName, String version, String group) { - return serviceDefinitions.get(URL.buildKey(interfaceName, group, version)); + public String getServiceDefinition(String serviceDefinitionKey) { + return serviceDefinitions.get(serviceDefinitionKey); } - @Override - public String getServiceDefinition(String serviceKey) { - return serviceDefinitions.get(serviceKey); + public Map> getExportedServiceURLs() { + return unmodifiableSortedMap(exportedServiceURLs); + } + + public Map> getSubscribedServiceURLs() { + return unmodifiableSortedMap(subscribedServiceURLs); + } + + public Map getServiceDefinitions() { + return unmodifiableSortedMap(serviceDefinitions); } boolean addURL(Map> serviceURLs, URL url) { @@ -223,7 +210,6 @@ private boolean isAcceptableProtocol(String protocol, URL url) { || protocol.equals(url.getProtocol()); } - static class URLComparator implements Comparator { public static final URLComparator INSTANCE = new URLComparator(); diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataService.java index 0a2dd76dd3e..c2ae3e512a6 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataService.java @@ -17,35 +17,22 @@ package org.apache.dubbo.metadata.store; 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.CollectionUtils; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.metadata.URLRevisionResolver; import org.apache.dubbo.metadata.WritableMetadataService; import org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder; import org.apache.dubbo.metadata.definition.model.FullServiceDefinition; import org.apache.dubbo.metadata.report.MetadataReport; import org.apache.dubbo.metadata.report.MetadataReportInstance; import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; -import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; -import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; -import org.apache.dubbo.remoting.Constants; -import org.apache.dubbo.rpc.RpcException; -import java.util.Iterator; -import java.util.Set; import java.util.SortedSet; -import java.util.function.BiConsumer; -import java.util.function.Consumer; import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; -import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; /** @@ -55,15 +42,15 @@ * * @since 2.7.5 */ -public class RemoteWritableMetadataService implements WritableMetadataService { +public class RemoteWritableMetadataService extends AbstractAbstractWritableMetadataService { - protected final Logger logger = LoggerFactory.getLogger(getClass()); - private volatile String exportedRevision; - private volatile String subscribedRevision; - private InMemoryWritableMetadataService writableMetadataService; + private final InMemoryWritableMetadataService writableMetadataServiceDelegate; - public RemoteWritableMetadataService(InMemoryWritableMetadataService writableMetadataService) { - this.writableMetadataService = writableMetadataService; + private final URLRevisionResolver urlRevisionResolver; + + public RemoteWritableMetadataService() { + this.writableMetadataServiceDelegate = (InMemoryWritableMetadataService) WritableMetadataService.getDefaultExtension(); + urlRevisionResolver = URLRevisionResolver.INSTANCE; } public MetadataReport getMetadataReport() { @@ -71,163 +58,65 @@ public MetadataReport getMetadataReport() { } @Override - public void publishServiceDefinition(URL url) { - String side = url.getParameter(SIDE_KEY); - if (PROVIDER_SIDE.equalsIgnoreCase(side)) { - //TODO, the params part is duplicate with that stored by exportURL(url), can be further optimized in the future. - publishProvider(url); - } else { - //TODO, only useful for ops showing the url parameters, this is duplicate with subscribeURL(url), can be removed in the future. - publishConsumer(url); - } + protected void publishConsumerParameters(URL consumerURL) { + getMetadataReport().storeConsumerMetadata(new MetadataIdentifier(consumerURL.getServiceInterface(), + consumerURL.getParameter(VERSION_KEY), consumerURL.getParameter(GROUP_KEY), CONSUMER_SIDE, + consumerURL.getParameter(APPLICATION_KEY)), consumerURL.getParameters()); } - private void publishProvider(URL providerUrl) throws RpcException { - //first add into the list - // remove the individual param - providerUrl = providerUrl.removeParameters(PID_KEY, TIMESTAMP_KEY, Constants.BIND_IP_KEY, - Constants.BIND_PORT_KEY, TIMESTAMP_KEY); - + @Override + protected void publishProviderServiceDefinition(URL providerURL) { try { - String interfaceName = providerUrl.getParameter(INTERFACE_KEY); + String interfaceName = providerURL.getParameter(INTERFACE_KEY); if (StringUtils.isNotEmpty(interfaceName)) { Class interfaceClass = Class.forName(interfaceName); FullServiceDefinition fullServiceDefinition = ServiceDefinitionBuilder.buildFullDefinition(interfaceClass, - providerUrl.getParameters()); - getMetadataReport().storeProviderMetadata(new MetadataIdentifier(providerUrl.getServiceInterface(), - providerUrl.getParameter(VERSION_KEY), providerUrl.getParameter(GROUP_KEY), - PROVIDER_SIDE, providerUrl.getParameter(APPLICATION_KEY)), fullServiceDefinition); + providerURL.getParameters()); + getMetadataReport().storeProviderMetadata(new MetadataIdentifier(providerURL.getServiceInterface(), + providerURL.getParameter(VERSION_KEY), providerURL.getParameter(GROUP_KEY), + PROVIDER_SIDE, providerURL.getParameter(APPLICATION_KEY)), fullServiceDefinition); return; } - logger.error("publishProvider interfaceName is empty . providerUrl: " + providerUrl.toFullString()); - } catch (Throwable t) { + logger.error("publishProvider interfaceName is empty . url: " + providerURL.toFullString()); + } catch (ClassNotFoundException e) { //ignore error - logger.error("publishProvider getServiceDescriptor error. providerUrl: " + providerUrl.toFullString(), t.getCause()); + logger.error("publishProvider getServiceDescriptor error. url: " + providerURL.toFullString(), e); } } - private void publishConsumer(URL consumerURL) throws RpcException { - consumerURL = consumerURL.removeParameters(PID_KEY, TIMESTAMP_KEY, Constants.BIND_IP_KEY, - Constants.BIND_PORT_KEY, TIMESTAMP_KEY); - getMetadataReport().storeConsumerMetadata(new MetadataIdentifier(consumerURL.getServiceInterface(), - consumerURL.getParameter(VERSION_KEY), consumerURL.getParameter(GROUP_KEY), CONSUMER_SIDE, - consumerURL.getParameter(APPLICATION_KEY)), consumerURL.getParameters()); - } - @Override public boolean exportURL(URL url) { - // do nothing for one single url export, the actual report will be done in callback (refreshMetadata) after all urls are exported. - return true; + return writableMetadataServiceDelegate.exportURL(url); } @Override public boolean unexportURL(URL url) { - ServiceMetadataIdentifier metadataIdentifier = new ServiceMetadataIdentifier(url); - metadataIdentifier.setRevision(exportedRevision); - metadataIdentifier.setProtocol(url.getProtocol()); - return throwableAction(getMetadataReport()::removeServiceMetadata, metadataIdentifier); + return writableMetadataServiceDelegate.unexportURL(url); } @Override public boolean subscribeURL(URL url) { - // do nothing for one single url export, the actual report will be done in callback (refreshMetadata) after all urls are exported. - return true; + return writableMetadataServiceDelegate.subscribeURL(url); } @Override public boolean unsubscribeURL(URL url) { - // do nothing for one single url export, the actual report will be done in callback (refreshMetadata) after all urls are exported. - return true; + return writableMetadataServiceDelegate.unsubscribeURL(url); } - @Override - public boolean refreshMetadata(String exportedRevision, String subscribedRevision) { - boolean result = true; - if (!StringUtils.isEmpty(exportedRevision) && !exportedRevision.equals(this.exportedRevision)) { - this.exportedRevision = exportedRevision; - boolean executeResult = saveServiceMetadata(); - if (!executeResult) { - result = false; - } - } - if (!StringUtils.isEmpty(subscribedRevision) && !subscribedRevision.equals(this.subscribedRevision) - && CollectionUtils.isNotEmpty(writableMetadataService.getSubscribedURLs())) { - this.subscribedRevision = subscribedRevision; - SubscriberMetadataIdentifier metadataIdentifier = new SubscriberMetadataIdentifier(); - metadataIdentifier.setApplication(serviceName()); - metadataIdentifier.setRevision(subscribedRevision); - boolean executeResult = throwableAction(getMetadataReport()::saveSubscribedData, metadataIdentifier, - writableMetadataService.getSubscribedURLs()); - if (!executeResult) { - result = false; - } - } - return result; - } - - private boolean saveServiceMetadata() { - boolean result = true; - for (SortedSet urls : writableMetadataService.exportedServiceURLs.values()) { - Iterator iterator = urls.iterator(); - while (iterator.hasNext()) { - URL url = iterator.next(); - // refresh revision in urls - ServiceMetadataIdentifier metadataIdentifier = new ServiceMetadataIdentifier(url); - metadataIdentifier.setRevision(exportedRevision); - metadataIdentifier.setProtocol(url.getProtocol()); - - boolean tmpResult = throwableAction(getMetadataReport()::saveServiceMetadata, metadataIdentifier, url); - if (!tmpResult) result = tmpResult; - } - } - return result; - } - - @Override public SortedSet getExportedURLs(String serviceInterface, String group, String version, String protocol) { - return null; - } - - @Override - public String getServiceDefinition(String interfaceName, String version, String group) { - return null; + return writableMetadataServiceDelegate.getExportedURLs(serviceInterface, group, version, protocol); } @Override public String getServiceDefinition(String serviceKey) { - return null; - } - - boolean throwableAction(BiConsumer consumer, - ServiceMetadataIdentifier metadataIdentifier, URL url) { - try { - consumer.accept(metadataIdentifier, url); - } catch (Exception e) { - logger.error("Failed to execute consumer, url is: " + url); - return false; - } - return true; + return writableMetadataServiceDelegate.getServiceDefinition(serviceKey); } - boolean throwableAction(BiConsumer> consumer, - SubscriberMetadataIdentifier metadataIdentifier, Set urls) { - try { - consumer.accept(metadataIdentifier, urls); - } catch (Exception e) { - logger.error("Failed to execute consumer, url is: " + urls); - return false; - } - return true; + @Override + public SortedSet getSubscribedURLs() { + return writableMetadataServiceDelegate.getSubscribedURLs(); } - boolean throwableAction(Consumer consumer, ServiceMetadataIdentifier metadataIdentifier) { - try { - consumer.accept(metadataIdentifier); - } catch (Exception e) { - logger.error("Failed to remove url metadata to remote center, metadataIdentifier is: " + metadataIdentifier); - return false; - } - return true; - } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegate.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegate.java deleted file mode 100644 index 132a0cbe034..00000000000 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegate.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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; - -import org.apache.dubbo.common.URL; -import org.apache.dubbo.metadata.WritableMetadataService; - -import java.util.SortedSet; -import java.util.function.BiFunction; - -/** - * 2019-08-14 - * - * @since 2.7.5 - */ -public class RemoteWritableMetadataServiceDelegate implements WritableMetadataService { - InMemoryWritableMetadataService defaultWritableMetadataService; - RemoteWritableMetadataService remoteWritableMetadataService; - - public RemoteWritableMetadataServiceDelegate() { - defaultWritableMetadataService = (InMemoryWritableMetadataService) WritableMetadataService.getExtension("local"); - remoteWritableMetadataService = new RemoteWritableMetadataService(defaultWritableMetadataService); - } - - private WritableMetadataService getDefaultWritableMetadataService() { - return defaultWritableMetadataService; - } - - @Override - public boolean exportURL(URL url) { - return doFunction(WritableMetadataService::exportURL, url); - } - - @Override - public boolean unexportURL(URL url) { - return doFunction(WritableMetadataService::unexportURL, url); - } - - @Override - public boolean subscribeURL(URL url) { - return doFunction(WritableMetadataService::subscribeURL, url); - } - - @Override - public boolean unsubscribeURL(URL url) { - return doFunction(WritableMetadataService::unsubscribeURL, url); - } - - @Override - public boolean refreshMetadata(String exportedRevision, String subscribedRevision) { - boolean result = true; - result &= defaultWritableMetadataService.refreshMetadata(exportedRevision, subscribedRevision); - result &= remoteWritableMetadataService.refreshMetadata(exportedRevision, subscribedRevision); - return result; - } - - @Override - public void publishServiceDefinition(URL providerUrl) { - defaultWritableMetadataService.publishServiceDefinition(providerUrl); - remoteWritableMetadataService.publishServiceDefinition(providerUrl); - } - - @Override - public SortedSet getExportedURLs(String serviceInterface, String group, String version, String protocol) { - return getDefaultWritableMetadataService().getExportedURLs(serviceInterface, group, version, protocol); - } - - @Override - public SortedSet getSubscribedURLs() { - return getDefaultWritableMetadataService().getSubscribedURLs(); - } - - @Override - public String getServiceDefinition(String interfaceName, String version, String group) { - return getDefaultWritableMetadataService().getServiceDefinition(interfaceName, version, group); - } - - @Override - public String getServiceDefinition(String serviceKey) { - return getDefaultWritableMetadataService().getServiceDefinition(serviceKey); - } - - private boolean doFunction(BiFunction func, URL url) { - return func.apply(defaultWritableMetadataService, url) && func.apply(remoteWritableMetadataService, url); - } -} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping index 3975068fc93..beadd2eb479 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping +++ b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping @@ -1 +1,9 @@ -default=org.apache.dubbo.metadata.DynamicConfigurationServiceNameMapping \ No newline at end of file +# "default" implementation has been changed since 2.7.8 +default=org.apache.dubbo.metadata.CompositeServiceNameMapping + +# "properties-file" and "parameterized" are introduced since 2.7.8 +properties-file = org.apache.dubbo.metadata.PropertiesFileServiceNameMapping +parameterized = org.apache.dubbo.metadata.ParameterizedServiceNameMapping + +# "dynamic-configuration" has been revised since 2.7.8 +dynamic-configuration = org.apache.dubbo.metadata.DynamicConfigurationServiceNameMapping \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.WritableMetadataService b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.WritableMetadataService index bfe794bf963..26bc942e704 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.WritableMetadataService +++ b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.WritableMetadataService @@ -1,2 +1,2 @@ local=org.apache.dubbo.metadata.store.InMemoryWritableMetadataService -remote=org.apache.dubbo.metadata.store.RemoteWritableMetadataServiceDelegate \ No newline at end of file +remote=org.apache.dubbo.metadata.store.RemoteWritableMetadataService \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory new file mode 100644 index 00000000000..b686fced440 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory @@ -0,0 +1 @@ +file = org.apache.dubbo.metadata.report.support.file.FileSystemMetadataReportFactory \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/CompositeServiceNameMappingTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/CompositeServiceNameMappingTest.java new file mode 100644 index 00000000000..48243f8c49e --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/CompositeServiceNameMappingTest.java @@ -0,0 +1,107 @@ +/* + * 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; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfiguration; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.service.EchoService; + +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static java.util.Collections.singleton; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY; +import static org.apache.dubbo.common.utils.CollectionUtils.ofSet; +import static org.apache.dubbo.metadata.DynamicConfigurationServiceNameMapping.buildGroup; +import static org.apache.dubbo.rpc.model.ApplicationModel.getApplicationConfig; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * {@link CompositeServiceNameMapping} Test + * + * @since 2.7.8 + */ +public class CompositeServiceNameMappingTest { + + private static final URL BASE_URL = URL.valueOf("dubbo://127.0.0.1:20880") + .setPath(EchoService.class.getName()) + .addParameter(GROUP_KEY, "default") + .addParameter(VERSION_KEY, "1.0.0"); + + private static final String APP_NAME = "test-service"; + + private ServiceNameMapping serviceNameMapping; + + private FileSystemDynamicConfiguration dynamicConfiguration; + + @BeforeEach + public void init() { + serviceNameMapping = ServiceNameMapping.getDefaultExtension(); + dynamicConfiguration = new FileSystemDynamicConfiguration(); + ApplicationModel.getConfigManager().setApplication(new ApplicationConfig(APP_NAME)); + ApplicationModel.getEnvironment().setDynamicConfiguration(dynamicConfiguration); + } + + @AfterEach + public void reset() { + FileUtils.deleteQuietly(dynamicConfiguration.getRootDirectory()); + ApplicationModel.reset(); + } + + @Test + public void testType() { + assertEquals(CompositeServiceNameMapping.class, serviceNameMapping.getClass()); + } + + @Test + public void testMap() { + serviceNameMapping.map(BASE_URL); + assertNotNull(dynamicConfiguration.getConfig(APP_NAME, + buildGroup(BASE_URL.getServiceInterface(), null, null, null))); + } + + @Test + public void testGet() { + serviceNameMapping.map(BASE_URL); + Set serviceNames = serviceNameMapping.get(BASE_URL); + assertEquals(singleton(APP_NAME), serviceNames); + + getApplicationConfig().setName("service1"); + serviceNameMapping.map(BASE_URL); + serviceNames = serviceNameMapping.get(BASE_URL); + assertEquals(ofSet(APP_NAME, "service1"), serviceNames); + + serviceNames = serviceNameMapping.get(BASE_URL + .setPath("com.acme.Interface1") + .removeParameter(VERSION_KEY) + ); + assertEquals(singleton("Service1"), serviceNames); + + serviceNames = serviceNameMapping.get(BASE_URL.addParameter(SUBSCRIBED_SERVICE_NAMES_KEY, "s1 , s2 , s3 ")); + assertEquals(ofSet("s1", "s2", "s3"), serviceNames); + } +} + diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMappingTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMappingTest.java index 0e677dfa096..d4d25ee85c5 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMappingTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMappingTest.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.metadata; +import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; import org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory; import org.apache.dubbo.config.ApplicationConfig; @@ -28,10 +29,13 @@ import java.util.TreeSet; import static java.util.Arrays.asList; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; import static org.apache.dubbo.metadata.DynamicConfigurationServiceNameMapping.buildGroup; import static org.apache.dubbo.metadata.ServiceNameMapping.getDefaultExtension; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * {@link DynamicConfigurationServiceNameMapping} Test @@ -61,6 +65,17 @@ public void testBuildGroup() { assertEquals("mapping/test", buildGroup("test", "default", "1.0.0", "dubbo")); } + @Test + public void testAndGetOnFailed() { + assertThrows(UnsupportedOperationException.class, () -> { + serviceNameMapping.map(null, null, null, null); + }); + + assertThrows(UnsupportedOperationException.class, () -> { + serviceNameMapping.get(null, null, null, null); + }); + } + @Test public void testMapAndGet() { @@ -74,14 +89,18 @@ public void testMapAndGet() { String version = null; String protocol = null; - serviceNameMapping.map(serviceInterface, group, version, protocol); + URL url = URL.valueOf("dubbo://127.0.0.1:20880").setServiceInterface(serviceInterface) + .addParameter(GROUP_KEY, group) + .addParameter(VERSION_KEY, version); + + serviceNameMapping.map(url); ApplicationModel.getConfigManager().removeConfig(new ApplicationConfig(serviceName)); ApplicationModel.getConfigManager().setApplication(new ApplicationConfig(serviceName2)); - serviceNameMapping.map(serviceInterface, group, version, protocol); + serviceNameMapping.map(url); - Set serviceNames = serviceNameMapping.get(serviceInterface, group, version, protocol); + Set serviceNames = serviceNameMapping.get(url); assertEquals(new TreeSet(asList(serviceName, serviceName2)), serviceNames); diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/InMemoryWritableMetadataServiceTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/InMemoryWritableMetadataServiceTest.java index 461cf28149b..187f12612dd 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/InMemoryWritableMetadataServiceTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/InMemoryWritableMetadataServiceTest.java @@ -17,10 +17,12 @@ package org.apache.dubbo.metadata; import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.metadata.store.InMemoryWritableMetadataService; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.Set; @@ -54,9 +56,15 @@ public class InMemoryWritableMetadataServiceTest { private static final URL BASE_URL_GROUP_AND_VERSION = BASE_URL_GROUP.addParameter(VERSION_KEY, "1.0.0"); private static final URL BASE_URL_GROUP_AND_VERSION_AND_PROTOCOL = BASE_URL_GROUP_AND_VERSION.addParameter(PROTOCOL_KEY, "rest"); - @BeforeAll - public static void init() { - ApplicationModel.setApplication("test"); + @BeforeEach + public void init() { + ApplicationConfig applicationConfig = new ApplicationConfig("test"); + ApplicationModel.getConfigManager().setApplication(applicationConfig); + } + + @AfterEach + public void reset() { + ApplicationModel.reset(); } @Test diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/MetadataConstantsTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/MetadataConstantsTest.java new file mode 100644 index 00000000000..d0c201b0d7c --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/MetadataConstantsTest.java @@ -0,0 +1,35 @@ +/* + * 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; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link MetadataConstants} Test-Cases + * + * @since 2.7.8 + */ +public class MetadataConstantsTest { + + @Test + public void testConstants() { + assertEquals("exported-urls", MetadataConstants.EXPORTED_URLS_TAG); + assertEquals("subscribed-urls", MetadataConstants.SUBSCRIBED_URLS_TAG); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/MetadataServiceTypeTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/MetadataServiceTypeTest.java new file mode 100644 index 00000000000..11eec1dff4b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/MetadataServiceTypeTest.java @@ -0,0 +1,48 @@ +/* + * 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; + +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.metadata.MetadataServiceType.COMPOSITE; +import static org.apache.dubbo.metadata.MetadataServiceType.DEFAULT; +import static org.apache.dubbo.metadata.MetadataServiceType.REMOTE; +import static org.apache.dubbo.metadata.MetadataServiceType.getOrDefault; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link MetadataServiceType} Test-Cases + * + * @since 2.7.8 + */ +public class MetadataServiceTypeTest { + + @Test + public void testGetValue() { + assertEquals("local", DEFAULT.getValue()); + assertEquals("remote", REMOTE.getValue()); + assertEquals("composite", COMPOSITE.getValue()); + } + + @Test + public void testGetOrDefault() { + assertEquals(DEFAULT, getOrDefault("local")); + assertEquals(REMOTE, getOrDefault("remote")); + assertEquals(COMPOSITE, getOrDefault("composite")); + assertEquals(DEFAULT, getOrDefault("others")); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/ParameterizedServiceNameMappingTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/ParameterizedServiceNameMappingTest.java new file mode 100644 index 00000000000..dbe54540726 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/ParameterizedServiceNameMappingTest.java @@ -0,0 +1,67 @@ +/* + * 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; + +import org.apache.dubbo.common.URL; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; + +import static java.util.Collections.emptySet; +import static java.util.Collections.singleton; +import static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link ParameterizedServiceNameMapping} Test + * + * @see ParameterizedServiceNameMapping + * @since 2.7.8 + */ +public class ParameterizedServiceNameMappingTest { + + private static final URL BASE_URL = URL.valueOf("dubbo://127.0.0.1:20880"); + + private ParameterizedServiceNameMapping serviceNameMapping; + + @BeforeEach + public void init() { + serviceNameMapping = new ParameterizedServiceNameMapping(); + } + + @Test + public void testMap() { + // NOTHING to happen + serviceNameMapping.map(BASE_URL); + } + + @Test + public void testGet() { + Set serviceNames = serviceNameMapping.get(BASE_URL); + assertEquals(emptySet(), serviceNames); + + serviceNames = serviceNameMapping.get(BASE_URL.addParameter(SUBSCRIBED_SERVICE_NAMES_KEY, " Service1 ")); + assertEquals(singleton("Service1"), serviceNames); + + serviceNames = serviceNameMapping.get(BASE_URL.addParameter(SUBSCRIBED_SERVICE_NAMES_KEY, "Service1 , Service2 ")); + assertEquals(new LinkedHashSet(Arrays.asList("Service1", "Service2")), serviceNames); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/PropertiesFileServiceNameMappingTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/PropertiesFileServiceNameMappingTest.java new file mode 100644 index 00000000000..68a6ebfcf84 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/PropertiesFileServiceNameMappingTest.java @@ -0,0 +1,60 @@ +/* + * 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; + +import org.apache.dubbo.common.URL; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.LinkedHashSet; + +import static java.util.Collections.singleton; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link PropertiesFileServiceNameMapping} Test + * + * @since 2.7.8 + */ +public class PropertiesFileServiceNameMappingTest { + + private static final URL BASE_URL = URL.valueOf("dubbo://127.0.0.1:20880"); + + + @Test + public void testMap() { + PropertiesFileServiceNameMapping serviceNameMapping = new PropertiesFileServiceNameMapping(); + serviceNameMapping.map(BASE_URL); + } + + @Test + public void testGet() { + + PropertiesFileServiceNameMapping serviceNameMapping = new PropertiesFileServiceNameMapping(); + URL url = BASE_URL.setServiceInterface("com.acme.Interface1").addParameter(GROUP_KEY, "default"); + assertEquals(singleton("Service1"), serviceNameMapping.get(url)); + + System.setProperty(SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY, "///META-INF//dubbo/service-name-mapping.properties"); + serviceNameMapping = new PropertiesFileServiceNameMapping(); + + url = BASE_URL.setProtocol("thirft").setServiceInterface("com.acme.InterfaceX"); + assertEquals(new LinkedHashSet<>(Arrays.asList("Service1", "Service2")), serviceNameMapping.get(url)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/ServiceNameMappingTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/ServiceNameMappingTest.java new file mode 100644 index 00000000000..8c379983d6b --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/ServiceNameMappingTest.java @@ -0,0 +1,121 @@ +/* + * 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; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfiguration; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.LinkedHashSet; +import java.util.Set; + +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY; +import static org.apache.dubbo.metadata.DynamicConfigurationServiceNameMapping.buildGroup; +import static org.apache.dubbo.metadata.ServiceNameMapping.getDefaultExtension; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * {@link ServiceNameMapping} Test + * + * @since 2.7.8 + */ +public class ServiceNameMappingTest { + + private static final URL BASE_URL = URL.valueOf("dubbo://127.0.0.1:20880"); + + private FileSystemDynamicConfiguration configuration; + + private ServiceNameMapping serviceNameMapping; + + private String applicationName; + + @BeforeEach + public void init() { + + ApplicationModel.reset(); + + applicationName = getClass().getSimpleName(); + + ApplicationModel.getConfigManager().setApplication(new ApplicationConfig(applicationName)); + + configuration = new FileSystemDynamicConfiguration(); + + FileUtils.deleteQuietly(configuration.getRootDirectory()); + + ApplicationModel.getEnvironment().setDynamicConfiguration(configuration); + + serviceNameMapping = getDefaultExtension(); + } + + @AfterEach + public void reset() throws Exception { + FileUtils.deleteQuietly(configuration.getRootDirectory()); + configuration.close(); + ApplicationModel.reset(); + } + + @Test + public void testDeprecatedMethods() { + assertThrows(UnsupportedOperationException.class, () -> { + serviceNameMapping.map(null, null, null, null); + }); + + assertThrows(UnsupportedOperationException.class, () -> { + serviceNameMapping.get(null, null, null, null); + }); + } + + @Test + public void testMap() { + String serviceInterface = ServiceNameMapping.class.getName(); + String key = applicationName; + String group = buildGroup(serviceInterface, null, null, null); + URL url = BASE_URL.setServiceInterface(serviceInterface); + serviceNameMapping.map(url); + assertNotNull(configuration.getConfig(key, group)); + } + + @Test + public void testGet() { + String serviceInterface = ServiceNameMapping.class.getName(); + URL url = BASE_URL.setServiceInterface(serviceInterface); + serviceNameMapping.map(url); + Set serviceNames = serviceNameMapping.get(url); + assertEquals(singleton(applicationName), serviceNames); + + url = url.setServiceInterface("com.acme.Interface1").addParameter(GROUP_KEY, "default"); + serviceNames = serviceNameMapping.get(url); + assertEquals(singleton("Service1"), serviceNames); + + + url = url.addParameter(SUBSCRIBED_SERVICE_NAMES_KEY, "A , B , C "); + serviceNames = serviceNameMapping.get(url); + assertEquals(new LinkedHashSet<>(asList("A", "B", "C")), serviceNames); + + } +} diff --git a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/URLRevisionResolverTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/URLRevisionResolverTest.java similarity index 67% rename from dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/URLRevisionResolverTest.java rename to dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/URLRevisionResolverTest.java index 3386bba0e84..b36ebcb480a 100644 --- a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/URLRevisionResolverTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/URLRevisionResolverTest.java @@ -14,12 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.registry.client.metadata; +package org.apache.dubbo.metadata; import org.junit.jupiter.api.Test; +import java.util.Arrays; +import java.util.Collection; + import static java.util.Arrays.asList; -import static org.apache.dubbo.registry.client.metadata.URLRevisionResolver.NO_REVISION; +import static org.apache.dubbo.metadata.URLRevisionResolver.UNKNOWN_REVISION; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -29,19 +32,19 @@ */ public class URLRevisionResolverTest { - private static final String URL = "dubbo://192.168.0.102:20881/org.apache.dubbo.registry.client.metadata.URLRevisionResolverTest"; + private static final String URL = "dubbo://192.168.0.102:20881/org.apache.dubbo.metadata.URLRevisionResolverTest"; - private final URLRevisionResolver resolver = new URLRevisionResolver(); + private final URLRevisionResolver resolver = URLRevisionResolver.INSTANCE; @Test public void testResolve() { - String revision = resolver.resolve(asList()); - assertEquals(NO_REVISION, revision); + String revision = resolver.resolve(Arrays.asList()); + assertEquals(UNKNOWN_REVISION, revision); - revision = resolver.resolve(null); - assertEquals(NO_REVISION, revision); + revision = resolver.resolve((Collection) null); + assertEquals(UNKNOWN_REVISION, revision); revision = resolver.resolve(asList(URL)); - assertEquals("7960327984321481979", revision); + assertEquals("2ca0638f189ce569", revision); } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/KeyTypeEnumTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/KeyTypeEnumTest.java new file mode 100644 index 00000000000..c4dae1f9190 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/KeyTypeEnumTest.java @@ -0,0 +1,38 @@ +/* + * 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.report.identifier; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link KeyTypeEnum} Test-Cases + * + * @since 2.7.8 + */ +public class KeyTypeEnumTest { + + /** + * {@link KeyTypeEnum#build(String, String...)} + */ + @Test + public void testBuild() { + assertEquals("/A/B/C", KeyTypeEnum.PATH.build("/A", "/B", "C")); + assertEquals("A:B:C", KeyTypeEnum.UNIQUE_KEY.build("A", "B", "C")); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReportFactoryTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReportFactoryTest.java index 30d4ad1a300..3aa5c029d20 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReportFactoryTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReportFactoryTest.java @@ -28,9 +28,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** @@ -65,7 +65,7 @@ public List getExportedURLs(ServiceMetadataIdentifier metadataIdentifier @Override public void saveSubscribedData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, - Set urls) { + Collection urls) { } @@ -84,6 +84,11 @@ public void storeConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, store.put(consumerMetadataIdentifier.getIdentifierKey(), JSON.toJSONString(serviceParameterMap)); } + @Override + public void close() throws Exception { + + } + Map store = new ConcurrentHashMap<>(); diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReportTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReportTest.java index 9d4267f7e3d..c5325a1fa30 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReportTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReportTest.java @@ -18,14 +18,18 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder; import org.apache.dubbo.metadata.definition.model.FullServiceDefinition; +import org.apache.dubbo.metadata.report.MetadataReport; import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; +import org.apache.dubbo.rpc.model.ApplicationModel; import com.google.gson.Gson; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -35,10 +39,15 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.SortedSet; import java.util.concurrent.ConcurrentHashMap; +import static java.util.Collections.emptySet; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @@ -52,17 +61,25 @@ public class AbstractMetadataReportTest { public void before() { URL url = URL.valueOf("zookeeper://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic"); abstractMetadataReport = new NewMetadataReport(url); + // set the simple name of current class as the application name + ApplicationModel.getConfigManager().setApplication(new ApplicationConfig(getClass().getSimpleName())); + } + + @AfterEach + public void reset() { + // reset + ApplicationModel.reset(); } @Test public void testGetProtocol() { URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic&side=provider"); String protocol = abstractMetadataReport.getProtocol(url); - Assertions.assertEquals(protocol, "provider"); + assertEquals(protocol, "provider"); URL url2 = URL.valueOf("consumer://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic"); String protocol2 = abstractMetadataReport.getProtocol(url2); - Assertions.assertEquals(protocol2, "consumer"); + assertEquals(protocol2, "consumer"); } @Test @@ -93,7 +110,7 @@ public void testFileExistAfterPut() throws InterruptedException, ClassNotFoundEx URL singleUrl = URL.valueOf("redis://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.metadata.store.InterfaceNameTestService?version=1.0.0&application=singleTest"); NewMetadataReport singleMetadataReport = new NewMetadataReport(singleUrl); - Assertions.assertFalse(singleMetadataReport.file.exists()); + Assertions.assertFalse(singleMetadataReport.localCacheFile.exists()); String interfaceName = "org.apache.dubbo.metadata.store.InterfaceNameTestService"; String version = "1.0.0"; @@ -102,8 +119,8 @@ public void testFileExistAfterPut() throws InterruptedException, ClassNotFoundEx MetadataIdentifier providerMetadataIdentifier = storePrivider(singleMetadataReport, interfaceName, version, group, application); Thread.sleep(2000); - Assertions.assertTrue(singleMetadataReport.file.exists()); - Assertions.assertTrue(singleMetadataReport.properties.containsKey(providerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY))); + assertTrue(singleMetadataReport.localCacheFile.exists()); + assertTrue(singleMetadataReport.properties.containsKey(providerMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY))); } @Test @@ -117,22 +134,22 @@ public void testRetry() throws InterruptedException, ClassNotFoundException { retryReport.metadataReportRetry.retryPeriod = 400L; URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic"); Assertions.assertNull(retryReport.metadataReportRetry.retryScheduledFuture); - Assertions.assertEquals(0, retryReport.metadataReportRetry.retryCounter.get()); - Assertions.assertTrue(retryReport.store.isEmpty()); - Assertions.assertTrue(retryReport.failedReports.isEmpty()); + assertEquals(0, retryReport.metadataReportRetry.retryCounter.get()); + assertTrue(retryReport.store.isEmpty()); + assertTrue(retryReport.failedReports.isEmpty()); storePrivider(retryReport, interfaceName, version, group, application); Thread.sleep(150); - Assertions.assertTrue(retryReport.store.isEmpty()); + assertTrue(retryReport.store.isEmpty()); Assertions.assertFalse(retryReport.failedReports.isEmpty()); Assertions.assertNotNull(retryReport.metadataReportRetry.retryScheduledFuture); Thread.sleep(2000L); - Assertions.assertTrue(retryReport.metadataReportRetry.retryCounter.get() != 0); - Assertions.assertTrue(retryReport.metadataReportRetry.retryCounter.get() >= 3); + assertTrue(retryReport.metadataReportRetry.retryCounter.get() != 0); + assertTrue(retryReport.metadataReportRetry.retryCounter.get() >= 3); Assertions.assertFalse(retryReport.store.isEmpty()); - Assertions.assertTrue(retryReport.failedReports.isEmpty()); + assertTrue(retryReport.failedReports.isEmpty()); } @Test @@ -152,8 +169,8 @@ public void testRetryCancel() throws InterruptedException, ClassNotFoundExceptio Assertions.assertFalse(retryReport.metadataReportRetry.retryScheduledFuture.isCancelled()); Assertions.assertFalse(retryReport.metadataReportRetry.retryExecutor.isShutdown()); Thread.sleep(1000L); - Assertions.assertTrue(retryReport.metadataReportRetry.retryScheduledFuture.isCancelled()); - Assertions.assertTrue(retryReport.metadataReportRetry.retryExecutor.isShutdown()); + assertTrue(retryReport.metadataReportRetry.retryScheduledFuture.isCancelled()); + assertTrue(retryReport.metadataReportRetry.retryExecutor.isShutdown()); } @@ -185,42 +202,42 @@ private MetadataIdentifier storeConsumer(AbstractMetadataReport abstractMetadata @Test public void testPublishAll() throws ClassNotFoundException, InterruptedException { - Assertions.assertTrue(abstractMetadataReport.store.isEmpty()); - Assertions.assertTrue(abstractMetadataReport.allMetadataReports.isEmpty()); + assertTrue(abstractMetadataReport.store.isEmpty()); + assertTrue(abstractMetadataReport.allMetadataReports.isEmpty()); String interfaceName = "org.apache.dubbo.metadata.store.InterfaceNameTestService"; String version = "1.0.0"; String group = null; String application = "vic"; MetadataIdentifier providerMetadataIdentifier1 = storePrivider(abstractMetadataReport, interfaceName, version, group, application); Thread.sleep(1000); - Assertions.assertEquals(abstractMetadataReport.allMetadataReports.size(), 1); - Assertions.assertTrue(((FullServiceDefinition) abstractMetadataReport.allMetadataReports.get(providerMetadataIdentifier1)).getParameters().containsKey("testPKey")); + assertEquals(abstractMetadataReport.allMetadataReports.size(), 1); + assertTrue(((FullServiceDefinition) abstractMetadataReport.allMetadataReports.get(providerMetadataIdentifier1)).getParameters().containsKey("testPKey")); MetadataIdentifier providerMetadataIdentifier2 = storePrivider(abstractMetadataReport, interfaceName, version + "_2", group + "_2", application); Thread.sleep(1000); - Assertions.assertEquals(abstractMetadataReport.allMetadataReports.size(), 2); - Assertions.assertTrue(((FullServiceDefinition) abstractMetadataReport.allMetadataReports.get(providerMetadataIdentifier2)).getParameters().containsKey("testPKey")); - Assertions.assertEquals(((FullServiceDefinition) abstractMetadataReport.allMetadataReports.get(providerMetadataIdentifier2)).getParameters().get("version"), version + "_2"); + assertEquals(abstractMetadataReport.allMetadataReports.size(), 2); + assertTrue(((FullServiceDefinition) abstractMetadataReport.allMetadataReports.get(providerMetadataIdentifier2)).getParameters().containsKey("testPKey")); + assertEquals(((FullServiceDefinition) abstractMetadataReport.allMetadataReports.get(providerMetadataIdentifier2)).getParameters().get("version"), version + "_2"); Map tmpMap = new HashMap<>(); tmpMap.put("testKey", "value"); MetadataIdentifier consumerMetadataIdentifier = storeConsumer(abstractMetadataReport, interfaceName, version + "_3", group + "_3", application, tmpMap); Thread.sleep(1000); - Assertions.assertEquals(abstractMetadataReport.allMetadataReports.size(), 3); + assertEquals(abstractMetadataReport.allMetadataReports.size(), 3); Map tmpMapResult = (Map) abstractMetadataReport.allMetadataReports.get(consumerMetadataIdentifier); - Assertions.assertEquals(tmpMapResult.get("testPKey"), "9090"); - Assertions.assertEquals(tmpMapResult.get("testKey"), "value"); - Assertions.assertEquals(3, abstractMetadataReport.store.size()); + assertEquals(tmpMapResult.get("testPKey"), "9090"); + assertEquals(tmpMapResult.get("testKey"), "value"); + assertEquals(3, abstractMetadataReport.store.size()); abstractMetadataReport.store.clear(); - Assertions.assertEquals(0, abstractMetadataReport.store.size()); + assertEquals(0, abstractMetadataReport.store.size()); abstractMetadataReport.publishAll(); Thread.sleep(200); - Assertions.assertEquals(3, abstractMetadataReport.store.size()); + assertEquals(3, abstractMetadataReport.store.size()); String v = abstractMetadataReport.store.get(providerMetadataIdentifier1.getUniqueKey(KeyTypeEnum.UNIQUE_KEY)); Gson gson = new Gson(); @@ -244,11 +261,53 @@ public void testCalculateStartTime() { long t = abstractMetadataReport.calculateStartTime() + System.currentTimeMillis(); Calendar c = Calendar.getInstance(); c.setTimeInMillis(t); - Assertions.assertTrue(c.get(Calendar.HOUR_OF_DAY) >= 2); - Assertions.assertTrue(c.get(Calendar.HOUR_OF_DAY) <= 6); + assertTrue(c.get(Calendar.HOUR_OF_DAY) >= 2); + assertTrue(c.get(Calendar.HOUR_OF_DAY) <= 6); } } + /** + * Test {@link MetadataReport#saveExportedURLs(String, String, String)} method + * + * @since 2.7.8 + */ + @Test + public void testSaveExportedURLs() { + String serviceName = null; + String exportedServiceRevision = null; + String exportedURLsContent = null; + SortedSet exportedURLs = null; + // Default methods return true + assertTrue(abstractMetadataReport.saveExportedURLs(exportedURLs)); + assertTrue(abstractMetadataReport.saveExportedURLs(exportedServiceRevision, exportedURLs)); + assertTrue(abstractMetadataReport.saveExportedURLs(serviceName, exportedServiceRevision, exportedURLs)); + assertTrue(abstractMetadataReport.saveExportedURLs(serviceName, exportedServiceRevision, exportedURLsContent)); + } + + /** + * Test {@link MetadataReport#getExportedURLs(String, String)} method + * + * @since 2.7.8 + */ + @Test + public void testGetExportedURLs() { + String serviceName = null; + String exportedServiceRevision = null; + assertEquals(emptySet(), abstractMetadataReport.getExportedURLs(serviceName, exportedServiceRevision)); + } + + /** + * Test {@link MetadataReport#getExportedURLsContent(String, String)} method + * + * @since 2.7.8 + */ + @Test + public void testGetExportedURLsContent() { + String serviceName = null; + String exportedServiceRevision = null; + assertNull(abstractMetadataReport.getExportedURLsContent(serviceName, exportedServiceRevision)); + } + private FullServiceDefinition toServiceDefinition(String v) { Gson gson = new Gson(); FullServiceDefinition data = gson.fromJson(v, FullServiceDefinition.class); @@ -256,8 +315,8 @@ private FullServiceDefinition toServiceDefinition(String v) { } private void checkParam(Map map, String application, String version) { - Assertions.assertEquals(map.get("application"), application); - Assertions.assertEquals(map.get("version"), version); + assertEquals(map.get("application"), application); + assertEquals(map.get("version"), version); } private Map queryUrlToMap(String urlQuery) { diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/ConfigCenterBasedMetadataReportTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/ConfigCenterBasedMetadataReportTest.java new file mode 100644 index 00000000000..32205b9a1fd --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/support/ConfigCenterBasedMetadataReportTest.java @@ -0,0 +1,155 @@ +/* + * 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.report.support; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.metadata.URLRevisionResolver; +import org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder; +import org.apache.dubbo.metadata.definition.model.ServiceDefinition; +import org.apache.dubbo.metadata.report.MetadataReport; +import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; +import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; +import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; +import org.apache.dubbo.metadata.report.support.file.FileSystemMetadataReportFactory; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.service.EchoService; + +import com.google.gson.Gson; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import static java.util.Collections.singleton; +import static java.util.stream.Collectors.toSet; +import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; +import static org.apache.dubbo.metadata.report.support.Constants.SYNC_REPORT_KEY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * {@link ConfigCenterBasedMetadataReport} Test-Cases + * + * @since 2.7.8 + */ +public class ConfigCenterBasedMetadataReportTest { + + private static final URL REPORT_SERVER_URL = URL.valueOf("file://") + .addParameter(APPLICATION_KEY, "test") + .addParameter(SYNC_REPORT_KEY, "true"); + + private static final Class INTERFACE_CLASS = EchoService.class; + + private static final String INTERFACE_NAME = INTERFACE_CLASS.getName(); + + private static final String APP_NAME = "test-service"; + + private static final URL BASE_URL = URL + .valueOf("dubbo://127.0.0.1:20880") + .setPath(INTERFACE_NAME) + .addParameter(APPLICATION_KEY, APP_NAME) + .addParameter(SIDE_KEY, "provider"); + + private ConfigCenterBasedMetadataReport metadataReport; + + @BeforeEach + public void init() { + ApplicationModel.getConfigManager().setApplication(new ApplicationConfig("test-service")); + this.metadataReport = new FileSystemMetadataReportFactory().getMetadataReport(REPORT_SERVER_URL); + } + + @AfterEach + public void reset() throws Exception { + ApplicationModel.reset(); + this.metadataReport.close(); + } + + /** + * Test {@link MetadataReport#storeProviderMetadata(MetadataIdentifier, ServiceDefinition)} and + * {@link MetadataReport#getServiceDefinition(MetadataIdentifier)} + */ + @Test + public void testStoreProviderMetadataAndGetServiceDefinition() { + MetadataIdentifier metadataIdentifier = new MetadataIdentifier(BASE_URL); + ServiceDefinition serviceDefinition = ServiceDefinitionBuilder.buildFullDefinition(INTERFACE_CLASS, BASE_URL.getParameters()); + metadataReport.storeProviderMetadata(metadataIdentifier, serviceDefinition); + String serviceDefinitionJSON = metadataReport.getServiceDefinition(metadataIdentifier); + assertEquals(serviceDefinitionJSON, new Gson().toJson(serviceDefinition)); + } + + /** + * Test {@link MetadataReport#storeConsumerMetadata(MetadataIdentifier, Map)} and + * {@link MetadataReport#getServiceDefinition(MetadataIdentifier)} + */ + @Test + public void testStoreConsumerMetadata() { + MetadataIdentifier metadataIdentifier = new MetadataIdentifier(BASE_URL); + metadataReport.storeConsumerMetadata(metadataIdentifier, BASE_URL.getParameters()); + String parametersJSON = metadataReport.getServiceDefinition(metadataIdentifier); + assertEquals(parametersJSON, new Gson().toJson(BASE_URL.getParameters())); + } + + /** + * Test {@link MetadataReport#saveServiceMetadata(ServiceMetadataIdentifier, URL)} and + * {@link MetadataReport#removeServiceMetadata(ServiceMetadataIdentifier)} + */ + @Test + public void testSaveServiceMetadataAndRemoveServiceMetadata() { + ServiceMetadataIdentifier metadataIdentifier = new ServiceMetadataIdentifier(BASE_URL); + metadataReport.saveServiceMetadata(metadataIdentifier, BASE_URL); + String metadata = metadataReport.getMetadata(metadataIdentifier); + assertEquals(URL.encode(BASE_URL.toFullString()), metadata); + metadataReport.removeServiceMetadata(metadataIdentifier); + assertNull(metadataReport.getMetadata(metadataIdentifier)); + } + + /** + * Test {@link MetadataReport#saveSubscribedData(SubscriberMetadataIdentifier, Collection)} and + * {@link MetadataReport#getSubscribedURLs(SubscriberMetadataIdentifier)} + */ + @Test + public void testSaveSubscribedDataAndGetSubscribedURLs() { + SubscriberMetadataIdentifier metadataIdentifier = new SubscriberMetadataIdentifier(BASE_URL); + Set urls = singleton(BASE_URL).stream().map(URL::toIdentityString).collect(toSet()); + metadataReport.saveSubscribedData(metadataIdentifier, urls); + Collection subscribedURLs = metadataReport.getSubscribedURLs(metadataIdentifier); + assertEquals(1, subscribedURLs.size()); + assertEquals(urls, subscribedURLs); + } + + /** + * Test {@link MetadataReport#saveExportedURLs(SortedSet)}, + * {@link MetadataReport#getExportedURLsContent(String, String)} and + * {@link MetadataReport#getExportedURLs(String, String)} + */ + @Test + public void testSaveExportedURLsAndGetExportedURLs() { + SortedSet urls = singleton(BASE_URL).stream().map(URL::toIdentityString).collect(TreeSet::new, Set::add, Set::addAll); + metadataReport.saveExportedURLs(urls); + + URLRevisionResolver urlRevisionResolver = URLRevisionResolver.INSTANCE; + String revision = urlRevisionResolver.resolve(urls); + assertEquals(urls, metadataReport.getExportedURLs(APP_NAME, revision)); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataServiceTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataServiceTest.java index 199564443b0..b7db3fb111f 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataServiceTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/InMemoryWritableMetadataServiceTest.java @@ -68,8 +68,8 @@ public void testExportURL() { URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test567Service?version=1.0.44&application=vicpubprovder&side=provider"); inMemoryWritableMetadataService.exportURL(url); - Assertions.assertTrue(inMemoryWritableMetadataService.exportedServiceURLs.size() == 1); - Assertions.assertEquals(inMemoryWritableMetadataService.exportedServiceURLs.get(url.getServiceKey()).first(), url); + Assertions.assertTrue(inMemoryWritableMetadataService.getExportedServiceURLs().size() == 1); + Assertions.assertEquals(inMemoryWritableMetadataService.getExportedServiceURLs().get(url.getServiceKey()).first(), url); } @Test @@ -78,8 +78,8 @@ public void testSubscribeURL() { URL url = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test678Service?version=1.0.44&application=vicpubprovder&side=provider"); inMemoryWritableMetadataService.subscribeURL(url); - Assertions.assertTrue(inMemoryWritableMetadataService.subscribedServiceURLs.size() == 1); - Assertions.assertEquals(inMemoryWritableMetadataService.subscribedServiceURLs.get(url.getServiceKey()).first(), url); + Assertions.assertTrue(inMemoryWritableMetadataService.getSubscribedServiceURLs().size() == 1); + Assertions.assertEquals(inMemoryWritableMetadataService.getSubscribedServiceURLs().get(url.getServiceKey()).first(), url); } @Test @@ -88,11 +88,11 @@ public void testUnExportURL() { URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test567Service?version=1.0.44&application=vicpubprovder&side=provider"); inMemoryWritableMetadataService.exportURL(url); - Assertions.assertTrue(inMemoryWritableMetadataService.exportedServiceURLs.size() == 1); - Assertions.assertEquals(inMemoryWritableMetadataService.exportedServiceURLs.get(url.getServiceKey()).first(), url); + Assertions.assertTrue(inMemoryWritableMetadataService.getExportedServiceURLs().size() == 1); + Assertions.assertEquals(inMemoryWritableMetadataService.getExportedServiceURLs().get(url.getServiceKey()).first(), url); inMemoryWritableMetadataService.unexportURL(url); - Assertions.assertTrue(inMemoryWritableMetadataService.exportedServiceURLs.size() == 0); + Assertions.assertTrue(inMemoryWritableMetadataService.getExportedServiceURLs().size() == 0); } @Test @@ -101,11 +101,11 @@ public void testUnSubscribeURL() { URL url = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test678Service?version=1.0.44&application=vicpubprovder&side=provider"); inMemoryWritableMetadataService.subscribeURL(url); - Assertions.assertTrue(inMemoryWritableMetadataService.subscribedServiceURLs.size() == 1); - Assertions.assertEquals(inMemoryWritableMetadataService.subscribedServiceURLs.get(url.getServiceKey()).first(), url); + Assertions.assertTrue(inMemoryWritableMetadataService.getSubscribedServiceURLs().size() == 1); + Assertions.assertEquals(inMemoryWritableMetadataService.getSubscribedServiceURLs().get(url.getServiceKey()).first(), url); inMemoryWritableMetadataService.unsubscribeURL(url); - Assertions.assertTrue(inMemoryWritableMetadataService.subscribedServiceURLs.size() == 0); + Assertions.assertTrue(inMemoryWritableMetadataService.getSubscribedServiceURLs().size() == 0); } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegateTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegateTest.java deleted file mode 100644 index 8db9534136e..00000000000 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceDelegateTest.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * 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. - */ - -/* - * 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; - -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.utils.NetUtils; -import org.apache.dubbo.metadata.WritableMetadataService; -import org.apache.dubbo.metadata.report.MetadataReportInstance; -import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; -import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; -import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; -import org.apache.dubbo.metadata.test.JTestMetadataReport4Test; -import org.apache.dubbo.rpc.model.ApplicationModel; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.SortedSet; - - -/** - * 2019-08-27 - */ -public class RemoteWritableMetadataServiceDelegateTest { - static URL metadataURL = URL.valueOf("JTest://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Tes33tService?version=1.0.0&application=vic"); - - RemoteWritableMetadataServiceDelegate metadataReportService; - - String interfaceName = "org.apache.dubbo.metadata.store.InterfaceNameTestService80", version = "0.6.9", group = null; - URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/?interface=" + interfaceName + "&version=" - + version + "&application=vicpubprovder&side=provider"); - - @BeforeAll - public static void beforeAll() { - MetadataReportInstance.init(metadataURL); - } - - @BeforeEach - public void before() { - metadataReportService = new RemoteWritableMetadataServiceDelegate(); - } - - - @Test - public void testInstance() { - WritableMetadataService metadataReportService1 = WritableMetadataService.getExtension("remote"); - WritableMetadataService metadataReportService2 = WritableMetadataService.getExtension("remote"); - Assertions.assertSame(metadataReportService1, metadataReportService2); - Assertions.assertTrue(metadataReportService1 instanceof RemoteWritableMetadataServiceDelegate); - } - - @Test - public void testPublishServiceDefinition() throws InterruptedException { - String interfaceName = "org.apache.dubbo.metadata.store.InterfaceNameTestService2", version = "0.9.9", group = null; - URL tmpUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/?interface=" + interfaceName + "&version=" - + version + "&application=vicpubprovder&side=provider"); - metadataReportService.publishServiceDefinition(tmpUrl); - Thread.sleep(150); - String v = metadataReportService.getServiceDefinition(interfaceName, version, group); - Assertions.assertNotNull(v); - } - - @Test - public void testExportURL() throws InterruptedException { - URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test567Service?version=1.0.44&application=vicpubprovder&side=provider"); - metadataReportService.exportURL(url); - Thread.sleep(100); - Assertions.assertTrue(getInMemoryWriableMetadataService().exportedServiceURLs.size() == 1); - Assertions.assertEquals(getInMemoryWriableMetadataService().exportedServiceURLs.get(url.getServiceKey()).first(), url); - } - - @Test - public void testSubscribeURL() throws InterruptedException { - URL url = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test0678Service?version=1.3.144&application=vicpubprovder&side=provider"); - int origSize = getInMemoryWriableMetadataService().subscribedServiceURLs.size(); - metadataReportService.subscribeURL(url); - Thread.sleep(100); - int size = getInMemoryWriableMetadataService().subscribedServiceURLs.size(); - Assertions.assertTrue(size - origSize == 1); - Assertions.assertEquals(getInMemoryWriableMetadataService().subscribedServiceURLs.get(url.getServiceKey()).first(), url); - } - - @Test - public void testUnExportURL() throws InterruptedException { - URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test0567Service?version=1.2.44&application=vicpubprovder&side=provider"); - int origSize = getInMemoryWriableMetadataService().exportedServiceURLs.size(); - metadataReportService.exportURL(url); - Thread.sleep(100); - int size = getInMemoryWriableMetadataService().exportedServiceURLs.size(); - Assertions.assertTrue(size - origSize == 1); - Assertions.assertEquals(getInMemoryWriableMetadataService().exportedServiceURLs.get(url.getServiceKey()).first(), url); - - metadataReportService.unexportURL(url); - int unexportSize = getInMemoryWriableMetadataService().exportedServiceURLs.size(); - Assertions.assertTrue(size - unexportSize == 1); - } - - @Test - public void testUnSubscribeURL() throws InterruptedException { - URL url = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.Test0678Service?version=1.5.477&application=vicpubprovder&side=provider"); - int origSize = getInMemoryWriableMetadataService().subscribedServiceURLs.size(); - metadataReportService.subscribeURL(url); - Thread.sleep(100); - int size = getInMemoryWriableMetadataService().subscribedServiceURLs.size(); - Assertions.assertTrue(size - origSize == 1); - Assertions.assertEquals(getInMemoryWriableMetadataService().subscribedServiceURLs.get(url.getServiceKey()).first(), url); - - metadataReportService.unsubscribeURL(url); - Thread.sleep(100); - Assertions.assertTrue(getInMemoryWriableMetadataService().subscribedServiceURLs.size() == 0); - } - - @Test - public void testRefreshMetadataService() throws InterruptedException { - URL publishUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadataService?version=1.6.8&application=vicpubprovder&side=provider"); - URL publishUrl2 = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata2Service?version=1.6.5&application=vicpubprovder&side=provider"); - metadataReportService.exportURL(publishUrl); - metadataReportService.exportURL(publishUrl2); - String exportedRevision = "9999"; - JTestMetadataReport4Test jTestMetadataReport4Test = (JTestMetadataReport4Test) MetadataReportInstance.getMetadataReport(true); - int origSize = jTestMetadataReport4Test.store.size(); - int num = countNum(); - Assertions.assertTrue(metadataReportService.refreshMetadata(exportedRevision, "1109")); - Thread.sleep(200); - int size = jTestMetadataReport4Test.store.size(); - Assertions.assertTrue(size - origSize == num); - Assertions.assertEquals(jTestMetadataReport4Test.store.get(getServiceMetadataIdentifier(publishUrl, exportedRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY)), publishUrl.toFullString()); - Assertions.assertEquals(jTestMetadataReport4Test.store.get(getServiceMetadataIdentifier(publishUrl2, exportedRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY)), publishUrl2.toFullString()); - } - - - // unstable test -// @Test -// public void testRefreshMetadataSubscription() throws InterruptedException { -// URL subscriberUrl1 = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata00Service?version=2.0.8&application=vicpubprovder&side=provider"); -// URL subscriberUrl2 = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata09Service?version=2.0.5&application=vicpubprovder&side=provider"); -// metadataReportService.subscribeURL(subscriberUrl1); -// metadataReportService.subscribeURL(subscriberUrl2); -// String exportedRevision = "9999"; -// String subscriberRevision = "2099"; -// String applicationName = "wriableMetadataService"; -// JTestMetadataReport4Test jTestMetadataReport4Test = (JTestMetadataReport4Test) MetadataReportInstance.getMetadataReport(true); -// int origSize = jTestMetadataReport4Test.store.size(); -// ApplicationModel.setApplication(applicationName); -// Assertions.assertTrue(metadataReportService.refreshMetadata(exportedRevision, subscriberRevision)); -// Thread.sleep(200); -// int size = jTestMetadataReport4Test.store.size(); -// Assertions.assertTrue(size - origSize == 1); -// String r = jTestMetadataReport4Test.store.get(getSubscriberMetadataIdentifier( -// subscriberRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY)); -// Assertions.assertNotNull(r); -// } - - - private ServiceMetadataIdentifier getServiceMetadataIdentifier(URL publishUrl, String exportedRevision) { - ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(publishUrl); - serviceMetadataIdentifier.setRevision(exportedRevision); - serviceMetadataIdentifier.setProtocol(publishUrl.getProtocol()); - return serviceMetadataIdentifier; - } - - private SubscriberMetadataIdentifier getSubscriberMetadataIdentifier(String subscriberRevision) { - SubscriberMetadataIdentifier subscriberMetadataIdentifier = new SubscriberMetadataIdentifier(); - subscriberMetadataIdentifier.setRevision(subscriberRevision); - subscriberMetadataIdentifier.setApplication(ApplicationModel.getApplication()); - return subscriberMetadataIdentifier; - } - - private InMemoryWritableMetadataService getInMemoryWriableMetadataService() { - return (InMemoryWritableMetadataService) metadataReportService.defaultWritableMetadataService; - } - - private int countNum() { - int num = 0; - for (SortedSet tmp : getInMemoryWriableMetadataService().exportedServiceURLs.values()) { - num += tmp.size(); - } - if (!getInMemoryWriableMetadataService().subscribedServiceURLs.values().isEmpty()) { - num++; - } - return num; - } -} diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMeatadataServiceTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceTest.java similarity index 90% rename from dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMeatadataServiceTest.java rename to dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceTest.java index bdd748cf491..e9ca89f6731 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMeatadataServiceTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/store/RemoteWritableMetadataServiceTest.java @@ -36,15 +36,13 @@ /** * 2018/9/14 */ -public class RemoteWritableMeatadataServiceTest { +public class RemoteWritableMetadataServiceTest { URL url = URL.valueOf("JTest://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic"); RemoteWritableMetadataService metadataReportService1; - InMemoryWritableMetadataService inMemoryWritableMetadataService; @BeforeEach public void before() { - inMemoryWritableMetadataService = new InMemoryWritableMetadataService(); - metadataReportService1 = new RemoteWritableMetadataService(inMemoryWritableMetadataService); + metadataReportService1 = new RemoteWritableMetadataService(); MetadataReportInstance.init(url); } @@ -134,25 +132,25 @@ public void testUnexportURL() { public void testRefreshMetadataService() throws InterruptedException { URL publishUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadataService?version=1.0.8&application=vicpubprovder&side=provider"); URL publishUrl2 = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata2Service?version=1.0.5&application=vicpubprovder&side=provider"); - inMemoryWritableMetadataService.exportURL(publishUrl); - inMemoryWritableMetadataService.exportURL(publishUrl2); + metadataReportService1.exportURL(publishUrl); + metadataReportService1.exportURL(publishUrl2); String exportedRevision = "9999"; JTestMetadataReport4Test jTestMetadataReport4Test = (JTestMetadataReport4Test) metadataReportService1.getMetadataReport(); int origSize = jTestMetadataReport4Test.store.size(); Assertions.assertTrue(metadataReportService1.refreshMetadata(exportedRevision, "1109")); Thread.sleep(200); int size = jTestMetadataReport4Test.store.size(); - Assertions.assertTrue(size - origSize == 2); - Assertions.assertEquals(jTestMetadataReport4Test.store.get(getServiceMetadataIdentifier(publishUrl, exportedRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY)), publishUrl.toFullString()); - Assertions.assertEquals(jTestMetadataReport4Test.store.get(getServiceMetadataIdentifier(publishUrl2, exportedRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY)), publishUrl2.toFullString()); + Assertions.assertEquals(origSize, size); + Assertions.assertNull(jTestMetadataReport4Test.store.get(getServiceMetadataIdentifier(publishUrl, exportedRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY))); + Assertions.assertNull(jTestMetadataReport4Test.store.get(getServiceMetadataIdentifier(publishUrl2, exportedRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY))); } @Test public void testRefreshMetadataSubscription() throws InterruptedException { URL subscriberUrl1 = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata00Service?version=1.0.8&application=vicpubprovder&side=provider"); URL subscriberUrl2 = URL.valueOf("subscriber://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestRefreshMetadata09Service?version=1.0.5&application=vicpubprovder&side=provider"); - inMemoryWritableMetadataService.subscribeURL(subscriberUrl1); - inMemoryWritableMetadataService.subscribeURL(subscriberUrl2); + metadataReportService1.subscribeURL(subscriberUrl1); + metadataReportService1.subscribeURL(subscriberUrl2); String exportedRevision = "9999"; String subscriberRevision = "2099"; String applicationName = "wriableMetadataService"; @@ -162,10 +160,10 @@ public void testRefreshMetadataSubscription() throws InterruptedException { Assertions.assertTrue(metadataReportService1.refreshMetadata(exportedRevision, subscriberRevision)); Thread.sleep(200); int size = jTestMetadataReport4Test.store.size(); - Assertions.assertTrue(size - origSize == 1); + Assertions.assertEquals(origSize, size); String r = jTestMetadataReport4Test.store.get(getSubscriberMetadataIdentifier( subscriberRevision).getUniqueKey(KeyTypeEnum.UNIQUE_KEY)); - Assertions.assertNotNull(r); + Assertions.assertNull(r); } private ServiceMetadataIdentifier getServiceMetadataIdentifier(URL publishUrl, String exportedRevision) { diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/resources/META-INF/dubbo/service-name-mapping.properties b/dubbo-metadata/dubbo-metadata-api/src/test/resources/META-INF/dubbo/service-name-mapping.properties new file mode 100644 index 00000000000..5f3863d1007 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/test/resources/META-INF/dubbo/service-name-mapping.properties @@ -0,0 +1,3 @@ +dubbo\:com.acme.Interface1\:default = Service1 +thirft\:com.acme.InterfaceX = Service1,Service2 +rest\:com.acme.interfaceN = Service3 \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-report-consul/pom.xml b/dubbo-metadata/dubbo-metadata-report-consul/pom.xml index b30001a8b03..8a01b72d49c 100644 --- a/dubbo-metadata/dubbo-metadata-report-consul/pom.xml +++ b/dubbo-metadata/dubbo-metadata-report-consul/pom.xml @@ -16,7 +16,8 @@ ~ limitations under the License. --> - + org.apache.dubbo dubbo-metadata @@ -33,6 +34,11 @@ dubbo-metadata-api ${project.parent.version} + + org.apache.dubbo + dubbo-configcenter-consul + ${project.parent.version} + com.ecwid.consul consul-api diff --git a/dubbo-metadata/dubbo-metadata-report-consul/src/main/java/org/apache/dubbo/metadata/store/consul/ConsulMetadataReport.java b/dubbo-metadata/dubbo-metadata-report-consul/src/main/java/org/apache/dubbo/metadata/store/consul/ConsulMetadataReport.java index c1e0a309bef..e6b70542619 100644 --- a/dubbo-metadata/dubbo-metadata-report-consul/src/main/java/org/apache/dubbo/metadata/store/consul/ConsulMetadataReport.java +++ b/dubbo-metadata/dubbo-metadata-report-consul/src/main/java/org/apache/dubbo/metadata/store/consul/ConsulMetadataReport.java @@ -27,6 +27,7 @@ import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; import org.apache.dubbo.metadata.report.support.AbstractMetadataReport; +import org.apache.dubbo.metadata.report.support.ConfigCenterBasedMetadataReport; import org.apache.dubbo.rpc.RpcException; import com.ecwid.consul.v1.ConsulClient; @@ -40,7 +41,10 @@ /** * metadata report impl for consul + * + * @deprecated 2.7.8 This class will be removed in the future, {@link ConfigCenterBasedMetadataReport} as a substitute. */ +@Deprecated public class ConsulMetadataReport extends AbstractMetadataReport { private static final Logger logger = LoggerFactory.getLogger(ConsulMetadataReport.class); private static final int DEFAULT_PORT = 8500; diff --git a/dubbo-metadata/dubbo-metadata-report-consul/src/main/java/org/apache/dubbo/metadata/store/consul/ConsulMetadataReportFactory.java b/dubbo-metadata/dubbo-metadata-report-consul/src/main/java/org/apache/dubbo/metadata/store/consul/ConsulMetadataReportFactory.java index 1d1f5bbd409..7f5f1901e72 100644 --- a/dubbo-metadata/dubbo-metadata-report-consul/src/main/java/org/apache/dubbo/metadata/store/consul/ConsulMetadataReportFactory.java +++ b/dubbo-metadata/dubbo-metadata-report-consul/src/main/java/org/apache/dubbo/metadata/store/consul/ConsulMetadataReportFactory.java @@ -17,16 +17,15 @@ package org.apache.dubbo.metadata.store.consul; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.metadata.report.MetadataReport; -import org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory; +import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; +import org.apache.dubbo.metadata.report.support.ConfigCenterBasedMetadataReportFactory; /** * metadata report factory impl for consul */ -public class ConsulMetadataReportFactory extends AbstractMetadataReportFactory { - @Override - protected MetadataReport createMetadataReport(URL url) { - return new ConsulMetadataReport(url); +public class ConsulMetadataReportFactory extends ConfigCenterBasedMetadataReportFactory { + + public ConsulMetadataReportFactory() { + super(KeyTypeEnum.UNIQUE_KEY); } } diff --git a/dubbo-metadata/dubbo-metadata-report-nacos/pom.xml b/dubbo-metadata/dubbo-metadata-report-nacos/pom.xml index db76cae7d4d..03211e02ec8 100644 --- a/dubbo-metadata/dubbo-metadata-report-nacos/pom.xml +++ b/dubbo-metadata/dubbo-metadata-report-nacos/pom.xml @@ -16,7 +16,8 @@ ~ limitations under the License. --> - + org.apache.dubbo dubbo-metadata @@ -33,9 +34,11 @@ dubbo-metadata-api ${project.parent.version} + - com.alibaba.nacos - nacos-client + org.apache.dubbo + dubbo-configcenter-nacos + ${project.parent.version} diff --git a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java index 707d2b8261c..5c413d8fb0a 100644 --- a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java +++ b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java @@ -18,6 +18,7 @@ package org.apache.dubbo.metadata.store.nacos; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.StringUtils; @@ -27,132 +28,36 @@ import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; import org.apache.dubbo.metadata.report.support.AbstractMetadataReport; +import org.apache.dubbo.metadata.report.support.ConfigCenterBasedMetadataReport; import org.apache.dubbo.rpc.RpcException; -import com.alibaba.nacos.api.NacosFactory; -import com.alibaba.nacos.api.config.ConfigService; -import com.alibaba.nacos.api.exception.NacosException; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Properties; - -import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY; -import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME; -import static com.alibaba.nacos.api.PropertyKeyConst.CONFIG_LONG_POLL_TIMEOUT; -import static com.alibaba.nacos.api.PropertyKeyConst.CONFIG_RETRY_TIME; -import static com.alibaba.nacos.api.PropertyKeyConst.CONTEXT_PATH; -import static com.alibaba.nacos.api.PropertyKeyConst.ENABLE_REMOTE_SYNC_CONFIG; -import static com.alibaba.nacos.api.PropertyKeyConst.ENCODE; -import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT; -import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT_PORT; -import static com.alibaba.nacos.api.PropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING; -import static com.alibaba.nacos.api.PropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE; -import static com.alibaba.nacos.api.PropertyKeyConst.MAX_RETRY; -import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE; -import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_CLIENT_BEAT_THREAD_COUNT; -import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_LOAD_CACHE_AT_START; -import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_POLLING_THREAD_COUNT; -import static com.alibaba.nacos.api.PropertyKeyConst.RAM_ROLE_NAME; -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_KEY; -import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY; + +import static java.util.concurrent.TimeUnit.SECONDS; /** * metadata report impl for nacos + * + * @deprecated 2.7.8 This class will be removed in the future, {@link ConfigCenterBasedMetadataReport} as a substitute. */ +@Deprecated public class NacosMetadataReport extends AbstractMetadataReport { private static final Logger logger = LoggerFactory.getLogger(NacosMetadataReport.class); - private ConfigService configService; + private final DynamicConfiguration dynamicConfiguration; /** * The group used to store metadata in Nacos */ private String group; - - public NacosMetadataReport(URL url) { + public NacosMetadataReport(URL url, DynamicConfiguration dynamicConfiguration) { super(url); - this.configService = buildConfigService(url); - group = url.getParameter(GROUP_KEY, DEFAULT_ROOT); - } - - 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 static void setProperties(URL url, Properties properties) { - putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME); - putPropertyIfAbsent(url, properties, IS_USE_CLOUD_NAMESPACE_PARSING); - putPropertyIfAbsent(url, properties, IS_USE_ENDPOINT_PARSING_RULE); - putPropertyIfAbsent(url, properties, ENDPOINT); - putPropertyIfAbsent(url, properties, ENDPOINT_PORT); - putPropertyIfAbsent(url, properties, NAMESPACE); - putPropertyIfAbsent(url, properties, ACCESS_KEY); - putPropertyIfAbsent(url, properties, SECRET_KEY); - putPropertyIfAbsent(url, properties, RAM_ROLE_NAME); - putPropertyIfAbsent(url, properties, CONTEXT_PATH); - putPropertyIfAbsent(url, properties, CLUSTER_NAME); - putPropertyIfAbsent(url, properties, ENCODE); - putPropertyIfAbsent(url, properties, CONFIG_LONG_POLL_TIMEOUT); - putPropertyIfAbsent(url, properties, CONFIG_RETRY_TIME); - putPropertyIfAbsent(url, properties, MAX_RETRY); - putPropertyIfAbsent(url, properties, ENABLE_REMOTE_SYNC_CONFIG); - putPropertyIfAbsent(url, properties, NAMING_LOAD_CACHE_AT_START, "true"); - putPropertyIfAbsent(url, properties, NAMING_CLIENT_BEAT_THREAD_COUNT); - putPropertyIfAbsent(url, properties, NAMING_POLLING_THREAD_COUNT); - } - - private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName) { - String propertyValue = url.getParameter(propertyName); - if (StringUtils.isNotEmpty(propertyValue)) { - properties.setProperty(propertyName, propertyValue); - } - } - - private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName, String defaultValue) { - String propertyValue = url.getParameter(propertyName); - if (StringUtils.isNotEmpty(propertyValue)) { - properties.setProperty(propertyName, propertyValue); - } else { - properties.setProperty(propertyName, defaultValue); - } + this.dynamicConfiguration = dynamicConfiguration; } @Override @@ -199,9 +104,19 @@ public String getServiceDefinition(MetadataIdentifier metadataIdentifier) { return getConfig(metadataIdentifier); } + @Override + public boolean saveExportedURLs(String serviceName, String exportedServicesRevision, String exportedURLsContent) { + return dynamicConfiguration.publishConfig(serviceName, exportedServicesRevision, exportedURLsContent); + } + + @Override + public String getExportedURLsContent(String serviceName, String exportedServicesRevision) { + return dynamicConfiguration.getConfig(serviceName, exportedServicesRevision, SECONDS.toMillis(3)); + } + private void storeMetadata(BaseMetadataIdentifier identifier, String value) { try { - boolean publishResult = configService.publishConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group, value); + boolean publishResult = dynamicConfiguration.publishConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group, value); if (!publishResult) { throw new RuntimeException("publish nacos metadata failed"); } @@ -213,7 +128,7 @@ private void storeMetadata(BaseMetadataIdentifier identifier, String value) { private void deleteMetadata(BaseMetadataIdentifier identifier) { try { - boolean publishResult = configService.removeConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group); + boolean publishResult = dynamicConfiguration.removeConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group); if (!publishResult) { throw new RuntimeException("remove nacos metadata failed"); } @@ -225,7 +140,7 @@ private void deleteMetadata(BaseMetadataIdentifier identifier) { private String getConfig(BaseMetadataIdentifier identifier) { try { - return configService.getConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group, 300); + return dynamicConfiguration.getConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group, 300); } catch (Throwable t) { logger.error("Failed to get " + identifier + " from nacos , cause: " + t.getMessage(), t); throw new RpcException("Failed to get " + identifier + " from nacos , cause: " + t.getMessage(), t); diff --git a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java index 2cff74c9a1b..8c8d5a2efae 100644 --- a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java +++ b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java @@ -17,16 +17,15 @@ package org.apache.dubbo.metadata.store.nacos; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.metadata.report.MetadataReport; -import org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory; +import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; +import org.apache.dubbo.metadata.report.support.ConfigCenterBasedMetadataReportFactory; /** * metadata report factory impl for nacos */ -public class NacosMetadataReportFactory extends AbstractMetadataReportFactory { - @Override - protected MetadataReport createMetadataReport(URL url) { - return new NacosMetadataReport(url); +public class NacosMetadataReportFactory extends ConfigCenterBasedMetadataReportFactory { + + public NacosMetadataReportFactory() { + super(KeyTypeEnum.UNIQUE_KEY); } } diff --git a/dubbo-metadata/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportTest.java b/dubbo-metadata/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportTest.java deleted file mode 100644 index 88fc75ab5a4..00000000000 --- a/dubbo-metadata/dubbo-metadata-report-nacos/src/test/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportTest.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * 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.exception.NacosException; -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.report.identifier.KeyTypeEnum; -import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; - -import com.alibaba.nacos.api.config.ConfigService; -import com.google.gson.Gson; -import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; -import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE; -import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; - -//FIXME: waiting for embedded Nacos suport, then we can open the switch. -@Disabled("https://github.com/alibaba/nacos/issues/1188") -public class NacosMetadataReportTest { - - private static final String SESSION_TIMEOUT_KEY = "session"; - - private static final String TEST_SERVICE = "org.apache.dubbo.metadata.store.nacos.NacosMetadata4TstService"; - - private NacosMetadataReport nacosMetadataReport; - - private NacosMetadataReportFactory nacosMetadataReportFactory; - - private ConfigService configService; - - private static final String NACOS_GROUP = "metadata_test"; - - /** - * timeout(ms) for nacos session - */ - private static final int SESSION_TIMEOUT = 15 * 1000; - - /** - * timeout(ms) for query operation on nacos - */ - private static final int NACOS_READ_TIMEOUT = 5 * 1000; - - /** - * interval(ms) to make nacos cache refresh - */ - private static final int INTERVAL_TO_MAKE_NACOS_REFRESH = 1000; - - /** - * version for test - */ - private static final String VERSION = "1.0.0"; - - /** - * group for test - */ - private static final String METADATA_GROUP = null; - - /** - * application name for test - */ - private static final String APPLICATION_NAME = "nacos-metdata-report-test"; - - /** - * revision for test - */ - private static final String REVISION = "90980"; - - /** - * protocol for test - */ - private static final String PROTOCOL = "xxx"; - - @BeforeEach - public void setUp() { - URL url = URL.valueOf("nacos://127.0.0.1:8848?group=" + NACOS_GROUP) - .addParameter(SESSION_TIMEOUT_KEY, SESSION_TIMEOUT); - 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 { - MetadataIdentifier providerIdentifier = - storeProvider(nacosMetadataReport, TEST_SERVICE, VERSION, METADATA_GROUP, APPLICATION_NAME); - String serverContent = configService.getConfig(providerIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP, NACOS_READ_TIMEOUT); - Assertions.assertNotNull(serverContent); - - Gson gson = new Gson(); - FullServiceDefinition fullServiceDefinition = gson.fromJson(serverContent, FullServiceDefinition.class); - Assertions.assertEquals(fullServiceDefinition.getParameters().get("paramTest"), "nacosTest"); - - //Clear test data - configService.removeConfig(providerIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP); - } - - @Test - public void testStoreConsumer() throws Exception { - MetadataIdentifier consumerIdentifier = storeConsumer(nacosMetadataReport, TEST_SERVICE, VERSION, METADATA_GROUP, APPLICATION_NAME); - - String serverContent = configService.getConfig(consumerIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP, NACOS_READ_TIMEOUT); - Assertions.assertNotNull(serverContent); - Assertions.assertEquals(serverContent, "{\"paramConsumerTest\":\"nacosConsumer\"}"); - - //clear test data - configService.removeConfig(consumerIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP); - } - - @Test - public void testDoSaveServiceMetadata() throws Exception { - URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":4444/" + TEST_SERVICE + - "?paramTest=nacosTest&version=" + VERSION + "&application=" - + APPLICATION_NAME + (METADATA_GROUP == null ? "" : "&group=" + METADATA_GROUP)); - ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(TEST_SERVICE, VERSION, - METADATA_GROUP, "provider", REVISION, PROTOCOL); - nacosMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url); - Thread.sleep(INTERVAL_TO_MAKE_NACOS_REFRESH); - String serviceMetaData = configService.getConfig(serviceMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP, NACOS_READ_TIMEOUT); - Assertions.assertNotNull(serviceMetaData); - Assertions.assertEquals(serviceMetaData, URL.encode(url.toFullString())); - - //clear test data - configService.removeConfig(serviceMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP); - } - - @Test - public void testDoRemoveServiceMetadata() throws Exception { - URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":4444/" + TEST_SERVICE + - "?paramTest=nacosTest&version=" + VERSION + "&application=" - + APPLICATION_NAME + (METADATA_GROUP == null ? "" : "&group=" + METADATA_GROUP)); - ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(TEST_SERVICE, VERSION, - METADATA_GROUP, "provider", REVISION, PROTOCOL); - nacosMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url); - Thread.sleep(INTERVAL_TO_MAKE_NACOS_REFRESH); - String serviceMetaData = configService.getConfig(serviceMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP, NACOS_READ_TIMEOUT); - Assertions.assertNotNull(serviceMetaData); - - nacosMetadataReport.doRemoveMetadata(serviceMetadataIdentifier); - Thread.sleep(INTERVAL_TO_MAKE_NACOS_REFRESH); - serviceMetaData = configService.getConfig(serviceMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP, NACOS_READ_TIMEOUT); - Assertions.assertNull(serviceMetaData); - } - - @Test - public void testDoGetExportedURLs() throws InterruptedException, NacosException { - URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":4444/" + TEST_SERVICE + - "?paramTest=nacosTest&version=" + VERSION + "&application=" - + APPLICATION_NAME + (METADATA_GROUP == null ? "" : "&group=" + METADATA_GROUP)); - ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(TEST_SERVICE, VERSION, - METADATA_GROUP, "provider", REVISION, PROTOCOL); - - nacosMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url); - Thread.sleep(INTERVAL_TO_MAKE_NACOS_REFRESH); - - List exportedURLs = nacosMetadataReport.doGetExportedURLs(serviceMetadataIdentifier); - Assertions.assertTrue(exportedURLs.size() == 1); - - String exportedUrl = exportedURLs.get(0); - Assertions.assertNotNull(exportedUrl); - Assertions.assertEquals(exportedUrl, url.toFullString()); - - //clear test data - configService.removeConfig(serviceMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP); - } - - @Test - public void testDoSaveSubscriberData() throws InterruptedException, NacosException { - URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":4444/" + TEST_SERVICE + - "?paramTest=nacosTest&version=" + VERSION + "&application=" - + APPLICATION_NAME + (METADATA_GROUP == null ? "" : "&group=" + METADATA_GROUP)); - SubscriberMetadataIdentifier subscriberMetadataIdentifier = new SubscriberMetadataIdentifier(APPLICATION_NAME, REVISION); - Gson gson = new Gson(); - String urlListJsonString = gson.toJson(Arrays.asList(url)); - nacosMetadataReport.doSaveSubscriberData(subscriberMetadataIdentifier, urlListJsonString); - Thread.sleep(INTERVAL_TO_MAKE_NACOS_REFRESH); - - String subscriberMetadata = configService.getConfig(subscriberMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP, NACOS_READ_TIMEOUT); - Assertions.assertNotNull(subscriberMetadata); - Assertions.assertEquals(subscriberMetadata, urlListJsonString); - - //clear test data - configService.removeConfig(subscriberMetadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), NACOS_GROUP); - - } - - 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(INTERVAL_TO_MAKE_NACOS_REFRESH); - 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(INTERVAL_TO_MAKE_NACOS_REFRESH); - return consumerIdentifier; - } - -} diff --git a/dubbo-metadata/dubbo-metadata-report-zookeeper/pom.xml b/dubbo-metadata/dubbo-metadata-report-zookeeper/pom.xml index 89a5f9c3dfc..fa614a09f0a 100644 --- a/dubbo-metadata/dubbo-metadata-report-zookeeper/pom.xml +++ b/dubbo-metadata/dubbo-metadata-report-zookeeper/pom.xml @@ -34,7 +34,7 @@ org.apache.dubbo - dubbo-remoting-zookeeper + dubbo-configcenter-zookeeper ${project.parent.version} diff --git a/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java b/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java index 9ca2e42024a..3a74f8dbfc1 100644 --- a/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java +++ b/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java @@ -19,6 +19,7 @@ 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.PathUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.metadata.report.identifier.BaseMetadataIdentifier; import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; @@ -26,6 +27,7 @@ import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; import org.apache.dubbo.metadata.report.support.AbstractMetadataReport; +import org.apache.dubbo.metadata.report.support.ConfigCenterBasedMetadataReport; import org.apache.dubbo.remoting.zookeeper.ZookeeperClient; import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; @@ -36,10 +38,15 @@ import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR; +import static org.apache.dubbo.metadata.MetadataConstants.DEFAULT_PATH_TAG; +import static org.apache.dubbo.metadata.MetadataConstants.EXPORTED_URLS_TAG; /** * ZookeeperMetadataReport + * + * @deprecated 2.7.8 This class will be removed in the future, {@link ConfigCenterBasedMetadataReport} as a substitute. */ +@Deprecated public class ZookeeperMetadataReport extends AbstractMetadataReport { private final static Logger logger = LoggerFactory.getLogger(ZookeeperMetadataReport.class); @@ -120,4 +127,26 @@ String getNodePath(BaseMetadataIdentifier metadataIdentifier) { return toRootDir() + metadataIdentifier.getUniqueKey(KeyTypeEnum.PATH); } + @Override + public boolean saveExportedURLs(String serviceName, String exportedServicesRevision, String exportedURLsContent) { + String path = buildExportedURLsMetadataPath(serviceName, exportedServicesRevision); + zkClient.create(path, exportedURLsContent, false); + return true; + } + + @Override + public String getExportedURLsContent(String serviceName, String exportedServicesRevision) { + String path = buildExportedURLsMetadataPath(serviceName, exportedServicesRevision); + String content = zkClient.getContent(path); + return content; + } + + private String buildExportedURLsMetadataPath(String serviceName, String exportedServicesRevision) { + return buildPath(DEFAULT_PATH_TAG, EXPORTED_URLS_TAG, serviceName, exportedServicesRevision); + } + + private String buildPath(String... paths) { + return PathUtils.buildPath(toRootDir(), paths); + } + } diff --git a/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportFactory.java b/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportFactory.java index 0ffed8db8e9..4773e1eb77b 100644 --- a/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportFactory.java +++ b/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportFactory.java @@ -16,25 +16,17 @@ */ package org.apache.dubbo.metadata.store.zookeeper; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.metadata.report.MetadataReport; -import org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory; -import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; +import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; +import org.apache.dubbo.metadata.report.support.ConfigCenterBasedMetadataReportFactory; /** * ZookeeperRegistryFactory. + * + * @revised 2.7.8 {@link ConfigCenterBasedMetadataReportFactory} */ -public class ZookeeperMetadataReportFactory extends AbstractMetadataReportFactory { - - private ZookeeperTransporter zookeeperTransporter; +public class ZookeeperMetadataReportFactory extends ConfigCenterBasedMetadataReportFactory { - public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) { - this.zookeeperTransporter = zookeeperTransporter; + public ZookeeperMetadataReportFactory() { + super(KeyTypeEnum.PATH); } - - @Override - public MetadataReport createMetadataReport(URL url) { - return new ZookeeperMetadataReport(url, zookeeperTransporter); - } - } diff --git a/dubbo-metadata/dubbo-metadata-report-zookeeper/src/test/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportTest.java b/dubbo-metadata/dubbo-metadata-report-zookeeper/src/test/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportTest.java index 454f25ed13a..4e6ae3d82db 100644 --- a/dubbo-metadata/dubbo-metadata-report-zookeeper/src/test/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportTest.java +++ b/dubbo-metadata/dubbo-metadata-report-zookeeper/src/test/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportTest.java @@ -1,277 +1,276 @@ -/* - * 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.zookeeper; - -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.report.identifier.KeyTypeEnum; -import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; -import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; -import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; -import org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperTransporter; - -import com.google.gson.Gson; -import org.apache.curator.test.TestingServer; -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 java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; - -import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE; -import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; - -/** - * 2018/10/9 - */ -public class ZookeeperMetadataReportTest { - private TestingServer zkServer; - private ZookeeperMetadataReport zookeeperMetadataReport; - private URL registryUrl; - private ZookeeperMetadataReportFactory zookeeperMetadataReportFactory; - - @BeforeEach - public void setUp() throws Exception { - int zkServerPort = NetUtils.getAvailablePort(); - this.zkServer = new TestingServer(zkServerPort, true); - this.registryUrl = URL.valueOf("zookeeper://localhost:" + zkServerPort); - - zookeeperMetadataReportFactory = new ZookeeperMetadataReportFactory(); - zookeeperMetadataReportFactory.setZookeeperTransporter(new CuratorZookeeperTransporter()); - this.zookeeperMetadataReport = (ZookeeperMetadataReport) zookeeperMetadataReportFactory.createMetadataReport(registryUrl); - } - - @AfterEach - public void tearDown() throws Exception { - zkServer.stop(); - } - - private void deletePath(MetadataIdentifier metadataIdentifier, ZookeeperMetadataReport zookeeperMetadataReport) { - String category = zookeeperMetadataReport.toRootDir() + metadataIdentifier.getUniqueKey(KeyTypeEnum.PATH); - zookeeperMetadataReport.zkClient.delete(category); - } - - @Test - public void testStoreProvider() throws ClassNotFoundException, InterruptedException { - String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; - String version = "1.0.0.zk.md"; - String group = null; - String application = "vic.zk.md"; - MetadataIdentifier providerMetadataIdentifier = storePrivider(zookeeperMetadataReport, interfaceName, version, group, application); - - String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); - fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); - Assertions.assertNotNull(fileContent); - - deletePath(providerMetadataIdentifier, zookeeperMetadataReport); - fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); - fileContent = waitSeconds(fileContent, 1000, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); - Assertions.assertNull(fileContent); - - - providerMetadataIdentifier = storePrivider(zookeeperMetadataReport, interfaceName, version, group, application); - fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); - fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); - Assertions.assertNotNull(fileContent); - - Gson gson = new Gson(); - FullServiceDefinition fullServiceDefinition = gson.fromJson(fileContent, FullServiceDefinition.class); - Assertions.assertEquals(fullServiceDefinition.getParameters().get("paramTest"), "zkTest"); - } - - - @Test - public void testConsumer() throws ClassNotFoundException, InterruptedException { - String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; - String version = "1.0.0.zk.md"; - String group = null; - String application = "vic.zk.md"; - MetadataIdentifier consumerMetadataIdentifier = storeConsumer(zookeeperMetadataReport, interfaceName, version, group, application); - - String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); - fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); - Assertions.assertNotNull(fileContent); - - deletePath(consumerMetadataIdentifier, zookeeperMetadataReport); - fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); - fileContent = waitSeconds(fileContent, 1000, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); - Assertions.assertNull(fileContent); - - consumerMetadataIdentifier = storeConsumer(zookeeperMetadataReport, interfaceName, version, group, application); - fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); - fileContent = waitSeconds(fileContent, 3000, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); - Assertions.assertNotNull(fileContent); - Assertions.assertEquals(fileContent, "{\"paramConsumerTest\":\"zkCm\"}"); - } - - @Test - public void testDoSaveMetadata() throws ExecutionException, InterruptedException { - String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; - String version = "1.0.0"; - String group = null; - String application = "etc-metadata-report-consumer-test"; - String revision = "90980"; - String protocol = "xxx"; - URL url = generateURL(interfaceName, version, group, application); - ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(interfaceName, version, - group, "provider", revision, protocol); - zookeeperMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url); - - String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(serviceMetadataIdentifier)); - Assertions.assertNotNull(fileContent); - - Assertions.assertEquals(fileContent, URL.encode(url.toFullString())); - } - - @Test - public void testDoRemoveMetadata() throws ExecutionException, InterruptedException { - String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; - String version = "1.0.0"; - String group = null; - String application = "etc-metadata-report-consumer-test"; - String revision = "90980"; - String protocol = "xxx"; - URL url = generateURL(interfaceName, version, group, application); - ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(interfaceName, version, - group, "provider", revision, protocol); - zookeeperMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url); - String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(serviceMetadataIdentifier)); - - Assertions.assertNotNull(fileContent); - - - zookeeperMetadataReport.doRemoveMetadata(serviceMetadataIdentifier); - - fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(serviceMetadataIdentifier)); - Assertions.assertNull(fileContent); - } - - @Test - public void testDoGetExportedURLs() throws ExecutionException, InterruptedException { - String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; - String version = "1.0.0"; - String group = null; - String application = "etc-metadata-report-consumer-test"; - String revision = "90980"; - String protocol = "xxx"; - URL url = generateURL(interfaceName, version, group, application); - ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(interfaceName, version, - group, "provider", revision, protocol); - zookeeperMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url); - - List r = zookeeperMetadataReport.doGetExportedURLs(serviceMetadataIdentifier); - Assertions.assertTrue(r.size() == 1); - - String fileContent = r.get(0); - Assertions.assertNotNull(fileContent); - - Assertions.assertEquals(fileContent, url.toFullString()); - } - - @Test - public void testDoSaveSubscriberData() throws ExecutionException, InterruptedException { - String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; - String version = "1.0.0"; - String group = null; - String application = "etc-metadata-report-consumer-test"; - String revision = "90980"; - String protocol = "xxx"; - URL url = generateURL(interfaceName, version, group, application); - SubscriberMetadataIdentifier subscriberMetadataIdentifier = new SubscriberMetadataIdentifier(application, revision); - Gson gson = new Gson(); - String r = gson.toJson(Arrays.asList(url)); - zookeeperMetadataReport.doSaveSubscriberData(subscriberMetadataIdentifier, r); - - String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(subscriberMetadataIdentifier)); - - Assertions.assertNotNull(fileContent); - - Assertions.assertEquals(fileContent, r); - } - - @Test - public void testDoGetSubscribedURLs() throws ExecutionException, InterruptedException { - String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; - String version = "1.0.0"; - String group = null; - String application = "etc-metadata-report-consumer-test"; - String revision = "90980"; - String protocol = "xxx"; - URL url = generateURL(interfaceName, version, group, application); - SubscriberMetadataIdentifier subscriberMetadataIdentifier = new SubscriberMetadataIdentifier(application, revision); - Gson gson = new Gson(); - String r = gson.toJson(Arrays.asList(url)); - zookeeperMetadataReport.doSaveSubscriberData(subscriberMetadataIdentifier, r); - - String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(subscriberMetadataIdentifier)); - - Assertions.assertNotNull(fileContent); - - Assertions.assertEquals(fileContent, r); - } - - - private MetadataIdentifier storePrivider(ZookeeperMetadataReport zookeeperMetadataReport, String interfaceName, String version, String group, String application) throws ClassNotFoundException, InterruptedException { - URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":4444/" + interfaceName + "?paramTest=zkTest&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()); - - zookeeperMetadataReport.storeProviderMetadata(providerMetadataIdentifier, fullServiceDefinition); - Thread.sleep(2000); - return providerMetadataIdentifier; - } - - private MetadataIdentifier storeConsumer(ZookeeperMetadataReport zookeeperMetadataReport, String interfaceName, String version, String group, String application) throws ClassNotFoundException, InterruptedException { - URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":4444/" + interfaceName + "?version=" + version + "&application=" - + application + (group == null ? "" : "&group=" + group)); - - MetadataIdentifier consumerMetadataIdentifier = new MetadataIdentifier(interfaceName, version, group, CONSUMER_SIDE, application); - Class interfaceClass = Class.forName(interfaceName); - - Map tmp = new HashMap<>(); - tmp.put("paramConsumerTest", "zkCm"); - zookeeperMetadataReport.storeConsumerMetadata(consumerMetadataIdentifier, tmp); - Thread.sleep(2000); - - return consumerMetadataIdentifier; - } - - private String waitSeconds(String value, long moreTime, String path) throws InterruptedException { - if (value == null) { - Thread.sleep(moreTime); - return zookeeperMetadataReport.zkClient.getContent(path); - } - return value; - } - - private URL generateURL(String interfaceName, String version, String group, String application) { - URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":8989/" + interfaceName + - "?paramTest=etcdTest&version=" + version + "&application=" - + application + (group == null ? "" : "&group=" + group)); - return url; - } -} +///* +// * 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.zookeeper; +// +//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.report.MetadataReport; +//import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; +//import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; +//import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; +//import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; +// +//import com.google.gson.Gson; +//import org.apache.curator.test.TestingServer; +//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 java.util.Arrays; +//import java.util.HashMap; +//import java.util.List; +//import java.util.Map; +//import java.util.concurrent.ExecutionException; +// +//import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE; +//import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; +// +///** +// * 2018/10/9 +// */ +//public class ZookeeperMetadataReportTest { +// private TestingServer zkServer; +// private MetadataReport zookeeperMetadataReport; +// private URL registryUrl; +// private ZookeeperMetadataReportFactory zookeeperMetadataReportFactory; +// +// @BeforeEach +// public void setUp() throws Exception { +// int zkServerPort = NetUtils.getAvailablePort(); +// this.zkServer = new TestingServer(zkServerPort, true); +// this.registryUrl = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort); +// +// zookeeperMetadataReportFactory = new ZookeeperMetadataReportFactory(); +// this.zookeeperMetadataReport = zookeeperMetadataReportFactory.getMetadataReport(registryUrl); +// } +// +// @AfterEach +// public void tearDown() throws Exception { +// zkServer.stop(); +// } +// +// private void deletePath(MetadataIdentifier metadataIdentifier, MetadataReport zookeeperMetadataReport) { +// String category = zookeeperMetadataReport.toRootDir() + metadataIdentifier.getUniqueKey(KeyTypeEnum.PATH); +// zookeeperMetadataReport.zkClient.delete(category); +// } +// +// @Test +// public void testStoreProvider() throws ClassNotFoundException, InterruptedException { +// String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; +// String version = "1.0.0.zk.md"; +// String group = null; +// String application = "vic.zk.md"; +// MetadataIdentifier providerMetadataIdentifier = storePrivider(zookeeperMetadataReport, interfaceName, version, group, application); +// +// String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); +// fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); +// Assertions.assertNotNull(fileContent); +// +// deletePath(providerMetadataIdentifier, zookeeperMetadataReport); +// fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); +// fileContent = waitSeconds(fileContent, 1000, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); +// Assertions.assertNull(fileContent); +// +// +// providerMetadataIdentifier = storePrivider(zookeeperMetadataReport, interfaceName, version, group, application); +// fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); +// fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); +// Assertions.assertNotNull(fileContent); +// +// Gson gson = new Gson(); +// FullServiceDefinition fullServiceDefinition = gson.fromJson(fileContent, FullServiceDefinition.class); +// Assertions.assertEquals(fullServiceDefinition.getParameters().get("paramTest"), "zkTest"); +// } +// +// +// @Test +// public void testConsumer() throws ClassNotFoundException, InterruptedException { +// String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; +// String version = "1.0.0.zk.md"; +// String group = null; +// String application = "vic.zk.md"; +// MetadataIdentifier consumerMetadataIdentifier = storeConsumer(zookeeperMetadataReport, interfaceName, version, group, application); +// +// String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); +// fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); +// Assertions.assertNotNull(fileContent); +// +// deletePath(consumerMetadataIdentifier, zookeeperMetadataReport); +// fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); +// fileContent = waitSeconds(fileContent, 1000, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); +// Assertions.assertNull(fileContent); +// +// consumerMetadataIdentifier = storeConsumer(zookeeperMetadataReport, interfaceName, version, group, application); +// fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); +// fileContent = waitSeconds(fileContent, 3000, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); +// Assertions.assertNotNull(fileContent); +// Assertions.assertEquals(fileContent, "{\"paramConsumerTest\":\"zkCm\"}"); +// } +// +// @Test +// public void testDoSaveMetadata() throws ExecutionException, InterruptedException { +// String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; +// String version = "1.0.0"; +// String group = null; +// String application = "etc-metadata-report-consumer-test"; +// String revision = "90980"; +// String protocol = "xxx"; +// URL url = generateURL(interfaceName, version, group, application); +// ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(interfaceName, version, +// group, "provider", revision, protocol); +// zookeeperMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url); +// +// String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(serviceMetadataIdentifier)); +// Assertions.assertNotNull(fileContent); +// +// Assertions.assertEquals(fileContent, URL.encode(url.toFullString())); +// } +// +// @Test +// public void testDoRemoveMetadata() throws ExecutionException, InterruptedException { +// String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; +// String version = "1.0.0"; +// String group = null; +// String application = "etc-metadata-report-consumer-test"; +// String revision = "90980"; +// String protocol = "xxx"; +// URL url = generateURL(interfaceName, version, group, application); +// ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(interfaceName, version, +// group, "provider", revision, protocol); +// zookeeperMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url); +// String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(serviceMetadataIdentifier)); +// +// Assertions.assertNotNull(fileContent); +// +// +// zookeeperMetadataReport.doRemoveMetadata(serviceMetadataIdentifier); +// +// fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(serviceMetadataIdentifier)); +// Assertions.assertNull(fileContent); +// } +// +// @Test +// public void testDoGetExportedURLs() throws ExecutionException, InterruptedException { +// String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; +// String version = "1.0.0"; +// String group = null; +// String application = "etc-metadata-report-consumer-test"; +// String revision = "90980"; +// String protocol = "xxx"; +// URL url = generateURL(interfaceName, version, group, application); +// ServiceMetadataIdentifier serviceMetadataIdentifier = new ServiceMetadataIdentifier(interfaceName, version, +// group, "provider", revision, protocol); +// zookeeperMetadataReport.doSaveMetadata(serviceMetadataIdentifier, url); +// +// List r = zookeeperMetadataReport.doGetExportedURLs(serviceMetadataIdentifier); +// Assertions.assertTrue(r.size() == 1); +// +// String fileContent = r.get(0); +// Assertions.assertNotNull(fileContent); +// +// Assertions.assertEquals(fileContent, url.toFullString()); +// } +// +// @Test +// public void testDoSaveSubscriberData() throws ExecutionException, InterruptedException { +// String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; +// String version = "1.0.0"; +// String group = null; +// String application = "etc-metadata-report-consumer-test"; +// String revision = "90980"; +// String protocol = "xxx"; +// URL url = generateURL(interfaceName, version, group, application); +// SubscriberMetadataIdentifier subscriberMetadataIdentifier = new SubscriberMetadataIdentifier(application, revision); +// Gson gson = new Gson(); +// String r = gson.toJson(Arrays.asList(url)); +// zookeeperMetadataReport.doSaveSubscriberData(subscriberMetadataIdentifier, r); +// +// String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(subscriberMetadataIdentifier)); +// +// Assertions.assertNotNull(fileContent); +// +// Assertions.assertEquals(fileContent, r); +// } +// +// @Test +// public void testDoGetSubscribedURLs() throws ExecutionException, InterruptedException { +// String interfaceName = "org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport4TstService"; +// String version = "1.0.0"; +// String group = null; +// String application = "etc-metadata-report-consumer-test"; +// String revision = "90980"; +// String protocol = "xxx"; +// URL url = generateURL(interfaceName, version, group, application); +// SubscriberMetadataIdentifier subscriberMetadataIdentifier = new SubscriberMetadataIdentifier(application, revision); +// Gson gson = new Gson(); +// String r = gson.toJson(Arrays.asList(url)); +// zookeeperMetadataReport.doSaveSubscriberData(subscriberMetadataIdentifier, r); +// +// String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(subscriberMetadataIdentifier)); +// +// Assertions.assertNotNull(fileContent); +// +// Assertions.assertEquals(fileContent, r); +// } +// +// +// private MetadataIdentifier storePrivider(MetadataReport zookeeperMetadataReport, String interfaceName, String version, String group, String application) throws ClassNotFoundException, InterruptedException { +// URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":4444/" + interfaceName + "?paramTest=zkTest&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()); +// +// zookeeperMetadataReport.storeProviderMetadata(providerMetadataIdentifier, fullServiceDefinition); +// Thread.sleep(2000); +// return providerMetadataIdentifier; +// } +// +// private MetadataIdentifier storeConsumer(MetadataReport zookeeperMetadataReport, String interfaceName, String version, String group, String application) throws ClassNotFoundException, InterruptedException { +// URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":4444/" + interfaceName + "?version=" + version + "&application=" +// + application + (group == null ? "" : "&group=" + group)); +// +// MetadataIdentifier consumerMetadataIdentifier = new MetadataIdentifier(interfaceName, version, group, CONSUMER_SIDE, application); +// Class interfaceClass = Class.forName(interfaceName); +// +// Map tmp = new HashMap<>(); +// tmp.put("paramConsumerTest", "zkCm"); +// zookeeperMetadataReport.storeConsumerMetadata(consumerMetadataIdentifier, tmp); +// Thread.sleep(2000); +// +// return consumerMetadataIdentifier; +// } +// +// private String waitSeconds(String value, long moreTime, String path) throws InterruptedException { +// if (value == null) { +// Thread.sleep(moreTime); +// return zookeeperMetadataReport.zkClient.getContent(path); +// } +// return value; +// } +// +// private URL generateURL(String interfaceName, String version, String group, String application) { +// URL url = URL.valueOf("xxx://" + NetUtils.getLocalAddress().getHostName() + ":8989/" + interfaceName + +// "?paramTest=etcdTest&version=" + version + "&application=" +// + application + (group == null ? "" : "&group=" + group)); +// return url; +// } +//} diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java index 7459da153f6..db03a3cc34d 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java @@ -22,7 +22,6 @@ import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.metadata.MetadataService; import org.apache.dubbo.metadata.ServiceNameMapping; @@ -57,12 +56,8 @@ import static java.lang.String.format; import static java.util.Collections.emptyList; -import static java.util.Collections.emptySet; -import static java.util.Collections.unmodifiableSet; -import static java.util.stream.Collectors.toSet; -import static java.util.stream.Stream.of; import static org.apache.dubbo.common.URLBuilder.from; -import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL; +import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR_CHAR; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY; @@ -71,6 +66,8 @@ import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL; import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDED_BY; import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE; @@ -79,7 +76,7 @@ import static org.apache.dubbo.common.function.ThrowableAction.execute; import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty; import static org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty; -import static org.apache.dubbo.common.utils.StringUtils.isBlank; +import static org.apache.dubbo.common.utils.StringUtils.splitToSet; import static org.apache.dubbo.metadata.MetadataService.toURLs; import static org.apache.dubbo.registry.client.ServiceDiscoveryFactory.getExtension; import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getExportedServicesRevision; @@ -107,7 +104,7 @@ * {@link ServiceNameMapping} will help to figure out one or more services that exported correlative Dubbo services. If * the service names can be found, the exported {@link URL URLs} will be get from the remote {@link MetadataService} * being deployed on all {@link ServiceInstance instances} of services. The whole process runs under the - * {@link #subscribeURLs(URL, NotifyListener, String, Collection)} method. It's very expensive to invoke + * {@link #subscribeURLs(URL, List, String, Collection)} method. It's very expensive to invoke * {@link MetadataService} for each {@link ServiceInstance service instance}, thus {@link ServiceDiscoveryRegistry} * introduces a cache to optimize the calculation with "revisions". If the revisions of N * {@link ServiceInstance service instances} are same, {@link MetadataService} is invoked just only once, and then it @@ -129,7 +126,7 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry { private final ServiceDiscovery serviceDiscovery; - private final Set subscribedServices; + private Set subscribedServices; private final ServiceNameMapping serviceNameMapping; @@ -151,7 +148,6 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry { public ServiceDiscoveryRegistry(URL registryURL) { super(registryURL); this.serviceDiscovery = createServiceDiscovery(registryURL); - this.subscribedServices = parseServices(registryURL.getParameter(SUBSCRIBED_SERVICE_NAMES_KEY)); this.serviceNameMapping = ServiceNameMapping.getDefaultExtension(); String metadataStorageType = getMetadataStorageType(registryURL); this.writableMetadataService = WritableMetadataService.getExtension(metadataStorageType); @@ -169,12 +165,7 @@ public ServiceDiscovery getServiceDiscovery() { * @return non-null */ public static Set getSubscribedServices(URL registryURL) { - String subscribedServiceNames = registryURL.getParameter(SUBSCRIBED_SERVICE_NAMES_KEY); - return isBlank(subscribedServiceNames) ? emptySet() : - unmodifiableSet(of(subscribedServiceNames.split(",")) - .map(String::trim) - .filter(StringUtils::isNotEmpty) - .collect(toSet())); + return parseServices(registryURL.getParameter(SUBSCRIBED_SERVICE_NAMES_KEY)); } /** @@ -326,28 +317,73 @@ protected void subscribeURLs(URL url, NotifyListener listener) { writableMetadataService.subscribeURL(url); Set serviceNames = getServices(url); - if (CollectionUtils.isEmpty(serviceNames)) { - throw new IllegalStateException("Should has at least one way to know which services this interface belongs to, subscription url: " + url); - } - serviceNames.forEach(serviceName -> subscribeURLs(url, listener, serviceName)); + List subscribedURLs = new LinkedList<>(); - } + serviceNames.forEach(serviceName -> { - protected void subscribeURLs(URL url, NotifyListener listener, String serviceName) { + subscribeURLs(url, subscribedURLs, serviceName); - List serviceInstances = serviceDiscovery.getInstances(serviceName); + // register ServiceInstancesChangedListener + registerServiceInstancesChangedListener(url, new ServiceInstancesChangedListener(serviceName) { - subscribeURLs(url, listener, serviceName, serviceInstances); + @Override + public void onEvent(ServiceInstancesChangedEvent event) { + List subscribedURLs = new LinkedList<>(); + Set others = new HashSet<>(serviceNames); + others.remove(serviceName); - // register ServiceInstancesChangedListener - registerServiceInstancesChangedListener(url, new ServiceInstancesChangedListener(serviceName) { + // Collect the subscribedURLs + subscribeURLs(url, subscribedURLs, serviceName, () -> event.getServiceInstances()); + subscribeURLs(url, subscribedURLs, others.toString(), () -> getServiceInstances(others)); - @Override - public void onEvent(ServiceInstancesChangedEvent event) { - subscribeURLs(url, listener, event.getServiceName(), new ArrayList<>(event.getServiceInstances())); - } + // Notify all + notifyAllSubscribedURLs(url, subscribedURLs, listener); + + } + }); }); + + // Notify all + notifyAllSubscribedURLs(url, subscribedURLs, listener); + + } + + private void notifyAllSubscribedURLs(URL url, List subscribedURLs, NotifyListener listener) { + + if (subscribedURLs.isEmpty()) { + // Add the EMPTY_PROTOCOL URL + subscribedURLs.add(from(url).setProtocol(EMPTY_PROTOCOL).removeParameter(CATEGORY_KEY).build()); + } + + // Notify all + listener.notify(subscribedURLs); + } + + private List getServiceInstances(Set serviceNames) { + if (isEmpty(serviceNames)) { + return emptyList(); + } + List allServiceInstances = new LinkedList<>(); + for (String serviceName : serviceNames) { + List serviceInstances = serviceDiscovery.getInstances(serviceName); + if (!isEmpty(serviceInstances)) { + allServiceInstances.addAll(serviceInstances); + } + } + return allServiceInstances; + } + + protected void subscribeURLs(URL subscribedURL, List subscribedURLs, + String serviceName, Supplier> serviceInstancesSupplier) { + Collection serviceInstances = serviceInstancesSupplier.get(); + subscribeURLs(subscribedURL, subscribedURLs, serviceName, serviceInstances); + } + + + protected void subscribeURLs(URL url, List subscribedURLs, String serviceName) { + List serviceInstances = serviceDiscovery.getInstances(serviceName); + subscribeURLs(url, subscribedURLs, serviceName, serviceInstances); } /** @@ -374,13 +410,13 @@ private String createListenerId(URL url, ServiceInstancesChangedListener listene * the instances of {@link SubscribedURLsSynthesizer} * * @param subscribedURL the subscribed {@link URL url} - * @param listener {@link NotifyListener} + * @param subscribedURLs {@link NotifyListener} * @param serviceName * @param serviceInstances * @see #getExportedURLs(URL, Collection) * @see #synthesizeSubscribedURLs(URL, Collection) */ - protected void subscribeURLs(URL subscribedURL, NotifyListener listener, String serviceName, + protected void subscribeURLs(URL subscribedURL, List subscribedURLs, String serviceName, Collection serviceInstances) { if (isEmpty(serviceInstances)) { @@ -388,8 +424,6 @@ protected void subscribeURLs(URL subscribedURL, NotifyListener listener, String return; } - List subscribedURLs = new LinkedList<>(); - /** * Add the exported URLs from {@link MetadataService} */ @@ -401,8 +435,6 @@ protected void subscribeURLs(URL subscribedURL, NotifyListener listener, String */ subscribedURLs.addAll(synthesizeSubscribedURLs(subscribedURL, serviceInstances)); } - - listener.notify(subscribedURLs); } /** @@ -805,9 +837,11 @@ private Collection synthesizeSubscribedURLs(URL subscribedURL, Co * * @param subscribedURL * @return + * @throws IllegalStateException If no service name is not found */ - protected Set getServices(URL subscribedURL) { - Set subscribedServices = new LinkedHashSet<>(); + protected Set getServices(URL subscribedURL) throws IllegalStateException { + + Set subscribedServices = null; String serviceNames = subscribedURL.getParameter(PROVIDED_BY); if (StringUtils.isNotEmpty(serviceNames)) { @@ -816,19 +850,21 @@ protected Set getServices(URL subscribedURL) { if (isEmpty(subscribedServices)) { subscribedServices = findMappedServices(subscribedURL); - if (isEmpty(subscribedServices)) { - subscribedServices = getSubscribedServices(); - } } + + if (isEmpty(subscribedServices)) { + subscribedServices = getSubscribedServices(); + } + + if (isEmpty(subscribedServices)) { + throw new IllegalStateException("Should has at least one way to know which services this interface belongs to, subscription url: " + subscribedURL); + } + return subscribedServices; } public static Set parseServices(String literalServices) { - return isBlank(literalServices) ? emptySet() : - unmodifiableSet(of(literalServices.split(",")) - .map(String::trim) - .filter(StringUtils::isNotEmpty) - .collect(toSet())); + return splitToSet(literalServices, COMMA_SEPARATOR_CHAR, true); } /** @@ -837,21 +873,20 @@ public static Set parseServices(String literalServices) { * @return non-null */ public Set getSubscribedServices() { + if (subscribedServices == null) { + subscribedServices = findMappedServices(getUrl()); + } return subscribedServices; } /** * Get the mapped services name by the specified {@link URL} * - * @param subscribedURL - * @return + * @param url the specified {@link URL} + * @return empty {@link Set} if not found */ - protected Set findMappedServices(URL subscribedURL) { - String serviceInterface = subscribedURL.getServiceInterface(); - String group = subscribedURL.getParameter(GROUP_KEY); - String version = subscribedURL.getParameter(VERSION_KEY); - String protocol = subscribedURL.getParameter(PROTOCOL_KEY, DUBBO_PROTOCOL); - return serviceNameMapping.get(serviceInterface, group, version, protocol); + protected Set findMappedServices(URL url) { + return serviceNameMapping.get(url); } /** diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceInstance.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceInstance.java index 0422925593a..896af9ca4ad 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceInstance.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceInstance.java @@ -82,6 +82,28 @@ default boolean isHealthy() { */ Map getMetadata(); + /** + * Get the value of metadata by the specified name + * + * @param name the specified name + * @return the value of metadata if found, or null + * @since 2.7.8 + */ + default String getMetadata(String name) { + return getMetadata(name, null); + } + + /** + * Get the value of metadata by the specified name + * + * @param name the specified name + * @return the value of metadata if found, or defaultValue + * @since 2.7.8 + */ + default String getMetadata(String name, String defaultValue) { + return getMetadata().getOrDefault(name, defaultValue); + } + /** * @return the hash code of current instance. */ diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/CustomizableServiceInstanceListener.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/CustomizableServiceInstanceListener.java index d2ee50fa856..f739ca825f2 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/CustomizableServiceInstanceListener.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/CustomizableServiceInstanceListener.java @@ -26,7 +26,9 @@ * Customize the {@link ServiceInstance} before registering to Registry. * * @since 2.7.5 + * @deprecated 2.7.8 Current class will be removed since 3.0.0 */ +@Deprecated public class CustomizableServiceInstanceListener implements EventListener { @Override diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ExportedServicesRevisionMetadataCustomizer.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ExportedServicesRevisionMetadataCustomizer.java index a356068b228..951f957ca44 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ExportedServicesRevisionMetadataCustomizer.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ExportedServicesRevisionMetadataCustomizer.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.registry.client.metadata; +import org.apache.dubbo.metadata.URLRevisionResolver; import org.apache.dubbo.metadata.WritableMetadataService; import org.apache.dubbo.registry.client.ServiceInstance; import org.apache.dubbo.registry.client.ServiceInstanceMetadataCustomizer; diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/RefreshServiceMetadataCustomizer.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/RefreshServiceMetadataCustomizer.java deleted file mode 100644 index 07b6bc7d824..00000000000 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/RefreshServiceMetadataCustomizer.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.client.metadata; - -import org.apache.dubbo.metadata.WritableMetadataService; -import org.apache.dubbo.registry.client.ServiceInstance; -import org.apache.dubbo.registry.client.ServiceInstanceCustomizer; - -import static org.apache.dubbo.metadata.WritableMetadataService.getExtension; -import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getExportedServicesRevision; -import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getMetadataStorageType; -import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getSubscribedServicesRevision; - -/** - * An {@link ServiceInstanceCustomizer} to refresh metadata. - */ -public class RefreshServiceMetadataCustomizer implements ServiceInstanceCustomizer { - - public int getPriority() { - return MIN_PRIORITY; - } - - @Override - public void customize(ServiceInstance serviceInstance) { - - String metadataStoredType = getMetadataStorageType(serviceInstance); - - WritableMetadataService writableMetadataService = getExtension(metadataStoredType); - - writableMetadataService.refreshMetadata(getExportedServicesRevision(serviceInstance), - getSubscribedServicesRevision(serviceInstance)); - } -} diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java index b66ae793fba..14c79883e8f 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java @@ -207,10 +207,10 @@ public static boolean isDubboServiceInstance(ServiceInstance serviceInstance) { || metadata.containsKey(METADATA_SERVICE_URLS_PROPERTY_NAME); } - public static void setEndpoints(ServiceInstance serviceInstance, Map protocolPortss) { + public static void setEndpoints(ServiceInstance serviceInstance, Map protocolPorts) { Map metadata = serviceInstance.getMetadata(); List endpoints = new ArrayList<>(); - protocolPortss.forEach((k, v) -> { + protocolPorts.forEach((k, v) -> { Endpoint endpoint = new Endpoint(v, k); endpoints.add(endpoint); }); diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/StandardMetadataServiceURLBuilder.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/StandardMetadataServiceURLBuilder.java index 026146e4241..216e832f5f1 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/StandardMetadataServiceURLBuilder.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/StandardMetadataServiceURLBuilder.java @@ -37,6 +37,7 @@ * @since 2.7.5 */ public class StandardMetadataServiceURLBuilder implements MetadataServiceURLBuilder { + public static final String NAME = "standard"; /** diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/SubscribedServicesRevisionMetadataCustomizer.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/SubscribedServicesRevisionMetadataCustomizer.java index fd5646b9cde..c9e6b04ab50 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/SubscribedServicesRevisionMetadataCustomizer.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/SubscribedServicesRevisionMetadataCustomizer.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.registry.client.metadata; +import org.apache.dubbo.metadata.URLRevisionResolver; import org.apache.dubbo.metadata.WritableMetadataService; import org.apache.dubbo.registry.client.ServiceInstance; import org.apache.dubbo.registry.client.ServiceInstanceMetadataCustomizer; diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/BaseMetadataServiceProxyFactory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/BaseMetadataServiceProxyFactory.java index 1e8d9fab01b..d599891bf46 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/BaseMetadataServiceProxyFactory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/BaseMetadataServiceProxyFactory.java @@ -18,21 +18,41 @@ import org.apache.dubbo.metadata.MetadataService; import org.apache.dubbo.registry.client.ServiceInstance; -import org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils; -import java.util.HashMap; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.getExportedServicesRevision; /** * base class for remote and local implementations. + * + * @since 2.7.5 */ abstract class BaseMetadataServiceProxyFactory implements MetadataServiceProxyFactory { - private final Map proxies = new HashMap<>(); + + private final ConcurrentMap proxiesCache = new ConcurrentHashMap<>(); public final MetadataService getProxy(ServiceInstance serviceInstance) { - return proxies.computeIfAbsent(serviceInstance.getServiceName() + "##" + - ServiceInstanceMetadataUtils.getExportedServicesRevision(serviceInstance), id -> createProxy(serviceInstance)); + return proxiesCache.computeIfAbsent(createProxyCacheKey(serviceInstance), id -> createProxy(serviceInstance)); + } + + /** + * Create the cache key of the proxy of {@link MetadataService} + * + * @param serviceInstance {@link ServiceInstance} + * @return non-null + * @since 2.7.8 + */ + protected String createProxyCacheKey(ServiceInstance serviceInstance) { + return serviceInstance.getServiceName() + "#" + getExportedServicesRevision(serviceInstance); } + /** + * Create the instance proxy of {@link MetadataService} + * + * @param serviceInstance {@link ServiceInstance} + * @return non-null + */ protected abstract MetadataService createProxy(ServiceInstance serviceInstance); } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/CompositeMetadataServiceProxyFactory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/CompositeMetadataServiceProxyFactory.java new file mode 100644 index 00000000000..f8c95d6fc10 --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/CompositeMetadataServiceProxyFactory.java @@ -0,0 +1,133 @@ +/* + * 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.client.metadata.proxy; + +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.metadata.MetadataService; +import org.apache.dubbo.registry.client.ServiceInstance; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static java.lang.reflect.Proxy.newProxyInstance; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; + +/** + * The composite implementation of {@link MetadataServiceProxyFactory} + * + * @since 2.7.8 + */ +public class CompositeMetadataServiceProxyFactory extends BaseMetadataServiceProxyFactory { + + private static final Logger logger = LoggerFactory.getLogger(CompositeMetadataServiceProxyFactory.class); + + @Override + public MetadataService createProxy(ServiceInstance serviceInstance) { + MetadataService metadataService = (MetadataService) newProxyInstance( + getClass().getClassLoader(), + new Class[]{MetadataService.class}, + new MetadataServiceInvocationHandler(serviceInstance, this) + ); + return metadataService; + } + + static class MetadataServiceInvocationHandler implements InvocationHandler { + + private final ServiceInstance serviceInstance; + + private final MetadataServiceProxyFactory excluded; + + private volatile List metadataServices; + + MetadataServiceInvocationHandler(ServiceInstance serviceInstance, + MetadataServiceProxyFactory excluded) { + this.serviceInstance = serviceInstance; + this.excluded = excluded; + } + + private List loadMetadataServices() { + return getExtensionLoader(MetadataServiceProxyFactory.class) + .getSupportedExtensionInstances() + .stream() + .filter(this::isRequiredFactory) + .map(this::getProxy) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + private List getMetadataServices() { + if (metadataServices == null) { + metadataServices = loadMetadataServices(); + if (metadataServices.isEmpty()) { + throw new IllegalStateException(format("No valid proxy of %s can't be loaded.", + MetadataService.class.getName())); + } + } + return metadataServices; + } + + private boolean isRequiredFactory(MetadataServiceProxyFactory factory) { + return !factory.equals(excluded); + } + + private MetadataService getProxy(MetadataServiceProxyFactory factory) { + MetadataService metadataService = null; + try { + metadataService = factory.getProxy(serviceInstance); + } catch (Exception e) { + if (logger.isErrorEnabled()) { + logger.error(format("The proxy of %s can't be gotten by %s [from : %s].", + MetadataService.class.getName(), + factory.getClass().getName(), + serviceInstance.toString())); + } + } + return metadataService; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + + if (Object.class.equals(method.getDeclaringClass())) { + return method.invoke(proxy, args); + } + + Object result = null; + + for (MetadataService metadataService : getMetadataServices()) { + try { + result = method.invoke(metadataService, args); + if (result != null) { + break; + } + } catch (Exception e) { + if (logger.isErrorEnabled()) { + logger.error(format("MetadataService[type : %s] executes failed.", metadataService.getClass().getName()), e); + } + } + } + + return result; + } + } + +} diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/MetadataServiceProxyFactory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/MetadataServiceProxyFactory.java index 14523ace0a4..e49003fbb9a 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/MetadataServiceProxyFactory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/MetadataServiceProxyFactory.java @@ -31,7 +31,6 @@ * @since 2.7.5 */ @SPI(DEFAULT_METADATA_STORAGE_TYPE) - public interface MetadataServiceProxyFactory { /** diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/RemoteMetadataServiceProxy.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/RemoteMetadataServiceProxy.java index e6bc86ddfc7..a92cafb6721 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/RemoteMetadataServiceProxy.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/proxy/RemoteMetadataServiceProxy.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.registry.client.metadata.proxy; +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.UrlUtils; @@ -23,30 +24,36 @@ import org.apache.dubbo.metadata.report.MetadataReport; import org.apache.dubbo.metadata.report.MetadataReportInstance; import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; -import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; import org.apache.dubbo.registry.client.ServiceInstance; -import org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils; -import java.util.Collection; -import java.util.Collections; +import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import static java.util.Collections.unmodifiableSortedSet; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; -import static org.apache.dubbo.registry.client.metadata.URLRevisionResolver.NO_REVISION; +import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.metadata.URLRevisionResolver.UNKNOWN_REVISION; +import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME; +/** + * The proxy of {@link MetadataService} is based on {@link MetadataReport} + * + * @since 2.7.5 + */ public class RemoteMetadataServiceProxy implements MetadataService { + protected final Logger logger = LoggerFactory.getLogger(getClass()); - private String serviceName; - private String revision; + private final String serviceName; + private final String revision; public RemoteMetadataServiceProxy(ServiceInstance serviceInstance) { this.serviceName = serviceInstance.getServiceName(); // this is ServiceInstance of registry(Provider) - this.revision = serviceInstance.getMetadata() - .getOrDefault(ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME, NO_REVISION); + this.revision = serviceInstance.getMetadata(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, UNKNOWN_REVISION); } @Override @@ -56,12 +63,23 @@ public String serviceName() { @Override public SortedSet getExportedURLs(String serviceInterface, String group, String version, String protocol) { - return toSortedStrings(getMetadataReport().getExportedURLs( - new ServiceMetadataIdentifier(serviceInterface, group, version, PROVIDER_SIDE, revision, protocol))); - } - private static SortedSet toSortedStrings(Collection values) { - return Collections.unmodifiableSortedSet(new TreeSet<>(values)); + SortedSet exportedURLs = getMetadataReport().getExportedURLs(serviceName, revision); + if (ALL_SERVICE_INTERFACES.equals(serviceInterface)) { + return exportedURLs; + } + + return unmodifiableSortedSet( + exportedURLs + .stream() + .map(URL::valueOf) + .filter(url -> serviceInterface == null || serviceInterface.equals(url.getServiceInterface())) + .filter(url -> group == null || group.equals(url.getParameter(GROUP_KEY))) + .filter(url -> version == null || version.equals(url.getParameter(VERSION_KEY))) + .filter(url -> protocol == null || protocol.equals(url.getProtocol())) + .map(URL::toFullString) + .collect(TreeSet::new, Set::add, Set::addAll) + ); } @Override @@ -71,8 +89,8 @@ public String getServiceDefinition(String interfaceName, String version, String } @Override - public String getServiceDefinition(String serviceKey) { - String[] services = UrlUtils.parseServiceKey(serviceKey); + public String getServiceDefinition(String serviceDefinitionKey) { + String[] services = UrlUtils.parseServiceKey(serviceDefinitionKey); String serviceInterface = services[0]; // if version or group is not exist String version = null; @@ -90,6 +108,4 @@ public String getServiceDefinition(String serviceKey) { MetadataReport getMetadataReport() { return MetadataReportInstance.getMetadataReport(true); } - - } diff --git a/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener index 729e8a510ac..a7fb58de0e8 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener +++ b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.event.EventListener @@ -1,2 +1,4 @@ -service-instance=org.apache.dubbo.registry.client.event.listener.CustomizableServiceInstanceListener -registry-logging=org.apache.dubbo.registry.client.event.listener.LoggingEventListener \ No newline at end of file +# "service-instance" has been deprecated since 2.7.8 +# service-instance=org.apache.dubbo.registry.client.event.listener.CustomizableServiceInstanceListener + +registry-logging=org.apache.dubbo.registry.client.event.listener.LoggingEventListener diff --git a/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceInstanceCustomizer b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceInstanceCustomizer index 3451e0014b8..9307410ac49 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceInstanceCustomizer +++ b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceInstanceCustomizer @@ -1,6 +1,5 @@ metadata-url=org.apache.dubbo.registry.client.metadata.MetadataServiceURLParamsMetadataCustomizer exported-revision=org.apache.dubbo.registry.client.metadata.ExportedServicesRevisionMetadataCustomizer -subscribe-revision=org.apache.dubbo.registry.client.metadata.SubscribedServicesRevisionMetadataCustomizer -refresh=org.apache.dubbo.registry.client.metadata.RefreshServiceMetadataCustomizer +subscribed-revision=org.apache.dubbo.registry.client.metadata.SubscribedServicesRevisionMetadataCustomizer protocol-ports=org.apache.dubbo.registry.client.metadata.ProtocolPortsMetadataCustomizer instance-port=org.apache.dubbo.config.metadata.ServiceInstancePortCustomizer diff --git a/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory index d9283dec444..a42e022abb1 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory +++ b/dubbo-registry/dubbo-registry-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory @@ -1,2 +1,3 @@ local=org.apache.dubbo.registry.client.metadata.proxy.DefaultMetadataServiceProxyFactory -remote=org.apache.dubbo.registry.client.metadata.proxy.RemoteMetadataServiceProxyFactory \ No newline at end of file +remote=org.apache.dubbo.registry.client.metadata.proxy.RemoteMetadataServiceProxyFactory +composite = org.apache.dubbo.registry.client.metadata.proxy.CompositeMetadataServiceProxyFactory \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/DefaultServiceInstanceTest.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/DefaultServiceInstanceTest.java index e55b223bf6f..85b63de95dc 100644 --- a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/DefaultServiceInstanceTest.java +++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/DefaultServiceInstanceTest.java @@ -20,8 +20,11 @@ import org.junit.jupiter.api.Test; import static java.lang.String.valueOf; +import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_URLS_PROPERTY_NAME; +import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -64,4 +67,10 @@ public void testSetAndGetValues() { assertFalse(instance.isHealthy()); assertFalse(instance.getMetadata().isEmpty()); } + + @Test + public void testGetMetadata() { + assertNotNull(instance.getMetadata(METADATA_SERVICE_URLS_PROPERTY_NAME)); + assertNotNull(instance.getMetadata(METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME)); + } } diff --git a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/BaseMetadataServiceProxyFactoryTest.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/BaseMetadataServiceProxyFactoryTest.java new file mode 100644 index 00000000000..6aca4c64eff --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/BaseMetadataServiceProxyFactoryTest.java @@ -0,0 +1,78 @@ +/* + * 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.client.metadata.proxy; + +import org.apache.dubbo.metadata.MetadataService; +import org.apache.dubbo.registry.client.DefaultServiceInstance; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static java.lang.String.valueOf; +import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; + +/** + * {@link BaseMetadataServiceProxyFactory} Test-Cases + * + * @since 2.7.8 + */ +public class BaseMetadataServiceProxyFactoryTest { + + private MyMetadataServiceProxyFactory factory; + + private DefaultServiceInstance instance; + + @BeforeEach + public void init() { + factory = new MyMetadataServiceProxyFactory(); + instance = createServiceInstance(); + } + + private DefaultServiceInstance createServiceInstance() { + DefaultServiceInstance serviceInstance = new DefaultServiceInstance(valueOf(System.nanoTime()), "A", "127.0.0.1", 8080); + Map metadata = new HashMap<>(); + metadata.put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, "X"); + serviceInstance.setMetadata(metadata); + return serviceInstance; + } + + @Test + public void testCreateProxyCacheKey() { + assertEquals("A#X", factory.createProxyCacheKey(instance)); + } + + @Test + public void testCreateProxy() { + MetadataService metadataService = factory.createProxy(instance); + MetadataService metadataService2 = factory.createProxy(instance); + assertNotSame(metadataService, metadataService2); + } + + @Test + public void testGetProxy() { + MetadataService metadataService = factory.getProxy(instance); + MetadataService metadataService2 = factory.getProxy(instance); + assertSame(metadataService, metadataService2); + } + +} diff --git a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/CompositeMetadataServiceProxyFactoryTest.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/CompositeMetadataServiceProxyFactoryTest.java new file mode 100644 index 00000000000..ddd78e04b04 --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/CompositeMetadataServiceProxyFactoryTest.java @@ -0,0 +1,96 @@ +/* + * 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.client.metadata.proxy; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.metadata.MetadataService; +import org.apache.dubbo.metadata.report.MetadataReportInstance; +import org.apache.dubbo.registry.client.DefaultServiceInstance; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.SortedSet; + +import static java.lang.String.valueOf; +import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.COMPOSITE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.metadata.report.support.Constants.SYNC_REPORT_KEY; +import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME; +import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link CompositeMetadataServiceProxyFactory} Test-Cases + * + * @since 2.7.8 + */ +public class CompositeMetadataServiceProxyFactoryTest { + + private static final URL METADATA_REPORT_URL = URL.valueOf("file://") + .addParameter(APPLICATION_KEY, "test") + .addParameter(SYNC_REPORT_KEY, "true"); + + private static final String APP_NAME = "test-service"; + + private MetadataServiceProxyFactory factory; + + private DefaultServiceInstance instance; + + @BeforeEach + public void init() { + ApplicationModel.getConfigManager().setApplication(new ApplicationConfig(APP_NAME)); + MetadataReportInstance.init(METADATA_REPORT_URL); + factory = MetadataServiceProxyFactory.getExtension(COMPOSITE_METADATA_STORAGE_TYPE); + instance = createServiceInstance(); + } + + @AfterEach + public void reset() throws Exception { + ApplicationModel.reset(); + MetadataReportInstance.getMetadataReport().close(); + } + + private DefaultServiceInstance createServiceInstance() { + DefaultServiceInstance serviceInstance = new DefaultServiceInstance(valueOf(System.nanoTime()), "A", "127.0.0.1", 8080); + Map metadata = new HashMap<>(); + metadata.put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, "X"); + metadata.put(METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME, "{\"dubbo\":{\"application\":\"dubbo-provider-demo\",\"deprecated\":\"false\",\"group\":\"dubbo-provider-demo\",\"version\":\"1.0.0\",\"timestamp\":\"1564845042651\",\"dubbo\":\"2.0.2\",\"host\":\"192.168.0.102\",\"port\":\"20880\"}}"); + serviceInstance.setMetadata(metadata); + return serviceInstance; + } + + @Test + public void testGetProxy() { + MetadataService metadataService = factory.getProxy(instance); + MetadataService metadataService2 = factory.getProxy(instance); + assertSame(metadataService, metadataService2); + } + + @Test + public void testGetExportedURLs() { + MetadataService metadataService = factory.getProxy(instance); + SortedSet exportedURLs = metadataService.getExportedURLs(); + assertTrue(exportedURLs.isEmpty()); + } +} diff --git a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/MetadataServiceProxyFactoryTest.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/MetadataServiceProxyFactoryTest.java new file mode 100644 index 00000000000..2c31c225947 --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/MetadataServiceProxyFactoryTest.java @@ -0,0 +1,49 @@ +/* + * 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.client.metadata.proxy; + +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.constants.CommonConstants.COMPOSITE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory.getDefaultExtension; +import static org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory.getExtension; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link MetadataServiceProxyFactory} Test-Cases + * + * @since 2.7.8 + */ +public class MetadataServiceProxyFactoryTest { + + @Test + public void testExtension() { + MetadataServiceProxyFactory defaultFactory = getDefaultExtension(); + MetadataServiceProxyFactory factory = getExtension(DEFAULT_METADATA_STORAGE_TYPE); + assertEquals(defaultFactory, factory); + + assertEquals(MyMetadataServiceProxyFactory.class, factory.getClass()); + + factory = getExtension(REMOTE_METADATA_STORAGE_TYPE); + assertEquals(RemoteMetadataServiceProxyFactory.class, factory.getClass()); + + factory = getExtension(COMPOSITE_METADATA_STORAGE_TYPE); + assertEquals(CompositeMetadataServiceProxyFactory.class, factory.getClass()); + } +} diff --git a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/MyMetadataServiceProxyFactory.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/MyMetadataServiceProxyFactory.java new file mode 100644 index 00000000000..86247e1155c --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/proxy/MyMetadataServiceProxyFactory.java @@ -0,0 +1,29 @@ +/* + * 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.client.metadata.proxy; + +import org.apache.dubbo.metadata.MetadataService; +import org.apache.dubbo.metadata.store.InMemoryWritableMetadataService; +import org.apache.dubbo.registry.client.ServiceInstance; + +public class MyMetadataServiceProxyFactory extends BaseMetadataServiceProxyFactory { + + @Override + protected MetadataService createProxy(ServiceInstance serviceInstance) { + return new InMemoryWritableMetadataService(); + } +} diff --git a/dubbo-registry/dubbo-registry-api/src/test/resources/META-INF/dubbo/org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory b/dubbo-registry/dubbo-registry-api/src/test/resources/META-INF/dubbo/org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory new file mode 100644 index 00000000000..6d2b9dd19c0 --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/test/resources/META-INF/dubbo/org.apache.dubbo.registry.client.metadata.proxy.MetadataServiceProxyFactory @@ -0,0 +1,2 @@ +# Override "local" implementation +local=org.apache.dubbo.registry.client.metadata.proxy.MyMetadataServiceProxyFactory \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulParameter.java b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulParameter.java new file mode 100644 index 00000000000..f3fb024c9ce --- /dev/null +++ b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulParameter.java @@ -0,0 +1,87 @@ +/* + * 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.consul; + +import org.apache.dubbo.common.URL; + +import static org.apache.dubbo.common.utils.StringUtils.isBlank; + +/** + * The enumeration for the Consul's parameters on the {@link URL} + * + * @see URL#getParameters() + * @since 2.7.8 + */ +public enum ConsulParameter { + + ACL_TOKEN, + + TAGS, + + INSTANCE_ZONE, + + DEFAULT_ZONE_METADATA_NAME("zone"), + + INSTANCE_GROUP, + + CONSISTENCY_MODE, + + ; + + private final String name; + + private final String defaultValue; + + ConsulParameter() { + this(null); + } + + ConsulParameter(String defaultValue) { + this(null, defaultValue); + } + + ConsulParameter(String name, String defaultValue) { + this.name = isBlank(name) ? defaultName() : name; + this.defaultValue = defaultValue; + } + + private String defaultName() { + return name().toLowerCase().replace('_', '-'); + } + + /** + * The parameter value from the specified registry {@link URL} + * + * @param registryURL the specified registry {@link URL} + * @return defaultValue if not found + */ + public String getValue(URL registryURL) { + return registryURL.getParameter(name, defaultValue); + } + + /** + * The parameter value from the specified registry {@link URL} + * + * @param registryURL the specified registry {@link URL} + * @param valueType the type of parameter value + * @param defaultValue the default value if parameter is absent + * @return defaultValue if not found + */ + public T getValue(URL registryURL, Class valueType, T defaultValue) { + return registryURL.getParameter(name, valueType, defaultValue); + } +} diff --git a/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java index 5d5e98b7973..b05f1d83614 100644 --- a/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java @@ -29,10 +29,12 @@ import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent; import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener; +import com.ecwid.consul.v1.ConsistencyMode; import com.ecwid.consul.v1.ConsulClient; import com.ecwid.consul.v1.QueryParams; import com.ecwid.consul.v1.Response; import com.ecwid.consul.v1.agent.model.NewService; +import com.ecwid.consul.v1.catalog.CatalogServicesRequest; import com.ecwid.consul.v1.health.HealthServicesRequest; import com.ecwid.consul.v1.health.model.HealthService; @@ -41,6 +43,7 @@ import java.util.Base64; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -53,6 +56,7 @@ import java.util.stream.Collectors; import static java.util.concurrent.Executors.newCachedThreadPool; +import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR_CHAR; import static org.apache.dubbo.common.constants.CommonConstants.SEMICOLON_SPLIT_PATTERN; import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.CHECK_PASS_INTERVAL; import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_CHECK_PASS_INTERVAL; @@ -61,6 +65,12 @@ import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_WATCH_TIMEOUT; import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEREGISTER_AFTER; import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.WATCH_TIMEOUT; +import static org.apache.dubbo.registry.consul.ConsulParameter.ACL_TOKEN; +import static org.apache.dubbo.registry.consul.ConsulParameter.CONSISTENCY_MODE; +import static org.apache.dubbo.registry.consul.ConsulParameter.DEFAULT_ZONE_METADATA_NAME; +import static org.apache.dubbo.registry.consul.ConsulParameter.INSTANCE_GROUP; +import static org.apache.dubbo.registry.consul.ConsulParameter.INSTANCE_ZONE; +import static org.apache.dubbo.registry.consul.ConsulParameter.TAGS; /** * 2019-07-31 @@ -82,6 +92,25 @@ public class ConsulServiceDiscovery implements ServiceDiscovery, EventListener tags; + + private ConsistencyMode consistencyMode; + + private String defaultZoneMetadataName; + + /** + * Service instance zone. + */ + private String instanceZone; + + /** + * Service instance group. + */ + private String instanceGroup; + + @Override public void onEvent(ServiceInstancesChangedEvent event) { @@ -97,6 +126,39 @@ public void initialize(URL registryURL) throws Exception { ttlScheduler = new TtlScheduler(checkPassInterval, client); this.tag = registryURL.getParameter(QUERY_TAG); this.registeringTags.addAll(getRegisteringTags(url)); + this.aclToken = ACL_TOKEN.getValue(registryURL); + this.tags = getTags(registryURL); + this.consistencyMode = getConsistencyMode(registryURL); + this.defaultZoneMetadataName = DEFAULT_ZONE_METADATA_NAME.getValue(registryURL); + this.instanceZone = INSTANCE_ZONE.getValue(registryURL); + this.instanceGroup = INSTANCE_GROUP.getValue(registryURL); + } + + /** + * Get the {@link ConsistencyMode} + * + * @param registryURL the {@link URL} of registry + * @return non-null, {@link ConsistencyMode#DEFAULT} as default + * @sine 2.7.8 + */ + private ConsistencyMode getConsistencyMode(URL registryURL) { + String value = CONSISTENCY_MODE.getValue(registryURL); + if (StringUtils.isNotEmpty(value)) { + return ConsistencyMode.valueOf(value); + } + return ConsistencyMode.DEFAULT; + } + + /** + * Get the "tags" from the {@link URL} of registry + * + * @param registryURL the {@link URL} of registry + * @return non-null + * @sine 2.7.8 + */ + private List getTags(URL registryURL) { + String value = TAGS.getValue(registryURL); + return StringUtils.splitToList(value, COMMA_SEPARATOR_CHAR); } private List getRegisteringTags(URL url) { @@ -122,7 +184,7 @@ public void destroy() { public void register(ServiceInstance serviceInstance) throws RuntimeException { NewService consulService = buildService(serviceInstance); ttlScheduler.add(consulService.getId()); - client.agentServiceRegister(consulService); + client.agentServiceRegister(consulService, aclToken); } @Override @@ -146,12 +208,16 @@ public void update(ServiceInstance serviceInstance) throws RuntimeException { public void unregister(ServiceInstance serviceInstance) throws RuntimeException { String id = buildId(serviceInstance); ttlScheduler.remove(id); - client.agentServiceDeregister(id); + client.agentServiceDeregister(id, aclToken); } @Override public Set getServices() { - return null; + CatalogServicesRequest request = CatalogServicesRequest.newBuilder() + .setQueryParams(QueryParams.DEFAULT) + .setToken(aclToken) + .build(); + return this.client.getCatalogServices(request).getValue().keySet(); } @Override @@ -231,7 +297,6 @@ private NewService buildService(ServiceInstance serviceInstance) { service.setName(serviceInstance.getServiceName()); service.setCheck(buildCheck(serviceInstance)); service.setTags(buildTags(serviceInstance)); -// service.setMeta(buildMetadata(serviceInstance)); return service; } @@ -240,10 +305,21 @@ private String buildId(ServiceInstance serviceInstance) { } private List buildTags(ServiceInstance serviceInstance) { + List tags = new LinkedList<>(this.tags); + + if (StringUtils.isNotEmpty(instanceZone)) { + tags.add(defaultZoneMetadataName + "=" + instanceZone); + } + + if (StringUtils.isNotEmpty(instanceGroup)) { + tags.add("group=" + instanceGroup); + } + Map params = serviceInstance.getMetadata(); - List tags = params.keySet().stream() + params.keySet().stream() .map(k -> k + "=" + params.get(k)) - .collect(Collectors.toList()); + .forEach(tags::add); + tags.addAll(registeringTags); return tags; } @@ -281,7 +357,6 @@ private NewService.Check buildCheck(ServiceInstance serviceInstance) { check.setTtl((checkPassInterval / 1000) + "s"); String deregister = serviceInstance.getMetadata().get(DEREGISTER_AFTER); check.setDeregisterCriticalServiceAfter(deregister == null ? DEFAULT_DEREGISTER_TIME : deregister); - return check; } diff --git a/dubbo-registry/dubbo-registry-consul/src/test/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryTest.java b/dubbo-registry/dubbo-registry-consul/src/test/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryTest.java index e106248fa33..9f10d0ab16b 100644 --- a/dubbo-registry/dubbo-registry-consul/src/test/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryTest.java +++ b/dubbo-registry/dubbo-registry-consul/src/test/java/org/apache/dubbo/registry/consul/ConsulServiceDiscoveryTest.java @@ -16,12 +16,13 @@ */ package org.apache.dubbo.registry.consul; -import com.pszymczyk.consul.ConsulProcess; -import com.pszymczyk.consul.ConsulStarterBuilder; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.registry.client.DefaultServiceInstance; import org.apache.dubbo.registry.client.ServiceInstance; + +import com.pszymczyk.consul.ConsulProcess; +import com.pszymczyk.consul.ConsulStarterBuilder; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -36,9 +37,9 @@ public class ConsulServiceDiscoveryTest { - private static ConsulProcess consul; private URL url; - static ConsulServiceDiscovery consulServiceDiscovery; + private ConsulServiceDiscovery consulServiceDiscovery; + private ConsulProcess consul; private static final String SERVICE_NAME = "A"; private static final String LOCALHOST = "127.0.0.1"; @@ -49,7 +50,6 @@ public void init() throws Exception { .start(); url = URL.valueOf("consul://localhost:" + consul.getHttpPort()); consulServiceDiscovery = new ConsulServiceDiscovery(); - Assertions.assertNull(consulServiceDiscovery.getServices()); consulServiceDiscovery.initialize(url); } @@ -60,7 +60,7 @@ public void close() { } @Test - public void testRegistration() throws InterruptedException{ + public void testRegistration() throws InterruptedException { DefaultServiceInstance serviceInstance = createServiceInstance(SERVICE_NAME, LOCALHOST, NetUtils.getAvailablePort()); consulServiceDiscovery.register(serviceInstance); Thread.sleep(5000); @@ -94,8 +94,8 @@ public void testGetInstances() throws Exception { Thread.sleep(5000); Assertions.assertFalse(consulServiceDiscovery.getInstances(serviceName).isEmpty()); List r = convertToIpPort(consulServiceDiscovery.getInstances(serviceName)); - assertTrue(r.contains("127.0.0.1:"+portA)); - assertTrue(r.contains("127.0.0.1:"+portB)); + assertTrue(r.contains("127.0.0.1:" + portA)); + assertTrue(r.contains("127.0.0.1:" + portB)); } private List convertToIpPort(List serviceInstances) { diff --git a/dubbo-registry/dubbo-registry-eureka/src/main/java/org/apache/dubbo/registry/eureka/EurekaServiceDiscovery.java b/dubbo-registry/dubbo-registry-eureka/src/main/java/org/apache/dubbo/registry/eureka/EurekaServiceDiscovery.java index bb49c100ecd..516c9e55848 100644 --- a/dubbo-registry/dubbo-registry-eureka/src/main/java/org/apache/dubbo/registry/eureka/EurekaServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-eureka/src/main/java/org/apache/dubbo/registry/eureka/EurekaServiceDiscovery.java @@ -46,9 +46,8 @@ import java.util.Set; import static java.util.Collections.emptyList; -import static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY; import static org.apache.dubbo.event.EventDispatcher.getDefaultExtension; -import static org.apache.dubbo.registry.client.ServiceDiscoveryRegistry.parseServices; +import static org.apache.dubbo.registry.client.ServiceDiscoveryRegistry.getSubscribedServices; /** * Eureka {@link ServiceDiscovery} implementation based on Eureka API @@ -100,7 +99,7 @@ private Properties buildEurekaConfigProperties(URL registryURL) { * @param registryURL the {@link URL url} to connect Eureka */ private void initSubscribedServices(URL registryURL) { - this.subscribedServices = parseServices(registryURL.getParameter(SUBSCRIBED_SERVICE_NAMES_KEY)); + this.subscribedServices = getSubscribedServices(registryURL); } private boolean filterEurekaProperty(Map.Entry propertyEntry) { diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java index 9c4f1b84828..b301a784e5b 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.remoting.transport.netty4; -import io.netty.channel.socket.SocketChannel; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -37,6 +36,7 @@ import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; +import io.netty.channel.socket.SocketChannel; import io.netty.handler.timeout.IdleStateHandler; import java.net.InetSocketAddress; diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java index b34245aadbd..380b2c3c40e 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java @@ -25,8 +25,6 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; public class RpcContextTest { diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/ArgumentCallbackTest.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/ArgumentCallbackTest.java index c3ccb331168..4bc08005a1b 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/ArgumentCallbackTest.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/ArgumentCallbackTest.java @@ -16,27 +16,28 @@ */ package org.apache.dubbo.rpc.protocol.dubbo; -import static org.apache.dubbo.common.constants.CommonConstants.CALLBACK_INSTANCES_LIMIT_KEY; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.remoting.Constants; import org.apache.dubbo.rpc.Exporter; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.protocol.dubbo.support.ProtocolUtils; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.apache.dubbo.remoting.Constants; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import static org.apache.dubbo.common.constants.CommonConstants.CALLBACK_INSTANCES_LIMIT_KEY; public class ArgumentCallbackTest {