/*
* 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.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.weibo.api.motan.cluster.Cluster;
import com.weibo.api.motan.common.MotanConstants;
import com.weibo.api.motan.common.URLParamType;
import com.weibo.api.motan.core.extension.ExtensionLoader;
import com.weibo.api.motan.exception.MotanErrorMsgConstant;
import com.weibo.api.motan.exception.MotanServiceException;
import com.weibo.api.motan.rpc.ApplicationInfo;
import com.weibo.api.motan.rpc.DefaultRequest;
import com.weibo.api.motan.rpc.Referer;
import com.weibo.api.motan.rpc.Response;
import com.weibo.api.motan.rpc.ResponseFuture;
import com.weibo.api.motan.rpc.RpcContext;
import com.weibo.api.motan.switcher.Switcher;
import com.weibo.api.motan.switcher.SwitcherService;
import com.weibo.api.motan.util.ExceptionUtil;
import com.weibo.api.motan.util.LoggerUtil;
import com.weibo.api.motan.util.MotanFrameworkUtil;
import com.weibo.api.motan.util.ReflectUtil;
import com.weibo.api.motan.util.RequestIdGenerator;
/**
*
* @author maijunsheng
*
* @param <T>
*/
public class RefererInvocationHandler<T> implements InvocationHandler {
private List<Cluster<T>> clusters;
private Class<T> clz;
private SwitcherService switcherService = null;
private String interfaceName;
public RefererInvocationHandler(Class<T> clz, Cluster<T> cluster) {
this.clz = clz;
this.clusters = new ArrayList<Cluster<T>>(1);
this.clusters.add(cluster);
init();
}
public RefererInvocationHandler(Class<T> clz, List<Cluster<T>> clusters) {
this.clz = clz;
this.clusters = clusters;
init();
}
private void init() {
// clusters 不应该为空
String switchName =
this.clusters.get(0).getUrl().getParameter(URLParamType.switcherService.getName(), URLParamType.switcherService.getValue());
switcherService = ExtensionLoader.getExtensionLoader(SwitcherService.class).getExtension(switchName);
interfaceName = MotanFrameworkUtil.removeAsyncSuffix(clz.getName());
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (isLocalMethod(method)) {
if ("toString".equals(method.getName())) {
return clustersToString();
}
throw new MotanServiceException("can not invoke local method:" + method.getName());
}
DefaultRequest request = new DefaultRequest();
request.setRequestId(RequestIdGenerator.getRequestId());
request.setArguments(args);
String methodName = method.getName();
boolean async = false;
if (methodName.endsWith(MotanConstants.ASYNC_SUFFIX) && method.getReturnType().equals(ResponseFuture.class)) {
methodName = MotanFrameworkUtil.removeAsyncSuffix(methodName);
async = true;
}
RpcContext.getContext().putAttribute(MotanConstants.ASYNC_SUFFIX, async);
request.setMethodName(methodName);
request.setParamtersDesc(ReflectUtil.getMethodParamDesc(method));
request.setInterfaceName(interfaceName);
request.setAttachment(URLParamType.requestIdFromClient.getName(), String.valueOf(RequestIdGenerator.getRequestIdFromClient()));
// 当 referer配置多个protocol的时候,比如A,B,C,
// 那么正常情况下只会使用A,如果A被开关降级,那么就会使用B,B也被降级,那么会使用C
for (Cluster<T> cluster : clusters) {
String protocolSwitcher = MotanConstants.PROTOCOL_SWITCHER_PREFIX + cluster.getUrl().getProtocol();
Switcher switcher = switcherService.getSwitcher(protocolSwitcher);
if (switcher != null && !switcher.isOn()) {
continue;
}
request.setAttachment(URLParamType.version.getName(), cluster.getUrl().getVersion());
request.setAttachment(URLParamType.clientGroup.getName(), cluster.getUrl().getGroup());
// 带上client的application和module
request.setAttachment(URLParamType.application.getName(), ApplicationInfo.getApplication(cluster.getUrl()).getApplication());
request.setAttachment(URLParamType.module.getName(), ApplicationInfo.getApplication(cluster.getUrl()).getModule());
Response response = null;
boolean throwException =
Boolean.parseBoolean(cluster.getUrl().getParameter(URLParamType.throwException.getName(),
URLParamType.throwException.getValue()));
try {
response = cluster.call(request);
if (async && response instanceof ResponseFuture) {
return response;
} else {
return response.getValue();
}
} catch (RuntimeException e) {
if (ExceptionUtil.isBizException(e)) {
Throwable t = e.getCause();
// 只抛出Exception,防止抛出远程的Error
if (t != null && t instanceof Exception) {
throw t;
} else {
String msg =
t == null ? "biz exception cause is null" : ("biz exception cause is throwable error:" + t.getClass()
+ ", errmsg:" + t.getMessage());
throw new MotanServiceException(msg, MotanErrorMsgConstant.SERVICE_DEFAULT_ERROR);
}
} else if (!throwException) {
LoggerUtil.warn("RefererInvocationHandler invoke false, so return default value: uri=" + cluster.getUrl().getUri()
+ " " + MotanFrameworkUtil.toString(request), e);
return getDefaultReturnValue(method.getReturnType());
} else {
LoggerUtil.error(
"RefererInvocationHandler invoke Error: uri=" + cluster.getUrl().getUri() + " "
+ MotanFrameworkUtil.toString(request), e);
throw e;
}
}
}
throw new MotanServiceException("Referer call Error: cluster not exist, interface=" + clz.getName() + " "
+ MotanFrameworkUtil.toString(request), MotanErrorMsgConstant.SERVICE_UNFOUND);
}
/**
* tostring,equals,hashCode,finalize等接口未声明的方法不进行远程调用
* @param method
* @return
*/
public boolean isLocalMethod(Method method){
if(method.getDeclaringClass().equals(Object.class)){
try{
Method interfaceMethod = clz.getDeclaredMethod(method.getName(), method.getParameterTypes());
return false;
}catch(Exception e){
return true;
}
}
return false;
}
private String clustersToString(){
StringBuilder sb = new StringBuilder();
for(Cluster<T> cluster: clusters){
sb.append("{protocol:").append(cluster.getUrl().getProtocol());
for(Referer<T> refer : (List<Referer<T>>)cluster.getReferers()){
sb.append("[").append(refer.getUrl().toSimpleString()).append(", available:").append(refer.isAvailable()).append("]");
}
sb.append("}");
}
return sb.toString();
}
private Object getDefaultReturnValue(Class<?> returnType) {
if (returnType != null && returnType.isPrimitive()) {
return PrimitiveDefault.getDefaultReturnValue(returnType);
}
return null;
}
private static class PrimitiveDefault {
private static boolean defaultBoolean;
private static char defaultChar;
private static byte defaultByte;
private static short defaultShort;
private static int defaultInt;
private static long defaultLong;
private static float defaultFloat;
private static double defaultDouble;
private static Map<Class<?>, Object> primitiveValues = new HashMap<Class<?>, Object>();
static {
primitiveValues.put(boolean.class, defaultBoolean);
primitiveValues.put(char.class, defaultChar);
primitiveValues.put(byte.class, defaultByte);
primitiveValues.put(short.class, defaultShort);
primitiveValues.put(int.class, defaultInt);
primitiveValues.put(long.class, defaultLong);
primitiveValues.put(float.class, defaultFloat);
primitiveValues.put(double.class, defaultDouble);
}
public static Object getDefaultReturnValue(Class<?> returnType) {
return primitiveValues.get(returnType);
}
}
}