Typesafe Activator

Go Reactive with Java 8 & Play Framework

Go Reactive with Java 8 & Play Framework

typesafehub
Source
March 13, 2014
playframework java java8

Contains a collection of samples for using Java 8 with Play Framework to build Reactive applications.

How to get "Go Reactive with Java 8 & Play Framework" on your computer

There are several ways to get this template.

Option 1: Choose reactive-java8-play in the Typesafe Activator UI.

Already have Typesafe Activator (get it here)? Launch the UI then search for reactive-java8-play in the list of templates.

Option 2: Download the reactive-java8-play project as a zip archive

If you haven't installed Activator, you can get the code by downloading the template bundle for reactive-java8-play.

  1. Download the Template Bundle for "Go Reactive with Java 8 & Play Framework"
  2. Extract the downloaded zip file to your system
  3. The bundle includes a small bootstrap script that can start Activator. To start Typesafe Activator's UI:

    In your File Explorer, navigate into the directory that the template was extracted to, right-click on the file named "activator.bat", then select "Open", and if prompted with a warning, click to continue:

    Or from a command line:

     C:\Users\typesafe\reactive-java8-play> activator ui 
    This will start Typesafe Activator and open this template in your browser.

Option 3: Create a reactive-java8-play project from the command line

If you have Typesafe Activator, use its command line mode to create a new project from this template. Type activator new PROJECTNAME reactive-java8-play on the command line.

Option 4: View the template source

The creator of this template maintains it at https://github.com/typesafehub/activator-reactive-java8-play#master.

Option 5: Preview the tutorial below

We've included the text of this template's tutorial below, but it may work better if you view it inside Activator on your computer. Activator tutorials are often designed to be interactive.

Preview the tutorial

You've just created a simple Play Framework application! Now lets explore the code and make some changes.

View the App

Once the application has been compiled and the server started, your application can be accessed at: http://localhost:9000
Check in Run to see the server status.

To see how HTTP verbs and paths are mapped to controllers that handle the requests check out the conf/routes file. The single controller class for this application is defined in the app/controllers/Application.java file.

Reactive Requests

A regular controller method in Play takes request and returns a response, like:

public static Result syncFoo() {
    return ok("sync foo");
}
Underneath the covers Play is implementing this in a async & non-blocking way, meaning threads in a waiting state can be reclaimed and used for something else. This differs from the usual Java servlet model where each open connection must have a thread. But this simple controller method doesn't have anything asynchronous about it. There is no reason to be asynchronous unless you can also be non-blocking so you don't have to add extra async boilerplate code to your controllers unless there is something to not block on. If you did want to do this same thing asynchronously using Java 8's Lambdas it would look like:
public static F.Promise<Result> asyncFoo() {
    return F.Promise.promise(() -> ok("async foo"));
}
Instead of returning a Result this controller method returns a handle to something that will in the future return the result. In Play's Java API this is a Promise. This now allows an event to trigger the response and in the meantime the thread used for handling this request can be reclaimed. This controller method constructs a Promise that immediately is completed with a value, the Result. The controller is now asynchronous but it still isn't non-blocking because it has nothing to not block on. A simple example of non-blocking is to set a delay or callback to happen after some amount of time. Here is an example of that:
public static F.Promise<Result> asyncNonBlockingFoo() {
    return F.Promise.delayed(() -> ok("async non-blocking foo"), 5, TimeUnit.SECONDS);
}
When a request comes into this controller method the method will immediately return the Promise. Now Play can un-block a thread. During the 5 second delay there won't be any threads used for the request. Try this request in your browser. You will notice that your browser loading indicator spins for 5 seconds but even though there was an open connection to the server for the request, most of the time no threads were being used to handle the request.

Reactive Composition

Artificial delays are a simple place to not-block but aren't are very usual. A more practical place to not-block is when an incoming request must fetch some remote data in order to fulfill the request. Here is an example that does just that:

public static F.Promise<Result> reactiveRequest() {
    F.Promise<WS.Response> typesafePromise = WS.url("http://www.typesafe.com").get();
    return typesafePromise.map(response -> ok(response.getBody()));
}
The controller method returns a Promise so it is asynchronous. Inside the controller method a web client request is made to www.typesafe.com which is async & non-blocking. It returns a Promise<WS.Response> but the controller method must return a Promise<Result>. The WS.Response is essentially the read side of a web response and the Result is the write side. When the response comes back from www.typesafe.com we need to transform the WS.Response into a Result. The map method on the Promise allows us to do exactly that. When the response comes back the Lambda function is executed on the response, which in this case creates the Result containing just the response body. Try it out in your browser. Note: You will notice that since we didn't set the content type the response is just plain text. Usually we'd be working with JSON or other data formats instead of HTML pages. There were two requests, both of which were async & non-blocking; the request from your browser to the Play app and the request from the Play app to www.typesafe.com. Each of these requests was not using a thread when it was waiting for the other side to respond. This is called Reactive Composition. There was some point of time when we were just waiting for www.typesafe.com to respond, during which no threads were being used to handle this request. But as soon as the response came back from www.typesafe.com, the typesafePromise was completed, then the Response was transformed into Result and the controller method's Promise was completed, thus sending the response back to the user. This gets more exciting when a web request composes together more than one async & non-blocking service in order to produce a result. Here is an example of a controller method that makes two web requests:
public static F.Promise<Result> reactiveComposition() {
    final F.Promise<WS.Response> twitterPromise = WS.url("http://www.twitter.com").get();
    final F.Promise<WS.Response> typesafePromise = WS.url("http://www.typesafe.com").get();

    return twitterPromise.flatMap((twitter) ->
            typesafePromise.map((typesafe) ->
                    ok(twitter.getBody() + typesafe.getBody())));
}
In this case an incoming request needs to compose together responses from www.twitter.com and www.typesafe.com. One way to get the responses from both requests in a async & non-blocking way is to call flatMap on one, then inside that Lambda function, call map on the other. The reason for the flatMap is it's Lambda function takes a response but returns a Promise<Result> instead of just a Result. Using a map in this way would result in a Promise<Promise<Result>> and we really just a Promise<Result> so we flatten them. (Note: flatMap is really a map and a flatten together.) Try this example out in your browser. Now three requests are chained together and are all async & non-blocking. So there is some amount of time when we are waiting on either www.twitter.com and www.typesafe.com and no threads are being used for the user's request.

Reactive Push

Not only can typical web requests be async & non-blocking but this same foundation can be used for doing Reactive Push from the server to the client. Play supports three different ways to do this which have varying browser support: Comet, Server Sent Events, and WebSockets. WebSockets in unique because it supports bi-directional Reactive Push so the client can also push messages to the server. Here is an example controller method that sets up the Server Sent Event channel (also known as EventSource) and sends a message when the browser connects to that channel:

public static Result events() {
    EventSource eventSource = new EventSource() {
        public void onConnected() {
            sendData("hello");
        }
    };
    return ok(eventSource);
}
Note: This example doesn't yet take advantage of Lambdas but it will be able to in the upcoming Play 2.3 release. Also in most cases these messages would be JSON but this simple example just sends a string. You can find the client-side code for this example (written in CoffeeScript) in the app/assets/javascripts/index.coffee file. Once created the eventSource object can be used to send messages to the client whenever your applications wants to push a message. The only time a thread is used for this push connection is when a message is being sent.

WebSockets provide a way to do bi-directional push. In Play this is done async & non-blocking like everything else. Here is a controller method that creates the WebSocket:

public static WebSocket<String> echo() {
    return new WebSocket<String>() {
        public void onReady(final In<String> in, final Out<String> out) {
            in.onMessage(out::write);
        }
    };
}
In this case the WebSocket has a onMessage handler for when the client sends a message to the server. This uses a Java 8 method handle to simply send that message back down to the client. Check out the app/assets/javascripts/index.coffee file to see the client-side of this example.

comments powered by Disqus