My Favorite Part of JAX-RS 2.1: An Implementer’s View

Originally posted on September 19, 2017 at:
https://www.linkedin.com/pulse/my-favorite-part-jax-rs-21-implementers-view-j-andrew-mccright/

In the Spring of 2016, my manager asked me to take the JAX-RS team lead rolefor WebSphere. This responsibility included participation in the Apache CXF open source community and the JAX-RS 2.1 (JSR 370) expert group. I haven’t had much experience in the open source community, and I was definitely not an expert in JAX-RS. Nevertheless, both of these communities accepted me with welcome arms. I mention this mainly to encourage anyone interested in joining either of these communities, but also to highlight my inexperience with this technology. Over the last year and a half, I have learned a lot – and I hope to be able to share some of that knowledge in this article.

The Java API for RESTful Web Services (JAX-RS) is an amazing technology. It makes the development of RESTful services very simple – using POJOs and annotations, but also allows for more complex edge cases. JAX-RS 2.0 further advanced the technology adding powerful features like filters and interceptors, and a Client API that rivals many third party APIs (like the Apache Wink client API or Apache Commons HTTP Client). By doing this in the JAX-RS spec, the user is no longer tied to a particular vendor.

JAX-RS 2.1 continues to advance RESTful services in Java. There are quite a few minor updates – like the addition of the @PATCH annotation to easily enable the increasingly popular PATCH HTTP method, and better support for executors in both the client and server APIs. Perhaps the biggest splash in JAX-RS 2.1 is the Reactive Client. JAX-RS 2.1 requires Java 8, so now it can utilize some of the Java 8 language features like lambda expressions – this can make for some very powerful client code when reacting to server responses.

Still, my favorite part of the JAX-RS 2.1 spec has to be Server Sent Events (SSE). As a former runtime guy and as a father of three, I can say unequivocally that polling stinks (“Are we there yet? Are we there yet? How about now?”). Other tricks for handling server originated responses (like long polling) are better, but only SSE really makes sense.

SSE was first introduced in HTML5. The idea is that a client (often a browser, but doesn’t have to be) will create an HTTP connection to the server and send it’s initial request, but instead of closing the connection, the client and server will keep the connection open, and the server will send data to the client at it’s own pace. The client can then process this data as events. Either side can close the connection. No more polling or tricks – we finally have a legit “pub/sub” type model in the web.

JAX-RS 2.1 makes SSE easy to implement – both as a client or a server. Let’s use a music radio service (like Pandora, or Spotify, etc.) as an example. We want a RESTful service that will tell us what we are listening to, who sings it, etc.

    @GET
    @Path("/songDataStream")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    public void songDataStream(@Context SseEventSink eventSink, @Context Sse sse) {
    Runnable r = new Runnable() {
      @Override
      public void run() {
        Song song = RadioService.getCurrentSong();
        while (song != null) {
          OutboundSseEvent event = sse.newEventBuilder()
                                      .mediaType(MediaType.APPLICATION_JSON_TYPE)
                                      .data(Song.class, song)
                                      .build();
          eventSink.send(event);
          try {
            Thread.currentThread().sleep(song.timeRemaining());
          } catch (InterruptedException ex) {
            // ...
          }
        }  
      }
    }

Ok, this could probably be implemented better, but it shows how simple it can be to write a resource that will fire server sent events. What might the client code look like?

Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost/RadioSvc/rest/songDataStream");
try (SseEventSource source = SseEventSource.target(target).build()) {
  source.register(new Consumer<InboundSseEvent>(){

    @Override
    public void accept(InboundSseEvent event) {
      // called when we receive a new event
      Song song = event.readData(Song.class);
      System.out.println("Now playing " + song.title() + " by " + song.artist());
    }}, new Consumer<Throwable>(){

      @Override
      public void accept(Throwable t) {
        // called when something went wrong
        t.printStackTrace();
      }}, new Runnable() {

        @Override
        public void run() {
          // called when our connection is closed
          System.out.println("All done for now!");                            
        }});

  source.open();
  Thread.sleep(3600000);      // Consume song events for one hour

} catch (InterruptedException e) {
  e.printStackTrace();
}

Both of these examples assumes that the Song class can be easily converted interceptors JSON and back – otherwise, you may need a MessageBodyReader and MessageBodyWriter. But otherwise we’ve got a very straightforward example of sending and receiving server sent events.

Since SSE is part of the HTML5 spec, you don’t need JAX-RS. Most browsers (all major browsers except for Microsoft Internet Explorer) will support SSE. So we could create a simple web page to show what song is playing in HTML and JavaScript, like this:

<!DOCTYPE html>
<html>
<head>
  <title>SSE Radio - Now Playing</title>
</head>
<body>
  <h2>Now Playing:</h2>
  <div id="song">Song: </div>
  <div id="artist">Artist: </div>
  <script>
    var source = new EventSource('rest/songDataStream');

    source.onmessage = function(e) {
        var song = JSON.parse(e.data);
        document.getElementById("song").innerHTML = 'Song: ' + song.title;
        document.getElementById("artist").innerHTML = 'Artist: ' + song.artist;
      };
  </script>
</body>
</html>

If you package that HTML page with your web application, and then browse to it, it will receive song events from the server and automatically update the web page without a full page refresh. Very efficient!

The examples above show how to send data back to a specific client. If multiple clients invoked the songDataStream resource method, each method invocation would create a new thread that would send data specifically to that user. It might turn out to be the same event data – that would depend on the implementation of the business logic in the RadioService. But if you wanted to ensure that all active clients saw the same data, you could use a Broadcaster like this:

    @Context
    private Sse sse;

    private static SseBroadcaster broadcaster;

    private synchronized static SseBroadcaster getBroadcaster(Sse sse) {
        if (broadcaster == null) {
            broadcaster = sse.newBroadcaster();
        }
        return broadcaster;
    }

    @GET
    @Path("listen")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    public void listen(@Context SseEventSink sink, @Context Sse sse) {
        SseBroadcaster b = getBroadcaster(this.sse);
        b.register(sink);
    }

  @PUT
  @Path("playSong")
  public Response playSong(@PathParam("songId") String songId) {
    Song song = RadioService.getSong(songId);
    SseBroadcaster b = getBroadcaster(this.sse);
    OutboundSseEvent event = sse.newEventBuilder()
                                .mediaType(MediaType.APPLICATION_JSON_TYPE)
                                .data(Song.class, song)
                                .build();
        b.broadcast(event);
  }

In this example, multiple clients can “subscribe” to the radio station by invoking the “listen” SSE resource method. Then whenever somebody invokes the normal “playSong” resource method, all subscribing clients will receive the event with the newly selected song data. Both the JAX-RS client and JavaScript examples above would work with this broadcasting example – the only change necessary would be the URL.

Hopefully, you can see why I like this technology so much. It is a simple yet efficient way to send data to interested clients. Be sure to keep an eye out for this technology on WASdev.net – the next WebSphere Liberty Beta will have this tech preview. If you want a sneak peak, you can also see JAX-RS 2.1 in action in the newly-available Open Liberty project.

Leave a Comment

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s