Review of new Http client API

Chris Hegarty chris.hegarty at oracle.com
Thu Aug 23 08:05:04 PDT 2012


Paul,

All good feedback, and I will leave it to Michael to reply to the 
specifics. On thought I had on separation of modes is something list this:

   interface HeaderHandler {
       onHeaders(HttpResponse);
   }
   interface ErrorHandler {
       onError(HttpResponse, Throwable);
   }
   interface BodyHandler {
       onBodyPart(HttpResponse, ByteBuffer, boolean);
   }

   class HttpRequest {
       ....
       AsyncHttpRequest async(HttpRequest);
       ....
   }

   class AsyncHttpRequest extends HttpRequest {
       // no public constructors
       ....
       AsyncHttpRequest onHeaders(HeaderHandler);
       AsyncHttpRequest onError(ErrorHandler);
       AsyncHttpRequest onBodyPart(BodyHandler);
   }

   class HttpClient {
       ....
       OutputStream sendHeaders(HttpRequest request, long contentLength)
       Future<HttpResponse> sendRequest(HttpRequest req)
       void sendRequest(AsyncHttpRequest req)
   }

Then user code may do:

   AsyncHttpRequest request.async()
                .onHeaders(r -> dumpHeaders(r))
                .onError((r,t) -> handleError(r,t));
                .onBodyPart((r,bb,c) -> transformBody(r,bb,t));
   client.sendRequest(request);

   ....

   void dumpHeaders(HttpResponse r) {
       System.out.println(r);
   }
   void handleError(HttpResponse r, t) {
       throw t;
   }
   void transformBody(HttpResponse r, bb, boolean complete) {
       System.out.println("Hello there!");
   }

Some experimentation is necessary to find a good balance here.

-Chris.

On 23/08/2012 15:20, Paul Sandoz wrote:
> Hi,
>
> A potential simplification of the HttpResponseHeadersHandler interface is to turn it into a functional interface:
>
>    HttpResponseHandler onHeaders(Future<HttpResponse>  dresp) throws InterruptedException, ExecutionException;
>
> [Chris, i am not sure if an interface with two methods, one default, is classified as a functional interface.]
>
> - mirrors the pull-based asynchronous approach
>
> - dresp.isDone() always returns true
>
> - the Future encapsulates the underling exception, if any
>
> - harder to swallow errors, since the exception from drep.get() will propagate if not caught.
>
> - a return of a null HttpResponseHandler means "not interested in the body".
>
> FWIW the use of Future is the approach i chose for the Jersey client.
>
> HttpResponseHandler would also be a functional interface:
>
>      void onBodyPart(Future<ByteBuffer>  bb) throws InterruptedException, ExecutionException
>
> - there is no inheritance relationship between HttpResponseHeadersHandler and HttpResponseHandler.
>
> - a "bb" with a capacity of 0 indicates the last part.
>
> - the HttpResponse is not required as a parameter because the implementation can obtain it from the onHeaders method.
>
> If the use of Future is a bit extreme for some :-) then things can still be simplified by following the above approach with an additional, and optional, functional interface to handle errors when HttpClient.sendRequest is called.
>
> --
>
> Rather than setting the bytes on the HttpRequest with numerous methods i wonder if it is better to have a functional interfaces for both OutputStream and the NIO equivalent:
>
>    interface EntityWriter<T>  { // Oh for disjunct types!
>      /**
>       * @return true if there is more to write
>       */
>      boolean write(T t) throws IOException;
>    }
>
> I believe the above can support all the existing functionality currently expressed as methods, including the Iterable/Iterator. There can be instances of EntityWriter for common functionality:
>
>    EntityWriters.fromBytes(byte[] b, ...);
>
> The same might be applicable to HttpResponse with an EntityReader:
>
>    interface EntityReader<T, U>  {
>      U read(T t) throws IOException;
>    }
>
> Of course i might be missing something obvious here in terms of optimisation currently performed by the implementation!
>
> --
>
> It somewhat bugs me that blocking and asynchronous pull/push functionality is all defined using the same artifacts. But, my imagination is currently is failing me on how to improve on such matters. Perhaps something better may come out of fluent-based API?
>
> Paul.
>
> On Aug 14, 2012, at 2:01 PM, Michael McMahon<michael.x.mcmahon at oracle.com>  wrote:
>
>> Hi,
>>
>> (apologies for sending this again)
>> We have just published a draft of a proposed new Http client API [1] for JDK 8.
>>
>> This message has been cc'd to jdk8-dev so that as many people as possible
>> know about it, but the discussion will be on the net-dev list (net-dev at openjdk.java.net).
>> So, folks will have to join that list [2], in order to take part.
>>
>> Thanks,
>> Michael.
>>
>> [1] http://cr.openjdk.java.net/~michaelm/httpclient/v0.3/
>>
>> [2] http://mail.openjdk.java.net/mailman/listinfo/net-dev
>



More information about the net-dev mailing list