Book Image

Play Framework Cookbook

By : Alexander Reelsen
Book Image

Play Framework Cookbook

By: Alexander Reelsen

Overview of this book

<p>The Play framework is the new kid on the block of Java frameworks. By breaking with existing standards the play framework tries not to abstract away from HTTP as most web frameworks do, but tightly integrates with it. This means quite a shift for Java programmers. Understanding these concepts behind the play framework and its impact on web development with Java are crucial for fast development of applications.<br /><br />The Play Framework Cookbook starts where the beginner documentation ends. It shows you how to utilize advanced features of the Play framework &ndash; piece by piece and completely outlined with working applications!<br /><br />The reader will be taken through all layers of the Play Framework and provided with in-depth knowledge from as many examples and applications as possible. Leveraging the most from the Play framework means to think simple again in a java environment. Implement your own renderers, integrate tightly with HTTP, use existing code, improve site performance with caching and integrate with other web services and interfaces. Learn about non-functional issues like modularity or integration into production and testing environments. In order to provide the best learning experience during reading Play Framework Cookbook, almost every example is provided with source code, so you can start immediately to integrate recipes into your own play applications.</p>
Table of Contents (16 chapters)
Play Framework Cookbook
Credits
Foreword
About the Author
About the Reviewers
www.PacktPub.com
Preface
Further Information About the Play Framework
Index

Using Java Extensions to format data in your views


Java Extensions are a very nice helper inside your templates, which will help you to keep your template code as well as your model code clean from issues such as data formatting. Reformatting values such as dates is a standard problem at the view layer for most web developers. For example, the problem of having a date with millisecond exactness, though only the year should be printed. This is where these extensions start. Many web developers also do this by using JavaScript, but this often results in code duplication on frontend and backend.

This recipe shows a pretty common example, where a date needs to be formatted to show some relative date measured from the current time. This is very common in the Twitter timeline, where every Tweet in the web interface has no correct date, but merely a "n hours ago" or "n days ago" flag.

Getting ready

Just create a tiny application. You will need to create a new application and add a database to the application configuration, so entities can be specified.

How to do it...

You need a route to show your tweets in conf/routes:

GET      /{username}/timeline           Application.showTweet

After that we can model a tweet model class:

package models;


import java.util.Date;
import javax.persistence.Entity;
import play.data.validation.Max;
import play.db.jpa.Model;

@Entity
public class Tweet extends Model {

        @Max(140) public String content;
        public Date postedAt;
        public User user;
}

As well as a simple user entity:

@Entity
public class User extends Model {

        @Column(unique=true) 
        public String login;
}

The controller is quite short. It uses an alternative query for the 20 newest tweets, which is more JPA like:

public static void showTweets(String username) {
        User user = User.find("byLogin", username).first();
        notFoundIfNull(user);
        List<Tweet> tweets = Tweet.find("user = ? order by postedAt DESC", user).fetch(20);
        render(tweets, user);
}

The rendering code will look like this:

#{extends 'main.html' /}
#{set 'title'}${user.login} tweets#{/set}

#{list tweets, as:'tweet'}
<div><h3>${tweet.content}</h3> by ${tweet.user.login} at <i>${tweet.postedAt.since()}</i></h3></div>
#{/list}

Now this code works. However, the since() Java Extension, which is built in with Play only works when you hand over a date in the past as it calculates the difference from now. What if you want to add a feature of a future tweet which is blurred, but will show a time when it is shown? You need to hack up your own extensions to do this. Create a new class called CustomExtensions in the extensions package inside your application directory (so the file is ./app/extensions/CustomExtension.java)

public class CustomExtensions extends JavaExtensions {

        private static final long MIN   = 60;
        private static final long HOUR  = MIN * 60;
        private static final long DAY   = HOUR * 24;
        private static final long MONTH = DAY * 30;
        private static final long YEAR  = DAY * 365;

        public static String pretty(Date date) {
                Date now = new Date();
                if (date.after(now)) {
	                long delta = (date.getTime() - now.getTime()) / 1000;

                if (delta < 60) {
                    return Messages.get("in.seconds", delta,
 pluralize(delta));
                }

                if (delta < HOUR) {
                    long minutes = delta / MIN;
                    return Messages.get("in.minutes", minutes, pluralize(minutes));
                }

                if (delta < DAY) {
                    long hours = delta / HOUR;
                    return Messages.get("in.hours", hours,
 pluralize(hours));
                }

                if (delta < MONTH) {
                    long days = delta / DAY;
                    return Messages.get("in.days", days, pluralize(days));
                }

                if (delta < YEAR) {
                    long months = delta / MONTH;
                    return Messages.get("in.months", months,
 pluralize(months));
                }

                long years = delta / YEAR;
                return Messages.get("in.years", years, pluralize(years));

                } else {
                        return JavaExtensions.since(date);
                }

        }
}

Update your ./app/conf/messages file for successful internationalization by appending to it:

in.seconds = in %s second%s
in.minutes = in %s minute%s
in.hours   = in %s hour%s
in.days    = in %s day%s
in.months  = in %s month%s
in.years   = in %s year%s

The last change is to replace the template code to:

#{list tweets, as:'tweet'}
<div><h3>${tweet.content}</h3> by ${tweet.user.login} at <i>${tweet.postedAt.pretty()}</i></h3></div>
#{/list}

How it works...

A lot of code has been written for an allegedly short example. The entity definitions, routes configuration, and controller code should by now be familiar to you. The only new thing is the call of ${tweet.postedAt.since()} in the template, which does call a standard Java Extension already shipped with Play. When calling the since() method, you must make sure that you called it on an object from the java.util.Date class. Otherwise, this extension will not be found, as they are dependent on the type called on. What the since() method does, is to reformat the boring date to a pretty printed and internationalized string, how long ago this date is from the current time. However this functionality only works for dates in the past and not for future dates.

Therefore the CustomExtensions class has been created with the pretty() method in it. Every class which inherits from JavaExtensions automatically exposes its methods as extension in your templates. The most important part of the pretty() method is actually its signature. By marking the first parameter as type java.util.Date you define for which data type this method applies. The logic inside the method is pretty straightforward as it also reuses the code from the since() extension. The only unknown thing is the call to Messages.get(), which just returns the string in the correct language, such as"3 days ago" in English and "vor 3 Tagen" in German.

Last but not least, the template code is changed to use the new extension instead of since().

There's more...

Java Extensions can be incredibly handy if used right. You should also make sure that this area of your application is properly documented, so frontend developers know what to search for, before trying to implement it somehow in the view layer.

Using parameters in extensions

It is pretty simple to use parameters as well, by extending the method with an arbitrary amount of parameters like this:

public static void pretty(Date date, String name) {

Using it in the template is as simple as ${tweet.postedAt.pretty("someStr")}

Check for more built in Java Extensions

There are tons of useful helpers already built-in. Not only for dates, but also for currency formatting, numbers, strings, or list. Check it out at http://www.playframework.org/documentation/1.2/javaextensions.

Check for internationalization on plurals

Play has the great feature and possibility of definin a plural of internationalized strings, which is incidentally also defined in the built-in JavaExtensions class.