Previously on Andrea’s blog: we have discussed how, given the setup of a database (Part I), we create Actors (with AKKA) to encapsulate workers that access our database through DAOs (or something like DAO). Now we have our Service Layer, our Data Layer… we need the View Layer. Please note that the project reference is this repository on GitHub for an application I did in 8 hours for an interview.

Ok, Controllers are not really complicated with Play. You have just to encapsulate your reply into an Action object, or use the Action.async if you want the reply to be asynchronous (meaning that you have to wait for a Future, for example an interaction with your database). You can moreover have to handle JSON, Play comes with a nice way to encode and decode JSON. For example, in the Admin controller you can find this:

  1. request.body.asJson.map { json =>
  2.         json.validate[(Event, List[Votes])].map {
  3.           case (event, votes) => // Put your code here
  4.         }
  5. }

 

This is using some implicit converters we defined for our objects, in the above case the adminFormRead.
I won’t speak about the template library of Play (you can have an introduction on Play website), it remembers me JSP and anyway it is kind of simple to use and integrate. But for my frontend I had to code using three javascript libraries.

I used JQuery for simple access to ajax calls (remember that ajax calls in JQuery return a promise). I used  AlpacaJS for creating forms and tables (it was the first javascript library I found for this, I think there are easier libs for the same purpose) and I used CanvasJS. All of this wrapped into Bootstrap just to have a basic formatting. Please remember, time was of the essence.
The first version of the frontend needed a refresh of the page to reload the updated data, so I decided to introduce a websocket. A websocket let your browser push and receive data with the server, the definition is straightforward (please notice that if the browser doesn’t support websockets, I just reload the page every 10 seconds, that is absolutely a poor workaround). The most important part of its definition is to set the method to handle a message. In the presenter page I use it to refresh data for the votes. I get the infos for the event with an ajax call, the first result of the vote with ajax and then I setup the websocket for the live updates:

  1. [...]
  2.   // After the first load we try to setup a websocket
  3.   openSocket("/presenter/websocket", function(result) {
  4.     var votes = JSON.parse(result.data);
  5.     generateChart("c_graph", window.storedtype, window.storedevent, votes);
  6.     createTable("#c_table", votes);
  7.   });
  8. [...]

 

How is this handled in the backend? Play provides two easy ways to handle websockets: one is based on  iteratees, but to me (I didn’t study this solution too much, anyway) it looked an easy way to react to incoming messages related to a websocket. I need more to push data from the server than not to receive data from the client. So I adopted the second solution, using Actors.
Now remember again that this was a project I coded in a short time, of course I could have put an in memory cache instead of querying the db for each websocket every tot seconds. Updating the cache every vote or every tot seconds would have saved lot of queries to the database. Again, the presenter should be one, so it makes not so much sense to worry about that.

So, the Presenter controller setup the websocket in this way:

  1. def websocket = {
  2.     implicit val messageFlowTransformer = MessageFlowTransformer.jsonMessageFlowTransformer[String, JsValue]
  3.     WebSocket.accept[String, JsValue] { request =>
  4.       ActorFlow.actorRef(out => WebSocketActor.props(out, presenterActor))
  5.     }
  6.   }

The MessageFlowTransformer transforms our input and ourput into the required format. We don’t care about the input, so we leave it as a String, but our output should become a json object. For each socket we create a WebSocketActor by passing the DAO for the presenter (its Actor, actually, the presenterActor) to its constructor.

Our WebSocketActor is easy to understand: in the initialization (preStart) it set a recurring timeout, meaning that every 5 seconds after the first 2 seconds it sends to itself a message Refresh. The message is handled by recomputing the new data and sending it to the actor out, that is basically the Actor that communicates with the browser through the websocket. If the Actor is closed it disposed the timeout event. Again, nothing too much complicated, there are some implicits like our encoders (Writers) for the JSON of our models.

This closes more or less all the challenges I faced to create a full webapp for this interview. If you need more details, don’t be shy and ask. And…
Stay tuned!

Share