@Override
    public void doClose(ServerStatusAndMetadata statusAndMetadata) {
        try {
            final ResponseHeaders responseHeaders = responseHeaders();
            final Status status = statusAndMetadata.status();
            final Metadata metadata = statusAndMetadata.metadata();
            final HttpResponse response;
            if (status.isOk()) {
                assert responseHeaders != null;
                assert responseMessage != null;
                final HttpData responseBody = toPayload(responseMessage);

                final HttpObject responseTrailers = responseTrailers(ctx, status, metadata, false);
                if (responseTrailers instanceof HttpData) {
                    // gRPC-Web encodes response trailers as response body.
                    final HttpData httpData =
                            aggregateData(responseBody, (HttpData) responseTrailers, ctx.alloc());
                    response = HttpResponse.of(responseHeaders, httpData);
                } else {
                    response = HttpResponse.of(responseHeaders, responseBody, (HttpHeaders) responseTrailers);
                }
            } else {
                final ResponseHeadersBuilder trailersBuilder;
                if (responseHeaders != null) {
                    trailersBuilder = responseHeaders.toBuilder();
                } else {
                    trailersBuilder = defaultResponseHeaders().toBuilder();
                }
                response = HttpResponse.of((ResponseHeaders) statusToTrailers(ctx, trailersBuilder,
                                                                              status, metadata));
            }

            // Set responseContent before closing stream to use responseCause in error handling
            ctx.logBuilder().responseContent(GrpcLogUtil.rpcResponse(statusAndMetadata, responseMessage), null);
            resFuture.complete(response);
        } catch (Exception ex) {
            final StatusAndMetadata statusAndMetadata0 = exceptionHandler().handle(ctx, ex);
            final Status status = statusAndMetadata0.status();
            final Metadata metadata = statusAndMetadata0.metadata();
            assert metadata != null;
            statusAndMetadata = new ServerStatusAndMetadata(status, metadata, true);

            final ResponseHeadersBuilder trailersBuilder = defaultResponseHeaders().toBuilder();
            final HttpResponse response = HttpResponse.of(
                    (ResponseHeaders) statusToTrailers(ctx, trailersBuilder, status, metadata));
            resFuture.complete(response);
        } finally {
            closeListener(statusAndMetadata);
        }
    }
Encapsulates the state of a single server call, reading messages from the client, passing to business logic
via {@link Listener}, and writing messages passed back to the response.
grpc/src/main/java/com/linecorp/armeria/server/grpc/UnaryServerCall.java