Play Framework

At the start of my last project by Chess IX (I’m leaving after working there for over 5 years) I looked at several Java web frameworks. One of the frameworks was Wicked, which I blogged about earlier, but the hands-down winner was the Play Framework. On the surface it seemed to be designed much like my beloved Django, and now that we’ve arrived at the final week of the project at my final week at Chess IX it seems like a good idea to write about my findings.

Contents

Overview of Play

Play is a full application stack, from the incoming HTTP request all the way to persistence, e-mails, scheduled jobs and dependency management. At the time of writing, version 1.2.3 is the current version.

The Play website already shows us 5 cool things we can do with Play, so I won’t repeat them here. Go check them out, they’re cool.

The HTTP cycle

Play has a very clear notion of a HTTP request-response cycle:

  1. HTTP request for a certain URL comes in.
  2. The routing table is consulted to determine the controller method that’s to be called. In our case this is a static Java method.
  3. The controller method is called with the parameters from the request
  4. The controller does its work, and results in a HTTP response.

By using a routing table, the URLs of the application are well defined. This has several advantages, for example bookmarkability of your pages.

Play compiles and reloads your Java code on the fly. It can determine by itself whether it should restart or not, and if it happens the restart is quite fast.

Another important feature is that Play is stateless. Anything that in other frameworks would be stored in server-side state is stored in client-side cookies (cryptographically signed to prevent tampering) or delegated to the database.

The automatic reloading, combined with the routing table, result in a very pleasant development flow. You can just hit F5 and your page including your code will be reloaded. This is quite different when using things like Tomcat or JBoss and more traditional Java frameworks.

Controllers

The routing engine delegates a HTTP request to a controller method. This is a static method in a subclass of Controller. Here is one controller class with two controller methods. The certificateId parameter comes from the request, for example when it ends in ?certificateId=123.

package controllers.admin;

public class Certificates extends SecureCHController {

    public static void showCertificate(@Required Long certificateId) {
        Certificate cert = Certificate.findById(certificateId);
        render(cert);
    }

    public static void redirectDemo() {
        showHistory(123);
    }
}

The controller class is dynamically altered in such a way that the showHistory(123) call results in a HTTP redirect to the URL that results in the showHistory call. The routing table is used to determine which URL the browser should be sent to. The resulting property is that the URL always reflects the displayed page. This dynamic alteration is done for all public static void methods, so if you want such a method but not have it altered that way, annotate it with @Util.

Debugging your controllers is very easy. You don’t need to restart Play, you can simply tell Eclipse to connect a debugger and you’re done. Now you can set breakpoints, step through code, view/change variables, etc.

Updating complex objects

Play has nice features for editing complex objects. Here is an example:

// the model in models/User.java
@Entity
public class User extends Model {
    public String firstName;
    public String lastName;
    public Integer numberOfPets;
}

// the controller in controllers/Users.java
public class Users extends Controller {
    public static void edit(@Required Long id) {
        User user = User.findById(id);

        if (request.method.equals("POST")) {
            user.edit("user", params.all());
            user.validateAndSave();
        }

        render(user);
    }
}

You would typically create a form like this:

<form action='@{edit(user.id)}' method='POST'>
    <input type='text' name='user.firstName' value='{user.firstName}'>
    <input type='text' name='user.lastName' value='{user.lastName}'>
    <input type='text' name='user.numberOfPets' value='{user.numberOfPets}'>
    <button type='submit'>Submit</button>
</form>

Because in the posted data the names match the properties of the User class, the user.edit(...) line updates the user object just like you’d expect.

Be aware that the controller has no knowledge of the form that was posted. Someone could forge a POST request that contains more properties than the original form. If you're not careful, users could raise their own privileges.

For example, if your User class has a Boolean isAdmin, then a POST could contain user.isAdmin=true. Without any modification, a user.edit("user", params.all()) call will happily set that isAdmin property.

Template engine

A lot of Java web frameworks are XML-centred. The reasoning behind it is that it’s easy to validate the templates. This is of course true, but of limited use

  • the validity of the templates doesn’t imply the validity of the produced HTML. The nature of XML also makes it difficult to stick to the DRY principle, as you’ll get constructions like below. This code tries to set class="secure" for HTTPS links, and class="insecure" for other links:
<c:if test='href.startsWith("https://")'><a href="<%= href %>" class="secure"><%= linkText %></a><c:/if>
<c:else><a href="<%= href %>" class="insecure"><%= linkText %></a></c:else>

Play uses Groovy as template language. With Groovy, the same concept would look like this:

<a href="${href}" class="#{if not href.startsWith('https://')}in#{/}secure">${linkText}</a>

With Play you can also template anything that’s not an element, such as part of a string or an HTML attribute. For example:

<link rel='stylesheet' href='{base_path}/style.css' type='text/css' />

This is impossible using Wicket without having to move the entire element to your Java code.

As you can see, you’re free to place your expressions right where you want them, without having to bother making the mix of HTML and XML valid XML. This is very important for modern sites, as HTML 5 is not XML.

Another upside is that you can use the same template engine for different content: XML, CSV files, mixed HTML and plain text e-mails, etc. Note that this also applies to JavaScript. With Wicket and other XML-based systems you cannot do this:

alert("Page title: {page.title}");

Referring to the URL that will call a certain controller method is very easy:

<a href='@{controllers.SomeController.javaMethod()}'>clickme</a>

Use @@{...} instead of @{...} to get absolute URLs, for example in e-mails.

Extending

Templates can “extend” each other, in a somewhat object-oriented fashion. A “parent” template can use a #{doLayout /} statement, which will be replaced by the contents of the “child” template. For example:

<!-- master.html -->
<html>
<head>
    <title>#{get 'title' /} - My Super App</title>
    <link type='text/css' href='/style.css' rel='stylesheet'>
</head>
<body>
    <header>some header</header>
    #{doLayout /}
    <footer>some footer</footer>
</body>
<html>

<!-- page.html -->
#{extends 'master.html' /}
#{set title: 'This page' /}

<article>The content of this page</article>

It’s equally simple to create your own template tags. Just create a tags directory in the right spot, and place your tag files there. The tag files are simply HTML (or whatever you want) and the filename will become the tag name. Similar as #{doLayout /} template tags have a #{doBody /} that renders the template tag’s body. Here is a silly example:

<!-- tags/link.html -->
<a href='{_href}'>#{doBody /}</a>

<!-- usage in a template: -->
#{link href: 'https://stuvel.eu/'}my website#{/link}

I do miss some features in the templating engine, though. Django has “blocks” which you define in a “parent” template and can override in a “child” template. In the child you can also include the block content of the parent, so it’s very easy to add something to the parent, rather than replacing the entire block. I didn’t see this kind of flexibility in Play, but I must admit that I only looked at the default templating engine; other engines are offered as plugins.

Groovy

Groovy has many language features that Java lacks. Of course with Java you can do the same - it just takes more work. Here is a quick example in which we have a list of people, where each person has some eye colour, and we want to have a mapping from eye colour to the people with that eye colour. The script would look like this:

perEyeColour = people.groupBy { person -> person.eyeColour};

One could argue that grouping and sorting information is part of the presentation logic (rather than doing this at the database layer). The powerful way that Groovy can work with collections makes it a templating language that’s pleasant to work with.

For more information, check out the Groovy collections documentation.

Translations

Play has a simple yet quite effective translation system. It reads the file messages for all translations, and messages.nl if your browser tells the server you want Dutch, or messages.hr when you want Croatian (if you configure your server to support those languages, of course). Whatever it cannot find in these files it will take from the messages file instead.

AJAX integration

Play hasn’t got explicit AJAX support, but using AJAX is quite easy nonetheless. Returning a JSON response that serializes some object is as simple as:

public static void someMethod(Long personId) {
    Person person = Person.findById(personId);
    renderJSON(person);
}

Accepting POSTed JSON is similarly easy. Replace renderJSON with renderXml if you’d rather us XML.

As for the client side you’re free to use whatever tooling you like, such as jQuery.

Database layer

Hibernate is used as the DB layer, but with a slight twist. By itself Hibernate will persist all changes to a managed Java object, unless you explicitly prevent it. In Play changes to the Java object are always never persisted to the DB, unless you explicitly call someObject.save(). In this case I feel that explicit is better than implicit.

For simple queries Play created a simple language. Of course more powerful queries are possible as well, and Play will detect from the syntax whether the simple or more complex language is used. Here are some examples of the findBy(...) method:

@Entity
public class Profile extends Model {
    public User user;
    public String nickname;

    public static Profile findByNickname(String nick) {
        return find("byNickname", nick).first();
    }

    public static Profile findByUser(User user) {
        return find("byUser", user).first();
    }

    public static List<Profile> findActivatable() {

        String query = "select p from Profile p "
                + "where p.user is NULL "
                + "or p.user.activated = false";

        return find(query).fetch();
    }
}

The database interface is quite object oriented. Methods that we would traditionally create a separate Database Access Object (DAO) for, are simply methods on the DB object itself. Static methods are used for queries on groups, whereas non-statics are used for operations on single entities.

What I do miss is per-page query logging. When Django is running in development mode I can display the SQL statements and the time they took, right in the template. This makes debugging your SQL a lot easier. Something like this is also possible with Play of course, but requires you to go through a lot more steps configuring Hibernate, and then the logging still shows up in your log file, not on the page itself.

Property simulation

Many Javanians feel that you shouldn’t use direct property access. Instead you should write a getter and a setter method for the property. This often results in trivial methods that only clutter up your source. Sure, they can be automatically generated, but code is read more than it is written so readability counts heavily.

Play generates your setters and getters dynamically. Public properties will become private with public setters/getters, and all direct property access will use those. Any existing getters or setters you wrote because they actually have to do something more intelligent will be used by Play. So in this example, properties firstName and lastName will get trivial setters and getters, whereas the url property will use the hand-written setter and a dynamically generated getter:

public class PropDemo {
    public String firstName;
    public String lastName;
    public String url;

    public void setUrl(String url) {
        this.url = UrlLibrary.cleanupUrl(url);
    }
}

Because the getters and setters are generated, the objects are still compatible with the “java beans” concept, and thus can be freely passed to libraries that expect them.

I like this very much. It keeps my code clean, and increases information density on my screen: more functionality per line of code, with increased readability.

Authentication and authorization

Auth & auth is one of the areas where I’m less enthusiastic about Play. There is no built-in “user” class, nor groups, roles or rights. The login/logout controllers are tightly integrated with the rest of the security code, which makes it a chore if you want to have multiple login pages (for example using one URL for your users, and another for staff members).

Django does come with a “user” class and all the rest, proving that it’s very much possible to make a generic auth & auth system. Application-specific user properties are delegated to a “profile” model that you’re free to create yourself, so you don’t need to touch the built-in stuff. Very elegantly solved, and very missing from Play.

Play also has no template tags that help you with security, for example hiding links to pages that can’t be accessed by the user. The result is that you have to duplicate your access rules for the controller classes and the template engine.

Having said all that, once we had implemented the login system and defined the roles, it was quite easy to secure controllers. All we needed was something simple like this:

@With(controllers.Secure.class)
@Check("newsadmin|superuser")
public class NewsEditor extends Controller {
    ...
}

The @With annotation points to a class that checks the user’s access, and the @Check annotation describes the roles that are allowed to access the controller. You can also apply @Check to individual methods.

Dependency management

Dependencies are managed by Play too. They can be downloaded from the main Play repository, but it’s also possible to use one or more Maven 2 repositories.

Run play --deps to download the dependencies and install them in the modules directory. Add the --sync option to remove any old dependencies that may still be lingering around.

For my project we chose to commit those files to Subversion for a reason that was good at the time (I still support it but it’s no longer necessary due to an update). I now suggest you do not do this, as syncing the dependencies also removes the hidden .svn directories, making Subversion loose its temper (and its metadata). Of course this also applies to CVS. Mercurial and Git can handle this just fine, as they no longer have metadata in every directory (they have a top-level .hg resp. .git only).

Unit testing and CM-RC

The unit testing framework uses JUnit 4. You can subclass Play’s UnitTest class to run your tests in the Play context, or create a POJO for regular tests that don’t need the database etc.

By default the unit tests do not run transactionally. This was surprising, as I’m quite accustomed to that. This was fixed by creating an abstract TransactionalTest class containing the following:

@Before
public void createTransaction() {
    JPA.setRollbackOnly();
}

By calling JPA.setRollbackOnly() writes to the database are still allowed, but rolled back at the end of the transaction.

The test running isn’t restricted to unit tests though; it can also run Selenium tests. However, we decided against using Selenium in this way, as the Selenium tests flash by so quickly that you can’t see what’s going on. They’re gone faster than you can click the pause button. Instead we use Checkmate-RC for our front-end testing.

Code coverage measurements are possible using the Cobertura plugin. By running both your unit tests and front-end test in the same “play test” session you’ll get combined coverage reports. This is a lot easier than trying to get front-end coverage reports using Tomcat or JBoss.

Spring injection

There is a Play plugin for Spring, but it lacks automatic injection into the controller classes. My guess is that it’s due to the static nature of the controller methods. If your architecture heavily depends on Spring, it may not be a good idea to tightly integrate it with the Play framework.

A different approach (one that I quite like in theory, but haven’t tried yet) is to use a multi-tier system: Play for the front-end and a separate server for the Spring services / business logic. For the communication between those there is a plethora of RPC tooling.

Other front-end tech

During the project we used the following front-end tools:

  • jQuery for most of the JavaScript stuff. It makes cross-browser scripting a breeze, and easily extendible.
  • DataTables for more features for displaying tabular data.
  • jQuery-UI for date pickers, auto-completing text boxes, and other UI components.

The verdict

Above I’ve touched on the more important parts of the Play Framework. After working with it for a couple of months I’m quite pleased with it. The things that are meant to be simple really are simple, and we’ve noticed that adding more features to a webapp that’s been in development for months remains simple.

The different aspects of Play are cleanly separated. You can use it with another database layer, for example, or even without DB. You can swap out the templating engine if you like. Not only does this allow you to replace components with better alternatives, but it also indicates a good underlying design.

However, there are also downsides. The documentation is really good, but can be improved. The framework feels rather new, because there seem to be no Best Practices documented - there are multiple ways to reach the same goal, and they don’t tell you which is the best.

Some features also seem to be tacked on and left behind. For example, the play war command should give me a WAR file that runs on Apache Tomcat. I tried it, but it didn’t work. Posting to the discussion group resulted in no answer what so ever.

Adding auth & auth to the application also felt like it wasn’t really well thought out. The “security” module does its job, but is quite limited. Also the security warning I wrote above should have been in the Play documentation itself, but it’s painfully missing.

Having said all that, I would still recommend Play. It’s a pleasure to work with, bringing a lot of the features I was used to from Django into the Java world. Debugging is easy, the error messages are friendly and informative, and just pressing F5 to refresh is refreshing.

Play sticks closely to HTTP, rather than trying to reinvent the wheel, and I (mostly) kept feeling in control over the application. All the HTTP requests and responses are as designed, where other Java frameworks try to hide HTML and HTTP; I feel that knowing what is sent “over the wire” is part of the interface contract between client and server application, and as with every client/server architecture it is important to keep a grip over the communication.

Kudos to the people behind Play, and sincerely I hope that version 2 will be at least as appealing.

dr. Sybren A. Stüvel
dr. Sybren A. Stüvel
Open Source software developer, photographer, drummer, and electronics tinkerer

Related