Play! Framework for JavaEE Developers
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Play! Framework for JavaEE Developers

on

  • 18,594 views

Play! Framework for JavaEE Developers

Play! Framework for JavaEE Developers
Presented in JavaTWO Taiwan @ Jul 29,2011

Statistics

Views

Total Views
18,594
Views on SlideShare
18,427
Embed Views
167

Actions

Likes
30
Downloads
552
Comments
2

8 Embeds 167

https://dia.log.pt 55
http://www.scoop.it 39
http://www.linkedin.com 36
https://twitter.com 23
http://tweetedtimes.com 6
http://twitter.com 5
https://si0.twimg.com 2
http://www.slashdocs.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • Hello Smallufo,

    Can you please help me how to use 2 databases in a single play application.
    I am using MYSQL and POSTGRESQL

    Thanks in advance.
    Are you sure you want to
    Your message goes here
    Processing…
  • examples do not work
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Play! Framework for JavaEE Developers Presentation Transcript

  • 1. JavaTWO專業技術大會
  • 2. Play!Framework for JavaEE Developers
  • 3. Who am I
    Exp : JSP/Servlet , Tapestry , Spring/Hibernate/JavaEE , Wicket , Android , Grails , Play! Framework
    http://gplus.to/smallufo
    http://twitter.com/smallufo
    smallufo@gmail.com
  • 4. Web Framework Experiences
    • JSP/Servlet
    • 5. Too old , cumbersome
    • 6.  Tapestry (old experience, T5 is very good)
    • 7. Complicated , evolution/deprecation too fast
    • 8.  Wicket
    • 9. Too elaborate , fail to see the wood for the trees
    • 10. May lead to over-engineered architecture for OO-purism
    • 11. Spend too much time refactoring
    • 12. Maybe web component reuse is just a myth
    • 13. Grails (old experience, without Groovy++)
    • 14. Slow
    • 15. Too many inconsistent DSLs (URL-mapping , DB , logging...)
    • 16. Not Java , IDE unfriendly
  • Conventional JavaEE Stack
  • 17. Conventional JavaEE Stack
    • Want standard page ?
    • 18. Let's define JSP/JSTL (JSR-53)
    • 19. And let Apache (or others) to implement Jakata Taglibs
    • 20.  Want web components ?
    • 21. Let's define Java Server Faces (JSR-127)
    • 22. And let communities to implement MyFaces, PrimeFaces, ICEfaces...
    • 23. Want restful ?
    • 24. Let's define JAX-RS (JSR-311)
    • 25. And let communities to implement CXF, Jersey, RESTEasy, Wink...
  • Conventional JavaEE Stack
    • Lots of ...
    • 26. Specs
    • 27. Implementations
    • 28. Configurations
    • 29. Tedious , Error-prone
    • 30. Unless you use a full-fledged JavaEE Server (Glassfish or WebLogic ...)
    • 31. Layered
    • 32. Defined by Standards/Specs
    • 33. Assembled by Interfaces
    OVER ARCHITECTED
  • 34.
  • 35. Play’s App Looks Like ?
    conf/routes
    app/App.java
    GET /hello App.hello
    public class App extends Controller {
    public static void hello() {
    User user = User.findById(1L);
    render(user);
    }
    }
    views/App/hello.html
    Hello World : ${user.name}
    http://localhost:9000/hello
  • 36. And Play is ...
    • A full stack framework (platform)
    • 37. Totally independent of JavaEE environment
    • 38. RESTful
    • 39. No session
    • 40. Stateless
    • 41. Pure server side
    • 42. Similar to Rails / Django
    • 43. Rich domain model
    • 44. Unlike JavaEE's anemic domain model
  • Full Stack Framework?
    • Bundles compiler , embedded server , hibernate , logger , test runner , email , groovy template engine, scala...
    • 45. Can be packaged as a WAR and deployed to servlet containers
  • Play! A Glued Pure Web Framework
    Shallow!
    Most libs are directly 
    exposed to Play! & replaceable
    Where Magic Happens
  • 46. Play! URLs are RESTful & SEO-friendly
    UGLY
    GRACEFUL
    • /car/1
    • 47. /listcar/page1/count10
    • 48. /listcar/page1?count=10
    • 49. /listcar/page/1/count/10
    • 50. /car.jsp?id=1
    • 51. /listcars.jsp?page=1&count=10
    • 52. http://www.facebook.com/ photo.php? fbid=2121715487568& set=o.172881386106136& type=1&theater
  • Play is not based on Servlet
    Many java server side frameworks (Spring MVC / Struts / Wicket / JSF / Tapestry ...) are based on servlets, but Play! is not!
    You cannot do such things :
    • session.setAttribute("user" , user); 
    • 53. Use HttpSessionListener to count sessions (online users)
    • 54. ServletFilter
    • 55. Servlet-related securities
    • 56.  @ServletSecurity
    • 57.  <auth-constraint /> , <security-role />
  • Play! is Stateless
    • Play! shares nothing between each request!
    • 58. The most important feature you have to keep in mind
    • 59. No session!
    • 60. Session is the source of all problems of the JavaEE platform!
    • 61. Session replication 
    • 62. Sticky session
    • 63. Play uses (delegates to) memcached to eliminates such headaches
  • Play's Informative Error Page
  • 64. Play's Domain Objects Are Rich
    Play
    *Spring promoted JavaEE
    User extends Model
    User extends Object
    UserDao.java
    • save(User u)
    User u = new User(...)
    u.save()
    UserDaoImpl implements UserDao
    • void setEntityManager(...)
    • 65. save(User u)
    Client.java
    @Inject UserDao userDao
    User u = new User(...)
    userDao.save(u)
    VS
    *JPA advocates eliminating the DAO layer
  • 66. Play's Architecture
    $ play new myproj
    myproj
    app
    controllers
    models
    conf
    application.conf
    views
    messages
    lib
    foo
    routes
    modules
    bar
    public
    images
    javascripts
    src
    stylesheets
  • 67. conf/application.conf
    application.name=myapp
    application.mode=dev
    application.secret=OOXXOOXXOOXXOOXXOOXX
    http.port=9000
    java.source=1.6
    db.url=jdbc:mysql:...
    db.driver=com.mysql.jdbc.Driver
    db.user=user
    db.pass=pass
    hibernate.use_sql_comments=true
    hibernate.format_sql = true
    XForwardedSupport=127.0.0.1
  • 68. Play's Architecture
    controllers
    app
    MyController.java
    public static void index()
    public static void show()
    models
    views
    MyController
    index.html
    foo
    show.html
    bar
  • 69. conf/routes
    HTTP method
    URI Pattern
    Action
    GET    /                      App.index
    POST   /login                 App.login
    GET    /tag/{name}            App.tag(name)
    GET    /list/{page}           App.list(page)
    GET    /list/{<[0-9]+>page}   App.list(page)
    GET    /list/{page}/{count}   App.list(page,count)
    GET    /public/               staticDir:public
    *      /{controller}/{action} {controller}.{action}
  • 70. Play's Request Life Cycle
  • 71. Controllers and Redirections
    public class App extends play.mvc.Controller {
      public static void index() {
        render(); // views/App/index.html contains a login form
      }
      public static void login(String name,String passwd) {
        if(...) // success
          welcome();
        else   // failed
          index();
      }
      public static void welcome() {
        render();  // renders views/App/welcome.html 
      }
    }
  • 72. Controller Interceptions
    public class App extends play.mvc.Controller {
      @play.mvc.Before(unless={“index”, “login”})
      public static void intercept() {
        if (session.get("uid")==null) 
          index();
      }
      public static void index() {...}
      public static void login(String name,Stringpasswd){..}
      public static void welcome() {...}
    }
  • 73. Session : A Signed Cookie
    public static void login(String name , String passwd) {
      User u = ...
      if (...) {
        session.put("uid" , u.id);
      }
    }
    Only put index data to session
    Never store sensitive data
    signed, 
    uneditable!
  • 74. Controller Revisited
    public static void show(Long uid, String type) {
      User u = ...
      if (type.equals("json") {
        renderJSON(u);   // provided by GSON
      } 
      else if (type.equals("xml") {
        renderXml(u);    // provided by XStream
      } 
      
      render(u);  
    }
    Why not continue rendering?
    play.mvc.Controller
    throw new RenderJson(jsonString);
    throw new RenderXml(xml);
    throw new RenderTemplate(...);
  • 75. Controller and View
    controllers/App.java
    public static void showUser(Long uid) {
      User u = ...
      List<Car> cars = ...
      renderArgs.put("user",u);
      render(cars, company, job, ...);  
    }
    public static void showCar(Long id) {...}
    renderArgs.put(“cars”,car);
    renderArgs.put(“company”,company);
    renderArgs.put(“job”,job);
    same
    views/App/showUser.html
    Hello ${user.name} , these are your cars :
    #{list items:cars , as:'car'}
      #{a @showCar(car.id)} ${car.name} #{/a}
    #{/list}
    template tag
    @App.showCar(car.id)
  • 76. How objects are passed to View !?
    controllers/App.java
    public static void showUser(Long uid) {
      renderArgs.put("user",u);
      render(cars , ...);  
    }
    !!??
    views/App/showUser.html
    ${user.name}
    #{list items:cars , as:'car'}
    Let's decompile it...
  • 77. public static void showUser(Long uid)
    {
      play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.enter();
      play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.addVariable("uid", uid);
      if(!play.classloading.enhancers.ControllersEnhancer.ControllerInstrumentation.isActionCallAllowed())
      {
        Controller.redirect("controllers.App.showUser", new Object[] {
          uid
        });
      } else
      {
        play.classloading.enhancers.ControllersEnhancer.ControllerInstrumentation.stopActionCall();
        User u = (User)User.findById(uid);
        play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.addVariable("u", u);
        List cars = Car.all().fetch();
        play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.addVariable("cars", cars);
        Object obj = null;
        play.mvc.Scope.RenderArgs renderargs = null;
        renderargs = (play.mvc.Scope.RenderArgs)Java.invokeStatic(Desc.getType("Lplay/mvc/Scope$RenderArgs;"), "current");
        renderargs.put("user", u);
        render(new Object[] {
          cars
        });
      }
      break MISSING_BLOCK_LABEL_120;
      Exception exception;
      exception;
      Object obj1 = null;
      play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.exit();
      throw exception;
      Object obj2 = null;
      play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer.exit();
      return;
    }
  • 78. Who Modifies My Code !?
    Who ?
    • Play's custom classloader & JDT & javassist
    When ?
    • DEV mode : When you modify the code and reload the page
    • 79. PROD mode : App's start time
    How ?
    • At compile time , some classes are enhanced by play.classloading.enhancers.* (powered by javassist)
    • 80. ContinuationEnhancer
    • 81. ControllerEnhancer
    • 82. PropertiesEnhancer
    • 83. LocalvariablesNamesEnhancer, ...
    Impact ?
    • Rapid development time !
  • View Template
    object path
    ${objectname}
    ${object.property}
    implicit objects
    ${params.userId}
    ${session.userId}
    ${request.userId}
    built-in tags
    #{if} ... #{/if} #{else}... #{/else}
    #{list items:users , as:'user'}
      ${user.name}
    #{/list}
    #{a @App.showUser(user.id)} show user #{/a}
    #{form @App.login() } ... #{/form}
  • 84. Rich Domain Object Model
    package models;
    @javax.persistence.Entity
    public class User extends play.db.jpa.Model {
      public String username;
      public String password;
    }
    Support JPA's annotations : @Column , @ManyToOne , @OneToMany ...
    NO more getters & setters... Great !
  • 85. Rich Domain Object Model
    BUT...
    The underlayer is hibernate & hibernate needs getter/setter
    Again...
    Who modifies my model ?
  • 86. Rich Domain Object Model
    In Fact...
        Your model still contains getter/setter , modified by Play's custom classloader & JDT & javassist
    User.java
    public String getUsername() {
      return "overridden";
    }
    ${user.username} will be ??
  • 87. Rich Domain Object
    User u = User.findById(1);
    User u = User.find("byUsernameAndPassword", username , password).first();
    User u = User.find("select u from User u where u.username = :username and u.password = :password")
      .bind("username",username)
      .bind("password",password)
      .first();
    List<User> users = User.all().fetch();
    User.em().createQuery(...);
  • 88. Validations : Controller
    #{form @App.login()}
    <p>
    username
    <input type=“text” name=“username” value=“${flash.username}” />
    <span class=“error”>#{error 'username'/}</span>
    </p>
    <p>
    password
    <input type=“password” name=“password” value=“${flash.password}” />
    <span class=“error”>#{error 'password'/}</span>
    </p>
    <input type="submit" value=“Login" />
    <span class=“error”>#{error ‘other'/}</span>
    #{/form}
    username
    請輸入帳號
    password
    請輸入密碼
    Login
    帳號或密碼輸入錯誤
  • 89. Validations : Controller
    public static void login(
    @Required(message ="請輸入帳號")String username,
    @Required(message ="請輸入密碼")String password) {
    User user = User.login(username , password);
    if (validation.hasErrors()){
    params.flash(); // add parameters to flash scope
    validation.keep(); // keeps the errors
    flash.error(validation.errors().get(0).toString());
    render(“pleaseLogin.html”);
    }
    flash.success(“welcome : “ + user.username);
    render();
    }
  • 90. Validation : Model
    public class User extends Model {
    @Required @MinSize(6)
    public username;
    @Required @MinSize(6)
    public password;
    public static User login(String username , String password) {
    Validation validation = Validation.current();
    User user = ...
    validation.isTrue(user!=null)
    .key(“other”).message(“帳號或密碼輸入錯誤”);
    return user;
    }}
    Will @MinSize affect login() ?
  • 91. Validations
    @Required , @Min , @Max , @MinSize , @MaxSize , @Range , @Email , @URL ...
    Custom validation annotation
    extends AbstractAnnotationCheck & implements isSatisfied()
    i18n messages
    /conf/messages
  • 92. Cache
    Conventional JavaEE's Way
    public User getUser(String name) {
      Session s = (Session)em.getDelegate();
      Criteria c = s.createCriteria(User.class);
      c.add(Restrictions.eq("username",name);
      c.setMaxResults(1);
      c.setCacheable(true);
      if (c.uniqueResult() == null)
        return null;
      return (User) c.uniqueResult();
    }
  • 93. Cache
    Play's Way : Not In Favor of 2nd Level
    public static User getUser(String name) {
      String key="username_"+name;
      User user = Cache.get(key,User.class);
      if (user != null)
        return user;
      user = User.find("byUsername",name).first();
      Cache.set(key,user,"30mn");
      return user;
    }
  • 94. Cache - Problem !
    User.java {
      public static User getUser(Long id) {
        String key = "userId_"+id;
        ...
      }
      public static List<User> getUsers(Long page, int cnt) {
        String key="users_"+page+"_"+cnt;
        ...
      }
    }
    public interface UserDao.java {
    public User getUser(Long id);
    public List<User> getUsers(Long page, int cnt);
    }
  • 95. Conventional JavaEE's Way
    User u1 = userDao.getUsers(1,10).get(0);
    User u2 = userDao.get(1L);
    assertTrue(u1.equals(u2)); // PASSED
    u2.modifySomething(...);
    userDao.save(u2);
    User u3 = userDao.getUsers(1,10).get(0);
    assertTrue(u3.equals(u2)); // PASSED
    Play's Way
    User u1 = User.getUsers(1,10).get(0);
    User u2 = User.getUser(1L);
    assertTrue(u1.equals(u2)); // PASSED
    u2.modifySomething(...);
    u2.save();
    User u3 = User.getUsers(1,10).get(0);
    assertTrue(u3.equals(u2)); // FAILED!
  • 96. Cache Problem : Reason
    users_1_10
    cache key :
    TIME
    u
    u
    u
    u
    u
    u
    u
    u
    u
    u
    u1
    userId_1
    cache key :
    u
    modified / updated
    u2
    users_1_10
    cache key :
    ?
    u
    u
    u
    u
    u
    u
    u
    u
    u
    u3
  • 97. Cache - Problem! How to Solve It ?
    • Ignore it , accept it
    • 98. Never cache sensitive data
    • 99. Two phase list retrieval
    • 100. Cache object ids instead of objects
    public static List<User> getUsers(Long page, int cnt) {
      String key="users_"+page+"_"+cnt;  
      List<Long> userIds = 
        User.find("select u.id from User u)
        .fetch(page,cnt);
      Cache.set(key, userIds, "1mn");
      // iterate each id in result and query cache or fetch
    }
  • 101. Cache : Wait... I saw Model.em() ?
    How about get underlaying Hibernate’s session and setCacheable(true) ?
    Session s = (Session) User.em().getDelegate();
    Critieria c = s.createCriteria(...);
    c.add(... criterions ... );
    c.setCacheable(true);
  • 102. Play's Module System
  • 103. Module : CRUD
    package models;
    public class User extends Model { ... }
    package controllers;
    public class Users extends CRUD { ... }
    Cars , Photos , Logs
    even ...
    Boxs , Buss, Kisss
  • 104. Module GAE + Module Siena
    public class User extends siena.Model { 
      public String uid;
      public static User getUser(String uid) {
        return User.all(User.class).filter("uid",uid).get();
      }
      public static User getUsers(int page , int count) {
        return User
          .all(User.class)
          .fetch(count,(page-1)*count);
      }
    }
    Don't forget war/WEB-INF/appengine-web.xml
    $ play gae:deploy 
    Done !
  • 105. Play on GAE
    • Simplest way to deploy Java Apps on GAE !
    • 106. Shortest cold start time
    • 107. Less than 10 seconds
    • 108. Cache is wrapped to GAE's memcache
    • 109. Mail is wrapped to GAE's mail service
  • Issue : Portal-like Page
    • Many blocks query DB in every page
    • 110. Passing these query results in every action is cumbersome
    • 111. Solution : @Before and renderArgs.put()
    @Before
    static void addDefaults() {
      renderArgs.put("brands", Brand.all().fetch());
      renderArgs.put("forums", Forum.getAll()); 
      renderArgs.put("tags" , Tag.getAll());
    }
  • 112. Issue : High Availability
    <VirtualHost *:80>
     ServerName myapp.com
     <Location /balancer-manager>
      SetHandler balancer-manager
      Order Deny,Allow
      Deny from all
      Allow from .myapp.com
     </Location>
     <Proxy balancer://mycluster>
       BalancerMember http://localhost:9002
       BalancerMember http://localhost:9003 status=+H
     </Proxy>
     <Proxy *>
       Order Allow,Deny
       Allow From All
     </Proxy>
     ProxyPreserveHost on
     ProxyPass /balancer-manager !
     ProxyPass / balancer://mycluster/
     ProxyPassReverse / http://localhost:9002/
     ProxyPassReverse / http://localhost:9003/
    </VirtualHost>
    Apache Web Server
    localhost:9002
    localhost:9003
    Same directory structures & application.secret , only different http.port
  • 113. Issue : Action Burst
    controllers/App
    controllers/App
    login()
    logout()
    register()
    myaccount()
    mybooks()
    index()
    page()
    search()
    showbook()
    login()
    logout()
    register()
    myaccount()
    mybooks()
    index()
    page()
    search()
    showBook()
    listUsers()
    editUser()
    editBook()
    controllers/Admin
    listUsers()
    editUser()
    editBook()
  • 114. Issues : Validation Dilemma
    Validation in controllers ?
    validation in models ?
    or hybrid ?
  • 115. Issue : DI
    Dependency Injection is not so useful in Play’s Rich Domain Object environment
  • 116. Case Study : VAGTW.COM
    VW/Audi Car Problem Stats
  • 117. vagtw.com Data Model
  • 118. VAGTW.com development
    • Dev in one month (Since 2010/4/1)
    • 119. Modified from Play's YABE sample
    • 120. 10 days learning Play! & modeling & coding
    • 121. 20 days tuning HTML & CSS(3)
    • 122. 2010/5/1 Debut
    • 123. Peak 4x users in 15 mins
    • 124. Indexed by Google in 2 days
    • 125. Indexed by Yahoo in 2 weeks
    • 126. Indexed by Bing after 2 months
  • Conclusions
    IS ...
    • A Glued Pure Web Framework
    • 127. Loose
    • 128. Shallow
    • 129. non-Standardized
    • 130. Page-based
    • 131. Stateless
    IS-NOT ...
    • A Java library
    • 132. Full-Fledged JavaEE stack
    • 133. Standard
    • 134. Strict
    • 135. Defined-assembled by interfaces
    • 136. Component-based
    • 137. Stateful (Session-aware)
  • Conclusions : Use Play! If You...
    Have to prototype or build something quickly
    Don’t want to buy high-priced Java application servers
    Are not so OO-purism, feel OK without interfaces
    Many Play’s “hook” are not enforced by abctract mathods or interfaces
    Know JavaScript & other JS frameworks
    You can build slick UIs without sluggish server-state implementation responses (Wicket/JSF...)
    Feel OK about object inconsistences in cache
    Want to develop GAE apps
    Your team have a strong mendiator
    Because programming in play is too unrestrained
    Want to learn Scala
  • 138. 小心
    回不去了