@Override
  protected void doHandle(RestRequest restRequest, RestResponseChannel restResponseChannel,
      Callback<ReadableStreamChannel> callback) {
    namedBlobListHandler.handle(restRequest, restResponseChannel,
        buildCallback(metrics.s3ListHandleMetrics, (result) -> {
          // Convert from json response to S3 xml response as defined in
          // https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html#API_ListObjectsV2_ResponseSyntax.
          ByteBuffer byteBuffer = ((ByteBufferReadableStreamChannel) result).getContent();
          JSONObject jsonObject = new JSONObject(new JSONTokener(new ByteBufferDataInputStream(byteBuffer)));
          Page<NamedBlobListEntry> page = Page.fromJson(jsonObject, NamedBlobListEntry::new);
          ReadableStreamChannel readableStreamChannel = serializeAsXml(restRequest, page);
          restResponseChannel.setHeader(Headers.DATE, new GregorianCalendar().getTime());
          restResponseChannel.setHeader(Headers.CONTENT_TYPE, XML_CONTENT_TYPE);
          restResponseChannel.setHeader(Headers.CONTENT_LENGTH, readableStreamChannel.getSize());
          callback.onCompletion(readableStreamChannel, null);
        }, restRequest.getUri(), LOGGER, callback));
  }
Asynchronously get account metadata.
@param restRequest the {@link RestRequest} that contains the request parameters and body.
@param restResponseChannel the {@link RestResponseChannel} where headers should be set.
@param callback the {@link Callback} to invoke when the response is ready (or if there is an exception).
ambry-frontend/src/main/java/com/github/ambry/frontend/s3/S3ListHandler.java