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.protocol.rpc; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInput; import java.io.ObjectOutput; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import org.apache.commons.lang3.StringUtils; import com.weibo.api.motan.codec.AbstractCodec; import com.weibo.api.motan.codec.Serialization; 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.core.extension.SpiMeta; import com.weibo.api.motan.exception.MotanErrorMsgConstant; import com.weibo.api.motan.exception.MotanFrameworkException; import com.weibo.api.motan.rpc.DefaultRequest; import com.weibo.api.motan.rpc.DefaultResponse; import com.weibo.api.motan.rpc.Provider; import com.weibo.api.motan.rpc.Request; import com.weibo.api.motan.rpc.Response; import com.weibo.api.motan.transport.Channel; import com.weibo.api.motan.transport.support.DefaultRpcHeartbeatFactory; import com.weibo.api.motan.util.ByteUtil; import com.weibo.api.motan.util.ConcurrentHashSet; import com.weibo.api.motan.util.ExceptionUtil; import com.weibo.api.motan.util.LoggerUtil; import com.weibo.api.motan.util.MotanDigestUtil; import com.weibo.api.motan.util.MotanFrameworkUtil; import com.weibo.api.motan.util.MotanSwitcherUtil; import com.weibo.api.motan.util.ReflectUtil; /** * ??codec??gzip * * @author zhanglei * */ @SpiMeta(name = "compressMotan") public class CompressRpcCodec extends AbstractCodec { private static final short MAGIC = (short) 0xF0F0; private static final byte MASK = 0x07; // ????decode requestserver private static ConcurrentHashMap<String, MethodInfo> SIGN_METHOD_MAP = new ConcurrentHashMap<String, MethodInfo>(); // ???? private static ConcurrentHashMap<String, String> METHOD_SIGN_MAP = new ConcurrentHashMap<String, String>(); // ???attachmentapplication?decode requestserver private static ConcurrentHashMap<String, AttachmentInfo> SIGN_ATTACHMENT_MAP = new ConcurrentHashMap<String, AttachmentInfo>(); private static ConcurrentHashSet<String> ACCEPT_ATTACHMENT_SIGN = new ConcurrentHashSet<String>();// ?serverattachment??? // clientserver????? private static final String SIGN_FLAG = "1";// ???? // attachmentkey_ private static final String ATTACHMENT_SIGN = "_A";// attachment????key?server???key private static final String UN_ATTACHMENT_SIGN = "_UA";// server???key private static final String CLIENT_REQUESTID = "_RID";// client requestidkey public static final String CODEC_VERSION_SWITCHER = "feature.motanrpc.codecversion.degrade";// codec?falsetruev1? public static final String GROUP_CODEC_VERSION_SWITCHER = "feature.motanrpc.codecversion.groupdegrade.";// group?codec?falsetruev1? private DefaultRpcCodec v1Codec = new DefaultRpcCodec(); static { LoggerUtil.info("init compress codec"); MotanSwitcherUtil.initSwitcher(CODEC_VERSION_SWITCHER, false); } @Override public byte[] encode(Channel channel, Object message) throws IOException { if (needEncodeV1(message)) { return v1Codec.encode(channel, message); } else { // v2 return encodeV2(channel, message); } } // v1???clientv1?v1? private boolean needEncodeV1(Object message) { if (MotanSwitcherUtil.isOpen(CODEC_VERSION_SWITCHER)) { return true; } if (message instanceof Request) { // ? if (DefaultRpcHeartbeatFactory.isHeartbeatRequest(message)) { return true; } // ??? String group = MotanFrameworkUtil.getGroupFromRequest((Request) message); if (MotanSwitcherUtil.switcherIsOpenWithDefault(GROUP_CODEC_VERSION_SWITCHER + group, false)) { return true; } } return message instanceof Response && ((Response) message).getRpcProtocolVersion() == RpcProtocolVersion.VERSION_1.getVersion(); } /** * decode data * * <pre> * client??serverresponse or exception * server: ??clientrequest * </pre> * * @param data * @return * @throws IOException */ @Override public Object decode(Channel channel, String remoteIp, byte[] data) throws IOException { if (MotanSwitcherUtil.isOpen(CODEC_VERSION_SWITCHER)) { // ?v1codec return v1Codec.decode(channel, remoteIp, data); } else { if (data.length <= 3) { throw new MotanFrameworkException("decode error: format problem", MotanErrorMsgConstant.FRAMEWORK_DECODE_ERROR); } // ??v1v2 if (data[2] == RpcProtocolVersion.VERSION_1.getVersion()) { return v1Codec.decode(channel, remoteIp, data); } else if (data[2] == RpcProtocolVersion.VERSION_2.getVersion()) { // v2 return decodeV2(channel, remoteIp, data); } else { throw new MotanFrameworkException("decode error: version error. version=" + data[2], MotanErrorMsgConstant.FRAMEWORK_DECODE_ERROR); } } } public byte[] encodeV2(Channel channel, Object message) throws IOException { try { if (message instanceof Request) { return encodeRequest(channel, (Request) message); } else if (message instanceof Response) { return encodeResponse(channel, (Response) message); } } catch (Exception e) { if (ExceptionUtil.isMotanException(e)) { throw (RuntimeException) e; } else { throw new MotanFrameworkException("encode error: isResponse=" + (message instanceof Response), e, MotanErrorMsgConstant.FRAMEWORK_ENCODE_ERROR); } } throw new MotanFrameworkException("encode error: message type not support, " + message.getClass(), MotanErrorMsgConstant.FRAMEWORK_ENCODE_ERROR); } /** * decode data * * <pre> * client??serverresponse or exception * server: ??clientrequest * </pre> * * @param data * @return * @throws IOException */ public Object decodeV2(Channel channel, String remoteIp, byte[] data) throws IOException { if (data.length <= RpcProtocolVersion.VERSION_2.getHeaderLength()) { throw new MotanFrameworkException("decode error: format problem", MotanErrorMsgConstant.FRAMEWORK_DECODE_ERROR); } short type = ByteUtil.bytes2short(data, 0); if (type != MAGIC) { throw new MotanFrameworkException("decode error: magic error", MotanErrorMsgConstant.FRAMEWORK_DECODE_ERROR); } int bodyLength = ByteUtil.bytes2int(data, 12); if (RpcProtocolVersion.VERSION_2.getHeaderLength() + bodyLength != data.length) { throw new MotanFrameworkException("decode error: content length error", MotanErrorMsgConstant.FRAMEWORK_DECODE_ERROR); } byte flag = data[3]; byte dataType = (byte) (flag & MASK); boolean isResponse = (dataType != MotanConstants.FLAG_REQUEST); byte[] body = new byte[bodyLength]; System.arraycopy(data, RpcProtocolVersion.VERSION_1.getHeaderLength(), body, 0, bodyLength); long requestId = ByteUtil.bytes2long(data, 4); Serialization serialization = ExtensionLoader.getExtensionLoader(Serialization.class).getExtension( channel.getUrl().getParameter(URLParamType.serialize.getName(), URLParamType.serialize.getValue())); try { if (isResponse) { return decodeResponse(body, dataType, requestId, data[2], serialization); } else { return decodeRequest(body, requestId, remoteIp, serialization); } } catch (ClassNotFoundException e) { throw new MotanFrameworkException( "decode " + (isResponse ? "response" : "request") + " error: class not found", e, MotanErrorMsgConstant.FRAMEWORK_DECODE_ERROR); } catch (Exception e) { if (ExceptionUtil.isMotanException(e)) { throw (RuntimeException) e; } else { throw new MotanFrameworkException("decode error: isResponse=" + isResponse, e, MotanErrorMsgConstant.FRAMEWORK_DECODE_ERROR); } } } /** * request body ? * * <pre> * * body: * * byte[] data : * * serialize(interface_name, method_name, method_param_desc, method_param_value, attachments_size, attachments_value) * * method_param_desc: for_each (string.append(method_param_interface_name)) * * method_param_value: for_each (method_param_name, method_param_value) * * attachments_value: for_each (attachment_name, attachment_value) * * </pre> * * @param request * @return * @throws IOException */ private byte[] encodeRequest(Channel channel, Request request) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ObjectOutput output = createOutput(outputStream); addMethodInfo(output, request); Serialization serialization = ExtensionLoader.getExtensionLoader(Serialization.class).getExtension( channel.getUrl().getParameter(URLParamType.serialize.getName(), URLParamType.serialize.getValue())); if (request.getArguments() != null && request.getArguments().length > 0) { for (Object obj : request.getArguments()) { serialize(output, obj, serialization); } } if (request.getAttachments() == null || request.getAttachments().isEmpty()) { // empty attachments output.writeShort(0); } else { // ?copyattachment????request??? Map<String, String> attachments = copyMap(request.getAttachments()); replaceAttachmentParamsBySign(channel, attachments); addAttachment(output, attachments); } output.flush(); byte[] body = outputStream.toByteArray(); byte flag = MotanConstants.FLAG_REQUEST; output.close(); Boolean usegz = channel.getUrl().getBooleanParameter(URLParamType.usegz.getName(), URLParamType.usegz.getBooleanValue()); int minGzSize = channel.getUrl().getIntParameter(URLParamType.mingzSize.getName(), URLParamType.mingzSize.getIntValue()); return encode(compress(body, usegz, minGzSize), flag, request.getRequestId()); } private Map<String, String> copyMap(Map<String, String> attachments) { Map<String, String> resultMap = new HashMap<String, String>(); for (Map.Entry<String, String> entry : attachments.entrySet()) { resultMap.put(entry.getKey(), entry.getValue()); } return resultMap; } /** * ??? * * @param output * @param request * @throws IOException */ private void addMethodInfo(ObjectOutput output, Request request) throws IOException { String methodInfoStr = MotanFrameworkUtil.getServiceKey(request) + request.getMethodName() + request.getParamtersDesc(); String methodSign = METHOD_SIGN_MAP.get(methodInfoStr); if (methodSign == null) { MethodInfo temp = new MethodInfo(MotanFrameworkUtil.getGroupFromRequest(request), request.getInterfaceName(), request.getMethodName(), request.getParamtersDesc(), MotanFrameworkUtil.getVersionFromRequest(request)); try { methodSign = temp.getSign(); METHOD_SIGN_MAP.putIfAbsent(methodInfoStr, methodSign); LoggerUtil.info("add method sign:" + methodSign + ", methodinfo:" + temp.toString()); } catch (Exception e) { LoggerUtil.warn("gen method sign fail!" + e.getMessage()); } } if (methodSign != null) { output.writeUTF(SIGN_FLAG);// ?? output.writeUTF(methodSign); } else {// ????? output.writeUTF(request.getInterfaceName()); output.writeUTF(request.getMethodName()); output.writeUTF(request.getParamtersDesc()); } } /** * ???Attachment?? * * @param attachments */ private void replaceAttachmentParamsBySign(Channel channel, Map<String, String> attachments) { // attachment????server????? AttachmentInfo info = getAttachmentInfoMap(attachments); if (info != null) { String sign = info.getAttachmetnSign(); if (sign != null) { attachments.put(ATTACHMENT_SIGN, sign); if (ACCEPT_ATTACHMENT_SIGN.contains(sign)) {// server?????application? removeAttachmentInfoMap(attachments); } } } // clientrequestid???key // ?????codec? String clientRequestid = attachments.get(URLParamType.requestIdFromClient.getName()); if (clientRequestid != null && !URLParamType.requestIdFromClient.getValue().equals(clientRequestid)) { attachments.put(CLIENT_REQUESTID, clientRequestid); } attachments.remove(URLParamType.requestIdFromClient.getName()); } private void addAttachment(ObjectOutput output, Map<String, String> attachments) throws IOException { output.writeShort(attachments.size()); for (Map.Entry<String, String> entry : attachments.entrySet()) { output.writeUTF(entry.getKey()); output.writeUTF(entry.getValue()); } } /** * response body ? * * <pre> * * body: * * byte[] : serialize (result) or serialize (exception) * * </pre> * * @param channel * @param value * @return * @throws IOException */ private byte[] encodeResponse(Channel channel, Response value) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ObjectOutput output = createOutput(outputStream); Serialization serialization = ExtensionLoader.getExtensionLoader(Serialization.class).getExtension( channel.getUrl().getParameter(URLParamType.serialize.getName(), URLParamType.serialize.getValue())); byte flag = 0; output.writeLong(value.getProcessTime()); if (value.getException() != null) { output.writeUTF(value.getException().getClass().getName()); serialize(output, value.getException(), serialization); flag = MotanConstants.FLAG_RESPONSE_EXCEPTION; } else if (value.getValue() == null) { flag = MotanConstants.FLAG_RESPONSE_VOID; } else { output.writeUTF(value.getValue().getClass().getName()); serialize(output, value.getValue(), serialization); // v2?responseattachment Map<String, String> attachments = value.getAttachments(); if (attachments != null) { String signed = attachments.get(ATTACHMENT_SIGN); String unSigned = attachments.get(UN_ATTACHMENT_SIGN); attachments.clear(); // attachment???? if (StringUtils.isNotBlank(signed)) { attachments.put(ATTACHMENT_SIGN, signed); } if (StringUtils.isNotBlank(unSigned)) { attachments.put(UN_ATTACHMENT_SIGN, unSigned); } } if (attachments != null && !attachments.isEmpty()) {// ?? addAttachment(output, attachments); } else { // empty attachments output.writeShort(0); } flag = MotanConstants.FLAG_RESPONSE_ATTACHMENT; // v2flag } output.flush(); byte[] body = outputStream.toByteArray(); output.close(); Boolean usegz = channel.getUrl().getBooleanParameter(URLParamType.usegz.getName(), URLParamType.usegz.getBooleanValue()); int minGzSize = channel.getUrl().getIntParameter(URLParamType.mingzSize.getName(), URLParamType.mingzSize.getIntValue()); return encode(compress(body, usegz, minGzSize), flag, value.getRequestId()); } /** * ??? * * <pre> * * header: 16 * * 0-15 bit : magic * 16-23 bit : version * 24-31 bit : extend flag , 29-30 bit: event ??4?eventnormal, exception, 31 bit : 0 is request , 1 is response * 32-95 bit : request id * 96-127 bit : body content length * * </pre> * * @param body * @param flag * @param requestId * @return * @throws IOException */ private byte[] encode(byte[] body, byte flag, long requestId) throws IOException { byte[] header = new byte[RpcProtocolVersion.VERSION_2.getHeaderLength()]; int offset = 0; // 0 - 15 bit : magic ByteUtil.short2bytes(MAGIC, header, offset); offset += 2; // 16 - 23 bit : version header[offset++] = RpcProtocolVersion.VERSION_2.getVersion(); // 24 - 31 bit : extend flag header[offset++] = flag; // 32 - 95 bit : requestId ByteUtil.long2bytes(requestId, header, offset); offset += 8; // 96 - 127 bit : body content length ByteUtil.int2bytes(body.length, header, offset); byte[] data = new byte[header.length + body.length]; System.arraycopy(header, 0, data, 0, header.length); System.arraycopy(body, 0, data, header.length, body.length); return data; } private Object decodeRequest(byte[] body, long requestId, String remoteIp, Serialization serialization) throws IOException, ClassNotFoundException { ObjectInput input = createInput(getInputStream(body)); String interfaceName = null; String methodName = null; String paramtersDesc = null; String group = null; String version = null; String flag = input.readUTF(); if (SIGN_FLAG.equals(flag)) {// ??? String sign = input.readUTF(); MethodInfo mInfo = SIGN_METHOD_MAP.get(sign); if (mInfo == null) { throw new MotanFrameworkException("decode error: invalid method sign: " + sign, MotanErrorMsgConstant.FRAMEWORK_DECODE_ERROR); } interfaceName = mInfo.getInterfaceName(); methodName = mInfo.getMethodName(); paramtersDesc = mInfo.getParamtersDesc(); group = mInfo.getGroup(); version = mInfo.getVersion(); } else { interfaceName = flag; methodName = input.readUTF(); paramtersDesc = input.readUTF(); } DefaultRequest rpcRequest = new DefaultRequest(); rpcRequest.setRequestId(requestId); rpcRequest.setInterfaceName(interfaceName); rpcRequest.setMethodName(methodName); rpcRequest.setParamtersDesc(paramtersDesc); rpcRequest.setArguments(decodeRequestParameter(input, paramtersDesc, serialization)); rpcRequest.setAttachments(decodeRequestAttachments(input)); rpcRequest.setRpcProtocolVersion(RpcProtocolVersion.VERSION_2.getVersion()); input.close(); Map<String, String> attachments = rpcRequest.getAttachments(); putSignedAttachment(attachments, remoteIp);// ???client? if (attachments.get(URLParamType.group.name()) == null) { // attachment sign?methodsigngroup? attachments.put(URLParamType.group.name(), group); attachments.put(URLParamType.version.name(), version); } return rpcRequest; } private void putSignedAttachment(Map<String, String> attachments, String remoteIp) { if (attachments != null && !attachments.isEmpty()) { AttachmentInfo info = getAttachmentInfoMap(attachments); if (info != null) {// clientapplication? String sign = attachments.get(ATTACHMENT_SIGN); if (StringUtils.isNotBlank(sign)) { SIGN_ATTACHMENT_MAP.put(remoteIp + sign, info); LoggerUtil .info("update attachment sign:" + remoteIp + sign + ", info-group:" + info.getGroup()); } } else {// ?? String sign = attachments.get(ATTACHMENT_SIGN); if (StringUtils.isNotBlank(sign)) { info = SIGN_ATTACHMENT_MAP.get(remoteIp + sign); if (info != null) { // ?requestattachment putAttachmentInfoMap(info, attachments); } else {// serversigninfo?client???info attachments.put(UN_ATTACHMENT_SIGN, sign); LoggerUtil.info("miss attachment sign:" + remoteIp + sign); } // repsponseATTACHMENT_SIGNserver? // clientattachmentinfo? attachments.remove(ATTACHMENT_SIGN); } else { LoggerUtil.warn("attachment sign is blankapplication info miss!"); } } // client requestid String clientRequestid = URLParamType.requestIdFromClient.getValue();// if (attachments.containsKey(CLIENT_REQUESTID)) { clientRequestid = attachments.get(CLIENT_REQUESTID); } attachments.put(URLParamType.requestIdFromClient.getName(), clientRequestid); } } private Object[] decodeRequestParameter(ObjectInput input, String parameterDesc, Serialization serialization) throws IOException, ClassNotFoundException { if (parameterDesc == null || parameterDesc.equals("")) { return null; } Class<?>[] classTypes = ReflectUtil.forNames(parameterDesc); Object[] paramObjs = new Object[classTypes.length]; for (int i = 0; i < classTypes.length; i++) { paramObjs[i] = deserialize((byte[]) input.readObject(), classTypes[i], serialization); } return paramObjs; } private Map<String, String> decodeRequestAttachments(ObjectInput input) throws IOException, ClassNotFoundException { int size = input.readShort(); if (size <= 0) { return null; } Map<String, String> attachments = new HashMap<String, String>(); for (int i = 0; i < size; i++) { attachments.put(input.readUTF(), input.readUTF()); } return attachments; } /** * * @param body * @param dataType * @param requestId * @param rpcProtocolVersion rpc?????????? * @param serialization * @return * @throws IOException * @throws ClassNotFoundException */ private Object decodeResponse(byte[] body, byte dataType, long requestId, byte rpcProtocolVersion, Serialization serialization) throws IOException, ClassNotFoundException { ObjectInput input = createInput(getInputStream(body)); long processTime = input.readLong(); DefaultResponse response = new DefaultResponse(); response.setRequestId(requestId); response.setProcessTime(processTime); if (dataType == MotanConstants.FLAG_RESPONSE_VOID) { return response; } String className = input.readUTF(); Class<?> clz = ReflectUtil.forName(className); Object result = deserialize((byte[]) input.readObject(), clz, serialization); if (dataType == MotanConstants.FLAG_RESPONSE) { response.setValue(result); } else if (dataType == MotanConstants.FLAG_RESPONSE_ATTACHMENT) { response.setValue(result); Map<String, String> attachment = decodeRequestAttachments(input); checkAttachment(attachment); } else if (dataType == MotanConstants.FLAG_RESPONSE_EXCEPTION) { response.setException((Exception) result); } else { throw new MotanFrameworkException("decode error: response dataType not support " + dataType, MotanErrorMsgConstant.FRAMEWORK_DECODE_ERROR); } response.setRequestId(requestId); input.close(); return response; } // repsonse?serversignserversign private void checkAttachment(Map<String, String> attachment) { if (attachment != null && !attachment.isEmpty()) { String acceptSign = attachment.get(ATTACHMENT_SIGN); if (StringUtils.isNotBlank(acceptSign)) {// attachment // signserver??attachment ACCEPT_ATTACHMENT_SIGN.add(acceptSign); } String notAcceptSign = attachment.get(UN_ATTACHMENT_SIGN); if (StringUtils.isNotBlank(notAcceptSign)) {// serversignattachment?? ACCEPT_ATTACHMENT_SIGN.remove(notAcceptSign); } } } // requestattachments?AttachmentInfonull private AttachmentInfo getAttachmentInfoMap(Map<String, String> attachments) { AttachmentInfo result = null; if (attachments != null && attachments.containsKey(URLParamType.application.name())) { String group = attachments.get(URLParamType.group.name()); String application = attachments.get(URLParamType.application.name()); String module = attachments.get(URLParamType.module.name()); String version = attachments.get(URLParamType.version.name()); result = new AttachmentInfo(group, application, module, version); } return result; } private void putAttachmentInfoMap(AttachmentInfo attachmentInfo, Map<String, String> attachments) { if (attachments != null) { attachments.put(URLParamType.group.name(), attachmentInfo.getGroup()); attachments.put(URLParamType.application.name(), attachmentInfo.getApplication()); attachments.put(URLParamType.module.name(), attachmentInfo.getModule()); attachments.put(URLParamType.version.name(), attachmentInfo.getVersion()); } } private void removeAttachmentInfoMap(Map<String, String> attachments) { if (attachments != null) { attachments.remove(URLParamType.group.name()); attachments.remove(URLParamType.application.name()); attachments.remove(URLParamType.module.name()); attachments.remove(URLParamType.version.name()); } } /** * ??gzip * * @param data * @return */ public static InputStream getInputStream(byte[] data) { InputStream ret = new ByteArrayInputStream(data); try { GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(data)); return gis; } catch (Exception ignore) { } return ret; } // rpc body public byte[] compress(byte[] org, boolean useGzip, int minGzSize) throws IOException { if (useGzip && org.length > minGzSize) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); GZIPOutputStream gos = new GZIPOutputStream(outputStream); gos.write(org); gos.finish(); gos.flush(); gos.close(); byte[] ret = outputStream.toByteArray(); return ret; } else { return org; } } public static void putMethodSign(Provider<?> provider, List<Method> methods) { String group = provider.getUrl().getGroup(); String interfaceName = provider.getInterface().getName(); String version = provider.getUrl().getVersion(); for (Method method : methods) { MethodInfo temp = new MethodInfo(group, interfaceName, method.getName(), ReflectUtil.getMethodParamDesc(method), version); String sign = temp.getSign(); MethodInfo priInfo = SIGN_METHOD_MAP.putIfAbsent(sign, temp); if (priInfo != null && !temp.equals(priInfo)) {// ??? throw new MotanFrameworkException( "add method sign conflict! " + temp.toString() + " with " + priInfo.toString(), MotanErrorMsgConstant.FRAMEWORK_DECODE_ERROR); } else { LoggerUtil.info("add method sign:" + sign + ", methodinfo:" + temp.toString()); } } } public static void putMethodSign(String methodSign, MethodInfo methodInfo) { SIGN_METHOD_MAP.putIfAbsent(methodSign, methodInfo); } static class MethodInfo { String group; String interfaceName; String methodName; String paramtersDesc; String version; public MethodInfo(String group, String interfaceName, String methodName, String paramtersDesc, String version) { super(); this.group = group; this.interfaceName = interfaceName; this.methodName = methodName; this.paramtersDesc = paramtersDesc; this.version = version; } /** * ????? ??? * * @return * @throws Exception */ public String getSign() { try { StringBuilder sb = new StringBuilder(); sb.append(group).append(interfaceName).append(methodName).append(paramtersDesc).append(version); String surfix = MotanDigestUtil.md5LowerCase(sb.toString()).substring(8, 20); // ?32?md58-20? int endIndex = methodName.length() > 4 ? 4 : methodName.length(); String prefix = methodName.substring(0, endIndex); return prefix + surfix; } catch (Exception e) { throw new MotanFrameworkException("gen method sign error! " + this.toString(), MotanErrorMsgConstant.FRAMEWORK_DECODE_ERROR); } } public String getGroup() { return group; } public void setGroup(String group) { this.group = group; } public String getInterfaceName() { return interfaceName; } public void setInterfaceName(String interfaceName) { this.interfaceName = interfaceName; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public String getParamtersDesc() { return paramtersDesc; } public void setParamtersDesc(String paramtersDesc) { this.paramtersDesc = paramtersDesc; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((group == null) ? 0 : group.hashCode()); result = prime * result + ((interfaceName == null) ? 0 : interfaceName.hashCode()); result = prime * result + ((methodName == null) ? 0 : methodName.hashCode()); result = prime * result + ((paramtersDesc == null) ? 0 : paramtersDesc.hashCode()); result = prime * result + ((version == null) ? 0 : version.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MethodInfo other = (MethodInfo) obj; if (group == null) { if (other.group != null) return false; } else if (!group.equals(other.group)) return false; if (interfaceName == null) { if (other.interfaceName != null) return false; } else if (!interfaceName.equals(other.interfaceName)) return false; if (methodName == null) { if (other.methodName != null) return false; } else if (!methodName.equals(other.methodName)) return false; if (paramtersDesc == null) { if (other.paramtersDesc != null) return false; } else if (!paramtersDesc.equals(other.paramtersDesc)) return false; if (version == null) { if (other.version != null) return false; } else if (!version.equals(other.version)) return false; return true; } @Override public String toString() { return "MethodInfo [group=" + group + ", interfaceName=" + interfaceName + ", methodName=" + methodName + ", paramtersDesc=" + paramtersDesc + ", version=" + version + "]"; } } static class AttachmentInfo { String group; String application; String module; String version; public AttachmentInfo(String group, String application, String module, String version) { super(); this.group = group; this.application = application; this.module = module; this.version = version; } public String getAttachmetnSign() { String signstr = group + application + module + version; String hashcodeStr = null; try { hashcodeStr = MotanDigestUtil.md5LowerCase(signstr).substring(8, 12); // ?md5 } catch (Exception e) { LoggerUtil.warn("getAttachmetnSign fail!" + e.getMessage()); } return hashcodeStr; } public String getGroup() { return group; } public String getApplication() { return application; } public String getModule() { return module; } public String getVersion() { return version; } } }