For Play! 2.x & Scala, please read my Play! 2.x guide.
The Play! framework is a web application framework that can be used with Java or Scala. And it makes it easy, quick but also powerful. By purposfully not adhering to the outdated j2ee spec, Play's api is much cleaner and RESTful. Its feature of dynamic class reloading makes development very quick.
Heroku is a cloud based application platform or PAAS (Platform as a Service). Or a "Polyglot Cloud Application Platform" according to James Ward. It runs on top of Amazon AWS ec2, but you do not need to know anything about that. The interface is so easy and quick to use which is why I like it. The big bonus is that if you only run one "web server" (dyno) per application it is free. Only when you need to scale or add special features do you need to pay anything. And then it is mostly pay as you go, so not locked in for the year. Another neat feature of Heroku is the use of Git as deployment tool.
This guide will assume Ubuntu is your OS. However any Linux distro will be fine, Mac OSX will also be quite similar. Windows will be different but with similar steps.
Since Oracle decided to disallow security updates for Java 6 on Ubuntu, I will assume OpenJDK 7.
sudo aptitude install openjdk-7-jdk
You can alternatively install Oracle Java 7 via a PPA.
Heroku's deployment model uses Git so while you don't need to be a git guro, you do need to use it.
sudo aptitude install git gitk
The Debian Play module seems outdated, and I have not been able to find a good PPA, so there is no .deb packge to install. However installing manually is easy. You will have to upgrade it manully in the future however.
Download the latest 1.x version from www.playframework.org/download (currently 1.2.4)
wget http://download.playframework.org/releases/play-1.2.4.zip
Unzip and move to a library position
unzip play-1.2.4.zip;
sudo mv play-1.2.4 /usr/local/lib/;
cd /usr/local/lib;
sudo ln -s play-1.2.4 play;
Add play to your path by editing /etc/environment
sudo vi /etc/environment
Append play path to the
PATH="/usr/local/..../usr/games:/usr/local/lib/play"
To delay relogging in to activate the /etc/environment changes
export PATH="$PATH:/usr/local/lib/play"
To test if it works
play version
If you can afford the Ultimate edition (or get work to pay for it) then great as it has from version 11 built in support for Play. However I can not afford it so I will describe the Community edition.
Download IntelliJ from www.jetbrains.com/idea/download/
Unpack it and move to an appliation location
tar xzf ideaIC-11.tar.gz;
sudo mkdir -p /opt/jetbrains;
sudo mv idea-IC-111.69 /opt/jetbrains/;
cd /opt/jetbrains;
sudo ln -s idea-IC-111.69 idea
You can now start IntelliJ with:
/opt/jetbrains/idea/bin/idea.sh
Or add /opt/jetbrains/idea/bin folder to your PATH variable like we did with Play, or create a Unity launcher.
Basically we are following step 1-3 of the Heroku quickstart article
First sign up to Heroku.
To use Heroku's command line tool called Toolbelt you need to add a PPA repository (toolbelt.herokuapp.com/ubuntu) and install heroku-toolbelt. Either do it via Ubuntu Software Center, Synaptic or by the commands below:
sudo apt-add-repository 'deb http://toolbelt.herokuapp.com/ubuntu ./';
curl http://toolbelt.herokuapp.com/apt/release.key | sudo apt-key add -;
sudo aptitude update;
sudo aptitude install heroku-toolbelt;
On initial login it will ask you to upload a SSH public key. If you have one already you can reuse it, or you can manually create one before hand, or Heroku will create one for you.
heroku auth:login
As detailed in Plays tutorial
play new pizzeria
Then set up version control.
cd pizzeria;
git init;
git add .;
git commit -m "Initial"
Create an IntelliJ project.
play idealize
Now you can open the project in IntelliJ IDEA. (You probably want to add *.iml, *.ipr and .idea to the .gitignore file)
As Play continously reloads classes while in development mode, we start the Play application first. (again similar to Play's tutorial)
play run
If you go to localhost:9000 you will see the initial page for your application.
Next we will then set up a controller and some views
In your IDEA open app/controllers/Application.java. Notice the index method:
...
public static void index() {
render();
}
...
Since this controller method just calls render() without parameters it will render the view app/views/Application/index.html. If you open this file:
#{extends 'main.html' /}
#{set title:'Home' /}
#{welcome /}
First line tells you this is a subset of another template main.html. Then sets the title of the page. The #{welcome /} shows a custom tag which is all the welcome blahbla you see on the front page. Modify this file to:
#{extends 'main.html' /}
#{set title:'Pizzeria' /}
<h1>Pizzeria</h1>
<ul>
<li><a href="@{Application.about}">About</a></li>
</ul>
If you refresh your browser window (localhost:9000), you will now get an error. This is because the URL in the list above is not yet implemented.
Open app/controllers/Application.java. Add this method:
...
public static void about() {
render();
}
...
Again a very simple method, and you need to create the view at app/views/Application/about.html.
#{extends 'main.html' /}
#{set title:'About the Pizzeria' /}
<h1>About the Pizzeria</h1>
<p>
Lorem ipsum dolor sit amet, arcu et leo lacinia etiam
viverra fames, facilisi inceptos ultricies vitae tristique
phasellus, leo ut proin cum dictumst ultricies ultricies
</p>
You can now reload the front page, and even click on the about page link.
The url shown and in the links are not so "tidy", and to make them more RESTlike you need to edit the conf/routes file. Modify it so it is similar to:
...
# Home page
GET /
Application.index
GET /index.html
Application.index
GET /about.html
Application.about
...
You can read more about controllers, template views and routes in the play documentation.
More interesting than the above mostly static templates are forms and binding to objects within Play. We will create a pizza order form, and relevant controllers for dealing with the order. (You may apply TDD for this development using Play's built in testing support).
Create a new controller at app/controllers/PizzaOrder.java.
package controllers;
import play.mvc.Controller;
import play.Logger;
public class PizzaOrder extends Controller {
public void showOrderForm(){
render("PizzaOrder/orderform.html");
}
}
The showOrderForm method is a simple template redirection to show the form. This time we are actually specifying the template name.
Create the template app/views/PizzaOrder/orderform.html
<h1>Pizza order</h1>
#{form @PizzaOrder.orderPizza()}
<fieldset>
<legend>Choose pizza</legend>
#{select 'pizzaType', value:'pepperoni'}
#{option 'margherita'}Margherita{/option}
#{option 'hawaiian'}Hawaiian{/option}
#{option 'pepperoni'}Pepperoni{/option}
#{option 'quattroformaggi'}Quattro formaggi{/option}
#{/select}
</fieldset>
<fieldset>
<legend>Size</legend>
<input type="radio" name="size" id="sizeMedium"
value="Medium" checked="checked" />
<label for="sizeMedium">Medium</label>
<br/>
<input type="radio" name="size" id="sizeLarge"
value="Large" />
<label for="sizeLarge">Large</label>
</fieldset>
<fieldset>
<legend>Delivery address</legend>
<input type="text" name="address" />
</fieldset>
<button type="submit">Order pizza<button>
#{/form}
(We are using Play 1.x's Groovy based templated script and tagging to simplefy the form generation).
Modify app/controllers/PizzaOrder.java by adding two methods:
...
public void orderPizza(
String pizzaType, String size, String address){
Logger.info("Ordering pizza: " pizzaType);
// business order logic
pizzaOrdered(pizzaType);
}
public void pizzaOrdered(String pizzaType){
render(pizzaType);
}
...
The orderPizza method is the real business logic method. It receives form data, binds it to java objects and processes this. (Actually we mostly ignore the data, but a real application would obviously not). Then it calls the pizzaOrdered method for showing a confirmation template. Play will detect this and issue a HTTP redirect to this method, so that you are protected against multiple accidental orders.
Create the template app/views/PizzaOrder/pizzaOrdered.html
<h1>Pizza ordered</h1>
<p>
The ${pizzaType} pizza will arrive within 40 minuttes!
</p>
We need to tidy up the URLs. We need one (and perhaps two aliases) to show the form, a POST handler for receiving the form, and a confirmation page. Open conf/routes:
...
GET /order/
PizzaOrder.showOrderForm
GET /order/index.html
PizzaOrder.showOrderForm
GET /order/new.html
PizzaOrder.showOrderForm
POST /order/
PizzaOrder.orderPizza
GET /pizzaOrdered.html
PizzaOrder.pizzaOrdered
...
Ps. A cleaner way when the form expands is to create a POJO binding instead of individual method parameters.
Ps2. We could also have applied validation.
A more usefull order flow is perhaps if we are notified of the order! Play provides an easy way of sending email. And enables a mocking class for email in development mode.
Open conf/application.properties. We will keep the mock feature enabled, but set production mode to connect to relay via GMail.
...
# Mail configuration
# ~~~~~
# Default is to use a mock Mailer
mail.smtp=mock
%prod.mail.smtp.host=smtp.gmail.com
%prod.mail.smtp.user=yourusername@gmail.com
%prod.mail.smtp.pass=yourpassword
%prod.mail.smtp.channel=ssl
...
Open app/controllers/PizzaOrder.java, modify the orderPizza method and add a call to PizzaOrderMailer.
...
public void orderPizza(
String pizzaType, String size, String address){
...
PizzaOrderMailer.sendOrder(pizzaType, size, address);
...
pizzaOrdered(pizzaType);
}
...
Create app/notifiers/PizzaOrderMailer.java.
package notifiers;
import play.mvc.Mailer;
public class PizzaOrderMailer extends Mailer {
public static void sendOrder(
String pizzaType, String size, String address){
setSubject("Pizza order");
addRecipient("[email protected]");
setFrom("Pizzeria Website <[email protected]>");
send(pizzaType, size, address);
}
}
The actual email sent can be plain text but in our case it will be html based. Like normal pages it is a template. Open app/views/PizzaOrderMailer/sendOrder.html:
<html>
<body>
<pre>
Pizza order
Pizza type: ${pizzaType}
Pizza size: ${size}
Delivery address: ${address}
<pre>
</body>
</html>
You can customise the error pages (404 & 500 only). Simply edit the files in app/views/errors. For further fine grained errors (410, 403, 302, etc) you will need an Apache server in front.
To create a dyno for this application:
heroku create -s cedar
This will create a server for you to deploy to. It will respond with a domain name that your application will run on. Something like blue-moon-123.herokuapp.com.
Previously you needed to create a Procfile, to describe launch parameters, such as port number etc. This is no longer needed, unless you need to customise this.
Make sure everything is added and commited to git:
git commit -am "kitchen sink commit"
Then to deploy your appliction to the dyno created by Heroku:
git push heroku master
Now either open a browser and type in the dyno's domain name or execute:
heroku open
Voila!
Heroku offers a range of add-ons to add to your application. Most are free or at least free initially and only start to charge once you application requires heavy load or further scaling.
The URL blue-moon-123.herokuapp.com is fine to use while testing and developing. But in many production situation it is not ideal. So you can add the domain name add-on, which will listen to requests of that name if the dns aliases to blue-moon-123.herokuapp.com.
More practically in my situation is that this enables the Play application to know it is listening to your real domain name. And so that you can put an Apache httpd server infront as a load balancer while still proxying to blue-moon-123....
heroku domains:add myapp.example.com
(Note Heroku now includes Custom domain addon by default).
(Note2 in Play's conf/application.conf you can also hard code the production domain name under %prod.application.baseUrl).
If you need more customisation than the mentioned integration with GMail, like not involving Google for example, among several choices is SendGrid add-on.
Several choices including the plain Logging add-on.
There are multiple databases available as add-ons. From standard RDBMS like PostgreSQL and MySQL (with Amazon RDS as an option as well) to NoSQL DBs like MongoDB, Redis and CouchDB to in memory caching solutions like Memcache.
You do not need to have an Apache Httpd server in front your Play application(s). Especially if you have added the Custom Domain add-on.
However I do so that I can switch between Heroku and applications hosted elsewhere. And enable smooth load balancing especially during rollout staging. The fact I already run a httpd server means no increased cost for me.
Play also document how to configure lighthttpd as proxy infront of Play, I will however use Apache.
As part of my AWS ec2 guides I detail how to relay traffic from between Apache Httpd and Tomcat servers. And in this situation we need to do the same.
I am asuming you already have an Apache server up and running. If not, follow my AWS ec2 Apache Httpd and Tomcat servers guide. In that I detail how to set up the servers. I also describe how to relay traffic from between Apache Httpd and Tomcat servers and in this situation we need to do something similar.
You need to install and enable the Reverse proxy module.
sudo aptitude install libapache2-mod-proxy-html;
sudo a2enmod proxy_html
Ensure you are not exposing your server as a normal proxy, by stating ProxyRequests Off.
sudo vi /etc/apache2/mods-enabled/proxy.conf
...
ProxyRequests Off
...
Open you virtual host and modify to something like these proxy lines
sudo vi /etc/apache2/sites-available/example.com
ServerName www.example.com
...br/>
<IfModule mod_proxy.c>
ProxyPreserveHost On
ProxyPass /pagenottoproxy.html !
ProxyPass / http://blue-moon-123.herokuapp.com/
ProxyPassReverse / http://blue-moon-123.herokuapp.com/
</IfModule mod_proxy.c>
...
</VirtualHost>
Activate changes with
sudo apachectl -t;
sudo service apache2 reload
The main benefit with having a httpd server in front of Play applications is the ability to load balance smoothly.
Enable the balancer module.
sudo a2enmod proxy_balancer
Modify your virtual host file similar to this:
sudo vi /etc/apache2/sites-available/example.com
ServerName www.example.com
...
<Location /balancer-manager>
SetHandler balancer-manager
Order Deny,Allow
Deny from all
</Location>
<IfModule mod_proxy.c>
ProxyPreserveHost On
ProxyPass /pagenottoproxy.html !
<Proxy balancer://mycluster>
BalancerMember http://blue-moon-123.herokuapp.com
BalancerMember http://apps.example.com:9000 status=+H
</Proxy>
ProxyPass / balancer://mycluster/
ProxyPassReverse / http://blue-moon-123.herokuapp.com/
ProxyPassReverse / http://apps.example.com:9000/
</IfModule mod_proxy.c>
...
</VirtualHost>
In this example we use Heroku but also the application is deployed to a different server on port 9000.
The stats=+H of the second balancer member indicate that this member will only be used when no other can be reached. So this configuration is a fail-over load balancer.
Do remember Heroku will do load balancing for you. But this configuration is nice for staging rollout, and for simple switchover to alternative hosting.
For a smooth rollout you can use Heroku and load balancing. Note when deploying Play it will initially be unvailable due to when running in Production mode it will pre-compile all classes, so a smooth rollout makes a difference.
With Heroku's pricing model you only need to pay for those few minuttes the second server is running.
I have a seperate document for Play1 2.0 + Scala + Heroku
Next possible steps could be:
If you need assistance, please use these channels:
Or hire me (www.eray.co.uk) for: