Convention over configuration has became a buzz word these days. It is a software design paradigm which seeks to decrease the number of decisions that developers need to make, gaining simplicity, but not necessarily losing flexibility. More and more web frameworks are using this approach and making web development simple. Ruby on rails, DJango, Grails, CakePHP, ASP .NET, Apache Wicket etc are few in top demand these days.
What’s Play!?
One of the newest one is Play! framework. Play is heavily inspired by Ruby on Rails and Django. A developer familiar with any of these frameworks will feel at home. Play leverages the power of Java to build web applications in an environment that is not Java Enterprise Edition-centric. By lifting away the Java EE constraints, Play provides developers with an easy-to-develop and elegant stack aimed at productivity. I have worked in CakePHP and I am a big fan of it. I believe Play! is bringing the same experience of fast web application development to the Java world, right from hello world baby steps to create a full production ready application and writing tests. When you visit Play!’s overview webpage on their site, the very first line will surely catch your attention. The Play framework is a clean alternative to bloated Enterprise Java stacks. It focuses on developer productivity and targets RESTful architectures. Play is a perfect companion to agile software development. Although the words “bloated Enterprise Java stacks” may offend many Java developers who are very used to work with Spring MVC, Struts of JavaServer Faces; I think its more of less correct and many of us already feels so working for years now in Spring / Struts and realizing how much boiler plate code is being pushed into system and how complex things became over period of time. What I like most about Play! framework is the flexibility of this new framework and how easy it makes the life of developer. The application development becomes a piece of cake (like most CakePHP developers will feel). And the best part is all this you can do with Java without switching your favorite language and shifting to other like Rube or PHP.Highlights of Play! framework
Let us see few differences of Play! from other Java frameworks (Courtesy Wiki):- Play is fully RESTful – there is no Java EE session per connection. This makes Play more outwardly-scalable than many other frameworks.
- No configuration: download, unpack and develop – it’s that simple.
- Easy round trips: no need to deploy to an application server, just edit the code and press the refresh button on the browser.
- Integrated unit testing: unit testing is at the core of Play!
- Elegant API: rarely will a developer need to import any third party library – Play comes with all the typical stuff built-in.
- CRUD module: easily build administration UI with little code.
- Play is a web framework: it is language agnostic and currently supports Java and Scala.
- Modular architecture
Your first Play! application
Hello world in Play! is straight forward. I will not spend much time in describing steps for installing and configuring Play!. On its homepage, Play! framework developer Guillaume Bort has made this wonderful getting started screencast which you can follow to create your very first Play! application. Few points I would like to highlight here is:- Play is a real “Share nothing” system. Ready for REST, it is easily scaled by running multiple instances of the same application on several servers.
- Play! loads the code dynamically. Just fix the bug in Java file and hit reload and voila, the change will get reflected instantly on webpage. No need to go through those sluggish rebuild / deployment / server restart.
- Play! comes with a very efficient template system. The template system is based on Groovy as an expression language. It provides template inheritence, includes and tags.
- A fully functional stack of modules are available in Play!. Provides integration with Hibernate, OpenID, Memcached… And a plugin system to create your own customize plugin or include one from hundreds of freely available ones.
- Error discovery is very easy with Play!. When an error occurs, play shows you the source code and the exact line containing the problem. Even in templates.
Your first Play! – GAE – Siena application
For this tutorial, I have chosen a little complex example which we develop in Play! and deploy on Google App Engine (GAE). The GAE offers fast development and deployment; simple administration, with no need to worry about hardware, patches or backups; and effortless scalability. The Google app engine does not support SQL or RDBMS. The App Engine datastore provides robust, scalable storage for your web application, with an emphasis on read and query performance. An application creates entities, with data values stored as properties of an entity. The app can perform queries over entities. All queries are pre-indexed for fast results over very large data sets. Our demo application called eazyBookmark is already running on Google App engine. This is a Bookmark application where user can login and save their bookmarks. Click below image to visit online demo.Online Demo
Link: http://eazybookmark.appspot.com/ Following are the functional aspects of eazyBookmark app.- User can login to eazyBookmark using their Google account. No need to remember password for new account.
- Using “Add link” functionality, user can add any URL and save as bookmark.
- Any bookmark can be tagged with multiple tags. This way user can organize the links easily.
- A bookmark once added can later be Edited or deleted.
- A small bookmarklet script is available for user to add it in browser favorites. This bookmarklet can be later used by User to bookmark any webpage. Read Tools page of eazyBookmark.
Getting started
Create a blank application in Play! using play create eazybookmark commnd.C:\Play>play new eazybookmark ~ _ _ ~ _ __ | | __ _ _ _| | ~ | '_ \| |/ _' | || |_| ~ | __/|_|\____|\__ (_) ~ |_| |__/ ~ ~ play! 1.1, http://www.playframework.org ~ ~ The new application will be created in C:\Play\eazybookmark ~ What is the application name? [eazybookmark] ~ ~ OK, the application is created. ~ Start it with : play run eazybookmark ~ Have fun! ~The above Hello World video shows in depth how to install and use Play and create your first application.
Adding Google App Engine (GAE) and Siena module to Play!
We need two modules for our eazybookmark application. One is Google App engine (GAE) and another one is Siena. You can install these modules by running following command with Play!.C:\Play> play install gae .. .. C:\Play> play install sienaThe above commands will install latest version of these modules. If you are behind proxy than the above command may fails. Currently there is no way of setting up proxy with Play! (v1.1) so you can manually download gae and siena from its homepage and copy them in /modules directory of your Play!. Once the modules are installed successfully, you can add following lines in eazybookmark apps /conf/application.conf file.
# ---- Google app engine module ---- module.gae=${play.path}/modules/gae-1.4 # ---- Siena module ---- module.siena=${play.path}/modules/siena-1.3You may want to restart the Play application to reflect the changes of the modules. Once the application is restarted, the GAE module creates
/war/WEB-INF/appengine-web.xml
file. You need to update this file and add the application id of GAE. In our case we will have following data.
File: /war/WEB-INF/appengine-web.xml<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>eazybookmark</application>
<version>1</version>
</appengine-web-app>
Code language: HTML, XML (xml)
You may want to replace eazybookmark with your own GAE Application ID.Play! and Siena models
Let us first review the model classes we going to use for our application. We will have four model classes.- User – This is a User model. All user related information such as email, name, etc will get stored here.
- Link – This is Link model. All links related information such as URL, title, description etc will get stored here.
- Tag – This is Tag model. All the tags related information such as tagname etc will get stored here.
- LinkTag – This is a mapping model which maps Links with Tag. In Siena to create Many to Many relationship we need to create three classes. This class maps Link and Tag and add a many to many relationship to these entities.
package models;
import siena.*;
public class User extends Model {
@Id
public Long id;
public String email;
public String name;
public Date created;
public Date modified;
static Query<User> all() {
return Model.all(User.class);
}
public static User findById(Long id) {
return all().filter("id", id).get();
}
public static User findByEmail(String email) {
return all().filter("email", email).get();
}
public User() {
super();
}
public User(String email) {
this.email = email;
}
public String toString() {
return email;
}
}
Code language: Java (java)
The User model has few attributes like email, name, created and modified which define a user. Few methods like findById()
and findByEmail()
select the User based on Id and email respectively. File: /app/model/Link.javapackage models;
import java.util.*;
import siena.*;
public class Link extends Model {
@Id(Generator.AUTO_INCREMENT)
public Long id;
public String url;
public String title;
public String description;
public Date created;
public Date modified;
@Filter("link")
public Query<LinkTag> linktags;
@Index("user_index")
public User user;
public Link(User user, String url) {
super();
this.url = url;
this.user = user;
}
public Link() {
super();
}
static Query<Link> all() {
return Model.all(Link.class);
}
public static Link findById(Long id) {
return all().filter("id", id).get();
}
public static List<Link> findByUser(User user) {
return all().filter("user", user).order("-created").fetch();
}
public static void addTag(Link link, Tag tag) {
LinkTag linkTag = new LinkTag(link, tag);
linkTag.insert();
}
public String toString() {
return url;
}
public List<Tag> findTagsByLink() {
List<Tag> tags = LinkTag.findByLink(this);
return tags;
}
public static void addTagsFromCSV(Link link, String tagcsv, User user) {
Collection<Tag> tags = null;
if(null != tagcsv || !tagcsv.equalsIgnoreCase("")) {
String [] tagArr = tagcsv.split(",");
tags = new ArrayList<Tag>();
for(String tagstr : tagArr) {
tagstr = play.templates.JavaExtensions.slugify(tagstr.trim()).trim();
if(null != tagstr && !tagstr.equals("")) {
Link.addTag(link, Tag.findOrCreateByName(tagstr,user));
}
}
}
}
}
Code language: Java (java)
The Link model class is similar to User. It has its own attributes such as url, title, description etc. Also note that Link model has few methods like findById()
, findTagsByLink()
, addTag()
, addTagsFromCSV()
etc. These methods are used from the controller to manipulate the link data. The Link has a many to many relationship with Tag. One link can have multiple tags attached to it. File: /app/model/Tag.javapackage models;
import siena.*;
import java.util.*;
public class Tag extends Model {
@Id(Generator.AUTO_INCREMENT)
public Long id;
public String name;
@Index("user_index")
public User user;
public static Query<Tag> all() {
return Model.all(Tag.class);
}
public static Tag findOrCreateByName(String name, User user) {
Tag tag = all().filter("user", user).filter("name", name).get();
if(null == tag) {
tag = new Tag();
tag.name = name;
tag.user = user;
tag.insert();
}
return tag;
}
public static Tag findById(Long id) {
return all().filter("id", id).get();
}
public static Tag findByName(String name, User user) {
return all().filter("user", user).filter("name", name).get();
}
public static List<Tag> findByUser(User user) {
return all().filter("user", user).fetch();
}
public String toString() {
return name;
}
}
Code language: Java (java)
The Tag model has one attribute tag name. This can be anything like travel, leisure, technology, news etc. Also note that each tag has one to one mapping with User. This is defined by @Index("user_index")
annotation with object User. The Tag has usual methods findById
, findByName
, findByUser
, findOrCreateByName
etc which is used from controller to manipulate the Tag data. File: /app/model/LinkTag.javapackage models;
import java.util.*;
import siena.*;
public class LinkTag extends Model {
@Id
public Long id;
@NotNull
@Column("link_id")
@Index("link_index")
public Link link;
@NotNull
@Column("tag_id")
@Index("tag_index")
public Tag tag;
public LinkTag(Link link, Tag tag) {
super();
this.link = link;
this.tag = tag;
}
public static Query<LinkTag> all() {
return Model.all(LinkTag.class);
}
public static List<Tag> findByLink(Link link) {
List<LinkTag> linkTags = all().filter("link", link).fetch();
List<Tag> tags = new ArrayList<Tag>();
for(LinkTag linkTag : linkTags) {
tags.add(Tag.findById(linkTag.tag.id));
}
return tags;
}
public static List<Link> findByTag(Tag tag) {
List<LinkTag> linkTags = all().filter("tag", tag).fetch();
List<Link> links = new ArrayList<Link>();
for(LinkTag linkTag : linkTags) {
links.add(Link.findById(linkTag.link.id));
}
return links;
}
public String toString() {
return link.toString() + " : " + tag.toString();
}
public static void deleteByLink(Link link) {
List<LinkTag> linkTags = all().filter("link", link).fetch();
if(null != linkTags) {
for(LinkTag linktag : linkTags) {
linktag.delete();
}
}
}
}
Code language: Java (java)
The LinkTag model links the models Link and Tag. It adds the Many-to-many relationship between these models. We have few useful methods like findByLink
, findByTag
to get the list of relationship.The Play! Controllers
The controller in Play! framework handles all the request / response between client and web server. It is a plain Java class which extends Controller class of Play!. In our application we will use two controller classes: Application and Profile. We will also have a helper class called Auth which has few useful methods to determine is a user is logged in, or to get email address of logged in user. This class invoke GAE module to get the authentication details and route user to Google page for authentication. File: /app/controller/Auth.javapackage controllers;
import play.modules.gae.*;
import com.google.appengine.api.users.*;
public class Auth {
public static boolean isLoggedIn() {
return GAE.isLoggedIn();
}
public static String getEmail() {
return GAE.getUser().getEmail();
}
public static User getUser() {
return GAE.getUser();
}
public static void login(String action) {
GAE.login(action);
}
public static void logout(String action) {
GAE.logout(action);
}
}
Code language: Java (java)
Note that above Auth
class is not part of controller (We haven’t extended it with Controller). It is just a utility class that we can use from other controllers to access user information. You may want to create your own package utils
and keep this class there. For sake of simplicity, I am keeping this in controllers
package. File: /app/controller/Application.javapackage controllers;
import play.mvc.*;
import models.*;
import models.User;
import java.util.*;
public class Application extends Controller {
public static void index() {
if(Auth.isLoggedIn()) {
User user = User.findByEmail(Auth.getEmail());
if(null == user) {
user = new User();
user.email = Auth.getEmail();
user.created = new Date();
user.insert();
Profile.edit(user.id);
return;
}
Profile.index(null);
}
render();
}
public static void login() {
Auth.login("Application.index");
}
public static void logout() {
Auth.logout("Application.index");
}
}
Code language: Java (java)
Check the Application controller which is the entry point to our application. The index() method will be called whenever user request homepage /. In index()
method we are checking if user is logged in. If not, then we show her a Login page using render()
method. This method renders the default view of this action. We will see this view later in our example. Also note that if user is authenticated, we redirect it to Profile.index
action. If user has logged in for first time in eazyBookmark, she will be redirected to Edit Profile page where she can select username for her profile. File: /app/controller/Profile.javapackage controllers;
import models.*;
import play.*;
import play.mvc.*;
import java.util.*;
import play.data.validation.*;
import java.net.*;
import net.htmlparser.jericho.*;
import java.io.*;
import play.Logger;
import models.Tag;
public class Profile extends Application {
@Before
static void checkConnected() {
if(Auth.getUser() == null) {
Application.login();
} else {
renderArgs.put("user", Auth.getEmail());
}
}
public static void index(String tag) {
User user = getUser();
List<Link> links = null;
if(null == tag || tag.equalsIgnoreCase("")) {
links = Link.findByUser(user);
} else {
links = LinkTag.findByTag(Tag.findByName(tag, user));
}
List<Tag> tags = Tag.findByUser(user);
render(user, links, tags);
}
//...
//...
}
Code language: Java (java)
The Profile controller is extended from Application controller to take advantage of login() / logout() method. Also note that this is not the full code for Profile.java. You can check the full source in the project source code.The View
All the view files in Play! framework as saved in /views/ folder with .html extension. These are the plain HTML files with certain groovy template tags. Read more about built-in template tags in Play! here. There is a file main.html in /views folder which act as the template for all other views. Following is the content of main.html for eazyBookmark. File: /views/main.html<!DOCTYPE html>
<html>
<head>
<title>#{get 'title' /}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/main.css'}">
#{get 'moreStyles' /}
<link rel="shortcut icon" type="image/png" href="@{'/public/images/favicon.ico'}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript" charset="utf-8"></script>
#{get 'moreScripts' /}
</head>
<body>
<div id="pagewidth" >
<div id="headerbar">
<div id="headercol">
<div id="logo">
<h3><a href="/">eazyBookmark</a></h3>
</div>
<div id="headerlink">
#{if user}
${user} <span class="sep">|</span> <a href="@{Application.logout()}">Logout</a>
#{/if}
#{else}
<a href="@{Application.login()}">Login</a>
#{/else}
</div>
</div>
</div>
<div id="wrapper" class="clearfix">
<div id="maincol">
#{if flash.error}
<p class="error">${flash.error}</p>
#{/if}
#{if flash.success}
<p class="success">${flash.success}</p>
#{/if}
#{doLayout /}
</div>
</div>
<div id="footer">
<p> Copyright © ${new Date().format('yyyy')}
<a href="http://eazybookmark.appspot.com">eazyBookmark</a> </p>
</div>
</div>
</body>
</html>
Code language: HTML, XML (xml)
In above template main.html file, we have #{doLayout /}
tag which renders the content. Also note that we are displaying error / success message using flash mechanism of Play!. For each controller, we create a separate folder in views/ folder. And these folders will contain the view file for each action in given controller. Thus in /views/Application
folder we will have index.html
and in /views/Profile
folder we will have edit.html
, editlink.html
and index.html
. Download these html files from the source code attached at the end of tutorial.Deploying Play! app in Google App Engine (GAE)
We are done with the coding of our eazyBookmark application. Now we can deploy this app in our GAE account. For that follow the basic steps given here:- Get yourself a GAE account and set up an application. you will need the ID.
- Download the GAE SDK for Java
- run play war myappname -o myappname-war
- run APPENGINE_SDK_DIR/bin/appcfg update myappname-war/
- Log in to your app engine console and check out your application!
To use play behind a proxy (on a unix system at least) try:
export http_proxy=http://user:pass@hostname:port
Seems to work for me.
excellent tutorial, very detailed in deed…
you should publish it on http://www.dzone.com
Play! can do the deployment to GAE in one command (precompiled, war creation, upload, etc…) by using this command :
play gae:deploy –gae={path_to_gae_sdk}
Source :
http://blog.infin-it.fr/2010/12/27/une-application-play-sur-google-appengine/
@Jean – thanks for the info. I was not aware of that command line.
Hello,
Great article!
I’m Siena committer and great fan of play! and I also develop some applications for GAE+Siena and it’s really nice to see people use it as you did!
Would you accept to be referenced on Siena site as an example of site?
regards
Pascal
@Pascal – thanks for the comment. Feel free to reference the article. I am glad you liked it.
FYI, the gae module has a nice deploy command
play gae:deploy
have a look at this article (in french)
http://blog.infin-it.fr/2010/12/27/une-application-play-sur-google-appengine/
yes, deployment is even shorter if you set your $GAE_PATH environment variable.
.. then ..
play gae:deploy is enough
(it asks for your google app engine credentials the first time)
Congratulations for the article. The tutorial is excelent, it covers the important points in play, siena and gae , the source code compiles (there is a missing import for Date in models.User).
Thank you,
MVCaraiman.
Hi guys,
I tried this tutorial without creating any controller etc. I created a new play application, installed the modules updated the properties and deploy to GAE.
Should this work OK and display the default play home page? I’m getting a 500 server error.
Thanks!
There is an error in line ?
User user = getUser();
The method getUser() is undefined for the type Profile
The tutorial was great, thanks a lot. I have just one little problem, two actually. I would like to understand fully when to use those annotations you used, like ‘@Index’, ‘@Filter”, ‘and @Embedded and I would also like to understand more fully when there is a one to many, many to one, or many to many relationship between the models. Thanks.
Well written guide, I’ve submitted it as featured on GAE Cupboard.
Hello Viral,
Are there any IDE’s available to work with play framework.
Can I use Play framework in Eclipse ?
Hi Faisal, You can very well use Eclipse as IDE for your Play framework app. The above eazybookmark app is created in Eclipse only. Refer to this documentation http://www.playframework.org/documentation/1.0.1/ide and setup Eclipse as Play framework IDE.
Hi, is there a version for play 2.0?
thanks
Hi Friends, I newly joined a software company, they are using play
framework 1.2.4 as the IDE to develop a web application. My Question is, Which Version of Play framework is easy for a Junior level programmer, as i have basics of Java programming
Thanks