Home > Async Http client > Going Asynchronous using AsyncHttpClient: For Dummies

Going Asynchronous using AsyncHttpClient: For Dummies

Concluding on my “Going Asynchronous using AsyncHttpClient (Basic and Complex)” blog series, this week I will explains how to use the new SimpleAsynHttpClient API to write powerful async client applications.

The SimpleAsynchHttpClient is an implementation on top of the AsyncHttpClient and its builders class like AsyncHttpClientConfigBuilder, RealmBuilder etc. With SimpleAsynchHttpClient, all you need to do is to create a single builder, and configure your request from that builder:

 SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder()
                .setUrl("http://..")
                .setProxyHost("http://...")
                .addHeader("foo","bar")
                .setRealmPrincipal("me")
                .setRealmPassword("pwd")
                .build();

Once you have configured your SimpleAsyncHttpClient, you can invoke your HTTP method:

 client.get();
   or
 client.head();

Now the biggest difference with the AsyncHttpClient API is the support for BodyConsumer and BodyGenerator. The BodyGenerator API allows an application to customize how bytes are sent. This is quite useful when you need to stream large fie and you don’t want to load it in memory. As an example, the library contains a FileBodyGenerator defined as

public class FileBodyGenerator implements BodyGenerator {

    private final File file;

    public FileBodyGenerator(File file) {
        this.file = file;
    }

    public RandomAccessBody createBody() throws IOException {
        return new FileBody(file);
    }

    protected static class FileBody
            implements RandomAccessBody {

        private final RandomAccessFile file;

        private final FileChannel channel;

        private final long length;

        public FileBody(File file)
                throws IOException {
            this.file = new RandomAccessFile(file, "r");
            channel = this.file.getChannel();
            length = this.file.length();
        }

        public long getContentLength() {
            return length;
        }

        public long read(ByteBuffer buffer)
                throws IOException {
            return channel.read(buffer);
        }

        public long transferTo(long position,
                               long count, WritableByteChannel target)
                throws IOException {
            return channel.transferTo(position, count, target);
        }

        public void close()
                throws IOException {
            file.close();
        }
    }
}

The library ships with InpuStreamBodyGenerator, ByteArrayBodyGenerator and the one above. Those BodyGenerator never buffers bytes in memory, reducing the probability to fill the heap and get an OOM. For the response, the SimpleAsyncHttpClient support a new API called BodyConsumer, which is simply defined as

public interface BodyConsumer {

    void consume(ByteBuffer byteBuffer) throws IOException;

    void close() throws IOException;

}

Simple callback that are invoked as soon as the response’s bytes are available. As an example, the library ships with

public class AppendableBodyConsumer implements BodyConsumer {

    private final Appendable appendable;
    private final String encoding;

    public AppendableBodyConsumer(Appendable appendable, String encoding) {
        this.appendable = appendable;
        this.encoding = encoding;
    }

    public AppendableBodyConsumer(Appendable appendable) {
        this.appendable = appendable;
        this.encoding = "UTF-8";
    }

    public void consume(ByteBuffer byteBuffer) throws IOException {
        appendable.append(new String(byteBuffer.array(), encoding));
    }

    public void close() throws IOException {
        if (Closeable.class.isAssignableFrom(appendable.getClass())) {
            Closeable.class.cast(appendable).close();
        }
    }
}

The library ships with ByteBufferBodyConsumer, FileBodyConsumer and OutputStreamBodyConsumer. Hence normally you shouldn’t have to write BodyConsumer and BodyGenerator…just use the one available! Simply do:

 SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder()
                .setIdleConnectionInPoolTimeoutInMs(100)
                .setUrl("http://.....)
                .setHeader("Content-Type", "text/html")
                .build();

  Future future = client.post(
                new InputStreamBodyGenerator(myInputStream),
                new OutputStreamBodyConsumer(myOutputStream));

  Response response = future.get();

Finally, if you need to re-use your instance of SimpleAsyncHttpClient, you an use the Request API directly like when you work with AsyncHttpClient:

 SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder()
                .setIdleConnectionInPoolTimeoutInMs(100)
                .setUrl("http://.....)
                .setHeader("Content-Type", "text/html")
                .build();

  Future future = client.post(
                new InputStreamBodyGenerator(myInputStream),
                new OutputStreamBodyConsumer(myOutputStream));

  Response response = future.get();

  client.get(new RequestBuilder().setUrl("http://...").build(),
             new OutputStreamBodyConsumer(myOutputStream));
  response = future.get();  

The SimpleAsyncHttpClient will be included in 1.5.0, which is targeted to ship weeks of January 18. For any questions you can use our Google Group, irc.freenode.net #asynchttpclient or use Twitter to reach me! You can checkout the code on Github, download the jars from Maven Central or use Maven:

<dependency>
    <groupId>com.ning</groupId>
    <artifactId>async-http-client</artifactId>
    <version>1.5.0-SNAPSHOT</version>
</dependency>

About these ads
Categories: Async Http client
  1. January 12, 2011 at 8:00 pm

    Great series on this library. The nice work is appreciated as it was a valuable getting started guide on a project I was working on as this was being published. Thanks.

  2. saphen
    January 13, 2011 at 1:44 pm

    Hi Jean,

    Do you have email?

  3. January 13, 2011 at 6:08 pm

    Hi. I’m glad to see all the continued work on AsyncHttpClient. A question about the SimpleAsyncHttpClient: From your examples, it looks like SimpleAsyncHttpClient is meant to be used with a single URL to query a particular resource- is that its intended use case? If I want to have a long-lived reusable instance of a Client to use against multiple endpoints, should I use the regular AsyncHttpClient instead?
    Thanks! -Dave

    • January 13, 2011 at 6:38 pm

      Salut,

      look at the very end. You can change the URL via the Request object and it’s builder. That way you aren’t limited to a single url.

      Hope that help.

      - Jeanfrancois

  4. saphen
    January 14, 2011 at 1:53 am

    Hi,
    We intend to use dwr. And we have found you on the dwr-3.0.M1.jar source code. Could you tell me whether you have signed the dojo CLA?

  5. January 14, 2011 at 1:11 pm

    Salut,

    I don’t see the relationship with Dojo :-) Why would I need to sign a CLA?

    – Jeanfrancois

    • saphen
      January 14, 2011 at 3:56 pm

      Thank you for your reply.
      Are you a contributor of dwr project before? I have found that DWR joined the Dojo Foundation in 2007, and since then, they have been handling legal matters for DWR, including managing CLAs.
      The details you can find from here: http://directwebremoting.org/dwr/development/icla.html

  6. January 14, 2011 at 4:02 pm

    @saphen That’s totally unrelated to this project ;-)

  7. February 3, 2011 at 1:43 pm

    Can this somehow be combined with continuations in modern containers (like Jetty) to free the request thread (suspend) during HTTP calls with AHC? Would be awesome.

    Best
    Stephan

    • February 3, 2011 at 2:41 pm

      Yes,

      my other project, Atmosphere, use it for executing full asynchronous request to the Twitter API. Read it here. Atmosphere run on top of Jetty Continuation (and other container).

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 50 other followers

%d bloggers like this: