Java tutorial
/* * 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 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.MotanFrameworkException; import com.weibo.api.motan.exception.MotanServiceException; import com.weibo.api.motan.rpc.*; import com.weibo.api.motan.serialize.DeserializableObject; import com.weibo.api.motan.switcher.Switcher; import com.weibo.api.motan.switcher.SwitcherService; import com.weibo.api.motan.util.*; import org.apache.commons.lang3.StringUtils; import java.io.IOException; 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; /** * @param <T> * @author maijunsheng */ 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(); } if ("equals".equals(method.getName())) { return proxyEquals(args[0]); } 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); RpcContext curContext = RpcContext.getContext(); Map<String, String> attachments = curContext.getRpcAttachments(); if (!attachments.isEmpty()) { // set rpccontext attachments to request for (Map.Entry<String, String> entry : attachments.entrySet()) { request.setAttachment(entry.getKey(), entry.getValue()); } } if (StringUtils.isNotBlank(curContext.getClientRequestId())) {// add to attachment if client request id is set request.setAttachment(URLParamType.requestIdFromClient.getName(), curContext.getClientRequestId()); } // referer?protocolA,B,C // ?AA?BB?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()); // clientapplicationmodule request.setAttachment(URLParamType.application.getName(), cluster.getUrl().getApplication()); request.setAttachment(URLParamType.module.getName(), cluster.getUrl().getModule()); Response response = null; boolean throwException = Boolean.parseBoolean(cluster.getUrl() .getParameter(URLParamType.throwException.getName(), URLParamType.throwException.getValue())); Class returnType = getRealReturnType(async, this.clz, method, methodName); try { response = cluster.call(request); if (async) { if (response instanceof ResponseFuture) { ((ResponseFuture) response).setReturnType(returnType); return response; } else { ResponseFuture responseFuture = new DefaultResponseFuture(request, 0, cluster.getUrl()); if (response.getException() != null) { responseFuture.onFailure(response); } else { responseFuture.onSuccess(response); } responseFuture.setReturnType(returnType); return responseFuture; } } else { Object value = response.getValue(); if (value != null && value instanceof DeserializableObject) { try { value = ((DeserializableObject) value).deserialize(returnType); } catch (IOException e) { LoggerUtil.error("deserialize response value fail! deserialize type:" + returnType, e); throw new MotanFrameworkException( "deserialize return value fail! deserialize type:" + returnType, e); } } return value; } } catch (RuntimeException e) { if (ExceptionUtil.isBizException(e)) { Throwable t = e.getCause(); // ?ExceptionError if (t != null && t instanceof Exception) { throw t; } else { String msg = t == null ? "biz exception cause is null. origin error msg : " + e.getMessage() : ("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(returnType); } 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()); List<Referer<T>> referers = cluster.getReferers(); if (referers != null) { for (Referer<T> refer : referers) { sb.append("[").append(refer.getUrl().toSimpleString()).append(", available:") .append(refer.isAvailable()).append("]"); } } sb.append("}"); } return sb.toString(); } private Class<?> getRealReturnType(boolean asyncCall, Class<?> clazz, Method method, String methodName) { if (asyncCall) { try { Method m = clazz.getMethod(methodName, method.getParameterTypes()); return m.getReturnType(); } catch (Exception e) { LoggerUtil.warn("RefererInvocationHandler get real return type fail. err:" + e.getMessage()); return method.getReturnType(); } } else { return method.getReturnType(); } } private Object getDefaultReturnValue(Class<?> returnType) { if (returnType != null && returnType.isPrimitive()) { return PrimitiveDefault.getDefaultReturnValue(returnType); } return null; } private boolean proxyEquals(Object o) { if (o == null || this.clusters == null) { return false; } if (o instanceof List) { return this.clusters == o; } else { return o.equals(this.clusters); } } 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); } } }