From 98e7313e71fab2d24103956ee3befc7b13ebdd92 Mon Sep 17 00:00:00 2001 From: namelessssssssssss <100946116+namelessssssssssss@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:56:10 +0800 Subject: [PATCH] Split DefaultConfigValidator to SPI implements (#12948) * * Simplify responsibilities of ConfigValidationUtils * * Update validators * * Bug fix * * Bug fix * Add ut * * Add license * * Rename folder * * Fix pom & name * * Code style fix * * Bug fix * * Bug fix * * Update validator init process * * Refactor ConfigValidateFacade init method * * Bug fix * Add license * * Fix test * * Fix ut * * Update ConfigValidateFacade init process * * Bug fix * * Bug fix * * Bug fix * * Doc fix * * Bug fix * * Bug fix * * Bug fix * * Bug fix * * Bug fix * * Test fix * * refactor validator mapping * * Code style fix * * Fix conflict * * Fix conflict * * Remove default instance of ConfigValidateFacade * * Remove default instance of ConfigValidateFacade * * Add license --- .../common/constants/CommonConstants.java | 2 + .../apache/dubbo/config/AbstractConfig.java | 7 + .../dubbo/config/ConfigValidateFacade.java | 115 +++ .../config/context/AbstractConfigManager.java | 13 +- .../dubbo/config/context/ConfigValidator.java | 20 +- .../exception/ConfigValidationException.java | 39 + .../config/utils/ConfigValidationUtils.java | 355 +++++++++ .../validator/ApplicationConfigValidator.java | 97 +++ .../validator/ModuleConfigValidator.java | 49 ++ .../org/apache/dubbo/registry/Constants.java | 0 .../apache/dubbo/rpc/cluster/Constants.java | 0 ...pache.dubbo.config.context.ConfigValidator | 2 + .../config/context/ConfigManagerTest.java | 2 + .../config/ConfigScopeModelInitializer.java | 3 - .../apache/dubbo/config/ReferenceConfig.java | 6 +- .../apache/dubbo/config/ServiceConfig.java | 5 +- .../application/ApplicationLifecycle.java | 3 + .../ConfigCenterApplicationLifecycle.java | 5 +- .../MetadataInitializeLifecycle.java | 4 +- .../ValidatorRegistryDeployListener.java | 41 + .../config/utils/ConfigValidationUtils.java | 741 ------------------ .../config/utils/DefaultConfigValidator.java | 62 -- .../ConfigCenterConfigValidator.java | 44 ++ .../validator/ConsumerConfigValidator.java | 42 + .../validator/InterfaceConfigValidator.java | 68 ++ .../validator/MethodConfigValidator.java | 63 ++ .../validator/ProviderConfigValidator.java | 58 ++ .../validator/ReferenceConfigValidator.java | 65 ++ .../validator/ServiceConfigValidator.java | 78 ++ ...pache.dubbo.config.context.ConfigValidator | 8 + ...lifecycle.application.ApplicationLifecycle | 1 + .../dubbo/config/AbstractConfigTest.java | 2 +- .../config/ConfigValidatorExistTest.java | 94 +++ .../config/bootstrap/DubboBootstrapTest.java | 18 +- .../utils/ConfigValidationUtilsTest.java | 39 +- dubbo-distribution/dubbo-all/pom.xml | 7 + .../validator/MetadataConfigValidator.java | 64 ++ ...pache.dubbo.config.context.ConfigValidator | 1 + .../validator/MetricsConfigValidator.java | 42 + ...pache.dubbo.config.context.ConfigValidator | 1 + .../collector/DefaultCollectorTest.java | 5 +- .../validator/TracingConfigValidator.java | 42 + ...pache.dubbo.config.context.ConfigValidator | 1 + .../org/apache/dubbo/util/MonitorUrlUtil.java | 102 +++ .../validator/MonitorConfigValidator.java | 53 ++ ...pache.dubbo.config.context.ConfigValidator | 1 + .../cert/CertDeployerListenerTest.java | 3 +- .../validate/RegistryConfigValidator.java | 56 ++ .../config/validator/SslConfigValidator.java | 40 + ...pache.dubbo.config.context.ConfigValidator | 1 + .../validator/ProtocolConfigValidator.java | 82 ++ ...pache.dubbo.config.context.ConfigValidator | 1 + 52 files changed, 1800 insertions(+), 853 deletions(-) create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/config/ConfigValidateFacade.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/config/exception/ConfigValidationException.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/config/validator/ApplicationConfigValidator.java create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/config/validator/ModuleConfigValidator.java rename {dubbo-registry/dubbo-registry-api => dubbo-common}/src/main/java/org/apache/dubbo/registry/Constants.java (100%) rename {dubbo-cluster => dubbo-common}/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java (100%) create mode 100644 dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator create mode 100644 dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ValidatorRegistryDeployListener.java delete mode 100644 dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java delete mode 100644 dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/DefaultConfigValidator.java create mode 100644 dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConfigCenterConfigValidator.java create mode 100644 dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConsumerConfigValidator.java create mode 100644 dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/InterfaceConfigValidator.java create mode 100644 dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/MethodConfigValidator.java create mode 100644 dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ProviderConfigValidator.java create mode 100644 dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ReferenceConfigValidator.java create mode 100644 dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ServiceConfigValidator.java create mode 100644 dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator create mode 100644 dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigValidatorExistTest.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/config/validator/MetadataConfigValidator.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator create mode 100644 dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/config/validator/MetricsConfigValidator.java create mode 100644 dubbo-metrics/dubbo-metrics-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator create mode 100644 dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/config/validator/TracingConfigValidator.java create mode 100644 dubbo-metrics/dubbo-tracing/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator create mode 100644 dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/util/MonitorUrlUtil.java create mode 100644 dubbo-monitor/dubbo-monitor-common/src/main/java/org/apache/dubbo/config/validator/MonitorConfigValidator.java create mode 100644 dubbo-monitor/dubbo-monitor-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator create mode 100644 dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/config/validate/RegistryConfigValidator.java create mode 100644 dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/config/validator/SslConfigValidator.java create mode 100644 dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator create mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/config/validator/ProtocolConfigValidator.java create mode 100644 dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java index 3380621774..4224da82fd 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java @@ -337,6 +337,8 @@ public interface CommonConstants { String REGISTRY_PROTOCOL_LISTENER_KEY = "registry.protocol.listener"; + String REGISTRY_SERVICE_CLASS_NAME = "org.apache.dubbo.registry.RegistryService"; + String DUBBO_VERSION_KEY = "dubbo"; String TAG_KEY = "dubbo.tag"; diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java index 75a80c8999..3c23216f09 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java @@ -172,6 +172,13 @@ public abstract class AbstractConfig implements Serializable { appendParameters0(parameters, config, prefix, false); } + public boolean validate() { + if(scopeModel == null || scopeModel.getBeanFactory() == null || scopeModel.getBeanFactory().isDestroyed()){ + return ConfigValidateFacade.getDefaultInstance().validate(this); + } + return scopeModel.getBeanFactory().getOrRegisterBean(ConfigValidateFacade.class,clz -> new ConfigValidateFacade(scopeModel)).validate(this); + } + private static void appendParameters0(Map parameters, Object config, String prefix, boolean asParameters) { if (config == null) { return; diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ConfigValidateFacade.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ConfigValidateFacade.java new file mode 100644 index 0000000000..732ec39f30 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ConfigValidateFacade.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config; + +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.config.context.ConfigValidator; +import org.apache.dubbo.config.exception.ConfigValidationException; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.ScopeModel; + +import java.util.Collections; +import java.util.List; + +@SuppressWarnings({"rawtypes", "unchecked"}) +public class ConfigValidateFacade implements ConfigValidator{ + + private static final Logger LOGGER = LoggerFactory.getErrorTypeAwareLogger(ConfigValidateFacade.class); + + private final List validators; + + /** + * For test + */ + private static boolean enableValidate = true; + + public ConfigValidateFacade(ScopeModel scopeModel) { + if(scopeModel != null) { + ExtensionLoader extensionLoader = scopeModel.getExtensionLoader(ConfigValidator.class); + if (extensionLoader != null) { + this.validators = extensionLoader.getActivateExtensions(); + this.validators.forEach(scopeModel.getBeanFactory()::registerBean); + } else { + this.validators = Collections.emptyList(); + } + }else { + this.validators = Collections.emptyList(); + } + } + + public List getValidators() { + return validators; + } + + /** + * Auto choose a appropriate validator to validate config. + * + * @param config the config to validate + * @return TRUE if pass the validation. + * FALSE if no ConfigValidator found for this config, + * or one of the supported {@link ConfigValidator#validate(AbstractConfig)} returns FALSE. + */ + @Override + public boolean validate(AbstractConfig config) throws ConfigValidationException{ + if(!enableValidate){ + return true; + } + if (config == null) { + return false; + } + boolean validated = false; + try { + for (ConfigValidator validator : validators) { + if (validator.isSupport(config.getClass())) { + validated = true; + if(!validator.validate(config)){ + return false; + } + } + } + }catch (Throwable t){ + throw new ConfigValidationException(config.getClass().getSimpleName()+" validation failed: "+t.getMessage(),t); + } + if (!validated) { + LOGGER.info(config.getClass().getSimpleName()+" is not validated. This may caused by you did not imported the relevant module."); + } + return validated; + } + + @Override + public boolean isSupport(Class configClass) { + return true; + } + + /** + * For test + */ + @Deprecated + public static ConfigValidateFacade getDefaultInstance() { + return ApplicationModel.defaultModel().getBeanFactory().getOrRegisterBean(ConfigValidateFacade.class); + } + + /** + * For test + */ + @Deprecated + public static void setEnableValidate(boolean enable){ + enableValidate = enable; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java index 0f8a0e23d4..d61009799d 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java @@ -31,6 +31,7 @@ import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.AbstractConfig; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ConfigKeys; +import org.apache.dubbo.config.ConfigValidateFacade; import org.apache.dubbo.config.MetadataReportConfig; import org.apache.dubbo.config.MetricsConfig; import org.apache.dubbo.config.ModuleConfig; @@ -585,10 +586,8 @@ public abstract class AbstractConfigManager extends LifecycleAdapter { // validate configs Collection configs = this.getConfigs(configType); - if (getConfigValidator() != null) { - for (T config : configs) { - getConfigValidator().validate(config); - } + for (T config : configs) { + getConfigValidator().validate(config); } // check required default @@ -611,11 +610,11 @@ public abstract class AbstractConfigManager extends LifecycleAdapter { return true; } - private ConfigValidator getConfigValidator() { + private ConfigValidateFacade getConfigValidator() { if (configValidator == null) { - configValidator = applicationModel.getBeanFactory().getBean(ConfigValidator.class); + configValidator = applicationModel.getBeanFactory().getOrRegisterBean(ConfigValidateFacade.class, clz -> new ConfigValidateFacade(scopeModel)); } - return configValidator; + return (ConfigValidateFacade) configValidator; } /** diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java index 7d20b1b658..22b630f158 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java @@ -16,10 +16,26 @@ */ package org.apache.dubbo.config.context; +import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.config.AbstractConfig; +import org.apache.dubbo.config.exception.ConfigValidationException; -public interface ConfigValidator { +/** + * ConfigValidator. Allow provides an optional validation logic for a {@link AbstractConfig} impl. + * @param type of {@link AbstractConfig} implement + */ +@SPI +public interface ConfigValidator { - void validate(AbstractConfig config); + /** + * Validate a config. + * If the config does not pass validation, returns false or throws exception, depends on implementation. + * + * @param config the config to validate + * @return TRUE if pass validation + */ + boolean validate(T config) throws ConfigValidationException; + + boolean isSupport(Class configClass); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/exception/ConfigValidationException.java b/dubbo-common/src/main/java/org/apache/dubbo/config/exception/ConfigValidationException.java new file mode 100644 index 0000000000..5ee95d0c54 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/exception/ConfigValidationException.java @@ -0,0 +1,39 @@ +/* + * 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.exception; + +/** + * Config validation exception + */ +public class ConfigValidationException extends RuntimeException { + + public ConfigValidationException(String message) { + super(message); + } + + public ConfigValidationException(String message, Throwable cause) { + super(message, cause); + } + + public ConfigValidationException(Throwable cause) { + super(cause); + } + + public ConfigValidationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java new file mode 100644 index 0000000000..f4313a0b2a --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java @@ -0,0 +1,355 @@ +/* + * 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.utils; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.URLBuilder; +import org.apache.dubbo.common.config.ConfigurationUtils; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.status.reporter.FrameworkStatusReportService; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.common.utils.UrlUtils; +import org.apache.dubbo.config.AbstractConfig; +import org.apache.dubbo.config.AbstractInterfaceConfig; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.registry.Constants; +import org.apache.dubbo.rpc.model.ScopeModel; +import org.apache.dubbo.rpc.model.ScopeModelUtil; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL; +import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SERVICE_CLASS_NAME; +import static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_PARAMETER_FORMAT_ERROR; + +import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_ALL; +import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INSTANCE; +import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INTERFACE; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL; +import static org.apache.dubbo.common.constants.RegistryConstants.DUBBO_REGISTER_MODE_DEFAULT_KEY; +import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY; +import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; +import static org.apache.dubbo.config.Constants.IGNORE_CHECK_KEYS; +import static org.apache.dubbo.config.Constants.REGISTER_KEY; + +public class ConfigValidationUtils { + public static final String IPV6_START_MARK = "["; + public static final String IPV6_END_MARK = "]"; + /** + * The maximum length of a parameter's value + */ + private static final int MAX_LENGTH = 200; + /** + * The maximum length of a path + */ + private static final int MAX_PATH_LENGTH = 200; + /** + * The rule qualification for name + */ + private static final Pattern PATTERN_NAME = Pattern.compile("[\\-._0-9a-zA-Z]+"); + /** + * The rule qualification for multiply name + */ + private static final Pattern PATTERN_MULTI_NAME = Pattern.compile("[,\\-._0-9a-zA-Z]+"); + /** + * The rule qualification for method names + */ + private static final Pattern PATTERN_METHOD_NAME = Pattern.compile("[a-zA-Z][0-9a-zA-Z]*"); + /** + * The rule qualification for path + */ + private static final Pattern PATTERN_PATH = Pattern.compile("[/\\-$._0-9a-zA-Z]+"); + /** + * The pattern matches a value who has a symbol + */ + private static final Pattern PATTERN_NAME_HAS_SYMBOL = Pattern.compile("[:*,\\s/\\-._0-9a-zA-Z]+"); + /** + * The pattern matches a property key + */ + private static final Pattern PATTERN_KEY = Pattern.compile("[*,\\-._0-9a-zA-Z]+"); + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ConfigValidationUtils.class); + + public static List loadRegistries(AbstractInterfaceConfig interfaceConfig, boolean provider) { + // check && override if necessary + List registryList = new ArrayList<>(); + ApplicationConfig application = interfaceConfig.getApplication(); + List registries = interfaceConfig.getRegistries(); + if (CollectionUtils.isNotEmpty(registries)) { + for (RegistryConfig config : registries) { + // try to refresh registry in case it is set directly by user using config.setRegistries() + if (!config.isRefreshed()) { + config.refresh(); + } + String address = config.getAddress(); + if (StringUtils.isEmpty(address)) { + address = ANYHOST_VALUE; + } + if (!RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) { + Map map = new HashMap(); + AbstractConfig.appendParameters(map, application); + AbstractConfig.appendParameters(map, config); + map.put(PATH_KEY,REGISTRY_SERVICE_CLASS_NAME); + AbstractInterfaceConfig.appendRuntimeParameters(map); + if (!map.containsKey(PROTOCOL_KEY)) { + map.put(PROTOCOL_KEY, DUBBO_PROTOCOL); + } + List urls = UrlUtils.parseURLs(address, map); + + for (URL url : urls) { + url = URLBuilder.from(url) + .addParameter(REGISTRY_KEY, url.getProtocol()) + .setProtocol(extractRegistryType(url)) + .setScopeModel(interfaceConfig.getScopeModel()) + .build(); + // provider delay register state will be checked in RegistryProtocol#export + if (provider && url.getParameter(REGISTER_KEY, true)) { + registryList.add(url); + } + if (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true)) { + registryList.add(url); + } + } + } + } + } + return genCompatibleRegistries(interfaceConfig.getScopeModel(), registryList, provider); + } + + private static List genCompatibleRegistries(ScopeModel scopeModel, List registryList, boolean provider) { + List result = new ArrayList<>(registryList.size()); + registryList.forEach(registryURL -> { + if (provider) { + // for registries enabled service discovery, automatically register interface compatible addresses. + String registerMode; + if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) { + registerMode = registryURL.getParameter(REGISTER_MODE_KEY, ConfigurationUtils.getCachedDynamicProperty(scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_INSTANCE)); + if (!isValidRegisterMode(registerMode)) { + registerMode = DEFAULT_REGISTER_MODE_INSTANCE; + } + result.add(registryURL); + if (DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode) + && registryNotExists(registryURL, registryList, REGISTRY_PROTOCOL)) { + URL interfaceCompatibleRegistryURL = URLBuilder.from(registryURL) + .setProtocol(REGISTRY_PROTOCOL) + .removeParameter(REGISTRY_TYPE_KEY) + .build(); + result.add(interfaceCompatibleRegistryURL); + } + } else { + registerMode = registryURL.getParameter(REGISTER_MODE_KEY, ConfigurationUtils.getCachedDynamicProperty(scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_ALL)); + if (!isValidRegisterMode(registerMode)) { + registerMode = DEFAULT_REGISTER_MODE_INTERFACE; + } + if ((DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)) + && registryNotExists(registryURL, registryList, SERVICE_REGISTRY_PROTOCOL)) { + URL serviceDiscoveryRegistryURL = URLBuilder.from(registryURL) + .setProtocol(SERVICE_REGISTRY_PROTOCOL) + .removeParameter(REGISTRY_TYPE_KEY) + .build(); + result.add(serviceDiscoveryRegistryURL); + } + + if (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)) { + result.add(registryURL); + } + } + + FrameworkStatusReportService reportService = ScopeModelUtil.getApplicationModel(scopeModel).getBeanFactory().getBean(FrameworkStatusReportService.class); + reportService.reportRegistrationStatus(reportService.createRegistrationReport(registerMode)); + } else { + result.add(registryURL); + } + }); + + return result; + } + + private static boolean isValidRegisterMode(String mode) { + return isNotEmpty(mode) + && (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(mode) + || DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(mode) + || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(mode) + ); + } + + private static boolean registryNotExists(URL registryURL, List registryList, String registryType) { + return registryList.stream().noneMatch( + url -> registryType.equals(url.getProtocol()) && registryURL.getBackupAddress().equals(url.getBackupAddress()) + ); + } + + private static String extractRegistryType(URL url) { + return UrlUtils.hasServiceDiscoveryRegistryTypeKey(url) ? SERVICE_REGISTRY_PROTOCOL : getRegistryProtocolType(url); + } + + private static String getRegistryProtocolType(URL url) { + String registryProtocol = url.getParameter("registry-protocol-type"); + return isNotEmpty(registryProtocol) ? registryProtocol : REGISTRY_PROTOCOL; + } + + public static void checkExtension(ScopeModel scopeModel, Class type, String property, String value) { + checkName(property, value); + if (isNotEmpty(value) + && !scopeModel.getExtensionLoader(type).hasExtension(value)) { + throw new IllegalStateException("No such extension " + value + " for " + property + "/" + type.getName()); + } + } + + /** + * Check whether there is a Extension who's name (property) is value (special treatment is + * required) + * + * @param type The Extension type + * @param property The extension key + * @param value The Extension name + */ + public static void checkMultiExtension(ScopeModel scopeModel, Class type, String property, String value) { + checkMultiExtension(scopeModel, Collections.singletonList(type), property, value); + } + + public static void checkMultiExtension(ScopeModel scopeModel, List> types, String property, String value) { + checkMultiName(property, value); + if (isNotEmpty(value)) { + String[] values = value.split("\\s*[,]+\\s*"); + for (String v : values) { + v = StringUtils.trim(v); + if (v.startsWith(REMOVE_VALUE_PREFIX)) { + continue; + } + if (DEFAULT_KEY.equals(v)) { + continue; + } + boolean match = false; + for (Class type : types) { + if (scopeModel.getExtensionLoader(type).hasExtension(v)) { + match = true; + } + } + if (!match) { + throw new IllegalStateException("No such extension " + v + " for " + property + "/" + + types.stream().map(Class::getName).collect(Collectors.joining(","))); + } + } + } + } + + public static void checkLength(String property, String value) { + checkProperty(property, value, MAX_LENGTH, null); + } + + public static void checkPathLength(String property, String value) { + checkProperty(property, value, MAX_PATH_LENGTH, null); + } + + public static void checkName(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_NAME); + } + + public static void checkHost(String property, String value) { + if (StringUtils.isEmpty(value)) { + return; + } + if (value.startsWith(IPV6_START_MARK) && value.endsWith(IPV6_END_MARK)) { + // if the value start with "[" and end with "]", check whether it is IPV6 + try { + InetAddress.getByName(value); + return; + } catch (UnknownHostException e) { + // not a IPv6 string, do nothing, go on to checkName + } + } + checkName(property, value); + } + + public static void checkNameHasSymbol(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_NAME_HAS_SYMBOL); + } + + public static void checkKey(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_KEY); + } + + public static void checkMultiName(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_MULTI_NAME); + } + + public static void checkPathName(String property, String value) { + checkProperty(property, value, MAX_PATH_LENGTH, PATTERN_PATH); + } + + public static void checkMethodName(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_METHOD_NAME); + } + + public static void checkParameterName(Map parameters) { + if (CollectionUtils.isEmptyMap(parameters)) { + return; + } + List ignoreCheckKeys = new ArrayList<>(); + ignoreCheckKeys.add(BACKUP_KEY); + String ignoreCheckKeysStr = parameters.get(IGNORE_CHECK_KEYS); + if (!StringUtils.isBlank(ignoreCheckKeysStr)) { + ignoreCheckKeys.addAll(Arrays.asList(ignoreCheckKeysStr.split(","))); + } + for (Map.Entry entry : parameters.entrySet()) { + if (!ignoreCheckKeys.contains(entry.getKey())) { + checkNameHasSymbol(entry.getKey(), entry.getValue()); + } + } + } + + public static void checkProperty(String property, String value, int maxlength, Pattern pattern) { + if (StringUtils.isEmpty(value)) { + return; + } + if (value.length() > maxlength) { + logger.error(CONFIG_PARAMETER_FORMAT_ERROR, "the value content is too long", "", "Parameter value format error. Invalid " + + property + "=\"" + value + "\" is longer than " + maxlength); + } + if (pattern != null) { + Matcher matcher = pattern.matcher(value); + if (!matcher.matches()) { + logger.error(CONFIG_PARAMETER_FORMAT_ERROR, "the value content is illegal character", "", "Parameter value format error. Invalid " + + property + "=\"" + value + "\" contains illegal " + + "character, only digit, letter, '-', '_' or '.' is legal."); + } + } + } + +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ApplicationConfigValidator.java b/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ApplicationConfigValidator.java new file mode 100644 index 0000000000..c9563aab88 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ApplicationConfigValidator.java @@ -0,0 +1,97 @@ +/* + * 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.validator; + +import org.apache.dubbo.common.config.PropertiesConfiguration; +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.ClassUtils; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.context.ConfigValidator; +import org.apache.dubbo.config.exception.ConfigValidationException; +import org.apache.dubbo.config.utils.ConfigValidationUtils; +import org.apache.dubbo.rpc.model.ScopeModel; +import org.apache.dubbo.rpc.model.ScopeModelUtil; + +import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CLASS_NOT_FOUND; +import static org.apache.dubbo.config.Constants.ARCHITECTURE; +import static org.apache.dubbo.config.Constants.ENVIRONMENT; +import static org.apache.dubbo.config.Constants.NAME; +import static org.apache.dubbo.config.Constants.ORGANIZATION; +import static org.apache.dubbo.config.Constants.OWNER; + +@Activate +public class ApplicationConfigValidator implements ConfigValidator { + + private static ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ApplicationConfigValidator.class); + + public static void validateApplicationConfig(ApplicationConfig config) { + if (config == null) { + return; + } + + if (!config.isValid()) { + throw new ConfigValidationException("No application config found or it's not a valid config! " + + "Please add to your spring config."); + } + + // backward compatibility + ScopeModel scopeModel = ScopeModelUtil.getOrDefaultApplicationModel(config.getScopeModel()); + PropertiesConfiguration configuration = scopeModel.modelEnvironment().getPropertiesConfiguration(); + String wait = configuration.getProperty(SHUTDOWN_WAIT_KEY); + if (wait != null && wait.trim().length() > 0) { + System.setProperty(SHUTDOWN_WAIT_KEY, wait.trim()); + } else { + wait = configuration.getProperty(SHUTDOWN_WAIT_SECONDS_KEY); + if (wait != null && wait.trim().length() > 0) { + System.setProperty(SHUTDOWN_WAIT_SECONDS_KEY, wait.trim()); + } + } + + ConfigValidationUtils.checkName(NAME, config.getName()); + ConfigValidationUtils.checkMultiName(OWNER, config.getOwner()); + ConfigValidationUtils.checkName(ORGANIZATION, config.getOrganization()); + ConfigValidationUtils.checkName(ARCHITECTURE, config.getArchitecture()); + ConfigValidationUtils.checkName(ENVIRONMENT, config.getEnvironment()); + ConfigValidationUtils.checkParameterName(config.getParameters()); + checkQosDependency(config); + } + + public static void checkQosDependency(ApplicationConfig config) { + if (!Boolean.FALSE.equals(config.getQosEnable())) { + try { + ClassUtils.forName("org.apache.dubbo.qos.protocol.QosProtocolWrapper"); + } catch (ClassNotFoundException e) { + logger.warn(COMMON_CLASS_NOT_FOUND, "", "", "No QosProtocolWrapper class was found. Please check the dependency of dubbo-qos whether was imported correctly.", e); + } + } + } + + @Override + public boolean validate(ApplicationConfig config) { + validateApplicationConfig(config); + return true; + } + + @Override + public boolean isSupport(Class configClass) { + return ApplicationConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ModuleConfigValidator.java b/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ModuleConfigValidator.java new file mode 100644 index 0000000000..85ddd314aa --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ModuleConfigValidator.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.ModuleConfig; +import org.apache.dubbo.config.context.ConfigValidator; +import org.apache.dubbo.config.utils.ConfigValidationUtils; + +import static org.apache.dubbo.config.Constants.NAME; +import static org.apache.dubbo.config.Constants.ORGANIZATION; +import static org.apache.dubbo.config.Constants.OWNER; + +@Activate +public class ModuleConfigValidator implements ConfigValidator { + + @Override + public boolean validate(ModuleConfig config) { + validateModuleConfig(config); + return true; + } + + public static void validateModuleConfig(ModuleConfig config) { + if (config != null) { + ConfigValidationUtils.checkName(NAME, config.getName()); + ConfigValidationUtils.checkName(OWNER, config.getOwner()); + ConfigValidationUtils.checkName(ORGANIZATION, config.getOrganization()); + } + } + + @Override + public boolean isSupport(Class configClass) { + return ModuleConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Constants.java b/dubbo-common/src/main/java/org/apache/dubbo/registry/Constants.java similarity index 100% rename from dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Constants.java rename to dubbo-common/src/main/java/org/apache/dubbo/registry/Constants.java diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java similarity index 100% rename from dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java rename to dubbo-common/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java diff --git a/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator new file mode 100644 index 0000000000..8fe3a6c328 --- /dev/null +++ b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator @@ -0,0 +1,2 @@ +application=org.apache.dubbo.config.validator.ApplicationConfigValidator +module=org.apache.dubbo.config.validator.ModuleConfigValidator diff --git a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java index 5ddd74aad4..00d1ec7fcc 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java @@ -19,6 +19,7 @@ package org.apache.dubbo.config.context; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ConfigCenterConfig; +import org.apache.dubbo.config.ConfigValidateFacade; import org.apache.dubbo.config.ConsumerConfig; import org.apache.dubbo.config.MetricsConfig; import org.apache.dubbo.config.ModuleConfig; @@ -64,6 +65,7 @@ class ConfigManagerTest { ApplicationModel applicationModel = ApplicationModel.defaultModel(); configManager = applicationModel.getApplicationConfigManager(); moduleConfigManager = applicationModel.getDefaultModule().getConfigManager(); + ConfigValidateFacade.setEnableValidate(false); } @Test diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java index 955da26d23..fa82316dca 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java @@ -22,7 +22,6 @@ import org.apache.dubbo.common.deploy.ModuleDeployer; import org.apache.dubbo.config.deploy.DefaultApplicationDeployer; import org.apache.dubbo.config.deploy.DefaultModuleDeployer; import org.apache.dubbo.config.deploy.FrameworkModelCleaner; -import org.apache.dubbo.config.utils.DefaultConfigValidator; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.model.ModuleModel; @@ -38,11 +37,9 @@ public class ConfigScopeModelInitializer implements ScopeModelInitializer { @Override public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); - beanFactory.registerBean(DefaultConfigValidator.class); // applicationDeployer ApplicationDeployer applicationDeployer = beanFactory.registerBean(DefaultApplicationDeployer.class); applicationModel.setDeployer(applicationDeployer); - } @Override diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java index c11f9c3f62..924b1a9cb8 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java @@ -53,6 +53,7 @@ import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol; import org.apache.dubbo.rpc.service.GenericService; import org.apache.dubbo.rpc.stub.StubSuppliers; import org.apache.dubbo.rpc.support.ProtocolUtils; +import org.apache.dubbo.util.MonitorUrlUtil; import java.beans.Transient; import java.util.ArrayList; @@ -179,7 +180,6 @@ public class ReferenceConfig extends ReferenceConfigBase { @Override protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) { super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel); - protocolSPI = this.getExtensionLoader(Protocol.class).getAdaptiveExtension(); proxyFactory = this.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); } @@ -579,7 +579,7 @@ public class ReferenceConfig extends ReferenceConfigBase { List us = ConfigValidationUtils.loadRegistries(this, false); if (CollectionUtils.isNotEmpty(us)) { for (URL u : us) { - URL monitorUrl = ConfigValidationUtils.loadMonitor(this, u); + URL monitorUrl = MonitorUrlUtil.loadMonitor(this, u); if (monitorUrl != null) { u = u.putAttribute(MONITOR_KEY, monitorUrl); } @@ -746,7 +746,7 @@ public class ReferenceConfig extends ReferenceConfigBase { } resolveFile(); - ConfigValidationUtils.validateReferenceConfig(this); + validate(); postProcessConfig(); } 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 d9d6862255..91dde23fda 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 @@ -54,6 +54,7 @@ import org.apache.dubbo.rpc.model.ProviderModel; import org.apache.dubbo.rpc.model.ScopeModel; import org.apache.dubbo.rpc.model.ServiceDescriptor; import org.apache.dubbo.rpc.service.GenericService; +import org.apache.dubbo.util.MonitorUrlUtil; import java.beans.Transient; import java.lang.reflect.Method; @@ -468,7 +469,7 @@ public class ServiceConfig extends ServiceConfigBase { } } checkStubAndLocal(interfaceClass); - ConfigValidationUtils.validateServiceConfig(this); + validate(); postProcessConfig(); } @@ -805,7 +806,7 @@ public class ServiceConfig extends ServiceConfigBase { } url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY)); - URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL); + URL monitorUrl = MonitorUrlUtil.loadMonitor(this, registryURL); if (monitorUrl != null) { url = url.putAttribute(MONITOR_KEY, monitorUrl); } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ApplicationLifecycle.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ApplicationLifecycle.java index 505c228cf4..08aaeb2060 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ApplicationLifecycle.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ApplicationLifecycle.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.config.deploy.lifecycle.application; +import org.apache.dubbo.common.deploy.ApplicationDeployListener; import org.apache.dubbo.common.deploy.DeployState; import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.config.deploy.context.ApplicationContext; @@ -27,6 +28,8 @@ import org.apache.dubbo.rpc.model.ModuleModel; *
* Used in an application Lifecycle managing procedure, and dubbo packages * can implement this interface to define what to do when application status changes. + *

+ * Note: If you want to auto registry some extensions to BeanFactory, use {@link ApplicationDeployListener} instead. *
*/ @SPI diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ConfigCenterApplicationLifecycle.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ConfigCenterApplicationLifecycle.java index 82515fe48e..90e4926385 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ConfigCenterApplicationLifecycle.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ConfigCenterApplicationLifecycle.java @@ -34,7 +34,6 @@ import org.apache.dubbo.config.ConfigCenterConfig; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.deploy.context.ApplicationContext; -import org.apache.dubbo.config.utils.ConfigValidationUtils; import org.apache.dubbo.metrics.config.event.ConfigCenterEvent; import org.apache.dubbo.metrics.event.MetricsEventBus; import org.apache.dubbo.rpc.model.ApplicationModel; @@ -85,7 +84,7 @@ public class ConfigCenterApplicationLifecycle implements ApplicationLifecycle { ConfigCenterConfig configCenterConfig = new ConfigCenterConfig(); configCenterConfig.setScopeModel(applicationModel); configCenterConfig.refresh(); - ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig); + configCenterConfig.validate(); if (configCenterConfig.isValid()) { configManager.addConfigCenter(configCenterConfig); configCenters = configManager.getConfigCenters(); @@ -93,7 +92,7 @@ public class ConfigCenterApplicationLifecycle implements ApplicationLifecycle { } else { for (ConfigCenterConfig configCenterConfig : configCenters) { configCenterConfig.refresh(); - ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig); + configCenterConfig.validate(); } } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/MetadataInitializeLifecycle.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/MetadataInitializeLifecycle.java index fb35d4a141..a9e9bfdf4f 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/MetadataInitializeLifecycle.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/MetadataInitializeLifecycle.java @@ -28,7 +28,6 @@ import org.apache.dubbo.config.MetadataReportConfig; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.deploy.context.ApplicationContext; -import org.apache.dubbo.config.utils.ConfigValidationUtils; import org.apache.dubbo.metadata.report.MetadataReportFactory; import org.apache.dubbo.metadata.report.MetadataReportInstance; import org.apache.dubbo.rpc.model.ApplicationModel; @@ -91,8 +90,7 @@ public class MetadataInitializeLifecycle implements ApplicationLifecycle { List validMetadataReportConfigs = new ArrayList<>(metadataReportConfigs.size()); for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) { - if (ConfigValidationUtils.isValidMetadataConfig(metadataReportConfig)) { - ConfigValidationUtils.validateMetadataConfig(metadataReportConfig); + if (metadataReportConfig.validate()) { validMetadataReportConfigs.add(metadataReportConfig); } } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ValidatorRegistryDeployListener.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ValidatorRegistryDeployListener.java new file mode 100644 index 0000000000..3f5d75ffcf --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ValidatorRegistryDeployListener.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.deploy.lifecycle.application; + +import org.apache.dubbo.common.deploy.ApplicationDeployListener; +import org.apache.dubbo.config.ConfigValidateFacade; +import org.apache.dubbo.rpc.model.ApplicationModel; + +public class ValidatorRegistryDeployListener implements ApplicationDeployListener { + + @Override + public void onStarting(ApplicationModel scopeModel) { + ConfigValidateFacade validateFacade = new ConfigValidateFacade(scopeModel); + scopeModel.getBeanFactory().registerBean(validateFacade); + } + + @Override + public void onInitialize(ApplicationModel scopeModel) {} + @Override + public void onStarted(ApplicationModel scopeModel) {} + @Override + public void onStopping(ApplicationModel scopeModel) {} + @Override + public void onStopped(ApplicationModel scopeModel) {} + @Override + public void onFailure(ApplicationModel scopeModel, Throwable cause) {} +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java deleted file mode 100644 index 1f92b894ad..0000000000 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java +++ /dev/null @@ -1,741 +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.config.utils; - -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.URLBuilder; -import org.apache.dubbo.common.config.ConfigurationUtils; -import org.apache.dubbo.common.config.PropertiesConfiguration; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.serialize.Serialization; -import org.apache.dubbo.common.status.StatusChecker; -import org.apache.dubbo.common.status.reporter.FrameworkStatusReportService; -import org.apache.dubbo.common.threadpool.ThreadPool; -import org.apache.dubbo.common.utils.ClassUtils; -import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.common.utils.ConfigUtils; -import org.apache.dubbo.common.utils.NetUtils; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.common.utils.UrlUtils; -import org.apache.dubbo.config.AbstractConfig; -import org.apache.dubbo.config.AbstractInterfaceConfig; -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.MetricsConfig; -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.ReferenceConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.SslConfig; -import org.apache.dubbo.config.TracingConfig; -import org.apache.dubbo.monitor.MonitorFactory; -import org.apache.dubbo.monitor.MonitorService; -import org.apache.dubbo.registry.RegistryService; -import org.apache.dubbo.remoting.Codec2; -import org.apache.dubbo.remoting.Dispatcher; -import org.apache.dubbo.remoting.Transporter; -import org.apache.dubbo.remoting.exchange.Exchanger; -import org.apache.dubbo.remoting.telnet.TelnetHandler; -import org.apache.dubbo.rpc.ExporterListener; -import org.apache.dubbo.rpc.Filter; -import org.apache.dubbo.rpc.InvokerListener; -import org.apache.dubbo.rpc.ProxyFactory; -import org.apache.dubbo.rpc.cluster.Cluster; -import org.apache.dubbo.rpc.cluster.LoadBalance; -import org.apache.dubbo.rpc.cluster.filter.ClusterFilter; -import org.apache.dubbo.rpc.model.ScopeModel; -import org.apache.dubbo.rpc.model.ScopeModelUtil; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE; -import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_MONITOR_ADDRESS; -import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL; -import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.FILTER_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE; -import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX; -import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; -import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CLASS_NOT_FOUND; -import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_PARAMETER_FORMAT_ERROR; -import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_ALL; -import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INSTANCE; -import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INTERFACE; -import static org.apache.dubbo.common.constants.RegistryConstants.DUBBO_REGISTER_MODE_DEFAULT_KEY; -import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY; -import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY; -import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL; -import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY; -import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL; -import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY; -import static org.apache.dubbo.common.utils.StringUtils.isEmpty; -import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; -import static org.apache.dubbo.config.Constants.ARCHITECTURE; -import static org.apache.dubbo.config.Constants.CONTEXTPATH_KEY; -import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY; -import static org.apache.dubbo.config.Constants.ENVIRONMENT; -import static org.apache.dubbo.config.Constants.IGNORE_CHECK_KEYS; -import static org.apache.dubbo.config.Constants.LAYER_KEY; -import static org.apache.dubbo.config.Constants.NAME; -import static org.apache.dubbo.config.Constants.ORGANIZATION; -import static org.apache.dubbo.config.Constants.OWNER; -import static org.apache.dubbo.config.Constants.REGISTER_KEY; -import static org.apache.dubbo.config.Constants.STATUS_KEY; -import static org.apache.dubbo.monitor.Constants.LOGSTAT_PROTOCOL; -import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY; -import static org.apache.dubbo.registry.Constants.SUBSCRIBE_KEY; -import static org.apache.dubbo.remoting.Constants.CLIENT_KEY; -import static org.apache.dubbo.remoting.Constants.CODEC_KEY; -import static org.apache.dubbo.remoting.Constants.DISPATCHER_KEY; -import static org.apache.dubbo.remoting.Constants.EXCHANGER_KEY; -import static org.apache.dubbo.remoting.Constants.SERIALIZATION_KEY; -import static org.apache.dubbo.remoting.Constants.SERVER_KEY; -import static org.apache.dubbo.remoting.Constants.TELNET_KEY; -import static org.apache.dubbo.remoting.Constants.TRANSPORTER_KEY; -import static org.apache.dubbo.rpc.Constants.FAIL_PREFIX; -import static org.apache.dubbo.rpc.Constants.FORCE_PREFIX; -import static org.apache.dubbo.rpc.Constants.LOCAL_KEY; -import static org.apache.dubbo.rpc.Constants.MOCK_KEY; -import static org.apache.dubbo.rpc.Constants.PROXY_KEY; -import static org.apache.dubbo.rpc.Constants.RETURN_PREFIX; -import static org.apache.dubbo.rpc.Constants.THROW_PREFIX; -import static org.apache.dubbo.rpc.Constants.TOKEN_KEY; -import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY; - -public class ConfigValidationUtils { - private static ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ConfigValidationUtils.class); - /** - * The maximum length of a parameter's value - */ - private static final int MAX_LENGTH = 200; - - /** - * The maximum length of a path - */ - private static final int MAX_PATH_LENGTH = 200; - - /** - * The rule qualification for name - */ - private static final Pattern PATTERN_NAME = Pattern.compile("[\\-._0-9a-zA-Z]+"); - - /** - * The rule qualification for multiply name - */ - private static final Pattern PATTERN_MULTI_NAME = Pattern.compile("[,\\-._0-9a-zA-Z]+"); - - /** - * The rule qualification for method names - */ - private static final Pattern PATTERN_METHOD_NAME = Pattern.compile("[a-zA-Z][0-9a-zA-Z]*"); - - /** - * The rule qualification for path - */ - private static final Pattern PATTERN_PATH = Pattern.compile("[/\\-$._0-9a-zA-Z]+"); - - /** - * The pattern matches a value who has a symbol - */ - private static final Pattern PATTERN_NAME_HAS_SYMBOL = Pattern.compile("[:*,\\s/\\-._0-9a-zA-Z]+"); - - /** - * The pattern matches a property key - */ - private static final Pattern PATTERN_KEY = Pattern.compile("[*,\\-._0-9a-zA-Z]+"); - - public static final String IPV6_START_MARK = "["; - - public static final String IPV6_END_MARK = "]"; - - public static List loadRegistries(AbstractInterfaceConfig interfaceConfig, boolean provider) { - // check && override if necessary - List registryList = new ArrayList<>(); - ApplicationConfig application = interfaceConfig.getApplication(); - List registries = interfaceConfig.getRegistries(); - if (CollectionUtils.isNotEmpty(registries)) { - for (RegistryConfig config : registries) { - // try to refresh registry in case it is set directly by user using config.setRegistries() - if (!config.isRefreshed()) { - config.refresh(); - } - String address = config.getAddress(); - if (StringUtils.isEmpty(address)) { - address = ANYHOST_VALUE; - } - if (!RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) { - Map map = new HashMap(); - AbstractConfig.appendParameters(map, application); - AbstractConfig.appendParameters(map, config); - map.put(PATH_KEY, RegistryService.class.getName()); - AbstractInterfaceConfig.appendRuntimeParameters(map); - if (!map.containsKey(PROTOCOL_KEY)) { - map.put(PROTOCOL_KEY, DUBBO_PROTOCOL); - } - List urls = UrlUtils.parseURLs(address, map); - - for (URL url : urls) { - url = URLBuilder.from(url) - .addParameter(REGISTRY_KEY, url.getProtocol()) - .setProtocol(extractRegistryType(url)) - .setScopeModel(interfaceConfig.getScopeModel()) - .build(); - // provider delay register state will be checked in RegistryProtocol#export - if (provider && url.getParameter(REGISTER_KEY, true)) { - registryList.add(url); - } - if (!provider && url.getParameter(SUBSCRIBE_KEY, true)) { - registryList.add(url); - } - } - } - } - } - return genCompatibleRegistries(interfaceConfig.getScopeModel(), registryList, provider); - } - - private static List genCompatibleRegistries(ScopeModel scopeModel, List registryList, boolean provider) { - List result = new ArrayList<>(registryList.size()); - registryList.forEach(registryURL -> { - if (provider) { - // for registries enabled service discovery, automatically register interface compatible addresses. - String registerMode; - if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) { - registerMode = registryURL.getParameter(REGISTER_MODE_KEY, ConfigurationUtils.getCachedDynamicProperty(scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_INSTANCE)); - if (!isValidRegisterMode(registerMode)) { - registerMode = DEFAULT_REGISTER_MODE_INSTANCE; - } - result.add(registryURL); - if (DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode) - && registryNotExists(registryURL, registryList, REGISTRY_PROTOCOL)) { - URL interfaceCompatibleRegistryURL = URLBuilder.from(registryURL) - .setProtocol(REGISTRY_PROTOCOL) - .removeParameter(REGISTRY_TYPE_KEY) - .build(); - result.add(interfaceCompatibleRegistryURL); - } - } else { - registerMode = registryURL.getParameter(REGISTER_MODE_KEY, ConfigurationUtils.getCachedDynamicProperty(scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_ALL)); - if (!isValidRegisterMode(registerMode)) { - registerMode = DEFAULT_REGISTER_MODE_INTERFACE; - } - if ((DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)) - && registryNotExists(registryURL, registryList, SERVICE_REGISTRY_PROTOCOL)) { - URL serviceDiscoveryRegistryURL = URLBuilder.from(registryURL) - .setProtocol(SERVICE_REGISTRY_PROTOCOL) - .removeParameter(REGISTRY_TYPE_KEY) - .build(); - result.add(serviceDiscoveryRegistryURL); - } - - if (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)) { - result.add(registryURL); - } - } - - FrameworkStatusReportService reportService = ScopeModelUtil.getApplicationModel(scopeModel).getBeanFactory().getBean(FrameworkStatusReportService.class); - reportService.reportRegistrationStatus(reportService.createRegistrationReport(registerMode)); - } else { - result.add(registryURL); - } - }); - - return result; - } - - private static boolean isValidRegisterMode(String mode) { - return isNotEmpty(mode) - && (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(mode) - || DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(mode) - || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(mode) - ); - } - - private static boolean registryNotExists(URL registryURL, List registryList, String registryType) { - return registryList.stream().noneMatch( - url -> registryType.equals(url.getProtocol()) && registryURL.getBackupAddress().equals(url.getBackupAddress()) - ); - } - - public static URL loadMonitor(AbstractInterfaceConfig interfaceConfig, URL registryURL) { - Map map = new HashMap(); - map.put(INTERFACE_KEY, MonitorService.class.getName()); - AbstractInterfaceConfig.appendRuntimeParameters(map); - //set ip - String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY); - if (StringUtils.isEmpty(hostToRegistry)) { - hostToRegistry = NetUtils.getLocalHost(); - } else if (NetUtils.isInvalidLocalHost(hostToRegistry)) { - throw new IllegalArgumentException("Specified invalid registry ip from property:" + - DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); - } - map.put(REGISTER_IP_KEY, hostToRegistry); - - MonitorConfig monitor = interfaceConfig.getMonitor(); - ApplicationConfig application = interfaceConfig.getApplication(); - AbstractConfig.appendParameters(map, monitor); - AbstractConfig.appendParameters(map, application); - String address = null; - String sysAddress = System.getProperty(DUBBO_MONITOR_ADDRESS); - if (sysAddress != null && sysAddress.length() > 0) { - address = sysAddress; - } else if (monitor != null) { - address = monitor.getAddress(); - } - String protocol = monitor == null ? null : monitor.getProtocol(); - if (monitor != null && - (REGISTRY_PROTOCOL.equals(protocol) || SERVICE_REGISTRY_PROTOCOL.equals(protocol)) - && registryURL != null) { - return URLBuilder.from(registryURL) - .setProtocol(DUBBO_PROTOCOL) - .addParameter(PROTOCOL_KEY, protocol) - .putAttribute(REFER_KEY, map) - .build(); - } else if (ConfigUtils.isNotEmpty(address) || ConfigUtils.isNotEmpty(protocol)) { - if (!map.containsKey(PROTOCOL_KEY)) { - if (interfaceConfig.getScopeModel().getExtensionLoader(MonitorFactory.class).hasExtension(LOGSTAT_PROTOCOL)) { - map.put(PROTOCOL_KEY, LOGSTAT_PROTOCOL); - } else if (ConfigUtils.isNotEmpty(protocol)) { - map.put(PROTOCOL_KEY, protocol); - } else { - map.put(PROTOCOL_KEY, DUBBO_PROTOCOL); - } - } - if (ConfigUtils.isEmpty(address)) { - address = LOCALHOST_VALUE; - } - return UrlUtils.parseURL(address, map); - } - return null; - } - - - public static void validateAbstractInterfaceConfig(AbstractInterfaceConfig config) { - checkName(LOCAL_KEY, config.getLocal()); - checkName("stub", config.getStub()); - checkMultiName("owner", config.getOwner()); - - checkExtension(config.getScopeModel(), ProxyFactory.class, PROXY_KEY, config.getProxy()); - checkExtension(config.getScopeModel(), Cluster.class, CLUSTER_KEY, config.getCluster()); - checkMultiExtension(config.getScopeModel(), Arrays.asList(Filter.class, ClusterFilter.class), FILTER_KEY, config.getFilter()); - checkNameHasSymbol(LAYER_KEY, config.getLayer()); - - List methods = config.getMethods(); - if (CollectionUtils.isNotEmpty(methods)) { - methods.forEach(ConfigValidationUtils::validateMethodConfig); - } - } - - public static void validateServiceConfig(ServiceConfig config) { - checkKey(VERSION_KEY, config.getVersion()); - checkKey(GROUP_KEY, config.getGroup()); - checkName(TOKEN_KEY, config.getToken()); - checkPathName(PATH_KEY, config.getPath()); - - checkMultiExtension(config.getScopeModel(), ExporterListener.class, "listener", config.getListener()); - - validateAbstractInterfaceConfig(config); - - List registries = config.getRegistries(); - if (registries != null) { - for (RegistryConfig registry : registries) { - validateRegistryConfig(registry); - } - } - - List protocols = config.getProtocols(); - if (protocols != null) { - for (ProtocolConfig protocol : protocols) { - validateProtocolConfig(protocol); - } - } - - ProviderConfig providerConfig = config.getProvider(); - if (providerConfig != null) { - validateProviderConfig(providerConfig); - } - } - - public static void validateReferenceConfig(ReferenceConfig config) { - checkMultiExtension(config.getScopeModel(), InvokerListener.class, "listener", config.getListener()); - checkKey(VERSION_KEY, config.getVersion()); - checkKey(GROUP_KEY, config.getGroup()); - checkName(CLIENT_KEY, config.getClient()); - - validateAbstractInterfaceConfig(config); - - List registries = config.getRegistries(); - if (registries != null) { - for (RegistryConfig registry : registries) { - validateRegistryConfig(registry); - } - } - - ConsumerConfig consumerConfig = config.getConsumer(); - if (consumerConfig != null) { - validateConsumerConfig(consumerConfig); - } - } - - public static void validateConfigCenterConfig(ConfigCenterConfig config) { - if (config != null) { - checkParameterName(config.getParameters()); - } - } - - public static void validateApplicationConfig(ApplicationConfig config) { - if (config == null) { - return; - } - - if (!config.isValid()) { - throw new IllegalStateException("No application config found or it's not a valid config! " + - "Please add to your spring config."); - } - - // backward compatibility - ScopeModel scopeModel = ScopeModelUtil.getOrDefaultApplicationModel(config.getScopeModel()); - PropertiesConfiguration configuration = scopeModel.modelEnvironment().getPropertiesConfiguration(); - String wait = configuration.getProperty(SHUTDOWN_WAIT_KEY); - if (wait != null && wait.trim().length() > 0) { - System.setProperty(SHUTDOWN_WAIT_KEY, wait.trim()); - } else { - wait = configuration.getProperty(SHUTDOWN_WAIT_SECONDS_KEY); - if (wait != null && wait.trim().length() > 0) { - System.setProperty(SHUTDOWN_WAIT_SECONDS_KEY, wait.trim()); - } - } - - checkName(NAME, config.getName()); - checkMultiName(OWNER, config.getOwner()); - checkName(ORGANIZATION, config.getOrganization()); - checkName(ARCHITECTURE, config.getArchitecture()); - checkName(ENVIRONMENT, config.getEnvironment()); - checkParameterName(config.getParameters()); - checkQosDependency(config); - } - - private static void checkQosDependency(ApplicationConfig config) { - if (!Boolean.FALSE.equals(config.getQosEnable())) { - try { - ClassUtils.forName("org.apache.dubbo.qos.protocol.QosProtocolWrapper"); - } catch (ClassNotFoundException e) { - logger.warn(COMMON_CLASS_NOT_FOUND, "", "", "No QosProtocolWrapper class was found. Please check the dependency of dubbo-qos whether was imported correctly.", e); - } - } - } - - public static void validateModuleConfig(ModuleConfig config) { - if (config != null) { - checkName(NAME, config.getName()); - checkName(OWNER, config.getOwner()); - checkName(ORGANIZATION, config.getOrganization()); - } - } - - public static boolean isValidMetadataConfig(MetadataReportConfig metadataReportConfig) { - if (metadataReportConfig == null) { - return false; - } - - if (Boolean.FALSE.equals(metadataReportConfig.getReportMetadata()) && - Boolean.FALSE.equals(metadataReportConfig.getReportDefinition())) { - return false; - } - - return !isEmpty(metadataReportConfig.getAddress()); - } - - public static void validateMetadataConfig(MetadataReportConfig metadataReportConfig) { - if (!isValidMetadataConfig(metadataReportConfig)) { - return; - } - - String address = metadataReportConfig.getAddress(); - String protocol = metadataReportConfig.getProtocol(); - - if ((isEmpty(address) || !address.contains("://")) && isEmpty(protocol)) { - throw new IllegalArgumentException("Please specify valid protocol or address for metadata report " + address); - } - } - - public static void validateMetricsConfig(MetricsConfig metricsConfig) { - if (metricsConfig == null) { - return; - } - } - - public static void validateTracingConfig(TracingConfig tracingConfig) { - if (tracingConfig == null) { - return; - } - } - - public static void validateSslConfig(SslConfig sslConfig) { - if (sslConfig == null) { - return; - } - } - - public static void validateMonitorConfig(MonitorConfig config) { - if (config != null) { - if (!config.isValid()) { - logger.info("There's no valid monitor config found, if you want to open monitor statistics for Dubbo, " + - "please make sure your monitor is configured properly."); - } - - checkParameterName(config.getParameters()); - } - } - - public static void validateProtocolConfig(ProtocolConfig config) { - if (config != null) { - String name = config.getName(); - checkName("name", name); - checkHost(HOST_KEY, config.getHost()); - checkPathName("contextpath", config.getContextpath()); - - - if (DUBBO_PROTOCOL.equals(name)) { - checkMultiExtension(config.getScopeModel(), Codec2.class, CODEC_KEY, config.getCodec()); - checkMultiExtension(config.getScopeModel(), Serialization.class, SERIALIZATION_KEY, config.getSerialization()); - checkMultiExtension(config.getScopeModel(), Transporter.class, SERVER_KEY, config.getServer()); - checkMultiExtension(config.getScopeModel(), Transporter.class, CLIENT_KEY, config.getClient()); - } - - checkMultiExtension(config.getScopeModel(), TelnetHandler.class, TELNET_KEY, config.getTelnet()); - checkMultiExtension(config.getScopeModel(), StatusChecker.class, "status", config.getStatus()); - checkExtension(config.getScopeModel(), Transporter.class, TRANSPORTER_KEY, config.getTransporter()); - checkExtension(config.getScopeModel(), Exchanger.class, EXCHANGER_KEY, config.getExchanger()); - checkExtension(config.getScopeModel(), Dispatcher.class, DISPATCHER_KEY, config.getDispatcher()); - checkExtension(config.getScopeModel(), Dispatcher.class, "dispather", config.getDispather()); - checkExtension(config.getScopeModel(), ThreadPool.class, THREADPOOL_KEY, config.getThreadpool()); - } - } - - public static void validateProviderConfig(ProviderConfig config) { - checkPathName(CONTEXTPATH_KEY, config.getContextpath()); - checkExtension(config.getScopeModel(), ThreadPool.class, THREADPOOL_KEY, config.getThreadpool()); - checkMultiExtension(config.getScopeModel(), TelnetHandler.class, TELNET_KEY, config.getTelnet()); - checkMultiExtension(config.getScopeModel(), StatusChecker.class, STATUS_KEY, config.getStatus()); - checkExtension(config.getScopeModel(), Transporter.class, TRANSPORTER_KEY, config.getTransporter()); - checkExtension(config.getScopeModel(), Exchanger.class, EXCHANGER_KEY, config.getExchanger()); - } - - public static void validateConsumerConfig(ConsumerConfig config) { - if (config == null) { - return; - } - } - - public static void validateRegistryConfig(RegistryConfig config) { - checkName(PROTOCOL_KEY, config.getProtocol()); - checkName(USERNAME_KEY, config.getUsername()); - checkLength(PASSWORD_KEY, config.getPassword()); - checkPathLength(FILE_KEY, config.getFile()); - checkName(TRANSPORTER_KEY, config.getTransporter()); - checkName(SERVER_KEY, config.getServer()); - checkName(CLIENT_KEY, config.getClient()); - checkParameterName(config.getParameters()); - } - - public static void validateMethodConfig(MethodConfig config) { - checkExtension(config.getScopeModel(), LoadBalance.class, LOADBALANCE_KEY, config.getLoadbalance()); - checkParameterName(config.getParameters()); - checkMethodName("name", config.getName()); - - String mock = config.getMock(); - if (isNotEmpty(mock)) { - if (mock.startsWith(RETURN_PREFIX) || mock.startsWith(THROW_PREFIX + " ")) { - checkLength(MOCK_KEY, mock); - } else if (mock.startsWith(FAIL_PREFIX) || mock.startsWith(FORCE_PREFIX)) { - checkNameHasSymbol(MOCK_KEY, mock); - } else { - checkName(MOCK_KEY, mock); - } - } - } - - private static String extractRegistryType(URL url) { - return UrlUtils.hasServiceDiscoveryRegistryTypeKey(url) ? SERVICE_REGISTRY_PROTOCOL : getRegistryProtocolType(url); - } - - private static String getRegistryProtocolType(URL url) { - String registryProtocol = url.getParameter("registry-protocol-type"); - return isNotEmpty(registryProtocol) ? registryProtocol : REGISTRY_PROTOCOL; - } - - public static void checkExtension(ScopeModel scopeModel, Class type, String property, String value) { - checkName(property, value); - if (isNotEmpty(value) - && !scopeModel.getExtensionLoader(type).hasExtension(value)) { - throw new IllegalStateException("No such extension " + value + " for " + property + "/" + type.getName()); - } - } - - /** - * Check whether there is a Extension who's name (property) is value (special treatment is - * required) - * - * @param type The Extension type - * @param property The extension key - * @param value The Extension name - */ - public static void checkMultiExtension(ScopeModel scopeModel, Class type, String property, String value) { - checkMultiExtension(scopeModel, Collections.singletonList(type), property, value); - } - - public static void checkMultiExtension(ScopeModel scopeModel, List> types, String property, String value) { - checkMultiName(property, value); - if (isNotEmpty(value)) { - String[] values = value.split("\\s*[,]+\\s*"); - for (String v : values) { - v = StringUtils.trim(v); - if (v.startsWith(REMOVE_VALUE_PREFIX)) { - continue; - } - if (DEFAULT_KEY.equals(v)) { - continue; - } - boolean match = false; - for (Class type : types) { - if (scopeModel.getExtensionLoader(type).hasExtension(v)) { - match = true; - } - } - if (!match) { - throw new IllegalStateException("No such extension " + v + " for " + property + "/" + - types.stream().map(Class::getName).collect(Collectors.joining(","))); - } - } - } - } - - public static void checkLength(String property, String value) { - checkProperty(property, value, MAX_LENGTH, null); - } - - public static void checkPathLength(String property, String value) { - checkProperty(property, value, MAX_PATH_LENGTH, null); - } - - public static void checkName(String property, String value) { - checkProperty(property, value, MAX_LENGTH, PATTERN_NAME); - } - - public static void checkHost(String property, String value) { - if (StringUtils.isEmpty(value)) { - return; - } - if (value.startsWith(IPV6_START_MARK) && value.endsWith(IPV6_END_MARK)) { - // if the value start with "[" and end with "]", check whether it is IPV6 - try { - InetAddress.getByName(value); - return; - } catch (UnknownHostException e) { - // not a IPv6 string, do nothing, go on to checkName - } - } - checkName(property, value); - } - - public static void checkNameHasSymbol(String property, String value) { - checkProperty(property, value, MAX_LENGTH, PATTERN_NAME_HAS_SYMBOL); - } - - public static void checkKey(String property, String value) { - checkProperty(property, value, MAX_LENGTH, PATTERN_KEY); - } - - public static void checkMultiName(String property, String value) { - checkProperty(property, value, MAX_LENGTH, PATTERN_MULTI_NAME); - } - - public static void checkPathName(String property, String value) { - checkProperty(property, value, MAX_PATH_LENGTH, PATTERN_PATH); - } - - public static void checkMethodName(String property, String value) { - checkProperty(property, value, MAX_LENGTH, PATTERN_METHOD_NAME); - } - - public static void checkParameterName(Map parameters) { - if (CollectionUtils.isEmptyMap(parameters)) { - return; - } - List ignoreCheckKeys = new ArrayList<>(); - ignoreCheckKeys.add(BACKUP_KEY); - String ignoreCheckKeysStr = parameters.get(IGNORE_CHECK_KEYS); - if (!StringUtils.isBlank(ignoreCheckKeysStr)) { - ignoreCheckKeys.addAll(Arrays.asList(ignoreCheckKeysStr.split(","))); - } - for (Map.Entry entry : parameters.entrySet()) { - if (!ignoreCheckKeys.contains(entry.getKey())) { - checkNameHasSymbol(entry.getKey(), entry.getValue()); - } - } - } - - public static void checkProperty(String property, String value, int maxlength, Pattern pattern) { - if (StringUtils.isEmpty(value)) { - return; - } - if (value.length() > maxlength) { - logger.error(CONFIG_PARAMETER_FORMAT_ERROR, "the value content is too long", "", "Parameter value format error. Invalid " + - property + "=\"" + value + "\" is longer than " + maxlength); - } - if (pattern != null) { - Matcher matcher = pattern.matcher(value); - if (!matcher.matches()) { - logger.error(CONFIG_PARAMETER_FORMAT_ERROR, "the value content is illegal character", "", "Parameter value format error. Invalid " + - property + "=\"" + value + "\" contains illegal " + - "character, only digit, letter, '-', '_' or '.' is legal."); - } - } - } - -} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/DefaultConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/DefaultConfigValidator.java deleted file mode 100644 index 396f6afc49..0000000000 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/DefaultConfigValidator.java +++ /dev/null @@ -1,62 +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.config.utils; - -import org.apache.dubbo.config.AbstractConfig; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ConsumerConfig; -import org.apache.dubbo.config.MetadataReportConfig; -import org.apache.dubbo.config.MetricsConfig; -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.SslConfig; -import org.apache.dubbo.config.TracingConfig; -import org.apache.dubbo.config.context.ConfigValidator; - -public class DefaultConfigValidator implements ConfigValidator { - - @Override - public void validate(AbstractConfig config) { - if (config instanceof ProtocolConfig) { - ConfigValidationUtils.validateProtocolConfig((ProtocolConfig) config); - } else if (config instanceof RegistryConfig) { - ConfigValidationUtils.validateRegistryConfig((RegistryConfig) config); - } else if (config instanceof MetadataReportConfig) { - ConfigValidationUtils.validateMetadataConfig((MetadataReportConfig) config); - } else if (config instanceof ProviderConfig) { - ConfigValidationUtils.validateProviderConfig((ProviderConfig) config); - } else if (config instanceof ConsumerConfig) { - ConfigValidationUtils.validateConsumerConfig((ConsumerConfig) config); - } else if (config instanceof ApplicationConfig) { - ConfigValidationUtils.validateApplicationConfig((ApplicationConfig) config); - } else if (config instanceof MonitorConfig) { - ConfigValidationUtils.validateMonitorConfig((MonitorConfig) config); - } else if (config instanceof ModuleConfig) { - ConfigValidationUtils.validateModuleConfig((ModuleConfig) config); - } else if (config instanceof MetricsConfig) { - ConfigValidationUtils.validateMetricsConfig((MetricsConfig) config); - } else if (config instanceof TracingConfig) { - ConfigValidationUtils.validateTracingConfig((TracingConfig) config); - } else if (config instanceof SslConfig) { - ConfigValidationUtils.validateSslConfig((SslConfig) config); - } - } - -} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConfigCenterConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConfigCenterConfigValidator.java new file mode 100644 index 0000000000..a67580c05c --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConfigCenterConfigValidator.java @@ -0,0 +1,44 @@ +/* + * 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.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.ConfigCenterConfig; +import org.apache.dubbo.config.context.ConfigValidator; +import org.apache.dubbo.config.utils.ConfigValidationUtils; + +//TODO: Move to configcenter-api +@Activate +public class ConfigCenterConfigValidator implements ConfigValidator { + + public static void validateConfigCenterConfig(ConfigCenterConfig config) { + if (config != null) { + ConfigValidationUtils.checkParameterName(config.getParameters()); + } + } + + @Override + public boolean validate(ConfigCenterConfig config) { + validateConfigCenterConfig(config); + return true; + } + + @Override + public boolean isSupport(Class configClass) { + return ConfigCenterConfig.class.equals(configClass); + } +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConsumerConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConsumerConfigValidator.java new file mode 100644 index 0000000000..7c145ebfd2 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConsumerConfigValidator.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.context.ConfigValidator; + +@Activate +public class ConsumerConfigValidator implements ConfigValidator { + + public static void validateConsumerConfig(ConsumerConfig config) { + //TODO + if (config == null) { + } + } + + @Override + public boolean validate(ConsumerConfig config) { + validateConsumerConfig(config); + return true; + } + + @Override + public boolean isSupport(Class configClass) { + return ConsumerConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/InterfaceConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/InterfaceConfigValidator.java new file mode 100644 index 0000000000..4a55275338 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/InterfaceConfigValidator.java @@ -0,0 +1,68 @@ +/* + * 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.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.config.AbstractInterfaceConfig; +import org.apache.dubbo.config.MethodConfig; +import org.apache.dubbo.config.context.ConfigValidator; +import org.apache.dubbo.config.utils.ConfigValidationUtils; +import org.apache.dubbo.rpc.Filter; +import org.apache.dubbo.rpc.ProxyFactory; +import org.apache.dubbo.rpc.cluster.Cluster; +import org.apache.dubbo.rpc.cluster.filter.ClusterFilter; + +import java.util.Arrays; +import java.util.List; + +import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.FILTER_KEY; +import static org.apache.dubbo.config.Constants.LAYER_KEY; +import static org.apache.dubbo.rpc.Constants.LOCAL_KEY; +import static org.apache.dubbo.rpc.Constants.PROXY_KEY; + +@Activate +public class InterfaceConfigValidator implements ConfigValidator { + + public static void validateAbstractInterfaceConfig(AbstractInterfaceConfig config) { + ConfigValidationUtils.checkName(LOCAL_KEY, config.getLocal()); + ConfigValidationUtils.checkName("stub", config.getStub()); + ConfigValidationUtils.checkMultiName("owner", config.getOwner()); + + ConfigValidationUtils.checkExtension(config.getScopeModel(), ProxyFactory.class, PROXY_KEY, config.getProxy()); + ConfigValidationUtils.checkExtension(config.getScopeModel(), Cluster.class, CLUSTER_KEY, config.getCluster()); + ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), Arrays.asList(Filter.class, ClusterFilter.class), FILTER_KEY, config.getFilter()); + ConfigValidationUtils.checkNameHasSymbol(LAYER_KEY, config.getLayer()); + + List methods = config.getMethods(); + if (CollectionUtils.isNotEmpty(methods)) { + methods.forEach(MethodConfig::validate); + } + } + + @Override + public boolean validate(AbstractInterfaceConfig config) { + validateAbstractInterfaceConfig(config); + return true; + } + + @Override + public boolean isSupport(Class configClass) { + return AbstractInterfaceConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/MethodConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/MethodConfigValidator.java new file mode 100644 index 0000000000..811cd952ae --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/MethodConfigValidator.java @@ -0,0 +1,63 @@ +/* + * 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.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.MethodConfig; +import org.apache.dubbo.config.context.ConfigValidator; +import org.apache.dubbo.config.utils.ConfigValidationUtils; +import org.apache.dubbo.rpc.cluster.LoadBalance; + +import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY; +import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; +import static org.apache.dubbo.rpc.Constants.FAIL_PREFIX; +import static org.apache.dubbo.rpc.Constants.FORCE_PREFIX; +import static org.apache.dubbo.rpc.Constants.MOCK_KEY; +import static org.apache.dubbo.rpc.Constants.RETURN_PREFIX; +import static org.apache.dubbo.rpc.Constants.THROW_PREFIX; + +@Activate +public class MethodConfigValidator implements ConfigValidator { + + public static void validateMethodConfig(MethodConfig config) { + ConfigValidationUtils.checkExtension(config.getScopeModel(), LoadBalance.class, LOADBALANCE_KEY, config.getLoadbalance()); + ConfigValidationUtils.checkParameterName(config.getParameters()); + ConfigValidationUtils.checkMethodName("name", config.getName()); + + String mock = config.getMock(); + if (isNotEmpty(mock)) { + if (mock.startsWith(RETURN_PREFIX) || mock.startsWith(THROW_PREFIX + " ")) { + ConfigValidationUtils.checkLength(MOCK_KEY, mock); + } else if (mock.startsWith(FAIL_PREFIX) || mock.startsWith(FORCE_PREFIX)) { + ConfigValidationUtils.checkNameHasSymbol(MOCK_KEY, mock); + } else { + ConfigValidationUtils.checkName(MOCK_KEY, mock); + } + } + } + + @Override + public boolean validate(MethodConfig config) { + validateMethodConfig(config); + return true; + } + + @Override + public boolean isSupport(Class configClass) { + return MethodConfig.class.equals(configClass); + } +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ProviderConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ProviderConfigValidator.java new file mode 100644 index 0000000000..1d7b4df139 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ProviderConfigValidator.java @@ -0,0 +1,58 @@ +/* + * 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.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.status.StatusChecker; +import org.apache.dubbo.common.threadpool.ThreadPool; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.context.ConfigValidator; +import org.apache.dubbo.config.utils.ConfigValidationUtils; +import org.apache.dubbo.remoting.Transporter; +import org.apache.dubbo.remoting.exchange.Exchanger; +import org.apache.dubbo.remoting.telnet.TelnetHandler; + +import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY; +import static org.apache.dubbo.config.Constants.CONTEXTPATH_KEY; +import static org.apache.dubbo.config.Constants.STATUS_KEY; +import static org.apache.dubbo.remoting.Constants.EXCHANGER_KEY; +import static org.apache.dubbo.remoting.Constants.TELNET_KEY; +import static org.apache.dubbo.remoting.Constants.TRANSPORTER_KEY; + +@Activate +public class ProviderConfigValidator implements ConfigValidator { + + @Override + public boolean validate(ProviderConfig config) { + validateProviderConfig(config); + return true; + } + + public static void validateProviderConfig(ProviderConfig config) { + ConfigValidationUtils.checkPathName(CONTEXTPATH_KEY, config.getContextpath()); + ConfigValidationUtils.checkExtension(config.getScopeModel(), ThreadPool.class, THREADPOOL_KEY, config.getThreadpool()); + ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), TelnetHandler.class, TELNET_KEY, config.getTelnet()); + ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), StatusChecker.class, STATUS_KEY, config.getStatus()); + ConfigValidationUtils.checkExtension(config.getScopeModel(), Transporter.class, TRANSPORTER_KEY, config.getTransporter()); + ConfigValidationUtils.checkExtension(config.getScopeModel(), Exchanger.class, EXCHANGER_KEY, config.getExchanger()); + } + + @Override + public boolean isSupport(Class configClass) { + return ProviderConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ReferenceConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ReferenceConfigValidator.java new file mode 100644 index 0000000000..b804d62db2 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ReferenceConfigValidator.java @@ -0,0 +1,65 @@ +/* + * 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.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.ReferenceConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.context.ConfigValidator; +import org.apache.dubbo.config.utils.ConfigValidationUtils; +import org.apache.dubbo.rpc.InvokerListener; + +import java.util.List; + +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.remoting.Constants.CLIENT_KEY; + +@Activate +public class ReferenceConfigValidator implements ConfigValidator> { + + @Override + public boolean validate(ReferenceConfig config) { + validateReferenceConfig(config); + return true; + } + + public static void validateReferenceConfig(ReferenceConfig config) { + ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), InvokerListener.class, "listener", config.getListener()); + ConfigValidationUtils.checkKey(VERSION_KEY, config.getVersion()); + ConfigValidationUtils.checkKey(GROUP_KEY, config.getGroup()); + ConfigValidationUtils.checkName(CLIENT_KEY, config.getClient()); + + List registries = config.getRegistries(); + if (registries != null) { + for (RegistryConfig registry : registries) { + registry.validate(); + } + } + + ConsumerConfig consumerConfig = config.getConsumer(); + if (consumerConfig != null) { + consumerConfig.validate(); + } + } + + @Override + public boolean isSupport(Class configClass) { + return ReferenceConfig.class.equals(configClass); + } +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ServiceConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ServiceConfigValidator.java new file mode 100644 index 0000000000..bea8a54ab0 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ServiceConfigValidator.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.validator; + +import org.apache.dubbo.common.extension.Activate; +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.context.ConfigValidator; +import org.apache.dubbo.config.utils.ConfigValidationUtils; +import org.apache.dubbo.rpc.ExporterListener; + +import java.util.List; + +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; +import static org.apache.dubbo.rpc.Constants.TOKEN_KEY; + +@Activate +public class ServiceConfigValidator implements ConfigValidator> { + + public static void validateServiceConfig(ServiceConfig config) { + + ConfigValidationUtils.checkKey(VERSION_KEY, config.getVersion()); + ConfigValidationUtils.checkKey(GROUP_KEY, config.getGroup()); + ConfigValidationUtils.checkName(TOKEN_KEY, config.getToken()); + ConfigValidationUtils.checkPathName(PATH_KEY, config.getPath()); + + ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), ExporterListener.class, "listener", config.getListener()); + + List registries = config.getRegistries(); + if (registries != null) { + for (RegistryConfig registry : registries) { + registry.validate(); + } + } + + List protocols = config.getProtocols(); + if (protocols != null) { + for (ProtocolConfig protocol : protocols) { + protocol.validate(); + } + } + + ProviderConfig providerConfig = config.getProvider(); + if (providerConfig != null) { + providerConfig.validate(); + } + } + + @Override + public boolean validate(ServiceConfig config) { + validateServiceConfig(config); + return true; + } + + + @Override + public boolean isSupport(Class configClass) { + return ServiceConfig.class.equals(configClass); + } +} diff --git a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator new file mode 100644 index 0000000000..6ab0e95080 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator @@ -0,0 +1,8 @@ +config-center=org.apache.dubbo.config.validator.ConfigCenterConfigValidator +consumer=org.apache.dubbo.config.validator.ConsumerConfigValidator +interface=org.apache.dubbo.config.validator.InterfaceConfigValidator +method=org.apache.dubbo.config.validator.MethodConfigValidator +provider=org.apache.dubbo.config.validator.ProviderConfigValidator +reference=org.apache.dubbo.config.validator.ReferenceConfigValidator +service=org.apache.dubbo.config.validator.ServiceConfigValidator + diff --git a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.deploy.lifecycle.application.ApplicationLifecycle b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.deploy.lifecycle.application.ApplicationLifecycle index ca779fe73f..8e806008f2 100644 --- a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.deploy.lifecycle.application.ApplicationLifecycle +++ b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.deploy.lifecycle.application.ApplicationLifecycle @@ -3,3 +3,4 @@ config-post-handle=org.apache.dubbo.config.deploy.lifecycle.application.Applicat module-initialize=org.apache.dubbo.config.deploy.lifecycle.application.ModuleInitializeLifecycle post-offline=org.apache.dubbo.config.deploy.lifecycle.application.ApplicationPostOfflineLifecycle app-prepare=org.apache.dubbo.config.deploy.lifecycle.application.ApplicationPrepareLifecycle +validator-registry=org.apache.dubbo.config.deploy.lifecycle.application.ValidatorRegistryDeployListener diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java index 1a986a5884..55bcbae629 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java @@ -131,7 +131,7 @@ class AbstractConfigTest { protocolConfig.setCodec("exchange"); protocolConfig.setName("test"); protocolConfig.setHost("host"); - ConfigValidationUtils.validateProtocolConfig(protocolConfig); + protocolConfig.validate(); } @Test diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigValidatorExistTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigValidatorExistTest.java new file mode 100644 index 0000000000..980ce01583 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigValidatorExistTest.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config; + + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.validator.ConsumerConfigValidator; +import org.apache.dubbo.config.validator.InterfaceConfigValidator; +import org.apache.dubbo.config.validator.MethodConfigValidator; +import org.apache.dubbo.config.validator.ProviderConfigValidator; +import org.apache.dubbo.config.validator.ReferenceConfigValidator; +import org.apache.dubbo.config.validator.ServiceConfigValidator; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; + + +public class ConfigValidatorExistTest { + + ConfigValidateFacade validateFacade; + + @Test + void testConfigValidatorExist(){ + FrameworkModel frameworkModel = FrameworkModel.defaultModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + + validateFacade = new ConfigValidateFacade(applicationModel); + Assertions.assertNotNull(validateFacade); + Assertions.assertTrue(validateFacade.getValidators().size() >= 7); + + try( + MockedStatic configValidatorMockedStatic = Mockito.mockStatic(ConsumerConfigValidator.class); + MockedStatic interfaceConfigValidatorMockedStatic = Mockito.mockStatic(InterfaceConfigValidator.class); + MockedStatic methodConfigValidatorMockedStatic = Mockito.mockStatic(MethodConfigValidator.class); + MockedStatic providerConfigValidatorMockedStatic = Mockito.mockStatic(ProviderConfigValidator.class); + MockedStatic referenceConfigValidatorMockedStatic = Mockito.mockStatic(ReferenceConfigValidator.class); + MockedStatic serviceConfigValidatorMockedStatic = Mockito.mockStatic(ServiceConfigValidator.class); + ){ + configValidatorMockedStatic.when(()-> ConsumerConfigValidator.validateConsumerConfig(any())).thenCallRealMethod(); + interfaceConfigValidatorMockedStatic.when(()-> InterfaceConfigValidator.validateAbstractInterfaceConfig(any())).thenCallRealMethod(); + methodConfigValidatorMockedStatic.when(()-> MethodConfigValidator.validateMethodConfig(any())).thenCallRealMethod(); + providerConfigValidatorMockedStatic.when(()-> ProviderConfigValidator.validateProviderConfig(any())).thenCallRealMethod(); + referenceConfigValidatorMockedStatic.when(()-> ReferenceConfigValidator.validateReferenceConfig(any())).thenCallRealMethod(); + serviceConfigValidatorMockedStatic.when(()->ServiceConfigValidator.validateServiceConfig(any())).thenCallRealMethod(); + triggerValidate(new ConsumerConfig()); + triggerValidate(new AbstractInterfaceConfig() { + @Override + public List getExportedUrls() { + return super.getExportedUrls(); + } + }); + triggerValidate(new MethodConfig()); + triggerValidate(new ProviderConfig()); + triggerValidate(new ReferenceConfig<>()); + triggerValidate(new ServiceConfig<>()); + + configValidatorMockedStatic.verify(()-> ConsumerConfigValidator.validateConsumerConfig(any()),atLeastOnce()); + interfaceConfigValidatorMockedStatic.verify(()-> InterfaceConfigValidator.validateAbstractInterfaceConfig(any()),atLeastOnce()); + methodConfigValidatorMockedStatic.verify(()->MethodConfigValidator.validateMethodConfig(any()),atLeastOnce()); + providerConfigValidatorMockedStatic.verify(()->ProviderConfigValidator.validateProviderConfig(any()),atLeastOnce()); + referenceConfigValidatorMockedStatic.verify(()->ReferenceConfigValidator.validateReferenceConfig(any()),atLeastOnce()); + serviceConfigValidatorMockedStatic.verify(()-> ServiceConfigValidator.validateServiceConfig(any()),atLeastOnce()); + } + } + + void triggerValidate(AbstractConfig config){ + try { + validateFacade.validate(config); + }catch (Throwable ignored){}; + } + +} diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java index 92e6e2b595..83793deab2 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java @@ -35,6 +35,7 @@ import org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter; import org.apache.dubbo.config.metadata.ExporterDeployListener; import org.apache.dubbo.config.provider.impl.DemoServiceImpl; import org.apache.dubbo.config.utils.ConfigValidationUtils; +import org.apache.dubbo.config.validator.ApplicationConfigValidator; import org.apache.dubbo.metadata.MetadataService; import org.apache.dubbo.monitor.MonitorService; import org.apache.dubbo.registry.RegistryService; @@ -42,6 +43,7 @@ import org.apache.dubbo.rpc.Exporter; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol; import org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig; +import org.apache.dubbo.util.MonitorUrlUtil; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -114,13 +116,13 @@ class DubboBootstrapTest { writeDubboProperties(SHUTDOWN_WAIT_KEY, "100"); ApplicationModel.defaultModel().modelEnvironment().getPropertiesConfiguration().refresh(); - ConfigValidationUtils.validateApplicationConfig(new ApplicationConfig("demo")); + ApplicationConfigValidator.validateApplicationConfig(new ApplicationConfig("demo")); Assertions.assertEquals("100", System.getProperty(SHUTDOWN_WAIT_KEY)); System.clearProperty(SHUTDOWN_WAIT_KEY); writeDubboProperties(SHUTDOWN_WAIT_SECONDS_KEY, "1000"); ApplicationModel.defaultModel().modelEnvironment().getPropertiesConfiguration().refresh(); - ConfigValidationUtils.validateApplicationConfig(new ApplicationConfig("demo")); + ApplicationConfigValidator.validateApplicationConfig(new ApplicationConfig("demo")); Assertions.assertEquals("1000", System.getProperty(SHUTDOWN_WAIT_SECONDS_KEY)); } finally { System.clearProperty("dubbo.application.name"); @@ -162,7 +164,7 @@ class DubboBootstrapTest { void testLoadUserMonitor_address_only() { // -Ddubbo.monitor.address=monitor-addr:12080 SysProps.setProperty(DUBBO_MONITOR_ADDRESS, "monitor-addr:12080"); - URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(new MonitorConfig()), new ServiceConfigURL("dubbo", "addr1", 9090)); + URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(new MonitorConfig()), new ServiceConfigURL("dubbo", "addr1", 9090)); Assertions.assertEquals("monitor-addr:12080", url.getAddress()); Assertions.assertEquals(MonitorService.class.getName(), url.getParameter("interface")); Assertions.assertNotNull(url.getParameter("dubbo")); @@ -176,7 +178,7 @@ class DubboBootstrapTest { MonitorConfig monitorConfig = new MonitorConfig(); monitorConfig.setProtocol("registry"); - URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress())); + URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress())); Assertions.assertEquals("dubbo", url.getProtocol()); Assertions.assertEquals("registry", url.getParameter("protocol")); } @@ -187,14 +189,14 @@ class DubboBootstrapTest { MonitorConfig monitorConfig = new MonitorConfig(); monitorConfig.setProtocol("service-discovery-registry"); - URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress())); + URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress())); Assertions.assertEquals("dubbo", url.getProtocol()); Assertions.assertEquals("service-discovery-registry", url.getParameter("protocol")); } @Test void testLoadUserMonitor_no_monitor() { - URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(null), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress())); + URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(null), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress())); Assertions.assertNull(url); } @@ -204,7 +206,7 @@ class DubboBootstrapTest { MonitorConfig monitorConfig = new MonitorConfig(); monitorConfig.setProtocol("user"); - URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress())); + URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress())); Assertions.assertEquals("user", url.getProtocol()); } @@ -213,7 +215,7 @@ class DubboBootstrapTest { // dubbo.monitor.address=user://1.2.3.4:5678?k=v MonitorConfig monitorConfig = new MonitorConfig(); monitorConfig.setAddress("user://1.2.3.4:5678?param1=value1"); - URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress())); + URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress())); Assertions.assertEquals("user", url.getProtocol()); Assertions.assertEquals("1.2.3.4:5678", url.getAddress()); Assertions.assertEquals("value1", url.getParameter("param1")); diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ConfigValidationUtilsTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ConfigValidationUtilsTest.java index bd059ffb2a..d5bd6eac65 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ConfigValidationUtilsTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ConfigValidationUtilsTest.java @@ -20,7 +20,9 @@ import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.config.AbstractInterfaceConfig; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.MetadataReportConfig; - +import org.apache.dubbo.config.exception.ConfigValidationException; +import org.apache.dubbo.config.validator.ApplicationConfigValidator; +import org.apache.dubbo.config.validator.MetadataConfigValidator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; @@ -29,9 +31,12 @@ import org.mockito.Mockito; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; +import java.util.regex.Pattern; import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CLASS_NOT_FOUND; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -45,7 +50,7 @@ class ConfigValidationUtilsTest { MetadataReportConfig config = new MetadataReportConfig(); config.setAddress("protocol://ip:host"); try { - ConfigValidationUtils.validateMetadataConfig(config); + MetadataConfigValidator.validateMetadataConfig(config); } catch (Exception e) { Assertions.fail("valid config expected."); } @@ -53,7 +58,7 @@ class ConfigValidationUtilsTest { config.setAddress("ip:host"); config.setProtocol("protocol"); try { - ConfigValidationUtils.validateMetadataConfig(config); + MetadataConfigValidator.validateMetadataConfig(config); } catch (Exception e) { Assertions.fail("valid config expected."); } @@ -61,17 +66,18 @@ class ConfigValidationUtilsTest { config.setAddress("ip:host"); config.setProtocol(null); Assertions.assertThrows(IllegalArgumentException.class, () -> { - ConfigValidationUtils.validateMetadataConfig(config); + MetadataConfigValidator.validateMetadataConfig(config); }); } @Test void testValidateApplicationConfig() throws Exception { - try (MockedStatic mockedStatic = Mockito.mockStatic(ConfigValidationUtils.class);) { - mockedStatic.when(() -> ConfigValidationUtils.validateApplicationConfig(any())).thenCallRealMethod(); + try (MockedStatic mockedStatic = Mockito.mockStatic(ApplicationConfigValidator.class); + MockedStatic configValidationUtilsMockedStatic = Mockito.mockStatic(ConfigValidationUtils.class);) { + mockedStatic.when(() -> ApplicationConfigValidator.validateApplicationConfig(any())).thenCallRealMethod(); ApplicationConfig config = new ApplicationConfig(); - Assertions.assertThrows(IllegalStateException.class, () -> { - ConfigValidationUtils.validateApplicationConfig(config); + Assertions.assertThrows(ConfigValidationException.class, () -> { + ApplicationConfigValidator.validateApplicationConfig(config); }); config.setName("testName"); @@ -83,14 +89,19 @@ class ConfigValidationUtilsTest { map.put("k1", "v1"); map.put("k2", "v2"); config.setParameters(map); - ConfigValidationUtils.validateApplicationConfig(config); - mockedStatic.verify(() -> { + ApplicationConfigValidator.validateApplicationConfig(config); + + configValidationUtilsMockedStatic.when(()-> ConfigValidationUtils.checkName(anyString(),anyString())).thenCallRealMethod(); + configValidationUtilsMockedStatic.when(()-> ConfigValidationUtils.checkMultiName(anyString(),anyString())).thenCallRealMethod(); + configValidationUtilsMockedStatic.when(()-> ConfigValidationUtils.checkParameterName(any())).thenCallRealMethod(); + configValidationUtilsMockedStatic.when(()-> ConfigValidationUtils.checkProperty(anyString(),anyString(),anyInt(),any(Pattern.class))).thenCallRealMethod(); + configValidationUtilsMockedStatic.verify(() -> { ConfigValidationUtils.checkName(any(), any()); }, times(4)); - mockedStatic.verify(() -> { + configValidationUtilsMockedStatic.verify(() -> { ConfigValidationUtils.checkMultiName(any(), any()); }, times(1)); - mockedStatic.verify(() -> { + configValidationUtilsMockedStatic.verify(() -> { ConfigValidationUtils.checkParameterName(any()); }, times(1)); } @@ -98,13 +109,13 @@ class ConfigValidationUtilsTest { @Test void testCheckQosInApplicationConfig() throws Exception { - ConfigValidationUtils mock = Mockito.mock(ConfigValidationUtils.class); + ApplicationConfigValidator mock = Mockito.mock(ApplicationConfigValidator.class); ErrorTypeAwareLogger loggerMock = Mockito.mock(ErrorTypeAwareLogger.class); injectField(mock.getClass().getDeclaredField("logger"), loggerMock); ApplicationConfig config = new ApplicationConfig(); config.setName("testName"); config.setQosEnable(false); - mock.validateApplicationConfig(config); + ApplicationConfigValidator.validateApplicationConfig(config); verify(loggerMock, never()).warn(any(), any(Throwable.class)); config.setQosEnable(true); diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml index 8f8efd3369..60f9d50e5b 100644 --- a/dubbo-distribution/dubbo-all/pom.xml +++ b/dubbo-distribution/dubbo-all/pom.xml @@ -1590,6 +1590,13 @@ META-INF/dubbo/internal/org.apache.dubbo.config.CommonConfigPostProcessor + + + + META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator + + diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/config/validator/MetadataConfigValidator.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/config/validator/MetadataConfigValidator.java new file mode 100644 index 0000000000..d0beb62714 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/config/validator/MetadataConfigValidator.java @@ -0,0 +1,64 @@ +/* + * 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.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.MetadataReportConfig; +import org.apache.dubbo.config.context.ConfigValidator; + +import static org.apache.dubbo.common.utils.StringUtils.isEmpty; + +@Activate +public class MetadataConfigValidator implements ConfigValidator { + + @Override + public boolean validate(MetadataReportConfig config) { + return validateMetadataConfig(config); + } + + public static boolean validateMetadataConfig(MetadataReportConfig metadataReportConfig) { + if (!isValidMetadataConfig(metadataReportConfig)) { + return false; + } + + String address = metadataReportConfig.getAddress(); + String protocol = metadataReportConfig.getProtocol(); + + if ((isEmpty(address) || !address.contains("://")) && isEmpty(protocol)) { + throw new IllegalArgumentException("Please specify valid protocol or address for metadata report " + address); + } + return true; + } + + public static boolean isValidMetadataConfig(MetadataReportConfig metadataReportConfig) { + if (metadataReportConfig == null) { + return false; + } + + if (Boolean.FALSE.equals(metadataReportConfig.getReportMetadata()) && + Boolean.FALSE.equals(metadataReportConfig.getReportDefinition())) { + return false; + } + + return !isEmpty(metadataReportConfig.getAddress()); + } + + @Override + public boolean isSupport(Class configClass) { + return MetadataReportConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator new file mode 100644 index 0000000000..5301ecbc08 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator @@ -0,0 +1 @@ +metadata=org.apache.dubbo.config.validator.MetadataConfigValidator diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/config/validator/MetricsConfigValidator.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/config/validator/MetricsConfigValidator.java new file mode 100644 index 0000000000..f1fbc062e0 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/config/validator/MetricsConfigValidator.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.MetricsConfig; +import org.apache.dubbo.config.context.ConfigValidator; + +@Activate +public class MetricsConfigValidator implements ConfigValidator { + + public static void validateMetricsConfig(MetricsConfig metricsConfig) { + //TODO + if (metricsConfig == null) { + } + } + + @Override + public boolean validate(MetricsConfig config) { + validateMetricsConfig(config); + return true; + } + + @Override + public boolean isSupport(Class configClass) { + return MetricsConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-metrics/dubbo-metrics-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator new file mode 100644 index 0000000000..2716b9c85f --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator @@ -0,0 +1 @@ +metrics=org.apache.dubbo.config.validator.MetricsConfigValidator diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java index 9fd5257cc5..1e4ecebbe8 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java +++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java @@ -33,7 +33,6 @@ import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper; import org.apache.dubbo.metrics.model.key.MetricsLevel; import org.apache.dubbo.metrics.model.key.MetricsPlaceValue; -import org.apache.dubbo.metrics.model.key.TypeWrapper; import org.apache.dubbo.metrics.model.sample.CounterMetricSample; import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; import org.apache.dubbo.metrics.model.sample.MetricSample; @@ -45,7 +44,6 @@ import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; - import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -157,7 +155,8 @@ class DefaultCollectorTest { // push finish rt +1 List metricSamples = collector.collect(); //num(total+success+processing) + rt(5) + error code = 9 - Assertions.assertEquals(metricSamples.size(),9); + Assertions.assertEquals(9, metricSamples.size()); + List metricsNames = metricSamples.stream().map(MetricSample::getName).collect(Collectors.toList()); // No error will contain total+success+processing String REQUESTS = new MetricsKeyWrapper(METRIC_REQUESTS, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey(); diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/config/validator/TracingConfigValidator.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/config/validator/TracingConfigValidator.java new file mode 100644 index 0000000000..a975dc019a --- /dev/null +++ b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/config/validator/TracingConfigValidator.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.TracingConfig; +import org.apache.dubbo.config.context.ConfigValidator; + +@Activate +public class TracingConfigValidator implements ConfigValidator { + + public static void validateTracingConfig(TracingConfig tracingConfig) { + // TODO + if (tracingConfig == null) { + } + } + + @Override + public boolean validate(TracingConfig config) { + validateTracingConfig(config); + return true; + } + + @Override + public boolean isSupport(Class configClass) { + return TracingConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-metrics/dubbo-tracing/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-metrics/dubbo-tracing/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator new file mode 100644 index 0000000000..32777468ad --- /dev/null +++ b/dubbo-metrics/dubbo-tracing/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator @@ -0,0 +1 @@ +tracing=org.apache.dubbo.config.validator.TracingConfigValidator diff --git a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/util/MonitorUrlUtil.java b/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/util/MonitorUrlUtil.java new file mode 100644 index 0000000000..23fd61e9c0 --- /dev/null +++ b/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/util/MonitorUrlUtil.java @@ -0,0 +1,102 @@ +/* + * 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.util; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.URLBuilder; +import org.apache.dubbo.common.utils.ConfigUtils; +import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.common.utils.UrlUtils; +import org.apache.dubbo.config.AbstractConfig; +import org.apache.dubbo.config.AbstractInterfaceConfig; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.MonitorConfig; +import org.apache.dubbo.monitor.Constants; +import org.apache.dubbo.monitor.MonitorFactory; +import org.apache.dubbo.monitor.MonitorService; + + +import java.util.HashMap; +import java.util.Map; + +import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_MONITOR_ADDRESS; +import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL; +import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE; +import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL; +import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL; +import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY; +import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY; +import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY; + +public class MonitorUrlUtil { + + public static URL loadMonitor(AbstractInterfaceConfig interfaceConfig, URL registryURL) { + Map map = new HashMap(); + map.put(INTERFACE_KEY, MonitorService.class.getName()); + AbstractInterfaceConfig.appendRuntimeParameters(map); + //set ip + String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY); + if (StringUtils.isEmpty(hostToRegistry)) { + hostToRegistry = NetUtils.getLocalHost(); + } else if (NetUtils.isInvalidLocalHost(hostToRegistry)) { + throw new IllegalArgumentException("Specified invalid registry ip from property:" + + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); + } + map.put(REGISTER_IP_KEY, hostToRegistry); + + MonitorConfig monitor = interfaceConfig.getMonitor(); + ApplicationConfig application = interfaceConfig.getApplication(); + AbstractConfig.appendParameters(map, monitor); + AbstractConfig.appendParameters(map, application); + String address = null; + String sysAddress = System.getProperty(DUBBO_MONITOR_ADDRESS); + if (sysAddress != null && sysAddress.length() > 0) { + address = sysAddress; + } else if (monitor != null) { + address = monitor.getAddress(); + } + String protocol = monitor == null ? null : monitor.getProtocol(); + if (monitor != null && + (REGISTRY_PROTOCOL.equals(protocol) || SERVICE_REGISTRY_PROTOCOL.equals(protocol)) + && registryURL != null) { + return URLBuilder.from(registryURL) + .setProtocol(DUBBO_PROTOCOL) + .addParameter(PROTOCOL_KEY, protocol) + .putAttribute(REFER_KEY, map) + .build(); + + } else if (ConfigUtils.isNotEmpty(address) || ConfigUtils.isNotEmpty(protocol)) { + if (!map.containsKey(PROTOCOL_KEY)) { + if (interfaceConfig.getScopeModel().getExtensionLoader(MonitorFactory.class).hasExtension(Constants.LOGSTAT_PROTOCOL)) { + map.put(PROTOCOL_KEY, Constants.LOGSTAT_PROTOCOL); + } else if (ConfigUtils.isNotEmpty(protocol)) { + map.put(PROTOCOL_KEY, protocol); + } else { + map.put(PROTOCOL_KEY, DUBBO_PROTOCOL); + } + } + if (ConfigUtils.isEmpty(address)) { + address = LOCALHOST_VALUE; + } + return UrlUtils.parseURL(address, map); + } + return null; + } +} diff --git a/dubbo-monitor/dubbo-monitor-common/src/main/java/org/apache/dubbo/config/validator/MonitorConfigValidator.java b/dubbo-monitor/dubbo-monitor-common/src/main/java/org/apache/dubbo/config/validator/MonitorConfigValidator.java new file mode 100644 index 0000000000..efcc3c1bef --- /dev/null +++ b/dubbo-monitor/dubbo-monitor-common/src/main/java/org/apache/dubbo/config/validator/MonitorConfigValidator.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.config.MonitorConfig; +import org.apache.dubbo.config.context.ConfigValidator; +import org.apache.dubbo.config.utils.ConfigValidationUtils; + + +@Activate +public class MonitorConfigValidator implements ConfigValidator { + + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MonitorConfigValidator.class); + + public static boolean validateMonitorConfig(MonitorConfig config) { + if (config != null) { + if (!config.isValid()) { + logger.info("There's no valid monitor config found, if you want to open monitor statistics for Dubbo, " + + "please make sure your monitor is configured properly."); + return false; + } + ConfigValidationUtils.checkParameterName(config.getParameters()); + } + return true; + } + + @Override + public boolean validate(MonitorConfig config) { + return validateMonitorConfig(config); + } + + @Override + public boolean isSupport(Class configClass) { + return MonitorConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-monitor/dubbo-monitor-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-monitor/dubbo-monitor-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator new file mode 100644 index 0000000000..ca6341e3da --- /dev/null +++ b/dubbo-monitor/dubbo-monitor-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator @@ -0,0 +1 @@ +monitor=org.apache.dubbo.config.validator.MonitorConfigValidator diff --git a/dubbo-plugin/dubbo-security/src/test/java/org/apache/dubbo/security/cert/CertDeployerListenerTest.java b/dubbo-plugin/dubbo-security/src/test/java/org/apache/dubbo/security/cert/CertDeployerListenerTest.java index ce6a5fa665..11ca883d94 100644 --- a/dubbo-plugin/dubbo-security/src/test/java/org/apache/dubbo/security/cert/CertDeployerListenerTest.java +++ b/dubbo-plugin/dubbo-security/src/test/java/org/apache/dubbo/security/cert/CertDeployerListenerTest.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.deploy.ApplicationDeployer; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.MetadataReportConfig; import org.apache.dubbo.config.SslConfig; +import org.apache.dubbo.config.exception.ConfigValidationException; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; @@ -111,7 +112,7 @@ class CertDeployerListenerTest { applicationModel.getApplicationConfigManager().addMetadataReport(new MetadataReportConfig("absent")); ApplicationDeployer deployer = applicationModel.getDeployer(); - Assertions.assertThrows(IllegalArgumentException.class, deployer::start); + Assertions.assertThrows(ConfigValidationException.class, deployer::start); Mockito.verify(reference.get(), Mockito.times(1)) .connect(Mockito.any()); Mockito.verify(reference.get(), Mockito.atLeast(1)) diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/config/validate/RegistryConfigValidator.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/config/validate/RegistryConfigValidator.java new file mode 100644 index 0000000000..ce40b7a974 --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/config/validate/RegistryConfigValidator.java @@ -0,0 +1,56 @@ +/* + * 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.validate; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.context.ConfigValidator; +import org.apache.dubbo.config.utils.ConfigValidationUtils; + +import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY; +import static org.apache.dubbo.remoting.Constants.CLIENT_KEY; +import static org.apache.dubbo.remoting.Constants.SERVER_KEY; +import static org.apache.dubbo.remoting.Constants.TRANSPORTER_KEY; + +@Activate +public class RegistryConfigValidator implements ConfigValidator { + + @Override + public boolean validate(RegistryConfig config) { + validateRegistryConfig(config); + return true; + } + + public static void validateRegistryConfig(RegistryConfig config) { + ConfigValidationUtils.checkName(PROTOCOL_KEY, config.getProtocol()); + ConfigValidationUtils.checkName(USERNAME_KEY, config.getUsername()); + ConfigValidationUtils.checkLength(PASSWORD_KEY, config.getPassword()); + ConfigValidationUtils.checkPathLength(FILE_KEY, config.getFile()); + ConfigValidationUtils.checkName(TRANSPORTER_KEY, config.getTransporter()); + ConfigValidationUtils.checkName(SERVER_KEY, config.getServer()); + ConfigValidationUtils.checkName(CLIENT_KEY, config.getClient()); + ConfigValidationUtils.checkParameterName(config.getParameters()); + } + + @Override + public boolean isSupport(Class configClass) { + return RegistryConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/config/validator/SslConfigValidator.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/config/validator/SslConfigValidator.java new file mode 100644 index 0000000000..d6bf0374fc --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/config/validator/SslConfigValidator.java @@ -0,0 +1,40 @@ +/* + * 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.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.SslConfig; +import org.apache.dubbo.config.context.ConfigValidator; + +@Activate +public class SslConfigValidator implements ConfigValidator { + + public static void validateSslConfig(SslConfig sslConfig) { + // TODO + } + + @Override + public boolean validate(SslConfig config) { + validateSslConfig(config); + return true; + } + + @Override + public boolean isSupport(Class configClass) { + return SslConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator new file mode 100644 index 0000000000..56a39d1693 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator @@ -0,0 +1 @@ +ssl=org.apache.dubbo.config.validator.SslConfigValidator diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/config/validator/ProtocolConfigValidator.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/config/validator/ProtocolConfigValidator.java new file mode 100644 index 0000000000..2884bf4030 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/config/validator/ProtocolConfigValidator.java @@ -0,0 +1,82 @@ +/* + * 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.validator; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.serialize.Serialization; +import org.apache.dubbo.common.status.StatusChecker; +import org.apache.dubbo.common.threadpool.ThreadPool; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.context.ConfigValidator; +import org.apache.dubbo.config.utils.ConfigValidationUtils; +import org.apache.dubbo.remoting.Codec2; +import org.apache.dubbo.remoting.Dispatcher; +import org.apache.dubbo.remoting.Transporter; +import org.apache.dubbo.remoting.exchange.Exchanger; +import org.apache.dubbo.remoting.telnet.TelnetHandler; + +import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL; +import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY; +import static org.apache.dubbo.remoting.Constants.CLIENT_KEY; +import static org.apache.dubbo.remoting.Constants.CODEC_KEY; +import static org.apache.dubbo.remoting.Constants.DISPATCHER_KEY; +import static org.apache.dubbo.remoting.Constants.EXCHANGER_KEY; +import static org.apache.dubbo.remoting.Constants.SERIALIZATION_KEY; +import static org.apache.dubbo.remoting.Constants.SERVER_KEY; +import static org.apache.dubbo.remoting.Constants.TELNET_KEY; +import static org.apache.dubbo.remoting.Constants.TRANSPORTER_KEY; + +@Activate +public class ProtocolConfigValidator implements ConfigValidator { + + @Override + public boolean validate(ProtocolConfig config) { + validateProtocolConfig(config); + return true; + } + + public static void validateProtocolConfig(ProtocolConfig config) { + if (config != null) { + String name = config.getName(); + ConfigValidationUtils.checkName("name", name); + ConfigValidationUtils.checkHost(HOST_KEY, config.getHost()); + ConfigValidationUtils.checkPathName("contextpath", config.getContextpath()); + + + if (DUBBO_PROTOCOL.equals(name)) { + ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), Codec2.class, CODEC_KEY, config.getCodec()); + ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), Serialization.class, SERIALIZATION_KEY, config.getSerialization()); + ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), Transporter.class, SERVER_KEY, config.getServer()); + ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), Transporter.class, CLIENT_KEY, config.getClient()); + } + + ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), TelnetHandler.class, TELNET_KEY, config.getTelnet()); + ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), StatusChecker.class, "status", config.getStatus()); + ConfigValidationUtils.checkExtension(config.getScopeModel(), Transporter.class, TRANSPORTER_KEY, config.getTransporter()); + ConfigValidationUtils.checkExtension(config.getScopeModel(), Exchanger.class, EXCHANGER_KEY, config.getExchanger()); + ConfigValidationUtils.checkExtension(config.getScopeModel(), Dispatcher.class, DISPATCHER_KEY, config.getDispatcher()); + ConfigValidationUtils.checkExtension(config.getScopeModel(), Dispatcher.class, "dispather", config.getDispather()); + ConfigValidationUtils.checkExtension(config.getScopeModel(), ThreadPool.class, THREADPOOL_KEY, config.getThreadpool()); + } + } + + @Override + public boolean isSupport(Class configClass) { + return ProtocolConfig.class.isAssignableFrom(configClass); + } +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator new file mode 100644 index 0000000000..e53a309b5c --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator @@ -0,0 +1 @@ +protocol=org.apache.dubbo.config.validator.ProtocolConfigValidator