/* | |
* 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.extension.ExtensionLoader; | |
import com.alibaba.dubbo.common.utils.ConfigUtils; | |
import com.alibaba.dubbo.common.utils.NetUtils; | |
import com.alibaba.dubbo.common.utils.ReflectUtils; | |
import com.alibaba.dubbo.common.utils.StringUtils; | |
import com.alibaba.dubbo.common.utils.UrlUtils; | |
import com.alibaba.dubbo.config.support.Parameter; | |
import com.alibaba.dubbo.monitor.MonitorFactory; | |
import com.alibaba.dubbo.monitor.MonitorService; | |
import com.alibaba.dubbo.registry.RegistryFactory; | |
import com.alibaba.dubbo.registry.RegistryService; | |
import com.alibaba.dubbo.rpc.Filter; | |
import com.alibaba.dubbo.rpc.InvokerListener; | |
import com.alibaba.dubbo.rpc.ProxyFactory; | |
import com.alibaba.dubbo.rpc.cluster.Cluster; | |
import com.alibaba.dubbo.rpc.support.MockInvoker; | |
import static com.alibaba.dubbo.common.utils.NetUtils.isInvalidLocalHost; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
/** | |
* AbstractDefaultConfig | |
* | |
* @export | |
*/ | |
public abstract class AbstractInterfaceConfig extends AbstractMethodConfig { | |
private static final long serialVersionUID = -1559314110797223229L; | |
// local impl class name for the service interface | |
protected String local; | |
// local stub class name for the service interface | |
protected String stub; | |
// service monitor | |
protected MonitorConfig monitor; | |
// proxy type | |
protected String proxy; | |
// cluster type | |
protected String cluster; | |
// filter | |
protected String filter; | |
// listener | |
protected String listener; | |
// owner | |
protected String owner; | |
// connection limits, 0 means shared connection, otherwise it defines the connections delegated to the | |
// current service | |
protected Integer connections; | |
// layer | |
protected String layer; | |
// application info | |
protected ApplicationConfig application; | |
// module info | |
protected ModuleConfig module; | |
// registry centers | |
protected List<RegistryConfig> registries; | |
// connection events | |
protected String onconnect; | |
// disconnection events | |
protected String ondisconnect; | |
// callback limits | |
private Integer callbacks; | |
// the scope for referring/exporting a service, if it's local, it means searching in current JVM only. | |
private String scope; | |
protected void checkRegistry() { | |
// for backward compatibility | |
if (registries == null || registries.size() == 0) { | |
String address = ConfigUtils.getProperty("dubbo.registry.address"); | |
if (address != null && address.length() > 0) { | |
registries = new ArrayList<RegistryConfig>(); | |
String[] as = address.split("\\s*[|]+\\s*"); | |
for (String a : as) { | |
RegistryConfig registryConfig = new RegistryConfig(); | |
registryConfig.setAddress(a); | |
registries.add(registryConfig); | |
} | |
} | |
} | |
if ((registries == null || registries.size() == 0)) { | |
throw new IllegalStateException((getClass().getSimpleName().startsWith("Reference") | |
? "No such any registry to refer service in consumer " | |
: "No such any registry to export service in provider ") | |
+ NetUtils.getLocalHost() | |
+ " use dubbo version " | |
+ Version.getVersion() | |
+ ", Please add <dubbo:registry address=\"...\" /> to your spring config. If you want unregister, please set <dubbo:service registry=\"N/A\" />"); | |
} | |
for (RegistryConfig registryConfig : registries) { | |
appendProperties(registryConfig); | |
} | |
} | |
@SuppressWarnings("deprecation") | |
protected void checkApplication() { | |
// for backward compatibility | |
if (application == null) { | |
String applicationName = ConfigUtils.getProperty("dubbo.application.name"); | |
if (applicationName != null && applicationName.length() > 0) { | |
application = new ApplicationConfig(); | |
} | |
} | |
if (application == null) { | |
throw new IllegalStateException( | |
"No such application config! Please add <dubbo:application name=\"...\" /> to your spring config."); | |
} | |
appendProperties(application); | |
String wait = ConfigUtils.getProperty(Constants.SHUTDOWN_WAIT_KEY); | |
if (wait != null && wait.trim().length() > 0) { | |
System.setProperty(Constants.SHUTDOWN_WAIT_KEY, wait.trim()); | |
} else { | |
wait = ConfigUtils.getProperty(Constants.SHUTDOWN_WAIT_SECONDS_KEY); | |
if (wait != null && wait.trim().length() > 0) { | |
System.setProperty(Constants.SHUTDOWN_WAIT_SECONDS_KEY, wait.trim()); | |
} | |
} | |
} | |
protected List<URL> loadRegistries(boolean provider) { | |
checkRegistry(); | |
List<URL> registryList = new ArrayList<URL>(); | |
if (registries != null && registries.size() > 0) { | |
for (RegistryConfig config : registries) { | |
String address = config.getAddress(); | |
if (address == null || address.length() == 0) { | |
address = Constants.ANYHOST_VALUE; | |
} | |
String sysaddress = System.getProperty("dubbo.registry.address"); | |
if (sysaddress != null && sysaddress.length() > 0) { | |
address = sysaddress; | |
} | |
if (address != null && address.length() > 0 | |
&& !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) { | |
Map<String, String> map = new HashMap<String, String>(); | |
appendParameters(map, application); | |
appendParameters(map, config); | |
map.put("path", RegistryService.class.getName()); | |
map.put("dubbo", Version.getVersion()); | |
map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); | |
if (ConfigUtils.getPid() > 0) { | |
map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid())); | |
} | |
if (!map.containsKey("protocol")) { | |
if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) { | |
map.put("protocol", "remote"); | |
} else { | |
map.put("protocol", "dubbo"); | |
} | |
} | |
List<URL> urls = UrlUtils.parseURLs(address, map); | |
for (URL url : urls) { | |
url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol()); | |
url = url.setProtocol(Constants.REGISTRY_PROTOCOL); | |
if ((provider && url.getParameter(Constants.REGISTER_KEY, true)) | |
|| (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) { | |
registryList.add(url); | |
} | |
} | |
} | |
} | |
} | |
return registryList; | |
} | |
protected URL loadMonitor(URL registryURL) { | |
if (monitor == null) { | |
String monitorAddress = ConfigUtils.getProperty("dubbo.monitor.address"); | |
String monitorProtocol = ConfigUtils.getProperty("dubbo.monitor.protocol"); | |
if ((monitorAddress == null || monitorAddress.length() == 0) && (monitorProtocol == null || monitorProtocol.length() == 0)) { | |
return null; | |
} | |
monitor = new MonitorConfig(); | |
if (monitorAddress != null && monitorAddress.length() > 0) { | |
monitor.setAddress(monitorAddress); | |
} | |
if (monitorProtocol != null && monitorProtocol.length() > 0) { | |
monitor.setProtocol(monitorProtocol); | |
} | |
} | |
appendProperties(monitor); | |
Map<String, String> map = new HashMap<String, String>(); | |
map.put(Constants.INTERFACE_KEY, MonitorService.class.getName()); | |
map.put("dubbo", Version.getVersion()); | |
map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); | |
if (ConfigUtils.getPid() > 0) { | |
map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid())); | |
} | |
//set ip | |
String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY); | |
if (hostToRegistry == null || hostToRegistry.length() == 0) { | |
hostToRegistry = NetUtils.getLocalHost(); | |
} else if (isInvalidLocalHost(hostToRegistry)) { | |
throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); | |
} | |
map.put(Constants.REGISTER_IP_KEY, hostToRegistry); | |
appendParameters(map, monitor); | |
appendParameters(map, application); | |
String address = monitor.getAddress(); | |
String sysaddress = System.getProperty("dubbo.monitor.address"); | |
if (sysaddress != null && sysaddress.length() > 0) { | |
address = sysaddress; | |
} | |
if (ConfigUtils.isNotEmpty(address)) { | |
if (!map.containsKey(Constants.PROTOCOL_KEY)) { | |
if (ExtensionLoader.getExtensionLoader(MonitorFactory.class).hasExtension("logstat")) { | |
map.put(Constants.PROTOCOL_KEY, "logstat"); | |
} else { | |
map.put(Constants.PROTOCOL_KEY, "dubbo"); | |
} | |
} | |
return UrlUtils.parseURL(address, map); | |
} else if (Constants.REGISTRY_PROTOCOL.equals(monitor.getProtocol()) && registryURL != null) { | |
return registryURL.setProtocol("dubbo").addParameter(Constants.PROTOCOL_KEY, "registry").addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)); | |
} | |
return null; | |
} | |
protected void checkInterfaceAndMethods(Class<?> interfaceClass, List<MethodConfig> methods) { | |
// interface cannot be null | |
if (interfaceClass == null) { | |
throw new IllegalStateException("interface not allow null!"); | |
} | |
// to verify interfaceClass is an interface | |
if (!interfaceClass.isInterface()) { | |
throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); | |
} | |
// check if methods exist in the interface | |
if (methods != null && methods.size() > 0) { | |
for (MethodConfig methodBean : methods) { | |
String methodName = methodBean.getName(); | |
if (methodName == null || methodName.length() == 0) { | |
throw new IllegalStateException("<dubbo:method> name attribute is required! Please check: <dubbo:service interface=\"" + interfaceClass.getName() + "\" ... ><dubbo:method name=\"\" ... /></<dubbo:reference>"); | |
} | |
boolean hasMethod = false; | |
for (java.lang.reflect.Method method : interfaceClass.getMethods()) { | |
if (method.getName().equals(methodName)) { | |
hasMethod = true; | |
break; | |
} | |
} | |
if (!hasMethod) { | |
throw new IllegalStateException("The interface " + interfaceClass.getName() | |
+ " not found method " + methodName); | |
} | |
} | |
} | |
} | |
protected void checkStubAndMock(Class<?> interfaceClass) { | |
if (ConfigUtils.isNotEmpty(local)) { | |
Class<?> localClass = ConfigUtils.isDefault(local) ? ReflectUtils.forName(interfaceClass.getName() + "Local") : ReflectUtils.forName(local); | |
if (!interfaceClass.isAssignableFrom(localClass)) { | |
throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceClass.getName()); | |
} | |
try { | |
ReflectUtils.findConstructor(localClass, interfaceClass); | |
} catch (NoSuchMethodException e) { | |
throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")\" in local implementation class " + localClass.getName()); | |
} | |
} | |
if (ConfigUtils.isNotEmpty(stub)) { | |
Class<?> localClass = ConfigUtils.isDefault(stub) ? ReflectUtils.forName(interfaceClass.getName() + "Stub") : ReflectUtils.forName(stub); | |
if (!interfaceClass.isAssignableFrom(localClass)) { | |
throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceClass.getName()); | |
} | |
try { | |
ReflectUtils.findConstructor(localClass, interfaceClass); | |
} catch (NoSuchMethodException e) { | |
throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")\" in local implementation class " + localClass.getName()); | |
} | |
} | |
if (ConfigUtils.isNotEmpty(mock)) { | |
if (mock.startsWith(Constants.RETURN_PREFIX)) { | |
String value = mock.substring(Constants.RETURN_PREFIX.length()); | |
try { | |
MockInvoker.parseMockValue(value); | |
} catch (Exception e) { | |
throw new IllegalStateException("Illegal mock json value in <dubbo:service ... mock=\"" + mock + "\" />"); | |
} | |
} else { | |
Class<?> mockClass = ConfigUtils.isDefault(mock) ? ReflectUtils.forName(interfaceClass.getName() + "Mock") : ReflectUtils.forName(mock); | |
if (!interfaceClass.isAssignableFrom(mockClass)) { | |
throw new IllegalStateException("The mock implementation class " + mockClass.getName() + " not implement interface " + interfaceClass.getName()); | |
} | |
try { | |
mockClass.getConstructor(new Class<?>[0]); | |
} catch (NoSuchMethodException e) { | |
throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName() + "()\" in mock implementation class " + mockClass.getName()); | |
} | |
} | |
} | |
} | |
/** | |
* @return local | |
* @deprecated Replace to <code>getStub()</code> | |
*/ | |
@Deprecated | |
public String getLocal() { | |
return local; | |
} | |
/** | |
* @param local | |
* @deprecated Replace to <code>setStub(Boolean)</code> | |
*/ | |
@Deprecated | |
public void setLocal(Boolean local) { | |
if (local == null) { | |
setLocal((String) null); | |
} else { | |
setLocal(String.valueOf(local)); | |
} | |
} | |
/** | |
* @param local | |
* @deprecated Replace to <code>setStub(String)</code> | |
*/ | |
@Deprecated | |
public void setLocal(String local) { | |
checkName("local", local); | |
this.local = local; | |
} | |
public String getStub() { | |
return stub; | |
} | |
public void setStub(Boolean stub) { | |
if (local == null) { | |
setStub((String) null); | |
} else { | |
setStub(String.valueOf(stub)); | |
} | |
} | |
public void setStub(String stub) { | |
checkName("stub", stub); | |
this.stub = stub; | |
} | |
public String getCluster() { | |
return cluster; | |
} | |
public void setCluster(String cluster) { | |
checkExtension(Cluster.class, "cluster", cluster); | |
this.cluster = cluster; | |
} | |
public String getProxy() { | |
return proxy; | |
} | |
public void setProxy(String proxy) { | |
checkExtension(ProxyFactory.class, "proxy", proxy); | |
this.proxy = proxy; | |
} | |
public Integer getConnections() { | |
return connections; | |
} | |
public void setConnections(Integer connections) { | |
this.connections = connections; | |
} | |
@Parameter(key = Constants.REFERENCE_FILTER_KEY, append = true) | |
public String getFilter() { | |
return filter; | |
} | |
public void setFilter(String filter) { | |
checkMultiExtension(Filter.class, "filter", filter); | |
this.filter = filter; | |
} | |
@Parameter(key = Constants.INVOKER_LISTENER_KEY, append = true) | |
public String getListener() { | |
checkMultiExtension(InvokerListener.class, "listener", listener); | |
return listener; | |
} | |
public void setListener(String listener) { | |
this.listener = listener; | |
} | |
public String getLayer() { | |
return layer; | |
} | |
public void setLayer(String layer) { | |
checkNameHasSymbol("layer", layer); | |
this.layer = layer; | |
} | |
public ApplicationConfig getApplication() { | |
return application; | |
} | |
public void setApplication(ApplicationConfig application) { | |
this.application = application; | |
} | |
public ModuleConfig getModule() { | |
return module; | |
} | |
public void setModule(ModuleConfig module) { | |
this.module = module; | |
} | |
public RegistryConfig getRegistry() { | |
return registries == null || registries.size() == 0 ? null : registries.get(0); | |
} | |
public void setRegistry(RegistryConfig registry) { | |
List<RegistryConfig> registries = new ArrayList<RegistryConfig>(1); | |
registries.add(registry); | |
this.registries = registries; | |
} | |
public List<RegistryConfig> getRegistries() { | |
return registries; | |
} | |
@SuppressWarnings({"unchecked"}) | |
public void setRegistries(List<? extends RegistryConfig> registries) { | |
this.registries = (List<RegistryConfig>) registries; | |
} | |
public MonitorConfig getMonitor() { | |
return monitor; | |
} | |
public void setMonitor(String monitor) { | |
this.monitor = new MonitorConfig(monitor); | |
} | |
public void setMonitor(MonitorConfig monitor) { | |
this.monitor = monitor; | |
} | |
public String getOwner() { | |
return owner; | |
} | |
public void setOwner(String owner) { | |
checkMultiName("owner", owner); | |
this.owner = owner; | |
} | |
public Integer getCallbacks() { | |
return callbacks; | |
} | |
public void setCallbacks(Integer callbacks) { | |
this.callbacks = callbacks; | |
} | |
public String getOnconnect() { | |
return onconnect; | |
} | |
public void setOnconnect(String onconnect) { | |
this.onconnect = onconnect; | |
} | |
public String getOndisconnect() { | |
return ondisconnect; | |
} | |
public void setOndisconnect(String ondisconnect) { | |
this.ondisconnect = ondisconnect; | |
} | |
public String getScope() { | |
return scope; | |
} | |
public void setScope(String scope) { | |
this.scope = scope; | |
} | |
} |