diff --git a/dubbo-bootstrap/pom.xml b/dubbo-bootstrap/pom.xml index 17df1344ef..e38e05d207 100644 --- a/dubbo-bootstrap/pom.xml +++ b/dubbo-bootstrap/pom.xml @@ -90,6 +90,12 @@ test + + org.apache.curator + curator-test + test + + \ No newline at end of file diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java deleted file mode 100644 index 23934f0740..0000000000 --- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java +++ /dev/null @@ -1,127 +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.bootstrap; - -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.MonitorConfig; -import org.apache.dubbo.config.builders.ApplicationBuilder; - -import java.util.Map; - -/** - * {@link ApplicationConfig Application} settings - * - * @since 2.7.4 - */ -public class ApplicationSettings extends AbstractSettings { - - private final ApplicationBuilder builder; - - public ApplicationSettings(ApplicationBuilder builder, DubboBootstrap dubboBootstrap) { - super(dubboBootstrap); - this.builder = builder; - } - - public ApplicationSettings version(String version) { - builder.version(version); - return this; - } - - public ApplicationSettings owner(String owner) { - builder.owner(owner); - return this; - } - - public ApplicationSettings organization(String organization) { - builder.organization(organization); - return this; - } - - public ApplicationSettings architecture(String architecture) { - builder.architecture(architecture); - return this; - } - - public ApplicationSettings environment(String environment) { - builder.environment(environment); - return this; - } - - public ApplicationSettings compiler(String compiler) { - builder.compiler(compiler); - return this; - } - - public ApplicationSettings logger(String logger) { - builder.logger(logger); - return this; - } - - public ApplicationSettings monitor(MonitorConfig monitor) { - builder.monitor(monitor); - return this; - } - - public ApplicationSettings monitor(String monitor) { - builder.monitor(monitor); - return this; - } - - public ApplicationSettings isDefault(Boolean isDefault) { - builder.isDefault(isDefault); - return this; - } - - public ApplicationSettings dumpDirectory(String dumpDirectory) { - builder.dumpDirectory(dumpDirectory); - return this; - } - - public ApplicationSettings qosEnable(Boolean qosEnable) { - builder.qosEnable(qosEnable); - return this; - } - - public ApplicationSettings qosPort(Integer qosPort) { - builder.qosPort(qosPort); - return this; - } - - public ApplicationSettings qosAcceptForeignIp(Boolean qosAcceptForeignIp) { - builder.qosAcceptForeignIp(qosAcceptForeignIp); - return this; - } - - public ApplicationSettings shutwait(String shutwait) { - builder.shutwait(shutwait); - return this; - } - - public ApplicationSettings appendParameter(String key, String value) { - builder.appendParameter(key, value); - return this; - } - - public ApplicationSettings appendParameters(Map appendParameters) { - builder.appendParameters(appendParameters); - return this; - } - - ApplicationConfig build() { - return builder.build(); - } -} diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java index d20e3e0d02..6a2237fa23 100644 --- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java +++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java @@ -19,14 +19,11 @@ package org.apache.dubbo.bootstrap; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.Environment; import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; -import org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory; import org.apache.dubbo.common.config.configcenter.wrapper.CompositeDynamicConfiguration; import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.extension.ExtensionLoader; 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.config.AbstractConfig; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ConfigCenterConfig; @@ -59,7 +56,7 @@ import org.apache.dubbo.registry.support.ServiceOrientedRegistry; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -71,9 +68,13 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.stream.Collectors; +import static java.util.Arrays.asList; import static java.util.concurrent.Executors.newSingleThreadExecutor; import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties; +import static org.apache.dubbo.common.config.configcenter.DynamicConfiguration.getDynamicConfiguration; import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; +import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; +import static org.apache.dubbo.config.context.ConfigManager.getInstance; import static org.apache.dubbo.registry.support.AbstractRegistryFactory.getRegistries; /** @@ -91,6 +92,10 @@ public class DubboBootstrap { public static final String DEFAULT_REFERENCE_ID = "REFERENCE#DEFAULT"; + public static final String DEFAULT_PROVIDER_ID = "PROVIDER#DEFAULT"; + + public static final String DEFAULT_CONSUMER_ID = "CONSUMER#DEFAULT"; + private static final String NAME = DubboBootstrap.class.getSimpleName(); private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -105,6 +110,8 @@ public class DubboBootstrap { private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension(); + private final ConfigManager configManager = getInstance(); + /** * Is provider or not */ @@ -121,20 +128,6 @@ public class DubboBootstrap { private ServiceInstance serviceInstance; - private ApplicationBuilder applicationBuilder; - - private ConsumerBuilder consumerBuilder; - - private ProviderBuilder providerBuilder; - - private Map registryBuilders = new HashMap<>(); - - private Map protocolBuilders = new HashMap<>(); - - private Map> serviceBuilders = new HashMap<>(); - - private Map> referenceBuilders = new HashMap<>(); - public DubboBootstrap() { DubboShutdownHook.getDubboShutdownHook().register(); } @@ -150,96 +143,205 @@ public class DubboBootstrap { return this; } - /* accept Config instance */ - public DubboBootstrap application(ApplicationConfig applicationConfig) { - ConfigManager.getInstance().setApplication(applicationConfig); - return this; - } - - public DubboBootstrap configCenter(ConfigCenterConfig configCenterConfig) { - ConfigManager.getInstance().addConfigCenter(configCenterConfig); - return this; - } - - public DubboBootstrap configCenter(List configCenterConfigs) { - ConfigManager.getInstance().addConfigCenter(configCenterConfigs); - return this; - } - public DubboBootstrap metadataReport(MetadataReportConfig metadataReportConfig) { - ConfigManager.getInstance().addMetadataReport(metadataReportConfig); + configManager.addMetadataReport(metadataReportConfig); return this; } public DubboBootstrap metadataReport(List metadataReportConfigs) { - ConfigManager.getInstance().addMetadataReport(metadataReportConfigs); + configManager.addMetadataReports(metadataReportConfigs); return this; } + // {@link ApplicationConfig} correlative methods + + /** + * Set the name of application + * + * @param name the name of application + * @return current {@link DubboBootstrap} instance + */ + public DubboBootstrap application(String name) { + return application(name, builder -> { + // DO NOTHING + }); + } + + /** + * Set the name of application and it's future build + * + * @param name the name of application + * @param consumerBuilder {@link ApplicationBuilder} + * @return current {@link DubboBootstrap} instance + */ + public DubboBootstrap application(String name, Consumer consumerBuilder) { + ApplicationBuilder builder = createApplicationBuilder(name); + consumerBuilder.accept(builder); + return application(builder.build()); + } + + /** + * Set the {@link ApplicationConfig} + * + * @param applicationConfig the {@link ApplicationConfig} + * @return current {@link DubboBootstrap} instance + */ + public DubboBootstrap application(ApplicationConfig applicationConfig) { + configManager.setApplication(applicationConfig); + return this; + } + + // {@link RegistryConfig} correlative methods + + /** + * Add an instance of {@link RegistryConfig} with {@link #DEFAULT_REGISTRY_ID default ID} + * + * @param consumerBuilder the {@link Consumer} of {@link RegistryBuilder} + * @return current {@link DubboBootstrap} instance + */ + public DubboBootstrap registry(Consumer consumerBuilder) { + return registry(DEFAULT_REGISTRY_ID, consumerBuilder); + } + + /** + * Add an instance of {@link RegistryConfig} with the specified ID + * + * @param id the {@link RegistryConfig#getId() id} of {@link RegistryConfig} + * @param consumerBuilder the {@link Consumer} of {@link RegistryBuilder} + * @return current {@link DubboBootstrap} instance + */ + public DubboBootstrap registry(String id, Consumer consumerBuilder) { + RegistryBuilder builder = createRegistryBuilder(id); + consumerBuilder.accept(builder); + return registry(builder.build()); + } + + /** + * Add an instance of {@link RegistryConfig} + * + * @param registryConfig an instance of {@link RegistryConfig} + * @return current {@link DubboBootstrap} instance + */ public DubboBootstrap registry(RegistryConfig registryConfig) { - ConfigManager.getInstance().addRegistry(registryConfig, true); + configManager.addRegistry(registryConfig); return this; } - public DubboBootstrap registry(List registryConfigs) { - ConfigManager.getInstance().addRegistries(registryConfigs, true); + /** + * Add an instance of {@link RegistryConfig} + * + * @param registryConfigs the multiple instances of {@link RegistryConfig} + * @return current {@link DubboBootstrap} instance + */ + public DubboBootstrap registries(Iterable registryConfigs) { + registryConfigs.forEach(this::registry); return this; } + // {@link ProtocolConfig} correlative methods + + public DubboBootstrap protocol(Consumer consumerBuilder) { + return protocol(DEFAULT_PROTOCOL_ID, consumerBuilder); + } + + public DubboBootstrap protocol(String id, Consumer consumerBuilder) { + ProtocolBuilder builder = createProtocolBuilder(id); + consumerBuilder.accept(builder); + return protocol(builder.build()); + } + public DubboBootstrap protocol(ProtocolConfig protocolConfig) { - ConfigManager.getInstance().addProtocol(protocolConfig, true); - return this; + return protocols(asList(protocolConfig)); } public DubboBootstrap protocols(List protocolConfigs) { - ConfigManager.getInstance().addProtocols(protocolConfigs, true); + configManager.addProtocols(protocolConfigs, true); return this; } - public DubboBootstrap consumer(ConsumerConfig consumerConfig) { - ConfigManager.getInstance().addConsumer(consumerConfig); - return this; + // {@link ServiceConfig} correlative methods + + public DubboBootstrap service(Consumer> consumerBuilder) { + return service(DEFAULT_SERVICE_ID, consumerBuilder); } - public DubboBootstrap provider(ProviderConfig providerConfig) { - ConfigManager.getInstance().addProvider(providerConfig); - return this; + public DubboBootstrap service(String id, Consumer> consumerBuilder) { + ServiceBuilder builder = createServiceBuilder(id); + consumerBuilder.accept(builder); + return service(builder.build()); } public DubboBootstrap service(ServiceConfig serviceConfig) { - ConfigManager.getInstance().addService(serviceConfig); + configManager.addService(serviceConfig); return this; } + // {@link Reference} correlative methods + + public DubboBootstrap reference(Consumer> consumerBuilder) { + return reference(DEFAULT_REFERENCE_ID, consumerBuilder); + } + + public DubboBootstrap reference(String id, Consumer> consumerBuilder) { + ReferenceBuilder builder = createReferenceBuilder(id); + consumerBuilder.accept(builder); + return reference(builder.build()); + } + public DubboBootstrap reference(ReferenceConfig referenceConfig) { - ConfigManager.getInstance().addReference(referenceConfig); + configManager.addReference(referenceConfig); return this; } - /* accept builder functional interface */ - public DubboBootstrap application(String name, Consumer builder) { - initApplicationBuilder(name); - builder.accept(applicationBuilder); + // {@link ProviderConfig} correlative methods + + public DubboBootstrap provider(Consumer builderConsumer) { + return provider(DEFAULT_PROVIDER_ID, builderConsumer); + } + + public DubboBootstrap provider(String id, Consumer builderConsumer) { + ProviderBuilder builder = createProviderBuilder(id); + builderConsumer.accept(builder); + return provider(builder.build()); + } + + public DubboBootstrap provider(ProviderConfig providerConfig) { + return providers(asList(providerConfig)); + } + + public DubboBootstrap providers(List providerConfigs) { + providerConfigs.forEach(configManager::addProvider); return this; } - public DubboBootstrap registry(String id, Consumer builder) { - builder.accept(initRegistryBuilder(id)); + // {@link ConsumerConfig} correlative methods + + public DubboBootstrap consumer(Consumer builderConsumer) { + return consumer(DEFAULT_CONSUMER_ID, builderConsumer); + } + + public DubboBootstrap consumer(String id, Consumer builderConsumer) { + ConsumerBuilder builder = createConsumerBuilder(id); + builderConsumer.accept(builder); + return consumer(builder.build()); + } + + public DubboBootstrap consumer(ConsumerConfig consumerConfig) { + return consumers(asList(consumerConfig)); + } + + public DubboBootstrap consumers(List consumerConfigs) { + consumerConfigs.forEach(configManager::addConsumer); return this; } - public DubboBootstrap protocol(String id, Consumer builder) { - builder.accept(initProtocolBuilder(id)); - return this; + // {@link ConfigCenterConfig} correlative methods + public DubboBootstrap configCenter(ConfigCenterConfig configCenterConfig) { + return configCenter(asList(configCenterConfig)); } - public DubboBootstrap service(String id, Consumer> builder) { - builder.accept(initServiceBuilder(id)); - return this; - } - - public DubboBootstrap reference(String id, Consumer> builder) { - builder.accept(initReferenceBuilder(id)); + public DubboBootstrap configCenter(List configCenterConfigs) { + configManager.addConfigCenters(configCenterConfigs); return this; } @@ -252,30 +354,13 @@ public class DubboBootstrap { return; } - buildApplicationConfig(); - - buildRegistryConfigs(); - - buildProtocolConfigs(); - - buildServiceConfigs(); - - buildReferenceConfigs(); - - clearBuilders(); - startConfigCenter(); + startMetadataReport(); loadRemoteConfigs(); - useRegistryAsConfigCenterIfNecessary(); -// checkApplication(); -// checkProvider(); -// chcckConsumer(); -// checkRegistry(); -// checkProtocol(); -// checkMonitor(); + useRegistryAsConfigCenterIfNecessary(); initialized = true; @@ -285,8 +370,6 @@ public class DubboBootstrap { } private void loadRemoteConfigs() { - ConfigManager configManager = ConfigManager.getInstance(); - // registry ids to registry configs List tmpRegistries = new ArrayList<>(); Set registryIds = configManager.getRegistryIds(); @@ -301,7 +384,7 @@ public class DubboBootstrap { } }); - configManager.addRegistries(tmpRegistries, true); + configManager.addRegistries(tmpRegistries); // protocol ids to protocol configs List tmpProtocols = new ArrayList<>(); @@ -325,26 +408,26 @@ public class DubboBootstrap { * there's no config center specified explicitly. */ private void useRegistryAsConfigCenterIfNecessary() { - ConfigManager configManager = ConfigManager.getInstance(); - configManager.getDefaultRegistries().ifPresent(registryConfigs -> { - for (RegistryConfig registryConfig : registryConfigs) { - if (registryConfig != null && registryConfig.isZookeeperProtocol()) { - // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated. - Environment.getInstance().getDynamicConfiguration().orElseGet(() -> { - Set configCenters = configManager.getConfigCenters(); - if (CollectionUtils.isEmpty(configCenters)) { - ConfigCenterConfig cc = new ConfigCenterConfig(); - cc.setProtocol(registryConfig.getProtocol()); - cc.setAddress(registryConfig.getAddress()); - cc.setHighestPriority(false); - configManager.addConfigCenter(cc); - } - return null; - }); - } - } - startConfigCenter(); + // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated. + if (Environment.getInstance().getDynamicConfiguration().isPresent()) { + return; + } + + if (CollectionUtils.isNotEmpty(configManager.getConfigCenters())) { + return; + } + + configManager.getRegistries().forEach(registryConfig -> { + String protocol = registryConfig.getProtocol(); + String id = "config-center-" + protocol + "-" + registryConfig.getPort(); + ConfigCenterConfig cc = new ConfigCenterConfig(); + cc.setId(id); + cc.setProtocol(protocol); + cc.setAddress(registryConfig.getAddress()); + cc.setHighestPriority(false); + configManager.addConfigCenter(cc); }); + startConfigCenter(); } private List getServiceDiscoveries() { @@ -369,16 +452,15 @@ public class DubboBootstrap { exportServices(); // Not only provider register and some services are exported - if (!onlyRegisterProvider && !ConfigManager.getInstance().getServiceConfigs().isEmpty()) { + if (!onlyRegisterProvider && !configManager.getServiceConfigs().isEmpty()) { /** * export {@link MetadataService} */ - ConfigManager configManager = ConfigManager.getInstance(); // TODO, only export to default registry? - List exportedURLs = exportMetadataService ( + List exportedURLs = exportMetadataService( configManager.getApplication().orElseThrow(() -> new IllegalStateException("ApplicationConfig cannot be null")), - configManager.getDefaultRegistries().orElseThrow(() -> new IllegalStateException("No default RegistryConfig")), - configManager.getDefaultProtocols().orElseThrow(() -> new IllegalStateException("No default ProtocolConfig")) + configManager.getRegistries(), + configManager.getProtocols() ); /** @@ -450,10 +532,10 @@ public class DubboBootstrap { return started; } + /* serve for builder apis, begin */ - private ApplicationBuilder initApplicationBuilder(String name) { - applicationBuilder = new ApplicationBuilder().name(name); - return applicationBuilder; + private ApplicationBuilder createApplicationBuilder(String name) { + return new ApplicationBuilder().name(name); } private RegistryBuilder createRegistryBuilder(String id) { @@ -472,29 +554,21 @@ public class DubboBootstrap { return new ReferenceBuilder().id(id); } - private RegistryBuilder initRegistryBuilder(String id) { - return registryBuilders.computeIfAbsent(id, this::createRegistryBuilder); + private ProviderBuilder createProviderBuilder(String id) { + return new ProviderBuilder().id(id); } - private ProtocolBuilder initProtocolBuilder(String id) { - return protocolBuilders.computeIfAbsent(id, this::createProtocolBuilder); - } - - private ServiceBuilder initServiceBuilder(String id) { - return serviceBuilders.computeIfAbsent(id, this::createServiceBuilder); - } - - private ReferenceBuilder initReferenceBuilder(String id) { - return referenceBuilders.computeIfAbsent(id, this::createReferenceBuilder); + private ConsumerBuilder createConsumerBuilder(String id) { + return new ConsumerBuilder().id(id); } /* serve for builder apis, end */ private void startMetadataReport() { - ApplicationConfig applicationConfig = ConfigManager.getInstance().getApplication().orElseThrow(() -> new IllegalStateException("There's no ApplicationConfig specified.")); + ApplicationConfig applicationConfig = configManager.getApplication().orElseThrow(() -> new IllegalStateException("There's no ApplicationConfig specified.")); // FIXME, multiple metadata config support. - Set metadataReportConfigs = ConfigManager.getInstance().getMetadataConfigs(); + Collection metadataReportConfigs = configManager.getMetadataConfigs(); if (CollectionUtils.isEmpty(metadataReportConfigs)) { if (CommonConstants.METADATA_REMOTE.equals(applicationConfig.getMetadata())) { throw new IllegalStateException("No MetadataConfig found, you must specify the remote Metadata Center address when set 'metadata=remote'."); @@ -512,7 +586,7 @@ public class DubboBootstrap { } private void startConfigCenter() { - Set configCenters = ConfigManager.getInstance().getConfigCenters(); + Collection configCenters = configManager.getConfigCenters(); if (CollectionUtils.isNotEmpty(configCenters)) { CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration(); @@ -522,7 +596,7 @@ public class DubboBootstrap { } Environment.getInstance().setDynamicConfiguration(compositeDynamicConfiguration); } - ConfigManager.getInstance().refreshAll(); + configManager.refreshAll(); } private DynamicConfiguration prepareEnvironment(ConfigCenterConfig configCenter) { @@ -533,11 +607,11 @@ public class DubboBootstrap { DynamicConfiguration dynamicConfiguration = getDynamicConfiguration(configCenter.toUrl()); String configContent = dynamicConfiguration.getConfigs(configCenter.getConfigFile(), configCenter.getGroup()); - String appGroup = ConfigManager.getInstance().getApplication().orElse(new ApplicationConfig()).getName(); + String appGroup = configManager.getApplication().orElse(new ApplicationConfig()).getName(); String appConfigContent = null; - if (StringUtils.isNotEmpty(appGroup)) { + if (isNotEmpty(appGroup)) { appConfigContent = dynamicConfiguration.getConfigs - (StringUtils.isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(), + (isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(), appGroup ); } @@ -553,13 +627,6 @@ public class DubboBootstrap { return null; } - private DynamicConfiguration getDynamicConfiguration(URL url) { - DynamicConfigurationFactory factory = ExtensionLoader - .getExtensionLoader(DynamicConfigurationFactory.class) - .getExtension(url.getProtocol()); - return factory.getDynamicConfiguration(url); - } - /** * Add an instance of {@link EventListener} * @@ -572,8 +639,8 @@ public class DubboBootstrap { } private List exportMetadataService(ApplicationConfig applicationConfig, - List globalRegistryConfigs, - List globalProtocolConfigs) { + Collection globalRegistryConfigs, + Collection globalProtocolConfigs) { ConfigurableMetadataServiceExporter exporter = new ConfigurableMetadataServiceExporter(); exporter.setApplicationConfig(applicationConfig); exporter.setRegistries(globalRegistryConfigs); @@ -581,36 +648,8 @@ public class DubboBootstrap { return exporter.export(); } - private void buildApplicationConfig() { - ApplicationConfig applicationConfig = null; - if (applicationBuilder != null) { - applicationConfig = applicationBuilder.build(); - } - ConfigManager.getInstance().setApplication(applicationConfig); - } - - private void buildProtocolConfigs() { - List protocolConfigs = buildConfigs(protocolBuilders); - ConfigManager.getInstance().addProtocols(protocolConfigs, true); - } - - private void buildRegistryConfigs() { - List registryConfigs = buildConfigs(registryBuilders); - ConfigManager.getInstance().addRegistries(registryConfigs, true); - } - - private void buildServiceConfigs() { - List> serviceConfigs = buildConfigs(serviceBuilders); - serviceConfigs.forEach(ConfigManager.getInstance()::addService); - } - - private void buildReferenceConfigs() { - List> referenceConfigs = buildConfigs(referenceBuilders); - referenceConfigs.forEach(ConfigManager.getInstance()::addReference); - } - private void exportServices() { - ConfigManager.getInstance().getServiceConfigs().forEach(this::exportServiceConfig); + configManager.getServiceConfigs().forEach(this::exportServiceConfig); } public void exportServiceConfig(ServiceConfig serviceConfig) { @@ -658,46 +697,30 @@ public class DubboBootstrap { } private void destroyProtocolConfigs() { - ConfigManager.getInstance().getProtocols().values().forEach(ProtocolConfig::destroy); + configManager.getProtocols().forEach(ProtocolConfig::destroy); if (logger.isDebugEnabled()) { logger.debug(NAME + "'s all ProtocolConfigs have been destroyed."); } } private void destroyReferenceConfigs() { - ConfigManager.getInstance().getReferenceConfigs().forEach(ReferenceConfig::destroy); + configManager.getReferenceConfigs().forEach(ReferenceConfig::destroy); if (logger.isDebugEnabled()) { logger.debug(NAME + "'s all ReferenceConfigs have been destroyed."); } } private void clear() { - - clearBuilders(); - clearConfigs(); - - ConfigManager.getInstance().clear(); } private void clearConfigs() { - ConfigManager.getInstance().clear(); + configManager.clear(); if (logger.isDebugEnabled()) { logger.debug(NAME + "'s configs have been clear."); } } - private void clearBuilders() { - this.applicationBuilder = null; - this.registryBuilders.clear(); - this.protocolBuilders.clear(); - this.serviceBuilders.clear(); - this.referenceBuilders.clear(); - if (logger.isDebugEnabled()) { - logger.debug(NAME + "'s builders have been clear."); - } - } - private void release() { executeMutually(() -> { while (awaited.compareAndSet(false, true)) { @@ -725,7 +748,8 @@ public class DubboBootstrap { } } - private static List buildConfigs(Map map) { + private static List buildConfigs(Map map) { List configs = new ArrayList<>(); map.entrySet().forEach(entry -> { configs.add((C) entry.getValue().build()); diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java deleted file mode 100644 index 5fc49caf52..0000000000 --- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java +++ /dev/null @@ -1,215 +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.bootstrap; - -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.builders.ProtocolBuilder; - -import java.util.Map; - -/** - * The settings of {@link ProtocolConfig protcol} - * - * @see ProtocolBuilder - * @since 2.7.4 - */ -public class ProtocolSettings extends AbstractSettings { - - private final ProtocolBuilder builder; - - public ProtocolSettings(ProtocolBuilder builder, DubboBootstrap dubboBootstrap) { - super(dubboBootstrap); - this.builder = builder; - } - - public ProtocolSettings name(String name) { - builder.name(name); - return this; - } - - public ProtocolSettings host(String host) { - builder.host(host); - return this; - } - - public ProtocolSettings port(Integer port) { - builder.port(port); - return this; - } - - public ProtocolSettings contextpath(String contextpath) { - builder.contextpath(contextpath); - return this; - } - - @Deprecated - public ProtocolSettings path(String path) { - builder.path(path); - return this; - } - - public ProtocolSettings threadpool(String threadpool) { - builder.threadpool(threadpool); - return this; - } - - public ProtocolSettings corethreads(Integer corethreads) { - builder.corethreads(corethreads); - return this; - } - - public ProtocolSettings threads(Integer threads) { - builder.threads(threads); - return this; - } - - public ProtocolSettings iothreads(Integer iothreads) { - builder.iothreads(iothreads); - return this; - } - - public ProtocolSettings queues(Integer queues) { - builder.queues(queues); - return this; - } - - public ProtocolSettings accepts(Integer accepts) { - builder.accepts(accepts); - return this; - } - - public ProtocolSettings codec(String codec) { - builder.codec(codec); - return this; - } - - public ProtocolSettings serialization(String serialization) { - builder.serialization(serialization); - return this; - } - - public ProtocolSettings charset(String charset) { - builder.charset(charset); - return this; - } - - public ProtocolSettings payload(Integer payload) { - builder.payload(payload); - return this; - } - - public ProtocolSettings buffer(Integer buffer) { - builder.buffer(buffer); - return this; - } - - public ProtocolSettings heartbeat(Integer heartbeat) { - builder.heartbeat(heartbeat); - return this; - } - - public ProtocolSettings accesslog(String accesslog) { - builder.accesslog(accesslog); - return this; - } - - public ProtocolSettings transporter(String transporter) { - builder.transporter(transporter); - return this; - } - - public ProtocolSettings exchanger(String exchanger) { - builder.exchanger(exchanger); - return this; - } - - public ProtocolSettings dispatcher(String dispatcher) { - builder.dispatcher(dispatcher); - return this; - } - - @Deprecated - public ProtocolSettings dispather(String dispather) { - builder.dispather(dispather); - return this; - } - - public ProtocolSettings networker(String networker) { - builder.networker(networker); - return this; - } - - public ProtocolSettings server(String server) { - builder.server(server); - return this; - } - - public ProtocolSettings client(String client) { - builder.client(client); - return this; - } - - public ProtocolSettings telnet(String telnet) { - builder.telnet(telnet); - return this; - } - - public ProtocolSettings prompt(String prompt) { - builder.prompt(prompt); - return this; - } - - public ProtocolSettings status(String status) { - builder.status(status); - return this; - } - - public ProtocolSettings register(Boolean register) { - builder.register(register); - return this; - } - - public ProtocolSettings keepAlive(Boolean keepAlive) { - builder.keepAlive(keepAlive); - return this; - } - - public ProtocolSettings optimizer(String optimizer) { - builder.optimizer(optimizer); - return this; - } - - public ProtocolSettings extension(String extension) { - builder.extension(extension); - return this; - } - - public ProtocolSettings appendParameter(String key, String value) { - builder.appendParameter(key, value); - return this; - } - - public ProtocolSettings appendParameters(Map appendParameters) { - builder.appendParameters(appendParameters); - return this; - } - - public ProtocolSettings isDefault(Boolean isDefault) { - builder.isDefault(isDefault); - return this; - } -} diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java deleted file mode 100644 index bb24e6e30b..0000000000 --- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java +++ /dev/null @@ -1,334 +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.bootstrap; - -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ConfigCenterConfig; -import org.apache.dubbo.config.ConsumerConfig; -import org.apache.dubbo.config.MetadataReportConfig; -import org.apache.dubbo.config.MethodConfig; -import org.apache.dubbo.config.ModuleConfig; -import org.apache.dubbo.config.MonitorConfig; -import org.apache.dubbo.config.ReferenceConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.builders.ReferenceBuilder; - -import java.util.List; -import java.util.Map; - -/** - * The settings of {@link ReferenceConfig} - * - * @since 2.7.4 - */ -public class ReferenceSettings extends AbstractSettings { - - private final ReferenceBuilder builder; - - public ReferenceSettings(ReferenceBuilder builder, DubboBootstrap dubboBootstrap) { - super(dubboBootstrap); - this.builder = builder; - } - - public ReferenceSettings interfaceName(String interfaceName) { - builder.interfaceName(interfaceName); - return this; - } - - public ReferenceSettings interfaceClass(Class interfaceClass) { - builder.interfaceClass(interfaceClass); - return this; - } - - public ReferenceSettings client(String client) { - builder.client(client); - return this; - } - - public ReferenceSettings url(String url) { - builder.url(url); - return this; - } - - public ReferenceSettings addMethods(List methods) { - builder.addMethods(methods); - return this; - } - - public ReferenceSettings addMethod(MethodConfig method) { - builder.addMethod(method); - return this; - } - - public ReferenceSettings consumer(ConsumerConfig consumer) { - builder.consumer(consumer); - return this; - } - - public ReferenceSettings protocol(String protocol) { - builder.protocol(protocol); - return this; - } - - public ReferenceSettings check(Boolean check) { - builder.check(check); - return this; - } - - public ReferenceSettings init(Boolean init) { - builder.init(init); - return this; - } - - public ReferenceSettings generic(String generic) { - builder.generic(generic); - return this; - } - - public ReferenceSettings generic(Boolean generic) { - builder.generic(generic); - return this; - } - - @Deprecated - public ReferenceSettings injvm(Boolean injvm) { - builder.injvm(injvm); - return this; - } - - public ReferenceSettings lazy(Boolean lazy) { - builder.lazy(lazy); - return this; - } - - public ReferenceSettings reconnect(String reconnect) { - builder.reconnect(reconnect); - return this; - } - - public ReferenceSettings sticky(Boolean sticky) { - builder.sticky(sticky); - return this; - } - - public ReferenceSettings version(String version) { - builder.version(version); - return this; - } - - public ReferenceSettings group(String group) { - builder.group(group); - return this; - } - - @Deprecated - public ReferenceSettings local(String local) { - builder.local(local); - return this; - } - - @Deprecated - public ReferenceSettings local(Boolean local) { - builder.local(local); - return this; - } - - public ReferenceSettings stub(String stub) { - builder.stub(stub); - return this; - } - - public ReferenceSettings stub(Boolean stub) { - builder.stub(stub); - return this; - } - - public ReferenceSettings monitor(MonitorConfig monitor) { - builder.monitor(monitor); - return this; - } - - public ReferenceSettings monitor(String monitor) { - builder.monitor(monitor); - return this; - } - - public ReferenceSettings proxy(String proxy) { - builder.proxy(proxy); - return this; - } - - public ReferenceSettings cluster(String cluster) { - builder.cluster(cluster); - return this; - } - - public ReferenceSettings filter(String filter) { - builder.filter(filter); - return this; - } - - public ReferenceSettings listener(String listener) { - builder.listener(listener); - return this; - } - - public ReferenceSettings owner(String owner) { - builder.owner(owner); - return this; - } - - public ReferenceSettings connections(Integer connections) { - builder.connections(connections); - return this; - } - - public ReferenceSettings layer(String layer) { - builder.layer(layer); - return this; - } - - public ReferenceSettings application(ApplicationConfig application) { - builder.application(application); - return this; - } - - public ReferenceSettings module(ModuleConfig module) { - builder.module(module); - return this; - } - - public ReferenceSettings addRegistries(List registries) { - builder.addRegistries(registries); - return this; - } - - public ReferenceSettings addRegistry(RegistryConfig registry) { - builder.addRegistry(registry); - return this; - } - - public ReferenceSettings registryIds(String registryIds) { - builder.registryIds(registryIds); - return this; - } - - public ReferenceSettings onconnect(String onconnect) { - builder.onconnect(onconnect); - return this; - } - - public ReferenceSettings ondisconnect(String ondisconnect) { - builder.ondisconnect(ondisconnect); - return this; - } - - public ReferenceSettings metadataReportConfig(MetadataReportConfig metadataReportConfig) { - builder.metadataReportConfig(metadataReportConfig); - return this; - } - - public ReferenceSettings configCenter(ConfigCenterConfig configCenter) { - builder.configCenter(configCenter); - return this; - } - - public ReferenceSettings callbacks(Integer callbacks) { - builder.callbacks(callbacks); - return this; - } - - public ReferenceSettings scope(String scope) { - builder.scope(scope); - return this; - } - - public ReferenceSettings tag(String tag) { - builder.tag(tag); - return this; - } - - public ReferenceSettings timeout(Integer timeout) { - builder.timeout(timeout); - return this; - } - - public ReferenceSettings retries(Integer retries) { - builder.retries(retries); - return this; - } - - public ReferenceSettings actives(Integer actives) { - builder.actives(actives); - return this; - } - - public ReferenceSettings loadbalance(String loadbalance) { - builder.loadbalance(loadbalance); - return this; - } - - public ReferenceSettings async(Boolean async) { - builder.async(async); - return this; - } - - public ReferenceSettings sent(Boolean sent) { - builder.sent(sent); - return this; - } - - public ReferenceSettings mock(String mock) { - builder.mock(mock); - return this; - } - - public ReferenceSettings mock(Boolean mock) { - builder.mock(mock); - return this; - } - - public ReferenceSettings merger(String merger) { - builder.merger(merger); - return this; - } - - public ReferenceSettings cache(String cache) { - builder.cache(cache); - return this; - } - - public ReferenceSettings validation(String validation) { - builder.validation(validation); - return this; - } - - public ReferenceSettings appendParameters(Map appendParameters) { - builder.appendParameters(appendParameters); - return this; - } - - public ReferenceSettings appendParameter(String key, String value) { - builder.appendParameter(key, value); - return this; - } - - public ReferenceSettings forks(Integer forks) { - builder.forks(forks); - return this; - } -} diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java deleted file mode 100644 index 89899acfb1..0000000000 --- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java +++ /dev/null @@ -1,164 +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.bootstrap; - -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.builders.RegistryBuilder; - -import java.util.Map; - -/** - * The settings of {@link RegistryConfig} - * - * @since 2.7.4 - */ -public class RegistrySettings extends AbstractSettings { - - private final RegistryBuilder builder; - - public RegistrySettings(RegistryBuilder builder, DubboBootstrap dubboBootstrap) { - super(dubboBootstrap); - this.builder = builder; - } - - public RegistrySettings address(String address) { - builder.address(address); - return this; - } - - public RegistrySettings username(String username) { - builder.username(username); - return this; - } - - public RegistrySettings password(String password) { - builder.password(password); - return this; - } - - public RegistrySettings port(Integer port) { - builder.port(port); - return this; - } - - public RegistrySettings protocol(String protocol) { - builder.protocol(protocol); - return this; - } - - public RegistrySettings transporter(String transporter) { - builder.transporter(transporter); - return this; - } - - @Deprecated - public RegistrySettings transport(String transport) { - builder.transport(transport); - return this; - } - - public RegistrySettings server(String server) { - builder.server(server); - return this; - } - - public RegistrySettings client(String client) { - builder.client(client); - return this; - } - - public RegistrySettings cluster(String cluster) { - builder.cluster(cluster); - return this; - } - - public RegistrySettings group(String group) { - builder.group(group); - return this; - } - - public RegistrySettings version(String version) { - builder.version(version); - return this; - } - - public RegistrySettings timeout(Integer timeout) { - builder.timeout(timeout); - return this; - } - - public RegistrySettings session(Integer session) { - builder.session(session); - return this; - } - - public RegistrySettings file(String file) { - builder.file(file); - return this; - } - - @Deprecated - public RegistrySettings wait(Integer wait) { - builder.wait(wait); - return this; - } - - public RegistrySettings isCheck(Boolean check) { - builder.isCheck(check); - return this; - } - - public RegistrySettings isDynamic(Boolean dynamic) { - builder.isDynamic(dynamic); - return this; - } - - public RegistrySettings register(Boolean register) { - builder.register(register); - return this; - } - - public RegistrySettings subscribe(Boolean subscribe) { - builder.subscribe(subscribe); - return this; - } - - public RegistrySettings appendParameter(String key, String value) { - builder.appendParameter(key, value); - return this; - } - - public RegistrySettings appendParameters(Map appendParameters) { - builder.appendParameters(appendParameters); - return this; - } - - public RegistrySettings isDefault(Boolean isDefault) { - builder.isDefault(isDefault); - return this; - } - - public RegistrySettings simplified(Boolean simplified) { - builder.simplified(simplified); - return this; - } - - public RegistrySettings extraKeys(String extraKeys) { - builder.extraKeys(extraKeys); - return this; - } -} diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java deleted file mode 100644 index b17fa835d8..0000000000 --- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java +++ /dev/null @@ -1,384 +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.bootstrap; - -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ConfigCenterConfig; -import org.apache.dubbo.config.MetadataReportConfig; -import org.apache.dubbo.config.MethodConfig; -import org.apache.dubbo.config.ModuleConfig; -import org.apache.dubbo.config.MonitorConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.ProviderConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.builders.ServiceBuilder; - -import java.util.List; -import java.util.Map; - -/** - * The settings of {@link ServiceConfig Dubbo service} - * - * @since 2.7.4 - */ -public class ServiceSettings extends AbstractSettings { - - private final ServiceBuilder builder; - - public ServiceSettings(ServiceBuilder builder, DubboBootstrap dubboBootstrap) { - super(dubboBootstrap); - this.builder = builder; - } - - public ServiceSettings interfaceName(String interfaceName) { - builder.interfaceName(interfaceName); - return this; - } - - public ServiceSettings interfaceClass(Class interfaceClass) { - builder.interfaceClass(interfaceClass); - return this; - } - - public ServiceSettings ref(S ref) { - builder.ref(ref); - return this; - } - - public ServiceSettings path(String path) { - builder.path(path); - return this; - } - - public ServiceSettings addMethod(MethodConfig method) { - builder.addMethod(method); - return this; - } - - public ServiceSettings addMethods(List methods) { - builder.addMethods(methods); - return this; - } - - public ServiceSettings provider(ProviderConfig provider) { - builder.provider(provider); - return this; - } - - public ServiceSettings providerIds(String providerIds) { - builder.providerIds(providerIds); - return this; - } - - public ServiceSettings generic(String generic) { - builder.generic(generic); - return this; - } - - public ServiceSettings mock(String mock) { - builder.mock(mock); - return this; - } - - public ServiceSettings mock(Boolean mock) { - builder.mock(mock); - return this; - } - - public ServiceSettings version(String version) { - builder.version(version); - return this; - } - - public ServiceSettings group(String group) { - builder.group(group); - return this; - } - - public ServiceSettings deprecated(Boolean deprecated) { - builder.deprecated(deprecated); - return this; - } - - public ServiceSettings delay(Integer delay) { - builder.delay(delay); - return this; - } - - public ServiceSettings export(Boolean export) { - builder.export(export); - return this; - } - - public ServiceSettings weight(Integer weight) { - builder.weight(weight); - return this; - } - - public ServiceSettings document(String document) { - builder.document(document); - return this; - } - - public ServiceSettings dynamic(Boolean dynamic) { - builder.dynamic(dynamic); - return this; - } - - public ServiceSettings token(String token) { - builder.token(token); - return this; - } - - public ServiceSettings token(Boolean token) { - builder.token(token); - return this; - } - - public ServiceSettings accesslog(String accesslog) { - builder.accesslog(accesslog); - return this; - } - - public ServiceSettings accesslog(Boolean accesslog) { - builder.accesslog(accesslog); - return this; - } - - public ServiceSettings addProtocols(List protocols) { - builder.addProtocols(protocols); - return this; - } - - public ServiceSettings addProtocol(ProtocolConfig protocol) { - builder.addProtocol(protocol); - return this; - } - - public ServiceSettings protocolIds(String protocolIds) { - builder.protocolIds(protocolIds); - return this; - } - - public ServiceSettings executes(Integer executes) { - builder.executes(executes); - return this; - } - - public ServiceSettings register(Boolean register) { - builder.register(register); - return this; - } - - public ServiceSettings warmup(Integer warmup) { - builder.warmup(warmup); - return this; - } - - public ServiceSettings serialization(String serialization) { - builder.serialization(serialization); - return this; - } - - @Deprecated - public ServiceSettings local(String local) { - builder.local(local); - return this; - } - - @Deprecated - public ServiceSettings local(Boolean local) { - builder.local(local); - return this; - } - - public ServiceSettings stub(String stub) { - builder.stub(stub); - return this; - } - - public ServiceSettings stub(Boolean stub) { - builder.stub(stub); - return this; - } - - public ServiceSettings monitor(MonitorConfig monitor) { - builder.monitor(monitor); - return this; - } - - public ServiceSettings monitor(String monitor) { - builder.monitor(monitor); - return this; - } - - public ServiceSettings proxy(String proxy) { - builder.proxy(proxy); - return this; - } - - public ServiceSettings cluster(String cluster) { - builder.cluster(cluster); - return this; - } - - public ServiceSettings filter(String filter) { - builder.filter(filter); - return this; - } - - public ServiceSettings listener(String listener) { - builder.listener(listener); - return this; - } - - public ServiceSettings owner(String owner) { - builder.owner(owner); - return this; - } - - public ServiceSettings connections(Integer connections) { - builder.connections(connections); - return this; - } - - public ServiceSettings layer(String layer) { - builder.layer(layer); - return this; - } - - public ServiceSettings application(ApplicationConfig application) { - builder.application(application); - return this; - } - - public ServiceSettings module(ModuleConfig module) { - builder.module(module); - return this; - } - - public ServiceSettings addRegistries(List registries) { - builder.addRegistries(registries); - return this; - } - - public ServiceSettings addRegistry(RegistryConfig registry) { - builder.addRegistry(registry); - return this; - } - - public ServiceSettings registryIds(String registryIds) { - builder.registryIds(registryIds); - return this; - } - - public ServiceSettings onconnect(String onconnect) { - builder.onconnect(onconnect); - return this; - } - - public ServiceSettings ondisconnect(String ondisconnect) { - builder.ondisconnect(ondisconnect); - return this; - } - - public ServiceSettings metadataReportConfig(MetadataReportConfig metadataReportConfig) { - builder.metadataReportConfig(metadataReportConfig); - return this; - } - - public ServiceSettings configCenter(ConfigCenterConfig configCenter) { - builder.configCenter(configCenter); - return this; - } - - public ServiceSettings callbacks(Integer callbacks) { - builder.callbacks(callbacks); - return this; - } - - public ServiceSettings scope(String scope) { - builder.scope(scope); - return this; - } - - public ServiceSettings tag(String tag) { - builder.tag(tag); - return this; - } - - public ServiceSettings timeout(Integer timeout) { - builder.timeout(timeout); - return this; - } - - public ServiceSettings retries(Integer retries) { - builder.retries(retries); - return this; - } - - public ServiceSettings actives(Integer actives) { - builder.actives(actives); - return this; - } - - public ServiceSettings loadbalance(String loadbalance) { - builder.loadbalance(loadbalance); - return this; - } - - public ServiceSettings async(Boolean async) { - builder.async(async); - return this; - } - - public ServiceSettings sent(Boolean sent) { - builder.sent(sent); - return this; - } - - public ServiceSettings merger(String merger) { - builder.merger(merger); - return this; - } - - public ServiceSettings cache(String cache) { - builder.cache(cache); - return this; - } - - public ServiceSettings validation(String validation) { - builder.validation(validation); - return this; - } - - public ServiceSettings appendParameters(Map appendParameters) { - builder.appendParameters(appendParameters); - return this; - } - - public ServiceSettings appendParameter(String key, String value) { - builder.appendParameter(key, value); - return this; - } - - public ServiceSettings forks(Integer forks) { - builder.forks(forks); - return this; - } -} diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java index f49c340dba..96fbcc7665 100644 --- a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java +++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java @@ -16,11 +16,6 @@ */ package org.apache.dubbo.bootstrap; -import org.apache.dubbo.config.builders.ApplicationBuilder; -import org.apache.dubbo.config.builders.ProtocolBuilder; -import org.apache.dubbo.config.builders.RegistryBuilder; -import org.apache.dubbo.config.builders.ServiceBuilder; - import org.junit.jupiter.api.Test; import java.io.IOException; @@ -35,14 +30,5 @@ public class DubboBootstrapTest { @Test public void test() throws IOException { - new DubboBootstrap() - .application(ApplicationBuilder.newBuilder().name("dubbo-provider-demo").build()) - .registry(RegistryBuilder.newBuilder().address("zookeeper://127.0.0.1:2181?registry-type=service&metadata=remote").build()) - .protocol(ProtocolBuilder.newBuilder().port(-1).name("dubbo").build()) - .service(ServiceBuilder.newBuilder().id("test").interfaceClass(EchoService.class).ref(new EchoServiceImpl()).build()) - .start() - .await(); - - System.in.read(); } } diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java index 4e03c1be29..191b233313 100644 --- a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java +++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java @@ -16,9 +16,8 @@ */ package org.apache.dubbo.bootstrap; -import org.apache.dubbo.config.builders.ApplicationBuilder; -import org.apache.dubbo.config.builders.ReferenceBuilder; -import org.apache.dubbo.config.builders.RegistryBuilder; +import org.apache.dubbo.config.ReferenceConfig; +import org.apache.dubbo.config.context.ConfigManager; /** * Dubbo Provider Bootstrap @@ -29,23 +28,27 @@ public class DubboServiceConsumerBootstrap { public static void main(String[] args) throws Exception { - DubboBootstrap bootstrap = new DubboBootstrap() - .application(ApplicationBuilder.newBuilder().name("dubbo-consumer-demo").build()) - .registry(RegistryBuilder.newBuilder().address("zookeeper://127.0.0.1:2181?registry-type=service&subscribed-services=dubbo-provider-demo&metadata=remote").build()) - .reference(ReferenceBuilder.newBuilder().id("ref").interfaceClass(EchoService.class).build()) + new DubboBootstrap() + .application("dubbo-consumer-demo") + // Zookeeper + .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181?registry-type=service&subscribed-services=dubbo-provider-demo")) + // Nacos + .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry-type=service&subscribed-services=dubbo-provider-demo")) + .reference("ref", builder -> builder.interfaceClass(EchoService.class)) .onlyRegisterProvider(true) .start() .await(); - // TODO, -// ReferenceConfig referenceConfig = ReferenceConfigCache.getCache().get(EchoService.class.getName(), EchoService.class); -// -// EchoService echoService = referenceConfig.get(); -// -// for (int i = 0; i < 500; i++) { -// Thread.sleep(2000L); -// System.out.println(echoService.echo("Hello,World")); -// } + ConfigManager configManager = ConfigManager.getInstance(); + + ReferenceConfig referenceConfig = configManager.getReferenceConfig("ref"); + + EchoService echoService = referenceConfig.get(); + + for (int i = 0; i < 500; i++) { + Thread.sleep(2000L); + System.out.println(echoService.echo("Hello,World")); + } } } diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java index 7918bff172..1ed573f0ae 100644 --- a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java +++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java @@ -16,14 +16,6 @@ */ package org.apache.dubbo.bootstrap; -import org.apache.dubbo.config.builders.ApplicationBuilder; -import org.apache.dubbo.config.builders.MetadataReportBuilder; -import org.apache.dubbo.config.builders.ProtocolBuilder; -import org.apache.dubbo.config.builders.RegistryBuilder; -import org.apache.dubbo.config.builders.ServiceBuilder; - -import java.io.IOException; - /** * Dubbo Provider Bootstrap * @@ -31,15 +23,15 @@ import java.io.IOException; */ public class DubboServiceProviderBootstrap { - public static void main(String[] args) throws IOException { - + public static void main(String[] args) { new DubboBootstrap() - .application(ApplicationBuilder.newBuilder().name("dubbo-provider-demo").metadata("remote").build()) - .metadataReport(MetadataReportBuilder.newBuilder().address("zookeeper://127.0.0.1:2181").build()) -// .application(ApplicationBuilder.newBuilder().name("dubbo-provider-demo").build()) - .registry(RegistryBuilder.newBuilder().address("zookeeper://127.0.0.1:2181?registry-type=service").build()) - .protocol(ProtocolBuilder.newBuilder().port(-1).name("dubbo").build()) - .service(ServiceBuilder.newBuilder().id("test").interfaceClass(EchoService.class).ref(new EchoServiceImpl()).build()) + .application("dubbo-provider-demo") + // Zookeeper in service registry type + .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181?registry-type=service")) + // Nacos + .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry-type=service")) + .protocol(builder -> builder.port(-1).name("dubbo")) + .service(builder -> builder.id("test").interfaceClass(EchoService.class).ref(new EchoServiceImpl())) .start() .await(); } diff --git a/dubbo-common/pom.xml b/dubbo-common/pom.xml index 98ecc9b87b..dabf4bb47e 100644 --- a/dubbo-common/pom.xml +++ b/dubbo-common/pom.xml @@ -77,5 +77,9 @@ de.ruedigermoeller fst + + commons-io + commons-io + \ No newline at end of file diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangeEvent.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangeEvent.java index 751746f199..177551be92 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangeEvent.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangeEvent.java @@ -16,15 +16,18 @@ */ package org.apache.dubbo.common.config.configcenter; +import java.util.EventObject; + /** * Config change event, immutable. * * @see ConfigChangeType */ -public class ConfigChangeEvent { +public class ConfigChangeEvent extends EventObject { private final String key; private final String value; + private final ConfigChangeType changeType; public ConfigChangeEvent(String key, String value) { @@ -32,6 +35,7 @@ public class ConfigChangeEvent { } public ConfigChangeEvent(String key, String value, ConfigChangeType changeType) { + super(key + "=" + value); this.key = key; this.value = value; this.changeType = changeType; diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigurationListener.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigurationListener.java index 09746c5bce..2a1779a383 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigurationListener.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigurationListener.java @@ -16,10 +16,12 @@ */ package org.apache.dubbo.common.config.configcenter; +import java.util.EventListener; + /** * Config listener, will get notified when the config it listens on changes. */ -public interface ConfigurationListener { +public interface ConfigurationListener extends EventListener { /** * Listener call back method. Listener gets notified by this method once there's any change happens on the config 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 f5bf9a426a..84b6ec337d 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 @@ -16,16 +16,17 @@ */ package org.apache.dubbo.common.config.configcenter; +import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.Configuration; import org.apache.dubbo.common.config.Environment; import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.SortedMap; -import java.util.SortedSet; -import java.util.TreeMap; +import static org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory.getDynamicConfigurationFactory; import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; /** @@ -38,7 +39,7 @@ import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoad *
  • 3. addListener/removeListener, add or remove listeners for governance rules or config items that need to watch.
  • * */ -public interface DynamicConfiguration extends Configuration { +public interface DynamicConfiguration extends Configuration, AutoCloseable { String DEFAULT_GROUP = "dubbo"; @@ -133,6 +134,20 @@ public interface DynamicConfiguration extends Configuration { */ String getConfigs(String key, String group, long timeout) throws IllegalStateException; + + /** + * Publish Config mapped to the given key under the {@link #DEFAULT_GROUP default group} + * + * @param key the key to represent a configuration + * @param content the content of configuration + * @return true if success, or false + * @throws UnsupportedOperationException If the under layer does not support + * @since 2.7.4 + */ + default boolean publishConfig(String key, String content) throws UnsupportedOperationException { + return publishConfig(key, DEFAULT_GROUP, content); + } + /** * Publish Config mapped to the given key and the given group. * @@ -148,45 +163,92 @@ public interface DynamicConfiguration extends Configuration { } /** - * Get the config keys by the specified group + * Remove Config mapped to the given key under the {@link #DEFAULT_GROUP default group} * - * @param group the specified group - * @return the read-only non-null sorted {@link Set set} of config keys + * @param key the key to represent a configuration + * @return the content of configuration was removed * @throws UnsupportedOperationException If the under layer does not support * @since 2.7.4 */ - default SortedSet getConfigKeys(String group) throws UnsupportedOperationException { + default String removeConfig(String key) throws UnsupportedOperationException { + return removeConfig(key, DEFAULT_GROUP); + } + + /** + * Remove Config mapped to the given key and the given group. + * + * @param key the key to represent a configuration + * @param group the group where the key belongs to + * @return the content of configuration was removed + * @throws UnsupportedOperationException If the under layer does not support + * @since 2.7.4 + */ + default String removeConfig(String key, String group) throws UnsupportedOperationException { throw new UnsupportedOperationException("No support"); } /** - * Get the {@link SortedMap} with with config keys and contents value by the specified group + * Get all groups * - * @param group the specified group - * @return the read-only non-null sorted {@link SortedMap map} + * @return the read-only non-null {@link Set set} of config keys * @throws UnsupportedOperationException If the under layer does not support * @since 2.7.4 */ - default SortedMap getConfigs(String group) throws UnsupportedOperationException { + default Set getConfigGroups() throws UnsupportedOperationException { + throw new UnsupportedOperationException("No support"); + } + + /** + * Get the config keys by the specified group + * + * @param group the specified group + * @return the read-only non-null {@link Set set} of config keys + * @throws UnsupportedOperationException If the under layer does not support + * @since 2.7.4 + */ + default Set getConfigKeys(String group) throws UnsupportedOperationException { + throw new UnsupportedOperationException("No support"); + } + + /** + * Get the {@link Map} with with config keys and contents value by the specified group + * + * @param group the specified group + * @return the read-only non-null {@link Map map} + * @throws UnsupportedOperationException If the under layer does not support + * @since 2.7.4 + */ + default Map getConfigs(String group) throws UnsupportedOperationException { return getConfigs(group, -1); } /** - * Get the {@link SortedMap} with with config keys and content value by the specified group + * Get the {@link Map} with with config keys and content value by the specified group * * @param group the specified group * @param timeout the millisecond for timeout - * @return the read-only non-null sorted {@link SortedMap map} + * @return the read-only non-null {@link Map map} * @throws UnsupportedOperationException If the under layer does not support * @throws IllegalStateException If timeout exceeds * @since 2.7.4 */ - default SortedMap getConfigs(String group, long timeout) throws UnsupportedOperationException, + default Map getConfigs(String group, long timeout) throws UnsupportedOperationException, IllegalStateException { - SortedMap configs = new TreeMap<>(); - SortedSet configKeys = getConfigKeys(group); + Map configs = new LinkedHashMap<>(); + Set configKeys = getConfigKeys(group); configKeys.forEach(key -> configs.put(key, getConfig(key, group, timeout))); - return Collections.unmodifiableSortedMap(configs); + return Collections.unmodifiableMap(configs); + } + + /** + * Close the configuration + * + * @throws Exception + * @since 2.7.4 + */ + @Override + default void close() throws Exception { + throw new UnsupportedOperationException(); } /** @@ -200,4 +262,17 @@ public interface DynamicConfiguration extends Configuration { .getDefaultExtension() .getDynamicConfiguration(null)); } + + /** + * Get the instance of {@link DynamicConfiguration} by the specified connection {@link URL} + * + * @param connectionURL + * @return non-null + * @since 2.7.4 + */ + static DynamicConfiguration getDynamicConfiguration(URL connectionURL) { + String protocol = connectionURL.getProtocol(); + DynamicConfigurationFactory factory = getDynamicConfigurationFactory(protocol); + return factory.getDynamicConfiguration(connectionURL); + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactory.java index 59c27ce0cb..649eec6420 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactory.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactory.java @@ -17,14 +17,30 @@ package org.apache.dubbo.common.config.configcenter; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.extension.SPI; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; + /** - * + * The factory interface to create the instance of {@link DynamicConfiguration} */ -@SPI("nop") +@SPI("file") // 2.7.4 change the default SPI implementation public interface DynamicConfigurationFactory { DynamicConfiguration getDynamicConfiguration(URL url); + /** + * Get an instance of {@link DynamicConfigurationFactory} by the specified name. If not found, take the default + * extension of {@link DynamicConfigurationFactory} + * + * @param name the name of extension of {@link DynamicConfigurationFactory} + * @return non-null + * @see 2.7.4 + */ + static DynamicConfigurationFactory getDynamicConfigurationFactory(String name) { + Class factoryClass = DynamicConfigurationFactory.class; + ExtensionLoader loader = getExtensionLoader(factoryClass); + return loader.hasExtension(name) ? loader.getExtension(name) : loader.getDefaultExtension(); + } } 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 new file mode 100644 index 0000000000..b75527e8cc --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java @@ -0,0 +1,628 @@ +/* + * 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.file; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.ConfigChangeEvent; +import org.apache.dubbo.common.config.configcenter.ConfigChangeType; +import org.apache.dubbo.common.config.configcenter.ConfigurationListener; +import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; +import org.apache.dubbo.common.function.ThrowableConsumer; +import org.apache.dubbo.common.function.ThrowableFunction; +import org.apache.dubbo.common.utils.NamedThreadFactory; + +import com.sun.nio.file.SensitivityWatchEventModifier; +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +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.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.lang.String.format; +import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; +import static java.util.Collections.emptySet; +import static java.util.Collections.unmodifiableMap; +import static java.util.concurrent.Executors.newFixedThreadPool; +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.4 + */ +public class FileSystemDynamicConfiguration implements DynamicConfiguration { + + public static final String PARAM_NAME_PREFIX = "dubbo.config-center."; + + public static final String CONFIG_CENTER_DIR_PARAM_NAME = PARAM_NAME_PREFIX + "dir"; + + public static final String THREAD_POOL_PREFIX_PARAM_NAME = PARAM_NAME_PREFIX + "thread-pool.prefix"; + + public static final String THREAD_POOL_SIZE_PARAM_NAME = PARAM_NAME_PREFIX + "thread-pool.size"; + + public static final String CONFIG_CENTER_ENCODING_PARAM_NAME = PARAM_NAME_PREFIX + "encoding"; + + public static final String DEFAULT_CONFIG_CENTER_DIR_PATH = System.getProperty("user.home") + File.separator + + ".dubbo" + File.separator + "config-center"; + + public static final String DEFAULT_THREAD_POOL_PREFIX = PARAM_NAME_PREFIX + "workers"; + + public static final String DEFAULT_THREAD_POOL_SIZE = "1"; + + public static final String DEFAULT_CONFIG_CENTER_ENCODING = "UTF-8"; + + private static final WatchEvent.Kind[] INTEREST_PATH_KINDS = of(ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); + + /** + * The class name of {@linkplain sun.nio.fs.PollingWatchService} + */ + private static final String POLLING_WATCH_SERVICE_CLASS_NAME = "sun.nio.fs.PollingWatchService"; + + private static final int THREAD_POOL_SIZE = 1; + + /** + * Logger + */ + private static final Log logger = LogFactory.getLog(FileSystemDynamicConfiguration.class); + + /** + * The unmodifiable map for {@link ConfigChangeType} whose key is the {@link WatchEvent.Kind#name() name} of + * {@link WatchEvent.Kind WatchEvent's Kind} + */ + private static final Map CONFIG_CHANGE_TYPES_MAP = + unmodifiableMap(new HashMap() { + // Initializes the elements that is mapping ConfigChangeType + { + put(ENTRY_CREATE.name(), ConfigChangeType.ADDED); + put(ENTRY_DELETE.name(), ConfigChangeType.DELETED); + put(ENTRY_MODIFY.name(), ConfigChangeType.MODIFIED); + } + }); + + private static final Optional watchService; + + /** + * Is Pooling Based Watch Service + * + * @see #detectPoolingBasedWatchService(Optional) + */ + private static final boolean basedPoolingWatchService; + + private static final WatchEvent.Modifier[] modifiers; + + /** + * the delay to action in seconds. If null, execute indirectly + */ + private static final Integer delay; + + /** + * The thread pool for {@link WatchEvent WatchEvents} loop + * It's optional if there is not any {@link ConfigurationListener} registration + * + * @see ThreadPoolExecutor + */ + private static final ThreadPoolExecutor watchEventsLoopThreadPool; + + // static initialization + static { + watchService = newWatchService(); + basedPoolingWatchService = detectPoolingBasedWatchService(watchService); + modifiers = initWatchEventModifiers(); + delay = initDelay(modifiers); + watchEventsLoopThreadPool = newWatchEventsLoopThreadPool(); + } + + /** + * The Root Directory for config center + */ + private final File rootDirectory; + + private final String encoding; + + /** + * The thread pool for workers who executes the tasks + */ + private final ThreadPoolExecutor workersThreadPool; + + /** + * The {@link Set} of {@link #configDirectory(String) directories} that may be processing, + *

    + * if {@link #isBasedPoolingWatchService()} is false, this properties will be + * {@link Collections#emptySet() empty} + * + * @see #initProcessingDirectories() + */ + private final Set processingDirectories; + + private final Map> listenersRepository; + + public FileSystemDynamicConfiguration(URL url) { + this(initDirectory(url), getEncoding(url), getThreadPoolPrefixName(url), getThreadPoolSize(url)); + } + + public FileSystemDynamicConfiguration(File rootDirectory, String encoding, + String threadPoolPrefixName, + int threadPoolSize + ) { + this.rootDirectory = rootDirectory; + this.encoding = encoding; + this.workersThreadPool = initWorkersThreadPool(threadPoolPrefixName, threadPoolSize); + this.processingDirectories = initProcessingDirectories(); + this.listenersRepository = new LinkedHashMap<>(); + } + + 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); + }); + } + + protected File configDirectory(String group) { + String actualGroup = isBlank(group) ? DEFAULT_GROUP : group; + return new File(rootDirectory, actualGroup); + } + + protected File configFile(String key, String group) { + return new File(configDirectory(group), key); + } + + private void doInListener(String key, String group, BiConsumer> consumer) { + watchService.ifPresent(watchService -> { + File configFile = configFile(key, group); + executeMutually(configFile.getParentFile(), () -> { + // process the WatchEvents if not start + if (!isProcessingWatchEvents()) { + processWatchEvents(watchService); + } + + List listeners = getListeners(configFile); + consumer.accept(configFile, listeners); + + // Nothing to return + return null; + }); + }); + } + + private static boolean isProcessingWatchEvents() { + return getWatchEventsLoopThreadPool().getActiveCount() > 0; + } + + /** + * Process the {@link WatchEvent WatchEvents} loop in async execution + * + * @param watchService {@link WatchService} + */ + private void processWatchEvents(WatchService watchService) { + getWatchEventsLoopThreadPool().execute(() -> { // WatchEvents Loop + while (true) { + WatchKey watchKey = null; + try { + watchKey = watchService.take(); + if (watchKey.isValid()) { + for (WatchEvent event : watchKey.pollEvents()) { + WatchEvent.Kind kind = event.kind(); + // configChangeType's key to match WatchEvent's Kind + ConfigChangeType configChangeType = CONFIG_CHANGE_TYPES_MAP.get(kind.name()); + if (configChangeType != null) { + Path configDirectoryPath = (Path) watchKey.watchable(); + Path currentPath = (Path) event.context(); + Path configFilePath = configDirectoryPath.resolve(currentPath); + File configDirectory = configDirectoryPath.toFile(); + executeMutually(configDirectory, () -> { + fireConfigChangeEvent(configFilePath.toFile(), configChangeType); + signalConfigDirectory(configDirectory); + return null; + }); + } + } + } + } catch (Exception e) { + return; + } finally { + if (watchKey != null) { + // reset + watchKey.reset(); + } + } + } + }); + } + + private void signalConfigDirectory(File configDirectory) { + if (isBasedPoolingWatchService()) { + // remove configDirectory from processing set because it's done + removeProcessingDirectory(configDirectory); + // notify configDirectory + notifyProcessingDirectory(configDirectory); + if (logger.isDebugEnabled()) { + logger.debug(format("The config rootDirectory[%s] is signalled...", configDirectory.getName())); + } + } + } + + private void removeProcessingDirectory(File configDirectory) { + processingDirectories.remove(configDirectory); + } + + private void notifyProcessingDirectory(File configDirectory) { + configDirectory.notifyAll(); + } + + private List getListeners(File configFile) { + return listenersRepository.computeIfAbsent(configFile, p -> new LinkedList<>()); + } + + private void fireConfigChangeEvent(File configFile, ConfigChangeType configChangeType) { + String key = configFile.getName(); + String value = getConfig(configFile, -1L); + // fire ConfigChangeEvent one by one + getListeners(configFile).forEach(listener -> { + try { + listener.process(new ConfigChangeEvent(key, value, configChangeType)); + } catch (Throwable e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + }); + } + + @Override + public String getConfig(String key, String group, long timeout) throws IllegalStateException { + File configFile = configFile(key, group); + return getConfig(configFile, timeout); + } + + protected String getConfig(File configFile, long timeout) { + return canRead(configFile) ? execute(() -> readFileToString(configFile, getEncoding()), timeout) : null; + } + + private boolean canRead(File file) { + return file.exists() && file.canRead(); + } + + @Override + public String getConfigs(String key, String group, long timeout) throws IllegalStateException { + return getConfig(key, group, timeout); + } + + @Override + public Object getInternalProperty(String key) { + return null; + } + + @Override + public boolean publishConfig(String key, String group, String content) { + return delay(key, group, configFile -> { + FileUtils.write(configFile, content, getEncoding()); + return true; + }); + } + + @Override + public String removeConfig(String key, String group) { + return delay(key, group, configFile -> { + + String content = getConfig(configFile, -1L); + + FileUtils.deleteQuietly(configFile); + + return content; + }); + } + + private ThreadPoolExecutor initWorkersThreadPool(String prefix, int size) { + return (ThreadPoolExecutor) newFixedThreadPool(size, new NamedThreadFactory(prefix)); + } + + /** + * 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 + * @return + */ + protected V delay(String key, String group, ThrowableFunction function) { + File configFile = configFile(key, group); + // Must be based on PoolingWatchService and has listeners under config file + if (isBasedPoolingWatchService()) { + File configDirectory = configFile.getParentFile(); + executeMutually(configDirectory, () -> { + if (hasListeners(configFile) && isProcessing(configDirectory)) { + Integer delay = getDelay(); + if (delay != null) { + // 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)); + } + configDirectory.wait(timeout); + } + } + addProcessing(configDirectory); + return null; + }); + } + + V value = null; + + try { + value = function.apply(configFile); + } catch (Throwable e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + + return value; + } + + private boolean hasListeners(File configFile) { + return getListeners(configFile).size() > 0; + } + + /** + * Is processing on {@link #configDirectory(String) config rootDirectory} + * + * @param configDirectory {@link #configDirectory(String) config rootDirectory} + * @return if processing , return true, or false + */ + private boolean isProcessing(File configDirectory) { + return processingDirectories.contains(configDirectory); + } + + private void addProcessing(File configDirectory) { + processingDirectories.add(configDirectory); + } + + @Override + public Set getConfigKeys(String group) { + return Stream.of(configDirectory(group).listFiles(File::isFile)) + .map(File::getName) + .collect(Collectors.toSet()); + } + + + @Override + public Set getConfigGroups() { + return Stream.of(getRootDirectory().listFiles()) + .filter(File::isDirectory) + .map(File::getName) + .collect(Collectors.toSet()); + } + + @Override + public Map getConfigs(String group) throws UnsupportedOperationException { + return getConfigs(group, -1); + } + + @Override + public void close() throws Exception { + // TODO + } + + private V execute(Callable task, long timeout) { + V value = null; + try { + + if (timeout < 1) { // less or equal 0 + value = task.call(); + } else { + Future future = workersThreadPool.submit(task); + value = future.get(timeout, TimeUnit.MILLISECONDS); + } + } catch (Exception e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + return value; + } + + protected File getRootDirectory() { + return rootDirectory; + } + + protected ThreadPoolExecutor getWorkersThreadPool() { + return workersThreadPool; + } + + protected String getEncoding() { + return encoding; + } + + protected Integer getDelay() { + return delay; + } + + /** + * It's whether the implementation of {@link WatchService} is based on {@linkplain sun.nio.fs.PollingWatchService} + * or not. + *

    + * + * @return if based, return true, or false + * @see #detectPoolingBasedWatchService(Optional) + */ + protected static boolean isBasedPoolingWatchService() { + return basedPoolingWatchService; + } + + private static String getThreadPoolPrefixName(URL url) { + return getParameter(url, THREAD_POOL_PREFIX_PARAM_NAME, DEFAULT_THREAD_POOL_PREFIX); + } + + protected static ThreadPoolExecutor getWatchEventsLoopThreadPool() { + return watchEventsLoopThreadPool; + } + + private V executeMutually(Object mutex, Callable callable) { + V value = null; + synchronized (mutex) { + try { + value = callable.call(); + } catch (Exception e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } + } + return value; + } + + private static T[] of(T... values) { + return values; + } + + private static Integer initDelay(WatchEvent.Modifier[] modifiers) { + return Stream.of(modifiers) + .filter(modifier -> modifier instanceof SensitivityWatchEventModifier) + .map(SensitivityWatchEventModifier.class::cast) + .map(SensitivityWatchEventModifier::sensitivityValueInSeconds) + .max(Integer::compareTo) + .orElse(null); + } + + private static WatchEvent.Modifier[] initWatchEventModifiers() { + if (isBasedPoolingWatchService()) { // If based on PollingWatchService, High sensitivity will be used + return of(SensitivityWatchEventModifier.HIGH); + } else { + return of(); + } + } + + /** + * Detect the argument of {@link WatchService} is based on {@linkplain sun.nio.fs.PollingWatchService} + * or not. + *

    + * Some platforms do not provide the native implementation of {@link WatchService}, just use + * {@linkplain sun.nio.fs.PollingWatchService} in periodic poll file modifications. + * + * @param watchService the instance of {@link WatchService} + * @return if based, return true, or false + */ + private static boolean detectPoolingBasedWatchService(Optional watchService) { + String className = watchService.map(Object::getClass).map(Class::getName).orElse(null); + return POLLING_WATCH_SERVICE_CLASS_NAME.equals(className); + } + + private static Optional newWatchService() { + Optional watchService = null; + FileSystem fileSystem = FileSystems.getDefault(); + try { + watchService = Optional.of(fileSystem.newWatchService()); + } catch (IOException e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + watchService = Optional.empty(); + } + return watchService; + } + + private static File initDirectory(URL url) { + String directoryPath = getParameter(url, CONFIG_CENTER_DIR_PARAM_NAME, DEFAULT_CONFIG_CENTER_DIR_PATH); + File rootDirectory = new File(getParameter(url, CONFIG_CENTER_DIR_PARAM_NAME, DEFAULT_CONFIG_CENTER_DIR_PATH)); + if (!rootDirectory.exists() && !rootDirectory.mkdirs()) { + throw new IllegalStateException(format("Dubbo config center rootDirectory[%s] can't be created!", + directoryPath)); + } + return rootDirectory; + } + + private static String getParameter(URL url, String name, String defaultValue) { + if (url != null) { + return url.getParameter(name, defaultValue); + } + return defaultValue; + } + + private static String getEncoding(URL url) { + return getParameter(url, CONFIG_CENTER_ENCODING_PARAM_NAME, DEFAULT_CONFIG_CENTER_ENCODING); + } + + private static int getThreadPoolSize(URL url) { + return Integer.parseInt(getParameter(url, THREAD_POOL_SIZE_PARAM_NAME, DEFAULT_THREAD_POOL_SIZE)); + } + + private static ThreadPoolExecutor newWatchEventsLoopThreadPool() { + return new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, + 0L, MILLISECONDS, + new SynchronousQueue(), + new NamedThreadFactory("dubbo-config-center-watch-events-loop", true)); + } +} \ No newline at end of file diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationFactory.java similarity index 57% rename from dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java rename to dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationFactory.java index 7ed1de5498..f2a13322c6 100644 --- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationFactory.java @@ -14,23 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.bootstrap; +package org.apache.dubbo.common.config.configcenter.file; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory; +import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; +import org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory; /** - * Abstract {@link Settings} + * File-System based {@link DynamicConfigurationFactory} implementation * * @since 2.7.4 */ -public class AbstractSettings implements Settings { - - private final DubboBootstrap dubboBootstrap; - - public AbstractSettings(DubboBootstrap dubboBootstrap) { - this.dubboBootstrap = dubboBootstrap; - } +public class FileSystemDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory { @Override - public DubboBootstrap next() { - return dubboBootstrap; + protected DynamicConfiguration createDynamicConfiguration(URL url) { + return new FileSystemDynamicConfiguration(url); } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java index 14accb28a2..a69f115ab7 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java @@ -28,6 +28,7 @@ import static java.util.Collections.emptySortedSet; * The default extension of {@link DynamicConfiguration}. If user does not specify a config centre, or specifies one * that is not a valid extension, it will default to this one. */ +@Deprecated public class NopDynamicConfiguration implements DynamicConfiguration { public NopDynamicConfiguration(URL url) { diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfigurationFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfigurationFactory.java index bd45e7f736..487f70da6b 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfigurationFactory.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfigurationFactory.java @@ -23,6 +23,7 @@ import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; /** * */ +@Deprecated public class NopDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory { @Override diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java index 7f98d383d7..016265df87 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java @@ -89,9 +89,6 @@ public class CompositeDynamicConfiguration implements DynamicConfiguration { Object value = null; for (DynamicConfiguration configuration : configurations) { value = func.apply(configuration); - if (value != null) { - break; - } } return value; } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java index 27202299d2..f8e987c0a4 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java @@ -21,6 +21,9 @@ import javassist.CtConstructor; import javassist.CtMethod; import javassist.NotFoundException; +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -48,6 +51,7 @@ import java.util.concurrent.Future; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableSet; @@ -1127,7 +1131,7 @@ public final class ReflectUtils { } return new Type[]{returnType, genericReturnType}; } - + /** * Find the {@link Set} of {@link ParameterizedType} * @@ -1184,4 +1188,28 @@ public final class ReflectUtils { return unmodifiableSet(hierarchicalTypes); } + + public static T getProperty(Object bean, String propertyName) { + Class beanClass = bean.getClass(); + BeanInfo beanInfo = null; + T propertyValue = null; + try { + beanInfo = Introspector.getBeanInfo(beanClass); + propertyValue = (T) Stream.of(beanInfo.getPropertyDescriptors()) + .filter(propertyDescriptor -> propertyName.equals(propertyDescriptor.getName())) + .map(PropertyDescriptor::getReadMethod) + .findFirst() + .map(method -> { + try { + return method.invoke(bean); + } catch (Exception e) { + } + return null; + }).get(); + } catch (Exception e) { + + } + return propertyValue; + } + } \ No newline at end of file diff --git a/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory index 42d6a25112..f6fe6d68fc 100644 --- a/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory +++ b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory @@ -1 +1,2 @@ -nop=org.apache.dubbo.common.config.configcenter.nop.NopDynamicConfigurationFactory \ No newline at end of file +nop=org.apache.dubbo.common.config.configcenter.nop.NopDynamicConfigurationFactory +file=org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfigurationFactory \ No newline at end of file diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java b/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactoryTest.java similarity index 51% rename from dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java rename to dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactoryTest.java index 290bb7e4b9..eacd3eed1e 100644 --- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactoryTest.java @@ -14,19 +14,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.bootstrap; +package org.apache.dubbo.common.config.configcenter; + +import org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfigurationFactory; + +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; +import static org.junit.jupiter.api.Assertions.assertEquals; /** - * The Dubbo settings + * {@link DynamicConfigurationFactory} Test * * @since 2.7.4 */ -public interface Settings { +public class DynamicConfigurationFactoryTest { - /** - * Go next settings - * - * @return {@link DubboBootstrap} - */ - DubboBootstrap next(); + @Test + public void testDefaultExtension() { + DynamicConfigurationFactory factory = getExtensionLoader(DynamicConfigurationFactory.class).getDefaultExtension(); + assertEquals(FileSystemDynamicConfigurationFactory.class, factory.getClass()); + assertEquals(factory, getExtensionLoader(DynamicConfigurationFactory.class).getExtension("file")); + } } 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 new file mode 100644 index 0000000000..c68cd4c6d2 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationTest.java @@ -0,0 +1,169 @@ +/* + * 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.file; + +import org.apache.dubbo.common.URL; + +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicBoolean; + +import static java.util.Collections.singleton; +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.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link FileSystemDynamicConfiguration} Test + */ +public class FileSystemDynamicConfigurationTest { + + private FileSystemDynamicConfiguration configuration; + + private static final String KEY = "abc-def-ghi"; + + private static final String CONTENT = "Hello,World"; + + @BeforeEach + public void init() { + String classPath = getClassPath(); + URL url = valueOf("dubbo://127.0.0.1:20880").addParameter(CONFIG_CENTER_DIR_PARAM_NAME, classPath + File.separator + "config-center"); + configuration = new FileSystemDynamicConfiguration(url); + deleteQuietly(configuration.getRootDirectory()); + } + + private String getClassPath() { + return getClass().getProtectionDomain().getCodeSource().getLocation().getPath(); + } + + @Test + public void testInit() { + + assertEquals(new File(getClassPath(), "config-center"), configuration.getRootDirectory()); + assertEquals("UTF-8", configuration.getEncoding()); + 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()); + } else { + assertNull(configuration.getDelay()); + } + } + + @Test + public void testPublishAndGetConfig() { + assertTrue(configuration.publishConfig(KEY, CONTENT)); + assertTrue(configuration.publishConfig(KEY, CONTENT)); + assertTrue(configuration.publishConfig(KEY, CONTENT)); + assertEquals(CONTENT, configuration.getConfig(KEY)); + assertTrue(configuration.getConfigs(null).size() > 0); + } + + @Test + public void testPublishAndRemoveConfig() throws InterruptedException { + assertTrue(configuration.publishConfig(KEY, CONTENT)); + configuration.addListener(KEY, event -> { + System.out.printf("[%s] " + event + "\n", Thread.currentThread().getName()); + + }); + assertTrue(configuration.publishConfig(KEY, CONTENT)); + assertEquals(CONTENT, configuration.removeConfig(KEY)); + Thread.sleep(configuration.getDelay() * 1000); + } + + @Test + public void testGetConfigsAndGroups() { + assertTrue(configuration.publishConfig(KEY, CONTENT)); + assertEquals(singleton(KEY), configuration.getConfigKeys(DEFAULT_GROUP)); + assertEquals(singleton(DEFAULT_GROUP), configuration.getConfigGroups()); + + assertTrue(configuration.publishConfig(KEY, "test", CONTENT)); + assertEquals(singleton(KEY), configuration.getConfigKeys(DEFAULT_GROUP)); + assertTrue(configuration.getConfigGroups().contains(DEFAULT_GROUP)); + assertTrue(configuration.getConfigGroups().contains("test")); + } + + @Test + public void testAddAndRemoveListener() throws InterruptedException { + + configuration.publishConfig(KEY, "A"); + + AtomicBoolean processedEvent = new AtomicBoolean(); + + configuration.addListener(KEY, event -> { + + processedEvent.set(true); + assertEquals(KEY, event.getKey()); + System.out.printf("[%s] " + event + "\n", Thread.currentThread().getName()); + }); + + + configuration.publishConfig(KEY, "B"); + while (!processedEvent.get()) { + Thread.sleep(1 * 1000L); + } + + processedEvent.set(false); + configuration.publishConfig(KEY, "C"); + while (!processedEvent.get()) { + Thread.sleep(1 * 1000L); + } + + processedEvent.set(false); + configuration.publishConfig(KEY, "D"); + while (!processedEvent.get()) { + Thread.sleep(1 * 1000L); + } + + configuration.addListener("test", "test", event -> { + processedEvent.set(true); + assertEquals("test", event.getKey()); + System.out.printf("[%s] " + event + "\n", Thread.currentThread().getName()); + }); + processedEvent.set(false); + configuration.publishConfig("test", "test", "TEST"); + while (!processedEvent.get()) { + Thread.sleep(1 * 1000L); + } + + configuration.publishConfig("test", "test", "TEST"); + configuration.publishConfig("test", "test", "TEST"); + configuration.publishConfig("test", "test", "TEST"); + + + processedEvent.set(false); + File keyFile = configuration.configFile(KEY, DEFAULT_GROUP); + FileUtils.deleteQuietly(keyFile); + while (!processedEvent.get()) { + Thread.sleep(1 * 1000L); + } + } +} diff --git a/dubbo-common/src/test/resources/log4j.xml b/dubbo-common/src/test/resources/log4j.xml index bfb523c0cc..21ea447138 100644 --- a/dubbo-common/src/test/resources/log4j.xml +++ b/dubbo-common/src/test/resources/log4j.xml @@ -21,14 +21,14 @@ - + - + \ No newline at end of file diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java index 1ad15ecb72..874e38b968 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java @@ -255,7 +255,6 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig { } /** - * * Load the registry and conversion it to {@link URL}, the priority order is: system property > dubbo registry config * * @param provider whether it is the provider side @@ -298,7 +297,6 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig { } /** - * * Load the monitor config from the system properties and conversation it to {@link URL} * * @param registryURL @@ -358,7 +356,7 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig { * methods configured in the configuration file are included in the interface of remote service * * @param interfaceClass the interface of remote service - * @param methods the methods configured + * @param methods the methods configured */ protected void checkInterfaceAndMethods(Class interfaceClass, List methods) { // interface cannot be null @@ -466,15 +464,14 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig { private void convertRegistryIdsToRegistries() { if (StringUtils.isEmpty(registryIds)) { if (CollectionUtils.isEmpty(registries)) { - setRegistries( - ConfigManager.getInstance().getDefaultRegistries() - .filter(CollectionUtils::isNotEmpty) - .orElseGet(() -> { - RegistryConfig registryConfig = new RegistryConfig(); - registryConfig.refresh(); - return Arrays.asList(registryConfig); - }) - ); + List registryConfigs = ConfigManager.getInstance().getDefaultRegistries(); + if (registryConfigs.isEmpty()) { + registryConfigs = new ArrayList<>(); + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.refresh(); + registryConfigs.add(registryConfig); + } + setRegistries(registryConfigs); } } else { String[] ids = COMMA_SPLIT_PATTERN.split(registryIds); @@ -668,7 +665,7 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig { @SuppressWarnings({"unchecked"}) public void setRegistries(List registries) { - ConfigManager.getInstance().addRegistries((List) registries, false); + ConfigManager.getInstance().addRegistries((List) registries); this.registries = (List) registries; } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java index c9a96cb2a5..a5196df614 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.config; +import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.support.Parameter; import org.apache.dubbo.remoting.Constants; @@ -179,9 +180,14 @@ public class RegistryConfig extends AbstractConfig { public void setAddress(String address) { this.address = address; if (address != null) { - int i = address.indexOf("://"); - if (i > 0) { - this.updateIdIfAbsent(address.substring(0, i)); + try { + URL url = URL.valueOf(address); + setUsername(url.getUsername()); + setPassword(url.getPassword()); + setProtocol(url.getProtocol()); + setPort(url.getPort()); + setParameters(url.getParameters()); + } catch (Exception ignored) { } } } 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 fb9d247d30..c851ca133e 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 @@ -882,15 +882,14 @@ public class ServiceConfig extends AbstractServiceConfig { private void convertProtocolIdsToProtocols() { if (StringUtils.isEmpty(protocolIds)) { if (CollectionUtils.isEmpty(protocols)) { - setProtocols( - ConfigManager.getInstance().getDefaultProtocols() - .filter(CollectionUtils::isNotEmpty) - .orElseGet(() -> { - ProtocolConfig protocolConfig = new ProtocolConfig(); - protocolConfig.refresh(); - return new ArrayList<>(Arrays.asList(protocolConfig)); - }) - ); + List protocolConfigs = ConfigManager.getInstance().getDefaultProtocols(); + if (protocolConfigs.isEmpty()) { + protocolConfigs = new ArrayList<>(1); + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.refresh(); + protocolConfigs.add(protocolConfig); + } + setProtocols(protocolConfigs); } } else { String[] arr = COMMA_SPLIT_PATTERN.split(protocolIds); diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java index 12d09bf05c..1f51f1bc69 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java @@ -36,7 +36,7 @@ public abstract class AbstractBuilder protocols = new ConcurrentHashMap<>(); - private Map registries = new ConcurrentHashMap<>(); - private Map providers = new ConcurrentHashMap<>(); - private Map consumers = new ConcurrentHashMap<>(); + private final Map protocols = new ConcurrentHashMap<>(); + private final Map registries = new ConcurrentHashMap<>(); + private final Map providers = new ConcurrentHashMap<>(); + private final Map consumers = new ConcurrentHashMap<>(); + private final Map configCenters = new ConcurrentHashMap<>(); + private final Map metadataConfigs = new ConcurrentHashMap<>(); + private final Map> serviceConfigs = new ConcurrentHashMap<>(); + private final Map> referenceConfigs = new ConcurrentHashMap<>(); - private List defaultProtocols = new ArrayList<>(); - private List defaultRegistries = new ArrayList<>(); - - private Set configCenters = new HashSet<>(); - private Set metadataConfigs = new HashSet<>(); - private Set registryIds = new HashSet<>(); - private Set protocolIds = new HashSet<>(); - - private List> serviceConfigs = new ArrayList<>(); - private List> referenceConfigs = new ArrayList<>(); + private final StampedLock lock = new StampedLock(); public static ConfigManager getInstance() { return CONFIG_MANAGER; } private ConfigManager() { - } - public Optional getApplication() { - return Optional.ofNullable(application); - } + // ApplicationConfig correlative methods public void setApplication(ApplicationConfig application) { if (application != null) { @@ -124,10 +124,12 @@ public class ConfigManager { } } - public Optional getMonitor() { - return Optional.ofNullable(monitor); + public Optional getApplication() { + return ofNullable(application); } + // MonitorConfig correlative methods + public void setMonitor(MonitorConfig monitor) { if (monitor != null) { checkDuplicate(this.monitor, monitor); @@ -135,10 +137,12 @@ public class ConfigManager { } } - public Optional getModule() { - return Optional.ofNullable(module); + public Optional getMonitor() { + return ofNullable(monitor); } + // ModuleConfig correlative methods + public void setModule(ModuleConfig module) { if (module != null) { checkDuplicate(this.module, module); @@ -146,210 +150,175 @@ public class ConfigManager { } } - public Set getConfigCenters() { - return configCenters; + public Optional getModule() { + return ofNullable(module); } + // ConfigCenterConfig correlative methods + public void addConfigCenter(ConfigCenterConfig configCenter) { - if (configCenter != null && !configCenters.contains(configCenter)) { - this.configCenters.add(configCenter); - } + addIfAbsent(configCenter, configCenters); } - public void addConfigCenter(List configCenters) { - if (CollectionUtils.isNotEmpty(configCenters)) { - this.configCenters.addAll(configCenters); - } + public void addConfigCenters(Iterable configCenters) { + configCenters.forEach(this::addConfigCenter); } - public Set getMetadataConfigs() { - return metadataConfigs; + public ConfigCenterConfig getConfigCenter(String id) { + return configCenters.get(id); } + public Collection getConfigCenters() { + return configCenters.values(); + } + + // MetadataReportConfig correlative methods + public void addMetadataReport(MetadataReportConfig metadataReportConfig) { - if (metadataReportConfig != null && !metadataConfigs.contains(metadataReportConfig)) { - this.metadataConfigs.add(metadataReportConfig); - } + addIfAbsent(metadataReportConfig, metadataConfigs); } - public void addMetadataReport(List metadataReportConfigs) { - if (CollectionUtils.isNotEmpty(metadataReportConfigs)) { - this.metadataConfigs.addAll(metadataReportConfigs); - } + public void addMetadataReports(Iterable metadataReportConfigs) { + metadataReportConfigs.forEach(this::addMetadataReport); + } + + public Collection getMetadataConfigs() { + return metadataConfigs.values(); + } + + // MetadataReportConfig correlative methods + + public void addProvider(ProviderConfig providerConfig) { + addIfAbsent(providerConfig, providers); } public Optional getProvider(String id) { - return Optional.ofNullable(providers.get(id)); + return ofNullable(providers.get(id)); } public Optional getDefaultProvider() { - return Optional.ofNullable(providers.get(DEFAULT_KEY)); + return getProvider(DEFAULT_KEY); } - public void addProvider(ProviderConfig providerConfig) { - if (providerConfig == null) { - return; - } + public Collection getProviders() { + return providers.values(); + } - String key = StringUtils.isNotEmpty(providerConfig.getId()) - ? providerConfig.getId() - : (providerConfig.isDefault() == null || providerConfig.isDefault()) ? DEFAULT_KEY : null; + // ConsumerConfig correlative methods - if (StringUtils.isEmpty(key)) { - throw new IllegalStateException("A ProviderConfig should either has an id or it's the default one, " + providerConfig); - } - - if (providers.containsKey(key) && !providerConfig.equals(providers.get(key))) { - logger.warn("Duplicate ProviderConfig found, there already has one default ProviderConfig or more than two ProviderConfigs have the same id, " + - "you can try to give each ProviderConfig a different id. " + providerConfig); - } else { - providers.put(key, providerConfig); - } + public void addConsumer(ConsumerConfig consumerConfig) { + addIfAbsent(consumerConfig, consumers); } public Optional getConsumer(String id) { - return Optional.ofNullable(consumers.get(id)); + return ofNullable(consumers.get(id)); } public Optional getDefaultConsumer() { - return Optional.ofNullable(consumers.get(DEFAULT_KEY)); + return getConsumer(DEFAULT_KEY); } - public void addConsumer(ConsumerConfig consumerConfig) { - if (consumerConfig == null) { - return; - } + public Collection getConsumers() { + return consumers.values(); + } - String key = StringUtils.isNotEmpty(consumerConfig.getId()) - ? consumerConfig.getId() - : (consumerConfig.isDefault() == null || consumerConfig.isDefault()) ? DEFAULT_KEY : null; + // ProtocolConfig correlative methods - if (StringUtils.isEmpty(key)) { - throw new IllegalStateException("A ConsumerConfig should either has an id or it's the default one, " + consumerConfig); - } + public void addProtocol(ProtocolConfig protocolConfig) { + addIfAbsent(protocolConfig, protocols); + } - if (consumers.containsKey(key) && !consumerConfig.equals(consumers.get(key))) { - logger.warn("Duplicate ConsumerConfig found, there already has one default ConsumerConfig or more than two ConsumerConfigs have the same id, " + - "you can try to give each ConsumerConfig a different id. " + consumerConfig); - } else { - consumers.put(key, consumerConfig); + public void addProtocols(Iterable protocolConfigs, boolean canBeDefault) { + if (protocolConfigs != null) { + protocolConfigs.forEach(this::addProtocol); } } public Optional getProtocol(String id) { - return Optional.ofNullable(protocols.get(id)); + return ofNullable(protocols.get(id)); } - public Optional> getDefaultProtocols() { - return Optional.of(defaultProtocols); + public List getDefaultProtocols() { + return getDefaultConfigs(protocols); } - public void addProtocols(List protocolConfigs, boolean canBeDefault) { - if (protocolConfigs != null) { - protocolConfigs.forEach(pc -> this.addProtocol(pc, canBeDefault)); - } + public Collection getProtocols() { + return protocols.values(); } - public void addProtocol(ProtocolConfig protocolConfig, boolean canBeDefault) { - if (protocolConfig == null) { - return; - } + public Set getProtocolIds() { + Set protocolIds = new HashSet<>(); + protocolIds.addAll(getSubProperties(Environment.getInstance() + .getExternalConfigurationMap(), PROTOCOLS_SUFFIX)); + protocolIds.addAll(getSubProperties(Environment.getInstance() + .getAppExternalConfigurationMap(), PROTOCOLS_SUFFIX)); - // if isDefault is not false and a ProtocolConfig is not specified being false. - if (canBeDefault && (protocolConfig.isDefault() == null || protocolConfig.isDefault())) { - this.defaultProtocols.add(protocolConfig); - } + protocolIds.addAll(protocols.keySet()); + return unmodifiableSet(protocolIds); + } - String key = StringUtils.isNotEmpty(protocolConfig.getId()) - ? protocolConfig.getId() - : DEFAULT_KEY; - if (StringUtils.isEmpty(key)) { - throw new IllegalStateException("A ProtocolConfig should either has an id or it's the default one, " + protocolConfig); - } + // RegistryConfig correlative methods - if (protocols.containsKey(key) && !protocolConfig.equals(protocols.get(key))) { - logger.warn("Duplicate ProtocolConfig found, there already has one default ProtocolConfig or more than two ProtocolConfigs have the same id, " + - "you can try to give each ProtocolConfig a different id. " + protocolConfig); - } else { - protocols.put(key, protocolConfig); + public void addRegistry(RegistryConfig registryConfig) { + addIfAbsent(registryConfig, registries); + } + + public void addRegistries(Iterable registryConfigs) { + if (registryConfigs != null) { + registryConfigs.forEach(this::addRegistry); } } public Optional getRegistry(String id) { - return Optional.ofNullable(registries.get(id)); + return ofNullable(registries.get(id)); } - public Optional> getDefaultRegistries() { - return Optional.of(defaultRegistries); + public List getDefaultRegistries() { + return getDefaultConfigs(registries); } - public void addRegistries(List registryConfigs, boolean canBeDefault) { - if (registryConfigs != null) { - registryConfigs.forEach(rc -> this.addRegistry(rc, canBeDefault)); - } - } - - public void addRegistry(RegistryConfig registryConfig, boolean canBeDefault) { - if (registryConfig == null) { - return; - } - - if (canBeDefault && (registryConfig.isDefault() == null || registryConfig.isDefault())) { - this.defaultRegistries.add(registryConfig); - } - String key = StringUtils.isNotEmpty(registryConfig.getId()) - ? registryConfig.getId() - : DEFAULT_KEY; - - if (StringUtils.isEmpty(key)) { - throw new IllegalStateException("A RegistryConfig should either has an id or it's the default one, " + registryConfig); - } - - if (registries.containsKey(key) && !registryConfig.equals(registries.get(key))) { - logger.warn("Duplicate RegistryConfig found, there already has one default RegistryConfig or more than two RegistryConfigs have the same id, " + - "you can try to give each RegistryConfig a different id. " + registryConfig); - } else { - registries.put(key, registryConfig); - } - } - - public void addProtocolIds(List protocolIds) { - this.protocolIds.addAll(protocolIds); - } - - public void addRegistryIds(List registryIds) { - this.registryIds.addAll(registryIds); - } - - public void addService(ServiceConfig serviceConfig) { - this.serviceConfigs.add(serviceConfig); - } - - public void addReference(ReferenceConfig referenceConfig) { - this.referenceConfigs.add(referenceConfig); + public Collection getRegistries() { + return registries.values(); } public Set getRegistryIds() { - Set configedRegistries = new HashSet<>(); - configedRegistries.addAll(getSubProperties(Environment.getInstance().getExternalConfigurationMap(), + Set registryIds = new HashSet<>(); + registryIds.addAll(getSubProperties(Environment.getInstance().getExternalConfigurationMap(), REGISTRIES_SUFFIX)); - configedRegistries.addAll(getSubProperties(Environment.getInstance().getAppExternalConfigurationMap(), + registryIds.addAll(getSubProperties(Environment.getInstance().getAppExternalConfigurationMap(), REGISTRIES_SUFFIX)); - configedRegistries.addAll(registryIds); - return configedRegistries; + registryIds.addAll(registries.keySet()); + return unmodifiableSet(registryIds); } - public Set getProtocolIds() { - Set configedProtocols = new HashSet<>(); - configedProtocols.addAll(getSubProperties(Environment.getInstance() - .getExternalConfigurationMap(), PROTOCOLS_SUFFIX)); - configedProtocols.addAll(getSubProperties(Environment.getInstance() - .getAppExternalConfigurationMap(), PROTOCOLS_SUFFIX)); + // ServiceConfig correlative methods - configedProtocols.addAll(protocolIds); - return configedProtocols; + public void addService(ServiceConfig serviceConfig) { + addIfAbsent(serviceConfig, serviceConfigs); + } + + public Collection> getServiceConfigs() { + return serviceConfigs.values(); + } + + public ServiceConfig getServiceConfig(String id) { + return (ServiceConfig) serviceConfigs.get(id); + } + + // ReferenceConfig correlative methods + + public void addReference(ReferenceConfig referenceConfig) { + addIfAbsent(referenceConfig, referenceConfigs); + } + + public Collection> getReferenceConfigs() { + return referenceConfigs.values(); + } + + public ReferenceConfig getReferenceConfig(String id) { + return (ReferenceConfig) referenceConfigs.get(id); } protected static Set getSubProperties(Map properties, String prefix) { @@ -359,62 +328,130 @@ public class ConfigManager { }).collect(Collectors.toSet()); } - public Map getProtocols() { - return protocols; - } - - public Map getRegistries() { - return registries; - } - - public Map getProviders() { - return providers; - } - - public Map getConsumers() { - return consumers; - } - - public List> getServiceConfigs() { - return serviceConfigs; - } - - public List> getReferenceConfigs() { - return referenceConfigs; - } - public void refreshAll() { - // refresh all configs here, - getApplication().ifPresent(ApplicationConfig::refresh); - getMonitor().ifPresent(MonitorConfig::refresh); - getModule().ifPresent(ModuleConfig::refresh); + write(() -> { + // refresh all configs here, + getApplication().ifPresent(ApplicationConfig::refresh); + getMonitor().ifPresent(MonitorConfig::refresh); + getModule().ifPresent(ModuleConfig::refresh); + + getProtocols().forEach(ProtocolConfig::refresh); + getRegistries().forEach(RegistryConfig::refresh); + getProviders().forEach(ProviderConfig::refresh); + getConsumers().forEach(ConsumerConfig::refresh); + }); - getProtocols().values().forEach(ProtocolConfig::refresh); - getRegistries().values().forEach(RegistryConfig::refresh); - getProviders().values().forEach(ProviderConfig::refresh); - getConsumers().values().forEach(ConsumerConfig::refresh); } - private void checkDuplicate(AbstractConfig oldOne, AbstractConfig newOne) { + + // For test purpose + public void clear() { + write(() -> { + this.application = null; + this.monitor = null; + this.module = null; + this.registries.clear(); + this.protocols.clear(); + this.providers.clear(); + this.consumers.clear(); + this.configCenters.clear(); + this.metadataConfigs.clear(); + }); + } + + private V write(Callable callable) { + V value = null; + long stamp = lock.writeLock(); + try { + value = callable.call(); + } catch (Throwable e) { + throw new RuntimeException(e); + } finally { + lock.unlockWrite(stamp); + } + return value; + } + + private void write(Runnable runnable) { + write(() -> { + runnable.run(); + return null; + }); + } + + + private V read(Callable callable) { + long stamp = lock.tryOptimisticRead(); + + boolean readLock = false; + + V value = null; + + try { + readLock = !lock.validate(stamp); + + if (readLock) { + stamp = lock.readLock(); + } + value = callable.call(); + } catch (Throwable e) { + throw new RuntimeException(e); + } finally { + if (readLock) { + lock.unlockRead(stamp); + } + } + + return value; + } + + private static void checkDuplicate(AbstractConfig oldOne, AbstractConfig newOne) { if (oldOne != null && !oldOne.equals(newOne)) { String configName = oldOne.getClass().getSimpleName(); throw new IllegalStateException("Duplicate Config found for " + configName + ", you should use only one unique " + configName + " for one application."); } } - // For test purpose - public void clear() { - this.application = null; - this.monitor = null; - this.module = null; - this.registries.clear(); - this.protocols.clear(); - this.providers.clear(); - this.consumers.clear(); - this.configCenters.clear(); - this.metadataConfigs.clear(); - this.registryIds.clear(); - this.protocolIds.clear(); + private static Map, Map> newMap() { + return new HashMap<>(); } + private static void addIfAbsent(C config, Map configsMap) { + + if (config == null) { + return; + } + + String key = getId(config); + + C existedConfig = configsMap.get(key); + + if (existedConfig != null && !config.equals(existedConfig)) { + if (logger.isWarnEnabled()) { + String type = config.getClass().getSimpleName(); + logger.warn(String.format("Duplicate %s found, there already has one default %s or more than two %ss have the same id, " + + "you can try to give each %s a different id : %s", type, type, type, type, config)); + } + } else { + configsMap.put(key, config); + } + } + + static String getId(C config) { + String id = config.getId(); + return isNotEmpty(id) ? id : isDefaultConfig(config) ? + config.getClass().getSimpleName() + "#" + DEFAULT_KEY : null; + } + + static boolean isDefaultConfig(C config) { + Boolean isDefault = getProperty(config, "default"); + return isDefault == null || TRUE.equals(isDefault); + } + + static List getDefaultConfigs(Map configsMap) { + return configsMap.values() + .stream() + .filter(ConfigManager::isDefaultConfig) + .collect(Collectors.toList()); + } } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ServiceInstancePortCustomizer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ServiceInstancePortCustomizer.java index 37e9b3c16b..25c4d20353 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ServiceInstancePortCustomizer.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ServiceInstancePortCustomizer.java @@ -38,7 +38,6 @@ public class ServiceInstancePortCustomizer implements ServiceInstanceCustomizer ConfigManager.getInstance() .getProtocols() - .values() .stream() .findFirst() .ifPresent(protocolConfig -> { diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java new file mode 100644 index 0000000000..44e896d517 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java @@ -0,0 +1,71 @@ +/* + * 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.context; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ModuleConfig; +import org.apache.dubbo.config.MonitorConfig; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.apache.dubbo.config.context.ConfigManager.getInstance; +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 ConfigManager} Test + * + * @since 2.7.4 + */ +public class ConfigManagerTest { + + private ConfigManager configManager = getInstance(); + + @BeforeEach + public void init() { + configManager.clear(); + assertFalse(configManager.getApplication().isPresent()); + assertFalse(configManager.getMonitor().isPresent()); + assertFalse(configManager.getMonitor().isPresent()); + } + + @Test + public void testApplicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + configManager.setApplication(applicationConfig); + assertTrue(configManager.getApplication().isPresent()); + assertEquals(applicationConfig, configManager.getApplication().get()); + } + + @Test + public void testMonitorConfig() { + MonitorConfig monitorConfig = new MonitorConfig(); + configManager.setMonitor(monitorConfig); + assertTrue(configManager.getMonitor().isPresent()); + assertEquals(monitorConfig, configManager.getMonitor().get()); + } + + @Test + public void tesModuleConfig() { + ModuleConfig config = new ModuleConfig(); + configManager.setModule(config); + assertTrue(configManager.getModule().isPresent()); + assertEquals(config, configManager.getModule().get()); + } +} diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporterTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporterTest.java index e7db07d719..43331e996d 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporterTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporterTest.java @@ -49,9 +49,9 @@ public class ConfigurableMetadataServiceExporterTest { configManager.setApplication(applicationConfig); // Add ProtocolConfig - configManager.addProtocol(protocolConfig(), true); + configManager.addProtocol(protocolConfig()); // Add RegistryConfig - configManager.addRegistry(registryConfig(), true); + configManager.addRegistry(registryConfig()); } private static ProtocolConfig protocolConfig() { diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml index f7064cd170..3e56228a91 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml @@ -21,8 +21,22 @@ http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd "> + + + + + + + + + + + + - + + + 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 8c827a332f..6bcafcd4ce 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 @@ -94,12 +94,19 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { } public void publishNacosConfig(String key, String value) { + String[] keyAndGroup = getKeyAndGroup(key); + publishConfig(keyAndGroup[0], keyAndGroup[1], value); + } + + @Override + public boolean publishConfig(String key, String group, String content) { + boolean published = false; try { - String[] keyAndGroup = getKeyAndGroup(key); - configService.publishConfig(keyAndGroup[0], keyAndGroup[1], value); + published = configService.publishConfig(key, group, content); } catch (NacosException e) { logger.error(e.getErrMsg()); } + return published; } private String[] getKeyAndGroup(String key) { @@ -107,7 +114,7 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { if (i < 0) { return new String[]{key, null}; } else { - return new String[]{key.substring(0, i), key.substring(i+1)}; + return new String[]{key.substring(0, i), key.substring(i + 1)}; } } diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml index d6cf69e4bf..27e284f8f5 100644 --- a/dubbo-dependencies-bom/pom.xml +++ b/dubbo-dependencies-bom/pom.xml @@ -15,14 +15,15 @@ limitations under the License. --> - + 4.0.0 org.apache apache 21 - + org.apache.dubbo @@ -135,6 +136,7 @@ 1.2.16 1.2.2 2.11.1 + 2.6 0.6 @@ -442,6 +444,11 @@ commons-logging ${jcl_version} + + commons-io + commons-io + ${commons_io_version} + log4j log4j diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/FileSystemServiceDiscovery.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/FileSystemServiceDiscovery.java new file mode 100644 index 0000000000..1dbf90d612 --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/FileSystemServiceDiscovery.java @@ -0,0 +1,114 @@ +/* + * 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; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory; +import org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfiguration; +import org.apache.dubbo.event.EventListener; +import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent; +import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener; + +import java.util.Set; + +import static com.alibaba.fastjson.JSON.toJSONString; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; + +/** + * File System {@link ServiceDiscovery} implementation + * + * @see FileSystemDynamicConfiguration + * @since 2.7.4 + */ +public class FileSystemServiceDiscovery implements ServiceDiscovery, EventListener { + + private final URL connectionURL; + + private FileSystemDynamicConfiguration dynamicConfiguration; + + public FileSystemServiceDiscovery(URL connectionURL) { + this.connectionURL = connectionURL; + } + + @Override + public void onEvent(ServiceInstancesChangedEvent event) { + + } + + @Override + public void start() { + if (dynamicConfiguration == null) { + dynamicConfiguration = createDynamicConfiguration(connectionURL); + } + } + + @Override + public void stop() { + try { + if (dynamicConfiguration != null) { + dynamicConfiguration.close(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private String getConfigKey(ServiceInstance serviceInstance) { + return serviceInstance.getId(); + } + + private String getConfigGroup(ServiceInstance serviceInstance) { + return serviceInstance.getServiceName(); + } + + @Override + public void register(ServiceInstance serviceInstance) throws RuntimeException { + String key = getConfigKey(serviceInstance); + String group = getConfigGroup(serviceInstance); + String content = toJSONString(serviceInstance); + dynamicConfiguration.publishConfig(key, group, content); + } + + @Override + public void update(ServiceInstance serviceInstance) throws RuntimeException { + register(serviceInstance); + } + + @Override + public void unregister(ServiceInstance serviceInstance) throws RuntimeException { + String key = getConfigKey(serviceInstance); + String group = getConfigGroup(serviceInstance); + dynamicConfiguration.removeConfig(key, group); + } + + @Override + public Set getServices() { + return null; + } + + @Override + public void addServiceInstancesChangedListener(String serviceName, ServiceInstancesChangedListener listener) throws + NullPointerException, IllegalArgumentException { + + } + + private static FileSystemDynamicConfiguration createDynamicConfiguration(URL connectionURL) { + String protocol = connectionURL.getProtocol(); + DynamicConfigurationFactory factory = getExtensionLoader(DynamicConfigurationFactory.class).getExtension(protocol); + return (FileSystemDynamicConfiguration) factory.getDynamicConfiguration(connectionURL); + } +}