2. What is Play?
Play is a cool framework
Easy to learn
Play supports both Scala & Java
3. What do I like most
Best error reporting ever seen
Hit refresh and works
(this applies for configurations, templates or code changes)
4. What else?
Play is REST-ful
❖ Matches the web architecture which is stateless
➢ the state will be stored on the other tiers
(Cookie, Database,Cache Server)
❖ Easy testing, easy sharing, easy bookmarking
➢ an url is what you need
❖ Horizontal scalability
# Routes
# This file defines all application routes (Higher priority routes first)
GET / controllers.Application.index
GET /:timeout controllers.Application.asyncURLGet(timeout: Int, url:String)
GET /clients/$id<[0-9]+> controllers.Clients.show(id: Long)
GET /clients controllers.Clients.list(page: Int ?= 1)
GET /hello/:name controllers.Application.hello(name:String)
Play has a powerful URL rooting
➔ url should be established before coding
➔ more complicated routing can be achieved by extending
GlobalSettings or by defining your own Router
➔ even more can be done with PathBindable
➔ also possible to do reverse routing
routes.Application.hello("Bob")
Play has a very simple config
Play is a modern web framework
● application.conf
environment="development"
db.default.url = "jdbc:mysql://127.0.0.1:3306/mydb"
…
● production.conf
include "application.conf"
environment="production"
db.default.url = ${?MYSQL_URL}
5. Some Code Example
Request -> is the request performed by the client
Action -> something which converts a request into a response
Response -> Is the HTTP Response with Status Code, Cookies, Headers, Body
BodyParser -> a function that transforms the request body in a Scala (or Java) value, based on Content-Type of the
request
object Application extends Controller {
def index = Action {
Ok("It works!")
}
def hello(name: String) = Action {
Ok("Hello " + name)
}
}
GET / controllers.Application.index
GET /hello/:name controllers.Application.hello(name:String
The above example is not getting any reference from the incoming request, but we have another Action builder that takes as an
argument a function Request => Result:
def index = Action { request =>
Ok("Got request [" + request +
"]")
}
Simple example of serving a response
routes file
Action(parse.text) { request =>
val text = request.body
Ok("Got request " + text )
}
We can use a body parser in order to read the request.
In this example we will use the play.api.mvc.BodyParsers
parse.text -> parses the body as text if the Content-Type is text/plain.
6. Inside Play
Play has a MVC stack with a template system
Templates
Scala-based template engine
Template markup syntax
@(title: String, content: String)
<!DOCTYPE html>
<html>
<head>
<title>@title</title>
</head>
<body>
@content
</body>
</html>
Ok(views.html.main("title","content"))
Templates and assets are
compiled so any error will be
displayed immediately
app → Application sources
└ assets → Compiled asset sources
└ stylesheets → Typically LESS CSS sources
└ javascripts → Typically CoffeeScript sources
└ controllers → Application controllers
└ models → Application business layer
└ views → Templates
conf → Configurations files and other non-compiled resources
└ application.conf → Main configuration file
└ routes → Routes definition
public → Public assets
└ stylesheets → CSS files
└ javascripts → Javascript files
└ images → Image files
project → sbt configuration files
└ build.properties → Marker for sbt project
└ plugins.sbt → sbt plugins & declaration for Play itself
logs → Standard logs folder
└ application.log → Default log file
target → Generated stuff
test → source folder for unit or functional tests
myProject
7. Where is the fun?
Load Balancer
Play Server
Play Server
Play Server
This is what we have until now
- it’s cool but no fun -
8. This is fun !!!
Load Balancer
Play Server
Play Server
Play Server
Cloud Service
Memcache Service
Database
Cloud Storage
Cloud Service
Cloud Service
!!! The remote services latency in a threaded model could mean trouble !!!
9. Solving the issue
Play is built on top of Akka and Netty
➔ you can use non-blocking I/O when making calls to remote services
In high traffic environments, thread pools management is painful
❖ make threads on the fly
➢ This is expensive inefficient
❖ use a thread pool with too few threads
➢ run up of threads -> latency issues
❖ use a thread pool with too many threads
➢ context switching overhead
➢ Memory overhead
Play comes with a WS Library
WS.url(url).withHeaders("headerKey" -> "headerValue").get()
➔ request reading is also async
➔ enables:
◆ WebSockets
◆ Comet
Attention the database access most probably will not be async
11. Play it’s production ready
Play is already being used by companies like:
Play is scalable
Instant deployment on
but you can found instruction for:
Cloudbees
Cloud Foundry
Clever Cloud
12. Some other features
Database evolutions
evolutions.use.locks=true
database locks are used to ensure that only
one host applies any Evolutions
# Users schema
# --- !Ups
CREATE TABLE User (
id bigint(20) NOT NULL
AUTO_INCREMENT,
email varchar(255) NOT NULL,
password varchar(255) NOT NULL,
fullname varchar(255) NOT NULL,
isAdmin boolean NOT NULL,
PRIMARY KEY (id)
);
# --- !Downs
DROP TABLE User;
when running on multiple hosts only use evolutions if you are using
Postgres or Oracle
Anorm, simple SQL data access
Plugins
classes that extend the Plugins trait
conf/play.plugins file
10000:my.example.FirstPlugin
10001:my.example.SecondPlugin
<priority>:<classname>
def enabled : Boolean
def onStart (): Unit
def onStop (): Unit
in
can overwrite the following methods
conf/evolutions/default/1.sql
conf/evolutions/default/2.sql
...
Dependency injection
Activator
Spring
Subcut
Macwire
Guice
val appDependencies = Seq( javaJpa, "org.hibernate" %
"hibernate-entitymanager" % "3.6.9.Final")
Unit testing
Junit -> java
Specs2 -> scala
integration with Selenium
No built-in JPA implementation in Play, but you can add
Hibernate
SQL("Select name,indepYear from Country")().map {
row =>
row[String]("name") -> row[Int]("indepYear")
}