class ProtocolCodeBasedDecoder extends AbstractBatchDecoder {
    /** by default, suggest design a single byte for protocol version. */
    public static final int DEFAULT_PROTOCOL_VERSION_LENGTH         = 1;
    /** protocol version should be a positive number, we use -1 to represent illegal */
    public static final int DEFAULT_ILLEGAL_PROTOCOL_VERSION_LENGTH = -1;

    /** the length of protocol code */
    protected int           protocolCodeLength;

    public ProtocolCodeBasedDecoder(int protocolCodeLength) {
        super();
        this.protocolCodeLength = protocolCodeLength;
    }

    /**
     * decode the protocol code
     *
     * @param in input byte buf
     * @return an instance of ProtocolCode
     */
    protected ProtocolCode decodeProtocolCode(ByteBuf in) {
        if (in.readableBytes() >= protocolCodeLength) {
            byte[] protocolCodeBytes = new byte[protocolCodeLength];
            in.readBytes(protocolCodeBytes);
            return ProtocolCode.fromBytes(protocolCodeBytes);
        }
        return null;
    }

    /**
     * decode the protocol version
     *
     * @param in input byte buf
     * @return a byte to represent protocol version
     */
    protected byte decodeProtocolVersion(ByteBuf in) {
        if (in.readableBytes() >= DEFAULT_PROTOCOL_VERSION_LENGTH) {
            return in.readByte();
        }
        return DEFAULT_ILLEGAL_PROTOCOL_VERSION_LENGTH;
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {<FILL_FUNCTION_BODY>}
}

        in.markReaderIndex();
        ProtocolCode protocolCode;
        Protocol protocol;
        try {
            protocolCode = decodeProtocolCode(in);
            if (protocolCode == null) {
                // read to end
                return;
            }

            byte protocolVersion = decodeProtocolVersion(in);
            if (ctx.channel().attr(Connection.PROTOCOL).get() == null) {
                ctx.channel().attr(Connection.PROTOCOL).set(protocolCode);
                if (DEFAULT_ILLEGAL_PROTOCOL_VERSION_LENGTH != protocolVersion) {
                    ctx.channel().attr(Connection.VERSION).set(protocolVersion);
                }
            }

            protocol = ProtocolManager.getProtocol(protocolCode);
        } finally {
            // reset the readerIndex before throwing an exception or decoding content
            // to ensure that the packet is complete
            in.resetReaderIndex();
        }

        if (protocol == null) {
            throw new CodecException("Unknown protocol code: [" + protocolCode
                                     + "] while decode in ProtocolDecoder.");
        }

        protocol.getDecoder().decode(ctx, in, out);
    
<methods>public non-sealed void <init>() ,public void channelInactive(ChannelHandlerContext) throws java.lang.Exception,public void channelRead(ChannelHandlerContext, java.lang.Object) throws java.lang.Exception,public void channelReadComplete(ChannelHandlerContext) throws java.lang.Exception,public final void handlerRemoved(ChannelHandlerContext) throws java.lang.Exception,public boolean isSingleDecode() ,public void setCumulator(com.alipay.remoting.codec.AbstractBatchDecoder.Cumulator) ,public void setDiscardAfterReads(int) ,public void setSingleDecode(boolean) <variables>public static final com.alipay.remoting.codec.AbstractBatchDecoder.Cumulator COMPOSITE_CUMULATOR,public static final com.alipay.remoting.codec.AbstractBatchDecoder.Cumulator MERGE_CUMULATOR,ByteBuf cumulation,private com.alipay.remoting.codec.AbstractBatchDecoder.Cumulator cumulator,private boolean decodeWasNull,private int discardAfterReads,private boolean first,private int numReads,private boolean singleDecode