Asynchronous JAX-RS server side endpoints

JAX-RS 2.0 permits asynchronous generation of the output response in a manner that is similar to the Servlet 3.0 standard, in particular javax.servlet.AsyncContext. In order to achieve this in a REST style resource, somehow the JAX-RS must be informed that the resource method can be executed in another thread internally to the provider. The client does not need to know the exact details of where the method is invoked under the hood.

In order to inform the JAX-RS runtime, that a resource method generates asynchronous output, supply the annotation @javax.ws.rs.container.Suspended and also a new argument @javax.ws.rs.container.AsyncResponse. Yes, there is another JAX-RS sub-package called javax.ws.rs.container with classes and interfaces specifically for server-side containers.

In order to set a JAX-RS to fully asynchronous, the user must annotate the method with @javax.ejb.Asynchronous. Therefore, the JAX-RS resource has to be defined as a session EJB in Java EE 7, it can be either a stateless bean or a singleton.

The following is an example of another book REST style resource, but delivered as an asynchronous EJB:

package je7hb.jaxrs.basic;
import javax.ejb.*;
import javax.ws.rs.*;
import javax.ws.rs.container.*;
import javax.ws.rs.core.*;
import java.util.*;

@Path(«/async/books»)
@Stateless
public class RestfulBookAsyncService {

  private List<Book> products = Arrays.asList(
    new Book("Miguel De Cervantes", "Don Quixote"),
    new Book("Daniel Defoe", "Robinson Crusoe"),
    new Book("Jonathan Swift", "Gulliver's Travels"),
    new Book("Mary Shelley", "Frankenstein"),
    new Book("Charlotte Bronte", "Jane Eyre"));

  @GET
  @Asynchronous
  @Produces(MediaType.TEXT_PLAIN)
  public void getList( @Suspended AsyncResponse asyncResponse) {
    final long SLEEP=500;
    final int N=10;
    try {
      for (int j=0; j<N; ++j ) {
        System.out.print(".");
        System.out.flush();
        Thread.sleep(SLEEP);
      }
    }
    catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println(".
");
    StringBuffer buf = new StringBuffer();
    for (Book b: products) { buf.append(b.title); 
    buf.append('
'), }
    Response response = Response.ok(buf.toString()).build();
    asyncResponse.resume(response);
  }

  static class Book {
    public final String author;
    public final String title;

    Book(String author, String title) {
      this.author = author;
      this.title = title;
    }
  }
}

Inside the RestfulBookAsyncService class, the getList() resource method is triggered on a HTTP GET request on the URI. We contrived in this method to delay the generation of the output with a thread sleep call, so that it is easy to study the output. As soon as the JAX-RS implementation detects the @Suspended invocation; it will pause the output of the response to client on AsyncResponse. It is the combination of the EJB @Asynchronous and @Suspended AsyncResponse that causes the fire-and-forget behavior on the server side.

After the deliberate delay, the getList() method builds the generic response and then passes it to the AsyncResponse instance with a call to resume(). This call signals to the runtime that the asynchronous response will be resumed.

If the method is not annotated with @Asynchronous, then the JAX-RS runtime executes in a synchronous fashion, but the AsyncResponse will be still suspended.

The output from the unit test produces the following result:

RestfulBookAsyncService#acquireResource()
RestfulBookAsyncService.getList() thread: [Thread[http-listener(1),5,main]]
retrieve list asynchronously ...........

sending data back now on thread: [Thread[http-listener(1),5,main]]
**** response=org.glassfish.jersey.client.ScopedJaxrsResponse@3ae4568d
**** text=Don Quixote
Robinson Crusoe
Gulliver's Travels
Frankenstein
Jane Eyre

The extract sample of the output shows the invocation of the REST endpoint in the class RestfulBookAsyncService. In the working code, which you find in the source code and the website, we added @PostConstruct and @PreDestroy annotation methods. We also make use of the JAX-RS Client asynchronous API to invoke the resource in a unit test.

Let's move on to the filtering and interception of the resource and how the JAX-RS can do more advanced processing for your enterprise applications.

Tip

Why must I turn to EJB for full asynchronous operations?

At first glance, it does appear strange that for full asynchronous operation, a resource must be annotated as a session EJB (@Stateless or @Singleton) and the resource method requires a @javax.ejb.Asynchronous. Luckily, for us developers, Java EE containers treat EJB in a much smarter way than they did J2EE. A session EJB is no longer a monolithic behemoth of burden that it was once, modern Java EE servers are perfectly capable of creating thousands of EJB instances on the fly. There is no longer a need to even pool EJB instances as we once did! I do think, personally, that the EJB and CDI expert group missed a trick by not having an annotation for CDI @javax.annotation.Asynchronous.

If you prefer not use to EJB then you may want to investigate the Concurrency API. You can find out more about Java EE 7 ManagedExecutorService in Appendix D, Java EE 7 Assorted Topics.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.253.223