From c129da8133bbde1a4b9f4e1f891b5109be52a377 Mon Sep 17 00:00:00 2001 From: Huang Yunkun Date: Sat, 9 Feb 2019 21:14:14 +0800 Subject: [PATCH 1/2] add checkstyle for redundant import and fix all issue in repo --- codestyle/checkstyle.xml | 1 + .../dubbo/config/AbstractInterfaceConfig.java | 1 - .../apache/dubbo/config/ServiceConfig.java | 1999 ++++++++--------- 3 files changed, 1000 insertions(+), 1001 deletions(-) diff --git a/codestyle/checkstyle.xml b/codestyle/checkstyle.xml index f721d510d4c..fa4d735a785 100644 --- a/codestyle/checkstyle.xml +++ b/codestyle/checkstyle.xml @@ -20,6 +20,7 @@ + diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java index 3ba300c8a80..4899d5a7842 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java @@ -29,7 +29,6 @@ import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.UrlUtils; import org.apache.dubbo.config.context.ConfigManager; -import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.config.support.Parameter; import org.apache.dubbo.configcenter.DynamicConfiguration; import org.apache.dubbo.configcenter.DynamicConfigurationFactory; 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 3a85ac8b274..538a2a49398 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 @@ -1,1000 +1,999 @@ -/* - * 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.Constants; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.Version; -import org.apache.dubbo.common.bytecode.Wrapper; -import org.apache.dubbo.common.config.Environment; -import org.apache.dubbo.common.extension.ExtensionLoader; -import org.apache.dubbo.common.utils.ClassHelper; -import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.common.utils.ConfigUtils; -import org.apache.dubbo.common.utils.NamedThreadFactory; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.config.annotation.Service; -import org.apache.dubbo.config.context.ConfigManager; -import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker; -import org.apache.dubbo.config.support.Parameter; -import org.apache.dubbo.metadata.integration.MetadataReportService; -import org.apache.dubbo.rpc.Exporter; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.Protocol; -import org.apache.dubbo.rpc.ProxyFactory; -import org.apache.dubbo.rpc.cluster.ConfiguratorFactory; -import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.ProviderModel; -import org.apache.dubbo.rpc.service.GenericService; -import org.apache.dubbo.rpc.support.ProtocolUtils; - -import java.lang.reflect.Method; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import static org.apache.dubbo.common.Constants.LOCALHOST_VALUE; -import static org.apache.dubbo.common.utils.NetUtils.getAvailablePort; -import static org.apache.dubbo.common.utils.NetUtils.getLocalHost; -import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost; -import static org.apache.dubbo.common.utils.NetUtils.isInvalidPort; - -/** - * ServiceConfig - * - * @export - */ -public class ServiceConfig extends AbstractServiceConfig { - - private static final long serialVersionUID = 3033787999037024738L; - - /** - * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios. - * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}. - * For example: - * - *
  • when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample, - * then the protocol is RegistryProtocol
  • - * - *
  • when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then - * the protocol is DubboProtocol
  • - *

    - * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two - * layers, and eventually will get a ProtocolFilterWrapper or ProtocolListenerWrapper - */ - private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - - /** - * A {@link ProxyFactory} implementation that will generate a exported service proxy,the JavassistProxyFactory is its - * default implementation - */ - private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); - - /** - * A random port cache, the different protocols who has no port specified have different random port - */ - private static final Map RANDOM_PORT_MAP = new HashMap(); - - /** - * A delayed exposure service timer - */ - private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true)); - - /** - * The urls of the services exported - */ - private final List urls = new ArrayList(); - - /** - * The exported services - */ - private final List> exporters = new ArrayList>(); - - /** - * The interface name of the exported service - */ - private String interfaceName; - - /** - * The interface class of the exported service - */ - private Class interfaceClass; - - /** - * The reference of the interface implementation - */ - private T ref; - - /** - * The service name - */ - private String path; - - /** - * The method configuration - */ - private List methods; - - /** - * The provider configuration - */ - private ProviderConfig provider; - - /** - * The providerIds - */ - private String providerIds; - - /** - * Whether the provider has been exported - */ - private transient volatile boolean exported; - - /** - * The flag whether a service has unexported ,if the method unexported is invoked, the value is true - */ - private transient volatile boolean unexported; - - /** - * whether it is a GenericService - */ - private volatile String generic; - - public ServiceConfig() { - } - - public ServiceConfig(Service service) { - appendAnnotation(Service.class, service); - } - - @Deprecated - private static List convertProviderToProtocol(List providers) { - if (CollectionUtils.isEmpty(providers)) { - return null; - } - List protocols = new ArrayList(providers.size()); - for (ProviderConfig provider : providers) { - protocols.add(convertProviderToProtocol(provider)); - } - return protocols; - } - - @Deprecated - private static List convertProtocolToProvider(List protocols) { - if (CollectionUtils.isEmpty(protocols)) { - return null; - } - List providers = new ArrayList(protocols.size()); - for (ProtocolConfig provider : protocols) { - providers.add(convertProtocolToProvider(provider)); - } - return providers; - } - - @Deprecated - private static ProtocolConfig convertProviderToProtocol(ProviderConfig provider) { - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName(provider.getProtocol().getName()); - protocol.setServer(provider.getServer()); - protocol.setClient(provider.getClient()); - protocol.setCodec(provider.getCodec()); - protocol.setHost(provider.getHost()); - protocol.setPort(provider.getPort()); - protocol.setPath(provider.getPath()); - protocol.setPayload(provider.getPayload()); - protocol.setThreads(provider.getThreads()); - protocol.setParameters(provider.getParameters()); - return protocol; - } - - @Deprecated - private static ProviderConfig convertProtocolToProvider(ProtocolConfig protocol) { - ProviderConfig provider = new ProviderConfig(); - provider.setProtocol(protocol); - provider.setServer(protocol.getServer()); - provider.setClient(protocol.getClient()); - provider.setCodec(protocol.getCodec()); - provider.setHost(protocol.getHost()); - provider.setPort(protocol.getPort()); - provider.setPath(protocol.getPath()); - provider.setPayload(protocol.getPayload()); - provider.setThreads(protocol.getThreads()); - provider.setParameters(protocol.getParameters()); - return provider; - } - - private static Integer getRandomPort(String protocol) { - protocol = protocol.toLowerCase(); - return RANDOM_PORT_MAP.getOrDefault(protocol, Integer.MIN_VALUE); - } - - private static void putRandomPort(String protocol, Integer port) { - protocol = protocol.toLowerCase(); - if (!RANDOM_PORT_MAP.containsKey(protocol)) { - RANDOM_PORT_MAP.put(protocol, port); - logger.warn("Use random available port(" + port + ") for protocol " + protocol); - } - } - - public URL toUrl() { - return urls.isEmpty() ? null : urls.iterator().next(); - } - - public List toUrls() { - return urls; - } - - @Parameter(excluded = true) - public boolean isExported() { - return exported; - } - - @Parameter(excluded = true) - public boolean isUnexported() { - return unexported; - } - - public void checkAndUpdateSubConfigs() { - // Use default configs defined explicitly on global configs - completeCompoundConfigs(); - // Config Center should always being started first. - startConfigCenter(); - checkDefault(); - checkApplication(); - checkRegistry(); - checkProtocol(); - this.refresh(); - checkMetadataReport(); - - if (StringUtils.isEmpty(interfaceName)) { - throw new IllegalStateException(" interface not allow null!"); - } - - if (ref instanceof GenericService) { - interfaceClass = GenericService.class; - if (StringUtils.isEmpty(generic)) { - generic = Boolean.TRUE.toString(); - } - } else { - try { - interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() - .getContextClassLoader()); - } catch (ClassNotFoundException e) { - throw new IllegalStateException(e.getMessage(), e); - } - checkInterfaceAndMethods(interfaceClass, methods); - checkRef(); - generic = Boolean.FALSE.toString(); - } - if (local != null) { - if ("true".equals(local)) { - local = interfaceName + "Local"; - } - Class localClass; - try { - localClass = ClassHelper.forNameWithThreadContextClassLoader(local); - } catch (ClassNotFoundException e) { - throw new IllegalStateException(e.getMessage(), e); - } - if (!interfaceClass.isAssignableFrom(localClass)) { - throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName); - } - } - if (stub != null) { - if ("true".equals(stub)) { - stub = interfaceName + "Stub"; - } - Class stubClass; - try { - stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub); - } catch (ClassNotFoundException e) { - throw new IllegalStateException(e.getMessage(), e); - } - if (!interfaceClass.isAssignableFrom(stubClass)) { - throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName); - } - } - checkStubAndLocal(interfaceClass); - checkMock(interfaceClass); - } - - public synchronized void export() { - checkAndUpdateSubConfigs(); - - if (provider != null) { - if (export == null) { - export = provider.getExport(); - } - if (delay == null) { - delay = provider.getDelay(); - } - } - if (export != null && !export) { - return; - } - - if (delay != null && delay > 0) { - delayExportExecutor.schedule(this::doExport, delay, TimeUnit.MILLISECONDS); - } else { - doExport(); - } - } - - protected synchronized void doExport() { - if (unexported) { - throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!"); - } - if (exported) { - return; - } - exported = true; - - if (StringUtils.isEmpty(path)) { - path = interfaceName; - } - ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), ref, interfaceClass); - ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel); - doExportUrls(); - } - - private void checkRef() { - // reference should not be null, and is the implementation of the given interface - if (ref == null) { - throw new IllegalStateException("ref not allow null!"); - } - if (!interfaceClass.isInstance(ref)) { - throw new IllegalStateException("The class " - + ref.getClass().getName() + " unimplemented interface " - + interfaceClass + "!"); - } - } - - public synchronized void unexport() { - if (!exported) { - return; - } - if (unexported) { - return; - } - if (!exporters.isEmpty()) { - for (Exporter exporter : exporters) { - try { - exporter.unexport(); - } catch (Throwable t) { - logger.warn("Unexpected error occured when unexport " + exporter, t); - } - } - exporters.clear(); - } - unexported = true; - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private void doExportUrls() { - List registryURLs = loadRegistries(true); - for (ProtocolConfig protocolConfig : protocols) { - doExportUrlsFor1Protocol(protocolConfig, registryURLs); - } - } - - private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) { - String name = protocolConfig.getName(); - if (StringUtils.isEmpty(name)) { - name = Constants.DUBBO; - } - - Map map = new HashMap(); - map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE); - appendRuntimeParameters(map); - appendParameters(map, application); - appendParameters(map, module); - appendParameters(map, provider, Constants.DEFAULT_KEY); - appendParameters(map, protocolConfig); - appendParameters(map, this); - if (CollectionUtils.isNotEmpty(methods)) { - for (MethodConfig method : methods) { - appendParameters(map, method, method.getName()); - String retryKey = method.getName() + ".retry"; - if (map.containsKey(retryKey)) { - String retryValue = map.remove(retryKey); - if ("false".equals(retryValue)) { - map.put(method.getName() + ".retries", "0"); - } - } - List arguments = method.getArguments(); - if (CollectionUtils.isNotEmpty(arguments)) { - for (ArgumentConfig argument : arguments) { - // convert argument type - if (argument.getType() != null && argument.getType().length() > 0) { - Method[] methods = interfaceClass.getMethods(); - // visit all methods - if (methods != null && methods.length > 0) { - for (int i = 0; i < methods.length; i++) { - String methodName = methods[i].getName(); - // target the method, and get its signature - if (methodName.equals(method.getName())) { - Class[] argtypes = methods[i].getParameterTypes(); - // one callback in the method - if (argument.getIndex() != -1) { - if (argtypes[argument.getIndex()].getName().equals(argument.getType())) { - appendParameters(map, argument, method.getName() + "." + argument.getIndex()); - } else { - throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType()); - } - } else { - // multiple callbacks in the method - for (int j = 0; j < argtypes.length; j++) { - Class argclazz = argtypes[j]; - if (argclazz.getName().equals(argument.getType())) { - appendParameters(map, argument, method.getName() + "." + j); - if (argument.getIndex() != -1 && argument.getIndex() != j) { - throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType()); - } - } - } - } - } - } - } - } else if (argument.getIndex() != -1) { - appendParameters(map, argument, method.getName() + "." + argument.getIndex()); - } else { - throw new IllegalArgumentException("Argument config must set index or type attribute.eg: or "); - } - - } - } - } // end of methods for - } - - if (ProtocolUtils.isGeneric(generic)) { - map.put(Constants.GENERIC_KEY, generic); - map.put(Constants.METHODS_KEY, Constants.ANY_VALUE); - } else { - String revision = Version.getVersion(interfaceClass, version); - if (revision != null && revision.length() > 0) { - map.put("revision", revision); - } - - String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames(); - if (methods.length == 0) { - logger.warn("No method found in service interface " + interfaceClass.getName()); - map.put(Constants.METHODS_KEY, Constants.ANY_VALUE); - } else { - map.put(Constants.METHODS_KEY, StringUtils.join(new HashSet(Arrays.asList(methods)), ",")); - } - } - if (!ConfigUtils.isEmpty(token)) { - if (ConfigUtils.isDefault(token)) { - map.put(Constants.TOKEN_KEY, UUID.randomUUID().toString()); - } else { - map.put(Constants.TOKEN_KEY, token); - } - } - // export service - String contextPath = protocolConfig.getContextpath(); - if (StringUtils.isEmpty(contextPath) && provider != null) { - contextPath = provider.getContextpath(); - } - - String host = this.findConfigedHosts(protocolConfig, registryURLs, map); - Integer port = this.findConfigedPorts(protocolConfig, name, map); - URL url = new URL(name, host, port, (StringUtils.isEmpty(contextPath) ? "" : contextPath + "/") + path, map); - - if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) - .hasExtension(url.getProtocol())) { - url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) - .getExtension(url.getProtocol()).getConfigurator(url).configure(url); - } - - String scope = url.getParameter(Constants.SCOPE_KEY); - // don't export when none is configured - if (!Constants.SCOPE_NONE.equalsIgnoreCase(scope)) { - - // export to local if the config is not remote (export to remote only when config is remote) - if (!Constants.SCOPE_REMOTE.equalsIgnoreCase(scope)) { - exportLocal(url); - } - // export to remote if the config is not local (export to local only when config is local) - if (!Constants.SCOPE_LOCAL.equalsIgnoreCase(scope)) { - if (logger.isInfoEnabled()) { - logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url); - } - if (CollectionUtils.isNotEmpty(registryURLs)) { - for (URL registryURL : registryURLs) { - url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY)); - URL monitorUrl = loadMonitor(registryURL); - if (monitorUrl != null) { - url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString()); - } - if (logger.isInfoEnabled()) { - logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL); - } - - // For providers, this is used to enable custom proxy to generate invoker - String proxy = url.getParameter(Constants.PROXY_KEY); - if (StringUtils.isNotEmpty(proxy)) { - registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy); - } - - Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString())); - DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); - - Exporter exporter = protocol.export(wrapperInvoker); - exporters.add(exporter); - } - } else { - Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); - DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); - - Exporter exporter = protocol.export(wrapperInvoker); - exporters.add(exporter); - } - /** - * @since 2.7.0 - * ServiceData Store - */ - MetadataReportService metadataReportService = null; - if ((metadataReportService = getMetadataReportService()) != null) { - metadataReportService.publishProvider(url); - } - } - } - this.urls.add(url); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private void exportLocal(URL url) { - if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { - URL local = URL.valueOf(url.toFullString()) - .setProtocol(Constants.LOCAL_PROTOCOL) - .setHost(LOCALHOST_VALUE) - .setPort(0); - Exporter exporter = protocol.export( - proxyFactory.getInvoker(ref, (Class) interfaceClass, local)); - exporters.add(exporter); - logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry"); - } - } - - protected Class getServiceClass(T ref) { - return ref.getClass(); - } - - /** - * Register & bind IP address for service provider, can be configured separately. - * Configuration priority: environment variables -> java system properties -> host property in config file -> - * /etc/hosts -> default network address -> first available network address - * - * @param protocolConfig - * @param registryURLs - * @param map - * @return - */ - private String findConfigedHosts(ProtocolConfig protocolConfig, List registryURLs, Map map) { - boolean anyhost = false; - - String hostToBind = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_BIND); - if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) { - throw new IllegalArgumentException("Specified invalid bind ip from property:" + Constants.DUBBO_IP_TO_BIND + ", value:" + hostToBind); - } - - // if bind ip is not found in environment, keep looking up - if (StringUtils.isEmpty(hostToBind)) { - hostToBind = protocolConfig.getHost(); - if (provider != null && StringUtils.isEmpty(hostToBind)) { - hostToBind = provider.getHost(); - } - if (isInvalidLocalHost(hostToBind)) { - anyhost = true; - try { - hostToBind = InetAddress.getLocalHost().getHostAddress(); - } catch (UnknownHostException e) { - logger.warn(e.getMessage(), e); - } - if (isInvalidLocalHost(hostToBind)) { - if (CollectionUtils.isNotEmpty(registryURLs)) { - for (URL registryURL : registryURLs) { - if (Constants.MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) { - // skip multicast registry since we cannot connect to it via Socket - continue; - } - try (Socket socket = new Socket()) { - SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort()); - socket.connect(addr, 1000); - hostToBind = socket.getLocalAddress().getHostAddress(); - break; - } catch (Exception e) { - logger.warn(e.getMessage(), e); - } - } - } - if (isInvalidLocalHost(hostToBind)) { - hostToBind = getLocalHost(); - } - } - } - } - - map.put(Constants.BIND_IP_KEY, hostToBind); - - // registry ip is not used for bind ip by default - String hostToRegistry = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_REGISTRY); - if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) { - throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); - } else if (StringUtils.isEmpty(hostToRegistry)) { - // bind ip is used as registry ip by default - hostToRegistry = hostToBind; - } - - map.put(Constants.ANYHOST_KEY, String.valueOf(anyhost)); - - return hostToRegistry; - } - - /** - * Register port and bind port for the provider, can be configured separately - * Configuration priority: environment variable -> java system properties -> port property in protocol config file - * -> protocol default port - * - * @param protocolConfig - * @param name - * @return - */ - private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map map) { - Integer portToBind = null; - - // parse bind port from environment - String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND); - portToBind = parsePort(port); - - // if there's no bind port found from environment, keep looking up. - if (portToBind == null) { - portToBind = protocolConfig.getPort(); - if (provider != null && (portToBind == null || portToBind == 0)) { - portToBind = provider.getPort(); - } - final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort(); - if (portToBind == null || portToBind == 0) { - portToBind = defaultPort; - } - if (portToBind == null || portToBind <= 0) { - portToBind = getRandomPort(name); - if (portToBind == null || portToBind < 0) { - portToBind = getAvailablePort(defaultPort); - putRandomPort(name, portToBind); - } - } - } - - // save bind port, used as url's key later - map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind)); - - // registry port, not used as bind port by default - String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY); - Integer portToRegistry = parsePort(portToRegistryStr); - if (portToRegistry == null) { - portToRegistry = portToBind; - } - - return portToRegistry; - } - - private Integer parsePort(String configPort) { - Integer port = null; - if (configPort != null && configPort.length() > 0) { - try { - Integer intPort = Integer.parseInt(configPort); - if (isInvalidPort(intPort)) { - throw new IllegalArgumentException("Specified invalid port from env value:" + configPort); - } - port = intPort; - } catch (Exception e) { - throw new IllegalArgumentException("Specified invalid port from env value:" + configPort); - } - } - return port; - } - - private String getValueFromConfig(ProtocolConfig protocolConfig, String key) { - String protocolPrefix = protocolConfig.getName().toUpperCase() + "_"; - String port = ConfigUtils.getSystemProperty(protocolPrefix + key); - if (StringUtils.isEmpty(port)) { - port = ConfigUtils.getSystemProperty(key); - } - return port; - } - - private void completeCompoundConfigs() { - if (provider != null) { - if (application == null) { - setApplication(provider.getApplication()); - } - if (module == null) { - setModule(provider.getModule()); - } - if (registries == null) { - setRegistries(provider.getRegistries()); - } - if (monitor == null) { - setMonitor(provider.getMonitor()); - } - if (protocols == null) { - setProtocols(provider.getProtocols()); - } - if (configCenter == null) { - setConfigCenter(provider.getConfigCenter()); - } - } - if (module != null) { - if (registries == null) { - setRegistries(module.getRegistries()); - } - if (monitor == null) { - setMonitor(module.getMonitor()); - } - } - if (application != null) { - if (registries == null) { - setRegistries(application.getRegistries()); - } - if (monitor == null) { - setMonitor(application.getMonitor()); - } - } - } - - private void checkDefault() { - createProviderIfAbsent(); - } - - private void createProviderIfAbsent() { - if (provider != null) { - return; - } - setProvider ( - ConfigManager.getInstance() - .getDefaultProvider() - .orElseGet(() -> { - ProviderConfig providerConfig = new ProviderConfig(); - providerConfig.refresh(); - return providerConfig; - }) - ); - } - - private void checkProtocol() { - if (CollectionUtils.isEmpty(protocols) && provider != null) { - setProtocols(provider.getProtocols()); - } - convertProtocolIdsToProtocols(); - } - - private void convertProtocolIdsToProtocols() { - if (StringUtils.isEmpty(protocolIds) && CollectionUtils.isEmpty(protocols)) { - List configedProtocols = new ArrayList<>(); - configedProtocols.addAll(getSubProperties(Environment.getInstance() - .getExternalConfigurationMap(), Constants.PROTOCOLS_SUFFIX)); - configedProtocols.addAll(getSubProperties(Environment.getInstance() - .getAppExternalConfigurationMap(), Constants.PROTOCOLS_SUFFIX)); - - protocolIds = String.join(",", configedProtocols); - } - - if (StringUtils.isEmpty(protocolIds)) { - if (CollectionUtils.isEmpty(protocols)) { - setProtocols( - ConfigManager.getInstance().getDefaultProtocols() - .filter(CollectionUtils::isNotEmpty) - .orElseGet(() -> { - ProtocolConfig protocolConfig = new ProtocolConfig(); - protocolConfig.refresh(); - return Arrays.asList(protocolConfig); - }) - ); - } - } else { - String[] arr = Constants.COMMA_SPLIT_PATTERN.split(protocolIds); - List tmpProtocols = CollectionUtils.isNotEmpty(protocols) ? protocols : new ArrayList<>(); - Arrays.stream(arr).forEach(id -> { - if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) { - tmpProtocols.add(ConfigManager.getInstance().getProtocol(id).orElseGet(() -> { - ProtocolConfig protocolConfig = new ProtocolConfig(); - protocolConfig.setId(id); - protocolConfig.refresh(); - return protocolConfig; - })); - } - }); - if (tmpProtocols.size() > arr.length) { - throw new IllegalStateException("Too much protocols found, the protocols comply to this service are :" + protocolIds + " but got " + protocols - .size() + " registries!"); - } - setProtocols(tmpProtocols); - } - } - - public Class getInterfaceClass() { - if (interfaceClass != null) { - return interfaceClass; - } - if (ref instanceof GenericService) { - return GenericService.class; - } - try { - if (interfaceName != null && interfaceName.length() > 0) { - this.interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() - .getContextClassLoader()); - } - } catch (ClassNotFoundException t) { - throw new IllegalStateException(t.getMessage(), t); - } - return interfaceClass; - } - - /** - * @param interfaceClass - * @see #setInterface(Class) - * @deprecated - */ - public void setInterfaceClass(Class interfaceClass) { - setInterface(interfaceClass); - } - - public String getInterface() { - return interfaceName; - } - - public void setInterface(Class interfaceClass) { - if (interfaceClass != null && !interfaceClass.isInterface()) { - throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); - } - this.interfaceClass = interfaceClass; - setInterface(interfaceClass == null ? null : interfaceClass.getName()); - } - - public void setInterface(String interfaceName) { - this.interfaceName = interfaceName; - if (StringUtils.isEmpty(id)) { - id = interfaceName; - } - } - - public T getRef() { - return ref; - } - - public void setRef(T ref) { - this.ref = ref; - } - - @Parameter(excluded = true) - public String getPath() { - return path; - } - - public void setPath(String path) { - checkPathName(Constants.PATH_KEY, path); - this.path = path; - } - - public List getMethods() { - return methods; - } - - // ======== Deprecated ======== - - @SuppressWarnings("unchecked") - public void setMethods(List methods) { - this.methods = (List) methods; - } - - public ProviderConfig getProvider() { - return provider; - } - - public void setProvider(ProviderConfig provider) { - ConfigManager.getInstance().addProvider(provider); - this.provider = provider; - } - - @Parameter(excluded = true) - public String getProviderIds() { - return providerIds; - } - - public void setProviderIds(String providerIds) { - this.providerIds = providerIds; - } - - public String getGeneric() { - return generic; - } - - public void setGeneric(String generic) { - if (StringUtils.isEmpty(generic)) { - return; - } - if (ProtocolUtils.isGeneric(generic)) { - this.generic = generic; - } else { - throw new IllegalArgumentException("Unsupported generic type " + generic); - } - } - - @Override - public void setMock(Boolean mock) { - throw new IllegalArgumentException("mock doesn't support on provider side"); - } - - @Override - public void setMock(String mock) { - throw new IllegalArgumentException("mock doesn't support on provider side"); - } - - public List getExportedUrls() { - return urls; - } - - /** - * @deprecated Replace to getProtocols() - */ - @Deprecated - public List getProviders() { - return convertProtocolToProvider(protocols); - } - - /** - * @deprecated Replace to setProtocols() - */ - @Deprecated - public void setProviders(List providers) { - this.protocols = convertProviderToProtocol(providers); - } - - @Parameter(excluded = true) - public String getUniqueServiceName() { - StringBuilder buf = new StringBuilder(); - if (group != null && group.length() > 0) { - buf.append(group).append("/"); - } - buf.append(StringUtils.isNotEmpty(path) ? path : interfaceName); - if (version != null && version.length() > 0) { - buf.append(":").append(version); - } - return buf.toString(); - } - - @Override - @Parameter(excluded = true) - public String getPrefix() { - return Constants.DUBBO + ".service." + interfaceName; - } -} +/* + * 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.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.Version; +import org.apache.dubbo.common.bytecode.Wrapper; +import org.apache.dubbo.common.config.Environment; +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.utils.ClassHelper; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.ConfigUtils; +import org.apache.dubbo.common.utils.NamedThreadFactory; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.config.context.ConfigManager; +import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker; +import org.apache.dubbo.config.support.Parameter; +import org.apache.dubbo.metadata.integration.MetadataReportService; +import org.apache.dubbo.rpc.Exporter; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Protocol; +import org.apache.dubbo.rpc.ProxyFactory; +import org.apache.dubbo.rpc.cluster.ConfiguratorFactory; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.ProviderModel; +import org.apache.dubbo.rpc.service.GenericService; +import org.apache.dubbo.rpc.support.ProtocolUtils; + +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static org.apache.dubbo.common.Constants.LOCALHOST_VALUE; +import static org.apache.dubbo.common.utils.NetUtils.getAvailablePort; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHost; +import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost; +import static org.apache.dubbo.common.utils.NetUtils.isInvalidPort; + +/** + * ServiceConfig + * + * @export + */ +public class ServiceConfig extends AbstractServiceConfig { + + private static final long serialVersionUID = 3033787999037024738L; + + /** + * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios. + * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}. + * For example: + * + *

  • when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample, + * then the protocol is RegistryProtocol
  • + * + *
  • when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then + * the protocol is DubboProtocol
  • + *

    + * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two + * layers, and eventually will get a ProtocolFilterWrapper or ProtocolListenerWrapper + */ + private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + + /** + * A {@link ProxyFactory} implementation that will generate a exported service proxy,the JavassistProxyFactory is its + * default implementation + */ + private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + /** + * A random port cache, the different protocols who has no port specified have different random port + */ + private static final Map RANDOM_PORT_MAP = new HashMap(); + + /** + * A delayed exposure service timer + */ + private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true)); + + /** + * The urls of the services exported + */ + private final List urls = new ArrayList(); + + /** + * The exported services + */ + private final List> exporters = new ArrayList>(); + + /** + * The interface name of the exported service + */ + private String interfaceName; + + /** + * The interface class of the exported service + */ + private Class interfaceClass; + + /** + * The reference of the interface implementation + */ + private T ref; + + /** + * The service name + */ + private String path; + + /** + * The method configuration + */ + private List methods; + + /** + * The provider configuration + */ + private ProviderConfig provider; + + /** + * The providerIds + */ + private String providerIds; + + /** + * Whether the provider has been exported + */ + private transient volatile boolean exported; + + /** + * The flag whether a service has unexported ,if the method unexported is invoked, the value is true + */ + private transient volatile boolean unexported; + + /** + * whether it is a GenericService + */ + private volatile String generic; + + public ServiceConfig() { + } + + public ServiceConfig(Service service) { + appendAnnotation(Service.class, service); + } + + @Deprecated + private static List convertProviderToProtocol(List providers) { + if (CollectionUtils.isEmpty(providers)) { + return null; + } + List protocols = new ArrayList(providers.size()); + for (ProviderConfig provider : providers) { + protocols.add(convertProviderToProtocol(provider)); + } + return protocols; + } + + @Deprecated + private static List convertProtocolToProvider(List protocols) { + if (CollectionUtils.isEmpty(protocols)) { + return null; + } + List providers = new ArrayList(protocols.size()); + for (ProtocolConfig provider : protocols) { + providers.add(convertProtocolToProvider(provider)); + } + return providers; + } + + @Deprecated + private static ProtocolConfig convertProviderToProtocol(ProviderConfig provider) { + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName(provider.getProtocol().getName()); + protocol.setServer(provider.getServer()); + protocol.setClient(provider.getClient()); + protocol.setCodec(provider.getCodec()); + protocol.setHost(provider.getHost()); + protocol.setPort(provider.getPort()); + protocol.setPath(provider.getPath()); + protocol.setPayload(provider.getPayload()); + protocol.setThreads(provider.getThreads()); + protocol.setParameters(provider.getParameters()); + return protocol; + } + + @Deprecated + private static ProviderConfig convertProtocolToProvider(ProtocolConfig protocol) { + ProviderConfig provider = new ProviderConfig(); + provider.setProtocol(protocol); + provider.setServer(protocol.getServer()); + provider.setClient(protocol.getClient()); + provider.setCodec(protocol.getCodec()); + provider.setHost(protocol.getHost()); + provider.setPort(protocol.getPort()); + provider.setPath(protocol.getPath()); + provider.setPayload(protocol.getPayload()); + provider.setThreads(protocol.getThreads()); + provider.setParameters(protocol.getParameters()); + return provider; + } + + private static Integer getRandomPort(String protocol) { + protocol = protocol.toLowerCase(); + return RANDOM_PORT_MAP.getOrDefault(protocol, Integer.MIN_VALUE); + } + + private static void putRandomPort(String protocol, Integer port) { + protocol = protocol.toLowerCase(); + if (!RANDOM_PORT_MAP.containsKey(protocol)) { + RANDOM_PORT_MAP.put(protocol, port); + logger.warn("Use random available port(" + port + ") for protocol " + protocol); + } + } + + public URL toUrl() { + return urls.isEmpty() ? null : urls.iterator().next(); + } + + public List toUrls() { + return urls; + } + + @Parameter(excluded = true) + public boolean isExported() { + return exported; + } + + @Parameter(excluded = true) + public boolean isUnexported() { + return unexported; + } + + public void checkAndUpdateSubConfigs() { + // Use default configs defined explicitly on global configs + completeCompoundConfigs(); + // Config Center should always being started first. + startConfigCenter(); + checkDefault(); + checkApplication(); + checkRegistry(); + checkProtocol(); + this.refresh(); + checkMetadataReport(); + + if (StringUtils.isEmpty(interfaceName)) { + throw new IllegalStateException(" interface not allow null!"); + } + + if (ref instanceof GenericService) { + interfaceClass = GenericService.class; + if (StringUtils.isEmpty(generic)) { + generic = Boolean.TRUE.toString(); + } + } else { + try { + interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() + .getContextClassLoader()); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e.getMessage(), e); + } + checkInterfaceAndMethods(interfaceClass, methods); + checkRef(); + generic = Boolean.FALSE.toString(); + } + if (local != null) { + if ("true".equals(local)) { + local = interfaceName + "Local"; + } + Class localClass; + try { + localClass = ClassHelper.forNameWithThreadContextClassLoader(local); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e.getMessage(), e); + } + if (!interfaceClass.isAssignableFrom(localClass)) { + throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName); + } + } + if (stub != null) { + if ("true".equals(stub)) { + stub = interfaceName + "Stub"; + } + Class stubClass; + try { + stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e.getMessage(), e); + } + if (!interfaceClass.isAssignableFrom(stubClass)) { + throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName); + } + } + checkStubAndLocal(interfaceClass); + checkMock(interfaceClass); + } + + public synchronized void export() { + checkAndUpdateSubConfigs(); + + if (provider != null) { + if (export == null) { + export = provider.getExport(); + } + if (delay == null) { + delay = provider.getDelay(); + } + } + if (export != null && !export) { + return; + } + + if (delay != null && delay > 0) { + delayExportExecutor.schedule(this::doExport, delay, TimeUnit.MILLISECONDS); + } else { + doExport(); + } + } + + protected synchronized void doExport() { + if (unexported) { + throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!"); + } + if (exported) { + return; + } + exported = true; + + if (StringUtils.isEmpty(path)) { + path = interfaceName; + } + ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), ref, interfaceClass); + ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel); + doExportUrls(); + } + + private void checkRef() { + // reference should not be null, and is the implementation of the given interface + if (ref == null) { + throw new IllegalStateException("ref not allow null!"); + } + if (!interfaceClass.isInstance(ref)) { + throw new IllegalStateException("The class " + + ref.getClass().getName() + " unimplemented interface " + + interfaceClass + "!"); + } + } + + public synchronized void unexport() { + if (!exported) { + return; + } + if (unexported) { + return; + } + if (!exporters.isEmpty()) { + for (Exporter exporter : exporters) { + try { + exporter.unexport(); + } catch (Throwable t) { + logger.warn("Unexpected error occured when unexport " + exporter, t); + } + } + exporters.clear(); + } + unexported = true; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void doExportUrls() { + List registryURLs = loadRegistries(true); + for (ProtocolConfig protocolConfig : protocols) { + doExportUrlsFor1Protocol(protocolConfig, registryURLs); + } + } + + private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) { + String name = protocolConfig.getName(); + if (StringUtils.isEmpty(name)) { + name = Constants.DUBBO; + } + + Map map = new HashMap(); + map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE); + appendRuntimeParameters(map); + appendParameters(map, application); + appendParameters(map, module); + appendParameters(map, provider, Constants.DEFAULT_KEY); + appendParameters(map, protocolConfig); + appendParameters(map, this); + if (CollectionUtils.isNotEmpty(methods)) { + for (MethodConfig method : methods) { + appendParameters(map, method, method.getName()); + String retryKey = method.getName() + ".retry"; + if (map.containsKey(retryKey)) { + String retryValue = map.remove(retryKey); + if ("false".equals(retryValue)) { + map.put(method.getName() + ".retries", "0"); + } + } + List arguments = method.getArguments(); + if (CollectionUtils.isNotEmpty(arguments)) { + for (ArgumentConfig argument : arguments) { + // convert argument type + if (argument.getType() != null && argument.getType().length() > 0) { + Method[] methods = interfaceClass.getMethods(); + // visit all methods + if (methods != null && methods.length > 0) { + for (int i = 0; i < methods.length; i++) { + String methodName = methods[i].getName(); + // target the method, and get its signature + if (methodName.equals(method.getName())) { + Class[] argtypes = methods[i].getParameterTypes(); + // one callback in the method + if (argument.getIndex() != -1) { + if (argtypes[argument.getIndex()].getName().equals(argument.getType())) { + appendParameters(map, argument, method.getName() + "." + argument.getIndex()); + } else { + throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType()); + } + } else { + // multiple callbacks in the method + for (int j = 0; j < argtypes.length; j++) { + Class argclazz = argtypes[j]; + if (argclazz.getName().equals(argument.getType())) { + appendParameters(map, argument, method.getName() + "." + j); + if (argument.getIndex() != -1 && argument.getIndex() != j) { + throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType()); + } + } + } + } + } + } + } + } else if (argument.getIndex() != -1) { + appendParameters(map, argument, method.getName() + "." + argument.getIndex()); + } else { + throw new IllegalArgumentException("Argument config must set index or type attribute.eg: or "); + } + + } + } + } // end of methods for + } + + if (ProtocolUtils.isGeneric(generic)) { + map.put(Constants.GENERIC_KEY, generic); + map.put(Constants.METHODS_KEY, Constants.ANY_VALUE); + } else { + String revision = Version.getVersion(interfaceClass, version); + if (revision != null && revision.length() > 0) { + map.put("revision", revision); + } + + String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames(); + if (methods.length == 0) { + logger.warn("No method found in service interface " + interfaceClass.getName()); + map.put(Constants.METHODS_KEY, Constants.ANY_VALUE); + } else { + map.put(Constants.METHODS_KEY, StringUtils.join(new HashSet(Arrays.asList(methods)), ",")); + } + } + if (!ConfigUtils.isEmpty(token)) { + if (ConfigUtils.isDefault(token)) { + map.put(Constants.TOKEN_KEY, UUID.randomUUID().toString()); + } else { + map.put(Constants.TOKEN_KEY, token); + } + } + // export service + String contextPath = protocolConfig.getContextpath(); + if (StringUtils.isEmpty(contextPath) && provider != null) { + contextPath = provider.getContextpath(); + } + + String host = this.findConfigedHosts(protocolConfig, registryURLs, map); + Integer port = this.findConfigedPorts(protocolConfig, name, map); + URL url = new URL(name, host, port, (StringUtils.isEmpty(contextPath) ? "" : contextPath + "/") + path, map); + + if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) + .hasExtension(url.getProtocol())) { + url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) + .getExtension(url.getProtocol()).getConfigurator(url).configure(url); + } + + String scope = url.getParameter(Constants.SCOPE_KEY); + // don't export when none is configured + if (!Constants.SCOPE_NONE.equalsIgnoreCase(scope)) { + + // export to local if the config is not remote (export to remote only when config is remote) + if (!Constants.SCOPE_REMOTE.equalsIgnoreCase(scope)) { + exportLocal(url); + } + // export to remote if the config is not local (export to local only when config is local) + if (!Constants.SCOPE_LOCAL.equalsIgnoreCase(scope)) { + if (logger.isInfoEnabled()) { + logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url); + } + if (CollectionUtils.isNotEmpty(registryURLs)) { + for (URL registryURL : registryURLs) { + url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY)); + URL monitorUrl = loadMonitor(registryURL); + if (monitorUrl != null) { + url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString()); + } + if (logger.isInfoEnabled()) { + logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL); + } + + // For providers, this is used to enable custom proxy to generate invoker + String proxy = url.getParameter(Constants.PROXY_KEY); + if (StringUtils.isNotEmpty(proxy)) { + registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy); + } + + Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString())); + DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); + + Exporter exporter = protocol.export(wrapperInvoker); + exporters.add(exporter); + } + } else { + Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); + DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); + + Exporter exporter = protocol.export(wrapperInvoker); + exporters.add(exporter); + } + /** + * @since 2.7.0 + * ServiceData Store + */ + MetadataReportService metadataReportService = null; + if ((metadataReportService = getMetadataReportService()) != null) { + metadataReportService.publishProvider(url); + } + } + } + this.urls.add(url); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void exportLocal(URL url) { + if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { + URL local = URL.valueOf(url.toFullString()) + .setProtocol(Constants.LOCAL_PROTOCOL) + .setHost(LOCALHOST_VALUE) + .setPort(0); + Exporter exporter = protocol.export( + proxyFactory.getInvoker(ref, (Class) interfaceClass, local)); + exporters.add(exporter); + logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry"); + } + } + + protected Class getServiceClass(T ref) { + return ref.getClass(); + } + + /** + * Register & bind IP address for service provider, can be configured separately. + * Configuration priority: environment variables -> java system properties -> host property in config file -> + * /etc/hosts -> default network address -> first available network address + * + * @param protocolConfig + * @param registryURLs + * @param map + * @return + */ + private String findConfigedHosts(ProtocolConfig protocolConfig, List registryURLs, Map map) { + boolean anyhost = false; + + String hostToBind = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_BIND); + if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) { + throw new IllegalArgumentException("Specified invalid bind ip from property:" + Constants.DUBBO_IP_TO_BIND + ", value:" + hostToBind); + } + + // if bind ip is not found in environment, keep looking up + if (StringUtils.isEmpty(hostToBind)) { + hostToBind = protocolConfig.getHost(); + if (provider != null && StringUtils.isEmpty(hostToBind)) { + hostToBind = provider.getHost(); + } + if (isInvalidLocalHost(hostToBind)) { + anyhost = true; + try { + hostToBind = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + logger.warn(e.getMessage(), e); + } + if (isInvalidLocalHost(hostToBind)) { + if (CollectionUtils.isNotEmpty(registryURLs)) { + for (URL registryURL : registryURLs) { + if (Constants.MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) { + // skip multicast registry since we cannot connect to it via Socket + continue; + } + try (Socket socket = new Socket()) { + SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort()); + socket.connect(addr, 1000); + hostToBind = socket.getLocalAddress().getHostAddress(); + break; + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + } + } + if (isInvalidLocalHost(hostToBind)) { + hostToBind = getLocalHost(); + } + } + } + } + + map.put(Constants.BIND_IP_KEY, hostToBind); + + // registry ip is not used for bind ip by default + String hostToRegistry = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_REGISTRY); + if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) { + throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); + } else if (StringUtils.isEmpty(hostToRegistry)) { + // bind ip is used as registry ip by default + hostToRegistry = hostToBind; + } + + map.put(Constants.ANYHOST_KEY, String.valueOf(anyhost)); + + return hostToRegistry; + } + + /** + * Register port and bind port for the provider, can be configured separately + * Configuration priority: environment variable -> java system properties -> port property in protocol config file + * -> protocol default port + * + * @param protocolConfig + * @param name + * @return + */ + private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map map) { + Integer portToBind = null; + + // parse bind port from environment + String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND); + portToBind = parsePort(port); + + // if there's no bind port found from environment, keep looking up. + if (portToBind == null) { + portToBind = protocolConfig.getPort(); + if (provider != null && (portToBind == null || portToBind == 0)) { + portToBind = provider.getPort(); + } + final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort(); + if (portToBind == null || portToBind == 0) { + portToBind = defaultPort; + } + if (portToBind == null || portToBind <= 0) { + portToBind = getRandomPort(name); + if (portToBind == null || portToBind < 0) { + portToBind = getAvailablePort(defaultPort); + putRandomPort(name, portToBind); + } + } + } + + // save bind port, used as url's key later + map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind)); + + // registry port, not used as bind port by default + String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY); + Integer portToRegistry = parsePort(portToRegistryStr); + if (portToRegistry == null) { + portToRegistry = portToBind; + } + + return portToRegistry; + } + + private Integer parsePort(String configPort) { + Integer port = null; + if (configPort != null && configPort.length() > 0) { + try { + Integer intPort = Integer.parseInt(configPort); + if (isInvalidPort(intPort)) { + throw new IllegalArgumentException("Specified invalid port from env value:" + configPort); + } + port = intPort; + } catch (Exception e) { + throw new IllegalArgumentException("Specified invalid port from env value:" + configPort); + } + } + return port; + } + + private String getValueFromConfig(ProtocolConfig protocolConfig, String key) { + String protocolPrefix = protocolConfig.getName().toUpperCase() + "_"; + String port = ConfigUtils.getSystemProperty(protocolPrefix + key); + if (StringUtils.isEmpty(port)) { + port = ConfigUtils.getSystemProperty(key); + } + return port; + } + + private void completeCompoundConfigs() { + if (provider != null) { + if (application == null) { + setApplication(provider.getApplication()); + } + if (module == null) { + setModule(provider.getModule()); + } + if (registries == null) { + setRegistries(provider.getRegistries()); + } + if (monitor == null) { + setMonitor(provider.getMonitor()); + } + if (protocols == null) { + setProtocols(provider.getProtocols()); + } + if (configCenter == null) { + setConfigCenter(provider.getConfigCenter()); + } + } + if (module != null) { + if (registries == null) { + setRegistries(module.getRegistries()); + } + if (monitor == null) { + setMonitor(module.getMonitor()); + } + } + if (application != null) { + if (registries == null) { + setRegistries(application.getRegistries()); + } + if (monitor == null) { + setMonitor(application.getMonitor()); + } + } + } + + private void checkDefault() { + createProviderIfAbsent(); + } + + private void createProviderIfAbsent() { + if (provider != null) { + return; + } + setProvider ( + ConfigManager.getInstance() + .getDefaultProvider() + .orElseGet(() -> { + ProviderConfig providerConfig = new ProviderConfig(); + providerConfig.refresh(); + return providerConfig; + }) + ); + } + + private void checkProtocol() { + if (CollectionUtils.isEmpty(protocols) && provider != null) { + setProtocols(provider.getProtocols()); + } + convertProtocolIdsToProtocols(); + } + + private void convertProtocolIdsToProtocols() { + if (StringUtils.isEmpty(protocolIds) && CollectionUtils.isEmpty(protocols)) { + List configedProtocols = new ArrayList<>(); + configedProtocols.addAll(getSubProperties(Environment.getInstance() + .getExternalConfigurationMap(), Constants.PROTOCOLS_SUFFIX)); + configedProtocols.addAll(getSubProperties(Environment.getInstance() + .getAppExternalConfigurationMap(), Constants.PROTOCOLS_SUFFIX)); + + protocolIds = String.join(",", configedProtocols); + } + + if (StringUtils.isEmpty(protocolIds)) { + if (CollectionUtils.isEmpty(protocols)) { + setProtocols( + ConfigManager.getInstance().getDefaultProtocols() + .filter(CollectionUtils::isNotEmpty) + .orElseGet(() -> { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.refresh(); + return Arrays.asList(protocolConfig); + }) + ); + } + } else { + String[] arr = Constants.COMMA_SPLIT_PATTERN.split(protocolIds); + List tmpProtocols = CollectionUtils.isNotEmpty(protocols) ? protocols : new ArrayList<>(); + Arrays.stream(arr).forEach(id -> { + if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) { + tmpProtocols.add(ConfigManager.getInstance().getProtocol(id).orElseGet(() -> { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setId(id); + protocolConfig.refresh(); + return protocolConfig; + })); + } + }); + if (tmpProtocols.size() > arr.length) { + throw new IllegalStateException("Too much protocols found, the protocols comply to this service are :" + protocolIds + " but got " + protocols + .size() + " registries!"); + } + setProtocols(tmpProtocols); + } + } + + public Class getInterfaceClass() { + if (interfaceClass != null) { + return interfaceClass; + } + if (ref instanceof GenericService) { + return GenericService.class; + } + try { + if (interfaceName != null && interfaceName.length() > 0) { + this.interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() + .getContextClassLoader()); + } + } catch (ClassNotFoundException t) { + throw new IllegalStateException(t.getMessage(), t); + } + return interfaceClass; + } + + /** + * @param interfaceClass + * @see #setInterface(Class) + * @deprecated + */ + public void setInterfaceClass(Class interfaceClass) { + setInterface(interfaceClass); + } + + public String getInterface() { + return interfaceName; + } + + public void setInterface(Class interfaceClass) { + if (interfaceClass != null && !interfaceClass.isInterface()) { + throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); + } + this.interfaceClass = interfaceClass; + setInterface(interfaceClass == null ? null : interfaceClass.getName()); + } + + public void setInterface(String interfaceName) { + this.interfaceName = interfaceName; + if (StringUtils.isEmpty(id)) { + id = interfaceName; + } + } + + public T getRef() { + return ref; + } + + public void setRef(T ref) { + this.ref = ref; + } + + @Parameter(excluded = true) + public String getPath() { + return path; + } + + public void setPath(String path) { + checkPathName(Constants.PATH_KEY, path); + this.path = path; + } + + public List getMethods() { + return methods; + } + + // ======== Deprecated ======== + + @SuppressWarnings("unchecked") + public void setMethods(List methods) { + this.methods = (List) methods; + } + + public ProviderConfig getProvider() { + return provider; + } + + public void setProvider(ProviderConfig provider) { + ConfigManager.getInstance().addProvider(provider); + this.provider = provider; + } + + @Parameter(excluded = true) + public String getProviderIds() { + return providerIds; + } + + public void setProviderIds(String providerIds) { + this.providerIds = providerIds; + } + + public String getGeneric() { + return generic; + } + + public void setGeneric(String generic) { + if (StringUtils.isEmpty(generic)) { + return; + } + if (ProtocolUtils.isGeneric(generic)) { + this.generic = generic; + } else { + throw new IllegalArgumentException("Unsupported generic type " + generic); + } + } + + @Override + public void setMock(Boolean mock) { + throw new IllegalArgumentException("mock doesn't support on provider side"); + } + + @Override + public void setMock(String mock) { + throw new IllegalArgumentException("mock doesn't support on provider side"); + } + + public List getExportedUrls() { + return urls; + } + + /** + * @deprecated Replace to getProtocols() + */ + @Deprecated + public List getProviders() { + return convertProtocolToProvider(protocols); + } + + /** + * @deprecated Replace to setProtocols() + */ + @Deprecated + public void setProviders(List providers) { + this.protocols = convertProviderToProtocol(providers); + } + + @Parameter(excluded = true) + public String getUniqueServiceName() { + StringBuilder buf = new StringBuilder(); + if (group != null && group.length() > 0) { + buf.append(group).append("/"); + } + buf.append(StringUtils.isNotEmpty(path) ? path : interfaceName); + if (version != null && version.length() > 0) { + buf.append(":").append(version); + } + return buf.toString(); + } + + @Override + @Parameter(excluded = true) + public String getPrefix() { + return Constants.DUBBO + ".service." + interfaceName; + } +} From 01a83e656c6fb5ffe1b569d275a20b3805c61eec Mon Sep 17 00:00:00 2001 From: Huang Yunkun Date: Sat, 9 Feb 2019 22:11:38 +0800 Subject: [PATCH 2/2] fix git diff issue --- .../apache/dubbo/config/ServiceConfig.java | 1998 ++++++++--------- 1 file changed, 999 insertions(+), 999 deletions(-) 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 538a2a49398..51962d6b679 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 @@ -1,999 +1,999 @@ -/* - * 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.Constants; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.Version; -import org.apache.dubbo.common.bytecode.Wrapper; -import org.apache.dubbo.common.config.Environment; -import org.apache.dubbo.common.extension.ExtensionLoader; -import org.apache.dubbo.common.utils.ClassHelper; -import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.common.utils.ConfigUtils; -import org.apache.dubbo.common.utils.NamedThreadFactory; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.config.annotation.Service; -import org.apache.dubbo.config.context.ConfigManager; -import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker; -import org.apache.dubbo.config.support.Parameter; -import org.apache.dubbo.metadata.integration.MetadataReportService; -import org.apache.dubbo.rpc.Exporter; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.Protocol; -import org.apache.dubbo.rpc.ProxyFactory; -import org.apache.dubbo.rpc.cluster.ConfiguratorFactory; -import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.ProviderModel; -import org.apache.dubbo.rpc.service.GenericService; -import org.apache.dubbo.rpc.support.ProtocolUtils; - -import java.lang.reflect.Method; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import static org.apache.dubbo.common.Constants.LOCALHOST_VALUE; -import static org.apache.dubbo.common.utils.NetUtils.getAvailablePort; -import static org.apache.dubbo.common.utils.NetUtils.getLocalHost; -import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost; -import static org.apache.dubbo.common.utils.NetUtils.isInvalidPort; - -/** - * ServiceConfig - * - * @export - */ -public class ServiceConfig extends AbstractServiceConfig { - - private static final long serialVersionUID = 3033787999037024738L; - - /** - * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios. - * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}. - * For example: - * - *

  • when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample, - * then the protocol is RegistryProtocol
  • - * - *
  • when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then - * the protocol is DubboProtocol
  • - *

    - * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two - * layers, and eventually will get a ProtocolFilterWrapper or ProtocolListenerWrapper - */ - private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - - /** - * A {@link ProxyFactory} implementation that will generate a exported service proxy,the JavassistProxyFactory is its - * default implementation - */ - private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); - - /** - * A random port cache, the different protocols who has no port specified have different random port - */ - private static final Map RANDOM_PORT_MAP = new HashMap(); - - /** - * A delayed exposure service timer - */ - private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true)); - - /** - * The urls of the services exported - */ - private final List urls = new ArrayList(); - - /** - * The exported services - */ - private final List> exporters = new ArrayList>(); - - /** - * The interface name of the exported service - */ - private String interfaceName; - - /** - * The interface class of the exported service - */ - private Class interfaceClass; - - /** - * The reference of the interface implementation - */ - private T ref; - - /** - * The service name - */ - private String path; - - /** - * The method configuration - */ - private List methods; - - /** - * The provider configuration - */ - private ProviderConfig provider; - - /** - * The providerIds - */ - private String providerIds; - - /** - * Whether the provider has been exported - */ - private transient volatile boolean exported; - - /** - * The flag whether a service has unexported ,if the method unexported is invoked, the value is true - */ - private transient volatile boolean unexported; - - /** - * whether it is a GenericService - */ - private volatile String generic; - - public ServiceConfig() { - } - - public ServiceConfig(Service service) { - appendAnnotation(Service.class, service); - } - - @Deprecated - private static List convertProviderToProtocol(List providers) { - if (CollectionUtils.isEmpty(providers)) { - return null; - } - List protocols = new ArrayList(providers.size()); - for (ProviderConfig provider : providers) { - protocols.add(convertProviderToProtocol(provider)); - } - return protocols; - } - - @Deprecated - private static List convertProtocolToProvider(List protocols) { - if (CollectionUtils.isEmpty(protocols)) { - return null; - } - List providers = new ArrayList(protocols.size()); - for (ProtocolConfig provider : protocols) { - providers.add(convertProtocolToProvider(provider)); - } - return providers; - } - - @Deprecated - private static ProtocolConfig convertProviderToProtocol(ProviderConfig provider) { - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName(provider.getProtocol().getName()); - protocol.setServer(provider.getServer()); - protocol.setClient(provider.getClient()); - protocol.setCodec(provider.getCodec()); - protocol.setHost(provider.getHost()); - protocol.setPort(provider.getPort()); - protocol.setPath(provider.getPath()); - protocol.setPayload(provider.getPayload()); - protocol.setThreads(provider.getThreads()); - protocol.setParameters(provider.getParameters()); - return protocol; - } - - @Deprecated - private static ProviderConfig convertProtocolToProvider(ProtocolConfig protocol) { - ProviderConfig provider = new ProviderConfig(); - provider.setProtocol(protocol); - provider.setServer(protocol.getServer()); - provider.setClient(protocol.getClient()); - provider.setCodec(protocol.getCodec()); - provider.setHost(protocol.getHost()); - provider.setPort(protocol.getPort()); - provider.setPath(protocol.getPath()); - provider.setPayload(protocol.getPayload()); - provider.setThreads(protocol.getThreads()); - provider.setParameters(protocol.getParameters()); - return provider; - } - - private static Integer getRandomPort(String protocol) { - protocol = protocol.toLowerCase(); - return RANDOM_PORT_MAP.getOrDefault(protocol, Integer.MIN_VALUE); - } - - private static void putRandomPort(String protocol, Integer port) { - protocol = protocol.toLowerCase(); - if (!RANDOM_PORT_MAP.containsKey(protocol)) { - RANDOM_PORT_MAP.put(protocol, port); - logger.warn("Use random available port(" + port + ") for protocol " + protocol); - } - } - - public URL toUrl() { - return urls.isEmpty() ? null : urls.iterator().next(); - } - - public List toUrls() { - return urls; - } - - @Parameter(excluded = true) - public boolean isExported() { - return exported; - } - - @Parameter(excluded = true) - public boolean isUnexported() { - return unexported; - } - - public void checkAndUpdateSubConfigs() { - // Use default configs defined explicitly on global configs - completeCompoundConfigs(); - // Config Center should always being started first. - startConfigCenter(); - checkDefault(); - checkApplication(); - checkRegistry(); - checkProtocol(); - this.refresh(); - checkMetadataReport(); - - if (StringUtils.isEmpty(interfaceName)) { - throw new IllegalStateException(" interface not allow null!"); - } - - if (ref instanceof GenericService) { - interfaceClass = GenericService.class; - if (StringUtils.isEmpty(generic)) { - generic = Boolean.TRUE.toString(); - } - } else { - try { - interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() - .getContextClassLoader()); - } catch (ClassNotFoundException e) { - throw new IllegalStateException(e.getMessage(), e); - } - checkInterfaceAndMethods(interfaceClass, methods); - checkRef(); - generic = Boolean.FALSE.toString(); - } - if (local != null) { - if ("true".equals(local)) { - local = interfaceName + "Local"; - } - Class localClass; - try { - localClass = ClassHelper.forNameWithThreadContextClassLoader(local); - } catch (ClassNotFoundException e) { - throw new IllegalStateException(e.getMessage(), e); - } - if (!interfaceClass.isAssignableFrom(localClass)) { - throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName); - } - } - if (stub != null) { - if ("true".equals(stub)) { - stub = interfaceName + "Stub"; - } - Class stubClass; - try { - stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub); - } catch (ClassNotFoundException e) { - throw new IllegalStateException(e.getMessage(), e); - } - if (!interfaceClass.isAssignableFrom(stubClass)) { - throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName); - } - } - checkStubAndLocal(interfaceClass); - checkMock(interfaceClass); - } - - public synchronized void export() { - checkAndUpdateSubConfigs(); - - if (provider != null) { - if (export == null) { - export = provider.getExport(); - } - if (delay == null) { - delay = provider.getDelay(); - } - } - if (export != null && !export) { - return; - } - - if (delay != null && delay > 0) { - delayExportExecutor.schedule(this::doExport, delay, TimeUnit.MILLISECONDS); - } else { - doExport(); - } - } - - protected synchronized void doExport() { - if (unexported) { - throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!"); - } - if (exported) { - return; - } - exported = true; - - if (StringUtils.isEmpty(path)) { - path = interfaceName; - } - ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), ref, interfaceClass); - ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel); - doExportUrls(); - } - - private void checkRef() { - // reference should not be null, and is the implementation of the given interface - if (ref == null) { - throw new IllegalStateException("ref not allow null!"); - } - if (!interfaceClass.isInstance(ref)) { - throw new IllegalStateException("The class " - + ref.getClass().getName() + " unimplemented interface " - + interfaceClass + "!"); - } - } - - public synchronized void unexport() { - if (!exported) { - return; - } - if (unexported) { - return; - } - if (!exporters.isEmpty()) { - for (Exporter exporter : exporters) { - try { - exporter.unexport(); - } catch (Throwable t) { - logger.warn("Unexpected error occured when unexport " + exporter, t); - } - } - exporters.clear(); - } - unexported = true; - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private void doExportUrls() { - List registryURLs = loadRegistries(true); - for (ProtocolConfig protocolConfig : protocols) { - doExportUrlsFor1Protocol(protocolConfig, registryURLs); - } - } - - private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) { - String name = protocolConfig.getName(); - if (StringUtils.isEmpty(name)) { - name = Constants.DUBBO; - } - - Map map = new HashMap(); - map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE); - appendRuntimeParameters(map); - appendParameters(map, application); - appendParameters(map, module); - appendParameters(map, provider, Constants.DEFAULT_KEY); - appendParameters(map, protocolConfig); - appendParameters(map, this); - if (CollectionUtils.isNotEmpty(methods)) { - for (MethodConfig method : methods) { - appendParameters(map, method, method.getName()); - String retryKey = method.getName() + ".retry"; - if (map.containsKey(retryKey)) { - String retryValue = map.remove(retryKey); - if ("false".equals(retryValue)) { - map.put(method.getName() + ".retries", "0"); - } - } - List arguments = method.getArguments(); - if (CollectionUtils.isNotEmpty(arguments)) { - for (ArgumentConfig argument : arguments) { - // convert argument type - if (argument.getType() != null && argument.getType().length() > 0) { - Method[] methods = interfaceClass.getMethods(); - // visit all methods - if (methods != null && methods.length > 0) { - for (int i = 0; i < methods.length; i++) { - String methodName = methods[i].getName(); - // target the method, and get its signature - if (methodName.equals(method.getName())) { - Class[] argtypes = methods[i].getParameterTypes(); - // one callback in the method - if (argument.getIndex() != -1) { - if (argtypes[argument.getIndex()].getName().equals(argument.getType())) { - appendParameters(map, argument, method.getName() + "." + argument.getIndex()); - } else { - throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType()); - } - } else { - // multiple callbacks in the method - for (int j = 0; j < argtypes.length; j++) { - Class argclazz = argtypes[j]; - if (argclazz.getName().equals(argument.getType())) { - appendParameters(map, argument, method.getName() + "." + j); - if (argument.getIndex() != -1 && argument.getIndex() != j) { - throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType()); - } - } - } - } - } - } - } - } else if (argument.getIndex() != -1) { - appendParameters(map, argument, method.getName() + "." + argument.getIndex()); - } else { - throw new IllegalArgumentException("Argument config must set index or type attribute.eg: or "); - } - - } - } - } // end of methods for - } - - if (ProtocolUtils.isGeneric(generic)) { - map.put(Constants.GENERIC_KEY, generic); - map.put(Constants.METHODS_KEY, Constants.ANY_VALUE); - } else { - String revision = Version.getVersion(interfaceClass, version); - if (revision != null && revision.length() > 0) { - map.put("revision", revision); - } - - String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames(); - if (methods.length == 0) { - logger.warn("No method found in service interface " + interfaceClass.getName()); - map.put(Constants.METHODS_KEY, Constants.ANY_VALUE); - } else { - map.put(Constants.METHODS_KEY, StringUtils.join(new HashSet(Arrays.asList(methods)), ",")); - } - } - if (!ConfigUtils.isEmpty(token)) { - if (ConfigUtils.isDefault(token)) { - map.put(Constants.TOKEN_KEY, UUID.randomUUID().toString()); - } else { - map.put(Constants.TOKEN_KEY, token); - } - } - // export service - String contextPath = protocolConfig.getContextpath(); - if (StringUtils.isEmpty(contextPath) && provider != null) { - contextPath = provider.getContextpath(); - } - - String host = this.findConfigedHosts(protocolConfig, registryURLs, map); - Integer port = this.findConfigedPorts(protocolConfig, name, map); - URL url = new URL(name, host, port, (StringUtils.isEmpty(contextPath) ? "" : contextPath + "/") + path, map); - - if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) - .hasExtension(url.getProtocol())) { - url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) - .getExtension(url.getProtocol()).getConfigurator(url).configure(url); - } - - String scope = url.getParameter(Constants.SCOPE_KEY); - // don't export when none is configured - if (!Constants.SCOPE_NONE.equalsIgnoreCase(scope)) { - - // export to local if the config is not remote (export to remote only when config is remote) - if (!Constants.SCOPE_REMOTE.equalsIgnoreCase(scope)) { - exportLocal(url); - } - // export to remote if the config is not local (export to local only when config is local) - if (!Constants.SCOPE_LOCAL.equalsIgnoreCase(scope)) { - if (logger.isInfoEnabled()) { - logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url); - } - if (CollectionUtils.isNotEmpty(registryURLs)) { - for (URL registryURL : registryURLs) { - url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY)); - URL monitorUrl = loadMonitor(registryURL); - if (monitorUrl != null) { - url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString()); - } - if (logger.isInfoEnabled()) { - logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL); - } - - // For providers, this is used to enable custom proxy to generate invoker - String proxy = url.getParameter(Constants.PROXY_KEY); - if (StringUtils.isNotEmpty(proxy)) { - registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy); - } - - Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString())); - DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); - - Exporter exporter = protocol.export(wrapperInvoker); - exporters.add(exporter); - } - } else { - Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); - DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); - - Exporter exporter = protocol.export(wrapperInvoker); - exporters.add(exporter); - } - /** - * @since 2.7.0 - * ServiceData Store - */ - MetadataReportService metadataReportService = null; - if ((metadataReportService = getMetadataReportService()) != null) { - metadataReportService.publishProvider(url); - } - } - } - this.urls.add(url); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private void exportLocal(URL url) { - if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { - URL local = URL.valueOf(url.toFullString()) - .setProtocol(Constants.LOCAL_PROTOCOL) - .setHost(LOCALHOST_VALUE) - .setPort(0); - Exporter exporter = protocol.export( - proxyFactory.getInvoker(ref, (Class) interfaceClass, local)); - exporters.add(exporter); - logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry"); - } - } - - protected Class getServiceClass(T ref) { - return ref.getClass(); - } - - /** - * Register & bind IP address for service provider, can be configured separately. - * Configuration priority: environment variables -> java system properties -> host property in config file -> - * /etc/hosts -> default network address -> first available network address - * - * @param protocolConfig - * @param registryURLs - * @param map - * @return - */ - private String findConfigedHosts(ProtocolConfig protocolConfig, List registryURLs, Map map) { - boolean anyhost = false; - - String hostToBind = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_BIND); - if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) { - throw new IllegalArgumentException("Specified invalid bind ip from property:" + Constants.DUBBO_IP_TO_BIND + ", value:" + hostToBind); - } - - // if bind ip is not found in environment, keep looking up - if (StringUtils.isEmpty(hostToBind)) { - hostToBind = protocolConfig.getHost(); - if (provider != null && StringUtils.isEmpty(hostToBind)) { - hostToBind = provider.getHost(); - } - if (isInvalidLocalHost(hostToBind)) { - anyhost = true; - try { - hostToBind = InetAddress.getLocalHost().getHostAddress(); - } catch (UnknownHostException e) { - logger.warn(e.getMessage(), e); - } - if (isInvalidLocalHost(hostToBind)) { - if (CollectionUtils.isNotEmpty(registryURLs)) { - for (URL registryURL : registryURLs) { - if (Constants.MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) { - // skip multicast registry since we cannot connect to it via Socket - continue; - } - try (Socket socket = new Socket()) { - SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort()); - socket.connect(addr, 1000); - hostToBind = socket.getLocalAddress().getHostAddress(); - break; - } catch (Exception e) { - logger.warn(e.getMessage(), e); - } - } - } - if (isInvalidLocalHost(hostToBind)) { - hostToBind = getLocalHost(); - } - } - } - } - - map.put(Constants.BIND_IP_KEY, hostToBind); - - // registry ip is not used for bind ip by default - String hostToRegistry = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_REGISTRY); - if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) { - throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); - } else if (StringUtils.isEmpty(hostToRegistry)) { - // bind ip is used as registry ip by default - hostToRegistry = hostToBind; - } - - map.put(Constants.ANYHOST_KEY, String.valueOf(anyhost)); - - return hostToRegistry; - } - - /** - * Register port and bind port for the provider, can be configured separately - * Configuration priority: environment variable -> java system properties -> port property in protocol config file - * -> protocol default port - * - * @param protocolConfig - * @param name - * @return - */ - private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map map) { - Integer portToBind = null; - - // parse bind port from environment - String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND); - portToBind = parsePort(port); - - // if there's no bind port found from environment, keep looking up. - if (portToBind == null) { - portToBind = protocolConfig.getPort(); - if (provider != null && (portToBind == null || portToBind == 0)) { - portToBind = provider.getPort(); - } - final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort(); - if (portToBind == null || portToBind == 0) { - portToBind = defaultPort; - } - if (portToBind == null || portToBind <= 0) { - portToBind = getRandomPort(name); - if (portToBind == null || portToBind < 0) { - portToBind = getAvailablePort(defaultPort); - putRandomPort(name, portToBind); - } - } - } - - // save bind port, used as url's key later - map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind)); - - // registry port, not used as bind port by default - String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY); - Integer portToRegistry = parsePort(portToRegistryStr); - if (portToRegistry == null) { - portToRegistry = portToBind; - } - - return portToRegistry; - } - - private Integer parsePort(String configPort) { - Integer port = null; - if (configPort != null && configPort.length() > 0) { - try { - Integer intPort = Integer.parseInt(configPort); - if (isInvalidPort(intPort)) { - throw new IllegalArgumentException("Specified invalid port from env value:" + configPort); - } - port = intPort; - } catch (Exception e) { - throw new IllegalArgumentException("Specified invalid port from env value:" + configPort); - } - } - return port; - } - - private String getValueFromConfig(ProtocolConfig protocolConfig, String key) { - String protocolPrefix = protocolConfig.getName().toUpperCase() + "_"; - String port = ConfigUtils.getSystemProperty(protocolPrefix + key); - if (StringUtils.isEmpty(port)) { - port = ConfigUtils.getSystemProperty(key); - } - return port; - } - - private void completeCompoundConfigs() { - if (provider != null) { - if (application == null) { - setApplication(provider.getApplication()); - } - if (module == null) { - setModule(provider.getModule()); - } - if (registries == null) { - setRegistries(provider.getRegistries()); - } - if (monitor == null) { - setMonitor(provider.getMonitor()); - } - if (protocols == null) { - setProtocols(provider.getProtocols()); - } - if (configCenter == null) { - setConfigCenter(provider.getConfigCenter()); - } - } - if (module != null) { - if (registries == null) { - setRegistries(module.getRegistries()); - } - if (monitor == null) { - setMonitor(module.getMonitor()); - } - } - if (application != null) { - if (registries == null) { - setRegistries(application.getRegistries()); - } - if (monitor == null) { - setMonitor(application.getMonitor()); - } - } - } - - private void checkDefault() { - createProviderIfAbsent(); - } - - private void createProviderIfAbsent() { - if (provider != null) { - return; - } - setProvider ( - ConfigManager.getInstance() - .getDefaultProvider() - .orElseGet(() -> { - ProviderConfig providerConfig = new ProviderConfig(); - providerConfig.refresh(); - return providerConfig; - }) - ); - } - - private void checkProtocol() { - if (CollectionUtils.isEmpty(protocols) && provider != null) { - setProtocols(provider.getProtocols()); - } - convertProtocolIdsToProtocols(); - } - - private void convertProtocolIdsToProtocols() { - if (StringUtils.isEmpty(protocolIds) && CollectionUtils.isEmpty(protocols)) { - List configedProtocols = new ArrayList<>(); - configedProtocols.addAll(getSubProperties(Environment.getInstance() - .getExternalConfigurationMap(), Constants.PROTOCOLS_SUFFIX)); - configedProtocols.addAll(getSubProperties(Environment.getInstance() - .getAppExternalConfigurationMap(), Constants.PROTOCOLS_SUFFIX)); - - protocolIds = String.join(",", configedProtocols); - } - - if (StringUtils.isEmpty(protocolIds)) { - if (CollectionUtils.isEmpty(protocols)) { - setProtocols( - ConfigManager.getInstance().getDefaultProtocols() - .filter(CollectionUtils::isNotEmpty) - .orElseGet(() -> { - ProtocolConfig protocolConfig = new ProtocolConfig(); - protocolConfig.refresh(); - return Arrays.asList(protocolConfig); - }) - ); - } - } else { - String[] arr = Constants.COMMA_SPLIT_PATTERN.split(protocolIds); - List tmpProtocols = CollectionUtils.isNotEmpty(protocols) ? protocols : new ArrayList<>(); - Arrays.stream(arr).forEach(id -> { - if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) { - tmpProtocols.add(ConfigManager.getInstance().getProtocol(id).orElseGet(() -> { - ProtocolConfig protocolConfig = new ProtocolConfig(); - protocolConfig.setId(id); - protocolConfig.refresh(); - return protocolConfig; - })); - } - }); - if (tmpProtocols.size() > arr.length) { - throw new IllegalStateException("Too much protocols found, the protocols comply to this service are :" + protocolIds + " but got " + protocols - .size() + " registries!"); - } - setProtocols(tmpProtocols); - } - } - - public Class getInterfaceClass() { - if (interfaceClass != null) { - return interfaceClass; - } - if (ref instanceof GenericService) { - return GenericService.class; - } - try { - if (interfaceName != null && interfaceName.length() > 0) { - this.interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() - .getContextClassLoader()); - } - } catch (ClassNotFoundException t) { - throw new IllegalStateException(t.getMessage(), t); - } - return interfaceClass; - } - - /** - * @param interfaceClass - * @see #setInterface(Class) - * @deprecated - */ - public void setInterfaceClass(Class interfaceClass) { - setInterface(interfaceClass); - } - - public String getInterface() { - return interfaceName; - } - - public void setInterface(Class interfaceClass) { - if (interfaceClass != null && !interfaceClass.isInterface()) { - throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); - } - this.interfaceClass = interfaceClass; - setInterface(interfaceClass == null ? null : interfaceClass.getName()); - } - - public void setInterface(String interfaceName) { - this.interfaceName = interfaceName; - if (StringUtils.isEmpty(id)) { - id = interfaceName; - } - } - - public T getRef() { - return ref; - } - - public void setRef(T ref) { - this.ref = ref; - } - - @Parameter(excluded = true) - public String getPath() { - return path; - } - - public void setPath(String path) { - checkPathName(Constants.PATH_KEY, path); - this.path = path; - } - - public List getMethods() { - return methods; - } - - // ======== Deprecated ======== - - @SuppressWarnings("unchecked") - public void setMethods(List methods) { - this.methods = (List) methods; - } - - public ProviderConfig getProvider() { - return provider; - } - - public void setProvider(ProviderConfig provider) { - ConfigManager.getInstance().addProvider(provider); - this.provider = provider; - } - - @Parameter(excluded = true) - public String getProviderIds() { - return providerIds; - } - - public void setProviderIds(String providerIds) { - this.providerIds = providerIds; - } - - public String getGeneric() { - return generic; - } - - public void setGeneric(String generic) { - if (StringUtils.isEmpty(generic)) { - return; - } - if (ProtocolUtils.isGeneric(generic)) { - this.generic = generic; - } else { - throw new IllegalArgumentException("Unsupported generic type " + generic); - } - } - - @Override - public void setMock(Boolean mock) { - throw new IllegalArgumentException("mock doesn't support on provider side"); - } - - @Override - public void setMock(String mock) { - throw new IllegalArgumentException("mock doesn't support on provider side"); - } - - public List getExportedUrls() { - return urls; - } - - /** - * @deprecated Replace to getProtocols() - */ - @Deprecated - public List getProviders() { - return convertProtocolToProvider(protocols); - } - - /** - * @deprecated Replace to setProtocols() - */ - @Deprecated - public void setProviders(List providers) { - this.protocols = convertProviderToProtocol(providers); - } - - @Parameter(excluded = true) - public String getUniqueServiceName() { - StringBuilder buf = new StringBuilder(); - if (group != null && group.length() > 0) { - buf.append(group).append("/"); - } - buf.append(StringUtils.isNotEmpty(path) ? path : interfaceName); - if (version != null && version.length() > 0) { - buf.append(":").append(version); - } - return buf.toString(); - } - - @Override - @Parameter(excluded = true) - public String getPrefix() { - return Constants.DUBBO + ".service." + interfaceName; - } -} +/* + * 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.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.Version; +import org.apache.dubbo.common.bytecode.Wrapper; +import org.apache.dubbo.common.config.Environment; +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.utils.ClassHelper; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.ConfigUtils; +import org.apache.dubbo.common.utils.NamedThreadFactory; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.config.context.ConfigManager; +import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker; +import org.apache.dubbo.config.support.Parameter; +import org.apache.dubbo.metadata.integration.MetadataReportService; +import org.apache.dubbo.rpc.Exporter; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Protocol; +import org.apache.dubbo.rpc.ProxyFactory; +import org.apache.dubbo.rpc.cluster.ConfiguratorFactory; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.ProviderModel; +import org.apache.dubbo.rpc.service.GenericService; +import org.apache.dubbo.rpc.support.ProtocolUtils; + +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static org.apache.dubbo.common.Constants.LOCALHOST_VALUE; +import static org.apache.dubbo.common.utils.NetUtils.getAvailablePort; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHost; +import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost; +import static org.apache.dubbo.common.utils.NetUtils.isInvalidPort; + +/** + * ServiceConfig + * + * @export + */ +public class ServiceConfig extends AbstractServiceConfig { + + private static final long serialVersionUID = 3033787999037024738L; + + /** + * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios. + * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}. + * For example: + * + *

  • when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample, + * then the protocol is RegistryProtocol
  • + * + *
  • when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then + * the protocol is DubboProtocol
  • + *

    + * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two + * layers, and eventually will get a ProtocolFilterWrapper or ProtocolListenerWrapper + */ + private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + + /** + * A {@link ProxyFactory} implementation that will generate a exported service proxy,the JavassistProxyFactory is its + * default implementation + */ + private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + + /** + * A random port cache, the different protocols who has no port specified have different random port + */ + private static final Map RANDOM_PORT_MAP = new HashMap(); + + /** + * A delayed exposure service timer + */ + private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true)); + + /** + * The urls of the services exported + */ + private final List urls = new ArrayList(); + + /** + * The exported services + */ + private final List> exporters = new ArrayList>(); + + /** + * The interface name of the exported service + */ + private String interfaceName; + + /** + * The interface class of the exported service + */ + private Class interfaceClass; + + /** + * The reference of the interface implementation + */ + private T ref; + + /** + * The service name + */ + private String path; + + /** + * The method configuration + */ + private List methods; + + /** + * The provider configuration + */ + private ProviderConfig provider; + + /** + * The providerIds + */ + private String providerIds; + + /** + * Whether the provider has been exported + */ + private transient volatile boolean exported; + + /** + * The flag whether a service has unexported ,if the method unexported is invoked, the value is true + */ + private transient volatile boolean unexported; + + /** + * whether it is a GenericService + */ + private volatile String generic; + + public ServiceConfig() { + } + + public ServiceConfig(Service service) { + appendAnnotation(Service.class, service); + } + + @Deprecated + private static List convertProviderToProtocol(List providers) { + if (CollectionUtils.isEmpty(providers)) { + return null; + } + List protocols = new ArrayList(providers.size()); + for (ProviderConfig provider : providers) { + protocols.add(convertProviderToProtocol(provider)); + } + return protocols; + } + + @Deprecated + private static List convertProtocolToProvider(List protocols) { + if (CollectionUtils.isEmpty(protocols)) { + return null; + } + List providers = new ArrayList(protocols.size()); + for (ProtocolConfig provider : protocols) { + providers.add(convertProtocolToProvider(provider)); + } + return providers; + } + + @Deprecated + private static ProtocolConfig convertProviderToProtocol(ProviderConfig provider) { + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName(provider.getProtocol().getName()); + protocol.setServer(provider.getServer()); + protocol.setClient(provider.getClient()); + protocol.setCodec(provider.getCodec()); + protocol.setHost(provider.getHost()); + protocol.setPort(provider.getPort()); + protocol.setPath(provider.getPath()); + protocol.setPayload(provider.getPayload()); + protocol.setThreads(provider.getThreads()); + protocol.setParameters(provider.getParameters()); + return protocol; + } + + @Deprecated + private static ProviderConfig convertProtocolToProvider(ProtocolConfig protocol) { + ProviderConfig provider = new ProviderConfig(); + provider.setProtocol(protocol); + provider.setServer(protocol.getServer()); + provider.setClient(protocol.getClient()); + provider.setCodec(protocol.getCodec()); + provider.setHost(protocol.getHost()); + provider.setPort(protocol.getPort()); + provider.setPath(protocol.getPath()); + provider.setPayload(protocol.getPayload()); + provider.setThreads(protocol.getThreads()); + provider.setParameters(protocol.getParameters()); + return provider; + } + + private static Integer getRandomPort(String protocol) { + protocol = protocol.toLowerCase(); + return RANDOM_PORT_MAP.getOrDefault(protocol, Integer.MIN_VALUE); + } + + private static void putRandomPort(String protocol, Integer port) { + protocol = protocol.toLowerCase(); + if (!RANDOM_PORT_MAP.containsKey(protocol)) { + RANDOM_PORT_MAP.put(protocol, port); + logger.warn("Use random available port(" + port + ") for protocol " + protocol); + } + } + + public URL toUrl() { + return urls.isEmpty() ? null : urls.iterator().next(); + } + + public List toUrls() { + return urls; + } + + @Parameter(excluded = true) + public boolean isExported() { + return exported; + } + + @Parameter(excluded = true) + public boolean isUnexported() { + return unexported; + } + + public void checkAndUpdateSubConfigs() { + // Use default configs defined explicitly on global configs + completeCompoundConfigs(); + // Config Center should always being started first. + startConfigCenter(); + checkDefault(); + checkApplication(); + checkRegistry(); + checkProtocol(); + this.refresh(); + checkMetadataReport(); + + if (StringUtils.isEmpty(interfaceName)) { + throw new IllegalStateException(" interface not allow null!"); + } + + if (ref instanceof GenericService) { + interfaceClass = GenericService.class; + if (StringUtils.isEmpty(generic)) { + generic = Boolean.TRUE.toString(); + } + } else { + try { + interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() + .getContextClassLoader()); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e.getMessage(), e); + } + checkInterfaceAndMethods(interfaceClass, methods); + checkRef(); + generic = Boolean.FALSE.toString(); + } + if (local != null) { + if ("true".equals(local)) { + local = interfaceName + "Local"; + } + Class localClass; + try { + localClass = ClassHelper.forNameWithThreadContextClassLoader(local); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e.getMessage(), e); + } + if (!interfaceClass.isAssignableFrom(localClass)) { + throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName); + } + } + if (stub != null) { + if ("true".equals(stub)) { + stub = interfaceName + "Stub"; + } + Class stubClass; + try { + stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e.getMessage(), e); + } + if (!interfaceClass.isAssignableFrom(stubClass)) { + throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName); + } + } + checkStubAndLocal(interfaceClass); + checkMock(interfaceClass); + } + + public synchronized void export() { + checkAndUpdateSubConfigs(); + + if (provider != null) { + if (export == null) { + export = provider.getExport(); + } + if (delay == null) { + delay = provider.getDelay(); + } + } + if (export != null && !export) { + return; + } + + if (delay != null && delay > 0) { + delayExportExecutor.schedule(this::doExport, delay, TimeUnit.MILLISECONDS); + } else { + doExport(); + } + } + + protected synchronized void doExport() { + if (unexported) { + throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!"); + } + if (exported) { + return; + } + exported = true; + + if (StringUtils.isEmpty(path)) { + path = interfaceName; + } + ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), ref, interfaceClass); + ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel); + doExportUrls(); + } + + private void checkRef() { + // reference should not be null, and is the implementation of the given interface + if (ref == null) { + throw new IllegalStateException("ref not allow null!"); + } + if (!interfaceClass.isInstance(ref)) { + throw new IllegalStateException("The class " + + ref.getClass().getName() + " unimplemented interface " + + interfaceClass + "!"); + } + } + + public synchronized void unexport() { + if (!exported) { + return; + } + if (unexported) { + return; + } + if (!exporters.isEmpty()) { + for (Exporter exporter : exporters) { + try { + exporter.unexport(); + } catch (Throwable t) { + logger.warn("Unexpected error occured when unexport " + exporter, t); + } + } + exporters.clear(); + } + unexported = true; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void doExportUrls() { + List registryURLs = loadRegistries(true); + for (ProtocolConfig protocolConfig : protocols) { + doExportUrlsFor1Protocol(protocolConfig, registryURLs); + } + } + + private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) { + String name = protocolConfig.getName(); + if (StringUtils.isEmpty(name)) { + name = Constants.DUBBO; + } + + Map map = new HashMap(); + map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE); + appendRuntimeParameters(map); + appendParameters(map, application); + appendParameters(map, module); + appendParameters(map, provider, Constants.DEFAULT_KEY); + appendParameters(map, protocolConfig); + appendParameters(map, this); + if (CollectionUtils.isNotEmpty(methods)) { + for (MethodConfig method : methods) { + appendParameters(map, method, method.getName()); + String retryKey = method.getName() + ".retry"; + if (map.containsKey(retryKey)) { + String retryValue = map.remove(retryKey); + if ("false".equals(retryValue)) { + map.put(method.getName() + ".retries", "0"); + } + } + List arguments = method.getArguments(); + if (CollectionUtils.isNotEmpty(arguments)) { + for (ArgumentConfig argument : arguments) { + // convert argument type + if (argument.getType() != null && argument.getType().length() > 0) { + Method[] methods = interfaceClass.getMethods(); + // visit all methods + if (methods != null && methods.length > 0) { + for (int i = 0; i < methods.length; i++) { + String methodName = methods[i].getName(); + // target the method, and get its signature + if (methodName.equals(method.getName())) { + Class[] argtypes = methods[i].getParameterTypes(); + // one callback in the method + if (argument.getIndex() != -1) { + if (argtypes[argument.getIndex()].getName().equals(argument.getType())) { + appendParameters(map, argument, method.getName() + "." + argument.getIndex()); + } else { + throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType()); + } + } else { + // multiple callbacks in the method + for (int j = 0; j < argtypes.length; j++) { + Class argclazz = argtypes[j]; + if (argclazz.getName().equals(argument.getType())) { + appendParameters(map, argument, method.getName() + "." + j); + if (argument.getIndex() != -1 && argument.getIndex() != j) { + throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType()); + } + } + } + } + } + } + } + } else if (argument.getIndex() != -1) { + appendParameters(map, argument, method.getName() + "." + argument.getIndex()); + } else { + throw new IllegalArgumentException("Argument config must set index or type attribute.eg: or "); + } + + } + } + } // end of methods for + } + + if (ProtocolUtils.isGeneric(generic)) { + map.put(Constants.GENERIC_KEY, generic); + map.put(Constants.METHODS_KEY, Constants.ANY_VALUE); + } else { + String revision = Version.getVersion(interfaceClass, version); + if (revision != null && revision.length() > 0) { + map.put("revision", revision); + } + + String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames(); + if (methods.length == 0) { + logger.warn("No method found in service interface " + interfaceClass.getName()); + map.put(Constants.METHODS_KEY, Constants.ANY_VALUE); + } else { + map.put(Constants.METHODS_KEY, StringUtils.join(new HashSet(Arrays.asList(methods)), ",")); + } + } + if (!ConfigUtils.isEmpty(token)) { + if (ConfigUtils.isDefault(token)) { + map.put(Constants.TOKEN_KEY, UUID.randomUUID().toString()); + } else { + map.put(Constants.TOKEN_KEY, token); + } + } + // export service + String contextPath = protocolConfig.getContextpath(); + if (StringUtils.isEmpty(contextPath) && provider != null) { + contextPath = provider.getContextpath(); + } + + String host = this.findConfigedHosts(protocolConfig, registryURLs, map); + Integer port = this.findConfigedPorts(protocolConfig, name, map); + URL url = new URL(name, host, port, (StringUtils.isEmpty(contextPath) ? "" : contextPath + "/") + path, map); + + if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) + .hasExtension(url.getProtocol())) { + url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) + .getExtension(url.getProtocol()).getConfigurator(url).configure(url); + } + + String scope = url.getParameter(Constants.SCOPE_KEY); + // don't export when none is configured + if (!Constants.SCOPE_NONE.equalsIgnoreCase(scope)) { + + // export to local if the config is not remote (export to remote only when config is remote) + if (!Constants.SCOPE_REMOTE.equalsIgnoreCase(scope)) { + exportLocal(url); + } + // export to remote if the config is not local (export to local only when config is local) + if (!Constants.SCOPE_LOCAL.equalsIgnoreCase(scope)) { + if (logger.isInfoEnabled()) { + logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url); + } + if (CollectionUtils.isNotEmpty(registryURLs)) { + for (URL registryURL : registryURLs) { + url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY)); + URL monitorUrl = loadMonitor(registryURL); + if (monitorUrl != null) { + url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString()); + } + if (logger.isInfoEnabled()) { + logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL); + } + + // For providers, this is used to enable custom proxy to generate invoker + String proxy = url.getParameter(Constants.PROXY_KEY); + if (StringUtils.isNotEmpty(proxy)) { + registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy); + } + + Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString())); + DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); + + Exporter exporter = protocol.export(wrapperInvoker); + exporters.add(exporter); + } + } else { + Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); + DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); + + Exporter exporter = protocol.export(wrapperInvoker); + exporters.add(exporter); + } + /** + * @since 2.7.0 + * ServiceData Store + */ + MetadataReportService metadataReportService = null; + if ((metadataReportService = getMetadataReportService()) != null) { + metadataReportService.publishProvider(url); + } + } + } + this.urls.add(url); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void exportLocal(URL url) { + if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { + URL local = URL.valueOf(url.toFullString()) + .setProtocol(Constants.LOCAL_PROTOCOL) + .setHost(LOCALHOST_VALUE) + .setPort(0); + Exporter exporter = protocol.export( + proxyFactory.getInvoker(ref, (Class) interfaceClass, local)); + exporters.add(exporter); + logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry"); + } + } + + protected Class getServiceClass(T ref) { + return ref.getClass(); + } + + /** + * Register & bind IP address for service provider, can be configured separately. + * Configuration priority: environment variables -> java system properties -> host property in config file -> + * /etc/hosts -> default network address -> first available network address + * + * @param protocolConfig + * @param registryURLs + * @param map + * @return + */ + private String findConfigedHosts(ProtocolConfig protocolConfig, List registryURLs, Map map) { + boolean anyhost = false; + + String hostToBind = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_BIND); + if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) { + throw new IllegalArgumentException("Specified invalid bind ip from property:" + Constants.DUBBO_IP_TO_BIND + ", value:" + hostToBind); + } + + // if bind ip is not found in environment, keep looking up + if (StringUtils.isEmpty(hostToBind)) { + hostToBind = protocolConfig.getHost(); + if (provider != null && StringUtils.isEmpty(hostToBind)) { + hostToBind = provider.getHost(); + } + if (isInvalidLocalHost(hostToBind)) { + anyhost = true; + try { + hostToBind = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + logger.warn(e.getMessage(), e); + } + if (isInvalidLocalHost(hostToBind)) { + if (CollectionUtils.isNotEmpty(registryURLs)) { + for (URL registryURL : registryURLs) { + if (Constants.MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) { + // skip multicast registry since we cannot connect to it via Socket + continue; + } + try (Socket socket = new Socket()) { + SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort()); + socket.connect(addr, 1000); + hostToBind = socket.getLocalAddress().getHostAddress(); + break; + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + } + } + if (isInvalidLocalHost(hostToBind)) { + hostToBind = getLocalHost(); + } + } + } + } + + map.put(Constants.BIND_IP_KEY, hostToBind); + + // registry ip is not used for bind ip by default + String hostToRegistry = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_REGISTRY); + if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) { + throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); + } else if (StringUtils.isEmpty(hostToRegistry)) { + // bind ip is used as registry ip by default + hostToRegistry = hostToBind; + } + + map.put(Constants.ANYHOST_KEY, String.valueOf(anyhost)); + + return hostToRegistry; + } + + /** + * Register port and bind port for the provider, can be configured separately + * Configuration priority: environment variable -> java system properties -> port property in protocol config file + * -> protocol default port + * + * @param protocolConfig + * @param name + * @return + */ + private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map map) { + Integer portToBind = null; + + // parse bind port from environment + String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND); + portToBind = parsePort(port); + + // if there's no bind port found from environment, keep looking up. + if (portToBind == null) { + portToBind = protocolConfig.getPort(); + if (provider != null && (portToBind == null || portToBind == 0)) { + portToBind = provider.getPort(); + } + final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort(); + if (portToBind == null || portToBind == 0) { + portToBind = defaultPort; + } + if (portToBind == null || portToBind <= 0) { + portToBind = getRandomPort(name); + if (portToBind == null || portToBind < 0) { + portToBind = getAvailablePort(defaultPort); + putRandomPort(name, portToBind); + } + } + } + + // save bind port, used as url's key later + map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind)); + + // registry port, not used as bind port by default + String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY); + Integer portToRegistry = parsePort(portToRegistryStr); + if (portToRegistry == null) { + portToRegistry = portToBind; + } + + return portToRegistry; + } + + private Integer parsePort(String configPort) { + Integer port = null; + if (configPort != null && configPort.length() > 0) { + try { + Integer intPort = Integer.parseInt(configPort); + if (isInvalidPort(intPort)) { + throw new IllegalArgumentException("Specified invalid port from env value:" + configPort); + } + port = intPort; + } catch (Exception e) { + throw new IllegalArgumentException("Specified invalid port from env value:" + configPort); + } + } + return port; + } + + private String getValueFromConfig(ProtocolConfig protocolConfig, String key) { + String protocolPrefix = protocolConfig.getName().toUpperCase() + "_"; + String port = ConfigUtils.getSystemProperty(protocolPrefix + key); + if (StringUtils.isEmpty(port)) { + port = ConfigUtils.getSystemProperty(key); + } + return port; + } + + private void completeCompoundConfigs() { + if (provider != null) { + if (application == null) { + setApplication(provider.getApplication()); + } + if (module == null) { + setModule(provider.getModule()); + } + if (registries == null) { + setRegistries(provider.getRegistries()); + } + if (monitor == null) { + setMonitor(provider.getMonitor()); + } + if (protocols == null) { + setProtocols(provider.getProtocols()); + } + if (configCenter == null) { + setConfigCenter(provider.getConfigCenter()); + } + } + if (module != null) { + if (registries == null) { + setRegistries(module.getRegistries()); + } + if (monitor == null) { + setMonitor(module.getMonitor()); + } + } + if (application != null) { + if (registries == null) { + setRegistries(application.getRegistries()); + } + if (monitor == null) { + setMonitor(application.getMonitor()); + } + } + } + + private void checkDefault() { + createProviderIfAbsent(); + } + + private void createProviderIfAbsent() { + if (provider != null) { + return; + } + setProvider ( + ConfigManager.getInstance() + .getDefaultProvider() + .orElseGet(() -> { + ProviderConfig providerConfig = new ProviderConfig(); + providerConfig.refresh(); + return providerConfig; + }) + ); + } + + private void checkProtocol() { + if (CollectionUtils.isEmpty(protocols) && provider != null) { + setProtocols(provider.getProtocols()); + } + convertProtocolIdsToProtocols(); + } + + private void convertProtocolIdsToProtocols() { + if (StringUtils.isEmpty(protocolIds) && CollectionUtils.isEmpty(protocols)) { + List configedProtocols = new ArrayList<>(); + configedProtocols.addAll(getSubProperties(Environment.getInstance() + .getExternalConfigurationMap(), Constants.PROTOCOLS_SUFFIX)); + configedProtocols.addAll(getSubProperties(Environment.getInstance() + .getAppExternalConfigurationMap(), Constants.PROTOCOLS_SUFFIX)); + + protocolIds = String.join(",", configedProtocols); + } + + if (StringUtils.isEmpty(protocolIds)) { + if (CollectionUtils.isEmpty(protocols)) { + setProtocols( + ConfigManager.getInstance().getDefaultProtocols() + .filter(CollectionUtils::isNotEmpty) + .orElseGet(() -> { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.refresh(); + return Arrays.asList(protocolConfig); + }) + ); + } + } else { + String[] arr = Constants.COMMA_SPLIT_PATTERN.split(protocolIds); + List tmpProtocols = CollectionUtils.isNotEmpty(protocols) ? protocols : new ArrayList<>(); + Arrays.stream(arr).forEach(id -> { + if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) { + tmpProtocols.add(ConfigManager.getInstance().getProtocol(id).orElseGet(() -> { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setId(id); + protocolConfig.refresh(); + return protocolConfig; + })); + } + }); + if (tmpProtocols.size() > arr.length) { + throw new IllegalStateException("Too much protocols found, the protocols comply to this service are :" + protocolIds + " but got " + protocols + .size() + " registries!"); + } + setProtocols(tmpProtocols); + } + } + + public Class getInterfaceClass() { + if (interfaceClass != null) { + return interfaceClass; + } + if (ref instanceof GenericService) { + return GenericService.class; + } + try { + if (interfaceName != null && interfaceName.length() > 0) { + this.interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() + .getContextClassLoader()); + } + } catch (ClassNotFoundException t) { + throw new IllegalStateException(t.getMessage(), t); + } + return interfaceClass; + } + + /** + * @param interfaceClass + * @see #setInterface(Class) + * @deprecated + */ + public void setInterfaceClass(Class interfaceClass) { + setInterface(interfaceClass); + } + + public String getInterface() { + return interfaceName; + } + + public void setInterface(Class interfaceClass) { + if (interfaceClass != null && !interfaceClass.isInterface()) { + throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); + } + this.interfaceClass = interfaceClass; + setInterface(interfaceClass == null ? null : interfaceClass.getName()); + } + + public void setInterface(String interfaceName) { + this.interfaceName = interfaceName; + if (StringUtils.isEmpty(id)) { + id = interfaceName; + } + } + + public T getRef() { + return ref; + } + + public void setRef(T ref) { + this.ref = ref; + } + + @Parameter(excluded = true) + public String getPath() { + return path; + } + + public void setPath(String path) { + checkPathName(Constants.PATH_KEY, path); + this.path = path; + } + + public List getMethods() { + return methods; + } + + // ======== Deprecated ======== + + @SuppressWarnings("unchecked") + public void setMethods(List methods) { + this.methods = (List) methods; + } + + public ProviderConfig getProvider() { + return provider; + } + + public void setProvider(ProviderConfig provider) { + ConfigManager.getInstance().addProvider(provider); + this.provider = provider; + } + + @Parameter(excluded = true) + public String getProviderIds() { + return providerIds; + } + + public void setProviderIds(String providerIds) { + this.providerIds = providerIds; + } + + public String getGeneric() { + return generic; + } + + public void setGeneric(String generic) { + if (StringUtils.isEmpty(generic)) { + return; + } + if (ProtocolUtils.isGeneric(generic)) { + this.generic = generic; + } else { + throw new IllegalArgumentException("Unsupported generic type " + generic); + } + } + + @Override + public void setMock(Boolean mock) { + throw new IllegalArgumentException("mock doesn't support on provider side"); + } + + @Override + public void setMock(String mock) { + throw new IllegalArgumentException("mock doesn't support on provider side"); + } + + public List getExportedUrls() { + return urls; + } + + /** + * @deprecated Replace to getProtocols() + */ + @Deprecated + public List getProviders() { + return convertProtocolToProvider(protocols); + } + + /** + * @deprecated Replace to setProtocols() + */ + @Deprecated + public void setProviders(List providers) { + this.protocols = convertProviderToProtocol(providers); + } + + @Parameter(excluded = true) + public String getUniqueServiceName() { + StringBuilder buf = new StringBuilder(); + if (group != null && group.length() > 0) { + buf.append(group).append("/"); + } + buf.append(StringUtils.isNotEmpty(path) ? path : interfaceName); + if (version != null && version.length() > 0) { + buf.append(":").append(version); + } + return buf.toString(); + } + + @Override + @Parameter(excluded = true) + public String getPrefix() { + return Constants.DUBBO + ".service." + interfaceName; + } +}