/** * $Id: RemotingCommand.java 1831 2013-05-16 01:39:51Z shijia.wxr $ */ package com.alibaba.rocketmq.remoting.protocol; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import com.alibaba.rocketmq.remoting.CommandCustomHeader; import com.alibaba.rocketmq.remoting.annotation.CFNotNull; import com.alibaba.rocketmq.remoting.exception.RemotingCommandException; import com.alibaba.rocketmq.remoting.protocol.RemotingProtos.CommandHeader; import com.alibaba.rocketmq.remoting.protocol.RemotingProtos.FlagBit; import com.alibaba.rocketmq.remoting.protocol.RemotingProtos.LanguageCode; import com.alibaba.rocketmq.remoting.protocol.RemotingProtos.NVPair; import com.alibaba.rocketmq.remoting.protocol.RemotingProtos.ResponseCode; import com.google.protobuf.InvalidProtocolBufferException; /** * RPC ����Ӧ������ * * @author vintage.wang@gmail.com shijia.wxr@taobao.com */ public class RemotingCommand { public static String RemotingVersionKey = "rocketmq.remoting.version"; private static volatile int ConfigVersion = -1; private static AtomicInteger RequestId = new AtomicInteger(0); /** * Header ���� */ private int code; private LanguageCode language = LanguageCode.JAVA; private int version = 0; private int opaque = RequestId.getAndIncrement(); private int flag = 0; private String remark; private List<NVPair> extFields; private CommandCustomHeader customHeader; /** * Body ���� */ private byte[] body; protected RemotingCommand() { } public static RemotingCommand createRequestCommand(int code, CommandCustomHeader customHeader) { RemotingCommand cmd = new RemotingCommand(); cmd.setCode(code); cmd.customHeader = customHeader; setCmdVersion(cmd); return cmd; } public static RemotingCommand createResponseCommand(Class<? extends CommandCustomHeader> classHeader) { RemotingCommand cmd = createResponseCommand(ResponseCode.SYSTEM_ERROR_VALUE, "not set any response code", classHeader); return cmd; } public static RemotingCommand createResponseCommand(int code, String remark) { return createResponseCommand(code, remark, null); } /** * ֻ��ͨ�Ų��ڲ�����ã�ҵ�񲻻���� */ public static RemotingCommand createResponseCommand(int code, String remark, Class<? extends CommandCustomHeader> classHeader) { RemotingCommand cmd = new RemotingCommand(); cmd.markResponseType(); cmd.setCode(code); cmd.setRemark(remark); setCmdVersion(cmd); if (classHeader != null) { try { CommandCustomHeader objectHeader = classHeader.newInstance(); cmd.customHeader = objectHeader; } catch (InstantiationException e) { return null; } catch (IllegalAccessException e) { return null; } } return cmd; } private static void setCmdVersion(RemotingCommand cmd) { if (ConfigVersion >= 0) { cmd.setVersion(ConfigVersion); } else { String v = System.getProperty(RemotingVersionKey); if (v != null) { int value = Integer.parseInt(v); cmd.setVersion(value); ConfigVersion = value; } } } private void makeCustomHeaderToNet() { if (this.customHeader != null) { Field[] fields = this.customHeader.getClass().getDeclaredFields(); this.extFields = new ArrayList<NVPair>(fields.length); for (Field field : fields) { if (!Modifier.isStatic(field.getModifiers())) { String name = field.getName(); if (!name.startsWith("this")) { Object value = null; try { field.setAccessible(true); value = field.get(this.customHeader); } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } if (value != null) { NVPair.Builder nvb = NVPair.newBuilder(); nvb.setName(name); nvb.setValue(value.toString()); this.extFields.add(nvb.build()); } } } } } } public CommandCustomHeader getCustomHeader() { return customHeader; } public CommandCustomHeader decodeCommandCustomHeader(Class<? extends CommandCustomHeader> classHeader) throws RemotingCommandException { if (this.extFields != null) { CommandCustomHeader objectHeader; try { objectHeader = classHeader.newInstance(); } catch (InstantiationException e) { return null; } catch (IllegalAccessException e) { return null; } for (NVPair nvp : this.extFields) { String name = nvp.getName(); String value = nvp.getValue(); try { Field field = objectHeader.getClass().getDeclaredField(name); field.setAccessible(true); String type = field.getType().getSimpleName(); Object valueParsed = null; if (type.equals("String")) { valueParsed = value; } else if (type.equals("Integer")) { valueParsed = Integer.parseInt(value); } else if (type.equals("Long")) { valueParsed = Long.parseLong(value); } else if (type.equals("Boolean")) { valueParsed = Boolean.parseBoolean(value); } else if (type.equals("Double")) { valueParsed = Double.parseDouble(value); } else if (type.equals("int")) { valueParsed = Integer.parseInt(value); } else if (type.equals("long")) { valueParsed = Long.parseLong(value); } else if (type.equals("boolean")) { valueParsed = Boolean.parseBoolean(value); } else if (type.equals("double")) { valueParsed = Double.parseDouble(value); } field.set(objectHeader, valueParsed); } catch (SecurityException e) { } catch (NoSuchFieldException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } } // ��鷵�ض����Ƿ���Ч Field[] fields = objectHeader.getClass().getDeclaredFields(); for (Field field : fields) { if (!Modifier.isStatic(field.getModifiers())) { String name = field.getName(); if (!name.startsWith("this")) { Object value = null; try { field.setAccessible(true); value = field.get(objectHeader); } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } // ��ֵ��� if (null == value) { Annotation[] ann = field.getAnnotations(); if (ann != null && ann.length > 0) { if (ann[0].annotationType().getSimpleName() .equalsIgnoreCase(CFNotNull.class.getSimpleName())) { throw new RemotingCommandException(name + " is null"); } } } } } } objectHeader.checkFields(); return objectHeader; } return null; } private CommandHeader buildHeader() { CommandHeader.Builder builder = CommandHeader.newBuilder(); builder.setCode(this.code); builder.setLanguage(this.language); builder.setVersion(this.version); builder.setOpaque(this.opaque); builder.setFlag(this.flag); if (this.remark != null) { builder.setRemark(this.remark); } // customHeader this.makeCustomHeaderToNet(); // extFields if (this.extFields != null) { int i = 0; for (NVPair nv : this.extFields) { builder.addExtFields(i++, nv); } } return builder.build(); } public ByteBuffer encode() { CommandHeader header = this.buildHeader(); // 1> header length size int length = 4; // 2> header data length byte[] headerData = header.toByteArray(); length += headerData.length; // 3> body data length if (this.body != null) { length += body.length; } ByteBuffer result = ByteBuffer.allocate(4 + length); // length result.putInt(length); // header length result.putInt(headerData.length); // header data result.put(headerData); // body data; if (this.body != null) { result.put(this.body); } result.flip(); return result; } public ByteBuffer encodeHeader() { return encodeHeader(this.body != null ? this.body.length : 0); } /** * ֻ���Header��body���ֶ������� */ public ByteBuffer encodeHeader(final int bodyLength) { CommandHeader header = this.buildHeader(); // 1> header length size int length = 4; // 2> header data length byte[] headerData = header.toByteArray(); length += headerData.length; // 3> body data length length += bodyLength; ByteBuffer result = ByteBuffer.allocate(4 + length - bodyLength); // length result.putInt(length); // header length result.putInt(headerData.length); // header data result.put(headerData); result.flip(); return result; } public static RemotingCommand decode(final byte[] array) throws InvalidProtocolBufferException { ByteBuffer byteBuffer = ByteBuffer.wrap(array); return decode(byteBuffer); } public static RemotingCommand decode(final ByteBuffer byteBuffer) throws InvalidProtocolBufferException { int length = byteBuffer.limit(); int headerLength = byteBuffer.getInt(); byte[] headerData = new byte[headerLength]; byteBuffer.get(headerData); int bodyLength = length - 4 - headerLength; byte[] bodyData = null; if (bodyLength > 0) { bodyData = new byte[bodyLength]; byteBuffer.get(bodyData); } RemotingCommand cmd = new RemotingCommand(); CommandHeader header = CommandHeader.parseFrom(headerData); cmd.code = header.getCode(); cmd.language = header.getLanguage(); cmd.version = header.getVersion(); cmd.opaque = header.getOpaque(); cmd.flag = header.getFlag(); if (header.hasRemark()) cmd.remark = header.getRemark(); cmd.extFields = header.getExtFieldsList(); cmd.body = bodyData; return cmd; } public void markResponseType() { int bits = 1 << FlagBit.RPC_TYPE_VALUE; this.flag |= bits; } public boolean isResponseType() { int bits = 1 << FlagBit.RPC_TYPE_VALUE; return (this.flag & bits) == bits; } public void markOnewayRPC() { int bits = 1 << FlagBit.RPC_ONEWAY_VALUE; this.flag |= bits; } public boolean isOnewayRPC() { int bits = 1 << FlagBit.RPC_ONEWAY_VALUE; return (this.flag & bits) == bits; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public RemotingCommandType getType() { if (this.isResponseType()) { return RemotingCommandType.RESPONSE_COMMAND; } return RemotingCommandType.REQUEST_COMMAND; } public LanguageCode getLanguage() { return language; } public void setLanguage(LanguageCode language) { this.language = language; } public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } public int getOpaque() { return opaque; } public void setOpaque(int opaque) { this.opaque = opaque; } public int getFlag() { return flag; } public void setFlag(int flag) { this.flag = flag; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public byte[] getBody() { return body; } public void setBody(byte[] body) { this.body = body; } public List<NVPair> getExtFields() { return extFields; } public void setExtFields(List<NVPair> extFields) { this.extFields = extFields; } @Override public String toString() { return "RemotingCommand [code=" + code + ", language=" + language + ", version=" + version + ", opaque=" + opaque + ", flag(B)=" + Integer.toBinaryString(flag) + ", remark=" + remark + ", extFields=" + extFields + "]"; } // public CommandCustomHeader getCustomHeader() { // return customHeader; // } // // // public void setCustomHeader(CommandCustomHeader customHeader) { // this.customHeader = customHeader; // } }