class Http2ConnectionHandler extends ByteToMessageDecoder implements Http2LifecycleManager,
                                                                            ChannelOutboundHandler {

    @Override
    public ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode,
                                final ByteBuf debugData, ChannelPromise promise) {
        try {
            promise = promise.unvoid();
            final Http2Connection connection = connection();
            if (connection().goAwaySent()) {
                // Protect against re-entrancy. Could happen if writing the frame fails, and error handling
                // treating this is a connection handler and doing a graceful shutdown...
                if (lastStreamId == connection().remote().lastStreamKnownByPeer()) {
                    // Release the data and notify the promise
                    debugData.release();
                    return promise.setSuccess();
                }
                if (lastStreamId > connection.remote().lastStreamKnownByPeer()) {
                    throw connectionError(PROTOCOL_ERROR, "Last stream identifier must not increase between " +
                                                          "sending multiple GOAWAY frames (was '%d', is '%d').",
                                          connection.remote().lastStreamKnownByPeer(), lastStreamId);
                }
            }

            connection.goAwaySent(lastStreamId, errorCode, debugData);

            // Need to retain before we write the buffer because if we do it after the refCnt could already be 0 and
            // result in an IllegalRefCountException.
            debugData.retain();
            ChannelFuture future = frameWriter().writeGoAway(ctx, lastStreamId, errorCode, debugData, promise);

            if (future.isDone()) {
                processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future);
            } else {
                future.addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future);
                    }
                });
            }

            return future;
        } catch (Throwable cause) { // Make sure to catch Throwable because we are doing a retain() in this method.
            debugData.release();
            return promise.setFailure(cause);
        }
    }

    protected  Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
                                     Http2Settings initialSettings);
      Http2ConnectionHandler(boolean server, Http2FrameWriter frameWriter, Http2FrameLogger frameLogger,
                    Http2Settings initialSettings);

}