<img height="1" width="1" src="https://www.facebook.com/tr?id=1076094119157733&amp;ev=PageView &amp;noscript=1">

As part of Scala Days 2014 in Berlin, the Go Reactive Activator Contest was announced. The aim was to demonstrate a Reactive Application using the Typesafe Activator. We decided to participate, because it was an interesting opportunity to learn, have fun and the possibility of winning a prize helped too! Our Reactive Orientation Activator template was awarded with the first prize in the contest and the intention of this blog post is to discuss what we built.The template contains a thorough tutorial so we encourage you to have a look, try the application and also read the code. We will split the solution into multiple blog posts so that we can introduce the technologies in sufficient detail. We'll also describe and discuss the concepts, technologies, various alternatives that are provided to programmer to meet the goals. It should provide resources for further education and help even beginners to start with building Reactive Applications.

Typesafe activator

We probably don't have to introduce the Typesafe Activator but in case you don't know it. It is a tool helping to quickly start with Typesafe stack and you can try them without a large amount of preparation. It also runs in a web browser and provides support for all phases of development cycle - code editing, compilation, tests execution, starting and debugging the application. It is built on top of the Play framework and you can also use it to generate projects so that you can carry on the development within Idea or Eclipse. We think it's a useful tool at Cake, and for more information you can have a look at the official site. The Activator contains quite a few templates and each one is an example of a reactive application highlighting use of Scala, Typesafe technologies  and cooperation of the Typesafe stack with other technologies and languages in a form readable and helpful for beginners. Our template demonstrates how a non-trivial application can be written very quickly, elegantly, readably while being scalable - and with just a few lines of codes! It comprisesof a client-side  JavaScript application built using Ember.js, websockets and WebGL powered by Three.js, a JavaScript 3D library whic is then served from Play 2 Framework back end server written in Scala which works with high velocity data from multiple sources using Play Iteratees and Akka. We have choosed technologies which were not present in the other templates as it was one of the competitions conditions. Reactive Orientation template So what did we build?  The architecture consists of two main parts: 
  • front end for a mobile device and dashboard
  • non-blocking back end server running Play
The main functionality of the Play server is to act as a router for web socket messages. It accepts connections on two different web sockets. The first web socket receives messages with data about spatial orientation from an arbitrary number of mobile devices. Web sockets, in combination with orientation data serve, as a good descriptive source of data with reasonably high volume and velocity. The server applies a transformation function to each message and merges streams of messages from all devices into a single stream. This stream is then broadcasted to all connected dashboard websockets. The data for each individual device is then displayed in real time. This is illustrated on the figure below.

Play framework backend

Play controller and web socket handling

The traditional way of handling websockets in Play application is by using Iteratees. Play 2.3 brings better support for handling websockets using Actors/Iteratees, where websockets are defined as a standard play endpoints in the routes file.
GET /mobileWebSocket controllers.Application.mobileWebSocket
GET /dashboardWebSocket controllers.Application.dashboardWebSocket
The main work of the server part of the application happens in Application.scala.
object Application extends Controller with IpAddress {
val (dataEnumerator, dataChannel) = Concurrent.broadcast[JsValue]
implicit val timeout = Timeout(2 second)
def index = Action {
println(getIpAddresses())
println(Runtime.getRuntime().availableProcessors())
Ok(views.html.index(getIpAddresses()))
}
def mobileWebSocket = WebSocket.acceptWithActor[OrientationChangeEvent,
JsValue] { request => out =>
Props(new StreamMergingActor(dataChannel)) } def dashboardWebSocket = WebSocket.using[JsValue] { request => (Iteratee.ignore, dataEnumerator) } }
This object is the only Play Controller in the whole application. It has three methods. The index method attempts to retrieve network interfaces to be able to present the IP address and then presents index.scala.html view.
The most elegant way is to use the Play actor sockets (introduced in Play 2.3) for connections from mobile devices and Iteratees/Enumerator for dashboard sockets. You can read about both options in Play scala web sockets.
  
The controller has one instance of Enumerator and one instance of Channel. Messages pushed to the Channel will be received by web sockets using the Enumerator. This is important to understand, because these will be shared by actors that will push messages to the Channel and device websockets who will use the Enumerator.
  
Method mobileWebSocket is triggered when a new web socket connection is started from the mobile device. When using actor sockets, Play automatically creates one actor for each connection on the web socket. This is a very convenient way to scale - actors can run in parallel and have a nicely distributed responsibility. Plus, having as many actors as devices won’t create a performance bottleneck or a single point of failure.
Play automatically sends a message to the specified actor when a message on the web socket interface is received. The type of the message is specified by the first type parameter of acceptWithActor function It's possible to achieve the same using Iteratees and Enumerators approach. The code would then look, for example, like this:
def mobileWebSocket = WebSocket.using[OrientationChangeEvent] {
request =>
val in = Iteratee.foreach[OrientationChangeEvent] {
mergingActorRouter ! _  }
val out = Enumerator.empty[OrientationChangeEvent]

(in, out)
}

In this case, we would need to take care of the number of actors manually. One solution would be to create a Router that distributes incoming messages according to a predefined logic. The option to create a router would be to add one actor to the routees with each connection or create a router with a fixed number of actors equal to number of CPU cores available on the machine.

 lazy val mergingActorRouter = Akka.system.actorOf(RoundRobinPool(
Runtime.getRuntime().availableProcessors()) .props(Props(new StreamMergingActor(dataChannel))))

The method, dashboardWebSocket, manages the web socket connections from the dashboard page by using an Iteratee and Enumerator. Iteratee is a representation of incoming message stream and Enumerator of the outgoing. The code for handling the web sockets looks like this:

def dashboardWebSocket = WebSocket.using[JsValue] {
request => (Iteratee.ignore, dataEnumerator)}

This solution is very elegant and minimal, because we again use Play to do the hard work. We just use the same channel for each of the incoming websocket connections. When a message is received from mobile device, the actor that is responsible for handling the message will simply push it to this channel and because it is shared by all Dashboard web sockets, they will automatically all receive the message. In addition, this abstraction very nicely illustrates the intended functionality - messages from multiple devices are merged into one stream! Notice also the Iteratee is ignored (because we are not expecting any messages from the dashboard apart from initial web socket connection). Again this is not the only option and it would be possible implement the same logic using Actor web sockets, but we would have to manually handle the fact that the response is not going to the same socket as the received message.

To summarize the above solution, one actor is created for each Device connection. All these actors push messages the same shared output channel which in turn is also shared by all Dashboard connections.

Scala’s ecosystem offers a variety of options to handle this use case. One notable alternative to Play would be for example Spray.

Data stream merging using Akka actors

The application only uses one user defined actor located in StreamMergingActor.scala

object StreamMergingActor {
case class OrientationChangeEvent
deviceInfo: String, 
deviceId: String,
colour: Int, 
data: OrientationChangeData
) case class OrientationChangeData(
alpha: Double, beta: Double,  gamma: Double ) } class StreamMergingActor(dataChannel: Channel[JsValue]) extends Actor
with DegreesToRadiansConversions { def receive = { case e: OrientationChangeEvent => produceMessage(convertDegreesToRadians(e)) def produceMessage(event: OrientationChangeEvent) =  dataChannel.push(Json.toJson(event)) }

The instances of this actor are spawned by Play when web socket connection is accepted in controller's mobileWebSocket method described in previous section. The role of this actor is to merge incoming streams from the devices and send the resulting stream to dashboards using the share channel. The companion object StreamMergingActor defines messages which the actor understands. The OrientationChangeEvent and OrientationChangeData represent one single message received from the mobile device. Each message contains deviceId, information about the device, assigned colour and three values - alpha, beta and gamma - which represent the orientation data and will be explained later. Most important fact is, that the actor holds one instance of Channel[JsValue] called dataChannel which is passed to him in constructor and messages pushed to this channel are sent to all dashboard web socket connections. When a single message from mobile device is received by Play, it is sent to this actor (as an instance of OrientationChangeEvent case class) and the actor simply pushes the message to this channel, thus merging all incoming streams into one as described earlier. The important fact is that all this is non-blocking. Play sends a message using “fire and forget” technique where it is simply telling the actor what needs to be done and does not wait for response (and if one would wait for a response from actor, it would be done in a non-blocking way by simply defining the expected message in receive function or by using Future as a representation of asynchronous computation as described in the documentation). The message is processed asynchronously to the sender by the actor, usually in different thread.

Data transformations

Html5 device orientation events create data about angles in degrees, but three.js library used for display requires data in radians. This gives us an opportunity to apply a transformation function to the data stream. Trait DegreesToRadiansConversions has one public method called convertDegreesToRadians which converts the angles in data property in OrientationChangeEvent from degrees to radians. Since case classes are immutable, the angle values can not be simply updated and we need to provide a whole new instance of OrientationChangeData. However, data property in OrientationChangeEvent is also immutable so we need to provide a new instance of this class too. This is an implication of immutable data structures that may look like a disadvantage, but it actually is not and accompanies many advantages.

OrientationChangeEvent(
event.deviceInfo,
event.deviceId,
event.colour,
OrientationChangeData(
math.toRadians(event.data.alpha),
math.toRadians(event.data.beta),
math.toRadians(event.data.gamma)
)
)

This code is fine, but unnecessary. Updating properties in larger structures could become messy even when the logic would be extracted to a kind of factory class. That is why Scala provides copy method on case classes. It creates a new object based on values in the old one and the changes in the selected properties.

event.copy(data = OrientationChangeData
math.toRadians(event.data.alpha),
math.toRadians(event.data.beta),
math.toRadians(event.data.gamma)))

This template uses another approach which utilizes Scalaz library and a concept called lenses known from functional programming. A lens is created by passing get and set functions. We can then use the lens to modify the value viewed through it. Scalaz is a library which provides purely functional data structures to complement those from the Scala standard library.

trait DegreesToRadiansConversions {
def convertDegreesToRadians(event: OrientationChangeEvent) = {
val dataLens = Lens.lensu
[OrientationChangeEvent, OrientationChangeData] ( (a, value) => a.copy(data = value), _.data ) dataLens mod ((data: OrientationChangeData) => OrientationChangeData(math.toRadians(data.alpha),
math.toRadians(data.beta), math.toRadians(data.gamma)), event) } }

Note that the template uses the same data structure for both radians and degrees which may not be the best practice, because the client does not know which value is stored in it. It is used for the opportunity to discuss copy and lenses concepts, but otherwise you may want to distinguish the cases for example by using types, generics or separate classes.

Getting the IP address of the server

TraitIpAddress provides functionality to retrieve ip address. The most interesting thing here to note is how easily can Java functions be used in Scala. Java collections are transformed to Scala collections using asScala and therefore they can then be cleanly manipulated using Scala's collection transformations like map and flatMap. The trait also uses Validation from Scalaz to handle errors encountered during the address retrieval. In this case, it is used instead of try-catch block well known from most OO languages, because Validation makes error handling more explicit (it tells the reader explicitly that it can contain either an error description or a result), readable and provides a nice api for composition of multiple errors or computation results using monadic operators. Other alternatives to consider for this purpose are Scala’s Try and Either.

trait IpAddress {
def getIpAddresses() = {
def formatIpAddress(address: InetAddress): String =
address.getAddress.take(4).map(_ & 0xFF).mkString(".")
def findIpAddresses() = {
Validation.fromTryCatch(
NetworkInterface
.getNetworkInterfaces().asScala
.flatMap(_.getInetAddresses.asScala)
.map(formatIpAddress)
.toList
)
}
findIpAddresses() match {
case Success(addresses) => addresses.mkString(", ")
case Failure(_) => "Ip address could not be retrieved. Please find 
ip address of your server manually to continue." } } }

Json marshalling

Json marshalling and unmarshalling operations to convert json messages on websocket to objects in Scala and back to json are also very clean in Play and Scala generally. Notice we don’t need to do any marshalling explicitly. The signatures of methods that are used to handle web socket connections.

def acceptWithActor[In, Out]
(f: RequestHeader => HandlerProps)
(implicit in: FrameFormatter[In], out: FrameFormatter[Out],
app: Application, outMessageType: ClassTag[Out]): WebSocket[In, Out]
def using[A](f: RequestHeader => (Iteratee[A, _], Enumerator[A]))
(implicit frameFormatter: FrameFormatter[A]): WebSocket[A, A]

both require an implicit parameter called FrameFormatter. It is provided by importing object JsonFormats to scope and Scala compiler will inject the implicit parameter for us.

import json.JsonFormats._

All the case classes we use to represent web socket messages can be marshalled and unmarshalled using the default formats as shown in the below code snippet. For more complicated cases, you can write your own format definitions.

object JsonFormats {
implicit val eventDataJsonFormat = Json.format[OrientationChangeData]
implicit val eventJsonFormat = Json.format[OrientationChangeEvent]
implicit val eventFrame: FrameFormatter[OrientationChangeEvent] =
FrameFormatter.stringFrame.transform(_.toString,Json.parse(_).as
[OrientationChangeEvent])
}
That is it for the Play server application! As you can see only a very little code is required to accomplish the required functionality. Most of the heavy lifting is already done by Akka and Play. In next blog post we will have a look at Ember.js so stay tuned. We are now however completely focused on our pretty new 3DR RTF Y6 drone!

 

Need help on your next project?

Recent Posts

Posts by Topic

see all

Subscribe to Email Updates