1420c9859SShuo Chenpackage muduo.codec;
2420c9859SShuo Chen
3420c9859SShuo Chenimport java.nio.charset.Charset;
4420c9859SShuo Chenimport java.util.HashMap;
5420c9859SShuo Chenimport java.util.Map;
6420c9859SShuo Chenimport java.util.zip.Adler32;
7420c9859SShuo Chen
8420c9859SShuo Chenimport org.jboss.netty.buffer.ChannelBuffer;
9420c9859SShuo Chenimport org.jboss.netty.channel.Channel;
10420c9859SShuo Chenimport org.jboss.netty.channel.ChannelHandler.Sharable;
11420c9859SShuo Chenimport org.jboss.netty.channel.ChannelHandlerContext;
12420c9859SShuo Chenimport org.jboss.netty.handler.codec.oneone.OneToOneDecoder;
13420c9859SShuo Chen
14420c9859SShuo Chenimport com.google.protobuf.Message;
15420c9859SShuo Chen
16420c9859SShuo Chen@Sharable
17420c9859SShuo Chenpublic class ProtobufDecoder extends OneToOneDecoder {
18420c9859SShuo Chen
19420c9859SShuo Chen    private Map<String, Message> knownTypes = new HashMap<String, Message>();
20420c9859SShuo Chen
21420c9859SShuo Chen    @Override
22420c9859SShuo Chen    public Object decode(ChannelHandlerContext ctx, Channel channel, Object obj)
23420c9859SShuo Chen            throws Exception {
24420c9859SShuo Chen        if (!(obj instanceof ChannelBuffer)) {
25420c9859SShuo Chen            return obj;
26420c9859SShuo Chen        }
27420c9859SShuo Chen        ChannelBuffer buffer = (ChannelBuffer) obj;
28420c9859SShuo Chen        if (buffer.readableBytes() >= 10 && checksum(buffer)) {
29420c9859SShuo Chen            int nameLen = buffer.readInt();
30420c9859SShuo Chen            String typeName = buffer.toString(buffer.readerIndex(), nameLen - 1,
31420c9859SShuo Chen                    Charset.defaultCharset());
32420c9859SShuo Chen            buffer.readerIndex(buffer.readerIndex() + nameLen);
33420c9859SShuo Chen            Message prototype = knownTypes.get(typeName);
34420c9859SShuo Chen            if (prototype != null) {
35420c9859SShuo Chen                return prototype.newBuilderForType().mergeFrom(buffer.array(),
36420c9859SShuo Chen                        buffer.arrayOffset() + buffer.readerIndex(),
37420c9859SShuo Chen                        buffer.readableBytes() - 4).build();
38420c9859SShuo Chen            }
39420c9859SShuo Chen        }
40420c9859SShuo Chen        return obj;
41420c9859SShuo Chen    }
42420c9859SShuo Chen
43420c9859SShuo Chen    private boolean checksum(ChannelBuffer buffer) {
44420c9859SShuo Chen        Adler32 adler32 = new Adler32();
45420c9859SShuo Chen        adler32.update(buffer.array(),
46420c9859SShuo Chen                buffer.arrayOffset() + buffer.readerIndex(),
47420c9859SShuo Chen                buffer.readableBytes() - 4);
48420c9859SShuo Chen        buffer.markReaderIndex();
49420c9859SShuo Chen        buffer.readerIndex(buffer.writerIndex() - 4);
50420c9859SShuo Chen        int checksum = buffer.readInt();
51420c9859SShuo Chen        buffer.resetReaderIndex();
52420c9859SShuo Chen        return checksum == (int) adler32.getValue();
53420c9859SShuo Chen    }
54420c9859SShuo Chen
55420c9859SShuo Chen    public void addMessageType(Message message) {
56420c9859SShuo Chen        knownTypes.put(message.getDescriptorForType().getFullName(), message);
57420c9859SShuo Chen    }
58420c9859SShuo Chen}
59