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
- The HTTP cycle
- Controllers
- Template engine
- Translations
- AJAX integration
- Database layer
- Authentication and authorization
- Dependency management
- Unit testing and CM-RC
- Spring injection
- Other front-end tech
- The verdict
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:
- HTTP request for a certain URL comes in.
- The routing table is consulted to determine the controller method that’s to be called. In our case this is a static Java method.
- The controller method is called with the parameters from the request
- 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.
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, andclass="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.