Give a handler more control over how its buffers' read bytes are discarded.

This pull request adds two new handler methods: `discardInboundReadBytes(ctx)` and `discardOutboundReadBytes(ctx)` to `ChannelInboundByteHandler` and `ChannelOutboundByteHandler` respectively.  They are called between every `inboundBufferUpdated()` and `flush()` respectively.  Their default implementation is to call `discardSomeReadBytes()` on their buffers and a user can override this behavior easily.  For example, `ReplayingDecoder.discardInboundReadBytes()` looks like the following:

    @Override
    public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception {
        ByteBuf in = ctx.inboundByteBuffer();
        final int oldReaderIndex = in.readerIndex();
        super.discardInboundReadBytes(ctx);
        final int newReaderIndex = in.readerIndex();
        checkpoint -= oldReaderIndex - newReaderIndex;
    }

If a handler, which has its own buffer index variable, extends `ReplayingDecoder` or `ByteToMessageDecoder`, the handler can also override `discardInboundReadBytes()` and adjust its index variable accordingly.

### Caveat

Let's assume you write a decoder that extends `ReplayingDecoder`.  `ReplayingDecoder.discardInboundReadBytes()` has already been implemented to discard read bytes.  You cannot change this behavior. even if you override `discardInboundReadBytes()` in your decoder because you must call `super.discardInboundReadBytes()` to make sure the `checkpoint` is in-sync.

To workaround this problem, `ReplayingDecoder` must:

1. Make `discardInboundReadBytes()` final.
2. Add a new overridable protected method whose default implementation is `super.discardInboundReadBytes()` and make `discardInboundreadBytes()` call it rather than calling `super.discardInboundReadBytes()`.
3. A decoder that extends `ReplayingDecoder` overrides the method added at the step 2.

For example:

    @Override
    public void discardInboundReadBytes(ChannelHandlerContext ctx) throws Exception {
        ByteBuf in = ctx.inboundByteBuffer();
        final int oldReaderIndex = in.readerIndex();
        doDiscardInboundReadBytes(ctx);
        final int newReaderIndex = in.readerIndex();
        checkpoint -= oldReaderIndex - newReaderIndex;
    }

    protected void doDiscardInboundReadBytes(ctx) throws Exception {
        super.discardInboundReadBytes(ctx);
    }

Usually, the depth of class hierarchy will not really be greater than 2 or 3, so it might not be a big deal in most cases.