| /* |
| * 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.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.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 org.apache.dubbo.rpc.support.MockInvoker; |
| |
| 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.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.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 final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ConfigValidationUtils.class); |
| /** |
| * The maximum length of a <b>parameter's value</b> |
| */ |
| private static final int MAX_LENGTH = 200; |
| |
| /** |
| * The maximum length of a <b>path</b> |
| */ |
| private static final int MAX_PATH_LENGTH = 200; |
| |
| /** |
| * The rule qualification for <b>name</b> |
| */ |
| private static final Pattern PATTERN_NAME = Pattern.compile("[\\-._0-9a-zA-Z]+"); |
| |
| /** |
| * The rule qualification for <b>multiply name</b> |
| */ |
| private static final Pattern PATTERN_MULTI_NAME = Pattern.compile("[,\\-._0-9a-zA-Z]+"); |
| |
| /** |
| * The rule qualification for <b>method names</b> |
| */ |
| private static final Pattern PATTERN_METHOD_NAME = Pattern.compile("[a-zA-Z][0-9a-zA-Z]*"); |
| |
| /** |
| * The rule qualification for <b>path</b> |
| */ |
| 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<URL> loadRegistries(AbstractInterfaceConfig interfaceConfig, boolean provider) { |
| // check && override if necessary |
| List<URL> registryList = new ArrayList<>(); |
| ApplicationConfig application = interfaceConfig.getApplication(); |
| List<RegistryConfig> 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<String, String> map = new HashMap<String, String>(); |
| 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<URL> 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(SUBSCRIBE_KEY, true)) { |
| registryList.add(url); |
| } |
| } |
| } |
| } |
| } |
| return genCompatibleRegistries(interfaceConfig.getScopeModel(), registryList, provider); |
| } |
| |
| private static List<URL> genCompatibleRegistries(ScopeModel scopeModel, List<URL> registryList, boolean provider) { |
| List<URL> 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<URL> 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<String, String> map = new HashMap<String, String>(); |
| 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; |
| } |
| |
| /** |
| * Legitimacy check and setup of local simulated operations. The operations can be a string with Simple operation or |
| * a classname whose {@link Class} implements a particular function |
| * |
| * @param interfaceClass for provider side, it is the {@link Class} of the service that will be exported; for consumer |
| * side, it is the {@link Class} of the remote service interface that will be referenced |
| */ |
| public static void checkMock(Class<?> interfaceClass, AbstractInterfaceConfig config) { |
| String mock = config.getMock(); |
| if (ConfigUtils.isEmpty(mock)) { |
| return; |
| } |
| |
| String normalizedMock = MockInvoker.normalizeMock(mock); |
| if (normalizedMock.startsWith(RETURN_PREFIX)) { |
| normalizedMock = normalizedMock.substring(RETURN_PREFIX.length()).trim(); |
| try { |
| //Check whether the mock value is legal, if it is illegal, throw exception |
| MockInvoker.parseMockValue(normalizedMock); |
| } catch (Exception e) { |
| throw new IllegalStateException("Illegal mock return in <dubbo:service/reference ... " + |
| "mock=\"" + mock + "\" />"); |
| } |
| } else if (normalizedMock.startsWith(THROW_PREFIX)) { |
| normalizedMock = normalizedMock.substring(THROW_PREFIX.length()).trim(); |
| if (ConfigUtils.isNotEmpty(normalizedMock)) { |
| try { |
| //Check whether the mock value is legal |
| MockInvoker.getThrowable(normalizedMock); |
| } catch (Exception e) { |
| throw new IllegalStateException("Illegal mock throw in <dubbo:service/reference ... " + |
| "mock=\"" + mock + "\" />"); |
| } |
| } |
| } else { |
| //Check whether the mock class is a implementation of the interfaceClass, and if it has a default constructor |
| MockInvoker.getMockObject(config.getScopeModel().getExtensionDirector(), normalizedMock, interfaceClass); |
| } |
| } |
| |
| 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<MethodConfig> 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<RegistryConfig> registries = config.getRegistries(); |
| if (registries != null) { |
| for (RegistryConfig registry : registries) { |
| validateRegistryConfig(registry); |
| } |
| } |
| |
| List<ProtocolConfig> 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<RegistryConfig> 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 <dubbo:application name=\"...\" /> to your spring config."); |
| } |
| |
| // backward compatibility |
| ScopeModel scopeModel = ScopeModelUtil.getOrDefaultApplicationModel(config.getScopeModel()); |
| PropertiesConfiguration configuration = scopeModel.getModelEnvironment().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()); |
| } |
| |
| public static void validateModuleConfig(ModuleConfig config) { |
| if (config != null) { |
| checkName(NAME, config.getName()); |
| checkName(OWNER, config.getOwner()); |
| checkName(ORGANIZATION, config.getOrganization()); |
| } |
| } |
| |
| public static void validateMetadataConfig(MetadataReportConfig metadataReportConfig) { |
| if (metadataReportConfig == null) { |
| 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 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 <code>Extension</code> who's name (property) is <code>value</code> (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<Class<?>> types, String property, String value) { |
| checkMultiName(property, value); |
| if (isNotEmpty(value)) { |
| String[] values = value.split("\\s*[,]+\\s*"); |
| for (String v : values) { |
| if (v.startsWith(REMOVE_VALUE_PREFIX)) { |
| v = v.substring(1); |
| } |
| 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<String, String> parameters) { |
| if (CollectionUtils.isEmptyMap(parameters)) { |
| return; |
| } |
| List<String> 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<String, String> 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."); |
| } |
| } |
| } |
| |
| } |