Class BodyDeferringAsyncHandler

  • All Implemented Interfaces:
    AsyncHandler<Response>

    public class BodyDeferringAsyncHandler
    extends Object
    implements AsyncHandler<Response>
    An AsyncHandler that returns Response (without body, so status code and headers only) as fast as possible for inspection, but leaves you the option to defer body consumption.
    This class introduces new call: getResponse(), that blocks caller thread as long as headers are received, and return Response as soon as possible, but still pouring response body into supplied output stream. This handler is meant for situations when the "recommended" way (using client.prepareGet("http://foo.com/aResource").execute().get()), which would not work for you, since a potentially large response body is about to be GET-ted, but you need headers first, or you don't know yet (depending on some logic, maybe coming from headers) where to save the body, or you just want to leave body stream to some other component to consume it.
    All these above means that this AsyncHandler needs a bit of different handling than "recommended" way. Some examples:
         OutputStream fos = ...
         BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(fos);
         // client executes async
         Future<Response> fr = client.prepareGet("...).execute(
            bdah);
         // main thread will block here until headers are available
         Response response = bdah.getResponse();
         // you can continue examine headers while actual body download happens
         // in separate thread
         // ...
         // finally "join" the download
         fr.get();
     

         PipedOutputStream pout = new PipedOutputStream();
         try (PipedInputStream pin = new PipedInputStream(pout)) {
             BodyDeferringAsyncHandler handler = new BodyDeferringAsyncHandler(pout);
             ListenableFuture<Response> respFut = client.prepareGet(getTargetUrl()).execute(handler);
             Response resp = handler.getResponse();
             // main thread will block here until headers are available
             if (resp.getStatusCode() == 200) {
                 try (InputStream is = new BodyDeferringInputStream(respFut, handler, pin)) {
                     // consume InputStream
                     ...
                 }
             } else {
                 // handle unexpected response status code
                 ...
             }
         }
     
    • Constructor Detail

      • BodyDeferringAsyncHandler

        public BodyDeferringAsyncHandler​(OutputStream os)
    • Method Detail

      • onThrowable

        public void onThrowable​(Throwable t)
        Description copied from interface: AsyncHandler
        Invoked when an unexpected exception occurs during the processing of the response. The exception may have been produced by implementation of onXXXReceived method invocation.
        Specified by:
        onThrowable in interface AsyncHandler<Response>
        Parameters:
        t - a Throwable
      • onRetry

        public void onRetry()
        Description copied from interface: AsyncHandler
        Notify the callback every time a request is being retried.
        Specified by:
        onRetry in interface AsyncHandler<Response>
      • onBodyPartReceived

        public AsyncHandler.State onBodyPartReceived​(HttpResponseBodyPart bodyPart)
                                              throws Exception
        Description copied from interface: AsyncHandler
        Invoked as soon as some response body part are received. Could be invoked many times. Beware that, depending on the provider (Netty) this can be notified with empty body parts.
        Specified by:
        onBodyPartReceived in interface AsyncHandler<Response>
        Parameters:
        bodyPart - response's body part.
        Returns:
        a AsyncHandler.State telling to CONTINUE or ABORT the current processing. Aborting will also close the connection.
        Throws:
        Exception - if something wrong happens
      • getResponse

        @Nullable
        public @Nullable Response getResponse()
                                       throws InterruptedException,
                                              IOException
        This method -- unlike Future<Reponse>.get() -- will block only as long, as headers arrive. This is useful for large transfers, to examine headers ASAP, and defer body streaming to it's fine destination and prevent unneeded bandwidth consumption. The response here will contain the very 1st response from server, so status code and headers, but it might be incomplete in case of broken servers sending trailing headers. In that case, the "usual" Future<Response>.get() method will return complete headers, but multiple invocations of getResponse() will always return the 1st cached, probably incomplete one. Note: the response returned by this method will contain everything except the response body itself, so invoking any method like Response.getResponseBodyXXX() will result in error! Also, please note that this method might return null in case of some errors.
        Returns:
        a Response
        Throws:
        InterruptedException - if the latch is interrupted
        IOException - if the handler completed with an exception