ProtobufDecoder.java revision 420c9859
1package muduo.codec; 2 3import java.nio.charset.Charset; 4import java.util.HashMap; 5import java.util.Map; 6import java.util.zip.Adler32; 7 8import org.jboss.netty.buffer.ChannelBuffer; 9import org.jboss.netty.channel.Channel; 10import org.jboss.netty.channel.ChannelHandler.Sharable; 11import org.jboss.netty.channel.ChannelHandlerContext; 12import org.jboss.netty.handler.codec.oneone.OneToOneDecoder; 13 14import com.google.protobuf.Message; 15 16@Sharable 17public class ProtobufDecoder extends OneToOneDecoder { 18 19 private Map<String, Message> knownTypes = new HashMap<String, Message>(); 20 21 @Override 22 public Object decode(ChannelHandlerContext ctx, Channel channel, Object obj) 23 throws Exception { 24 if (!(obj instanceof ChannelBuffer)) { 25 return obj; 26 } 27 ChannelBuffer buffer = (ChannelBuffer) obj; 28 if (buffer.readableBytes() >= 10 && checksum(buffer)) { 29 int nameLen = buffer.readInt(); 30 String typeName = buffer.toString(buffer.readerIndex(), nameLen - 1, 31 Charset.defaultCharset()); 32 buffer.readerIndex(buffer.readerIndex() + nameLen); 33 Message prototype = knownTypes.get(typeName); 34 if (prototype != null) { 35 return prototype.newBuilderForType().mergeFrom(buffer.array(), 36 buffer.arrayOffset() + buffer.readerIndex(), 37 buffer.readableBytes() - 4).build(); 38 } 39 } 40 return obj; 41 } 42 43 private boolean checksum(ChannelBuffer buffer) { 44 Adler32 adler32 = new Adler32(); 45 adler32.update(buffer.array(), 46 buffer.arrayOffset() + buffer.readerIndex(), 47 buffer.readableBytes() - 4); 48 buffer.markReaderIndex(); 49 buffer.readerIndex(buffer.writerIndex() - 4); 50 int checksum = buffer.readInt(); 51 buffer.resetReaderIndex(); 52 return checksum == (int) adler32.getValue(); 53 } 54 55 public void addMessageType(Message message) { 56 knownTypes.put(message.getDescriptorForType().getFullName(), message); 57 } 58} 59