class HttpToHttp2ConnectionHandler extends Http2ConnectionHandler {

  @Override
  public void write(
      final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) {

    if (!(msg instanceof HttpMessage || msg instanceof HttpContent)) {
      ctx.write(msg, promise);
      return;
    }

    boolean release = true;
    final Http2CodecUtil.SimpleChannelPromiseAggregator promiseAggregator =
        new Http2CodecUtil.SimpleChannelPromiseAggregator(promise, ctx.channel(), ctx.executor());
    try {
      final Http2ConnectionEncoder encoder = encoder();
      boolean endStream = false;
      if (msg instanceof HttpMessage) {
        final HttpMessage httpMsg = (HttpMessage) msg;

        // Provide the user the opportunity to specify the streamId
        currentStreamId = getStreamId(httpMsg.headers());

        // Convert and write the headers.
        final Http2Headers http2Headers =
            HttpConversionUtil.toHttp2Headers(httpMsg, validateHeaders);
        endStream =
            msg instanceof FullHttpMessage && !((FullHttpMessage) msg).content().isReadable();
        writeHeaders(
            ctx,
            encoder,
            currentStreamId,
            httpMsg.headers(),
            http2Headers,
            endStream,
            promiseAggregator);
      }

      if (!endStream && msg instanceof HttpContent) {
        boolean isLastContent = false;
        HttpHeaders trailers = EmptyHttpHeaders.INSTANCE;
        Http2Headers http2Trailers = EmptyHttp2Headers.INSTANCE;
        if (msg instanceof LastHttpContent) {
          isLastContent = true;

          // Convert any trailing headers.
          final LastHttpContent lastContent = (LastHttpContent) msg;
          trailers = lastContent.trailingHeaders();
          http2Trailers = HttpConversionUtil.toHttp2Headers(trailers, validateHeaders);
        }

        // Write the data
        final ByteBuf content = ((HttpContent) msg).content();
        endStream = isLastContent && trailers.isEmpty();
        release = false;
        encoder.writeData(
            ctx, currentStreamId, content, 0, endStream, promiseAggregator.newPromise());

        if (!trailers.isEmpty()) {
          // Write trailing headers.
          writeHeaders(
              ctx, encoder, currentStreamId, trailers, http2Trailers, true, promiseAggregator);
        }
      }
    } catch (final Throwable t) {
      onError(ctx, true, t);
      promiseAggregator.setFailure(t);
    } finally {
      if (release) {
        ReferenceCountUtil.release(msg);
      }
      promiseAggregator.doneAllocatingPromises();
    }
  }

  protected  HttpToHttp2ConnectionHandler(
      final Http2ConnectionDecoder decoder,
      final Http2ConnectionEncoder encoder,
      final Http2Settings initialSettings,
      final boolean validateHeaders);
  protected  HttpToHttp2ConnectionHandler(
      final Http2ConnectionDecoder decoder,
      final Http2ConnectionEncoder encoder,
      final Http2Settings initialSettings,
      final boolean validateHeaders,
      final boolean decoupleCloseAndGoAway);

}