Skip to main content
Last updated July 30, 2011 09:02, by Markus Karg
Feedicon  

Abstract

This document descripes two different proposals for the most simple way to instruct JAX-RS to use asynchronous responses from the view of an application programmer. The proposals only solve the actual question "What is the least possible work for the application programmer to prevent the container's request thread from waiting?". It does explicitly not deal with Broadcast or Pub/Sub scenarios, as both are use cases which can built ontop of either proposal later.

Java SE Approach

This proposal is inspired by the Java SE way to tell the JVM that some long running work shall not block the calling thread.

First Attempt

In Java SE asynchronous work is done by ExecutorService and Future, so a Java SE programmer will possibly try this:

private static ExecutorService s = Executors.newCachedThreadPool();

@GET Future<MyEntity> myMethod() {
  Callable c = new Callable<MyEntity>() {
    MyEntity call() {
      MyEntity x = ...created by long running algorithm (e. g. JPA)...
      return x;
    }
  };
  return s.submit(c);
}
The benefit of this approach is that a Java SE programmer has nothing new to learn, as he is used to this API since Java SE 5. The drawback is that the JAX-RS engine must either poll for the result or needs to suspend a thread, so nothing is actually won. A solution to that could be that JAX-RS is internally handing over to another specialized singleton "polling thread" that checks all "open" Futures received so far for being done, which is rather uneffective, but would allow this style of coding (e. g. poll all Futures, then sleep for e. g. 250ms).

Second Attempt

To overcome this problem, a solution is to replace Future by Callable and to get rid of the custom executor service:

@GET Callable<MyBody> myMethod() {
  return new Callable<MyBody>() {
    MyBody call() {
      MyEntity x = ...created by long running algorithm (e. g. JPA)...
      return x;
    }
  }
}
In this second attempt, the calling thread will detect that the result is of type Callable and will place the invocation of myMethod into a work queue out of which a JAX-RS (or container) internal worker thread pool will get fed. The benefit of this approach is that it is even less for the Java SE programmer to code while still there is nothing to learn, and that the actual work will be offloaded to the possibly highly-optimized and managed container thread pool (as utilized in EJB and JCA already). Obviously it is hard to find a simpler approach to async responses with pure Java SE means. A real drawback is hard to identify. People possibly might not like writing that two boilerplate lines of code, but this possibly will get solved with Java SE 8's closure support and should be out of scope therefore.

JAX-RS Approach

To further reduce the amount of code to write and to support the current trend of declarative code style, annotations can be used to further simplify things:

@GET @Async MyBody myMethod() {
  MyEntity x = ...created by long running algorithm (e. g. JPA)...
  return x;
}
What happens here is obviously just syntactic sugar around the second attempt (see above): JAX-RS sees the @Async annotations, thus knowing that what it actually must do is to internally create a Callable that itself calls myMethod, and handle that one as described in the second attempt. The benefit of this approach is the code cannot be any shorter, and it feels just like natural to only add one single annotation to make things work asynchronously. The drawback of this approach is that another annotation is to be learned.

Conclusion

As soon as Broadcasting and Pub/Sub scenarios are getting ignored, there are several rather simple and easy to understand approaches to asynchronous programming in JAX-RS. Broadcasting and Pub/Sub are assumed to be added ontop later, as both are just "users" of asynchronous style. While it seems the most natural approach to JAX-RS is to just add @Async, Java SE programmers possibly will try Future or Callable instead (maybe they don't know @Async or they just don't understand why writing two code lines or having a polling thread shall be an actual problem). So my proposal is to allow all three styles of programming. The annotation based style will be prefered by JAX-RS programmers, while the Callable style just is natural to Java SE programmers. Since it looks just natural to use Future, it will be just comfortable to programmers if JAX-RS also allows that, e. g. by using a common polling thread handing this "problem" in the background (actually one more single thread should not be such a problem that we force people into a particular programming style). So I would suggest supporting all three code styles described in this proposal instead of selecting only one.

 
 
Close
loading
Please Confirm
Close