Play framework 2 : Peter Hilton


Published on

This presentation introduces the key innovations that Play 2 brings to web application development in Java and Scala. The Play framework has brought high-productivity web development to Java with three innovations that changed the rules on Java EE: Java class and template save-and-reload that just works, a simplified stateless architecture that enables cloud deployment, and superior ease-of-use. Following Play's rapidly-growing popularity, Play 2.0 was released in March 2012 with innovations that are not just new in the Java world: type-safe view templates and HTTP routing, compile-time checking for static resources, and native support for both Java and Scala. Type safety matters. After dynamically-typed programming languages such as PHP and Ruby set the standard for high-productivity web development, Play built on their advantages and has created a type-safe web development framework with extensive compile-time checking. This is essential for applications that will scale to tens of thousands of lines of code, with hundreds of view templates. Meanwhile, Play avoids the architectural-complexity that is promoted by Java EE-based approaches. The result is that Play 2 first enables rapid initial application development and then Play 2 helps you build big, serious and scalable web applications.

Published in: Technology

Play framework 2 : Peter Hilton

  1. 1. Play  framework  2@PeterHilton  at  #JAXLondon  on  17  October  2012
  2. 2. 2Peter  Hilton■ (sorry, I am not Guillaume Bort)■ Web developer and Operations Director at Lunatech Research in Rotterdam ■ Web application architecture, design and construction ■ Technical project management and functional design■ Play framework committer since 2010■ Co-author of the book Play for Scala (Manning)
  3. 3. 3About  Lunatech■ Founded  in  Ro*erdam  in  1993  as  an  IT  consul6ng,  product   research  and  development  team■ We  build  web  applica6ons,  web  services,  large-­‐scale  document-­‐ processing  and  message-­‐processing  applica6ons,  online  products■ Leverage  cuBng-­‐edge  open-­‐source  soCware  plaDorms■ Invest  in  product  research  and  development■ Play  framework;  Java  EE  -­‐  JBoss  AS,  Seam,  JPA,  jBPM,  Drools;   back-­‐end  -­‐  PostgreSQL,  Linux;  front-­‐end  -­‐  jQuery,  Backbone,  _.js■ Agile  soCware  development  -­‐  self-­‐managing  technical  teams
  4. 4. 4“ Play  introduces  high-­‐produc6vity   type  safe  web  development Presenta6on  goal:  show  you  how  cool  Play  is
  5. 5. 5Outline■ What Play is and why it matters (web architecture)■ High-productivity web development (but for Java and Scala developers)■ Developer Experience (DX) that doesn’t suck■ Type safe compile-time checked web development■ HTML5 front-end development
  6. 6. 6What  Play  is■ Full-stack web framework (what you need to build an app)■ Simple, flexible and powerful HTTP interface■ High-productivity web development■ High-performance scalable architecture■ Designed by web developers for web developers■ Play is fun
  7. 7. h&p://
  8. 8. h&p://
  9. 9. 9“ What  is  the  focal-­‐point  of  web   applica6on  architecture?
  10. 10. 10“ It’s  the  web  browser,  stupid
  11. 11. 11Why  Play  maCersThe  Back  bu*on  worksPlay’s  stateless  architecture  is  based  on  HTTP.  When  a  web  framework  starts  an  architecture  fight  with  the  web,  the  framework  loses.
  12. 12. 12Why  Play  maCers Back   The  Reload  bu*on  works bu*on During   development,   just   reload   the   page   to  see  changes  in  your  Java  (or  Scala)  code. That’s  high-­‐produc6vity  web  development.
  13. 13. 13Why  Play  maCers Back   You  design  the  URL Reload   bu*on bu*on You  can  use  ‘clean’  URLs: /products /product/42 /product/42/comments
  14. 14. 14Why  Play  maCers Back   Usability  (DX) URL Reload   bu*on bu*on Convenient  HTTP  API   and  template  syntax Clear  error  messages   and  short  stack  traces
  15. 15. 15“ What’s  the  story  behind  the  heart  icon?“ There  isn’t  one. Feel  free  to  make  one  up  :) Guillaume  Bort
  16. 16. 16“ Play  doesn’t  fight  web  architecture Stateless,  HTTP-­‐centric  architecture…
  17. 17. 18Stateless  architecture■ No state in the application’s web tier ■ e.g. Java Servlet API’s HTTP session (which isn’t actually part of HTTP)■ State belongs in other tiers ■ HTTP client, server cache or database■ Web application behaviour defined by URLs (requests)■ Exception for identifying authenticated user by cookie
  18. 18. 19Stateless  architecture  -­‐  why■ Simplifies application development and testing ■ (a URL is all you need for reproducability)■ Matches the web’s stateless HTTP architecture■ Avoids synchronising state between additional layers ■ (‘synchronisation’ should ring tech design alarm bells)■ Enables cloud deployment and horizontal scalability ■ (search the web for “Play framework Heroku”)
  19. 19.
  20. 20. 21“ Dear  Java  devs,  PHP  and  Rails  devs   have  been  laughing  at  you  for  years …  every  6me  they  reload  a  page’s  code  changes
  21. 21. 22Code  reloading■ During development, reload the page to see changes in: ■ Java and Scala classes ■ configuration files ■ templates.■ Play pre-compiles classes and templates for better performance in production mode■ This just works out-of-the-box
  22. 22. 23“ URLs  want  to  be  loved  too REST  architecture  isn’t  just  for  web  service  APIs
  23. 23. 24h  t  t  p  :  /    a  p  p  .  e    a  m  p  l  e  .  c  o  m  /  W    r    o  o  t  D    r     / x a R i ec  t  o  r    1  /    e      l  e    s      A    l  a    e    s    s  s    o  n  I  d  =  x  8   y S rv t On P n ? e i1  n  j  3  8  a  v    g    L  O  L  d  x  p  a    e  w  q  &  a  c  t  i  o  n  =  N  e  x  t   n j nP  a  g    &  H    n  e    B  a  d    e  r      r    s  =    a  l  s  e    e  n  t    t  y   e o y g Ca e f & iI  d    1  2  9  9  1  2  7  4  3  &  p  r  o  c  e  s  s  N    m  e  =    n  l  a  d  e  n   = a US  w  a  l  l  o  w  C  o  m  p  u  t  a  t  i  o  n  &  r  o  l  e  =  p  e  o  n  &  d  a  t  e  =  1  4  %  2  F    2  %  2  F  2  0  1  2  &  f  l    g    e    t  i  n  g    =  0  1  0   0 a S t s1  0  1  1  &  r  e  t  u  r  n  =  %  2  F  v  i  d  e  o  s  %  2  F  r  i  c  k  r  o  l  l  .  a  v  i
  24. 24. h&p://
  25. 25. 26URL  design  (HTTP  rouMng)■ Clean URLs are stable URLs: ■ ■■ Read it, bookmark it, mail it, tweet it■ URL-centric design: ■ Design the URL scheme before you start coding ■ Configure your application’s URLs in one file
  26. 26. 27URL  design  (HTTP  rouMng)■ Designed URLs are clean URLs: ■ ■■ Corresponding Play routing configuration: #  HTTP  routes  configuration  file #  method,  URL  path,  controller  action  method  (and  params) GET    /products            controllers.Products.list() GET    /product/:id      controllers.Products.details(id:Long)
  27. 27. 28#  HTTP  routes  configuraMon  fileGET        /                            controllers.Application.index()GET        /products            controllers.Products.list()POST      /products            controllers.Products.add(p:  Product)GET        /product/:id      controllers.Products.details(id:  Long)DELETE  /product/:id      controllers.Products.delete(id:  Long)GET  /products.json        controllers.Products.listJSON()GET  /product/:id.json  controllers.Products.detailsJSON(id:Long)
  28. 28. 29“ You  have  to  be  a  genius  to  successfully   use  some  web  frameworks For  the  rest  of  us,  there  are  good  error  messages
  29. 29. 30
  30. 30. 31Where’s  the  actual  error  message?13:07:55,796  ERROR  [[PersonServlet]]  Servlet.service()  for  servlet  PersonServlet  threw  exceptionjavax.ejb.EJBException:  null;  CausedByException  is:   null   at  org.jboss.ejb3.tx.Ejb3TxPolicy.handleExceptionInOurTx(   at  org.jboss.aspects.tx.TxPolicy.invokeInOurTx(   at  org.jboss.aspects.tx.TxInterceptor$Required.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.aspects.tx.TxPropagationInterceptor.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.ejb3.ENCPropagationInterceptor.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(   at  org.jboss.aop.Dispatcher.invoke(   at  org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.ejb3.stateless.StatelessRemoteProxy.invoke(   at  $Proxy76.getAllPeople(Unknown  Source)   at   at   at   at  javax.servlet.http.HttpServlet.service(   at  javax.servlet.http.HttpServlet.service(   at  org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(   at  org.apache.catalina.core.ApplicationFilterChain.doFilter(   at  org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(   at  org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(   at  org.apache.catalina.core.ApplicationFilterChain.doFilter(   at  org.apache.catalina.core.StandardWrapperValve.invoke(   at  org.apache.catalina.core.StandardContextValve.invoke(   at   at   at   at  org.apache.catalina.core.StandardHostValve.invoke(   at  org.apache.catalina.valves.ErrorReportValve.invoke(   at  org.apache.catalina.core.StandardEngineValve.invoke(   at  org.apache.catalina.connector.CoyoteAdapter.service(   at  org.apache.coyote.http11.Http11Processor.process(
  31. 31.   at  org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(   at   at 32   at   java.lang.NullPointerException   at   at  sun.reflect.NativeMethodAccessorImpl.invoke0(Native  Method)   at  sun.reflect.NativeMethodAccessorImpl.invoke(   at  sun.reflect.DelegatingMethodAccessorImpl.invoke(   at  java.lang.reflect.Method.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.ejb3.AllowedOperationsInterceptor.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.aspects.tx.TxPolicy.invokeInOurTx(   at  org.jboss.aspects.tx.TxInterceptor$Required.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.aspects.tx.TxPropagationInterceptor.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.ejb3.ENCPropagationInterceptor.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(   at  org.jboss.aop.Dispatcher.invoke(   at  org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(   at  org.jboss.aop.joinpoint.MethodInvocation.invokeNext(   at  org.jboss.ejb3.stateless.StatelessRemoteProxy.invoke(   at  $Proxy76.getAllPeople(Unknown  Source)   at   at   at   at  javax.servlet.http.HttpServlet.service(   at  javax.servlet.http.HttpServlet.service(   at  org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(   at  org.apache.catalina.core.ApplicationFilterChain.doFilter(   at  org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(   at  org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(   at  org.apache.catalina.core.ApplicationFilterChain.doFilter(   at  org.apache.catalina.core.StandardWrapperValve.invoke(   at  org.apache.catalina.core.StandardContextValve.invoke(   at   at   at   at  org.apache.catalina.core.StandardHostValve.invoke(   at  org.apache.catalina.valves.ErrorReportValve.invoke(   at  org.apache.catalina.core.StandardEngineValve.invoke(   at  org.apache.catalina.connector.CoyoteAdapter.service(
  32. 32. http://localhost/ 33Parse error: syntax error, unexpected T_VARIABLEin /usr/local/www/htdocs/index.php on line 3
  33. 33. 35“ Play  2  con6nues  the  innova6on First-­‐class  support  for  both  Java  and  Scala Type-­‐safe  templates Compile-­‐6me  checking Asynchronous  HTTP  programming
  34. 34. h&p://
  35. 35. 37Play  in  Java  and  Scala■ Play 2.0 provides parallel APIs for Java and Scala, for example, a controller action: //  Java  controller  action  method public  static  Result  index(String  name)  {    return  ok("Hello"  +  name); } //  Scala  controller  action  method def  hello(name:  String)  =  Action  {    Ok("Hello  "  +  name) }
  36. 36. 38Play  2.0  Scala  implementaMon■ Play 2.0 is itself implemented in Scala■ Scala removes the need for so much bytecode enhancement in the Java API (which is how Play 1.x works) ■ There is less ‘magic’ and strangeness in the API ■ The code you see in the IDE is the code that runs■ Scala source code not necessarily harder to read
  37. 37. 39“ Templates  want  to  be  beau6ful  too Type  safe  template  parameter  delcara6ons Minimal  interference  with  HTML  mark-­‐up
  38. 38. 40Type-­‐safe  template  parameters■ Templates include type-safe parameter declarations■ Similar to the lightweight template syntax in Play 1.x■ Templates are compiled into class files for run-time speed @(products:  List[Product]) <ul>   @for(product  <-­‐  products)  {    <li  class="@product.type"></li> }   </ul>
  39. 39. 41Template  funcMons■ Play 2.0’s template system is based on Scala■ A template is a Scala function that you call from your code //  Render  the  ‘Products.list’  template  in  Java  code. Html  html  =  views.html.Products.list.render(products); //  e.g.  as  the  result  of  a  controller  action  method. public  static  Result  list()  {    final  List<Product>  products  =  Products.list();    return  ok(views.html.Products.list.render(products)); }
  40. 40. Template syntax starts with @ 42 Template parameter declaration@(products:  List[Product])@if(products.isEmpty)  {    <h1>No  products</h1>} No delimiter for the end of a template syntax section
  41. 41. 43@(products:  List[Product])@if(products.isEmpty)  {    <h1>No  products</h1>}  else  {    <h1>@items.size  products</h1>} Output the value of an expression
  42. 42. 44 Define a ‘tag’ - output a details page link@display(product:  models.Product)  =  {    <a  href="@routes.Products.details(">    </a>}<ul>@for(product  <-­‐  products)  {    @display(product)}  </ul> Use the ‘display’ tag
  43. 43. 45<section  class="content">    …</section>@footer() Include the ‘footer’ template (i.e. call the ‘footer’ function)
  44. 44. main.scala.html 46@(title:  String)(content:  Html)<!DOCTYPE  html><html> Two parameter lists    <head> (one parameter each)        <title>@title</title>    </head>    <body>        @content    </body> Define a page layout</html> template called ‘main’ index.scala.html@main("Home  page")  { Render the ‘main’ template,    <h1>Welcome</h1> passing two parameters}
  45. 45. 47“ Dear  PHP  and  Rails  developers,   run6me  errors  make  you  look  bad Using  unit  tests  to  find  syntax  errors  is  a  hack There  is  a  solu6on…
  46. 46. 48
  47. 47. 49Compile-­‐Mme  checking■ Not just Java and Scala classes ■ HTTP routes file (maps URLs to controller actions) ■ Templates ■ JavaScript files (using Google Closure Compiler) ■ CoffeeScript files (alternative to JavaScript) ■ LESS style sheets (alternative to CSS)■ Fewer errors at run-time
  48. 48. controllers/ 50public  class  Products  extends  Controller  {    public  static  Result  details(final  Long  id)  {        return  ok();    }} conf/routesGET  /product/:id      controllers.Products.details(id:  String)
  49. 49. controllers/ 50public  class  Products  extends  Controller  {    public  static  Result  details(final  Long  id)  {        return  ok();    }} Incompatible types conf/routesGET  /product/:id      controllers.Products.details(id:  String)
  50. 50. controllers/ 50public  class  Products  extends  Controller  {    public  static  Result  details(final  Long  id)  {        return  ok();    }} Incompatible types conf/routesGET  /product/:id      controllers.Products.details(id:  String)
  51. 51. h&p://
  52. 52. @rainbow:  -­‐webkit-­‐gradient(linear,  left  top,  left  bottom,    color-­‐stop(0.00,  red),    color-­‐stop(20%,  orange),    color-­‐stop(25%,  yellow),    color-­‐stop(30%,  yellow),    color-­‐stop(45%,  green),    color-­‐stop(65%,  blue),    color-­‐stop(80%,  indigo),    color-­‐stop(1.00,  violet));
  53. 53. 57“ Use  HTML5  technologies Choose  a  web  framework  that  lets  you Hire  or  become  a  front-­‐end  expert Use  HTML  ‘bricks’  instead  of  moulded  components
  54. 54. 59
  55. 55. 60Modern  web  development■ Play is designed to work with HTML5 technologies■ No constraints on HTML output (front-end dev-friendly)■ UI components belong in the client, e.g. JQuery UI■ Built-in support for improvements to CSS and JavaScript: ■ LESS ■ CoffeeScript ■ Closure Compiler
  56. 56. 61Single-­‐page  JavaScript  applicaMons■ Server-side HTML templates are not the only game in town■ JavaScript and mobile apps need web services■ Play is great for building web services ■ You’ve already seen HTTP routing ■ Play has a type safe API for parsing/generating JSON ■ Play application architecture is natural fit for REST ■ Functionality is not tied to view templates
  57. 57. 62GeneraMng  a  JSON  response$  curl  -­‐i  http://localhost:9000/products/5010255079763HTTP/1.1  200  OKContent-­‐Type:  application/json;  charset=utf-­‐8Content-­‐Length:  88{    "ean":5010255079763,    "name":"Paperclips  Large",    "description":"Large  Plain  Pack  of  1000"}
  58. 58. 63GeneraMng  a  JSON  response//  Value  objectcase  class  Product(ean:  Long,  name:  String,      description:  String)//  JSON  formatterimplicit  object  ProductWrites  extends  Writes[Product]  {        def  writes(p:  Product)  =  Json.toJson(        Map(            "ean"  -­‐>  Json.toJson(p.ean),            "name"  -­‐>  Json.toJson(,            "description"  -­‐>  Json.toJson(p.description)        )    )}//  Controller  responseOk(Json.toJson(product))
  59. 59. 64Parsing  a  JSON  requestimplicit  object  ProductReads  extends  Reads[Product]  {    def  reads(json:  JsValue)  =  Product(        (json    "ean").as[Long],        (json    "name").as[String],        (json    "description").as[String]    )}//  Controller  method  -­‐  using  the  parse.json  body  parserdef  save(ean:  Long)  =  Action(parse.json)  {  request  =>    val  productJson  =  request.body    val  product  =[Product]    //  …}
  60. 60. h&p://
  61. 61. 66Asynchronous  HTTP  programming  model■ The future of web programming is asynchronous: ■ Perform simultaneous web service requests ■ Process streams, instead of filling up memory or disk ■ Publish real-time data ■ Predictable and minimal resource consumption■ Play’s internal architecture uses a reactive model based on Iteratee IO (read about ‘Iteratees’ in the Play 2.0 docs)
  62. 62. 67Other  Play  2.0  features■ Asynchronous web programming■ Build environment based on sbt ■ Scala REPL (irb eat your heart out)■ Designed for easy cloud deployment, e.g. Heroku■ Persistence - use your favourite framework ■ Ebean (Java) or Anorm (Scala) included with Play■ Test framework integration
  63. 63. $  play  [info]  Loading  project  definition  from  /demo/project[info]  Set  current  project  to  demo  (in  build  file:/Users/pedro/Documents/code/examples-­‐play/demo/)              _                        _    _  __  |  |  __  _  _    _|  ||  _  |  |/  _  |  ||  |_||    __/|_|____|__  (_)|_|                        |__/                            play!  2.0.1,>  Type  "help"  or  "license"  for  more  information.>  Type  "exit"  or  use  Ctrl+D  to  leave  this  console.[demo-­‐app]  $
  64. 64. [jfokus-­‐app]  $  console[info]  Starting  scala  interpreter...[info]  Welcome  to  Scala  version  (Java  HotSpot(TM)  64-­‐Bit  Server  VM,  Java  1.6.0_31).Type  in  expressions  to  have  them  evaluated.Type  :help  for  more  information.scala>
  65. 65. scala>  views.html.rainbow.renderres0:  play.api.templates.Html  =  <!DOCTYPE  html><html>    <head>        <title>rainbow</title>        <link  rel="stylesheet"  type="text/css"  href="/assets/colours.css">    </head>    <body>            <div  class="nyan">    <div  class="trail"></div>    <div  class="cat">insert  meme</div>    </div>    </body></html>
  66. 66. 71Play  2  books■ Play 2 for Scala, Peter Hilton, Erik Bakker, Francisco Canedo■ Play 2 for Java, Nicolas Leroux, Sietse de Kaper■ Early Access (MEAP) editions now available
  67. 67. @PeterHilton