Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Writing Comet Applications Using Scala and the Atmosphere Framework

DZone's Guide to

Writing Comet Applications Using Scala and the Atmosphere Framework

· Java Zone
Free Resource

Just released, a free O’Reilly book on Reactive Microsystems: The Evolution of Microservices at Scale. Brought to you in partnership with Lightbend.

Writing Atmosphere's Comet based applications is simple. Imagine using Scala instead of Java...it becomes really simple! No need to learn Lift anymore :-)

Not being an expert with Scala at all, I've decided to re-wrote the Chat based application I've recently used when adding cluster support to Atmosphere. This is really my first ever Scala application so don't jump looking at the code! Instead, tweet me a better implementation. I will not go into the details of how to write an Atmosphere application, so if this is the first time you learn about Atmosphere, start here.

For the chat, I've needed to implement two methods: one that will be invoked when suspending a response (Comet's HTTP streaming technique), and one for sending chat messages to those suspended response (to the other chat member). To do that in Scala, I did:

  package org.atmosphere.samples.scala.chat

import javax.ws.rs.{GET, POST, Path, Produces, WebApplicationException, Consumes}
import javax.ws.rs.core.MultivaluedMap
import org.atmosphere.core.annotation.{Broadcast, BroadcastFilter, Suspend}
import org.atmosphere.util.XSSHtmlFilter

@Path("/chat")
class Chat {

var JUNK : String = "<!-- Comet is a programming technique that enables web " +
"servers to send data to the client without having any need " +
"for the client to request it. -->\n"

@Suspend
@GET
@Produces(Array("text/html;charset=ISO-8859-1"))
def suspend() = {
var s = new StringBuilder()
for (i <- 0 to 10){
s.append(JUNK)
}
s.toString()
}

@Broadcast
@Consumes(Array("application/x-www-form-urlencoded"))
@POST
@Produces(Array("text/html"))
@BroadcastFilter(Array(classOf[XSSHtmlFilter],classOf[JsonpFilter]))
def publishMessage(form: MultivaluedMap[String, String]) = {
val action = form.getFirst("action")
val name = form.getFirst("name")

val result: String = if ("login".equals(action)) "System Message" + "__" + name + " has joined."
else if ("post".equals(action)) name + "__" + form.getFirst("message")
else throw new WebApplicationException(422)

result
}
}

To suspend the response, I've annotated the suspend() method (line 15) with @Suspend. The returned value of the suspend() method will be written and then the response will be suspended, waiting for server event, e.g messages from other chatter. Now when someone publish a message, method publishMessage() will be invoked. Since the method is annotated with @Broadcast (line 26), the method's returned value will be broadcaster to all suspended response, e.g. all suspended connections will get a chance to write the message. But since I don't want users to publish script or any kind of attack, I've also added the @BroadcastFilter annotation, which will make sure to filter malicious characters. Since my javascript client expect JSONp response, I've decided to write a BroadcastFilter in Scala that transform the message:

  package org.atmosphere.samples.scala.chat

import org.atmosphere.cpr.BroadcastFilter

class JsonpFilter extends BroadcastFilter[String] {

val BEGIN_SCRIPT_TAG = "<script type='text/javascript'>\n"
val END_SCRIPT_TAG = "</script>\n"

def filter(m : String) = {
var name = m
var message = ""

if (m.indexOf("__") > 0) {
name = m.substring(0, m.indexOf("__"))
message = m.substring(m.indexOf("__") + 2)
}

val result: String = (BEGIN_SCRIPT_TAG + "window.parent.app.update({ name: \""
+ name + "\", message: \""
+ message + "\" });\n"
+ END_SCRIPT_TAG)
}
}

Then I just pass the name of that class to the @BroadcastFilter annotation:

 @BroadcastFilter(Array(classOf[XSSHtmlFilter],classOf[JsonpFilter]))

What amaze me here is one filter is written in Java, the other one in Scala!. That's it. With those two classes, the Atmosphere REST Chat demo works. To complicate the application, I've decided to deploy it into a cluster. This is simple to achieve by annotating the publishMesaage with:

  @Cluster(Array(classOf[JGroupsFilter]))

Now my Scala application is Comet-Cluster enabled! That was fun!

For any questions or to download the above sample, go to our main site and use our Nabble forum (no subscription needed) or follow us on Twitter and tweet your questions there!

Strategies and techniques for building scalable and resilient microservices to refactor a monolithic application step-by-step, a free O'Reilly book. Brought to you in partnership with Lightbend.

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}