Play framework is joining the Typesafe Stack — More information in the official announcement

Meet the community

Planet Play

Here are collected blog posts from the Play! community. The content is uncensored, unfiltered and represents the views of the individual community members. To have your blog included, post your application to the Google Group.

Secure your web services and AJAX calls with Deadbolt Published February 21, 2012 on Objectify

Deadbolt makes it very easy to add authorization to your Play! application. However, until now, it’s been harder to add the same constraints to web services and AJAX-invoked methods – which is to say, the mechanism worked, but when access failed the response was always HTML. Less, in this asynchronous world, than useful.

Play takes HTML as the default response format when you invoke the Controller#render method. If your application typically, or even occasionally, returns another format then you have a problem. Unless you configure your routes file to specify the response format, or do some content negotiation from the client, you’re pretty much stuck with HTML. The impact for Deadbolt is that while your DeadboltHandler implementation has an onAccessFailure method, there’s no easy way to check what format you’re working with.

If you want to specify a default response format for when DeadboltHandler#onAccessFailure is invoked, you can add an entry to the application.conf file to do this:

deadbolt.default-response-format=json

This will set the request.format field to whatever response type you have set, which will in turn determine which template is called when you invoke render()…html will result in .html templates being rendered, json will result in .json templates being rendered, foo will result in .foo templates, and so on.

If you have an application that returns a mix of response types, then setting a default format may not be of much use to you. In these cases, you may want to use annotations
to give you some hints. There are two built-in annotations with Deadbolt, @JSON and @XML. You can apply these to a controller or to an individual method. When present,
the request format will be set to json or xml respectively before your DeadboltHandler’s onAccessFailure method is invoked.

@With(Deadbolt.class)
public class Foo extends Controller
{
    @Restrict("bar")
    @XML
    public static void getSomeXml()
    {
        // render some XML
    }

    @Restrict("bar")
    @JSON
    public static void getSomeJSON()
    {
        // render some JSON
    }
}

Note that you can annotate a controller with @JSON but have an @XML method in there, and vice-versa.

What about when the next great format is invented? That’s where you have to do your own work. You can add your own annotations to controllers or methods and check for them in your onAccessFailure implementation before you call render.

One important note – whichever forbidden method you invoke from onAccessFailure cannot be a redirect. The easiest way to do this is to create a 403 file in the views/errors directory of your application for each format type, and invoke Deadbolt.forbidden() from your onAccessFailure implementation. See samples-and-tests/content-types for an example.

Ideally, the content types would be specified in the routes file but since route wildcards are both possible and extremely useful, you sometimes need to get implementation-specific.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • StumbleUpon
  • DZone
  • Reddit
  • Facebook
  • Google Bookmarks
  • Slashdot
Read the original post…

Eat your own dog food, but throw in some unknown biscuits for variety Published February 20, 2012 on Objectify

Well, the example app that Jorge Aliss asked me to write to demonstrate a combination of SecureSocial and Deadbolt is working, and working nicely, and as soon as I’ve prettied it up a bit I’ll be releasing it to github and pushing it out to, probably, Heroku.

Deadbolt came about as a result of two projects I worked on that required a specific approach to security that wasn’t addressed by any existing modules of the Play! framework. I wrote and released the module, and it’s been updated every time a new feature was needed by my own projects or through a request by someone else. To use the vernacular, I eat my own dog food.

Let’s call me person A, and I eat my own dog food. Other people – let’s aggregate them into a single entity, person B…person B also eats my dog food, and delicious it is too. Based on my own experiences, Deadbolt dog food covers all the nutritional needs of my own highly-specialized pedigree dogs, and happily, also satisfies person B’s pet food requirements. Good enough…but what about when you suddenly switch dog – and nutritional requirements – and need something completely different? Then you suddenly might find that the dog food you’ve lovingly created and molded has a huge gap right where the vitamins should be.

End of dog food analogy. It’s getting annoying.

The demo app I’ve written – SociallySecure – allows you to log in through various social open auth providers and create an account which can then have other OAuth accounts linked to it. Once they’re linked, you can log in through any of them and get into your personal SociallySecure account. The key account is Twitter (at the moment – this is just a demo!) because security is applied to your tweets when someone is viewing your account page. If you’re friends, or you’ve decided your tweets should be public, the user can see all the exceptional and banal things you’ve tweeted along with those of the people you follow. If you’ve decided your tweets are visible only to friends, when someone views your user page then your tweets are not visible. Fairly simple stuff, but enough to demonstrate dynamic security.

Fairly simple stuff – except for the part where I’m not only considering the user privileges of the logged-in user, but that user’s privileges in relation to another user.

Deadbolt offers dynamic checks in the form of the #restrictedresource tag at the view level, and @RestrictedResource annotation at the controller level. If you’re in the controller level, you can already calculate what you need. In the view level, you’re pretty much screwed unless you’re able to pass in additional information. This is what the latest version of Deadbolt gives you, and without it you have a much more restricted version of dynamic security unless you *really* jump through some hoops.

If you’re curious about how this works, you can pass a map of string parameters to a tag argument called resourceParameters – this map is then available in your RestrictedResourceHandler. You can use it in two ways:

  • The string key/value pairs can be used by you directly
  • The value can be used to do a lookup in the request, or session, or cache, or whatever

The point of this blog post, however, is to emphasize than if you’re going to release something as open source, you’ll have a much higher chance of meeting developer needs if, once you’ve covered all your own use cases, sit down for a couple of hours with another developer and ask them to use it to develop something reasonably complex. It’s pretty much what you’ll see when releasing a product – you can test it to hell and back, but within a couple of hours of it going live you can pretty much guarantee that a user has found a bug.

Think of crucially missing gaps in your code as bugs. The code works perfectly well when it’s running according to what you have in mind, but as soon as it hits the real world then you’ll find that not everyone thinks like you.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • StumbleUpon
  • DZone
  • Reddit
  • Facebook
  • Google Bookmarks
  • Slashdot
Read the original post…

Using SecureSocial in your local dev environment Published February 14, 2012 on Objectify

Jorge Aliss has asked me (about 3 months ago, mea culpa) to write an example application that integrates the Deadbolt authorization module with his excellent SecureSocial module.

The application is currently in development as I take a five minute break to write this, and I thought I would share a handy shortcut for developing your own SecureSocial apps on your local box.

If you’re using, for example, Twitter to provide your OAuth service then you’ll need to provide a callback URL. Since you’re on your local computer, which doesn’t necessarily have its own external IP address then there are a couple of hacks you can use. One involves changing your hosts file to resolve an external URL to your local server.

Another, far easier – and lazier – method, is to use a URL shortener to provide the same situation. bit.ly doesn’t seem to allow request parameters, but goo.gl does. Simply create a shortened URL for http://localhost:9000/securesocial.securesocial/authenticate?type=twitter (adjust as necessary for port, OAuth provider, etc) and use that as the callback address in the application your register with the OAuth provider.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • StumbleUpon
  • DZone
  • Reddit
  • Facebook
  • Google Bookmarks
  • Slashdot
Read the original post…

Playframework, Twitter Bootstrap and Google Maps API Published January 2, 2012 on Wayne

So, what did you do over the Christmas break? Presents, plenty of family time, kick back a little? I did all that and wrote a little web application as well. I thought I would share a little insight into how I got on.

Background

A while back, I created a publicly shared google map so that anyone interested in Play framework could add themselves to the map. A decent number of people signed up, but it was a pain to maintain. There was no control over who could put what where. For example, someone could delete someone else’s pinpoint, change someone else’s details, or the most common issue, overwrite the play framework description and URL’s. So, I decided to create a web application that would allow the community to have a developer map, but without the issues of a simple shared google map.

The tools

Obviously, I used the Playframework, but additionally I decided to Bootstrap from Twitter. Bootstrap, if you haven’t used it yet, is a CSS base that offers a way to develop clean designs and neat interfaces. There are plenty of blogs already about how to use bootstrap, and the documentation itself is pretty complete, but suffice to say, it made the job of building the UI significantly easier. As I am not a naturally artistic person, Bootstrap has allowed me to build a UI I am proud of, without having to suffer for the cause. It fits in with the “just-works” approach of Play, it makes what should be simple, simple.

Secondly, I used Google Maps to render the maps and the icons on top of the maps. I have used Google Maps before, but decided to check out Bing Maps before making my final choice. Put simply, I found Google Maps to do everything I needed, with relative ease, and found no reason why Bing maps could be a better choice.

Quite simply, Play, Bootstrap and GoogleMaps work amazingly well together.

Deployment

As most people tend to do, I decided to deploy the code onto Heroku. I have used Heroku a few times previously, and have had good experiences with it. I was tempted to try something else, due to the limit on the database size of the free account, but as I already have hosting elsewhere, I decided to just use the database on my paid-for hosting alongside Heroku as the application server. Even with this separation, the response times for the application are excellent. It has made me wonder whether there is a gap in the market for a low-end Database-as-a-Service facility to bridge the gap between the Heroku Postgres offerings.

I did have one issue with the deployment, which you may want to be aware of. My views were all lowercase HTML files, rather than camelCase, which was the case for my controller actions. On my Macbook Pro this made no difference, but as soon as I deployed to Heroku I started getting errors. It took me a while to figure this out, because the error logging wasn’t working ver well. Unfortunately I had already committed my code to the local git repository on my mac, which did not care about case differences, so I had to fight with a few git mv commands to move the files to uppercase equivalents. Other than that, the whole thing has worked out pretty well.

Next Steps

Well, its still in beta, so if you guys like it, and it starts to take off, expect more features to start appearing. What I am hoping for is for the word to spread, so that more and more people add themselves to the maps (why not start with the play framework map). Additionally, I would hope that people will create maps for other technologies that they are interested in.

If you have any thoughts or comments, please feel free to get in touch!


Read the original post…

Where’s Felipe? A Location-based Play Framework, Scala, Google Maps Clustering, PostgreSQL, Heroku and Anorm App Published December 31, 2011 on Felipe Oliveira

Post image for Where’s Felipe? A Location-based Play Framework, Scala, Google Maps Clustering, PostgreSQL, Heroku and Anorm App

As I mentioned in a past article, Why Did I Fall in Love with Play! Framework?, I was the tech lead for a few real estate deployments for Fannie Mae, HUD, Foreclosure.com, etc; as you know, real estate is all about LOCATION! LOCATION! LOCATION!

I’m on vacation, but I am still a geek (and my wife is still sleeping!) so I decided to create a location-based application using the all-awesomeness of Play Framework, Scala, Google Maps v3, PostgreSQL and Anorm; you know, for ol’ times’ sake! On the map-side I will show you how to solve the very common “too many markers” problem (see image below) using clustering to group the markers.

See a live demo running on Heroku right here! The complete source code is available at https://github.com/feliperazeek/where-is-felipe. Thank you my crazy French friend Pascal (author of Siena) for the review.

  • First let’s create the data transfer classes returned by the Controller in JSON form and used by Google Maps (markers and clusters). These are very simple classes which will just hold data used by the thin RESTful layer.
  • /**
     * Map Marker
     *
     * @author Felipe Oliveira [@_felipera]
     */
    case class MapMarker(id: String, latitude: Double, longitude: Double, address: Option[String], city: Option[String], state: Option[String], zip: Option[String], county: Option[String])
    
    /**
     * Map Cluster
     *
     * @author Felipe Oliveira [@_felipera]
     */
    case class MapCluster(geohash: String, count: Long, latitude: Double, longitude: Double)
    
    /**
     * Map Cluster Companion
     *
     * @author Felipe Oliveira [@_felipera]
     */
    object MapCluster {
    
        /**
         * Constructor
         */
        def apply(geohash: String, count: Long): MapCluster = {
            val coords = GeoHashUtils decode geohash
            new MapCluster(geohash, count, coords(0), coords(1))
        }
    
    }
    
    /**
     * Map Overlay
     *
     * @author Felipe Oliveira [@_felipera]
     */
    case class MapOverlay(markers: List[MapMarker], clusters: List[MapCluster])
  • Second let’s define the model classes using Play Framework’s Anorm. There’s only one model defined—it’s called Site. That’s a very simple model which contains only basic fields, such as id, address, city, state, city, zip, county, latitude, longitude and geohash. Geohash uniquely identifies geographical areas, a system created by Gustavo Niemyer, and it has many limitations in comparison to true GIS tools, such as PostgreSQL’s PostGIS or search indexes with geo-features (like my personal favorite ElasticSearch). Although geohash has its share of limitations, it’s a very easy way to add geographical capabilities using data stores without GeoSpatial capabilities such as MySQL. In this case, I am using geohashes to group markers, the so-called marker clusters (punches in bunches, baby!). Click here to find a good representation on how geohashes work. I am using the geohash encoder and decoder from Lucene Spatial, very easy to use.
    /**
     * To String Trait
     *
     * @author Felipe Oliveira [@_felipera]
     */
    trait ToString {
        self: Entity =>
    
        /**
         * Reflection-Based ToString
         */
        override def toString = ToStringBuilder.reflectionToString(this)
    
    }
    
    /**
     * Entity Base Class
     *
     * @author Felipe Oliveira [@_felipera]
     */
    trait Entity extends ToString
    
    /**
     * Site Model
     *
     * @author Felipe Oliveira [@_felipera]
     */
    case class Site(
            var id: Pk[Long],
            @Required var name: Option[String],
            @Required var address: Option[String],
            @Required var city: Option[String],
            @Required var state: Option[String],
            @Required var zipcode: Option[String],
            @Required var county: Option[String],
            @Required var latitude: Option[Double],
            @Required var longitude: Option[Double]) extends Entity {
    
        /**
         * Constructor
         */
        def this(address: Option[String], city: Option[String], state: Option[String], zipcode: Option[String], county: Option[String], latitude: Option[Double], longitude: Option[Double]) {
            this(NotAssigned, None, address, city, state, zipcode, county, latitude, longitude)
        }
    
    }
    
    /**
     * Site Companion Object
     *
     * @author Felipe Oliveira [@_felipera]
     */
    object Site extends Magic[Site] {
    
        /**
         * Count
         */
        def count(implicit filters: SearchFilters): Long = statement("select count(1) as count from Site").as(scalar[Long])
    
        /**
         * Map Overlay
         */
        def mapOverlay(implicit filters: SearchFilters): MapOverlay = {
            // Get Map Clusters
            val clusters = mapClusters
    
            // Get Markers
            filters.geohashes = Option(clusters.filter(_.count == 1).map(_.geohash).toList)
            val markers = mapMarkers
    
            // Define Map Overlay
            new MapOverlay(markers, clusters.filter(_.count > 1))
        }
    
        /**
         * Map Clusters
         */
        def mapClusters(implicit filters: SearchFilters): List[MapCluster] = {
            // Get Query
            val query = statement("select " + geohashExpression + " as geohash, count(1) as count from Site", "group by " + geohashExpression + " order by count desc")
    
            // Get Results
            val list: List[MapCluster] = query().filter(_.data(0) != null).map {
                row =>
                    {
                        // Get Fields
                        val fields = row.data
    
                        // Geohash
                        Option(fields(0)) match {
                            case Some(geohash: String) => {
                                // Count
                                val count: Long = fields(1).toString.toLong
    
                                // Map Cluster
                                MapCluster(geohash, count)
                            }
                            case _ => null
                        }
                    }
            } toList
    
            // Log Debug
            please log "Map Clusters: " + list.size
    
            // Return List
            list.filter(_ != null)
        }
    
        /**
         * Map Markers
         */
        def mapMarkers(implicit filters: SearchFilters): List[MapMarker] = {
            // Get Query
            val query = statement("select site.* from Site site", "order by id")
    
            // Get Results
            val list: List[MapMarker] = query().map {
                row =>
                    try {
                        // Id
                        val id = row[String]("id")
    
                        // Fields
                        val address = row[Option[String]]("address")
                        val city = row[Option[String]]("city")
                        val state = row[Option[String]]("state")
                        val zip = row[Option[String]]("zip")
                        val county = row[Option[String]]("county")
                        val latitude = row[Option[Double]]("latitude")
                        val longitude = row[Option[Double]]("longitude")
    
                        // Map Marker (coord required)
                        (latitude, longitude) match {
                            case (lat: Some[Double], lng: Some[Double]) => new MapMarker(id, lat.get, lng.get, address, city, state, zip, county)
                            case _ => null
                        }
    
                    } catch {
                        case error: Throwable => {
                            please report error
                            null
                        }
                    }
            } toList
    
            // Log Debug
            please log "Map Markers: " + list.size
    
            // Return List
            list
        }
    
        /**
         * Statement
         */
        def statement(prefix: String, suffix: Option[String] = None)(implicit filterBy: SearchFilters) = {
            // Params
            val geohashes = filterBy geohashes
            val zoom = filterBy zoom
            val geohashPrecision = filterBy geohashPrecision
    
            // Params will contain the list of name/value pairs that need to be bound to the query
            val params = new HashMap[String, Any]
    
            // This is gonna define the statement that we'll use on the find method
            val terms = new StringBuffer
            terms.append(prefix)
            terms.append(" where ")
    
            // Boundary
            filterBy.hasBounds match {
                case true => {
                    params += "nw" -> filterBy.nw.get
                    params += "ne" -> filterBy.ne.get
                    params += "se" -> filterBy.se.get
                    params += "sw" -> filterBy.sw.get
                    terms.append("latitude between {nw} and {ne} and longitude between {sw} and {se} and ")
                }
                case _ => please log "Ignoring Map Bounds!"
            }
    
            // Geohashes
            geohashes match {
                case Some(list) => {
                    if (!list.isEmpty) {
                        val values = list.map(_.substring(0, geohashPrecision)).toSet
                        terms.append(geohashExpression + " in (" + multiValues(values) + ") and ")
                        terms.append("geohash is not null and ")
                    }
                }
                case _ => please log "Not including geohashes in query!"
            }
    
            // Final one just in case
            terms.append("1 = {someNumber} ")
    
            // Suffix
            terms.append(suffix.getOrElse(""))
    
            // Define SQL
            val sql = terms.toString.trim
    
            // Define Query
            var query = SQL(sql).on("someNumber" -> 1)
            for (param <- params) {             please log "Bind - " + param._1 + ": " + param._2             query = query.on(param._1 -> param._2)
            }
    
            // Return Query
            query
        }
    
        /**
         * Geohash Expression
         */
        def geohashExpression(implicit filterBy: SearchFilters): String = filterBy.zoom match {
            case Some(z: Int) if z > 0 => "substring(geohash from 1 for " + filterBy.geohashPrecision.toString + ")"
            case _ => "geohash"
        }
    }
  • Then let’s define the search filters.
    /**
     * Search Filters
     *
     * @author Felipe Oliveira [@_felipera]
     */
    case class SearchFilters(var ne: Option[Double], var sw: Option[Double], var nw: Option[Double], var se: Option[Double], var geohashes: Option[List[String]] = None, var zoom: Option[Int] = None) {
    
        /**
         * Log Debug
         */
        please log "NE: " + ne
        please log "SW: " + sw
        please log "NW: " + nw
        please log "SE: " + se
        please log "Geohashes: " + geohashes
        please log "Zoom: " + zoom
    
        /**
         * Format Date
         */
        def format(date: Date) = dateFormat format date
    
        /**
         * Geohash Precision
         */
        def geohashPrecision: Int = zoom match {
            case Some(z: Int) if z > 0 => 22 - z
            case _ => 1
        }
    
        /**
         * Geohash Suffix
         */
        def geohashSuffix: String = geohashPrecision toString
    
        /**
         * Has Bounds
         */
        def hasBounds: Boolean = {
            please log "Has Bounds? NE: " + ne + ", SW: " + sw + ", NW: " + nw + ", SE: " + se
            if (ne.valid && nw.valid && nw.valid && se.valid) {
                please log "Yes!"
                true
            } else {
                please log "No!"
                false
            }
        }
    
        /**
         * To Query String
         */
        def toQueryString = {
            // Start
            val queryString = new StringBuilder
    
            // Map Bounds
            if (hasBounds) {
                queryString append "ne=" append ne append "&"
                queryString append "sw=" append sw append "&"
                queryString append "nw=" append nw append "&"
                queryString append "se=" append se append "&"
            }
    
            // Zoom
            zoom match {
                case Some(s) => queryString append "zoom=" append s append "&"
                case _ => please log "No zoom level defined!"
            }
    
            // Log Debug
            please log "Query String: " + queryString
            queryString.toString
        }
    
    }
  • And a bunch of sugar!
    package pretty
    
    import play.Logger
    import play.mvc.Controller
    import org.apache.commons.lang.exception.ExceptionUtils
    import net.liftweb.json.Printer._
    import net.liftweb.json.JsonAST._
    import net.liftweb.json.Extraction._
    import java.util.{ Calendar, Date }
    import org.joda.time.Months
    import java.net.URLEncoder
    import java.text.SimpleDateFormat
    import org.apache.commons.lang.StringUtils
    import play.Logger
    import org.joda.time.DateTime
    import java.util.Date
    import java.sql.Timestamp
    
    /**
     * Helper Object
     *
     * @author Felipe Oliveira [@_felipera]
     */
    object please {
    
        /**
         * JSON Formats
         */
        implicit val formats = PlayParameterReader.Formats.formats
    
        /**
         * Compress
         */
        def compress[A](ls: List[A]): List[A] = {
            ls.foldRight(List[A]()) {
                (h, r) =>
                    if (r.isEmpty || r.head != h) {
                        h :: r
                    } else {
                        r
                    }
            }
        }
    
        /**
         * Time Execution
         */
        def time[T](identifier: String = "n/a")(runnable: => T): T = {
            throwOnError {
                // Define Search Start Time
                val started = new Date
    
                // Execute Action
                val results: T = runnable
    
                // Define Duration Time
                logOnError[Unit] {
                    val ended = new Date
                    val duration = ended.getTime - started.getTime
                    Logger.info("Runnable: " + identifier + ", Duration: " + duration + "ms (" + (duration / 1000.0) + "s)")
                }
    
                // Return Results
                results
            }
        }
    
        /**
         * Now
         */
        def now = new Date()
    
        /**
         * Current Time
         */
        def currentTime = now.getTime
    
        /**
         * Log
         */
        def log(any: String) = Logger info any
    
        /**
         * Report Exception
         */
        def report(error: Throwable) = Logger error ExceptionUtils.getStackTrace(error)
    
        /**
         * Dummy Controller
         */
        private val _dummy = new Controller {}
    
        /**
         * Conf
         */
        def conf(name: String) = play.Play.configuration.getProperty(name)
    
        /**
         * Multi Values
         */
        def multiValues(values: Iterable[String]) = values.mkString("'", "','", "'")
    
        /**
         * Log If Error
         */
        def logOnError[T](runnable: => T): Option[T] = {
            try {
                Some(runnable)
            } catch {
                case error: Throwable =>
                    please report error
                    None
            }
        }
    
        /**
         * Throw if Error
         */
        def throwOnError[T](runnable: => T): T = {
            try {
                runnable
            } catch {
                case error: Throwable => {
                    please report error
                    throw new RuntimeException(error fillInStackTrace)
                }
            }
        }
    
        /**
         * URL Encode
         */
        def encode(value: String) = URLEncoder.encode(value, conf("encoding"))
    
        /**
         * Automatically generate a standard perks json response.
         */
        def jsonify(runnable: => Any) = {
            _dummy.Json(pretty(render(decompose(
                try {
                    val data = runnable match {
                        // Lift-json has a cow if you pass it a mutable map to render.
                        case mmapResult: Map[Any, Any] => mmapResult.toMap
                        case result => result
                    }
                    Map("status" -> 200, "data" -> data)
                } catch {
                    case error: Throwable =>
                        please report error
                        Map("status" -> 409, "errors" -> Map(error.hashCode.toString -> error.getMessage))
                }
            ))))
        }
    
        /**
         * Option[Date] to Pimp Date Implicit Conversion
         */
        implicit def date2PimpDate(date: Option[Date]) = new PimpDate(date.getOrElse(new Date))
    
        /**
         * Option[Date] to Date Implicit Conversion
         */
        implicit def optionDate2Date(date: Option[Date]) = date.getOrElse(new Date)
    
        /**
         * Int to Pimp Int
         */
        implicit def int2PimpInt(i: Int) = new PimpInt(i)
    
        /**
         * String to Date
         */
        implicit def stringToDate(string: String): Date = dateFormat parse string
    
        /**
         * Date to String
         */
        implicit def dateToString(date: Date): String = dateFormat format date
    
        /**
         * Option Date to String
         */
        implicit def optionDate2String(date: Option[Date]): String = date match {
            case Some(d: Date) => d
            case _ => "n/a"
        }
    
        /**
         * Option Double to Pimp Option Double
         */
        implicit def optionDoubleToPimpOptionDouble(value: Option[Double]): PimpOptionDouble = new PimpOptionDouble(value)
    
        /**
         * String to Double
         */
        implicit def stringToDouble(str: Option[String]): Double = {
            str match {
                case Some(s) => {
                    try {
                        s.toDouble
                    } catch {
                        case ne: NumberFormatException => 0.0
                        case error: Throwable => 0.0
                    }
                }
                case _ => 0.0
            }
        }
    
        /**
         * Date Format
         */
        def dateFormat = new SimpleDateFormat("MM/dd/yyyy")
    
        /**
         * String to Option String
         */
        implicit def string2OptionString(value: String): Option[String] = Option(value)
    
        /**
         * Option String to String
         */
        implicit def optionString2String(value: Option[String]): String = value.getOrElse("n/a")
    
        /**
         * String to Option Double
         */
        implicit def string2OptionDouble(value: String): Option[Double] = try {
            if (StringUtils.isNotBlank(value)) {
                Option(value.toDouble)
            } else {
                None
            }
        } catch {
            case error: Throwable => {
                please report error
                None
            }
        }
    
        /**
         * Dinossaur Birth Date
         */
        def dinoBirthDate = {
            val c = Calendar.getInstance()
            c.set(0, 0, 0)
            c.getTime
        }
    
    }
    
    /**
     * Pimp Int
     *
     * @author Felipe Oliveira [@_felipera]
     */
    case class PimpInt(value: Int) {
    
        /**
         * Months Ago
         */
        def monthsAgo = {
            val c = Calendar.getInstance()
            c.setTime(new Date)
            c.add(Calendar.MONTH, (value * -1))
            c.getTime
        }
    
    }
    
    /**
     * Pimp Option Double
     *
     * @author Felipe Oliveira [@_felipera
     */
    case class PimpOptionDouble(value: Option[Double]) {
    
        /**
         * Is Valid
         */
        def valid: Boolean = value.getOrElse(0.0) != 0.0
    
    }
    
    /**
     * Pimp Date
     *
     * @author Felipe Oliveira [@_felipera]
     */
    class PimpDate(date: Date) {
    
        /**
         * Is?
         */
        def is = {
            Option(date) match {
                case Some(d) => d
                case _ => new Date
            }
        }
    
        /**
         * Before?
         */
        def before(other: Date) = date.before(other)
    
        /**
         * After?
         */
        def after(other: Date) = date.after(other)
    
        /**
         * Past?
         */
        def past = date.before(new Date)
    
        /**
         * Future?
         */
        def future = date.after(new Date)
    
        /**
         * Subtract
         */
        def -(months: Int) = {
            val c = Calendar.getInstance()
            c.setTime(date)
            c.add(Calendar.MONTH, (months * -1))
            c.getTime
        }
    
    }
    
    /**
     * Clockman Object
     *
     * @author Felipe Oliveira [@_felipera]
     */
    object Clockman {
    
        /**
         * Pimp Date
         */
        def is(date: Date) = new PimpDate(date)
    
    }
  • Then let’s define the controllers.
    /**
     * Filters Trait
     *
     * @author Felipe Oliveira [@_felipera]
     */
    trait Filters {
        self: Controller =>
    
        /**
         * Search Filters
         */
        def filters = new SearchFilters(ne, sw, nw, se, zoom = zoom)
    
        /**
         * Zoom
         */
        def zoom: Option[Int] = Option(params.get("zoom")) match {
            case Some(o: String) => Option(o.toInt)
            case _ => Option(1)
        }
    
        /**
         * NE Bound
         */
        def ne = boundParam("ne")
    
        /**
         * SW Bound
         */
        def sw = boundParam("sw")
    
        /**
         * NW Bound
         */
        def nw = boundParam("nw")
    
        /**
         * SE Bound
         */
        def se = boundParam("se")
    
        /**
         * Bound Param
         */
        def boundParam(name: String): String = Option(params.get(name)).getOrElse("")
    
    }
    
    /**
     * Main Controller
     *
     * @author Felipe Oliveira [@_felipera]
     */
    object Application extends Controller with controllers.Filters {
    
        /**
         * Index Action
         */
        def index = time("index") {
            views.Application.html.index(filters)
        }
    
    }
    
    /**
     * Geo Controller
     *
     * @author Felipe Oliveira [@_felipera]
     */
    object Geo extends Controller with controllers.Filters {
    
        /**
         * Map Overlay
         */
        def mapOverlay = time("mapOverlay") {
            jsonify {
                implicit val searchWith = filters
                Site mapOverlay
            }
        }
    
    }
  • Now it’s time for the frontend code, it’s mostly sugar so I am just gonna show you the JavaScript part of it, the important piece. Basically it defined the map, calls the RESTful MapOverlay API, grabs the markers and clusters and bind them to the map!
    // "Da" Map
    var map;
    
    // Global Markers Array
    var markers = [];
    
    // Global Debug Flag
    var debug = true;
    if (console == null) {
        debug = false;
    }
    
    // Log Function
    function log(msg) {
        if (debug) {
            console.log(msg);
        }
    }
    
    // Initialize Map
    function initialize() {
        // Map Options
        var myOptions = {
              zoom: 8,
              mapTypeId: google.maps.MapTypeId.ROADMAP
        };
    
        // Define Map
        map = new google.maps.Map(document.getElementById('map_canvas'), myOptions);
    
        // Set Map Position
        map.setCenter(new google.maps.LatLng(40.710623, -74.006605));
    
        // Load Markers
        loadMarkers(map, null);
    
        // Listen for Map Movements
        google.maps.event.addListener(map, 'idle', function(ev) {
                log("Idle Listener!");
                var bounds = map.getBounds();
                var ne = bounds.getNorthEast(); // LatLng of the north-east corner
                var sw = bounds.getSouthWest(); // LatLng of the south-west corner
                var nw = new google.maps.LatLng(ne.lat(), sw.lng());
                var se = new google.maps.LatLng(sw.lat(), ne.lng());
                var q = "&ne=" + ne.lat() + "&sw=" + sw.lng() + "&nw=" + sw.lat() + "&se=" + ne.lng();
                log("Map Bounds: " + q);
                clearOverlays();
                loadMarkers(map, q);
            });
    }
    
    // Clear Markers
    function clearOverlays() {
        log("Clear Overlays!");
        if (markers != null) {
            for (i in markers) {
                markers[i].setMap(null);
            }
        }
        markers = new Array();
    }
    
    // Cap Words
    function capWords(str){
        if (str == null) {
            return "";
        }
        str = str.toLowerCase();
       words = str.split(" ");
       for (i=0 ; i < words.length ; i++){
          testwd = words[i];
          firLet = testwd.substr(0,1); //lop off first letter
          rest = testwd.substr(1, testwd.length -1)
          words[i] = firLet.toUpperCase() + rest
       }
       return words.join(" ");
    }
    
    // Load Markers
    function loadMarkers(map, extra) {
        $(document).ready(function() {
            zoomLevel = map.getZoom();
            if (zoomLevel == null) {
                zoomLevel = 1;
            }
            var url = '/mapOverlay';
            if (document.location.search) {
                url = url + document.location.search;
            } else {
                url = url + "?1=1"
            }
            if (extra != null) {
                url = url + extra;
            }
            url = url + "&zoom=" + zoomLevel;
            log('URL: ' + url);
            $.getJSON(url, function(json) {
                markers = new Array(json.data.markers.length);
                for (i = 0; i < json.data.markers.length; i++) {
                      // Get Marker
                      var marker = json.data.markers[i];
    
                      // Customer Logo
                      var icon = "http://geeks.aretotally.in/wp-content/uploads/2011/03/html5_geek_matt_16.png";
                      var logo = "http://geeks.aretotally.in/wp-content/uploads/2011/03/html5_geek_matt_32.png";
                      var width = 32;
                      var height = 32;
                      var customer = marker.customer;
    
                      // console.log('Marker: ' + marker + ', Lat: ' + marker.latitude + ', Lng: ' + marker.longitude);
                      var contentString = marker.address + ' ' + marker.city + ', ' + marker.state + ' ' + marker.zip;
    
                      var position = new google.maps.LatLng(marker.latitude, marker.longitude);
    
                      var m = new google.maps.Marker({
                          position: position,
                          icon: icon,
                          html: contentString
                      });
    
                      markers[i] = m;
                }
    
                // Clusters
                for (i = 0; i < json.data.clusters.length; i++) {
                    var cluster = json.data.clusters[i];
                    log('Cluster: ' + cluster);
    
                    var position = new google.maps.LatLng(cluster.latitude, cluster.longitude);
    
                    for (c = 0; c < cluster.count; c++) {
                      log('Cluster Item: ' + c);
                      var m = new google.maps.Marker({
                          position: position
                      });
    
                      markers[i] = m;
                    }
                }
    
                // Marker Cluster
                var clusterOptions = { zoomOnClick: true }
                var markerCluster = new MarkerClusterer(map, markers, clusterOptions);
    
                // Info Window
                var infowindow = new google.maps.InfoWindow({
                    content: 'Loading...'
                });
    
                // Info Window Listener for Markers
                for (var i = 0; i < markers.length; i++) {
                    var marker = markers[i];
                    google.maps.event.addListener(marker, 'click', function () {
                        // Log Debug
                        log('Marker Click!');
    
                        // Set Info Window Marker Content
                        infowindow.close();
                        infowindow.setContent(this.html);
    
                        // Set Current Marker
                        var currentMarker = this;
    
                        // Get Map Position
                        var mapLatLng = map.getCenter();
                        var markerLatLng = currentMarker.getPosition();
    
                        // Check Coordinate
                        if (!markerLatLng.equals(mapLatLng)) {
                            // Map will need to pan
                            map.panTo(markerLatLng);
                            google.maps.event.addListenerOnce(map, 'idle', function() {
                                // Open Info Window
                                infowindow.open(map, currentMarker);
                                setTimeout(function () { infowindow.close(); }, 5000);
                            });
                        } else {
                            // Map won't be panning, which wouldn't trigger 'idle' listener so just open info window
                            infowindow.open(map, currentMarker);
                            setTimeout(function () { infowindow.close(); }, 5000);
                        }
                    });
                }
    
            });
        });
    }
    
    // Initialize Map
    google.maps.event.addDomListener(window, 'load', initialize);
  • Happy New Year! 2011 was a great year, I can’t wait for 2012!

    Read the original post…

    Klout Search Powered by ElasticSearch, Play Framework, Scala and Akka Published December 9, 2011 on Felipe Oliveira

    Post image for Klout Search Powered by ElasticSearch, Play Framework, Scala and Akka

    At Klout, we love data and as Dave Mariani, Klout’s VP of Engineering, stated in his latest blog post, we’ve got lots of it! Klout currently uses Hadoop to crunch large volumes of data but what do we do with that data? You already know about the Klout score, but I want to talk about a new feature I’m extremely excited about — search!

     

    Problem at Hand


    I just want to start off by saying, search is hard! Yet, the requirements were pretty simple:  we needed to create a robust solution that would allow us to search across all scored Klout users. Did I mention it had to be fast? Everyone likes to go fast! The problem is that 100 Million People have Klout (and that was this past September—an eternity in Social Media time) which means our search solution had to scale, scale horizontally.

    So how did we accomplish that?

     

    Share Nothing and Don’t Block


    We use Node.js in our front end to help scale to thousands of concurrent users.  We follow the same philosophy in our backend for search. Given the size of our dataset and its substantial growth rate, we needed to choose a search solution which would allow us to scale horizontally; On the application side we wanted to have a stateless Web layer, not only for performance, but also for manageability. So share nothing and block as little as possible!

     

    Let’s Play! and be “cool, bonsai cool”


    The technology stack chosen to address the problem was ElasticSearch and the Play! Framework. Why did we choose that stack? At Klout, we like to choose the right tool for the job, regardless of the platform it runs under or the company that’s behind it.  We chose ElasticSearch and Play! because both of these were designed to use fast, non-blocking IO, both of these provide powerful infrastructure, and both of these were designed to be easy to extend.  These tools help us build powerful search now, and continue improving search to give you more relevant results.

    ElasticSearch is a powerful, scalable and distributed search solution built on strong foundations like JBoss Netty and Apache Lucene. ElasticSearch builds off of Apache Lucene, a personal favorite of mine, created by Doug Cutting.  Doug Cutting has had a huge impact on many tools we use at Klout;  He is also the creator of Hadoop (and Nutch for that matter!).  Lucene is a search library—more than 10 years old—that provides powerful search capabilities such as relevancy ranking, fuzzy matching, wildcard, proximity operators, fielded searching, spell-checking, multi-lingual and all that jazz—all while still being completely portable since it’s a JVM-based solution; most important, it’s blazing fast!

    ElasticSearch uses JBoss Netty as its network library for async/non-blocking IO.  In a traditional blocking IO model, performing a search across multiple shards would be extremely expensive.  We could retrieve results serially, meaning that our search would become slower as our data size increased, or execute results in parallel threads, which would require ever increasing processing resources.  Netty allows ElasticSearch to retrieve results from multiple search nodes in parallel; there are no blocking threads waiting for it to finish.

    We used Play! Framework for the Web layer, which also uses JBoss Netty as its network library. Why? To find out more about this great framework, watch my Dreamforce presentation from this past September here in San Francisco, CA: “Introducing Play! Framework: Painless Java and Scala Web Applications”. Just recently, Play! has joined Typesafe, the creators of Scala, as an official part of its Scala-based technology stack and providers of the Web solution for Scala.

    Akka is also part of Typesafe’s stack and provides an event-driven and self-healing concurrency platform based on an Erlang-style, actor-based concurrency model for the JVM. In summary, Akka helps Klout’s search go fast! We have actors for the different searches we support, messages are dispatched to their mailboxes as Play’s controller actions are invoked. Akka actors, which are pretty similar to Scala actors, allow us to effortlessly execute parallel searches to minimize overall response time to provide our users the best experience possible.

    If you are down to Play! come join us and follow us on Twitter as @_felipera and @dwollen.

    Happy Searching!

     

    Read the original post…

    Why Play isn’t a Java web framework Published November 29, 2011 on Lunatech Research

    Play isn’t really a Java web framework. Java’s involved, but that isn’t the whole story.

    ‘Java’ refers to two different things these days, and only one of them’s a programming language. Increasingly, when people talk about ‘Java’ they are really talking about one or more aspects of the wider platform, which includes the programming language, but also the Java Virtual Machine, the Java SE SDK or the many APIs that make up the broader landscape of Java EE and in-progress JSRs. After all, we keep seeing conference presentations where the programming language isn’t Java.

    More subtly, Java EE is not so much a landscape as a whole country, with its own culture - norms and values, if you like.

    Eating pasta

    Java EE is the land of the architectural pattern. I’m not sure which country that is, but it would have to be one where people eat a lot of pasta, with its many related code-style metaphors. What’s more, the architecture astronauts who live there have made the endless layers of lasagne architecture their national dish.

    Play, on the other hand, is from somewhere else. Play 1.0 was written in Java and using Play 1.2 is currently the best way to build a web application in Java, but this has little to do with the established Java EE culture or the monsters it spawns. And even though the ugly beasts known as EJB 2.1 and JSF 1.2 eventually spawned more docile offspring (EJB 3 and JSF 2), they are merely tamed and not companions that you would want to Play with.

    Emigrating to the web

    The country that Play comes from is called the World-Wide Web (country code ‘www’), where people live happy joyful lives, get things done with minimal fuss, and tell jingoistic jokes about their Java EE neighbours. Fortunately for Java developers who are tired of being at the wrong end of these jokes, the immigration policy is welcoming and the language is easy to learn - an HTTP server can be as small as 1074 bytes or 3 mm long.

    The first version of the Play framework may have been written in Java, but it had little to do with Java common practice or the established Java web APIs, and avoided the standard Servlet API entirely. Play used the Java language, but little else from the Java ecosystem, and was more heavily influenced by technologies such as PHP and Ruby on Rails. After all, Play was not written for Java EE developers: Play was written for web developers.

    For example, Play 1.0 was influenced by Ruby on Rails’ project structure and user experience, which emphasised a standard pattern for getting started and having things just work. This makes a big difference to developer productivity; the opposite extreme sees teams using JavaServer Faces (JSF) spend days to ‘start-up the project’, with no two JSF applications structured the same way.

    Moving on

    Two years later, Play 1.2 has become so popular that it’s making Java developers who use other web frameworks look bad, because their productivity is so low. This is a good thing, because non-Java frameworks have already been doing this for years. Perhaps there is still hope for Java - as a language, a platform and a culture - to embrace the web and avoid being left behind. Until this happens, Play isn’t a Java web framework: Play is a web framework.

    Conclusion

    Java’s design and evolution seems to be based on the idea that the platform itself is more important than other systems that it might be used with. From a Java perspective, the web is just another external system. As with other APIs, the Servlet API has shielded Java EE from being infected by the web’s own architecture by abstracting it away into a more Java-like API. This approach is unfortunate, because the web is more important than Java - the platform and the language - and these days, a useful web framework is one whose architecture embraces the web’s, and whose API embraces HTTP.

    No programming language is an island. Not even Java.

    Read the original post…

    Semi-synchronicity: Deferred downloads based on time Published November 15, 2011 on Objectify

    Hmm, another blog entry on the Play framework. You must be sooo surprised!

    Play allows you to suspend requests while doing heavy computation – this frees up your application to continue processing new requests, regardless of how long the computation takes. However, you may be deploying to an environment with a fixed request timeout – in the case that prompted me to come up with this code, I was deploying to a server that required requests to return within 120 seconds.

    When generating PDFs, Excel files, images or whatever, that may take longer than the available window I needed to be able to push the computation into the background using a job. This solves the immediate problem, but leads to another issue – what if the job actually completes in a couple of seconds? I would then be forcing the user to then go to another link to download the generated content. Not so good for the user experience.

    A third way was clearly needed, and this is the solution I came up with:

    • All file generation computation runs in a job. This job is responsible for saving the content into the database.
    • A promise is requested from the job, and given a certain amount of time to complete in:
      F.Promise promise = downloadJob.now();
      UserContent userContent = promise.get(5,
                                                            TimeUnit.SECONDS);
      
    • If the object returned from the promise is not null, it’s sent to the browser. If it is null, a message is returned to the browser indicating the generation is on-going.
      if (userContent != null)
      {
          ...
          renderBinary(new ByteArrayInputStream(userContent.content.byteContent),
                            userContent.fileName,
                            userContent.content.byteContent.length,
                            MimeTypes.getMimeType(userContent.fileName),
                            false);
      }
      else
      {
          flash.success("Content is being generated in the background");
          index();
      }
      
    • A download manager is provided to download any generated content generated (even content that returned a binary response).
    • A job returns every night to remove any generated content older than a week
    • The result is an application that will guarantee to return within the alloted timeframe, and also allows users to keep working while their content is generated asynchronously. It also reduces concurrent load on the server because the generation job is executed from within the jobs pool, which can be limited using the application.conf.

      An example implementation can be found here: variable-downloads. The only thing missing (apart from comments – it’s pretty self-explanatory) is polling of the server to update the downloads table when a new download is available.

      Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
      • Digg
      • del.icio.us
      • StumbleUpon
      • DZone
      • Reddit
      • Facebook
      • Google Bookmarks
      • Slashdot
    Read the original post…

    Play framework meet-up at Devoxx Published November 11, 2011 on Lunatech Research

    The Lunatech team will be at Devoxx 2011 next week. We think this is the perfect opportunity to organise a Play framework meet-up at the same time.

    So if you want to talk about Play and meet other players, please join us:

    • Where: AXXES Café - Metropolis, Antwerpen (next to the Devoxx venue)
    • When: Thursday 17 of November, starting at 20:00

    See you there...

    Lunatech Network

    Read the original post…

    December Play!ground in Rotterdam Published November 8, 2011 on Lunatech Research

    Following a break for Devoxx and busy projects, we are now planning the next Play Framework event, for software developers and technical managers.

    This event is the perfect opportunity to learn practical techniques, learn more about Play’s advanced features and meet other Play developers. We also expect to have some fun.

    Details

    Programme

    This event will focus on Play 2.0, with presentations by Peter Hilton and Nicolas Leroux:

    • 16:30 - TBD
    • 17:15 - break
    • 17:30 - TBD
    • 18:15 - drinks, networking

    The programme will combine Play project news and announcements from Devoxx with a technical deep dive on how Play 2.0 works.

    As always, beer and networking are an essential part of the programme.

    Registration

    Register for this event.

    Read the original post…

    Deadbolt – wtf was I thinking? Published November 5, 2011 on Objectify

    I just re-read my previous post and thought to myself…huh? What’s the point in telling people who’ll probably never even read the blog to make sure they cache in order to improve performance?

    The answer came to me in a blaze of comprehension – add a caching feature to Deadbolt, document it and then it’s obvious (to anyone who RTFM of course).

    So, Deadbolt 1.4.3 is released tonight with caching. It should also have been the release with FastTags instead of Groovy tags, but that’s a bug for another day. Now it’s just a question of getting time to finish the Scala version – coming soon :)

    Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
    • Digg
    • del.icio.us
    • StumbleUpon
    • DZone
    • Reddit
    • Facebook
    • Google Bookmarks
    • Slashdot
    Read the original post…

    Play Framework Multiple Clusters Deployment with Capistrano Published November 2, 2011 on Felipe Oliveira

    Post image for Play Framework Multiple Clusters Deployment with Capistrano

    Capistrano is a Ruby-based deployment tool that you’ve probably heard about unless you’ve been living under a rock these past few years. There are plenty of Capistrano-specific tutorials and blog posts out there so I won’t waste your time with that. BUT, there’s not a lot of information regarding deployment for Play Framework applications and nothing specifically for Capistrano other than the documentation provided by the module.

     

    Here are two useful links I got out of the documentation:

     

    • First of all, let’s install Capistrano—that’s easy!

    gem install capistrano (you might have to sudo that depending on your local setup)

     

    • Just to make sure the installation occurred correctly, run “cap -V”. You should see something like this come up:

    Capistrano v2.9.0

     

    • Now let’s add the dependency to the Capistrano module developed by my friend Pascal (@mandubian on Twitter) who’s also the developer behind Siena. Open up conf/dependencies.yml and add the following:

    - play -> capistrano 1.0.0

     

    • Time to tell Play to import the module into your application, so execute the following (and don’t you worry! nobody will have to modify hundreds-of-lines-long pom.xml file!):

    play dependencies

     

    • Let’s add support to multiple stages to Capistrano! First execute “gem install capistrano-ext”. Then add the following lines to the very top of conf/deploy.rb:

    require 'capistrano/ext/multistage'
    set :stages, %w{staging production}
    set :default_stage, "staging"

     

    • Now create a configuration file for each enviroment:

    config/deploy/staging.rb
    role :web, "staging1", "staging2"

     

    config/deploy/production.rb
    role :web, "prod1", "prod2"

     

    • Now you need to input some information on conf/deploy.rb so Capistrano knows about your SCM setup, etc. This is what it should look like:

    set :application, "Felipe Oliveira Play Framework App"

    set :repository,  "git@github.com:feliperazeek/myproject.git"

    set :scm, :git

    set :deploy_to, "/opt/felipera_app"

    set :play_path, "/opt/play"

    ssh_options[:forward_agent] = true

    set :branch, "my_release_branch_1234"

    set :shared_path, "#{deploy_to}/shared"

    set :app_pid, "#{shared_path}/pids/server.pid"

    set :app_path, "#{deploy_to}/current"

    set :user, "felipera"

     

    • And finally … Dream Roll please …

    cap staging deploy

     

    • … Or Better Yet!

    cap production deploy

     

    The module provides more functionality than that. You can always visit the documentation; I don’t want to bore you repeating all that.

    Pascal keeps rolling out the goods!

     

    Enhanced by Zemanta

    Read the original post…

    Progress bars with jQuery UI, WebSocket & Play Published October 31, 2011 on Lunatech Research

    This article shows you how to use a jQuery UI component and Web Sockets to implement a progress bar for a deterministic asynchronous server-side job in a Play framework web application. This is an example of a user-interface component that is not part of the web’s stateless request-response paradigm, but is now possible with new HTML5 features.

    This follows on from earlier jQuery UI component articles: jQuery UI Ajax autocomplete with Play, Lazy loading page content with jQuery UI, Ajax and Play and Selector dialogue with jQuery UI, Ajax and Play. The examples and source code for all of these articles are available as part of the Play framework jQuery UI module.

    For this example, we are going to start a long-running job in our web application on the server, and display progress in real-time:

    Progress bar example

    Note that this time we are not using a time zones example, although the recent time zone database debacle seems to have been largely resolved.

    Architecture

    The Architecture of the World Wide Web is about resources and their identifiers and representations, and while we are used to the original web of HTML documents and URLs, resources and representations can be richer. The key resource in this progress bar example is a server-side process.

    The Play framework includes support for starting asynchronous server-side jobs - processes that continue running outside the scope of the HTTP request-response cycle. This is useful for important tasks that must be completed independently of the user’s navigation behaviour, such as sending hundreds of party invitation e-mails. The challenge with these long-running jobs is to use URIs to identify them as ‘resources’ in the web architecture sense, and to provide useful representations.

    For this example, we will use a web socket URI to address an asynchronous job, and on the server-side generate a representation consisting of only a single number - the job’s completion percentage. Play’s web sockets support is ideal for updating the progress bar, and Play’s asynchronous jobs are suitable for long-running jobs.

    Note that web sockets support on both server-side and client-side is still evolving. This example works with Play 1.2.3 and Safari 5.1.1; Play 1.2.4 adds Chrome support.

    Progress bar

    The jQuery UI progress bar widget shows progress for a server-side process for which the completion percentage can be calculated. Progress bars are useful for processes that take longer than a few seconds to complete, provided that they are deterministic, i.e. processes whose progress can be measured or predicted.

    Client

    The widget is based on an empty HTML div element.

    <div id="progressbar" data-url="@@{jqueryui.ProgressSocket.progress(processId)}"></div>
    

    The data-url attribute value specifies the URL for a web socket connection. Note that the template uses the @@ syntax to generate an absolute URL that includes the web socket protocol - ws://localhost:9000/progressbar/progress.

    The progressbar.js JavaScript applies the jQuery UI dialog plug-in to the div element and opens a web socket connection. Finally, the JavaScript uses web socket messages to update the progress bar value.

    $(function() {
    
       // Initialise the progress bar.
       var $progressbar = $('#progressbar').progressbar();
    
       // Open the web socket connection.
       var serverUrl = $progressbar.data('url');
       var socket = new WebSocket(serverUrl);
    
       // Use web socket messages to update the progress bar.
       socket.onmessage = function(event) {
          $progressbar.progressbar('value', parseInt(event.data));
       };
    });
    

    Server

    The server-side has three parts. First, we define an implementation of a long-running job, which has a generated UUID identifier and an event stream that the job will publish progress to. The implementation in this example simply waits for short intervals, publishing progress to the event stream after each one.

    package models.jqueryui;
    
    import play.jobs.Job;
    import play.libs.Codec;
    import play.libs.F;
    
    import java.io.Serializable;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Example job that publishes progress as an event stream.
     */
    public class Process extends Job implements Serializable {
    
       public static Map<String, Process> registry = new HashMap<String, Process>();
    
       public String id = Codec.UUID();
    
       /**
        * Event stream for events that report job completion percentage.
        */
       public F.EventStream<Integer> percentComplete = new F.EventStream<Integer>();
    
       public void doJob() {
          // Report completion percentage every 100 ms.
          for (int i = 1; i <= 50; i++) {
             try {
                Thread.sleep(100l);
                final int percent = i * 2;
                this.percentComplete.publish(percent);
             } catch (InterruptedException e) {
                // ignore
             }
          }
       }
    }
    

    The second server-side class is a conventional action that starts an asynchronous long-running job, and stores a reference to the job in a ‘registry’ singleton. This action then renders the same page with a processId argument that indicates that a job has been started.

    package controllers.jqueryui;
    
    import models.jqueryui.Process;
    
    /**
     * Progressbar example.
     */
    public class Progressbar extends JQueryUI {
    
       /**
        * Start a job, cache it and re-render the page
        */
       public static void startJob() {
          final Process process = new Process();
          process.now();
          final String processId = process.id;
          Process.registry.put(processId, process);
          renderTemplate("jqueryui/Progressbar/index.html", processId);
       }
    }
    

    The last part is a web socket controller that retrieves the running job from the registry, using its ID, and waits for events on the job’s event stream. When the job publishes a completion percentage to its event stream, the controller sends the data in a web socket message to the browser client.

    package controllers.jqueryui;
    
    import models.jqueryui.Process;
    import play.libs.F;
    import play.mvc.Http;
    import play.mvc.WebSocketController;
    
    import static play.libs.F.Matcher.ClassOf;
    
    /**
     * Web socket controller for use by the progress bar.
     */
    public class ProgressSocket extends WebSocketController {
    
       public static void progress(final String processId) {
    
          final Process process = Process.registry.get(processId);
          final F.EventStream<Integer> progress = process.percentComplete;
    
          // Loop while the socket is open
          while (inbound.isOpen()) {
    
             // Wait for either an inbound socket event or a process progress event.
             F.Either<Http.WebSocketEvent, Integer> e = await(F.Promise.waitEither(
                inbound.nextEvent(),
                progress.nextEvent()
             ));
    
             // Case: The socket has been closed
             for (Http.WebSocketClose closed : Http.WebSocketEvent.SocketClosed.match(e._1)) {
                disconnect();
             }
    
             // Case: percentComplete published - send the value to the client.
             for (Integer percentComplete : ClassOf(Integer.class).match(e._2)) {
                outbound.send(percentComplete.toString());
                if (percentComplete >= 100) {
                   disconnect();
                }
             }
          }
       }
    
    }
    

    Note that this design means that the job is started by a conventional HTTP POST request to the Progressbar.startJob() action, which means that the job is executed even if the client does not have web socket support and is therefore unable to update the progress bar.

    One possible enhancement would be to add JavaScript to detect the case where web sockets are not supported, and send a single Ajax request to get the current progress value to update the progress bar.

    Conclusion

    Web sockets are an HTML5 technology that you can now use in your web applications, thanks to browser support for the JavaScript API and Play’s server-side support. This is good news for developers who can see opportunities to improve user-experience in their applications with more sophisticated applications.

    Peter Hilton is a senior software developer at Lunatech Research and committer on the Play open-source project.

    Read the original post…

    Deadbolt – make sure your Play! framework app’s security is efficient Published October 27, 2011 on Objectify

    If you’re using Deadbolt to provide authorisation support for your Play! app, you need to be aware that DeadboltHandler#getRoleHolder() can potentially be called a lot due to the template tags. A rule of thumb is that for every #{restrict} or #{restrictedResource} tag in your template, getRoleHolder() will be invoked once. If you’re hitting the database to get the user every time, this can have a huge impact on your performance.

    Since it’s likely that the your RoleHolder won’t change within a request, you should consider adding the RoleHolder instance to the request argument if you’re not already storing it for the lifespan of the request!

    Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
    • Digg
    • del.icio.us
    • StumbleUpon
    • DZone
    • Reddit
    • Facebook
    • Google Bookmarks
    • Slashdot
    Read the original post…

    RivieraDEV - the official pictures Published October 25, 2011 on Lunatech Research

    Thanks to Nicolas Martignole I can now show some pictures from the RivieraDEV event.

    Nicolas Leroux is is a solution architect and technical director at Lunatech.

    Read the original post…

    Lunatech at the RivieraDEV Published October 24, 2011 on Lunatech Research

    I just came back from RivieraDEV, located on the French Riviera. Lunatech sponsored this nice and sunny conference. There were load of good talks and Nicolas Martignole and myself - the Nicolases ™ - gave a presentation about Play! framework with some really nice demos. One of the demo showed a video chat.

    RivieraDEV

    The presentation's video should be available pretty soon, stay tuned!

    Highlight of the conference were probably the Coffeescript presentation by Bodil Stokke and the Github presentation by Zach Holman. I hope to be invited next year - this year was easy since I helped organised the conference ;). Big thanks to Stephane, Yannis and all the RivieraDEV team.

    Play framework presentation slides

    Our presentation is available here: Play! Framework: To infinity and beyond (PDF).

    PS: I left my phone in Rotterdam, so although it was nice and quiet, I did not get any pictures of the event.

    Nicolas Leroux is is a solution architect and technical director at Lunatech.

    Read the original post…

    Play Hackathon Published October 16, 2011 on Wayne

    Get Hacking!

    Inspired by the National Novel Writing Month (NaNoWriMo), this competition is aimed at teams of Play developers to produce awesome applications during the month of November. At the end of November, the finished applications will be judged (by the Play Community) to see who has the best application, and which team has won.

    Rules

    • Start developing 1st November 2011
    • Finish developing 30th November 2011
    • Judging will start 1st December for 1 week
    • Winners will be announced 8th December
    • Teams up to 5 members
    • Your application must have an about page, or popup, stating it was developed as part of this event and using the Play Framework

    Sponsors and Prizes

    If you would like to be a sponsor, or donate prizes for this event, please get in contact with me.

    Register
    To sign up and register for the event, just go along to the Registration page, hosted on Heroku.

    I will post another short blog later this week on how simple it was to get up and running on Heroku.


    Read the original post…

    How to deploy your play applications on ArchLinux with daemons Published October 15, 2011 on GreWeb

    This video shows how to run different instances of Play framework server in the most Linux friendly way: using daemons. Example with ArchLinux, using yaourt, the playframework AUR package and nginx.

    Some links

    Abstract summary

    Introduction

    Existing Platform as a Service: Playapps.net, Heroku.com.

    Our needs are quite different: you sometimes need to have your own server on your own infrastructure and not depending on third party web services.

    Let’s see how to deploy some play applications from scratch with ArchLinux.

    Requirement

    Install ArchLinux on your server

    Install yaourt

    Installation

    yaourt -S playframework

    Creating 2 play framework applications

    mkdir sites && cd sites
    play new app1
    play new app2 # + editing app/views/

    Configuring daemons

    cd /etc/rc.d
    ln -s skeleton_playapp app1
    ln -s skeleton_playapp app2
    cd /etc/conf.d
    cp playapp_sample app1
    cp playapp_sample app2
    vim app1 # configure variables
    vim app2 # configure variables

    For app1 :

    PLAY_APP=/home/gre/sites/app1
    PLAY_USER=gre
    PLAY_ARGS="--%prod --http.port=9001"

    For app2 :

    PLAY_APP=/home/gre/sites/app2
    PLAY_USER=gre
    PLAY_ARGS="--%prod --http.port=9002"

    Starting daemons

    rc.d start app1
    rc.d start app2

    Make it permanent in /etc/rc.conf by adding them in the DAEMONS variable.

    ...
    DAEMONS=(... app1 app2)

    Nginx, as a front end proxy server

    Install nginx using pacman.

    Edit /etc/nginx/conf/nginx.conf

    ...
        server {
            listen 80;
            server_name app2.archdemo;
            location / {
              proxy_pass http://127.0.0.1:9002;
              proxy_set_header Host $host;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header X-Forwarded-Host $host;
              proxy_set_header X-Forwarded-Port $server_port;
              proxy_set_header X-Forwarded-Proto https;
            }
        }
        server {
            listen 80;
            server_name app1.archdemo;
            location / {
              proxy_pass http://127.0.0.1:9001;
              proxy_set_header Host $host;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header X-Forwarded-Host $host;
              proxy_set_header X-Forwarded-Port $server_port;
              proxy_set_header X-Forwarded-Proto https;
            }
        }
    ...

    flattr this!

    Read the original post…

    Client Certificates and Play! Published September 30, 2011 on Hugo Monteiro

    Sometimes we need the authentication of the client. That means, for instance, if you want to limit the access to your web application, from the people who has the right certificate.
    This is possible, using client certificates, which are installed inside the browser, and the user without this certificate cannot access the web application.

    To create client certificates, you need to check if you have openssl installed. After this verification, you need to find where the auxiliary command CA and/or CA.pl is installed. On my Mac  it’s located in “/System/Library/OpenSSL/misc/CA.pl“.

    1. First, we need to create a Certificate Authority (CA):

    $ CA.pl -newca

    After pressing enter, and following some instructions, a new folder “demoCA” is created with our newly created Certificate Authority.

    2. Create a certificate signing request:

    $ CA.pl -newreq

    Follow the instructions to create the certificate signing request. Two files will be created: “Request is in newreq.pem, private key is in newkey.pem“.

    3. Sign it with the CA:

    $ CA.pl -sign

    The signed certificate newcert.pem is generated.

    4. Create a client certificate that our user will install in his browser:

    $ openssl pkcs12 -export -inkey newkey.pem \
               -in newcert.pem -out clientCertificate.p12

    As we can see, we use the private key newkey.pem and the CA signed certificate to create the client certificate.

    Now that we have all the certificates created we need to use a tool to save our Certificate Authority that will be verified when someone asks for authorization with a certificate. I prefer to use the “keytool“. Verify that you have keytool command available before you begin:

    5. Create a keystore:

    $ keytool -genkey -keystore truststore.jks

    6. Add CA to keystore

    $ keytool -import -trustcacerts -alias "my CA" \
                    -file demoCA/cacert.pem -keystore truststore.jks

    7. Configure Play! Framework:

    Add to the  application.conf file, the keystore configurations:

    play.netty.clientAuth=need
    keystore.algorithm=jks
    keystore.file=conf/truststore.jks
    keystore.password=mykeystorepassword

    Conclusions:

    Inside the keystore, there is the Certificate Authority that will be verified when the client tries to comunicate with the server, using a certificate signed by the CA. This is very helpful if you want to build a web application that is in the Internet, and you just want the people from inside the company to access to it. Off course, the disadvantage of this approach is that if your user steals the certificate, he also can access the application everywhere.

    References:

    Read the original post…

    Step-by-Step for a Simple Twitter with Play Framework, AJAX, CRUD and Heroku Published August 30, 2011 on Felipe Oliveira

    Post image for Step-by-Step for a Simple Twitter with Play Framework, AJAX, CRUD and Heroku

    On August 31st, 2011: I will have the great honor to present our beloved Play Framework at Salesforce’s Dreamforce conference here in San Francisco, CA. If you are attending, please feel free to check it out or just stop by to say hello. Thank you Zenexity for the opportunity! I am always excited to help spread the word on this awesome framework!

    So the big announcement is out—Heroku started offering native support to Play Framework applications! If you haven’t heard it, checkout the post from Jesper Joergensen on Heroku’s blog.

    So for the presentation, I am setting up a very basic Twitter clone; it’s meant to be simple yet it displays just enough of the productivity that Play! provides. I am gonna go through the steps to setup the demo application which should cover what was announced on Heroku’s blog post but with a little more depth.

     

  • First step let’s create the application
  • play new twitter

     

  • Add dependency to CRUD module (conf/dependencies.yml)
  • - play -> crud

     

  • Get the dependencies
  • play dependencies

     

  • IDE Integration
  • play eclipsify (for Eclipse), play idealize (for IntelliJ) or play netbeansify (for Netbeans).

     

  • Create Model (app/models/Tweet.java)
  • package models;

    import java.util.Date;
    import java.util.List;

    import javax.persistence.Entity;

    import play.data.validation.MaxSize;
    import play.data.validation.Required;
    import play.db.jpa.Model;

    @Entity
    public class Tweet extends Model {

    @Required
    @MaxSize(140)
    public String tweet;

    @Required
    public Date createDate = new Date();

    public static List findLatest() {
    return Tweet.find(“order by createDate desc”).fetch();
    }

    @Override
    public String toString() {
    return this.tweet;
    }

    }

     

  • Define DB for JPA Models (conf/application.conf)
  • db=${DATABASE_URL}

     

  • Add Controller Actions (app/controllers/Application.java)
  • package controllers;

    import java.util.List;

    import models.Tweet;
    import play.mvc.Controller;

    public class Application extends Controller {

    public static void index() {
    List tweets = Tweet.findLatest();
    render(tweets);
    }

    public static void create(String msg) {
    Tweet tweet = new Tweet();
    tweet.tweet = msg;
    tweet.save();
    render(tweet);
    }

    public static void tweets() {
    List tweets = Tweet.findLatest();
    renderJSON(tweets);
    }
    }

     

  • Define Main View (app/views/Application/index.html)
  • #{extends ‘main.html’ /}
    #{set title:’Home’ /}

    <!– Create Tweet Form –>

    <form> <input name=”tweet” type=”text” />
    <input type=”submit” value=”Tweet” /> </form><!– Latest Tweets List –>
    <ul> #{list tweets}
    <li>${_.tweet} (${_.createDate.since()})</li><p><p>
    #{/list}</ul>
    <!– JS –>
    <script type=”text/javascript”>

    // Capture Form Submit Event
    $(‘form’).submit(function() {
    // Define Create Action
    var createAction = #{jsAction @create(‘:tweet’) /}

    // Call Create Action
    $.post(createAction({tweet: $(‘input:first’).val()}), function(data) {
    // Prepend Results to the List
    $(‘ul’).prepend(data);
    $(‘input:first’).val(”);

    });

    // Don’t let the browser redirect
    return false;
    });

    </script>

     

  • Define Create Action View (app/views/Application/create.html)
  • <li><code>${tweet.tweet} (${tweet.createDate.since()})</li>

     

     

  • Create Unit Test for Tweet Model
  • import models.Tweet;

    import org.junit.Assert;
    import org.junit.Test;

    import play.test.UnitTest;

    public class TweetTest extends UnitTest {

    @Test
    public void testModelSave() {
    long count = Tweet.count();
    Tweet t = new Tweet();
    t.tweet = “my sample tweet”;
    t.save();
    long count2 = Tweet.count();
    Assert.assertEquals(count + 1, count2);
    }

    }

     

  • Create CRUD Admin for Tweet Model
  • package controllers;
    public class Tweets extends CRUD {
    }

     

  • Add Routes (conf/routes)
  • * /admin module:crud

    GET /rest/tweets Application.tweets

     

  • Define Messages for CRUD Admin (conf/messages)
  • tweet=Tweet
    createDate=Date Created

     

  • Define Procfile
  • web: play run –%$FRAMEWORK_ID –http.port=$PORT -DusePrecompiled=$USE_PRECOMPILED -DDATABASE_URL=mem

     

  • Run in Development
  • play run –%dev -DusePrecompiled=false -DDATABASE_URL=mem

     

  • Create Application on Heroku
  • heroku create play-twitter –stack cedar

     

  • Setup Git Repository
  • git init; git add .; git commit -a -m “Initial Commit”; git remote add heroku git@heroku.com:play-twitter.git

     

  • Setup Heroku Environment Variables
  • heroku config:add FRAMEWORK_ID=prod; heroku config:add USE_PRECOMPILED=true

     

  • Deploy to Heroku
  • git push heroku master

     

  • If anything went wrong you can always check the log
  • heroku logs

     

  • To Setup a Real Database on Heroku
  • heroku addons:add shared-database

    You can checkout a live demo here, the admin interface here or clone the source code on Github.

    Voila! Now Go Play!

    Read the original post…