/*
* Copyright 2009-2016 Weibo, Inc.
*
* Licensed 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.weibo.api.motan.config;
import com.weibo.api.motan.common.MotanConstants;
import com.weibo.api.motan.common.URLParamType;
import com.weibo.api.motan.exception.MotanErrorMsgConstant;
import com.weibo.api.motan.exception.MotanFrameworkException;
import com.weibo.api.motan.exception.MotanServiceException;
import com.weibo.api.motan.registry.RegistryService;
import com.weibo.api.motan.rpc.ApplicationInfo;
import com.weibo.api.motan.rpc.URL;
import com.weibo.api.motan.util.NetUtils;
import com.weibo.api.motan.util.ReflectUtil;
import com.weibo.api.motan.util.UrlUtils;
import org.apache.commons.lang3.StringUtils;
import java.net.InetAddress;
import java.util.*;
/**
*
* <pre>
* Interface config,
*
* 配置约定
* 1 service 和 referer 端相同的参数的含义一定相同;
* 2 service端参数的覆盖策略:protocol--basicConfig--service,前面的配置会被后面的config参数覆盖;
* 3 registry 参数不进入service、referer端的参数列表;
* 4 referer端从注册中心拿到参数后,先用referer端的参数覆盖,然后再使用该service
* </pre>
*
* @author fishermen
* @version V1.0 created at: 2013-5-27
*/
public class AbstractInterfaceConfig extends AbstractConfig {
private static final long serialVersionUID = 4776516803466933310L;
// 暴露、使用的协议,暴露可以使用多种协议,但client只能用一种协议进行访问,原因是便于client的管理
protected List<ProtocolConfig> protocols;
// 注册中心的配置列表
protected List<RegistryConfig> registries;
// 扩展配置点
protected ExtConfig extConfig;
// 应用名称
protected String application;
// 模块名称
protected String module;
// 分组
protected String group;
// 服务版本
protected String version;
// 代理类型
protected String proxy;
// 过滤器
protected String filter;
// 最大并发调用
protected Integer actives;
// 是否异步
protected Boolean async;
// 服务接口的失败mock实现类名
protected String mock;
// 是否共享 channel
protected Boolean shareChannel;
// if throw exception when call failure,the default value is ture
protected Boolean throwException;
// 请求超时时间
protected Integer requestTimeout;
// 是否注册
protected Boolean register;
// 是否记录访问日志,true记录,false不记录
protected String accessLog;
// 是否进行check,如果为true,则在监测失败后抛异常
protected String check;
// 重试次数
protected Integer retries;
// 是否开启gzip压缩
protected Boolean usegz;
// 进行gzip压缩的最小阈值,usegz开启,且大于此值时才进行gzip压缩。单位Byte
protected Integer mingzSize;
protected String codec;
public Integer getRetries() {
return retries;
}
protected String localServiceAddress;
public void setRetries(Integer retries) {
this.retries = retries;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getProxy() {
return proxy;
}
public void setProxy(String proxy) {
this.proxy = proxy;
}
public String getFilter() {
return filter;
}
public void setFilter(String filter) {
this.filter = filter;
}
public String getApplication() {
return application;
}
public void setApplication(String application) {
this.application = application;
}
public String getModule() {
return module;
}
public void setModule(String module) {
this.module = module;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public String getAccessLog() {
return accessLog;
}
public void setAccessLog(String accessLog) {
this.accessLog = accessLog;
}
public List<RegistryConfig> getRegistries() {
return registries;
}
public void setRegistries(List<RegistryConfig> registries) {
this.registries = registries;
}
public ExtConfig getExtConfig() {
return extConfig;
}
public void setExtConfig(ExtConfig extConfig) {
this.extConfig = extConfig;
}
public void setRegistry(RegistryConfig registry) {
this.registries = Collections.singletonList(registry);
}
public Integer getActives() {
return actives;
}
public void setActives(Integer actives) {
this.actives = actives;
}
public Boolean getAsync() {
return async;
}
public void setAsync(Boolean async) {
this.async = async;
}
public String getMock() {
return mock;
}
public void setMock(String mock) {
this.mock = mock;
}
public String getCheck() {
return check;
}
public void setCheck(String check) {
this.check = check;
}
@Deprecated
public void setCheck(Boolean check) {
this.check = String.valueOf(check);
}
public Boolean getShareChannel() {
return shareChannel;
}
public void setShareChannel(Boolean shareChannel) {
this.shareChannel = shareChannel;
}
public List<ProtocolConfig> getProtocols() {
return protocols;
}
public void setProtocols(List<ProtocolConfig> protocols) {
this.protocols = protocols;
}
public void setProtocol(ProtocolConfig protocol) {
this.protocols = Collections.singletonList(protocol);
}
public Boolean getThrowException() {
return throwException;
}
public void setThrowException(Boolean throwException) {
this.throwException = throwException;
}
public Integer getRequestTimeout() {
return requestTimeout;
}
public void setRequestTimeout(Integer requestTimeout) {
this.requestTimeout = requestTimeout;
}
public boolean hasProtocol() {
return this.protocols != null && !this.protocols.isEmpty();
}
public Boolean getRegister() {
return register;
}
public void setRegister(Boolean register) {
this.register = register;
}
public String getLocalServiceAddress() {
return localServiceAddress;
}
public void setLocalServiceAddress(String localServiceAddress) {
this.localServiceAddress = localServiceAddress;
}
public Boolean getUsegz() {
return usegz;
}
public void setUsegz(Boolean usegz) {
this.usegz = usegz;
}
public Integer getMingzSize() {
return mingzSize;
}
public void setMingzSize(Integer mingzSize) {
this.mingzSize = mingzSize;
}
public String getCodec() {
return codec;
}
public void setCodec(String codec) {
this.codec = codec;
}
protected List<URL> loadRegistryUrls() {
List<URL> registryList = new ArrayList<URL>();
if (registries != null && !registries.isEmpty()) {
for (RegistryConfig config : registries) {
String address = config.getAddress();
if (StringUtils.isBlank(address)) {
address = NetUtils.LOCALHOST + ":" + MotanConstants.DEFAULT_INT_VALUE;
}
Map<String, String> map = new HashMap<String, String>();
config.appendConfigParams(map);
map.put(URLParamType.application.getName(), getApplication());
map.put(URLParamType.path.getName(), RegistryService.class.getName());
map.put(URLParamType.refreshTimestamp.getName(), String.valueOf(System.currentTimeMillis()));
// 设置默认的registry protocol,parse完protocol后,需要去掉该参数
if (!map.containsKey(URLParamType.protocol.getName())) {
if (address.contains("://")) {
map.put(URLParamType.protocol.getName(), address.substring(0, address.indexOf("://")));
}
map.put(URLParamType.protocol.getName(), MotanConstants.REGISTRY_PROTOCOL_LOCAL);
}
// address内部可能包含多个注册中心地址
List<URL> urls = UrlUtils.parseURLs(address, map);
if (urls != null && !urls.isEmpty()) {
for (URL url : urls) {
url.removeParameter(URLParamType.protocol.getName());
registryList.add(url);
}
}
}
}
return registryList;
}
protected void checkInterfaceAndMethods(Class<?> interfaceClass, List<MethodConfig> methods) {
if (interfaceClass == null) {
throw new IllegalStateException("interface not allow null!");
}
if (!interfaceClass.isInterface()) {
throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
}
// 检查方法是否在接口中存在
if (methods != null && !methods.isEmpty()) {
for (MethodConfig methodBean : methods) {
String methodName = methodBean.getName();
if (methodName == null || methodName.length() == 0) {
throw new IllegalStateException("<motan:method> name attribute is required! Please check: <motan:service interface=\""
+ interfaceClass.getName() + "\" ... ><motan:method name=\"\" ... /></<motan:referer>");
}
java.lang.reflect.Method hasMethod = null;
for (java.lang.reflect.Method method : interfaceClass.getMethods()) {
if (method.getName().equals(methodName)) {
if (methodBean.getArgumentTypes() != null
&& ReflectUtil.getMethodParamDesc(method).equals(methodBean.getArgumentTypes())) {
hasMethod = method;
break;
}
if (methodBean.getArgumentTypes() != null) {
continue;
}
if (hasMethod != null) {
throw new MotanFrameworkException("The interface " + interfaceClass.getName() + " has more than one method "
+ methodName + " , must set argumentTypes attribute.", MotanErrorMsgConstant.FRAMEWORK_INIT_ERROR);
}
hasMethod = method;
}
}
if (hasMethod == null) {
throw new MotanFrameworkException("The interface " + interfaceClass.getName() + " not found method " + methodName,
MotanErrorMsgConstant.FRAMEWORK_INIT_ERROR);
}
methodBean.setArgumentTypes(ReflectUtil.getMethodParamDesc(hasMethod));
}
}
}
protected String getLocalHostAddress(List<URL> registryURLs) {
String localAddress = null;
Map<String, Integer> regHostPorts = new HashMap<String, Integer>();
for (URL ru : registryURLs) {
if (StringUtils.isNotBlank(ru.getHost()) && ru.getPort() > 0) {
regHostPorts.put(ru.getHost(), ru.getPort());
}
}
InetAddress address = NetUtils.getLocalAddress(regHostPorts);
if (address != null) {
localAddress = address.getHostAddress();
}
if (NetUtils.isValidLocalHost(localAddress)) {
return localAddress;
}
throw new MotanServiceException("Please config local server hostname with intranet IP first!",
MotanErrorMsgConstant.FRAMEWORK_INIT_ERROR);
}
protected void initLocalAppInfo(URL localUrl) {
ApplicationInfo.addService(localUrl);
}
}