Improved developer experience and MicroProfile integration for MicroProfile Rest Client 1.2

Originally posted on March 28, 2019 at:
https://openliberty.io/blog/2019/03/28/developer-experience-microprofile-rest-client.html

MicroProfile Rest Client is a type-safe client API for invoking RESTful services. Version 1.2 improves the developer experience and enhances integration with other MicroProfile technologies such as CDI, Fault Tolerance, OpenTracing, etc. MicroProfile Rest Client 1.2 is part of MicroProfile 2.2, which is available in Open Liberty 19.0.0.3.

Previous releases of MicroProfile Rest Client lacked integration with CDI, Fault Tolerance, OpenTracing, etc. making it difficult to add things like timeouts, retries, circuit breakers, etc. to client interfaces. MicroProfile Rest Client 1.2 improves integration with other MicroProfile technologies but also improves the developer experience so that you can specify the base URL directly in the @RegisterRestClient annotation in the interface and specify connect and read timeouts in a portable fashion.

Sending HTTP headers or propagating them from a JAX-RS request has been a complicated problem with prior releases, but not anymore. Now you can specify HTTP headers to send or propagate using the new @ClientHeaderParam annotation, MicroProfile Config properties, or by implementing a new ClientHeadersFactory interface.

To enable the MicroProfile Rest Client feature in your server.xml:

<featureManager>
  <feature>mpRestClient-1.2</feature>
</featureManager>

Here is an example of specifying the URI in the annotation on the interface:

package io.openliberty.rest.client;
...
@RegisterRestClient(baseUri="http://localhost:9080/myBaseUri")
public interface ClientWithURI {
...

This can still be overridden by specifying a MicroProfile Config property like this:

io.openliberty.rest.client.ClientWithURI/mp-rest/uri=http://localhost:9080/myOverriddenBaseUri

If the MicroProfile Rest Client interface is invoked from within a JAX-RS resource class, then it is possible to propagate HTTP headers from the incoming request to the outgoing Rest Client request by specifying the headers to propagate using this MP Config property:

org.eclipse.microprofile.rest.client.propagateHeaders=Authorization,MyCustomHeader

It is also possible to specify or generate a header value using annotations like this:

@ClientHeaderParam(name="HeaderOrigin", value="MPRestClientInOpenLiberty")
@ClientHeaderParam(name="MyHeader", value="value1")
@Path("/somePath")
public interface MyClient {

    @GET
    @ClientHeaderParam(name="MyHeader", value="{computeValue}")
    MyResponse getSomeResponse();

    default String computeValue() {
        return "value2";
    }
...

In this example, the client would send two newly-created HTTP headers when the getSomeResponse() method is invoked:

    HeaderOrigin: MPRestClientInOpenLiberty
    MyHeader: value2

Header values can be computed by surrounding the method name in curly-braces. The only methods that can be specified to compute a header value are default interface methods in the same client interface or public static methods (which must be fully-qualified).

In the case where the same header is specified at the interface level and the method level, the value specified at the method level is used. Thus MyHeader is set to value2 rather than value1.

If the mpFaultTolerance-2.0 feature has been specified, then the functionality of the Rest Client interfaces can be augmented with handy Fault Tolerance APIs, for example:

public interface MyFaultTolerantClient {

    @GET
    @Retry(retryOn={WebApplicationException.class}, maxRetries = 3)
    String method1();

    @PUT
    @Timeout(value=3, unit=ChronoUnit.SECONDS)
    boolean method2(MyEntity entity);

    @POST
    @Fallback(fallbackMethod="queueForLater")
    boolean method3(MyEntity entity);

    default boolean queueForLater(MyEntity entity) {
        return addToRetryQueue(entity);
    }
}

In this example, method1 retries the request up to three times in the event that a WebApplicationException occurs. The @Timeout annotation on method2 automatically sets the connect and read timeouts for the request to 3 seconds, and if the request takes longer than 3 seconds, the Fault Tolerance implementation interrupts the request. Lastly, if an exception occurs when invoking method3, the Fault Tolerance implementation invokes the queueForLater method.

To try it out, take a look at Open Liberty 19.0.0.3, which provides a full implementation of MicroProfile 2.2, including MicroProfile Rest Client 1.2.

For more details, take a look at the MicroProfile Javadoc.

To learn to use MicroProfile Rest Client, see the Consuming RESTful services with template interfaces guide.

Asynchronous REST with JAX-RS and MicroProfile

Originally posted on January 24, 2019 at:
https://openliberty.io/blog/2019/01/24/async-rest-jaxrs-microprofile.html

JAX-RS and MicroProfile Rest Client make writing and consuming RESTful services both easy and powerful, especially when using their asynchronous capabilities. In this post, we’ll look at how to use asynchronous JAX-RS resource methods on the server side. There are limited use cases in which async is suitable on the server, so we’ll try to cover those cases where it is most useful. Async on the client can be very beneficial. We’ll cover the advantages, and we’ll also go over the different ways of implementing an asynchronous client including the JAX-RS 2.0 async APIs, the JAX-RS 2.1 reactive APIs, and the MicroProfile Rest Client 1.1 type-safe, async APIs.

We’ll follow a sample travel planning service at: https://github.com/OpenLiberty/sample-async-rest

The application makes RESTful calls to an airline service, hotel service, and car rental service in order to make reservations and determine the total cost of the trip.

Async on the server (JAX-RS 2.0 and 2.1)

A JAX-RS resource method can be made asynchronous by using the @Suspended annotation on a parameter of type, AsyncResponse. Usually, the resource method would return void since the actual response would be returned using the AsyncResponse.resume(Object) method. Here is an example:

@Path("/airline")
public class AirlineService {

    private static ExecutorService executor = Executors.newFixedThreadPool(10);

    @Path("/cost")
    @GET
    public void getReservation(@QueryParam("from") String from,
                               @QueryParam("to") String to,
                               @QueryParam("start") LocalDate start,
                               @QueryParam("end") LocalDate end,
                               @Suspended AsyncResponse ar) {

        executor.execute( () -> {
            Reservation r = new Reservation();
            r.setDestination(to);
            r.setInitialLocation(from);
            r.setStartDate(start);
            r.setReturnDate(end);
            r.setCost(DBHelper.getCostOfAirlineReservation(from, to, start, end));

            ar.resume(r);
        });

    }
}

So what does this actually do? First, notice that there is a fixed thread pool, limited to 10 threads (this is for simplicity – a better practice would be to make the thread pool size configurable with MicroProfile Config so that you could change this setting without recompiling). We might choose to limit the size of the thread pool to prevent overloading the back-end resource, a database in this case.

Next, notice that the getReservation resource method doesn’t actually return anything. Instead it creates a new Reservation in a Runnable (via lambda) that makes a database call and then returns the reservation to the client through the AsyncResponse object. This means that the thread invoking the getReservation method can return immediately to handle new requests. The client won’t see a response, however, until the call to the Reservation has been constructed and passed to the resume method, which might take a little while depending on how long the database request might take (DBHelper…​). This example is essentially throttling access to the database.

Let’s suppose that the database is running slowly for some reason. If we implement this method synchronously, we might run into a situation where the database starts rejecting work, leading to exceptions thrown back to the client. By implementing this asynchronously, we limit the connections to 10; additional requests would be queued until they could eventually be executed by the executor service. This is ideal so long as the database can eventually catch up with the work.

In practice, it is my opinion that there are relatively few use cases where asynchronous methods on the server are more effective than their synchronous counterparts. Throttling access to another resource (as above) is one use case. Others might include where the thread factory has created threads optimized for the response (i.e. they already contain data on a ThreadLocal). Perhaps there is a performance benefit on some application servers; Open Liberty uses a well-tuned, global thread pool, there aren’t a lot of performance benefits to using async methods on the server.

But the client is a different story…​

Async on the client using callbacks (JAX-RS 2.0)

Let’s say that your service returns a result that is composed of the results of a few other remote services. You could invoke those remote services serially, but that really only makes sense if your thread pool is limited. Instead, you could invoke the services asynchronously, using more threads, but saving time for the entire call. Here is an example:

@Path("/jaxrs20/travel")
public class MyTravelPlanningService {

    private static WebTarget airlineWebTarget = ClientBuilder.newClient()
                                                             .target(App.AIRLINE_URL);

    private static WebTarget hotelWebTarget = ClientBuilder.newClient()
                                                           .target(App.HOTEL_URL);

    private static WebTarget carRentalWebTarget = ClientBuilder.newClient()
                                                               .target(App.RENTAL_URL);

    private class ReservationInvocationCallback implements InvocationCallback<Reservation> {
        private final CountDownLatch latch;
        private final DoubleAdder costAdder;
        Throwable throwable;

        ReservationInvocationCallback(CountDownLatch latch, DoubleAdder adder) {
            this.latch = latch;
            this.costAdder = adder;
        }

        @Override
        public void completed(Reservation r) {
            costAdder.add(r.getCost());
            latch.countDown();
        }

        @Override
        public void failed(Throwable t) {
            t.printStackTrace();
            throwable = t;
            latch.countDown();
        }
    }

    @Path("/cost")
    @GET
    public double getCostOfTravel(@QueryParam("from") String from,
                                  @QueryParam("to") String to,
                                  @QueryParam("startDate") LocalDate start,
                                  @QueryParam("returnDate") LocalDate end) {

        final CountDownLatch latch = new CountDownLatch(3);
        final DoubleAdder cost = new DoubleAdder();
        ReservationInvocationCallback callback = new ReservationInvocationCallback(latch, cost);
        airlineWebTarget.queryParam("from", from)
                        .queryParam("to", to)
                        .queryParam("start", start)
                        .queryParam("end", end)
                        .request()
                        .async()
                        .get(callback);
        hotelWebTarget.queryParam("location", to)
                      .queryParam("start", start)
                      .queryParam("end", end)
                      .request()
                      .async()
                      .get(callback);
        carRentalWebTarget.queryParam("location", to)
                          .queryParam("start", start)
                          .queryParam("end", end)
                          .request()
                          .async()
                          .get(callback);

        try {
            latch.await();
        } catch (InterruptedException ex) {
            throw new WebApplicationException(ex, 500);
        }
        if (callback.throwable != null) {
            callback.throwable.printStackTrace();
            throw new WebApplicationException("Failure in downstream service",
                callback.throwable, 500);
        }
        return cost.doubleValue();
    }
}

This slightly more complex example uses an InvocationCallback which will be notified when the async response has completed (either through the completed method if the response is successful, or the failed method if not). We tell the client to invoke the services asynchronously by invoking the async() method on the Invocation.Builder object that is returned from the request() method. That returns an instance of AsyncInvoker. From there, we use an instance of the callback to asynchronously invoke three different services. We’ll only end up waiting for as long as the longest of those three services. Very efficient!

In a failure case we log the exception and then propagate it back to the client. Also, we are caching and re-using the WebTarget for each remote service. This avoids a lot of object creation in the JAX-RS implementation code, improving overall performance.

This works well, but JAX-RS 2.1 gives us another option: a reactive client API.

Async on the client using Reactive APIs (JAX-RS 2.1)

JAX-RS 2.1 adds support for reactive APIs. Out of the box, JAX-RS 2.1 supports a CompletionStage return type. This allows users to string together a chain of stages that can be completed asynchronously. JAX-RS 2.1 also allows users to extend the reactive capabilities of the client by using other reactive providers such as RxJava, Guava, etc. For simplicity and brevity, we will only cover the CompletionStage approach here. My colleague, John Koehler is writing a blog post that will provide more information on reactive extensions. Stay tuned!

Similar to the async() method in JAX-RS 2.0 (which is still available in 2.1), we get an instance of a CompletionStageRxInvoker by using the rx() method on the Invocation.Builder. The CompletionStageRxInvoker has methods similar to the AsyncInvoker, but returns CompletionStage rather than Future. Also note that these methods do not take an InvocationCallback either.

So, if we were to re-write the JAX-RS 2.0 client example using the reactive client in JAX-RS 2.1, it would look something like this:

@Path("/jaxrs21/travel")
public class MyTravelPlanningService {

    private static WebTarget airlineWebTarget = ClientBuilder.newClient()
                                                             .target(App.AIRLINE_URL);

    private static WebTarget hotelWebTarget = ClientBuilder.newClient()
                                                           .target(App.HOTEL_URL);

    private static WebTarget carRentalWebTarget = ClientBuilder.newClient()
                                                               .target(App.RENTAL_URL);


    @Path("/cost")
    @GET
    public double getCostOfTravel(@QueryParam("from") String from,
                                  @QueryParam("to") String to,
                                  @QueryParam("startDate") LocalDate start,
                                  @QueryParam("returnDate") LocalDate end) {

        final CountDownLatch latch = new CountDownLatch(3);
        final DoubleAdder cost = new DoubleAdder();
        final AtomicReference<Throwable> throwable = new AtomicReference<>();

        BiConsumer<Reservation, Throwable> consumer = (r, t) -> {
            if (t != null) {
                throwable.set(t);
            } else {
                cost.add(r.getCost());
            }
            latch.countDown();
        };

        airlineWebTarget.queryParam("from", from)
                        .queryParam("to", to)
                        .queryParam("start", start)
                        .queryParam("end", end)
                        .request()
                        .rx()
                        .get(Reservation.class)
                        .whenCompleteAsync(consumer);

        hotelWebTarget.queryParam("location", to)
                      .queryParam("start", start)
                      .queryParam("end", end)
                      .request()
                      .rx()
                      .get(Reservation.class)
                      .whenCompleteAsync(consumer);

        carRentalWebTarget.queryParam("location", to)
                          .queryParam("start", start)
                          .queryParam("end", end)
                          .request()
                          .rx()
                          .get(Reservation.class)
                          .whenCompleteAsync(consumer);
        try {
            latch.await();
        } catch (InterruptedException ex) {
            throw new WebApplicationException(ex, 500);
        }

        Throwable t = throwable.get();
        if (t != null) {
            throw new WebApplicationException("Failure in downstream service",
                                              t, 500);
        }
        return cost.doubleValue();
    }
}

Functionally, the JAX-RS 2.1 reactive client example here is not much different from the JAX-RS 2.0 async client, but I think the reactive example is cleaner and easier to understand. And less code to maintain is also nice!

Speaking of less code…​ hopefully by now you’ve heard about the MicroProfile Rest Client. It is a proxy-based, type safe client API for RESTful services. Starting in MP Rest Client 1.1, you can make asynchronous calls using Java 8’s CompletionStage. Let’s check out that approach:

Async on the client using type-safe interfaces (MicroProfile Rest Client 1.1)

MicroProfile Rest Client takes a different approach to accessing remote RESTful services – a more type-safe approach where an interface, annotated similar to a JAX-RS resource, represents a remote service. Invoking methods on the client interface would be similar to invoking methods on a service hosted locally – with clever usage of providers like ResponseExceptionMapper, ParamConverterProvider, MessageBodyReader, MessageBodyWriter, etc. which allows us to design a service interface that indeed acts like it is local.

In order for a Rest Client method to be executed asynchronously, it must return a CompletionStage. Note that in MP Rest Client 1.2, it is also possible to use MP Fault Tolerance’s @Asynchronous annotation. This functionality is outside the scope of this post, but the jist is that if your interface method returns a Future, then the MP Fault Tolerance implementation will invoke the method on a separate thread, immediately returning a Future. You can find more information about the Fault Tolerance APIs at the project site.

So in our travel planning example, you might want to create client interfaces like:

@Path("/airline")
@RegisterProvider(LocalDateParamConverter.class)
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface AirlineServiceClient {

    @Path("/cost")
    @GET
    CompletionStage<Reservation> getReservation(@QueryParam("from") String from,
                                                @QueryParam("to") String to,
                                                @QueryParam("start") LocalDate startDate,
                                                @QueryParam("end") LocalDate endDate);
}

And you would invoke the client like this:

@Path("/mpRest/travel")
public class MyTravelPlanningService {
    private final static String BASE_URI = "http://localhost:" + App.PORT + App.CONTEXT_ROOT;

    private final static AirlineServiceClient AIRLINE_CLIENT = RestClientBuilder.newBuilder()
                                                                                .baseUri(URI.create(BASE_URI))
                                                                                .build(AirlineServiceClient.class);
    private final static HotelServiceClient HOTEL_CLIENT = RestClientBuilder.newBuilder()
                                                                            .baseUri(URI.create(BASE_URI))
                                                                            .build(HotelServiceClient.class);
    private final static CarRentalServiceClient CAR_RENTAL_CLIENT = RestClientBuilder.newBuilder()
                                                                                     .baseUri(URI.create(BASE_URI))
                                                                                     .build(CarRentalServiceClient.class);

    @Path("/cost")
    @GET
    public double getCostOfTravel(@QueryParam("from") String from,
                                  @QueryParam("to") String to,
                                  @QueryParam("startDate") LocalDate start,
                                  @QueryParam("returnDate") LocalDate end) {
        final CountDownLatch latch = new CountDownLatch(3);
        final DoubleAdder cost = new DoubleAdder();
        final AtomicReference<Throwable> throwable = new AtomicReference<>();

        BiConsumer<Reservation, Throwable> consumer = (r, t) -> {
            if (t != null) {
                throwable.set(t);
            } else {
                cost.add(r.getCost());
            }
            latch.countDown();
        };

        AIRLINE_CLIENT.getReservation(from, to, start, end)
                      .whenCompleteAsync(consumer);

        HOTEL_CLIENT.getReservation(to, start, end)
                    .whenCompleteAsync(consumer);

        CAR_RENTAL_CLIENT.getReservation(to, start, end)
                         .whenCompleteAsync(consumer);

        try {
            latch.await();
        } catch (InterruptedException ex) {
            throw new WebApplicationException(ex, 500);
        }

        Throwable t = throwable.get();
        if (t != null) {
            throw new WebApplicationException("Failure in downstream service",
                                              t, 500);
        }
        return cost.doubleValue();
    }
}

This is even more clean than the JAX-RS 2.1 reactive client API!

The MP Rest Client approach also solves a problem of what to do with ThreadLocal objects that might be required for providers on the outbound request. Let’s say that we have a ThreadLocal object in our application that determines whether a given customer is a preferred loyalty club member. If so, we might add a ClientRequestFilter that would create a custom HTTP header to indicate that to the remote airline, hotel, or car rental service – something like Loyalty-ID: 1234 that might be used by the remote service to upgrade the reservation. The problem is that if the ClientRequestFilter checks the ThreadLocal object for the loyalty ID number on the asynchronous thread, it won’t be there – it was associated with the calling thread, not the async thread. This picture might help clarify the problem.

asyncREST thread local problem

Notice that the Loyalty ID is set on the calling thread, but that ID isn’t propagated to the async threads that are making the requests to the remote services. That’s where the AsyncInvocationInterceptor come into play. This is a provider type introduced in MP Rest Client 1.1 that allows users to propagate ThreadLocal objects – or really anything that is associated with the calling thread. This interface contains two methods (a third method is added in MP Rest Client 1.2 for removing contexts): prepareContext() and applyContext(). The former is invoked on the calling thread prior to “swapping” threads. The latter is invoked on the async thread.

asyncREST thread local solution

The AsyncInvocationInterceptor must be created by a AsyncInvocationInterceptorFactory like so:

public class LoyaltyAsyncInvocationInterceptorFactory
    implements AsyncInvocationInterceptorFactory {

    @Override
    public AsyncInvocationInterceptor newInterceptor() {
        return new AsyncInvocationInterceptor() {

            String loyaltyId;

            @Override
            public void prepareContext() {
                loyaltyId = App.LOYALTY_ID_THREADLOCAL.get();
            }

            @Override
            public void applyContext() {
                App.LOYALTY_ID_THREADLOCAL.set(loyaltyId);
            }};
    }
}

Let’s assume that loyalty members get a 10% discount when booking hotels online. Now let’s try invoking our travel planning site with a loyalty ID:

asyncREST curl output

With MP Rest Client we can get our loyalty discount and save about $200!

Summary

It’s getting easier to do things asynchronously with REST and Java. JAX-RS and MicroProfile give you some powerful tools in this space. Hopefully now you are more prepared to write and consumer RESTful services asynchronously.

If you’ve got any questions or run into any problems, please let us know. You can reach me on Twitter at @AndrewMcCright.

Thanks!

What’s new with REST in Open Liberty in 2018?

Originally posted on December 5, 2018 at:
https://openliberty.io/blog/2018/12/05/REST-Liberty-reactive-2018.html

It’s been a few months since you heard from us, so we wanted to check in and let you know about a few things we’ve been working on and a preview of what we’ve got in the 18.0.0.4 release of Open Liberty.

First, let’s take a look back at what we’ve done earlier this year. Over the summer, we shipped JAX-RS 2.1 in Open Liberty 18.0.0.2. This adds powerful new features like the Reactive Client, Server Sent Events, and more. If you missed it, check out our 18.0.0.2 blog post.

In September, we delivered the MicroProfile Rest Client 1.1 in Liberty 18.0.0.3. This adds asynchronous methods, URI support, better integration with CDI and a RestClientBuilderListener for third-party libraries to integrate with client instances.

While our upcoming 18.0.0.4 release won’t have any blockbuster spec implementations, we have still been hard at work. Here are some of the things we’ve been working on:

New async transport layer

We integrated the Apache HTTP Client transport layer from the CXF project. This improves asynchronous method invocations – in some performance benchmarks, we measured a 20-25% improvement in throughput (your mileage may vary).

Connection pooling enhancements

The JAX-RS client has had HTTP connection pooling for a while, but HTTPS connections were not being pooled. As more and more services require HTTPS (this is a good thing!), it can be a burden for systems to construct, tear down and reconstruct connections to the same endpoint. Starting with Liberty 18.0.0.4, HTTPS connections are now pooled.

Reactive extensions

JAX-RS 2.1 introduced the reactive client, but the spec only requires vendors to implement it using Java 8’s CompletionStage API. Other reactive frameworks can integrate with the reactive client, but that is optional in the spec. With Liberty 18.0.0.4, it is now possible to use these extensions. We’ve tested with RxJava 1 and 2 using providers from Apache CXF and Jersey, and we plan to test more. If there is a particular reactive technology that you would like to use, and it has a JAX-RS RxInvokerProvider implementation, please let us know!

Properties handling in the MicroProfile Rest Client

The RestClientBuilder and MicroProfile Config allows users to specify custom properties to the Rest Client instance. Now, you can use JAX-RS Client properties, such as:

  • com.ibm.ws.jaxrs.client.keepalive.connection – which you can set to close to prevent keeping connections alive for multiple requests
  • com.ibm.ws.jaxrs.client.connection.timeout – milliseconds to wait for the HTTP connection to be established before timing out
  • com.ibm.ws.jaxrs.client.receive.timeout – milliseconds to wait for a response from the remote service once the connection has been established
  • com.ibm.ws.jaxrs.client.proxy.host – hostname of the proxy server to use for requests from this client instance
  • com.ibm.ws.jaxrs.client.proxy.port – port number of the proxy server to use for requests from this client instance

Other bug fixes and minor enhancements

We’re constantly trying to improve the JAX-RS and MicroProfile Rest Client implementation. Sometimes we find things to fix on our own, and sometimes our users help us find bugs to fix. If you discover a bug or can think of something that we can do in Open Liberty to make it better, please let us know! The best way is probably to open an issue in GitHub, but you can also talk with us on the Open Liberty mailing list.

Thanks for checking in with us; we hope you enjoy our 18.0.0.4 release!

Introducing MicroProfile Rest Client 1.0

Originally posted on January 31, 2018 at:
https://openliberty.io/blog/2018/01/31/mpRestClient.html

The Liberty application server now offers the mpRestClient-1.0 feature. This is the implementation of the MicroProfile Rest Client 1.0 API spec released in December 2017. You can try out the MicroProfile Rest Client in our Open Liberty guide.

The MicroProfile Rest Client builds on JAX-RS 2.0 client APIs to provide a type-safe approach for invoking RESTful services. This means writing client applications with more model-centric code and less ‘plumbing’. Although these are client APIs, they are deployed in a server.

Here is a quick run-down of how to create your own REST clients:

The interface

First, we start off with an interface that represents the remote service. The methods of the interface should match the RESTful APIs of the endpoint. So if we want to access a service that provides online music and allows us to view and modify playlists, we might create an interface that looks like this:

@Path("/playlist")
@Consumes("application/json")
public interface MusicPlaylistService {

    @GET
    List<String> getPlaylistNames();

    @GET
    @Path("/{playlistName}")
    List<Song> getPlaylist(@PathParam("playlistName") String name)
        throws UnknownPlaylistException;

    @POST
    @Path("/{playlistName}")
    long newPlayList(@PathParam("playlistName") String name, List<Song> playlist)
        throws PlaylistAlreadyExistsException;

    @PUT
    @Path("/{playlistName}")
    long updatePlayList(@PathParam("playlistName") String name, List<Song> playlist)
        throws UnknownPlaylistException;
}

Just like JAX-RS on the server side, this interface uses annotations like @Path, @Consumes, @GET and @PathParam. From this, we know that when a user invokes the getPlaylistNames method, the MicroProfile Rest Client implementation sends a GET request to the endpoint at <baseUrl>/playlist. The GET request accepts the application/json media type of a list of strings indicating the available names of playlists.

ResponseExceptionMappers

To see what songs are in a given playlist, invoke the getPlaylist method. Notice that this method throws an UnknownPlaylistException – this situation might be indicated on the remote service as returning an HTTP 404 response. In order to convert this response to a specific exception, we need a ResponseExceptionMapper like this:

@Provider
public class PlaylistResponseExceptionMapper implements
    ResponseExceptionMapper<BasePlaylistException> {

    @Override
    public boolean handles(int statusCode, MultivaluedMap<String, Object> headers) {
        return statusCode == 404  // Not Found
            || statusCode == 409; // Conflict
    }

    @Override
    public BasePlaylistException toThrowable(Response response) {
        switch(response.getStatus()) {
        case 404: return new UnknownPlaylistException();
        case 409: return new PlaylistAlreadyExistsException();
        }
        return null;
    }

}

This code assumes that both UnknownPlaylistException and PlaylistAlreadyExistsException are both sub-classes of BasePlaylistException. Notice that the toThrowable returns an instance of the throwable rather than throwing it.

Implementation

Now that we have the interface and response exception mapper written, we just need to build the implementation and then invoke it. There are two ways to build the implementation: using the RestClientBuilder API or using CDI and MicroProfile Config. We’ll start with the RestClientBuilder – it is a little more verbose but can come in handy in environments where CDI is not available, like testing.

RestClientBuilder

...
URL apiUrl = new URL("http://localhost:9080/onlineMusicService");
MusicPlaylistService playlistSvc =
    RestClientBuilder.newBuilder()
                     .baseUrl(apiUrl)
                     .register(PlaylistResponseExceptionMapper.class)
                     .build(MusicPlaylistService.class);

List<String> playlistNames = playlistSvc.getPlaylistNames();
for (String name : playlistNames) {
    List<Song> songs = playlistSvc.getPlaylist(name);
    if (hasSongBy(songs, "Band of Horses")) {
        coolPlaylists.add(name);
    }
}
...

First we create a new instance of the RestClientBuilder. We must specify the baseUrl value for the remote endpoint – this is required before building the client. Next, we register the response exception mapper. If we need to register other provider classes like MessageBodyReaders or MessageBodyWriters, filters, interceptors, etc., we would do that here with the register method. Then we build the client, passing in the interface class. After that we can invoke methods on the client like it was any other Java object.

CDI and MicroProfile Config integration

It is also possible to let CDI instantiate the client. For all of the code we have covered so far, the user only needs to install the mpRestClient-1.0 feature in the Liberty server.xml. In order for this CDI approach to operate, we need to add two more features: cdi-1.2 (or 2.0) and mpConfig-1.1 (or 1.2). First, we need to update the MusicPlaylistService with some new annotations:



@Path("/playlist")
@Consumes("application/json")
@Dependent
@RegisterRestClient
@RegisterProvider(PlaylistResponseExceptionMapper.class)
public interface MusicPlaylistService {
    ...

The @Dependent and @RegisterRestClient annotations declare that this interface is to be managed by CDI. The @RegisterProvider annotation tells the MicroProfile Rest Client implementation code to register the specified provider class. This annotation can be repeated for as many providers as necessary. Now we can inject the client in another managed object like this:

@WebServlet(urlPatterns = "/PlaylistServlet")
public class PlaylistServlet extends HttpServlet {

    @Inject
    @RestClient
    private MusicPlaylistService playlistService;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

        List<String> names = playlistService.getPlaylistNames();
        ...
    }

The @Inject combined with the @RestClient decorator tells CDI that we want to inject an instance of the MusicPlaylistService interface. There is still one more step…​ we need to tell the MicroProfile Rest Client implementation the baseUrl value for the remote endpoint. For that, we use MicroProfile Config. The config property to use is <fullyQualifiedInterfaceName>/mp-rest/url. So you could specify this as a system property in the jvm.options file like this:

-Dcom.mypkg.MusicPlaylistService/mp-rest/url=http://localhost:9080/onlineMusicService

CDI injection makes things a lot simpler when it comes to bootstrapping the client and, with MicroProfile Config, it is possible to use different URLs for different environments; for example, use one URL for test and another URL for production, without needing to change code.

Additional Information

For more information on the MicroProfile Rest Client, see the MicroProfile Rest Client 1.0 spec

Get involved in the MicroProfile community at: https://microprofile.io

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.