Posts Tagged ‘Playframework’

Play! Framework 2 (2.1) Scala with Slick made easy (With example)

by @mgonto, original article can be found here

Hi everyone!

First of all, I want to tell you that the original post is from here (Blogeek).

Today I’ve seen some videos about Slick and Play! Framework 2.1 and I got excited, so I thought, let’s code an app with Slick. What did I realize? It wasn’t that simple. Play! isn’t yet thought to work with Slick very well.

First of all, if you want to see this example complete you can go to

https://github.com/mgonto/slick-play2-example

In Slick, you create table definitions for the class you want to use. However, all of the imports for the Table, the columns, etc. are driver dependant. So, when you change the driver, you don’t want to change the import in the code. You just want to change a configuration in the application.conf from Play! Framework. That’s exactly what I did.

So, let’s see first how it’s implemented. Every Driver (H2, Postgres, etc) extends from a trait called ExtendedProfile. So, I needed my table classes to use some profile that was injected by me. Once I realized that I needed to make some DI I thought about Cake Pattern. For more information about the Cake Pattern please viisit Cake pattern

So, the first thing I implemented was a Trait Profile with an abstract Extended Profile value:

package models

import slick.driver.ExtendedProfile

trait Profile {
  val profile: ExtendedProfile
}

After this, I needed to create the Users table. That Users table needed the profile, so I’d create a UserModule which would need the Profile trait. Then, as I’d mix with a Profile trait, I’d import the things from the abstract ExtendedProfile field and everything would compile. Then I create the users table with an ID and a Name (pretty simple)

package models

case class User(id: Option[Int], name : String)

trait UserComponent {
  this: Profile =>

  import profile.simple._

  object Users extends Table[User]("users") {
    def id = column[Int]("id", O.PrimaryKey)
    def name =  column[String]("name", O.NotNull)
    def * = id.? ~ name <> (User, User.unapply _)

    def add(user: User)(implicit session: Session) = {
      this.insert(user)
    }

    def countByName(name: String)(implicit session: Session) = {
      (for {
        user <- Users
        if (user.name === name)
      } yield(user)).list.size
    }

  }
}

After this, I create a DataAccessLayer class (DAL) which would receive the ExtendedProfile as a constructor parameter and then would include the other traits (Profile and UserModule)

package models

import slick.driver.ExtendedProfile

class DAL(override val profile: ExtendedProfile) extends UserComponent with Profile {

  import profile.simple._

  def create(implicit session: Session): Unit = {
    Users.ddl.create //helper method to create all tables
  }
}

After this, I have everything to create a DAL from a given profile. However, now I needed a way to configure the profile, so I added a new property in the application.conf.

slick.db.driver=scala.slick.driver.H2Driver

Then, I created a trait that would import this driver from the conf and create the database to do the queries and the dal with the corresponding profile. It has two methods, getDb and getDal which will be then used by two other classes.

package models

import slick.session.Database
import play.api.db.DB
import play.api.Application
import slick.driver.ExtendedProfile

trait DBeable {

  val SLICK_DRIVER = "slick.db.driver"
  val DEFAULT_SLICK_DRIVER = "scala.slick.driver.H2Driver"

  def getDal(implicit app : Application) : DAL = {
    val driverClass = app.configuration.getString(SLICK_DRIVER).getOrElse(DEFAULT_SLICK_DRIVER)
    val driver = singleton[ExtendedProfile](driverClass)
    new DAL(driver)
  }

  def getDb(implicit app : Application) = {
    Database.forDataSource(DB.getDataSource())
  }

  private def singleton[T](name : String)(implicit man: Manifest[T]) : T =
    Class.forName(name + "$").getField("MODULE$").get(man.runtimeClass).asInstanceOf[T]

}

The only things left are creating the DB once the app starts and having a singleton object to be able to ask for the dal and the database to do the queries from a controller. This is done as following:

import models.{User, DBeable, AppDB}
import play.api.db.DB
import play.api.GlobalSettings
import play.api.Application
import slick.session.Session

object Global extends GlobalSettings with DBeable {

  override def onStart(app: Application) {
    implicit val application = app
    lazy val database = getDb
    lazy val dal = getDal
    database.withSession {
      implicit session: Session =>
        dal.create
    }
  }
}
package models
import play.api.Play.current
object AppDB extends DBeable {

  lazy val database = getDb
  lazy val dal = getDal

}

And that’s it :). Now you have everything configured to start coding. I’ve tried if everything was working with a test as following.

class UserSpec extends Specification {

  "User" should {

    "be saved" in {
      running(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
        AppDB.database.withSession {
          implicit session: Session =>
            AppDB.dal.Users.add(User(Some(2), "hola"))
            AppDB.dal.Users.countByName("pepe") must beEqualTo(0)
            AppDB.dal.Users.countByName("hola") must beEqualTo(1)

        }
      }
    }
  }
}

And that’s it 🙂 Now you have Play! configured for running with Slick.

Cya people!

Exponiendo y consumiendo servicios de datos con mybatis, play framework 2.0 y jersey

Tomado del blog gishak.wordpress.com

 

Voy a escribir en esta ocasión sobre como exponer servicios de datos con play 2.0, utilizando mybatis como mapeador de datos y la librería Jersey para consumir los servicios expuestos.

El modelo de datos con el que vamos a trabajar es el siguiente:

Como ven en el modelo no hago uso de claves foráneas, ni PK compuestas, eso es una práctica (buena o mala) personal, así que no se alarmen si no ven un modelo ER típico.

Empezando con mybatis (anteriormente ibatis); es un mapeador de datos muy simple de utilizar y muy flexible; he sido fan de hibernate desde sus primeras versiones pero me he encontrado con la simplicidad de este framework que no te quita el control del SQL que escribes (algo que para algunos desarrolladores es importante), pero a su vez hace realmente fácil el mapeo entre las tablas y los objetos.

Hay varias opciones para el mapeo de datos con mybatis, en mi caso me gusta tener la conexión a la base de datos en XML y los mapeos con anotaciones (también se pueden hacer con XML al estilo de los .hbml), así que lo primero es crear un archivo de configuración, en este caso lo llamamos dbconfig.xml.

Ahora En el archivo de configuración dbconfig.xml, como estoy utilizando jdbc de SQL Server la configuración va de la siguiente manera

<pre><configuration>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
				<property name="url" value="jdbc:sqlserver://localhost\sql2008:51085;databaseName=dummy" />
				<property name="username" value="user" />
				<property name="password" value="secret" />
			</dataSource>
		</environment>
	</environments>
</configuration>

Tomando como ejemplo del modelo una de las clases:

public class Genre implements Serializable{

	private static final long serialVersionUID = -9130550406579029310L;
	private int id;
	private String name;

	public Genre(){
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return String.format("%s - %s", this.id, this.name);
	}

}

Debemos definir una interfaz, la cual tiene las sentencias SQL y los métodos con las anotaciones correspondientes para el mapeo de los datos entre los objetos y la base de datos, los mapeos son para cualquier operación (Select, Update, Delete); para nuestro ejemplo vamos solo a hacer uso de Selects; de la clase Genre vamos a definir 2 métodos: Uno para consultar todos los registros de la base y otro para hacer una consulta por ID

public interface IGenreMapper {
	final String SELECT = "select id,name from genre";
	final String SELECT_BY_ID = "select id,name from genre where id=#{id}";

	@Select(SELECT)
	@Results(value = {
			@Result(column = "id", property = "id", javaType = Integer.class),
			@Result(column = "name", property = "name", javaType= String.class) })
	public List selectAll();

	@Select(SELECT_BY_ID)
	@Results(value = {
			@Result(column = "id", property = "id", javaType = Integer.class),
			@Result(column = "name", property = "name", javaType= String.class) })
	public Genre selectByID(@Param("id") int id);
}

Como se puede ver sobre los métodos está definida la anotación @Select que hace uso de las sentencias SQL que tenemos como Strings, y que de esas columnas seleccionadas tenemos el mapeo hacia que propiedades de la clase Genre corresponde cada una; y cuando estamos introduciendo parámetros #{nombre_párametro} en el comando sql como el caso del SELECT_BY_ID los podemos relacionar fácilmente con la anotación @Param con los párametros que se reciben en el método.

Una vez creada la interfaz hay que crear la clase que la implemente ya que ese es el objeto que finalmente se va a instanciar para hacer las consultas; la implementación es poca cosa, es simplemente invocar a una sesión de mybatis que nos devuelve un mapeador para que  internamente haga uso de lo definido en la interfaz de mapeo y obtener los resultados de la ejecución.

public class GenreDAO extends BaseDAO implements IGenreMapper{

public GenreDAO(SqlSession session){
		super(session);
	}

	@Override
	public List selectAll() {
		List result = session.getMapper(IGenreMapper.class).selectAll();
		closeSession();
		return result;
	}

	@Override
	public Genre selectByID(int id) {
		Genre result = session.getMapper(IGenreMapper.class).selectByID(id);
		closeSession();
		return result;
	}
}

Hay ciertos detalle en la clase mostrada, como por ejemplo heredar de un BaseDAO que tiene un constructor que recibe un objeto que implemente SqlSession de mybatis pero ya eso es como lo desees implementar, para mayor detalle pueden descargar el fuente relacionado al post en el link que se encuentra al final para que vean la implementación completa.

Algo que si voy a detallar es el caso cuando tenemos una propiedad compleja en nuestra clase; por ejemplo la clase Song tiene las propiedades Album y Genre que son del tipo de las clases Album y Genre respectivamente:

public class Song implements Serializable{

	private static final long serialVersionUID = -3728048783934199398L;
	private int id;
	private String name;
	private String duration;
	private Album album;
	private Genre genre;
        .
        .
        .
}

Así que para cargar las propiedades, en nuestra interface de mapeo utilizamos la anotación @One que nos permite llenar una propiedad compleja a partir de un método select que devuelva ese tipo de objeto. Como se mostro unas líneas arriba, el mapeador IGenreMapper tiene un método selectByID, del cual vamos a hacer uso en el mapeador Song para llenar la propiedad Genre, pasandole el id para que realice la consulta:

public interface ISongMapper {
	final String SELECT = "select id,album,name,duration,genre from song";

	@Select(SELECT)
	@Results( value= {
			@Result(column="id", property="id"),
			@Result(column="album", property="album", one=@One(select="com.musicservices.datamodel.mapper.IAlbumMapper.selectByID"),javaType=Album.class),
			@Result(column="name", property="name"),
			@Result(column="duration", property="duration"),
			@Result(column="genre", property="genre", one=@One(select="com.musicservices.datamodel.mapper.IGenreMapper.selectByID"), javaType=Genre.class)
	})
	public List selectAll();

}

La misma estrategia se sigue para cargar la propiedad Album, de esta manera el mapeo es completo desde nuestra base de datos relacional hacia el modelo de objetos aunque tengamos propiedades complejas.
Adicionalmente he creado una clase DataManager en la cual están las líneas donde se instancian los objetos de mybatis y el acceso a todos mis objetos DAO para centralizar el llamado a las clases, nos vamos a centrar en el código para instanciar el objeto SqlSessionFactory que es la interfaz entre nuestros objetos y la base de datos:

private DataManager(){
		if(sessionFactory == null){
			try {
				Reader reader = Resources.getResourceAsReader(DataManager.class.getClassLoader(),"dbconfig.xml");
				sessionFactory = new SqlSessionFactoryBuilder().build(reader);
				sessionFactory.getConfiguration().addMapper(IGenreMapper.class);
				sessionFactory.getConfiguration().addMapper(IAlbumMapper.class);
				sessionFactory.getConfiguration().addMapper(ISongMapper.class);
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
	}

Aquí cargamos el archivo dbconfig.xml para poder crear la sesión de mybatis a través de la clase SessionFactoryBuilder, y luego de eso registramos todas las interfaces de mapeo que hayamos creado, las cuales le sirven a mybatis para hacer su trabajo, ya que como vimos en la implementación de las interfaces hacemos uso del metodo getMapper para hacer referencia a los mapeadores registrados.

Una vez con la capa de datos lista exportamos los binarios como un .jar y procedemos a exponerla como servicios Rest a traves del framework play, lo primero es descargar los binarios desde playframework.org descomprimirlo en un directorio (recomendado sin espacios en los nombres de las carpetas) y con el comando play new [NombreAplicacion] crear la estructura de un proyecto Java:

Para mayor comodidad y modificar los archivos creados por play podemos importarlo como un proyecto para Eclipse, para esto es recomendable agregar la ruta de instalación de play a las variables de ambiente para ubicarnos dentro del directorio de nuestra aplicación y ejecutar los comandos play y luego eclipsify, y luego de eso importamos el proyecto dentro de nuestro workspace de Eclipse (el paso es opcional ya que puedes editar los archivos desde cualquier editor de texto)


Navegando dentro de los directorios de nuestra aplicación play nos vamos a encontrar con las carpetas app y conf, que son las que vamos a utilizar para el ejemplo ya que solo vamos a hacer uso del framework para exponer servicios de datos, no vamos a abarcar toda la funcionalidad, solamente el enrutamiento por url hacia los controladores que van a hacer uso de nuestro modelo de datos para realizar las consultas a la base de datos.

Empezamos creando una carpeta lib en el proyecto de play y agregamos todas las dependencias de mybatis, jdbc, y el .jar creado con nuestro modelo de datos.

Ahora sí, lo primero es dentro de /app/controllers creamos un nuevo controlador Album.java que hereda de  play.mvc.controller y le agregamos un método estático public static Result all(), esta nueva notación es parte del nuevo play 2.0, en resumen vamos a crear un método que controle todos los requests realizados por HTTP GET a la ruta /album y los devuelva en formato Json, finalmente el código con todas las consideraciones antes mencionadas queda así:

public class Album extends Controller{

	@play.mvc.BodyParser.Of(Json.class)
	public static Result all(){
		ObjectMapper mapper = new ObjectMapper();
		String json = null;
		try {
			List<com.musicservices.datamodel.entities.Album> albumList = DataManager.Instance().albumDao().selectAll();
			json = mapper.writeValueAsString(albumList);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ok(json);
	}
}

Una vez que tenemos el controlador debemos decirle a play cual es la url de la que este método del controlador se va a hacer responsable, modificamos el archivo /conf/routes y agregamos la línea para indicarle que todo lo que pase por /album y sea un HTTP GET va a ser manejado por nuestro controlador:

# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Home page
GET     /                           controllers.Application.index()
GET	    /album                      controllers.Album.all()

# Map static resources from the /public folder to the /assets URL path
GET     /assets/*file               controllers.Assets.at(path="/public", file)

Listo, ahora procedemos a levantar nuestra aplicación en play con el comando run

*En dias previos a la redacción de este post aparecio la versión 2.0 de play y al tratar de referenciar al archivo xml de configuración de mybatis que se encuentra dentro del jar da un error de classpath, asi que como queria publicar el post como workaround deben copiar el archivo dbConfig.xml dentro de su aplicación play en la ruta [AplicacionPlay]\target\scala-2.9.1\classes 

Una vez que tenemos todo listo accedemos por URL a localhost:9000/album y vemos el resultado es un string con notación Json de la colección de resultados obtenidos:


Bajo el mismo esquema creamos el controlador para hacer consultas de Albumes por código, donde ahora el método debe recibir un parámetro, y llamamos al metodo selectByID del mapeador:

@play.mvc.BodyParser.Of(Json.class)
	public static Result getByID(Integer id){
		ObjectMapper mapper = new ObjectMapper();
		String json = null;
		try {
			com.musicservices.datamodel.entities.Album album = DataManager.Instance().albumDao().selectByID(id.intValue());
			json = mapper.writeValueAsString(album);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ok(json);
	}

Y en la configuración de rutas debemos indicar el mapeo hacia el nuevo metodo controlador de la siguiente manera:

# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Home page
GET     /                           controllers.Application.index()
GET	    /album                      controllers.Album.all()
GET	    /album/:id                 controllers.Album.getByID(id: Integer)

# Map static resources from the /public folder to the /assets URL path
GET     /assets/*file               controllers.Assets.at(path="/public", file)

Accedemos nuevamente por url a la ruta /album/{id} donde {id} en este caso es el valor de la columna id en la base de datos por la cual estamos consultando en al tabla Album, los resultados son los siguientes:

Y así podemos replicar el mismo esquema para todos los controladores que deseemos publicar. Ahora para consumir estos servicios Json vamos a hacer un simple cliente Java que haciendo uso de la libreria Jersey va a obtener via HTTP GET los resultados de la consulta y con la librería Gson de google vamos a regresarlos a su estado inicial de una Lista de objetos.

public static void main(String[] args) throws UnsupportedEncodingException{

		String albumName = URLEncoder.encode("Mane Attraction","UTF-8");
		String url = String.format("http://localhost:9000/song/album/%s",albumName);

		Client client = Client.create();
		WebResource res = client.resource(url);
		String jsonData = res.get(String.class);

		List<Song> songs = new ArrayList<>();
		Type listType = TypeToken.get(new TypeToken<Collection<Song>>(){}.getType()).getType();
		songs = new Gson().fromJson(jsonData, listType);
		for(Song s: songs){
			System.out.println(s);
		}
	}

En las primeras 2 líneas armamos la url al servicio expuesto de play, utilizando la clase URLEncoder ya que si no lo hacemos los espacios o cualquier caracter especial no se va a formatear correctamente, luego haciendo uso de las clases de Jersey generamos un WebResource de la url le hacemos un HTTP Get sólo con invocar el método del mismo nombre que nos devuelve el Json generado por nuestro servidor Rest; luego de esto tenemos que transformar este resultado en objetos manejables para java; por lo que hacemos uso de Gson, al cual tenemos que informarle el tipo de objeto al que debe transformar el String que le vamos a pasar, al pasar el tipo de la instancia de TypeToken<Collection<Song>> le indicamos que queremos transformar el Json a una lista de tipo Song, invocamos el metodo fromJson y listo estamos consumiendo ya los servicios expuestos de nuestro modelo de datos.
Los Rest services son una alternativa a los tradicionales Web Services, con play es tan simple como ya lo hemos visto; la flexibilidad de mybatis para mapear datos es fantastica y que podemos decir de las apis de Jersy y Gson que con no más de 9 líneas de código nos encapsulan una capa de comunicación y transformación de datos que debemos tener en cuenta y bajo nuestra amplia gama de frameworks para dar soluciones tecnológicas.

Saludos,

@gishac

 

Descargar fuentes

Play framework on the cloud made easy: Openshift module

Consider voting for Play framework native support on Openshift.

Just a couple of years ago finding an afordable hosting solution for a java web application was a hard task, and looking for a free one was an impossible mission. Not to mention that even thinking about things like auto-scaling, one-command deploy, continuos integration, and that sort of stuff was plain science fiction.

This last year has witnessed a cloud revolution, and nowdays there’s a really appalling amount of alternatives to choose from. It seemed like every medium-to-large size IT player had to come out with their own Platform as a Service (PaaS) cloud offering.

In this scenario, an offering from Red Hat couldn’t go unnoticed. Red Hat engineers really know a lot about managing servers, and, lucklily for us, they also know a lot about java web applications. Fortunately, they took the challenge, and what they have to offer would certainly not disappoint us.

openshift homepage

Isn't that panda bear cute?

So, here comes Openshift. Openshift is Red Hat’s free, auto-scaling, cloud-based platform-as-a-service for Java, Perl, PHP, Python, and Ruby applications. It’s a quickly evolving platform, that managed to shape a vibrant and helpful community supporting it. Moreover, it’s free offering largely surpases anything that the competence has to offer. Just by entering your email and choosing a password, you get five applicacions namespaces, each of them with a git repository and half GB of data (code + database) to use as you like it. Add to that support for mysql (with phpmyadmin), PostgreSQL, MongoDB 2.0 (with MongoRock) and even a fully functional Jenkins instance to have a continuous integration environment.

Deploying a java web application to openshift is really easy, just git add, git commit, git push… and that’s it. But we, play developers, spoiled by our beloved framework as we are, would rather just type something like play rhc:deploy and forget about it.

That’s what openshift module for play framework is about.

The short story

So you have everything set up to deploy a play framework application to openshift. That means you have installed JDK 1.6 or 1.5, play framework, ruby, ruby gems, openshift client tools, and that you have signed up at openshift and also created a domain.

In that case, you just have to:

$ play install openshift

and then

$ play new <my app> --with openshift
$ cd <my app>
$ play rhc:deploy -o

… and that’s it.

Your application is ready... and running on Openshift!

Every time you want to deploy your changes to openshift, just issue once again play rhc:deploy -o. The -o parameters just tells the module to open your application on a web browser right after deployment.

From zero to the cloud

Just as a reminder to myself, here are the steps required to go from a bare linux installation to deployment on openfhit:

1. Install Java jdk 1.6

on debian based linux distributions (like ubuntu, mint and others)

$ sudo apt-get install openjdk-6-jdk

on rmp based linux distributions (like fedora, red hat, centos, and others)

$ sudo yum install java-1.6.0-openjdk-devel.i686

2. Install play framework

Here’s my quick and dirty list of commands to install play framework.

$ cd ~
$ mkdir dev
$ cd dev
$ wget http://download.playframework.org/releases/play-1.2.4.zip
$ unzip play-1.2.4.zip 

$ echo "export PATH=$PATH:~/dev/play-1.2.4" >> ~/.profile

$ source ~/.profile

And then test it with:

$ play version
~        _            _ 
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/   
~
~ play! 1.2.4, http://www.playframework.org
~
1.2.4

Note: If you are running on fedora, you might need to issue sudo yum remove sox, because the sox package comes with it’s own play command that conflicts with play framework.

3. Sign up for openshift

Go to https://openshift.redhat.com/app/user/new/express enter your email and choose a password.

4. Install, git and ruby gems

On a Debian based linux distro:

$ sudo apt-get install git ruby rubygems

Rpm version:

$ sudo yum install git ruby rubygems

5. Install openshift client tools

Once you have installed ruby gems, installing red hat cloud tools is as easy as:

$ sudo gem install rhc

6. Create a domain

Your domain namespace is used to help identify your applications and as part of the URLs to your applications. It’s unique to you across all of openshift. For example, let’s say you have the namespace awesome, when you create a new app called wicked, you’ll find it at http://wicked-awesome.rhcloud.com. When you create a new app called freakin, it’ll be at http://freakin-awesome.rhcloud.com.

So go to your openshift control panel at https://openshift.redhat.com/app/control_panel and click on edit on the NAMESPACE section. Then enter something like playdemo (well, that one is already taken) and click save.

7. Create and register your SSH keys

Now you’ll have to a SSH key, which in fact means creating a private and a public key, so that openshift can validate that it’s really you the one trying to push something to the remote git repository. Just follow the steps at http://help.github.com/linux-set-up-git/, you just have to open a terminal and then

$ cd ~/.ssh

If you get a No such file or directory error, don’t worry, it means that you didn’t have any SSH key on your system. On the other hand, if you already have a SSH key, it would be a good idea to make a backup.

$ ssh-keygen -t rsa -C "<my email>"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/sas/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/sas/.ssh/id_rsa.
Your public key has been saved in /home/sas/.ssh/id_rsa.pub.
The key fingerprint is:
22:7b:cd:f3:98:4f:92:de:80:1d:ad:d6:ea:73:20:c2 <my email>
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
|                 |
|                 |
|         .       |
|   .. . S .      |
|    Eo.*.=       |
|    ..o.@.o      |
|     . o.@.      |
|       .*++      |
+-----------------+

And then, you can setup your username and email, like this:

$ git config --global user.name "<my name>"
$ git config --global user.email "<my email>"

Now you have to register this key at openshift. Just copy the content of the id_rsa.pub (be careful not to copy the file id_rsa, it’s your private key, and you should keep that to yourself) and add it as a new SSH KEY from your control panel.

On Fedora is pretty annoying having to enter your passphrase on every git operation. To avoid it, just run ssh-add and enter your passphrase for the last time.

Alternatively, you can also use the following command

$ rhc-create-domain -l <your email> -p <your password> -n <pick a domain>

and let openshift create a a pair of private and public keys as libra_id_rsa and libra_id_rsa.pub at your .ssh/ directory. I had a couple of conflicts between my own SSH keys and the libra ones created by openshift, so I prefer to handle the ssh keys myself.

Note: You won’t be able to push anything to your git repository unless you have a valid public key registered at openshift. Take into account that you can add as many keys as needed.

Go to your control panel at https://openshift.redhat.com/app/control_panel to check that everything is right.

Going to the cloud

And now yes, we are ready to deploy our play framework application to the cloud.

$ play install openshift
$ play new <my app> --with openshift
$ cd <my app>

Now, for every command you’ll have to enter, at least, your username and password. You can spare yourself this trouble by adding the following keys to your conf/application.conf file:

# Openshift module configuration
openshift.rhlogin=<my login>
openshift.password=<my password>

After that you should check that you have installed all the prerequisites. Just run:

$ play rhc:chk

It will check for a java 1.6 or 1.5 install, git, ruby, rubygem, and openshift client tools 0.84.15 or higher. It will also check that the application exists on openshift, otherwise it will ask you to create it, and finally it will check that you have a local git repository pointing at the remote repository at openshift.

Then you can deploy your app with:

$ play rhc:deploy -o

The first time it will take quite some time to issue the deploy, because the module has to upload all of the play framework libraries. After that initial deploy, subsequent commits will be much faster, because git is smart enough to send only the changed files. Moreover, the module will ask your permission to create the app on openshift, and also to create a local repo. If you just want the script to create everything withour asking for permission, just add a --bypass or -b parameter to the command.

Your application will now be available at: http://<my app>-<my domain>.rhcloud.com.

If you have already deployed your application to openshift, and you just want to retrieve it from your remote git repository, just issue:

$ play rhc:fetch

Take into account that this is a destructive operation. It will completely remove your local application and replace it with the contents of your remote repository.

To have a look at your server logs, issue:

$ play rhc:logs
Openshift log files

Having a look at openshift log files with "play rhc:logs"

To display information about your applications on openshift run:

$ play rhc:info

Which is just a short-hand for the rhc-domain-info command.

You can open your application at openshift anytime issuing:

$ play rhc:open

Which is also a short-hand for opening a web browser at http://<my app>-<my domain>.rhcloud.com.

Finally, if you think you want to remove your application from openshift, just run:

$ play rhc:destroy

Installing the openshift module

There are two ways to install openshift module. One is just to issue play install openshift, which will install the module directly with your framework, at <play install folder>/modules/openshift-0.1.1. That way it will be available to every app you create with

$ play new my-app --with openshift

The other way is to manually configure it as a dependency. Just add the following line to your conf/dependencies.yml file:

# Application dependencies
require:
    - play
    - play -> openshift 0.1.1

And then issue

play deps

Note: play keeps a cache of fetched dependencies at ~/.ivy2/cache. If you are having troubles with dependencies just clean that directory and try again.

Along with the module there’s a sample application at <openshift module folder>/samples_and_tests/openshift-demo. Just go to that folder and issue play deps and then play run to see it running locally. It just displays play configuration and the host environment variables to let you check that your app is running on openshift.

Openshift module demo application

Openshift module demo application

Then run play rhc:chk to verify that you have installed all the prerequisites. After that issue play rhc:deploy -o to create your remote application at openshift, create a local git repo, package your app as a war file, commit your new app, and deploy to openshift. Thanks to the -o parameter the module will open your openshift app in a web browser after deployment.

Getting help

You can have a look at the module’s commands issuing:

$ play help
~        _            _ 
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/   
~
~ play! 1.2.4, http://www.playframework.org
~

[...]
~
~ Modules commands:
~ ~~~~~~~~~~~~~~~~~
~ rhc:chk             Check openshift prerequisites, application and git repo.
~ rhc:deploy          Deploys application on openshift.
~ rhc:destroy         Destroys application on openshift.
~ rhc:fetch           Fetches application from remote openshift repository.
~ rhc:info            Displays information about user and configured applications.
~ rhc:logs            Show the logs of the application on openshift.
~ rhc:open            Opens the application deployed on openshift in web browser.
~
~ Also refer to documentation at http://www.playframework.org/documentation
~

Then you can get more help about parameters with the -h or --help parameter:

$ play rhc:chk -h
~        _            _ 
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/   
~
~ play! 1.2.4, http://www.playframework.org
~
Usage: play [options]

Options:
  -h, --help            show this help message and exit
  -a APP, --app=APP     Application name  (alphanumeric) (required)
  -s SUBDOMAIN, --subdomain=SUBDOMAIN
                        Application subdomain, root by default  (alphanumeric)
                        (optional)
  -l RHLOGIN, --rhlogin=RHLOGIN
                        Red Hat login (RHN or OpenShift login with OpenShift
                        Express access)
  -p PASSWORD, --password=PASSWORD
                        RHLogin password  (optional, will prompt)
  -d, --debug           Print Debug info
  -m MESSAGE, --message=MESSAGE
                        Commit message
  --timeout=TIMEOUT     Timeout, in seconds, for connection
  -o, --open            Open site after deploying
  -b, --bypass          Bypass warnings

You can also specify these options in the conf/application.conf file with the following keys:

openshift.rhlogin: Red Hat login (RHN or OpenShift login with OpenShift Express access)
openshift.password: RHLogin password  (optional, will prompt)
openshift.application.name: Application name  (alphanumeric) (required)
openshift.application.subdomain: Application subdomain, root by default  (alphanumeric)
openshift.debug: Print Debug info
openshift.timeout: Timeout, in seconds, for connection

You can see all versions of the module at the openshift module’s page on http://www.playframework.org/modules/openshift.

You can check the documentation at http://www.playframework.org/modules/openshift-0.1.1/home, or running locally your app in dev mode with play run, and then going to http://localhost:9000/@documentation/modules/openshift/home.

Local documentation

Browsing module documentation locally

You can ask questions at the play framework discussion list at https://groups.google.com/group/play-framework, or you can try with it’s spanish cousin at https://groups.google.com/group/play-latam.

Known issues

Unfortunately, right now the openshift module doesn’t work with windows. That’s because the module issues many git commands, and you can’t do that on windows from the standard shell, it requires a special “git bash” prompt.

Further steps

In the next version I’ll be exploring the possibility of building a java only version of the module using openshift’s java api. That way we won’t be needing git, ruby, nor the rhc tools installation. Morevoer, we should be able to use it all from windows as well.

Resources

Play framework openshift module page: http://www.playframework.org/modules/openshift

Latest version: http://www.playframework.org/modules/openshift-0.1.1/home

Project at github: https://github.com/opensas/openshift

Detailed tutorial about how to deploy a Play Framework application to openshift: https://github.com/opensas/play-demo/wiki/Step-12.5—deploy-to-openshift

Excellent tutorial about deploying java applications to openshift: https://gist.github.com/1637464#file_tutorial.rst

A couple of articles on jboss planet:
http://planet.jboss.org/post/let_s_play_on_the_red_hat_cloud_using_the_play_framework_on_openshift_express_with_jboss_as_7
https://community.jboss.org/blogs/thomas.heute/2011/06/29/play-framework-on-jboss-as-7?_sscc=t

Divide and conquer: Play framework modules

It’s usually the case that you start developing an application and go on fulfilling requirements. When your application grows bigger you start to realize the convenience of separating it into different components. Moreover, when you develop your second or third application, your begin to recognize certain features that could be reused across different applications.

These are two good reasons to modularize an application. Ideally we should aim at components with high cohesion and low coupling.

The Java language has proven itself quite fit to accomplish this kind of tasks. It provides general means to enforce the use of well defined API thru interfaces, abstract classes, etc.

Play framework developers think that this is perfectly fine for developing a general purpose library, but in the case of a web application reusability and modularization could be best achieved by other means. Have a look at this excerpt taken from play framework’s FAQ:

Java itself is a very generic programming language and not originally designed for web application development. It is a very different thing to write a generic and reusable Java library and to create a web application. A web application itself doesn’t need to be designed to be reusable. You need less abstraction, less configuration. Reusability does exist for web applications, but through web service APIs rather than language-level integration.

So when it comes to reusability, play provides us with a solution better suited for web applications.

Play modules

A module is just another Play framework application. The only difference is that a module is not meant to be run on his own, it needs to be included into a containing application.

Nevertheless, there area a couple of differences between a module and a regular application, mainly that a module has no conf file (it has to be provided by the main application) and everything in a module is optional.

Doing is better than saying, so as usual we will look for a fine opportunity to make a simple module to show how it works.

Creating a new play framework application and deploying it to the cloud

As many of you already know, we are working on the spanish translation of play framework site. We wanted to add web analytics to it so that we can see how people were using it.

So in order to follow this example, we’ll need a play framework app deployed somewhere on the Internet. Nowadays there are lots of Java hosting options available for free. Here you have a couple of tutorials for deploying on openshift, google application engine and heroku.

First let’s create a play framework application, I’ll create the app at ~/devel/apps/module-test, you can choose whatever location you like, just be sure to update the commands appropriately.

To create the app, run the following command at an os prompt:

sas@ubuntu:~/devel/apps/module-test$ play new analytics-app
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.2.4, http://www.playframework.org
~
~ The new application will be created in /home/sas/Dropbox/Public/devel/play/apps/module-test/analytics-app
~ What is the application name? [analytics-app]
~
~ OK, the application is created.
~ Start it with : play run analytics-app
~ Have fun!

Now it would be a good time to deploy it somewhere. For this tutorial we will deploy it at openshift, you can use any host you want (For more information on setting up your environment for openshift deployment follow this tutorial)

Consider voting for Play framework native support on Openshift.

Create a new directory at ~/devel/apps/module-test/openshift, go to that directory and run:

rhc-create-app -l mymail@mail.com -p mypassword -t jbossas-7.0 -a analyticsapp

Attempting to create remote application space: analyticsapp
Now your new domain name is being propagated worldwide (this might take a minute)...
Pulling new repo down

[...]

Successfully created application: analyticsapp

Next, we’ll get rid of the demo app:

cd ~/devel/apps/module-test/openshift/analyticsapp
rm -fr pom.xml src

And we’ll compile and package the newly created app as an exploded war. Go to ~/devel/apps/module-test folder and run:

cd ~/devel/apps/module-test
play war analytics-app -o openshift/analyticsapp/deployments/ROOT.war
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.2.4, http://www.playframework.org
~
JPDA port 8000 is already used. Will try to use any free port for debugging
Listening for transport dt_socket at address: 53978
00:22:38,021 INFO  ~ Starting /home/sas/Dropbox/Public/devel/play/apps/module-test/analytics-app
00:22:39,891 INFO  ~ Precompiling ...
00:22:49,075 INFO  ~ Done.
~ Packaging current version of the framework and the application to /home/sas/Dropbox/Public/devel/play/apps/module-test/openshift/analyticsapp/deployments/ROOT.war ...
~ Done !
~
~ You can now load /home/sas/Dropbox/Public/devel/play/apps/module-test/openshift/analyticsapp/deployments/ROOT.war as a standard WAR into your servlet container
~ You can't use play standard commands to run/stop/debug the WAR application...
~ ... just use your servlet container commands instead
~
~ Have fun!
~

Now we just need to commit the application and push it to our git repo on openshift:

cd ~/devel/apps/module-test/openshift/analyticsapp
touch deployments/ROOT.war.dodeploy
git add -A
git commit -m "deploy play framework app"
git push origin

Note: The first time it will take a couple of minutes to push the application, because of play framework libraries. Later pushes will be much quicker, git is smart enough to only send updated files.

And that’s it, you’ve just deployed your first app to red hat’s cloud. You can see it running at http://analyticsapp-opensas.rhcloud.com/ (of course, you’ll have to replace “opensas” with your own openshift user name).

Google web analytics & play framework

Adding Google web analytics to a play app is really easy. You just need a gmail account, then go to Google Analytics web site, click on “sign up”, login with your gmail account, and complete all the required data.

In the account name enter “analytics-app”, in the website’s url enter http://analyticsapp-opensas.rhcloud.com/, agree to the terms and conditions and click on “Create account”.

You’ll be taken to your analytics-app account page, there you can see the tracking code. You’ll just have to paste it in your app. So open the file at ~/devel/apps/module-test/analytics-app/app/views/main.html and paste the tracking code before the closing head tag, like this:

[...]
<script charset="${_response_encoding}" type="text/javascript" src="@{'/public/javascripts/jquery-1.6.4.min.js'}"></script>#{get 'moreScripts' /}<script type="text/javascript">
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();
</script>
[...]

Note: Google will provide you with your own UA-XXXXXXXX-1 account code, so just copy and paste the code from your Google analytics account page, and NOT from this page!

Now you just have to generate the war folder, commit, and push it once again to openshift to deploy your changes. Every time you make a change you’ll have to follow these same steps to deploy it to openshift.

cd ~/devel/apps/module-test
play war analytics-app/ -o openshift/analyticsapp/deployments/ROOT.war
cd openshift/analyticsapp/
git add -A
git commit -m "added tracking code"
git push origin

Visit again your page at http://analyticsapp-opensas.rhcloud.com/, and see the source of the page to check that the tracking code has been added. You can also see it in action on Google’s analytics page, click on “Home”, Real-Time (BETA), and the Overview. You should have one visitor (yes, it’s you!).

So far now we created a new play application and deployed it to openshift. Then we created a Google analytic account and added the tracking code the our play application. Everything is working ok and our app is being tracked by Google. Now we are going to move that functionality to a module so that we can reuse it from other apps.

Creating a module

To create a new module you have to use the “new-module” play command, like this:

cd /home/sas/devel/apps/module-test/
play new-module analytics

Now, in order to tell our main application (in our case analytics-app) to include this module, we have to configure a local repository.

Edit ~/devel/apps/module-test/analytics-app/conf/dependencies.yml like this:

# Application dependencies

require:
    - play
    - analytics -> analytics

repositories:
    - My local modules:
        type:       local
        artifact:   ${application.path}/../[module]
        contains:
            - analytics

and after that run the following command to tell play to resolve dependencies.

cd ~/devel/apps/module-test/analytics-app
play dependencies
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.2.4, http://www.playframework.org
~
~ Resolving dependencies using /home/sas/devel/apps/module-test/analytics-app/conf/dependencies.yml,
~
~ 	analytics->analytics -> (from My local modules)
~
~ Installing resolved dependencies,
~
~ 	modules/analytics -> /home/sas/devel/apps/module-test/analytics/../analytics
~
~ Done!
~

You can now start the main application on your workstation:

cd ~/devel/apps/module-test/analytics-app
play run

You can see your app running at http://localhost:9000.

Moving the tracking code to a reusable tag

Now we will move the tracking code to a tag defined in the module, so we’ll create a file ~/devel/apps/module-test/analytics/app/views/analytics.html with the tracking code, like this:

<script type="text/javascript">
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();
</script>

And now, replace the tracking code in main.html with a call to the tag, like this:

[...]
<script charset="${_response_encoding}" type="text/javascript" src="@{'/public/javascripts/jquery-1.6.4.min.js'}"></script>
        #{get 'moreScripts' /}

#{analytics /}

[...]

 

Getting module configuration from the application.conf file

Our module is almost ready, there’s just one thing that’s preventing us from really reusing it on another application: the Google analytics code is hardcoded in our tag! So we will read it from the application.conf file. Just edit the analytics.html tag like this:

%{
    String code = play.Play.configuration.getProperty("analytics.code", "")
}%
#{if code!=""}<script type="text/javascript">
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', '${code}}']);
  _gaq.push(['_trackPageview']);
  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();
</script>
#{/if}

and add the following to your main application configuration file at ~/devel/apps/module-test/analytics-app/conf/application.conf

analytics.code=UA-XXXXXXXX-1

Prevent tracking in dev mode

This tag will will update the tracker every time the page is rendered, even when we are working on our development workstation!

So we will add a minor improvement to prevent the module from logging the page activity while working in development mode.

Just add the following condition to the code:

%{
    String code = play.Play.configuration.getProperty("analytics.code", "")
}%
#{if play.mode.isProd() && code!=""}
<script type="text/javascript">

  var _gaq = _gaq || [];
[...]

Troubleshooting Openshift

Openshift won’t be able to resolve the relative reference to the module location (and in fact any war deployed application will have the same problem), so you’ll have to tell play to copy the module sources to the containing application before generating the war folder. Just issue:

cd ~/devel/apps/module-test/analytics-app
play dependencies --forceCopy

And that’s it, now you can deploy to openshift in the usual way:

cd ~/devel/apps/module-test
play war analytics-app/ -o openshift/analyticsapp/deployments/ROOT.war
cd openshift/analyticsapp/
git add -A
git commit -m "added analytics module"
git push origin

Run your site locally with “play run”, and also open it from http://analyticsapp-opensas.rhcloud.com/ (go on, give it a try, every click counts), check the source code of both sites, you should see that the app running at openshift contains the tracking code, contrary to your local application.

Conclusion

In this post we saw how to deploy a play framework app to openshift and, more important, how to move features from your application to a module in order to reuse it from other applications.

In the meantime, I’ve also added google analytics support to Play! framework spanish translation site. Here you can see it in action:

Google analytics realtime in action
Tracking visits from Colombia, Argentina, Perú, El Salvador
Venezuela, Costa Rica, Ecuador, México, Spain… in realtime

You can learn more about modules on this article or reading play’s documentation.

If you speak spanish you can help us with the translation, and you can also have a look at our work right here… You can be sure every click you make will be tracked!

%d bloggers like this: