package code.google.nfs.rpc.protocol; /** * nfs-rpc * Apache License * * http://code.google.com/p/nfs-rpc (c) 2011 */ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import code.google.nfs.rpc.Codecs; import code.google.nfs.rpc.RequestWrapper; import code.google.nfs.rpc.ResponseWrapper; /** * Protocol Header * VERSION(1B): Protocol Version * TYPE(1B): Protocol Type,so u can custom your protocol * Simple Processor Protocol * VERSION(1B): * TYPE(1B): request/response * CODECTYPE(1B): serialize/deserialize type * KEEPED(1B): * KEEPED(1B): * KEEPED(1B): * ID(4B): request id * TIMEOUT(4B): request timeout * BodyClassNameLen(4B): body className Len * LENGTH(4B): body length * BodyClassName: if need than set * BODY * * @author <a href="mailto:bluedavy@gmail.com">bluedavy</a> */ public class SimpleProcessorProtocol implements Protocol{ public static final int TYPE = 2; private static final Log LOGGER = LogFactory.getLog(SimpleProcessorProtocol.class); private static final int CUSTOMPROTOCOL_HEADER_LEN = 1 * 6 + 4 * 4; private static final byte VERSION = (byte)1; private static final byte REQUEST = (byte)0; private static final byte RESPONSE = (byte)1; public ByteBufferWrapper encode(Object message,ByteBufferWrapper bytebufferWrapper) throws Exception{ if(!(message instanceof RequestWrapper) && !(message instanceof ResponseWrapper)){ throw new Exception("only support send RequestWrapper && ResponseWrapper"); } int id = 0; byte type = REQUEST; byte[] body = null; int timeout = 0; int codecType = 0; byte[] className = null; if(message instanceof RequestWrapper){ try{ RequestWrapper wrapper = (RequestWrapper) message; codecType = wrapper.getCodecType(); body = Codecs.getEncoder(codecType).encode(wrapper.getMessage()); id = wrapper.getId(); timeout = wrapper.getTimeout(); if(codecType == Codecs.PB_CODEC) className = wrapper.getMessage().getClass().getName().getBytes(); } catch(Exception e){ LOGGER.error("encode request object error",e); throw e; } } else{ ResponseWrapper wrapper = (ResponseWrapper) message; try{ codecType = wrapper.getCodecType(); body = Codecs.getEncoder(codecType).encode(wrapper.getResponse()); id = wrapper.getRequestId(); if(codecType == Codecs.PB_CODEC) className = wrapper.getResponse().getClass().getName().getBytes(); } catch(Exception e){ LOGGER.error("encode response object error",e); // still create response,so client can get it wrapper.setResponse(new Exception("encode response object error",e)); if(codecType == Codecs.PB_CODEC) className = Exception.class.getName().getBytes(); body = Codecs.getEncoder(wrapper.getCodecType()).encode(wrapper.getResponse()); } type = RESPONSE; } int capacity = ProtocolUtils.HEADER_LEN + CUSTOMPROTOCOL_HEADER_LEN + body.length; if(codecType == Codecs.PB_CODEC){ capacity += className.length; } ByteBufferWrapper byteBuffer = bytebufferWrapper.get(capacity); byteBuffer.writeByte(ProtocolUtils.CURRENT_VERSION); byteBuffer.writeByte((byte)TYPE); byteBuffer.writeByte(VERSION); byteBuffer.writeByte(type); byteBuffer.writeByte((byte)codecType); byteBuffer.writeByte((byte)0); byteBuffer.writeByte((byte)0); byteBuffer.writeByte((byte)0); byteBuffer.writeInt(id); byteBuffer.writeInt(timeout); if(codecType == Codecs.PB_CODEC){ byteBuffer.writeInt(className.length); } else{ byteBuffer.writeInt(0); } byteBuffer.writeInt(body.length); if(codecType == Codecs.PB_CODEC) byteBuffer.writeBytes(className); byteBuffer.writeBytes(body); return byteBuffer; } public Object decode(ByteBufferWrapper wrapper,Object errorObject,int...originPosArray) throws Exception{ final int originPos; if(originPosArray!=null && originPosArray.length == 1){ originPos = originPosArray[0]; } else{ originPos = wrapper.readerIndex(); } if(wrapper.readableBytes() < CUSTOMPROTOCOL_HEADER_LEN){ wrapper.setReaderIndex(originPos); return errorObject; } byte version = wrapper.readByte(); if(version == (byte)1){ byte type = wrapper.readByte(); int codecType = wrapper.readByte(); wrapper.readByte(); wrapper.readByte(); wrapper.readByte(); int requestId = wrapper.readInt(); int timeout = wrapper.readInt(); int classNameLen = wrapper.readInt(); int bodyLen = wrapper.readInt(); if(wrapper.readableBytes() < bodyLen + classNameLen){ wrapper.setReaderIndex(originPos); return errorObject; } byte[] classNameByte = null; if(codecType == Codecs.PB_CODEC){ classNameByte = new byte[classNameLen]; wrapper.readBytes(classNameByte); } byte[] body = new byte[bodyLen]; wrapper.readBytes(body); int messageLen = ProtocolUtils.HEADER_LEN + CUSTOMPROTOCOL_HEADER_LEN + classNameLen + bodyLen; if(type == REQUEST){ RequestWrapper requestWrapper = new RequestWrapper(body,timeout,requestId,codecType, TYPE); requestWrapper.setMessageLen(messageLen); requestWrapper.setArgTypes(new byte[][]{classNameByte}); return requestWrapper; } else if(type == RESPONSE){ ResponseWrapper responseWrapper = new ResponseWrapper(requestId,codecType,TYPE); responseWrapper.setResponse(body); responseWrapper.setMessageLen(messageLen); responseWrapper.setResponseClassName(classNameByte); return responseWrapper; } else{ throw new UnsupportedOperationException("protocol type : "+type+" is not supported!"); } } else{ throw new UnsupportedOperationException("protocol version :"+version+" is not supported!"); } } }