Over a million developers have joined DZone.

JAX-RS 2.0 Asynchronous Server and Client

Asynchronous processing in server side and client side is a new feature that is offered by the JAX-RS 2.0. Asynchronous processing in RESTful services may seems a little bit odd or unconventional at the first sight.

· Java Zone

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

Asynchronous processing in server side and client side is a new feature that is offered by the JAX-RS 2.0. Asynchronous processing in RESTful services may seems a little bit odd or unconventional at the first sight. By considering what really happens under the hood, all the unknown aspects of RESTful asynchronous processing will be revealed. It will become clearer that async processing model is one of the essential factors in design and implementation of scalable enterprise services.

In synchronous request/response processing model, client connection is accepted and processed in a single I/O thread by the server. Normally a pool of such I/O threads is available at server side. So when a request is received, the server dedicates one of these threads to accept and process the request. The thread blocks until the processing is finished and returned. When the processing is done and response is sent back to the client, the thread can be released and sent back to the pool. At this point the container that serves requests, assume that the request processing is finished and all the associated resources including the connection can be freed.

This model works perfectly if the request processing doesn’t take so much time. As mentioned before, there is a pool of threads that accepts and processes incoming requests. When there is a huge number of requests and processing is heavy and time consuming, at some point we would expect to reach a point that all the threads are busy processing and the pool is empty. At this point there is no more threads available to accept any connection request.

This is the time that asynchronous processing model comes into action. The idea behind asynchronous processing model is to separate connection accepting and request processing operations. Technically speaking it means to allocate two different threads, one to accept the client connection and the other to handle heavy and time consuming operations. In this model, the container dispatched a thread to accept client connection (acceptor), hand over the request to processing (worker) thread and releases the acceptor one. The result is sent back to the client by the worker thread. In this mechanism client’s connection remains open. May not impact on performance so much, such processing model impacts on server’s THROUGHPUT and SCALABILITY a lot.

JAX-RS 2 async API perfectly support the aforementioned model. Consider the following piece of code:

@Stateless
@Path("/asyncresource")
public class AsynchronousResource {

   @GET
   @Asynchronous
    public void asyncRestMethod(@Suspended final AsyncResponse asyncResponse) {
                String result = heavyLifting();
                asyncResponse.resume(result);
            }

     private String heavyLifting() {
                return "RESULT";
      }

}

In “AsynchronousResource” class a normal REST resource “asyncresource” is defined. This resource has one method “asyncRestMethod” and is annotated with “@GET” annotation. The “asyncRestMethod” method injects an “AsyncResponse” instance using @Suspended annotation. Both “AsyncResponse” and @Suspended are contained in the JAX-RS async API. By using these parameters, the JAX-RS runtime are told to handle any incoming request asynchronously. One thing that is worth to mention is the VOID as the return type of the “asyncRestMethod” method. The VOID key word is indicating that it is totally normal for an acceptor thread that only accepts the client’s request and not to define any return type. The only responsibility of the acceptor thread is to dispatch the processing request to worker threads. When the processing is finished, “asyncResponse.resume(result)” will return the response to the client.

In the previous code, asynchronous feature of JAVA EE EJB was used.  @Asynchronous annotation tells the enterprise bean container to handle this method asynchronously and acts as a worker thread.

So the scenario is as follows: JAX-RS runtime dispatches a thread to accept a connection. The connection is accepted and is handed over to a worker thread for background processing. JAX-RS runtime releases the acceptor thread and returns it to the pool. It can then use it to accept more connections.

By default there is no timeout defined for this so called heavy processing. This is where the “TimeoutHandler” event handler comes into action. Consider the following code:

@Resource(lookup = "java:comp/DefaultManagedThreadFactory")
    private ManagedThreadFactory threadFactory;

    @GET
    public void asyncRestMethod(@Suspended final AsyncResponse asyncResponse) {

        asyncResponse.setTimeoutHandler(new TimeoutHandler() {
            @Override
            public void handleTimeout(AsyncResponse asyncResponse) {
                asyncResponse.resume(Response.status
                                     (Response.Status.SERVICE_UNAVAILABLE)
                        .entity("TIME OUT !").build());
            }
        });

        asyncResponse.setTimeout(40, TimeUnit.SECONDS);

        Thread thread = threadFactory.newThread(new Runnable() {
            @Override
            public void run() {
                String result = heavyLifting();
                asyncResponse.resume(result);
            }

            private String heavyLifting() {
                return "RESULT";
            }
        });
        thread.start();
    }


In the above code whenever the heavy operation processing takes more than 40 seconds, the processing is canceled, resources are released and the “handleTimeout()” method is called. Finally, the Http 503 response code will be returned. To show various mechanisms that are offered by JAVA EE for concurrency and asynchronous processing support, the “ManagedThreadFactory” is used this time. “ManagedThreadFactory” is used whenever an explicit creation and consumption of a thread is required in the JAVA EE runtime environment. As you can see, the actual thread is created as is done in a normal JAVA SE program. As the “Managed” name indicates, the JAVA EE environment manages the execution and life time of this thread.

Another useful feature that is offered by the JAX-RS async API is the asynchronous server side call backs “CompletionCallback / ConnectionCallback”. By registering the AsyncResponse with “CompletionCallback”, whenever a request is finished or failed, the onComplete() method  will be called. Similarly by registering the AsyncResponse with “ConnectionCallback”, whenever a connection to a client is closed or failed, the onDisconnect() method will be called. This come in handy whenever monitoring and logging of the runtime operations are needed. Consider the following code.

@Resource
    ManagedExecutorService managedExecutorService;

    @GET
    public void asyncRestMethod(@Suspended final AsyncResponse asyncResponse) {

        asyncResponse.register(new CompletionCallback() {
            @Override
            public void onComplete(Throwable throwable) {
                if (throwable == null) {
                    //Everything is good. Response has been successfully 
                 //dispatched to client
                } else {
                    //An error has occurred during request processing
                }
            }
        }, new ConnectionCallback() {
            public void onDisconnect(AsyncResponse disconnected) {
                //Connection lost or closed by the client!
            }
        });
        managedExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                String result = heavyLifting();
                asyncResponse.resume(result);
            }

            private String heavyLifting() {
                return "RESULT";
            }
        });
    }


Again a new utility for concurrency was used. A runnable object is submitted to     and the task will be executed asynchronously.

Besides the Server side async API, The client side async API is also supported by JAX-RS 2.0. Clients can use this API for asynchronous request response processing. Consider the following code:



The GET is called on async method rather than the request. This changes the synchronous call to an asynchronous one. Instead of responding synchronously, the async method returns a FUTURE object. By calling the get method, the call blocks until the response is ready. The Future.get() will be returned whenever the response is ready.

Again there are callback methods that are used in the async client side and complete the asynchronous scenario. The InvocationCallback interface provides two methods, completed() and failed(). The Completed method is called whenever the processing is finished and the response is received. If you are familiar with FUTURE object, the Completed callback method frees you from checking the isDone() method constantly until the response is ready. Conversely the Failed() method is called whenever the request processing is not successful. Consider the following code:

Future<Response> futureResponse = client.target(“http://www.mydomain.com/resource/”)
   .path("asyncresource").request().async().get(new InvocationCallback<Response>() {
@Override
public void completed(Response response) {
System.out.println("Response code "
+ response.getStatus() );
}
@Override
public void failed(Throwable throwable) {
System.out.println("Failed");
throwable.printStackTrace();
}
});


To some up, Asynchronous API is perfectly supported by JAX-RS 2.0. In this article various methods and mechanisms to use JAX-RS async API were introduced. Asynchronous system design improves system scalability and division of resources. Higher THROUGPUT is one of the remarkable product of following such programming approach.


The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:
java ,jax-rs

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}