/* | |
* 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 com.alibaba.dubbo.config; | |
import com.alibaba.dubbo.common.Constants; | |
import com.alibaba.dubbo.common.URL; | |
import com.alibaba.dubbo.common.Version; | |
import com.alibaba.dubbo.common.bytecode.Wrapper; | |
import com.alibaba.dubbo.common.extension.ExtensionLoader; | |
import com.alibaba.dubbo.common.utils.ClassHelper; | |
import com.alibaba.dubbo.common.utils.ConfigUtils; | |
import com.alibaba.dubbo.common.utils.NamedThreadFactory; | |
import com.alibaba.dubbo.common.utils.StringUtils; | |
import com.alibaba.dubbo.config.annotation.Service; | |
import com.alibaba.dubbo.config.invoker.DelegateProviderMetaDataInvoker; | |
import com.alibaba.dubbo.config.model.ApplicationModel; | |
import com.alibaba.dubbo.config.model.ProviderModel; | |
import com.alibaba.dubbo.config.support.Parameter; | |
import com.alibaba.dubbo.rpc.Exporter; | |
import com.alibaba.dubbo.rpc.Invoker; | |
import com.alibaba.dubbo.rpc.Protocol; | |
import com.alibaba.dubbo.rpc.ProxyFactory; | |
import com.alibaba.dubbo.rpc.ServiceClassHolder; | |
import com.alibaba.dubbo.rpc.cluster.ConfiguratorFactory; | |
import com.alibaba.dubbo.rpc.service.GenericService; | |
import com.alibaba.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 com.alibaba.dubbo.common.utils.NetUtils.LOCALHOST; | |
import static com.alibaba.dubbo.common.utils.NetUtils.getAvailablePort; | |
import static com.alibaba.dubbo.common.utils.NetUtils.getLocalHost; | |
import static com.alibaba.dubbo.common.utils.NetUtils.isInvalidLocalHost; | |
import static com.alibaba.dubbo.common.utils.NetUtils.isInvalidPort; | |
/** | |
* ServiceConfig | |
* | |
* @export | |
*/ | |
public class ServiceConfig<T> extends AbstractServiceConfig { | |
private static final long serialVersionUID = 3033787999037024738L; | |
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); | |
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); | |
private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap<String, Integer>(); | |
private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true)); | |
private final List<URL> urls = new ArrayList<URL>(); | |
private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>(); | |
// interface type | |
private String interfaceName; | |
private Class<?> interfaceClass; | |
// reference to interface impl | |
private T ref; | |
// service name | |
private String path; | |
// method configuration | |
private List<MethodConfig> methods; | |
private ProviderConfig provider; | |
private transient volatile boolean exported; | |
private transient volatile boolean unexported; | |
private volatile String generic; | |
public ServiceConfig() { | |
} | |
public ServiceConfig(Service service) { | |
appendAnnotation(Service.class, service); | |
} | |
@Deprecated | |
private static List<ProtocolConfig> convertProviderToProtocol(List<ProviderConfig> providers) { | |
if (providers == null || providers.isEmpty()) { | |
return null; | |
} | |
List<ProtocolConfig> protocols = new ArrayList<ProtocolConfig>(providers.size()); | |
for (ProviderConfig provider : providers) { | |
protocols.add(convertProviderToProtocol(provider)); | |
} | |
return protocols; | |
} | |
@Deprecated | |
private static List<ProviderConfig> convertProtocolToProvider(List<ProtocolConfig> protocols) { | |
if (protocols == null || protocols.isEmpty()) { | |
return null; | |
} | |
List<ProviderConfig> providers = new ArrayList<ProviderConfig>(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(); | |
if (RANDOM_PORT_MAP.containsKey(protocol)) { | |
return RANDOM_PORT_MAP.get(protocol); | |
} | |
return 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); | |
} | |
} | |
public URL toUrl() { | |
return urls.isEmpty() ? null : urls.iterator().next(); | |
} | |
public List<URL> toUrls() { | |
return urls; | |
} | |
@Parameter(excluded = true) | |
public boolean isExported() { | |
return exported; | |
} | |
@Parameter(excluded = true) | |
public boolean isUnexported() { | |
return unexported; | |
} | |
public synchronized void export() { | |
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(new Runnable() { | |
@Override | |
public void run() { | |
doExport(); | |
} | |
}, delay, TimeUnit.MILLISECONDS); | |
} else { | |
doExport(); | |
} | |
} | |
protected synchronized void doExport() { | |
if (unexported) { | |
throw new IllegalStateException("Already unexported!"); | |
} | |
if (exported) { | |
return; | |
} | |
exported = true; | |
if (interfaceName == null || interfaceName.length() == 0) { | |
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!"); | |
} | |
checkDefault(); | |
if (provider != null) { | |
if (application == null) { | |
application = provider.getApplication(); | |
} | |
if (module == null) { | |
module = provider.getModule(); | |
} | |
if (registries == null) { | |
registries = provider.getRegistries(); | |
} | |
if (monitor == null) { | |
monitor = provider.getMonitor(); | |
} | |
if (protocols == null) { | |
protocols = provider.getProtocols(); | |
} | |
} | |
if (module != null) { | |
if (registries == null) { | |
registries = module.getRegistries(); | |
} | |
if (monitor == null) { | |
monitor = module.getMonitor(); | |
} | |
} | |
if (application != null) { | |
if (registries == null) { | |
registries = application.getRegistries(); | |
} | |
if (monitor == null) { | |
monitor = application.getMonitor(); | |
} | |
} | |
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); | |
} | |
} | |
checkApplication(); | |
checkRegistry(); | |
checkProtocol(); | |
appendProperties(this); | |
checkStubAndMock(interfaceClass); | |
if (path == null || path.length() == 0) { | |
path = interfaceName; | |
} | |
doExportUrls(); | |
ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref); | |
ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel); | |
} | |
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 err when unexport" + exporter, t); | |
} | |
} | |
exporters.clear(); | |
} | |
unexported = true; | |
} | |
@SuppressWarnings({"unchecked", "rawtypes"}) | |
private void doExportUrls() { | |
List<URL> registryURLs = loadRegistries(true); | |
for (ProtocolConfig protocolConfig : protocols) { | |
doExportUrlsFor1Protocol(protocolConfig, registryURLs); | |
} | |
} | |
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) { | |
String name = protocolConfig.getName(); | |
if (name == null || name.length() == 0) { | |
name = "dubbo"; | |
} | |
Map<String, String> map = new HashMap<String, String>(); | |
map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE); | |
map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion()); | |
map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); | |
if (ConfigUtils.getPid() > 0) { | |
map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid())); | |
} | |
appendParameters(map, application); | |
appendParameters(map, module); | |
appendParameters(map, provider, Constants.DEFAULT_KEY); | |
appendParameters(map, protocolConfig); | |
appendParameters(map, this); | |
if (methods != null && !methods.isEmpty()) { | |
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<ArgumentConfig> arguments = method.getArguments(); | |
if (arguments != null && !arguments.isEmpty()) { | |
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: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>"); | |
} | |
} | |
} | |
} // 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<String>(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); | |
} | |
} | |
if (Constants.LOCAL_PROTOCOL.equals(protocolConfig.getName())) { | |
protocolConfig.setRegister(false); | |
map.put("notify", "false"); | |
} | |
// export service | |
String contextPath = protocolConfig.getContextpath(); | |
if ((contextPath == null || contextPath.length() == 0) && 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, (contextPath == null || contextPath.length() == 0 ? "" : 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.toString().equalsIgnoreCase(scope)) { | |
// export to local if the config is not remote (export to remote only when config is remote) | |
if (!Constants.SCOPE_REMOTE.toString().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.toString().equalsIgnoreCase(scope)) { | |
if (logger.isInfoEnabled()) { | |
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url); | |
} | |
if (registryURLs != null && !registryURLs.isEmpty()) { | |
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); | |
} | |
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); | |
} | |
} | |
} | |
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) | |
.setPort(0); | |
ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref)); | |
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<URL> registryURLs, Map<String, String> 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 (hostToBind == null || hostToBind.length() == 0) { | |
hostToBind = protocolConfig.getHost(); | |
if (provider != null && (hostToBind == null || hostToBind.length() == 0)) { | |
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 (registryURLs != null && !registryURLs.isEmpty()) { | |
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(); | |
try { | |
SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort()); | |
socket.connect(addr, 1000); | |
hostToBind = socket.getLocalAddress().getHostAddress(); | |
break; | |
} finally { | |
try { | |
socket.close(); | |
} catch (Throwable e) { | |
} | |
} | |
} 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 (hostToRegistry == null || hostToRegistry.length() == 0) { | |
// 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<String, String> 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); | |
} | |
logger.warn("Use random available port(" + portToBind + ") for protocol " + name); | |
} | |
} | |
// 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 (port == null || port.length() == 0) { | |
port = ConfigUtils.getSystemProperty(key); | |
} | |
return port; | |
} | |
private void checkDefault() { | |
if (provider == null) { | |
provider = new ProviderConfig(); | |
} | |
appendProperties(provider); | |
} | |
private void checkProtocol() { | |
if ((protocols == null || protocols.isEmpty()) | |
&& provider != null) { | |
setProtocols(provider.getProtocols()); | |
} | |
// backward compatibility | |
if (protocols == null || protocols.isEmpty()) { | |
setProtocol(new ProtocolConfig()); | |
} | |
for (ProtocolConfig protocolConfig : protocols) { | |
if (StringUtils.isEmpty(protocolConfig.getName())) { | |
protocolConfig.setName(Constants.DUBBO_VERSION_KEY); | |
} | |
appendProperties(protocolConfig); | |
} | |
} | |
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(String interfaceName) { | |
this.interfaceName = interfaceName; | |
if (id == null || id.length() == 0) { | |
id = 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 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<MethodConfig> getMethods() { | |
return methods; | |
} | |
// ======== Deprecated ======== | |
@SuppressWarnings("unchecked") | |
public void setMethods(List<? extends MethodConfig> methods) { | |
this.methods = (List<MethodConfig>) methods; | |
} | |
public ProviderConfig getProvider() { | |
return provider; | |
} | |
public void setProvider(ProviderConfig provider) { | |
this.provider = provider; | |
} | |
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); | |
} | |
} | |
public List<URL> getExportedUrls() { | |
return urls; | |
} | |
/** | |
* @deprecated Replace to getProtocols() | |
*/ | |
@Deprecated | |
public List<ProviderConfig> getProviders() { | |
return convertProtocolToProvider(protocols); | |
} | |
/** | |
* @deprecated Replace to setProtocols() | |
*/ | |
@Deprecated | |
public void setProviders(List<ProviderConfig> 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(interfaceName); | |
if (version != null && version.length() > 0) { | |
buf.append(":").append(version); | |
} | |
return buf.toString(); | |
} | |
} |