Play Framework + Eclipse + Postgresql + Mercurial – English Version

play cooked alawelinux

Hans Poo, hans@welinux.cl, Santiago de Chile, Septiembre de 2012

The saying “there are many ways to skin a cat” has motivated us to show how we peel the Play web development cat..

We have been working for a year with play framework using a specific set of free software tools. In this tutorial you will learn to install and use our development environment:

Java programming language, Play web framework, Eclipse integrated development environment, PostgreSQL database, Mercurial version control, Redmine tasks/incident management and Linux operating system: Ubuntu distribution, the latest edition so far 12.04 LTS.

Copy code snippets: To copy pieces of code, double-click on them, press the right mouse button and select Copy. Then the shortcut / keyboard shortcut to paste in terminal then is Shift + Control + V.

Java 6

Open a terminal and install the openjdk java with:

sudo apt-get install openjdk-6-jdk

Play 1.2.5

We can install play just for us on our $HOME folder, or for the entire system, we will do the second. In general the play commands execute on a terminal. We’ll be working in the Downloads folder, open a terminal and run:

cd ~/Downloads

The pig’s tail, “~” symbol is replaced by your home folder, that way commands are more generic, this symbol usually goes with Alt + 4 in Spanish keyboards, your home folder is also available in the $HOME environment variable.

We recommend placing the Terminal application in the Unity launcher.

Let’s download the framework, we can download it with firefox or using wget command line web client, run the following from the command line:

wget http://download.playframework.org/releases/play-1.2.5.zip

Unzip and move to the expected location for programs manually added to the system: /usr/local in our computer:

unzip play-1.2.5.zip
sudo mv play-1.2.5 /usr/local/

Configure access to the framework through a symbolic link to more comfortably handle its updates:

sudo ln -s /usr/local/play-1.2.5/ /usr/local/play

Let’s create a link in /usr/local/bin to the executable command “play”, so the play command will be available immediately from the terminal::

sudo ln -s /usr/local/play/play /usr/local/bin/play

Eclipse Indigo

Go to the download link of indigo http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/indigosr2, take a look at the section at the right titled “Download Links” and download the appropriate version of 32 or 64 bit Linux; move to the folder $HOME/Downloads, and unpack it from the command line:

cd ~/Downloads
tar xzvf eclipse-jee-indigo-SR2-linux-gtk-x86_64.tar.gz

Create a file for us to run eclipse from the Unity launcher.


mkdir -p ~/.local/share/applications

cat<<EOF>~/.local/share/applications/eclipse.desktop
[Desktop Entry]
Type=Application
Name=Eclipse
Comment=Eclipse Integrated Development Environment
Icon=$HOME/Downloads/eclipse/icon.xpm
Exec=$HOME/Downloads/eclipse/eclipse
Terminal=false
Categories=Development;IDE;Java
EOF

Copy the newly created file eclipse.desktop to the unity launcher, with nautilus open the folder ~/.local/share/applications running the following from the terminal:

nautilus ~/.local/share/applications/

Drag and drop the file eclipse.desktop over the Unity launcher on the left.

To start eclipse, click the icon just created in the launcher, in the dialog box asking for the Workspace, leave the field as it comes, turn on the checkbox that says “use this as the default …”, and then press OK. When starting the first time, Eclipse will create the folder $HOME/workspace, there we will create our play projects.

For those new to eclipse, after you enter Eclipse what you see is a set of views grouped in a Perspective.

The first application play

We do not intend to repeat the excellent play official tutorial, is a necessary step to learn play. Here we want to show the environment and tooling, then we’ll build a simple application, an Agenda of Friends, one of whose elements contains a photo gallery, this is to show packages and schemes.

To start let’s move to the folder $HOME/workspace eclipse just created. From now on we will use the terminal and Eclipse simultaneously:

cd $HOME/workspace

Create the play project, copy and paste the following command in the terminal, press Enter when prompted to confirm the name of the project::

play new agenda

Let’s try the project quickly, launch it:

play run agenda

Go to firefox and enter http://localhost:9000, you will see the default pages created. Go back to terminal and press Control + C to terminate the application.

The play run command will start your project from the terminal in the foreground, we should end it up with Control + C; if you execute play start instead of “play run”, the project will be running in the background as a service/daemon: it doesn’t stop if you close the terminal, in this mode you can monitor the project looking at the file logs/system.out, under the project folder, in this case run the play stop command from the project folder to stop the execution. The latter is the most common way to run it in production.

Let’s move now to the project folder just created:

cd agenda

The character encoding of the response is dynamic in play and is available in the templates through the variable _responseEncoding, the problem is that eclipse HTML editors have problems when they see this value, for now we’ll let it fixed in UTF-8:

find . -name \*.html -exec sed -i 's/${_response_encoding}/UTF-8/' "{}" \;

Install the Mercurial version control system:

sudo apt-get install mercurial

Create the mercurial ignore file .hgignore appropriate for play projects using here documents, you can also use any text editor:

cat<<EOF>.hgignore
^modules
^tmp
^precompiled
^test-result
^logs
^eclipse
^data
.*\.log$
\.classpath$
\.project$
.*\.pyc$
.*\.orig$
.*\.swp$
EOF

Mercurial requires a minimal configuration just to know who is commiting things, create a text file named ~/.hgrc in your home folder with the next content, replace with your name and email:

cat<<EOF>~/.hgrc
[ui]
username = Hans
EOF

Then we place the project under version control:

hg init
hg add .
hg commit -m'Inicialización del repo'

Mercurial is a DVCS: distributed version control system, and the working copy and the repository are always together, unlike subversion (centralized) where there was always a single repository and many working copies. The init command converts the current folder in a mercurial empty repository and creates the folder .hg representing the Mercurial repository. The add command put all the contents of the current folder and its children in version control, you can always view the status of the repository using hg status, and when you hava commited changes using the hg log command. Mercurial doesn’t create a new revision until you do a commit, which represents the modification unit data management.

Make the project an eclipse project eclipsify it,, in this way we can import and work with our project natively in eclipse. This command must be repeated each time you modify the project dependencies:

play ec

Import the project into Eclipse

Move to eclipse, select File > Import > General > Existing projects into workspace and then click Next, click the Browse button, select our project agenda located in the workspace folder, then click Finish, the project is now imported into eclipse.

To work on play projects we recommend the Java EE perspective, let’s add to this perspective the Navigator view: menu Window > ShowView > Navigator, this view is a generic file browser and will serve us to quickly move on to the eclipse folder where is the project launcher: agenda.launch.

The problem with the Project Explorer view is that the way play places java libraries, they occupy a vertical space very long which difficult to quickly access the application launcher. Anyway eclipse later will place a shortcut to the application launcher (green play button) and the debugger (button with the bug) in the principal button bar.

Run the project from Eclipse

Activate the Navigator View, within the project, the fourth folder is called eclipse, it contains the scripts to run and debug your application without leaving eclipse, at the moment we are interested in two files, one to run the project from within eclipse called: agenda.launch and another to connect the debugger: Connect JPDA to agenda.launch, beware that the debugger does not run the project, the project must be running first.

Click with the right mouse button on the file agenda.launch and choose the option Run As > agenda with this the project will start execution. To activate debugging right click Connect JPDA to agenda.launch and select Debug as > Connect JPDA to agenda.

Eclipse displays the standard error and output of the project in the Console View normally at bottom right section of JEE perspective, in its bar there is a square red button you should use to stop the project.

Test from firefox

Start firefox and connect to your running project in http://localhost:9000.

Configure PostgreSQL

For each of your projects create an user at the operating system and database level, the postgres database admin users is intentend just to administer the cluster.

Create user in the operating system for the project:

sudo adduser agenda

Install postgresql:

sudo apt-get install postgresql

Create database user agenda he will own the database, when prompted for the password for testing purposes put 123.

sudo su - postgres -c "createuser --no-superuser --no-createrole --createdb --pwprompt agenda"

Create the database with the user just created:

sudo su - agenda -c "createdb agenda"

In the previous command note that we are connecting as the operating system user and then just issuing a createdb, if we don’t specify the user to connect in the psql command, postgres will look in its users database for user equals in name to the operating system user connected and if found will enable trusted authentication, which is the case now.

The idea is that all the work to be done with the database is done login in with that account by issuing int the terminal sudo su – agenda.

Modify application.conf to play use the database you just created.

cd $HOME/workspace/agenda
echo "db=postgres://agenda:123@localhost/agenda" >> conf/application.conf

Sequence per table (advanced optional)

Current Java state of the art recommends using persistence through standard Java Persistence API JPA. Play designers have decided to use Hibernate as the JPA persistence provider. By default the Hibernate PostgreSQL adapter will create one sequence for the entire database, it seems better to have one sequence for each table, so we are using the following postgreSQL adapter slightly modified (created by Burt).

In the Project Explorer view (usually on the left), click the right mouse button on app, then select New > Package and then type utils as the name and click Finish.

In the newly created package utils click with the right mouse button, from the popup menu choose New > Class name it TableNameSequencePostgresDialect and press Finish.

Double click on the next piece of code, press the right mouse button and select Copy. Then double click on the just created class TableNameSequencePostgresDialect, press Control + A to select all of its contents, and then click Control + V to replace all the code of the class with what we’ve just copied.


package utils;
import java.util.Properties;

import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.SequenceGenerator;
import org.hibernate.type.Type;

/**
 * Creates a sequence per table instead of the default behavior of one sequence.
 *
 * From <a href=
 * 'http://www.hibernate.org/296.html'>http://www.hibernate.org/296.html</a>
 *
 * @author Burt
 */
public class TableNameSequencePostgresDialect extends PostgreSQLDialect {

	/**
	 * Get the native identifier generator class.
	 *
	 * @return TableNameSequenceGenerator.
	 */
	@Override
	public Class<?> getNativeIdentifierGeneratorClass() {
		return TableNameSequenceGenerator.class;
	}

	/**
	 * Creates a sequence per table instead of the default behavior of one
	 * sequence.
	 */
	public static class TableNameSequenceGenerator extends SequenceGenerator {

		/**
		 * {@inheritDoc} If the parameters do not contain a
		 * {@link SequenceGenerator#SEQUENCE} name, we assign one based on the
		 * table name.
		 */
		@Override
		public void configure(final Type type, final Properties params,
				final Dialect dialect) {
			if (params.getProperty(SEQUENCE) == null
					|| params.getProperty(SEQUENCE).length() == 0) {
				String tableName = params
						.getProperty(PersistentIdentifierGenerator.TABLE);
				if (tableName != null) {
					params.setProperty(SEQUENCE, "seq_" + tableName);
				}
			}
			super.configure(type, params, dialect);
		}
	}
}

From the terminal run the following command, modifying the configuration of hibernate in our project to use the just created adapter:

echo "jpa.dialect=utils.TableNameSequencePostgresDialect" >> conf/application.conf

Play assistants for eclipse playclipse

Play offers some assistance to work in eclipse, we must copy a jar file from the distribution of play to the eclipse dropins folder.

cp /usr/local/play/support/eclipse/org.playframework.playclipse_0.7.0.jar ~/Downloads/eclipse/dropins/

Restart eclipse with File > Restart, you will find four new buttons on the top toolbar of eclipse:

  • New Controller
  • New View
  • New Model
  • Go to Route

Controllers, Actions y views

All the dynamic html in play goes under the folder app/views. The entry point to the application code is driven by the conf/routes file that finally send you to a static method (called Action) defined in a Controller. Actually in our tests upon entering port 9000 we are seeing the implementation of the index Action located inside the controller Application, this is better seen looking at the code of the aforementioned controller::

package controllers;

import play.mvc.Controller;

public class Application extends Controller {

	public static void index() {
		render();
	}

}

The executed html template (or rendered if you prefer) in this case is located in views/Application/index.html following the play convention views/ControllerName/actionName.

To open classes or other resources in Eclipse we recommend two shortcuts that open a very cool live search: Shift + Control +T to search for Types and Java Clases, and Shift + Control + R to find any other resource file: html, css, javascript, etc.

Hello World program

Right click with your mouse on app/views/Application/index.html, activate the Open With menu, you will see that eclipse offers several editors for HTML, by default eclipse uses HTML Editor that is quite good, we recommend Web Page Editor which offer WYSIWYG support. The playclipse jar we aded before incorporates another editor HTML (Play) it allows to travel from templates to controllers, if you Control + Click in a template over an action call it will open the controller in the method and if the method doesn’t exist it will offer the creation.

With the restart of eclipse we did, the play server has stopped, right click agenda.launch as explained before an choose Run As > agenda. As it was the last run, eclipse keeps a keyboard shortcut to it: Control + F11, else use the Run button as shown in the following image:

Botonera principal de eclipse

Open the file app/views/Application/index.html and replace the call to the welcome tag: #{welcome /} by the next html code:


Hello World

…then press Control + S or click the diskette button to save the file. Then go to the browser and reload the page http://localhost:9000.

Capture Parameters

As is classic in the Hello World program, the first setting is for it to say Hello John, Hello Peter, etc, let’s pass a parameter called name directly in the URL, and see how to capture and display it in the template. Copy the following address into your browser:

http://localhost:9000/application/index?nombre=Player.

The page still displays Hello World, of course, to capture the parameter we must declare it as an argument in the action method. Activate the Project Explorer View and double click on the class app/controllers/Application.java, change the declaration of the index method to the following:

public static void index(String nombre) {

Then, for the template to be aware of this variable, we must pass it to the render method:

render(nombre);

The Application class is as follows, you can copy this code and replace all code in Application.java.

package controllers;

import play.mvc.Controller;

public class Application extends Controller {

	public static void index(String nombre) {
		render(nombre);
	}

}

Finally modify the template app/views/Application/index.html to display the contents of the variable name instead of the word World:

Hello ${nombre}

Reload the page http://localhost:9000/application/index?nombre=Player, to see that now says Hello Player.

Java package and database schema

The succesfull systems grow, java classes should go in packages and tables in database schemas. In the Project Explorer view, cactivate/click the package app/models and press the right mouse button, select New > Package, type models.fotos asname and press Finish. To create the equivalent scheme in the database do the following from the terminal:

sudo su - agenda -c "psql -c 'create schema fotos;'"

If you keep a terminal session as user agenda just running psql-c ‘create schema agenda;’ will do the same. If you are inside the shell of postgres psql it will suffice to execute just the sql command CREATE SCHEMA agenda.

JPA / Hibernate does not automatically create the schemas in the database, you should do it manually as we have seen with the CREATE SCHEMA statement.

Create Class Foto

Class diagram of the photo gallery, generated with BOUML 4.21:

In the Project Explorer view activate the package models.fotos and press the button New Model, give it the name Galeria and press Finish, do it again New Model, this time creating the class Foto.

Copy and paste the following into the Galeria class, remember before pasting to select all the Galeria.java code with Shift + Control + A:


package models.fotos;

import java.util.List;

import javax.persistence.*;
import play.db.jpa.*;

@Entity
@Table(schema = "fotos")
public class Galeria extends Model {

@OneToMany(cascade = CascadeType.ALL, mappedBy = "galeria")
public List fotos;

}

With the editor still in the class Galeria let’s introduce two key shortcuts. Press Control + Shift + F to format the code, and Shift + Ctrl + O to organize Imports.

Double click the Foto class to activate it, then replace its contents with the next code:

package models.fotos;

import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import play.db.jpa.Blob;
import play.db.jpa.Model;

@Entity
@Table(schema = "fotos")
public class Foto extends Model {

	public String descripcion;
	public Blob image;

	@ManyToOne
	public Galeria galeria;

}

We will not make a tutorial of the Java Persistence API JPA, to be studied separately, but please note the key annotation:

@Table(schema = "fotos")

That allows us to indicate the database schema where the table associated to this Entity will be created.

This relationship between Galeria and Foto is called composition, Foto depends on Galería, this is expressed mainly with @ManyToOne in Foto, bu too with the mappedBy in the @OneToMany of Galeria, in this case there is no association table created.

More flexible desing with association table

If we want the class Foto to be used in other contexts, and not only associated with a Galeria, first remove the @ManyToOne Galeria galeria declaration in Foto and remove the mappedBy attribute in the @OneToMany annotation of Galeria.

In this case Hibernate will create an association table and Foto will not hold the foreign key of Galeria. To indicate the schema where the association table should be created use the @JoinTable annotation in the @OneToMany as follows:

package models.fotos;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import play.db.jpa.Model;

@Entity
@Table(schema = "fotos")
public class Galeria extends Model {

	@OneToMany
	@JoinTable(schema = "fotos")
	public List fotos;

}

package models.fotos;

import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import play.db.jpa.Blob;
import play.db.jpa.Model;

@Entity
@Table(schema = "fotos")
public class Foto extends Model {

	public String descripcion;
	public Blob image;

}

This gain insight on how JPA annotations impact in the database structures we recommend:

  1. Do changes in JPA definitions.
  2. Drop and create the database schemas or database.
  3. Restart the play server and load some page.
  4. Explore the schemas with some tool like SQLPower or SQLeonardo.

Commit our work

Let’s review the status of the project with Mercurial:

hg status

The files that come with the question mark “?” at the beginning are not versioned, mercurial handles by itself the modifications to the files, but new files must be added manually. First we’ll put under version control all new files and then commit.

hg add *
hg commit -m"Primeros cambios"

We actually use mercurial with a mix of command line and the eclipse plugin https://bitbucket.org/mercurialeclipse.

Congratulations

You completed the tutorial, we invite you to make the official tutorial. In Yabe, the tutorial you are going to make there is a class called User, User is a reserved word in postgreSQL and other database engines, To instruct Hibernate to properly create the table we need to add a @Table annotation with backquotes in the name the table, it should looks like:


@Entity
@Table(name = "`user`")
public class User extends Model {
....
}

Our company promotes free software, we offer free lectures and presentations at educational institutions and training and technology transfer to companies.

Prepared by Hans Poo, hans@welinux.cl, Santiago de Chile, September 2012.

Añdir un comentario a Anónimo Cancelar respuesta

Su dirección de correo no se hará público. Los campos requeridos están marcados *