It's actually one of the first toy apps I wrote using Play! Here is version 1 of Application.scala:
... import org.apache.http.client.fluent.Request import org.apache.http.StatusLine object Application extends Controller { abstract trait Addressable { def getAddress():String } trait Pingable extends Addressable { def ping() : StatusLine= { println("Pinging '" + getAddress() + "'") val result = Request.Get( getAddress() ).execute().returnResponse().getStatusLine() println("Pinged '" + getAddress() + "' - got result: '" + result + "'") result } } case class PingTarget(url:String) extends Addressable with Pingable { override def getAddress():String = { url } } def sendPing = Action { val pingTargets = PingTarget("http://www.fake1.net") :: PingTarget("http://www.fake2.com") :: PingTarget("http://www.fake3.com") :: PingTarget("http://subdomain.fake4.com") :: Nil val results = pingTargets.map( pt => (pt.url, pt ping)) Ok(html.ping(results)) } }I was pretty happy with that; I was using a couple of Scala features, namely the use of a trait, a case class, cons-style list construction, the map operation and returning a tuple (containing the URL being pinged and the result of the ping) from it. It was also fun using the new (for me) fluent interface to the Apache HttpClient. And most importantly, it worked!
But this is Scala. I'm surely not done yet, right? Let's try and make this a bit more idiomatic ...
Firstly, the construction of all those PingTarget objects is very repetitive, let's do it just-in-time:
def sendPing = Action { val pingTargets = "http://www.fake1.net" :: "http://www.fake2.com" :: "http://www.fake3.com" :: "http://subdomain.fake4.com" :: Nil val results = pingTargets.map( pt => (pt, PingTarget(pt) ping)) Ok(html.ping(results)) }Actually, let's use an implicit conversion to hide PingTarget from the client entirely:
implicit def str2PingTarget(value: String) = PingTarget(value) ... val results = pingTargets.map( pt => (pt, pt ping))And actually, we can drop the whole PingTarget thing and get the converter to create us an anonymous type:
implicit def str2Pingable(value: String) = { new Addressable with Pingable { override val getAddress = value } }OK. But we're still executing those pings sequentially! How quaint! In the next installment, let's get parallel...
No comments:
Post a Comment
Comments welcome - spam is not. Spam will be detected, deleted and the source IP blocked.