Interface HttpResponse.MultiProcessor<U,T>

  • Type Parameters:
    U - a type representing the aggregated results
    T - a type representing all of the response bodies
    Enclosing class:

    public static interface HttpResponse.MultiProcessor<U,T>
    A response processor for a HTTP/2 multi response.
    Incubating Feature. Will be removed in a future release.

    A multi response comprises a main response, and zero or more additional responses. Each additional response is sent by the server in response to requests that the server also generates. Additional responses are typically resources that the server expects the client will need which are related to the initial request.

    Note. Instead of implementing this interface, applications should consider first using the mechanism (built on this interface) provided by MultiProcessor.asMap() which is a slightly simplified, but general purpose interface.

    The server generated requests are also known as push promises. The server is permitted to send any number of these requests up to the point where the main response is fully received. Therefore, after completion of the main response, the final number of additional responses is known. Additional responses may be canceled, but given that the server does not wait for any acknowledgment before sending the response, this must be done quickly to avoid unnecessary data transmission.

    MultiProcessors are parameterized with a type U which represents some meaningful aggregate of the responses received. This would typically be a collection of response or response body objects.

    • Method Detail

      • onRequest

        Optional<HttpResponse.BodyHandler<T>> onRequest​(HttpRequest request)
        Called for the main request and each push promise that is received. The first call will always be for the main request that was sent by the caller. This HttpRequest parameter represents the initial request or subsequent PUSH_PROMISE. The implementation must return an Optional of HttpResponse.BodyHandler for the response body. Different handlers (of the same type) can be returned for different pushes within the same multi send. If no handler (an empty Optional) is returned, then the push will be canceled. It is an error to not return a valid BodyHandler for the initial (main) request.
        request - the main request or subsequent push promise
        an optional body handler
      • onResponse

        void onResponse​(HttpResponse<T> response)
        Called for each response received. For each request either one of onResponse() or onError() is guaranteed to be called, but not both. [Note] The reason for switching to this callback interface rather than using CompletableFutures supplied to onRequest() is that there is a subtle interaction between those CFs and the CF returned from completion() (or when onComplete() was called formerly). The completion() CF will not complete until after all of the work done by the onResponse() calls is done. Whereas if you just create CF's dependent on a supplied CF (to onRequest()) then the implementation has no visibility of the dependent CFs and can't guarantee to call onComplete() (or complete the completion() CF) after the dependent CFs complete.
        response - the response received
      • onError

        void onError​(HttpRequest request,
                     Throwable t)
        Called if an error occurs receiving a response. For each request either one of onResponse() or onError() is guaranteed to be called, but not both.
        request - the main request or subsequent push promise
        t - the Throwable that caused the error
      • completion

        CompletableFuture<U> completion​(CompletableFuture<Void> onComplete,
                                        CompletableFuture<Void> onFinalPushPromise)
        Returns a CompletableFuture<U> which completes when the aggregate result object itself is available. It is expected that the returned CompletableFuture will depend on one of the given CompletableFuture<Voids which themselves complete after all individual responses associated with the multi response have completed, or after all push promises have been received.

        Implementation Note:
        Implementations might follow the pattern shown below
              CompletableFuture<U> completion(
                      CompletableFuture<Void> onComplete,
                      CompletableFuture<Void> onFinalPushPromise)
                  return onComplete.thenApply((v) -> {
                      U u = ... instantiate and populate a U instance
                      return u;

        onComplete - a CompletableFuture which completes after all responses have been received relating to this multi request.
        onFinalPushPromise - CompletableFuture which completes after all push promises have been received.
        the aggregate CF response object
      • asMap

        static <V> HttpResponse.MultiProcessor<MultiMapResult<V>,V> asMap​(Function<HttpRequest,Optional<HttpResponse.BodyHandler<V>>> pushHandler,
                                                                          boolean completion)
        Returns a general purpose handler for multi responses. The aggregated result object produced by this handler is a Map<HttpRequest,CompletableFuture<HttpResponse<V>>>. Each request (both the original user generated request and each server generated push promise) is returned as a key of the map. The value corresponding to each key is a CompletableFuture<HttpResponse<V>>.

        There are two ways to use these handlers, depending on the value of the completion parameter. If completion is true, then the aggregated result will be available after all responses have themselves completed. If completion is false, then the aggregated result will be available immediately after the last push promise was received. In the former case, this implies that all the CompletableFutures in the map values will have completed. In the latter case, they may or may not have completed yet.

        The simplest way to use these handlers is to set completion to true, and then all (results) values in the Map will be accessible without blocking.

        See asMap(java.util.function.Function, boolean) for a code sample of using this interface.

        Type Parameters:
        V - the body type used for all responses
        pushHandler - a function invoked for each request or push promise
        completion - true if the aggregate CompletableFuture completes after all responses have been received, or false after all push promises received.
        a MultiProcessor
      • asMap

        static <V> HttpResponse.MultiProcessor<MultiMapResult<V>,V> asMap​(Function<HttpRequest,Optional<HttpResponse.BodyHandler<V>>> pushHandler)
        Returns a general purpose handler for multi responses. This is a convenience method which invokes asMap(Function, true) meaning that the aggregate result object completes after all responses have been received.

        Example usage:

                  HttpRequest request = HttpRequest.newBuilder()
                  HttpClient client = HttpClient.newHttpClient();
                  Map<HttpRequest,CompletableFuture<HttpResponse<String>>> results = client
                      .sendAsync(request, MultiProcessor.asMap(
                          (req) -> Optional.of(HttpResponse.BodyHandler.asString())))

        The lambda in this example is the simplest possible implementation, where neither the incoming requests are examined, nor the response headers, and every push that the server sends is accepted. When the join() call returns, all HttpResponses and their associated body objects are available.

        Type Parameters:
        V - the body type used for all responses
        pushHandler - a function invoked for each request or push promise
        a MultiProcessor