public void decode(IoSession session, ByteBuffer in,
            ProtocolDecoderOutput out) throws Exception {
        boolean usingSessionBuffer = true;
        ByteBuffer buf = (ByteBuffer) session.getAttribute(BUFFER);
        // If we have a session buffer, append data to that; otherwise
        // use the buffer read from the network directly.
        if (buf != null) {
            buf.put(in);
            buf.flip();
        } else {
            buf = in;
            usingSessionBuffer = false;
        }

        for (;;) {
            int oldPos = buf.position();
            boolean decoded = doDecode(session, buf, out);
            if (decoded) {
                if (buf.position() == oldPos) {
                    throw new IllegalStateException(
                            "doDecode() can't return true when buffer is not consumed.");
                }

                if (!buf.hasRemaining()) {
                    break;
                }
            } else {
                break;
            }
        }

        // if there is any data left that cannot be decoded, we store
        // it in a buffer in the session and next time this decoder is
        // invoked the session buffer gets appended to
        if (buf.hasRemaining()) {
            if (usingSessionBuffer)
                buf.compact();
            else
                storeRemainingInSession(buf, session);
        } else {
            if (usingSessionBuffer)
                removeSessionBuffer(session);
        }
    }