SlideShare una empresa de Scribd logo
1 de 61
Descargar para leer sin conexión
Massimiliano Dessì
                                    &
                              Alberto Quario

                         Scala On Web
                         Play - Scalatra - Spray

                         Google Technology User Group Sardegna




                                                1
Thursday, March 28, 13                                           1
Speakers
                             Massimiliano Dessì & Alberto Quario                 GTUG Sardegna



                         Max has more than 13 years of experience in
                         programming. He’s a proud father of three.
                         Manager of GTUG Sardegna, Founder of
                         SpringFramework IT, co-founder of Jug Sardegna.
                         Author of Spring 2.5 AOP. He works in Energeya and
                         lives in Cagliari, Italy.




                         Alberto has more than 15 years experience in
                         developing software, he wrote his first programs on a
                         TI-99/4A and hasn't stopped since. Other than
                         languages and development, Alberto's passions
                         include squash, cooking and Monet paintings. He
                         lives and works in Milano, Italy.




                                                      2
Thursday, March 28, 13                                                                           2
Agenda
                         Massimiliano Dessì & Alberto Quario    GTUG Sardegna


                               Scalatra -Playframework -Spray

                                               REST

                                               JSON

                                             Routing

                                             Template

                                              Actors

                                             Sessions

                                              Deploy

                                          Hot Reloading

                                                Test


                                                  3
Thursday, March 28, 13                                                          3
Massimiliano Dessì & Alberto Quario   GTUG Sardegna



                                     Scalatra
                           is a web microframework
                                 written in Scala
                               inspired to Sinatra
                         a Ruby DSL to build webapp
                            http://www.scalatra.org

                               the BBC, LinkedIn,
                                  the Guardian,
                               games website IGN,
                                 UK government
                                 rely on Scalatra.

                                                  4
Thursday, March 28, 13                                                         4
REST
                                 Massimiliano Dessì & Alberto Quario       GTUG Sardegna


   class JellyBeans extends ScalatraServlet {

        get("/jellybs/:id") { ... }

        post("/jellybs") { ... }

        put("/jellybs/:id") { ... }

        delete("/jellybs/:id") { ... }

   }

   For browser add PUT & DELETE support client side
   X-HTTP-METHOD-OVERRIDE or _method=put _method=delete in the post body




   class JellyBeansBrowser extends ScalatraFilter with MethodOverride




                                                           5
Thursday, March 28, 13                                                                     5
Routes
                                   Massimiliano Dessì & Alberto Quario        GTUG Sardegna



    class JellyBeans extends ScalatraServlet {

        get("/jellybs/:id") {

                         val id:Int = params.getOrElse("id", halt(400)).toInt
                         ...
        }

        get("/jellybs/download/*.*") {                      //with wildcard
           ...
         }

        get("""^/j(.*)/f(.*)""".or) {                      //REGEX
           ...
         }

        post("/jellybs", request.getRemoteHost == "127.0.0.1",
           request.getRemoteUser == "admin") {
           ....
        }


                                                            6
Thursday, March 28, 13                                                                        6
Filter
                           Massimiliano Dessì & Alberto Quario                    GTUG Sardegna




      class JellyBeans extends ScalatraServlet {

           before() {
              db.acquireConnecion
              contentType="text/html"                                  Like Servlet Filter
          }                                                      (or Aspect Oriented Programming)
                                                                 You can add logic before or the
            get("/") {                                                        routes
               val menu = db.findWelcome()
               templateEngine.layout("index.ssp", menu)
            }

            after() {
               db.releaseConnection
            }
      }




                                                    7
Thursday, March 28, 13                                                                              7
Filter
                           Massimiliano Dessì & Alberto Quario   GTUG Sardegna




       class JellyBeans extends ScalatraServlet {

             before("""/api/v1/.*""".r) {
                 contentType = "application/json"
             }


             before("/admin/*") { auth }


             after("/admin/*") { user.logout }




       }



                                                    8
Thursday, March 28, 13                                                           8
Handlers
                              Massimiliano Dessì & Alberto Quario   GTUG Sardegna



     Handlers are top level methods for http routines


    class JellyBeans extends ScalatraServlet {


          notFound {
            <h1>Not found</h1>
          }

          halt(status = 301, headers =
                       Map("Location" -> "http://www.codemotion.com/"))


          get("/jellybs/names/*") {
            "Name not found!"
          }

    }



                                                        9
Thursday, March 28, 13                                                              9
Handlers
                         Massimiliano Dessì & Alberto Quario     GTUG Sardegna




 class JellyBeans extends ScalatraServlet {

       get("/jellybs/names/:who") {
         params("who") match {
           case "Cherry" => "Found Cherry!"
           case _ => pass() /* call the next matching route route, routes are
       matched from bottom up*/
         }
       }

     get("/jellybs/download/:id") {
            jellyBeanService.find(params("id")) match {
               case Some(jellybean) => Ok(jellybean)
               case None => NotFound("Sorry, jellybean not found")
           }
     }

 }


                                                 10
Thursday, March 28, 13                                                           10
Request Response & Friends
                              Massimiliano Dessì & Alberto Quario      GTUG Sardegna




          class JellyBeans extends ScalatraServlet {

                  get("/jellybs/shows/:id") {
                     //access to request,response, session and params
                     request.body                  //request body as a string
                     request.cookies               // cookie map
                     request.isAjax                // is ajaxRequest
                     request.getSession            // HttpServletSession
                     request.locale                // user locale
                     response.getOutputStream      //response outputstream
                     servletContext.get("myIntParam") //servlet context
                     val idString = params("id")
                     val id = params.getAs[Int]("id")
                  //val id = params.getOrElse("id", halt(500)) //another way
                     ....
                  }
          }




                                                      11
Thursday, March 28, 13                                                                 11
Request Response & Friends
                                  Massimiliano Dessì & Alberto Quario      GTUG Sardegna




                 class JellyBeans extends ScalatraServlet {


                         get("/jellybs/*/conf/*") {
                             // Matches "GET /jellybs/one/conf/two"
                             multiParams("splat") // Seq("one", "two")
                             //wildcard accessible with key splat
                          }

                         get("""^/jelly(.*)/fla(.*)""".r) {
                           // Matches "GET /jellybs/flavor"
                           multiParams("captures") // == Seq("bs", "vor")
                         }


                 }



                                                          12
Thursday, March 28, 13                                                                     12
Binding
                            Massimiliano Dessì & Alberto Quario                   GTUG Sardegna



    To avoid manual binding from http and our Object Scalatra provide a binding module



           case class MyClass(id: Integer, name: String)


          post("/myroute") {
              val cmd = command[CreateMyClassCommand]
              ...
          }




                                                    13
Thursday, March 28, 13                                                                            13
Binding
                              Massimiliano Dessì & Alberto Quario               GTUG Sardegna




      Under the hood


      abstract class MyClassCommand[S](implicit mf: Manifest[S])
                                                 extends ModelCommand[S] with JsonCommand {
  
          implicit def todoStringValidators(b: FieldDescriptor[String]) =
                                                                new MyClassStringValidations(b)
     }



      class CreateMyClassCommand extends MyClassCommand[MyClass] {

           protected implicit val jsonFormats = DefaultFormats
           val name: Field[String] = asType[String]("name").notBlank.minLength(3)
      }




                                                      14
Thursday, March 28, 13                                                                            14
Binding
                            Massimiliano Dessì & Alberto Quario                GTUG Sardegna




          Under the hood


      class MyClassStringValidations(b: FieldDescriptor[String]) {
          def startsWithCap(message: String = "%s must start with a capital letter.") =
          b.validateWith(_ =>
                          _ flatMap {
                                      new PredicateValidator[String](
                                         b.name,
                                         """^[A-Z,0-9]""".r.findFirstIn(_).isDefined,
                                         message).validate(_)
                                      )
                                   }
                         )
        }




                                                    15
Thursday, March 28, 13                                                                         15
Gzip
                         Massimiliano Dessì & Alberto Quario   GTUG Sardegna




        class GzipJellyBeans extends ScalatraServlet with GZipSupport{
            get("/") {
             <html>
               <body>
                 <h1>This is
                    <a href="http://en.wikipedia.org/wiki/Sparta">
                      http/gzip
                    </a>!
                 </h1>
               </body>
             </html>
          }
        }




                                                 16
Thursday, March 28, 13                                                         16
Flash message
                            Massimiliano Dessì & Alberto Quario   GTUG Sardegna




      class FlashServlet extends ScalatraServlet with FlashMapSupport{

           post("/jellybs/create") {
             flash("notice") = "jellybean created successfully"
             redirect("/home")
           }

           get("/home") {
             ssp("/home")       //Scala Server Pages
           }




                                                    17
Thursday, March 28, 13                                                            17
JSON
                             Massimiliano Dessì & Alberto Quario   GTUG Sardegna




  Automatic Serialization and deserialization of any Case class


  object JSONServlet extends ScalatraServlet with JacksonJsonSupport{


      case class JellyBean(id: Int, name: String, flavor:String)


      protected implicit val jsonFormats: Formats = DefaultFormats


      before() {
          contentType = formats("json")
      }

      ....




                                                     18
Thursday, March 28, 13                                                             18
JSON
                              Massimiliano Dessì & Alberto Quario    GTUG Sardegna



     Automatic Serialization and deserialization of any Case class


   object JSONServlet extends ScalatraServlet with JacksonJsonSupport{

       ...

       get("/jellybs/all"){
         jellyBeanRepo.all           //from class to json
       }

       post("/jellybs/create") {
         val jb = parsedBody.extract[JellyBean] //from json to class
         ...
       }

   }




                                                      19
Thursday, March 28, 13                                                               19
Template
                         Massimiliano Dessì & Alberto Quario   GTUG Sardegna




                                         Html inline,
                                            Scalate
                                    Twirl (Play2 template)


                                           Scalate
                                            mean
                                   SSP (Scala Server Page)
                                           Scaml
                                         Mustache
                                            Jade




                                                 20
Thursday, March 28, 13                                                         20
Template
                         Massimiliano Dessì & Alberto Quario   GTUG Sardegna


 class ScalateServlet extends ScalatraServlet with ScalateSupport{

     get("/"jellybeans/ssp) {
       contentType="text/html"
       ssp("/index", "foo" -> "uno", "bar" -> "two")
       // the layout used it’s WEB-INF/layouts/default.ssp
     }

   get("/jellybeans/jade") {
     jade("/index", "layout" -> "", "foo" -> "one", "bar" -> "two")
     // render without a layout.
   }

   get("/jellybeans/direct") {
      templateEngine.layout("/jellybeans/index.ssp")
     //direct invoking of scalate
   }




                                                 21
Thursday, March 28, 13                                                         21
Template
                               Massimiliano Dessì & Alberto Quario    GTUG Sardegna


                         SSP

                         <%@ var body: String %>
                         <%@ var title: String = "Some Default Title" %>
                         <%@ var head: String = "" %>
                         <html>
                         <head>
                           <title>${title}</title>

                           <%-- page specific head goes here --%>
                           ${unescape(head)}
                         </head>
                         <body>
                           <p>layout header goes here...</p>

                           ${unescape(body)}

                           <p>layout footer goes here...</p>
                         </body>
                         </html>



                                                       22
Thursday, March 28, 13                                                                22
Template
                         Massimiliano Dessì & Alberto Quario   GTUG Sardegna

                         JADE

                         !!! 5
                         html(lang="en")
                           head
                             title= pageTitle
                             :javascript
                                if (foo) {
                                   bar()
                                }
                           body
                             h1 Jade - node template engine
                             #container
                                - if (youAreUsingJade)
                                  p You are amazing
                                - else
                                  p Get on it!
                             :coffeescript
                                alert "Hello, Coffee!"




                                                 23
Thursday, March 28, 13                                                         23
Template
                         Massimiliano Dessì & Alberto Quario    GTUG Sardegna




                         Mustache

                         Hello {{name}}
                         You have just won ${{value}}!
                         {{#in_ca}}
                         Well, ${{taxed_value}}, after taxes.
                         {{/in_ca}}




                                                 24
Thursday, March 28, 13                                                          24
Template
                           Massimiliano Dessì & Alberto Quario   GTUG Sardegna




                         SCAML

                         !!! XML
                         !!!
                         %html
                           %head
                             %title Myspace
                           %body
                             %h1 I am the international space station
                             %p Sign my guestbook




                                                   25
Thursday, March 28, 13                                                           25
Actors
                            Massimiliano Dessì & Alberto Quario   GTUG Sardegna




                   Non Blocking and Async
                            with
                      Akka and Actors




                                                    26
Thursday, March 28, 13                                                            26
Actors
                               Massimiliano Dessì & Alberto Quario     GTUG Sardegna




  The routes can returns a Future

  class MyActorServlet(system:ActorSystem, myActor:ActorRef)
                           extends ScalatraServlet with FutureSupport {

      import _root_.akka.pattern.ask
      implicit val timeout = Timeout(10)
      protected implicit def executor: ExecutionContext = system.dispatcher

      get("/async") {
        myActor ? "Do stuff and give me an answer"
      }

      get("/fire-forget") {
        myActor ! "Hey, you know what?"
        Accepted() //if you do not want return a future
      }


  }


                                                       27
Thursday, March 28, 13                                                                 27
Actors
                         Massimiliano Dessì & Alberto Quario     GTUG Sardegna

     get("/async") {
       myActor ? "Do stuff and give me an answer"
     }


     get("/fire-forget") {
       myActor ! "Hey, you know what?"
       Accepted() //if you don’t want return a future
     }

     class CodemotionActor extends Actor {
       def receive = {
          case "Do stuff and give me an answer" => sender ! "The answer is 42"
          case "Hey, you know what?" => println("Yeah I know...")
       }
     }

 }




                                                 28
Thursday, March 28, 13                                                           28
Actors
                          Massimiliano Dessì & Alberto Quario       GTUG Sardegna

 Akka start in the Bootstrap of Scalatra



 class ScalatraBootstrap extends LifeCycle {

     val system = ActorSystem()
     val codemotionActor = system.actorOf(Props[CodemotionActor])

      override def init(context: ServletContext) {
        context.mount(new JSONServlet, "/jellybs/*")
        context.mount(new FrontServlet, "/template/*")
        context.mount(new MyActorServlet(system, codemotionActor), "/actors/*")
      }

      override def destroy(context:ServletContext) {
         system.shutdown()
       }
 }




                                                  29
Thursday, March 28, 13                                                              29
Authentication & Security
                         Massimiliano Dessì & Alberto Quario         GTUG Sardegna


Scalatra uses Scentry a porting of Ruby Warden authentication



class OurAuthStrategy(protected override val app: ScalatraBase, realm: String)
  extends BasicAuthStrategy[User](app, realm) {

    protected def validate(userName: String, password: String): Option[User] = {
      if(userName == "myusername" && password == "secret") Some(User("myusername"))
      else None
    }

    protected def getUserId(user: User): String = user.id
}



case class User(id: String)




                                                 30
Thursday, March 28, 13                                                                30
Authentication & Security
                           Massimiliano Dessì & Alberto Quario               GTUG Sardegna




 Now we need to combine our strategy and ScentrySupport
 trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] {
   self: ScalatraBase =>

     val realm = "Scalatra Basic Auth Example"

     protected def fromSession = { case id: String => User(id) }
     protected def toSession = { case usr: User => usr.id }
     protected val scentryConfig = (new ScentryConfig {}).asInstanceOf[ScentryConfiguration]


 }




                                                   31
Thursday, March 28, 13                                                                         31
Authentication & Security
                           Massimiliano Dessì & Alberto Quario                  GTUG Sardegna

 Now we need to combine our strategy and ScentrySupport


 trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] {
   ....

     override protected def configureScentry = {
       scentry.unauthenticated {
         scentry.strategies("Basic").unauthenticated()
         scentry.strategies("")
       }
     }

     override protected def registerAuthStrategies = {
       scentry.register("Basic", app => new OurBasicAuthStrategy(app, realm))
     }

     protected def validate(userName: String, password: String): Option[User] = {
        if(userName == "scalatra" && password == "scalatra") Some(User("scalatra"))
        else None
      }
 }




                                                   32
Thursday, March 28, 13                                                                          32
Authentication & Security
                             Massimiliano Dessì & Alberto Quario             GTUG Sardegna




 Now we can use the Authentication for all routes defined in our Authenticated Servlets


 class AuthenticatedServlet extends ScalatraServlet with AuthenticationSupport{

             //every route goes under authentication

 }

 Unauthenticated user will see a browser prompt login




                                                     33
Thursday, March 28, 13                                                                       33
Deployment
                         Massimiliano Dessì & Alberto Quario   GTUG Sardegna




         The simplest way to deploy
         your Scalatra application
         is as a
         Web application ARchive file




                                                 34
Thursday, March 28, 13                                                         34
Deployment
                                         Massimiliano Dessì & Alberto Quario                     GTUG Sardegna

                                              Scalatra is based on regular Java Servlet 3.0
                                                            it can start from:
                                                   Standalone from jetty embedded
                                                         From Servlet container
                                                                 Heroku
                                                                 Jelastic
                                                                CloudBees
                                                        GAE (not out of the box )

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0">
    <listener>
      <listener-class>org.scalatra.servlet.ScalatraListener</listener-class>
    </listener>

    <servlet-mapping>
      <servlet-name>default</servlet-name>
      <url-pattern>/img/*</url-pattern>
      <url-pattern>/css/*</url-pattern>
      <url-pattern>/js/*</url-pattern>
      <url-pattern>/assets/*</url-pattern>
    </servlet-mapping>
</web-app>




                                                                   35
Thursday, March 28, 13                                                                                           35
Test
                         Massimiliano Dessì & Alberto Quario   GTUG Sardegna

                                           Test with Specs2




class FrontServletSpec extends ScalatraSpec {
  def is =
    "GET / on FrontServlet" ^
      "should return status 200" ! root200 ^
      end

     addServlet(classOf[FrontServlet], "/*")

     def root200 = get("/") {
       status must_== 200
     }
}




                                                  36
Thursday, March 28, 13                                                         36
Hot reloading
                             Massimiliano Dessì & Alberto Quario   GTUG Sardegna




                         Thanks JRebel for free Scala plan !




                                                     37
Thursday, March 28, 13                                                             37
Massimiliano Dessì & Alberto Quario   GTUG Sardegna




                          www.playframework.com

              • Stateless
              • CoC
              • Integrated Testing
              • Asynchronous I/O
              • Java friendly


                                                 38
Thursday, March 28, 13                                                         38
Controller & View
                          Massimiliano Dessì & Alberto Quario            GTUG Sardegna



     package controllers                                        Application.scala
     import play.api.mvc.{Controller, Action}

     object Application extends Controller {
       def index() = Action {
         Ok(views.html.index("Hello codemotion!"))
       }
     }



     @(message: String)                                         index.scala.html
     @main("Welcome to Play 2.1") {
         <h2>@message</h2>
     }




                                                  39
Thursday, March 28, 13                                                                   39
Routing
                                    Massimiliano Dessì & Alberto Quario             GTUG Sardegna


        conf/routes
                GET      /clients/all                  controllers.Clients.list()
                GET      /clients/:id                  controllers.Clients.show(id: Long)




                GET      /clients/$id<[0-9]+>          controllers.Clients.show(id: Long)




                GET      /clients                      controllers.Clients.list(page: Int ?= 1)

                GET      /api/list-all                 controllers.Api.list(Option[version])


                                                            40
Thursday, March 28, 13                                                                              40
Session
                                Massimiliano Dessì & Alberto Quario     GTUG Sardegna




                         def index = Action { implicit request =>
                           session.get("connected").map { user =>
                             Ok("Hello " + user)
                           }.getOrElse {
                             Unauthorized("Oops, you are not connected")
                           }
                         }

                         Ok("Welcome!").withSession(
                           "connected" -> "user@gmail.com"
                         )

                         Ok("Welcome!").withSession(
                           session + ("saidHello" -> "yes") - "theme"
                         )




                                                        41
Thursday, March 28, 13                                                                  41
Authentication
                         Massimiliano Dessì & Alberto Quario   GTUG Sardegna

            import play.api.mvc.Security
            trait Secured {
              private def username(request: RequestHeader) =
            request.session.get("user_id")

              private def onUnauthorized(request: RequestHeader) =
            Results.Redirect(routes.Application.login)

              def isAuthenticated(f: => String => Request[AnyContent] =>
            Result) = Security.Authenticated(username,onUnauthorized) {
                user => Action(request => f(user)(request))
              }
            }
            object Application extends Controller with Secured {
              def index = isAuthenticated { userId => implicit request =>
                Ok(html.index(userId))
              }
            }


                                                 42
Thursday, March 28, 13                                                         42
Template
                                Massimiliano Dessì & Alberto Quario          GTUG Sardegna



            • compiled as standard Scala functions
            • follow a simple naming convention
                 views/index.scala.html ➡ views.html.index
                  @(customer: Customer, orders: List[Order])

                  @title(text: String) = @{
                    text.split(' ').map(_.capitalize).mkString(" ")
                  }

                  <h1>@title(customer.name)</h1>
                  <ul>
                  @for(order <- orders) {
                    <li>@order.getTitle()</li>
                  }
                  </ul>

                  @defining(customer.name + " " + customer.surname) { fullName =>
                    <div>Regards @fullName</div>
                  }


                                                        43
Thursday, March 28, 13                                                                       43
REST
                                     Massimiliano Dessì & Alberto Quario                                GTUG Sardegna


         GET             /api/reviews                             controllers.Reviews.list
         GET             /api/reviews/count                       controllers.Reviews.count
         GET             /api/reviews/:id                         controllers.Reviews.show(id: Int)
         import play.api.libs.json._                               object Reviews extends Controller {
         import play.api.libs.functional.syntax._
                                                                       def list = Action { request =>
         case class Review(id: Int, text: String)                        Ok(toJson(Review.findAll))
                                                                       }
         object Review {
           val reviews: List[Review] =                                 def count = Action { request =>
             List(Review(1, "hello"), Review(2, "codemotion"))           Ok(toJson(Review.count))
                                                                       }
             def findAll: Seq[Review] = reviews
                                                                       def show(id: Int) = Action {
             def count: Int = reviews.size                               Review.findById(id).map { review =>
                                                                           Ok(toJson(review))
             def findById(id: Int): Option[Review] =                     }.getOrElse(NotFound(
               reviews.find(_.id == id)                                    toJson(Map("error" ->
                                                                             "Review with id %s not found".
             implicit val reviewReads = (                                    format(id)))))
               (__  "id").read[Int] and                               }
               (__  "text").read[String]                          }
             )(Review.apply _)

             implicit val creatureWrites = (
               (__  "id").write[Int] and
               (__  "text").write[String]
             )(unlift(Review.unapply))
         }




                                                             44
Thursday, March 28, 13                                                                                                  44
Form
                         Massimiliano Dessì & Alberto Quario               GTUG Sardegna

      object Contacts extends Controller {
                                                               case class Contact(
        val contactForm: Form[Contact] = Form(                   firstname: String,
          mapping(                                               lastname: String,
                                                                 company: Option[String]
            "firstname" -> nonEmptyText,                       )
            "lastname" -> nonEmptyText,
            "company" -> optional(text)
          )(Contact.apply)(Contact.unapply)
        )

           def form = Action {
             Ok(html.contact.form(contactForm))
           }

           def submit = Action { implicit request =>
             contactForm.bindFromRequest.fold(
               errors => BadRequest(html.contact.form(errors)),
               contact => Ok(html.contact.summary(contact))
             )
           }


                                                 45
Thursday, March 28, 13                                                                     45
Form /2
                                      Massimiliano Dessì & Alberto Quario                     GTUG Sardegna

                         @(contactForm: Form[Contact])
                             @helper.form(action = routes.Contacts.submit) {

                                 <fieldset>
                                     <legend>General informations</legend>

                                     @inputText(
                                         contactForm("firstname"),
                                         '_label -> "First name"
                                     )

                                     @inputText(
                                         contactForm("lastname"),
                                         '_label -> "Last name"
                                     )

                                     @inputText(
                                         contactForm("company"),
                                         '_label -> "Company"
                                     )

                                 </fieldset>
                                 <div class="actions">
                                     <input type="submit" class="btn primary" value="Insert">
                                     <a href="@routes.Application.index" class="btn">Cancel</a>
                                 </div>

                             }



                                                              46
Thursday, March 28, 13                                                                                        46
Non-blocking IO
                                 Massimiliano Dessì & Alberto Quario    GTUG Sardegna




   object Application extends Controller {

        def intensiveComputation(): Int = ...

        def index = Action {
          val futureInt = scala.concurrent.Future { intensiveComputation() }
          Async {
            futureInt.map(i => Ok(views.html.index("Got result: " + i)))
          }
        }
   }

                         play.api.libs.ws.WS

                         WS.url("http://example.com/feed").get()
                         WS.url("http://example.com/item").post("content")




                                                         47
Thursday, March 28, 13                                                                  47
Non-blocking IO /2
                               Massimiliano Dessì & Alberto Quario          GTUG Sardegna


          def race() = Action {
            Async {
              val start = System.currentTimeMillis()
              def getLatency(r: Any): Long = System.currentTimeMillis() - start

                  val googleTime = WS.url("http://www.google.com").get().map(getLatency)
                  val yahooTime = WS.url("http://www.yahoo.com").get().map(getLatency)
                  val bingTime = WS.url("http://www.bing.com").get().map(getLatency)

                  Future.sequence(Seq(googleTime, yahooTime, bingTime)).map {
                    case times =>
                      Ok(Json.toJson(Map(
                        "google" -> times(0),
                        "yahoo" -> times(1),
                        "bing" -> times(2),
                        "total" -> getLatency(0))))
                  }
              }
          }

        {"google":343,"yahoo":3043,"bing":1608,"total":3048}

                                                       48
Thursday, March 28, 13                                                                      48
Test
                                     Massimiliano Dessì & Alberto Quario          GTUG Sardegna

     class ApplicationSpec extends Specification {

         "Application" should {

             "send 404 on a bad request" in {
               running(FakeApplication()) {
                 route(FakeRequest(GET, "/boum")) must beNone
               }
             }

             "render the index page" in {
               running(FakeApplication()) {
                 val home = route(FakeRequest(GET, "/")).get

                         status(home) must equalTo(OK)
                         contentType(home) must beSome.which(_ == "text/html")
                         contentAsString(home) must contain ("Your new application is ready.")
                  }
             }
         }
     }




                                                             49
Thursday, March 28, 13                                                                            49
Test /2
                                     Massimiliano Dessì & Alberto Quario          GTUG Sardegna

     class IntegrationSpec extends Specification {

         "Application" should {

             "work in a server" in {
               running(TestServer(3333)) {
                 await(WS.url("http://localhost:3333").get).status must equalTo(OK)
               }
             }

             "work from within a browser" in {
               running(TestServer(3333), HTMLUNIT) { browser =>

                         browser.goTo("http://localhost:3333/")

                         browser.pageSource must contain("Your new application is ready.")
                  }
             }
         }
     }




                                                             50
Thursday, March 28, 13                                                                            50
Deploy
                         Massimiliano Dessì & Alberto Quario   GTUG Sardegna




                                                 51
Thursday, March 28, 13                                                         51
Deploy /2
                              Massimiliano Dessì & Alberto Quario                  GTUG Sardegna

         Welcome to Play 2.1.0!

         These commands are available:
         -----------------------------
         classpath                  Display the project classpath.
         clean                      Clean all generated files.
         compile                    Compile the current application.
         console                    Launch the interactive Scala console (use :quit to exit).
         dependencies               Display the dependencies summary.
         dist                       Construct standalone application package.
         exit                       Exit the console.
         h2-browser                 Launch the H2 Web browser.
         license                    Display licensing informations.
         package                    Package your application as a JAR.
         play-version               Display the Play version.
         publish                    Publish your application in a remote repository.
         publish-local              Publish your application in the local repository.
         reload                     Reload the current application build file.
         run <port>                 Run the current application in DEV mode.
         test                       Run Junit tests and/or Specs from the command line
         eclipse                    generate eclipse project file
         idea                       generate Intellij IDEA project file
         sh <command to run>        execute a shell command
         start <port>               Start the current application in another JVM in PROD mode.
         update                     Update application dependencies.




                                                      52
Thursday, March 28, 13                                                                             52
Massimiliano Dessì & Alberto Quario          GTUG Sardegna




                         spray is an open-source toolkit for REST/HTTP
                                                 and
                         low-level network IO on top of Scala and Akka.


                                          aka Scala -IKEA


                                  VMWare and Ebay use spray
                                    for some internal projects




                                                     53
Thursday, March 28, 13                                                                    53
Routing
                         Massimiliano Dessì & Alberto Quario   GTUG Sardegna




      class PingServiceActor extends Actor {
        def receive = {
             case HttpRequest(GET, "/ping", _, _, _) =>
             sender ! HttpResponse(200, "PONG")
         }
      }




                                                 54
Thursday, March 28, 13                                                         54
Routing
                             Massimiliano Dessì & Alberto Quario   GTUG Sardegna

 path with name order => directive route
 get and put => are inner route
 ~ =>route concatenation

 class MyServiceActor extends Actor with Routing {
  def receive = receiveFromRoute {
    path("order" / HexIntNumber) { id =>
        get {
            completeWith {
                "Received GET for order " + id
            }
        } ~
        put {
            completeWith { "Received PUT for order " + id

                         }
                  }
         }
     }
 }

                                                     55
Thursday, March 28, 13                                                             55
Routing
                                   Massimiliano Dessì & Alberto Quario                       GTUG Sardegna



      trait LongerService extends HttpService with MyApp {

         val simpleCache = routeCache(maxCapacity = 1000, timeToIdle = Duration("30 min"))

           val route = {
           path("orders") {
             authenticate(BasicAuth(realm = "admin area")) { user =>
               get {
                 cache(simpleCache) {
                   encodeResponse(Deflate) {
                      complete {
                        getOrdersFromDB
                      }
                   }
                 }
               } ~
               post {
                 (decodeRequest(Gzip) | decodeRequest(NoEncoding)) {
                   entity(as[Order]) { order =>
                      detachTo(singleRequestServiceActor) {
                        complete {
                          // ... write order to DB
                          "Order received"
                        }
                      }
                   }
                 }
               }
             }
           } ~




                                                             56
Thursday, March 28, 13                                                                                       56
Routing
                              Massimiliano Dessì & Alberto Quario          GTUG Sardegna




              pathPrefix("order" / IntNumber) { orderId =>
                path("") {
                  // method tunneling via query param
                  (put | parameter('method ! "put")) {
                    // form extraction from multipart or www-url-encoded forms
                    formFields('email, 'total.as[Money]).as(Order) { order =>
                      complete {
                        // complete with serialized Future result
                        (myDbActor ? Update(order)).mapTo[TransactionResult]
                      }
                    }
                  } ~
                  get {
                    jsonpWithParameter("callback") {
                      produce(instanceOf[Order]) { complete => ctx =>
                        processOrderRequest(orderId, complete)
                      }
                    }
                  }
                } ~



                                                      57
Thursday, March 28, 13                                                                     57
Non-blocking IO
                                 Massimiliano Dessì & Alberto Quario          GTUG Sardegna


                def race() {
                  val start = System.currentTimeMillis()
                  def getLatency(r: Any): Long = System.currentTimeMillis() - start

                    val googleFuture = httpClient.ask(Get("http://www.google.com"))
                      .mapTo[HttpResponse].map(getLatency)
                    val yahooFuture = httpClient.ask(Get("http://www.yahoo.com"))
                      .mapTo[HttpResponse].map(getLatency)
                    val bingFuture = httpClient.ask(Get("http://www.example.com"))
                      .mapTo[HttpResponse].map(getLatency)

                    Future.sequence(Seq(googleFuture, yahooFuture, bingFuture)).map {
                      case times =>
                        log.info(
                          "google" + times(0) +
                          " yahoo" + times(1) +
                          " bing" + times(2) +
                          " total: "+getLatency(0))
                        system.shutdown() // stops all actors
                    }
                }



                                                         58
Thursday, March 28, 13                                                                        58
Test
                                Massimiliano Dessì & Alberto Quario               GTUG Sardegna

      class DemoServiceSpec extends Specification with Specs2RouteTest with DemoService {
        def actorRefFactory = system

          "The DemoService" should {

              "return a greeting for GET requests to the root path" in {
                Get() ~> demoRoute ~> check { entityAs[String] must contain("Say hello") }
              }

              "return a 'PONG!' response for GET requests to /ping" in {
                Get("/ping") ~> demoRoute ~> check { entityAs[String] === "PONG!" }
              }

              "leave GET requests to other paths unhandled" in {
                Get("/kermit") ~> demoRoute ~> check { handled must beFalse }
              }

              "return a MethodNotAllowed error for PUT requests to the root path" in {
                Put() ~> sealRoute(demoRoute) ~> check {
                  status === MethodNotAllowed
                  entityAs[String] === "HTTP method not allowed, supported methods: GET"
                }
              }
          }
      }



                                                        59
Thursday, March 28, 13                                                                            59
Massimiliano Dessì & Alberto Quario   GTUG Sardegna




                         Q&A




                                                   60
Thursday, March 28, 13                                                           60
Agenda
                               Massimiliano Dessì & Alberto Quario                           GTUG Sardegna




                                 Thanks for your attention!

                         Massimiliano: @desmax74                     Alberto :@realrealbot




                                                       61
Thursday, March 28, 13                                                                                       61

Más contenido relacionado

Destacado

Microservices in Go_Dessi_Massimiliano_Codemotion_2017_Rome
Microservices in Go_Dessi_Massimiliano_Codemotion_2017_Rome Microservices in Go_Dessi_Massimiliano_Codemotion_2017_Rome
Microservices in Go_Dessi_Massimiliano_Codemotion_2017_Rome Massimiliano Dessì
 
The hitchhiker's guide to UXing without a UXer - Chrissy Welsh - Codemotion M...
The hitchhiker's guide to UXing without a UXer - Chrissy Welsh - Codemotion M...The hitchhiker's guide to UXing without a UXer - Chrissy Welsh - Codemotion M...
The hitchhiker's guide to UXing without a UXer - Chrissy Welsh - Codemotion M...Codemotion
 
The final words about software estimation
The final words about software estimationThe final words about software estimation
The final words about software estimationAlberto Brandolini
 
The amazing world of Game Design - Emanuele Bolognesi - Codemotion Milan 2016
The amazing world of Game Design - Emanuele Bolognesi - Codemotion Milan 2016The amazing world of Game Design - Emanuele Bolognesi - Codemotion Milan 2016
The amazing world of Game Design - Emanuele Bolognesi - Codemotion Milan 2016Codemotion
 
Event sourcing your React-Redux applications
Event sourcing your React-Redux applicationsEvent sourcing your React-Redux applications
Event sourcing your React-Redux applicationsMaurice De Beijer [MVP]
 

Destacado (7)

Microservices in Go_Dessi_Massimiliano_Codemotion_2017_Rome
Microservices in Go_Dessi_Massimiliano_Codemotion_2017_Rome Microservices in Go_Dessi_Massimiliano_Codemotion_2017_Rome
Microservices in Go_Dessi_Massimiliano_Codemotion_2017_Rome
 
The busy developer guide to Docker
The busy developer guide to DockerThe busy developer guide to Docker
The busy developer guide to Docker
 
The hitchhiker's guide to UXing without a UXer - Chrissy Welsh - Codemotion M...
The hitchhiker's guide to UXing without a UXer - Chrissy Welsh - Codemotion M...The hitchhiker's guide to UXing without a UXer - Chrissy Welsh - Codemotion M...
The hitchhiker's guide to UXing without a UXer - Chrissy Welsh - Codemotion M...
 
Event storming recipes
Event storming recipesEvent storming recipes
Event storming recipes
 
The final words about software estimation
The final words about software estimationThe final words about software estimation
The final words about software estimation
 
The amazing world of Game Design - Emanuele Bolognesi - Codemotion Milan 2016
The amazing world of Game Design - Emanuele Bolognesi - Codemotion Milan 2016The amazing world of Game Design - Emanuele Bolognesi - Codemotion Milan 2016
The amazing world of Game Design - Emanuele Bolognesi - Codemotion Milan 2016
 
Event sourcing your React-Redux applications
Event sourcing your React-Redux applicationsEvent sourcing your React-Redux applications
Event sourcing your React-Redux applications
 

Similar a Codemotion 2013 scalatra_play_spray

Codemotion 2013 scalatra play spray
Codemotion 2013 scalatra play sprayCodemotion 2013 scalatra play spray
Codemotion 2013 scalatra play sprayrealbot
 
Scalatra - Massimiliano Dessì (Energeya)
Scalatra - Massimiliano Dessì (Energeya)Scalatra - Massimiliano Dessì (Energeya)
Scalatra - Massimiliano Dessì (Energeya)Scala Italy
 
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of Things
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of ThingsHTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of Things
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of ThingsJesse Cravens
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GParsPaul King
 
Implementing Quality on Java projects
Implementing Quality on Java projectsImplementing Quality on Java projects
Implementing Quality on Java projectsVincent Massol
 
JavaScriptを使って学ぶEnd-to-Endセキュリティ 第3回
JavaScriptを使って学ぶEnd-to-Endセキュリティ 第3回JavaScriptを使って学ぶEnd-to-Endセキュリティ 第3回
JavaScriptを使って学ぶEnd-to-Endセキュリティ 第3回Jun Kurihara
 

Similar a Codemotion 2013 scalatra_play_spray (7)

Codemotion 2013 scalatra play spray
Codemotion 2013 scalatra play sprayCodemotion 2013 scalatra play spray
Codemotion 2013 scalatra play spray
 
Scalatra - Massimiliano Dessì (Energeya)
Scalatra - Massimiliano Dessì (Energeya)Scalatra - Massimiliano Dessì (Energeya)
Scalatra - Massimiliano Dessì (Energeya)
 
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of Things
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of ThingsHTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of Things
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of Things
 
Deep learning
Deep learningDeep learning
Deep learning
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GPars
 
Implementing Quality on Java projects
Implementing Quality on Java projectsImplementing Quality on Java projects
Implementing Quality on Java projects
 
JavaScriptを使って学ぶEnd-to-Endセキュリティ 第3回
JavaScriptを使って学ぶEnd-to-Endセキュリティ 第3回JavaScriptを使って学ぶEnd-to-Endセキュリティ 第3回
JavaScriptを使って学ぶEnd-to-Endセキュリティ 第3回
 

Más de Massimiliano Dessì

When Old Meets New: Turning Maven into a High Scalable, Resource Efficient, C...
When Old Meets New: Turning Maven into a High Scalable, Resource Efficient, C...When Old Meets New: Turning Maven into a High Scalable, Resource Efficient, C...
When Old Meets New: Turning Maven into a High Scalable, Resource Efficient, C...Massimiliano Dessì
 
Web Marketing Training 2014 Community Online
Web Marketing Training 2014 Community OnlineWeb Marketing Training 2014 Community Online
Web Marketing Training 2014 Community OnlineMassimiliano Dessì
 
Three languages in thirty minutes
Three languages in thirty minutesThree languages in thirty minutes
Three languages in thirty minutesMassimiliano Dessì
 
Jaxitalia09 Spring Best Practices
Jaxitalia09 Spring Best PracticesJaxitalia09 Spring Best Practices
Jaxitalia09 Spring Best PracticesMassimiliano Dessì
 
MongoDB Scala Roma SpringFramework Meeting2009
MongoDB Scala Roma SpringFramework Meeting2009MongoDB Scala Roma SpringFramework Meeting2009
MongoDB Scala Roma SpringFramework Meeting2009Massimiliano Dessì
 
Scala Programming Linux Day 2009
Scala Programming Linux Day 2009Scala Programming Linux Day 2009
Scala Programming Linux Day 2009Massimiliano Dessì
 
MongoDB SpringFramework Meeting september 2009
MongoDB SpringFramework Meeting september 2009MongoDB SpringFramework Meeting september 2009
MongoDB SpringFramework Meeting september 2009Massimiliano Dessì
 
The hidden gems of Spring Security
The hidden gems of Spring SecurityThe hidden gems of Spring Security
The hidden gems of Spring SecurityMassimiliano Dessì
 
Aspect Oriented Programming and MVC with Spring Framework
Aspect Oriented Programming and MVC with Spring FrameworkAspect Oriented Programming and MVC with Spring Framework
Aspect Oriented Programming and MVC with Spring FrameworkMassimiliano Dessì
 
Real Spring Aop Recipes For Your Everyday Job
Real Spring Aop Recipes For Your Everyday JobReal Spring Aop Recipes For Your Everyday Job
Real Spring Aop Recipes For Your Everyday JobMassimiliano Dessì
 

Más de Massimiliano Dessì (20)

Code One 2018 maven
Code One 2018   mavenCode One 2018   maven
Code One 2018 maven
 
When Old Meets New: Turning Maven into a High Scalable, Resource Efficient, C...
When Old Meets New: Turning Maven into a High Scalable, Resource Efficient, C...When Old Meets New: Turning Maven into a High Scalable, Resource Efficient, C...
When Old Meets New: Turning Maven into a High Scalable, Resource Efficient, C...
 
Hacking Maven Linux day 2017
Hacking Maven Linux day 2017Hacking Maven Linux day 2017
Hacking Maven Linux day 2017
 
Web Marketing Training 2014 Community Online
Web Marketing Training 2014 Community OnlineWeb Marketing Training 2014 Community Online
Web Marketing Training 2014 Community Online
 
Scala linux day 2012
Scala linux day 2012 Scala linux day 2012
Scala linux day 2012
 
Three languages in thirty minutes
Three languages in thirty minutesThree languages in thirty minutes
Three languages in thirty minutes
 
MongoDB dessi-codemotion
MongoDB dessi-codemotionMongoDB dessi-codemotion
MongoDB dessi-codemotion
 
MongoDB Webtech conference 2010
MongoDB Webtech conference 2010MongoDB Webtech conference 2010
MongoDB Webtech conference 2010
 
RESTEasy
RESTEasyRESTEasy
RESTEasy
 
Spring Roo Internals Javaday IV
Spring Roo Internals Javaday IVSpring Roo Internals Javaday IV
Spring Roo Internals Javaday IV
 
Spring Roo JaxItalia09
Spring Roo JaxItalia09Spring Roo JaxItalia09
Spring Roo JaxItalia09
 
Jaxitalia09 Spring Best Practices
Jaxitalia09 Spring Best PracticesJaxitalia09 Spring Best Practices
Jaxitalia09 Spring Best Practices
 
Spring3.0 JaxItalia09
Spring3.0 JaxItalia09Spring3.0 JaxItalia09
Spring3.0 JaxItalia09
 
MongoDB Scala Roma SpringFramework Meeting2009
MongoDB Scala Roma SpringFramework Meeting2009MongoDB Scala Roma SpringFramework Meeting2009
MongoDB Scala Roma SpringFramework Meeting2009
 
Scala Programming Linux Day 2009
Scala Programming Linux Day 2009Scala Programming Linux Day 2009
Scala Programming Linux Day 2009
 
MongoDB SpringFramework Meeting september 2009
MongoDB SpringFramework Meeting september 2009MongoDB SpringFramework Meeting september 2009
MongoDB SpringFramework Meeting september 2009
 
The hidden gems of Spring Security
The hidden gems of Spring SecurityThe hidden gems of Spring Security
The hidden gems of Spring Security
 
Spring @Aspect e @Controller
Spring @Aspect e @Controller Spring @Aspect e @Controller
Spring @Aspect e @Controller
 
Aspect Oriented Programming and MVC with Spring Framework
Aspect Oriented Programming and MVC with Spring FrameworkAspect Oriented Programming and MVC with Spring Framework
Aspect Oriented Programming and MVC with Spring Framework
 
Real Spring Aop Recipes For Your Everyday Job
Real Spring Aop Recipes For Your Everyday JobReal Spring Aop Recipes For Your Everyday Job
Real Spring Aop Recipes For Your Everyday Job
 

Último

CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 

Último (20)

CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 

Codemotion 2013 scalatra_play_spray

  • 1. Massimiliano Dessì & Alberto Quario Scala On Web Play - Scalatra - Spray Google Technology User Group Sardegna 1 Thursday, March 28, 13 1
  • 2. Speakers Massimiliano Dessì & Alberto Quario GTUG Sardegna Max has more than 13 years of experience in programming. He’s a proud father of three. Manager of GTUG Sardegna, Founder of SpringFramework IT, co-founder of Jug Sardegna. Author of Spring 2.5 AOP. He works in Energeya and lives in Cagliari, Italy. Alberto has more than 15 years experience in developing software, he wrote his first programs on a TI-99/4A and hasn't stopped since. Other than languages and development, Alberto's passions include squash, cooking and Monet paintings. He lives and works in Milano, Italy. 2 Thursday, March 28, 13 2
  • 3. Agenda Massimiliano Dessì & Alberto Quario GTUG Sardegna Scalatra -Playframework -Spray REST JSON Routing Template Actors Sessions Deploy Hot Reloading Test 3 Thursday, March 28, 13 3
  • 4. Massimiliano Dessì & Alberto Quario GTUG Sardegna Scalatra is a web microframework written in Scala inspired to Sinatra a Ruby DSL to build webapp http://www.scalatra.org the BBC, LinkedIn, the Guardian, games website IGN, UK government rely on Scalatra. 4 Thursday, March 28, 13 4
  • 5. REST Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { get("/jellybs/:id") { ... } post("/jellybs") { ... } put("/jellybs/:id") { ... } delete("/jellybs/:id") { ... } } For browser add PUT & DELETE support client side X-HTTP-METHOD-OVERRIDE or _method=put _method=delete in the post body class JellyBeansBrowser extends ScalatraFilter with MethodOverride 5 Thursday, March 28, 13 5
  • 6. Routes Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { get("/jellybs/:id") { val id:Int = params.getOrElse("id", halt(400)).toInt ... } get("/jellybs/download/*.*") { //with wildcard ... } get("""^/j(.*)/f(.*)""".or) { //REGEX ... } post("/jellybs", request.getRemoteHost == "127.0.0.1", request.getRemoteUser == "admin") { .... } 6 Thursday, March 28, 13 6
  • 7. Filter Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { before() { db.acquireConnecion contentType="text/html" Like Servlet Filter } (or Aspect Oriented Programming) You can add logic before or the get("/") { routes val menu = db.findWelcome() templateEngine.layout("index.ssp", menu) } after() { db.releaseConnection } } 7 Thursday, March 28, 13 7
  • 8. Filter Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { before("""/api/v1/.*""".r) { contentType = "application/json" } before("/admin/*") { auth } after("/admin/*") { user.logout } } 8 Thursday, March 28, 13 8
  • 9. Handlers Massimiliano Dessì & Alberto Quario GTUG Sardegna Handlers are top level methods for http routines class JellyBeans extends ScalatraServlet { notFound { <h1>Not found</h1> } halt(status = 301, headers = Map("Location" -> "http://www.codemotion.com/")) get("/jellybs/names/*") { "Name not found!" } } 9 Thursday, March 28, 13 9
  • 10. Handlers Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { get("/jellybs/names/:who") { params("who") match { case "Cherry" => "Found Cherry!" case _ => pass() /* call the next matching route route, routes are matched from bottom up*/ } } get("/jellybs/download/:id") { jellyBeanService.find(params("id")) match { case Some(jellybean) => Ok(jellybean) case None => NotFound("Sorry, jellybean not found") } } } 10 Thursday, March 28, 13 10
  • 11. Request Response & Friends Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { get("/jellybs/shows/:id") { //access to request,response, session and params request.body //request body as a string request.cookies // cookie map request.isAjax // is ajaxRequest request.getSession // HttpServletSession request.locale // user locale response.getOutputStream //response outputstream servletContext.get("myIntParam") //servlet context val idString = params("id") val id = params.getAs[Int]("id") //val id = params.getOrElse("id", halt(500)) //another way .... } } 11 Thursday, March 28, 13 11
  • 12. Request Response & Friends Massimiliano Dessì & Alberto Quario GTUG Sardegna class JellyBeans extends ScalatraServlet { get("/jellybs/*/conf/*") { // Matches "GET /jellybs/one/conf/two" multiParams("splat") // Seq("one", "two") //wildcard accessible with key splat } get("""^/jelly(.*)/fla(.*)""".r) { // Matches "GET /jellybs/flavor" multiParams("captures") // == Seq("bs", "vor") } } 12 Thursday, March 28, 13 12
  • 13. Binding Massimiliano Dessì & Alberto Quario GTUG Sardegna To avoid manual binding from http and our Object Scalatra provide a binding module case class MyClass(id: Integer, name: String) post("/myroute") { val cmd = command[CreateMyClassCommand] ... } 13 Thursday, March 28, 13 13
  • 14. Binding Massimiliano Dessì & Alberto Quario GTUG Sardegna Under the hood abstract class MyClassCommand[S](implicit mf: Manifest[S]) extends ModelCommand[S] with JsonCommand {    implicit def todoStringValidators(b: FieldDescriptor[String]) = new MyClassStringValidations(b) } class CreateMyClassCommand extends MyClassCommand[MyClass] { protected implicit val jsonFormats = DefaultFormats val name: Field[String] = asType[String]("name").notBlank.minLength(3) } 14 Thursday, March 28, 13 14
  • 15. Binding Massimiliano Dessì & Alberto Quario GTUG Sardegna Under the hood class MyClassStringValidations(b: FieldDescriptor[String]) { def startsWithCap(message: String = "%s must start with a capital letter.") = b.validateWith(_ =>      _ flatMap { new PredicateValidator[String]( b.name, """^[A-Z,0-9]""".r.findFirstIn(_).isDefined, message).validate(_)    ) } ) } 15 Thursday, March 28, 13 15
  • 16. Gzip Massimiliano Dessì & Alberto Quario GTUG Sardegna class GzipJellyBeans extends ScalatraServlet with GZipSupport{ get("/") { <html> <body> <h1>This is <a href="http://en.wikipedia.org/wiki/Sparta"> http/gzip </a>! </h1> </body> </html> } } 16 Thursday, March 28, 13 16
  • 17. Flash message Massimiliano Dessì & Alberto Quario GTUG Sardegna class FlashServlet extends ScalatraServlet with FlashMapSupport{ post("/jellybs/create") { flash("notice") = "jellybean created successfully" redirect("/home") } get("/home") { ssp("/home") //Scala Server Pages } 17 Thursday, March 28, 13 17
  • 18. JSON Massimiliano Dessì & Alberto Quario GTUG Sardegna Automatic Serialization and deserialization of any Case class object JSONServlet extends ScalatraServlet with JacksonJsonSupport{ case class JellyBean(id: Int, name: String, flavor:String) protected implicit val jsonFormats: Formats = DefaultFormats before() { contentType = formats("json") } .... 18 Thursday, March 28, 13 18
  • 19. JSON Massimiliano Dessì & Alberto Quario GTUG Sardegna Automatic Serialization and deserialization of any Case class object JSONServlet extends ScalatraServlet with JacksonJsonSupport{ ... get("/jellybs/all"){ jellyBeanRepo.all //from class to json } post("/jellybs/create") { val jb = parsedBody.extract[JellyBean] //from json to class ... } } 19 Thursday, March 28, 13 19
  • 20. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna Html inline, Scalate Twirl (Play2 template) Scalate mean SSP (Scala Server Page) Scaml Mustache Jade 20 Thursday, March 28, 13 20
  • 21. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna class ScalateServlet extends ScalatraServlet with ScalateSupport{ get("/"jellybeans/ssp) { contentType="text/html" ssp("/index", "foo" -> "uno", "bar" -> "two") // the layout used it’s WEB-INF/layouts/default.ssp } get("/jellybeans/jade") { jade("/index", "layout" -> "", "foo" -> "one", "bar" -> "two") // render without a layout. } get("/jellybeans/direct") { templateEngine.layout("/jellybeans/index.ssp") //direct invoking of scalate } 21 Thursday, March 28, 13 21
  • 22. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna SSP <%@ var body: String %> <%@ var title: String = "Some Default Title" %> <%@ var head: String = "" %> <html> <head> <title>${title}</title> <%-- page specific head goes here --%> ${unescape(head)} </head> <body> <p>layout header goes here...</p> ${unescape(body)} <p>layout footer goes here...</p> </body> </html> 22 Thursday, March 28, 13 22
  • 23. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna JADE !!! 5 html(lang="en") head title= pageTitle :javascript if (foo) { bar() } body h1 Jade - node template engine #container - if (youAreUsingJade) p You are amazing - else p Get on it! :coffeescript alert "Hello, Coffee!" 23 Thursday, March 28, 13 23
  • 24. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna Mustache Hello {{name}} You have just won ${{value}}! {{#in_ca}} Well, ${{taxed_value}}, after taxes. {{/in_ca}} 24 Thursday, March 28, 13 24
  • 25. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna SCAML !!! XML !!! %html %head %title Myspace %body %h1 I am the international space station %p Sign my guestbook 25 Thursday, March 28, 13 25
  • 26. Actors Massimiliano Dessì & Alberto Quario GTUG Sardegna Non Blocking and Async with Akka and Actors 26 Thursday, March 28, 13 26
  • 27. Actors Massimiliano Dessì & Alberto Quario GTUG Sardegna The routes can returns a Future class MyActorServlet(system:ActorSystem, myActor:ActorRef) extends ScalatraServlet with FutureSupport { import _root_.akka.pattern.ask implicit val timeout = Timeout(10) protected implicit def executor: ExecutionContext = system.dispatcher get("/async") { myActor ? "Do stuff and give me an answer" } get("/fire-forget") { myActor ! "Hey, you know what?" Accepted() //if you do not want return a future } } 27 Thursday, March 28, 13 27
  • 28. Actors Massimiliano Dessì & Alberto Quario GTUG Sardegna get("/async") { myActor ? "Do stuff and give me an answer" } get("/fire-forget") { myActor ! "Hey, you know what?" Accepted() //if you don’t want return a future } class CodemotionActor extends Actor { def receive = { case "Do stuff and give me an answer" => sender ! "The answer is 42" case "Hey, you know what?" => println("Yeah I know...") } } } 28 Thursday, March 28, 13 28
  • 29. Actors Massimiliano Dessì & Alberto Quario GTUG Sardegna Akka start in the Bootstrap of Scalatra class ScalatraBootstrap extends LifeCycle { val system = ActorSystem() val codemotionActor = system.actorOf(Props[CodemotionActor]) override def init(context: ServletContext) { context.mount(new JSONServlet, "/jellybs/*") context.mount(new FrontServlet, "/template/*") context.mount(new MyActorServlet(system, codemotionActor), "/actors/*") } override def destroy(context:ServletContext) { system.shutdown() } } 29 Thursday, March 28, 13 29
  • 30. Authentication & Security Massimiliano Dessì & Alberto Quario GTUG Sardegna Scalatra uses Scentry a porting of Ruby Warden authentication class OurAuthStrategy(protected override val app: ScalatraBase, realm: String) extends BasicAuthStrategy[User](app, realm) { protected def validate(userName: String, password: String): Option[User] = { if(userName == "myusername" && password == "secret") Some(User("myusername")) else None } protected def getUserId(user: User): String = user.id } case class User(id: String) 30 Thursday, March 28, 13 30
  • 31. Authentication & Security Massimiliano Dessì & Alberto Quario GTUG Sardegna Now we need to combine our strategy and ScentrySupport trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] { self: ScalatraBase => val realm = "Scalatra Basic Auth Example" protected def fromSession = { case id: String => User(id) } protected def toSession = { case usr: User => usr.id } protected val scentryConfig = (new ScentryConfig {}).asInstanceOf[ScentryConfiguration] } 31 Thursday, March 28, 13 31
  • 32. Authentication & Security Massimiliano Dessì & Alberto Quario GTUG Sardegna Now we need to combine our strategy and ScentrySupport trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] { .... override protected def configureScentry = { scentry.unauthenticated { scentry.strategies("Basic").unauthenticated() scentry.strategies("") } } override protected def registerAuthStrategies = { scentry.register("Basic", app => new OurBasicAuthStrategy(app, realm)) } protected def validate(userName: String, password: String): Option[User] = { if(userName == "scalatra" && password == "scalatra") Some(User("scalatra")) else None } } 32 Thursday, March 28, 13 32
  • 33. Authentication & Security Massimiliano Dessì & Alberto Quario GTUG Sardegna Now we can use the Authentication for all routes defined in our Authenticated Servlets class AuthenticatedServlet extends ScalatraServlet with AuthenticationSupport{ //every route goes under authentication } Unauthenticated user will see a browser prompt login 33 Thursday, March 28, 13 33
  • 34. Deployment Massimiliano Dessì & Alberto Quario GTUG Sardegna The simplest way to deploy your Scalatra application is as a Web application ARchive file 34 Thursday, March 28, 13 34
  • 35. Deployment Massimiliano Dessì & Alberto Quario GTUG Sardegna Scalatra is based on regular Java Servlet 3.0 it can start from: Standalone from jetty embedded From Servlet container Heroku Jelastic CloudBees GAE (not out of the box ) web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <listener> <listener-class>org.scalatra.servlet.ScalatraListener</listener-class> </listener> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/img/*</url-pattern> <url-pattern>/css/*</url-pattern> <url-pattern>/js/*</url-pattern> <url-pattern>/assets/*</url-pattern> </servlet-mapping> </web-app> 35 Thursday, March 28, 13 35
  • 36. Test Massimiliano Dessì & Alberto Quario GTUG Sardegna Test with Specs2 class FrontServletSpec extends ScalatraSpec { def is = "GET / on FrontServlet" ^ "should return status 200" ! root200 ^ end addServlet(classOf[FrontServlet], "/*") def root200 = get("/") { status must_== 200 } } 36 Thursday, March 28, 13 36
  • 37. Hot reloading Massimiliano Dessì & Alberto Quario GTUG Sardegna Thanks JRebel for free Scala plan ! 37 Thursday, March 28, 13 37
  • 38. Massimiliano Dessì & Alberto Quario GTUG Sardegna www.playframework.com • Stateless • CoC • Integrated Testing • Asynchronous I/O • Java friendly 38 Thursday, March 28, 13 38
  • 39. Controller & View Massimiliano Dessì & Alberto Quario GTUG Sardegna package controllers Application.scala import play.api.mvc.{Controller, Action} object Application extends Controller { def index() = Action { Ok(views.html.index("Hello codemotion!")) } } @(message: String) index.scala.html @main("Welcome to Play 2.1") { <h2>@message</h2> } 39 Thursday, March 28, 13 39
  • 40. Routing Massimiliano Dessì & Alberto Quario GTUG Sardegna conf/routes GET /clients/all controllers.Clients.list() GET /clients/:id controllers.Clients.show(id: Long) GET /clients/$id<[0-9]+> controllers.Clients.show(id: Long) GET /clients controllers.Clients.list(page: Int ?= 1) GET /api/list-all controllers.Api.list(Option[version]) 40 Thursday, March 28, 13 40
  • 41. Session Massimiliano Dessì & Alberto Quario GTUG Sardegna def index = Action { implicit request => session.get("connected").map { user => Ok("Hello " + user) }.getOrElse { Unauthorized("Oops, you are not connected") } } Ok("Welcome!").withSession( "connected" -> "user@gmail.com" ) Ok("Welcome!").withSession( session + ("saidHello" -> "yes") - "theme" ) 41 Thursday, March 28, 13 41
  • 42. Authentication Massimiliano Dessì & Alberto Quario GTUG Sardegna import play.api.mvc.Security trait Secured { private def username(request: RequestHeader) = request.session.get("user_id") private def onUnauthorized(request: RequestHeader) = Results.Redirect(routes.Application.login) def isAuthenticated(f: => String => Request[AnyContent] => Result) = Security.Authenticated(username,onUnauthorized) { user => Action(request => f(user)(request)) } } object Application extends Controller with Secured { def index = isAuthenticated { userId => implicit request => Ok(html.index(userId)) } } 42 Thursday, March 28, 13 42
  • 43. Template Massimiliano Dessì & Alberto Quario GTUG Sardegna • compiled as standard Scala functions • follow a simple naming convention views/index.scala.html ➡ views.html.index @(customer: Customer, orders: List[Order]) @title(text: String) = @{ text.split(' ').map(_.capitalize).mkString(" ") } <h1>@title(customer.name)</h1> <ul> @for(order <- orders) { <li>@order.getTitle()</li> } </ul> @defining(customer.name + " " + customer.surname) { fullName => <div>Regards @fullName</div> } 43 Thursday, March 28, 13 43
  • 44. REST Massimiliano Dessì & Alberto Quario GTUG Sardegna GET /api/reviews controllers.Reviews.list GET /api/reviews/count controllers.Reviews.count GET /api/reviews/:id controllers.Reviews.show(id: Int) import play.api.libs.json._ object Reviews extends Controller { import play.api.libs.functional.syntax._ def list = Action { request => case class Review(id: Int, text: String) Ok(toJson(Review.findAll)) } object Review { val reviews: List[Review] = def count = Action { request => List(Review(1, "hello"), Review(2, "codemotion")) Ok(toJson(Review.count)) } def findAll: Seq[Review] = reviews def show(id: Int) = Action { def count: Int = reviews.size Review.findById(id).map { review => Ok(toJson(review)) def findById(id: Int): Option[Review] = }.getOrElse(NotFound( reviews.find(_.id == id) toJson(Map("error" -> "Review with id %s not found". implicit val reviewReads = ( format(id))))) (__ "id").read[Int] and } (__ "text").read[String] } )(Review.apply _) implicit val creatureWrites = ( (__ "id").write[Int] and (__ "text").write[String] )(unlift(Review.unapply)) } 44 Thursday, March 28, 13 44
  • 45. Form Massimiliano Dessì & Alberto Quario GTUG Sardegna object Contacts extends Controller { case class Contact( val contactForm: Form[Contact] = Form( firstname: String, mapping( lastname: String, company: Option[String] "firstname" -> nonEmptyText, ) "lastname" -> nonEmptyText, "company" -> optional(text) )(Contact.apply)(Contact.unapply) ) def form = Action { Ok(html.contact.form(contactForm)) } def submit = Action { implicit request => contactForm.bindFromRequest.fold( errors => BadRequest(html.contact.form(errors)), contact => Ok(html.contact.summary(contact)) ) } 45 Thursday, March 28, 13 45
  • 46. Form /2 Massimiliano Dessì & Alberto Quario GTUG Sardegna @(contactForm: Form[Contact]) @helper.form(action = routes.Contacts.submit) { <fieldset> <legend>General informations</legend> @inputText( contactForm("firstname"), '_label -> "First name" ) @inputText( contactForm("lastname"), '_label -> "Last name" ) @inputText( contactForm("company"), '_label -> "Company" ) </fieldset> <div class="actions"> <input type="submit" class="btn primary" value="Insert"> <a href="@routes.Application.index" class="btn">Cancel</a> </div> } 46 Thursday, March 28, 13 46
  • 47. Non-blocking IO Massimiliano Dessì & Alberto Quario GTUG Sardegna object Application extends Controller { def intensiveComputation(): Int = ... def index = Action { val futureInt = scala.concurrent.Future { intensiveComputation() } Async { futureInt.map(i => Ok(views.html.index("Got result: " + i))) } } } play.api.libs.ws.WS WS.url("http://example.com/feed").get() WS.url("http://example.com/item").post("content") 47 Thursday, March 28, 13 47
  • 48. Non-blocking IO /2 Massimiliano Dessì & Alberto Quario GTUG Sardegna def race() = Action { Async { val start = System.currentTimeMillis() def getLatency(r: Any): Long = System.currentTimeMillis() - start val googleTime = WS.url("http://www.google.com").get().map(getLatency) val yahooTime = WS.url("http://www.yahoo.com").get().map(getLatency) val bingTime = WS.url("http://www.bing.com").get().map(getLatency) Future.sequence(Seq(googleTime, yahooTime, bingTime)).map { case times => Ok(Json.toJson(Map( "google" -> times(0), "yahoo" -> times(1), "bing" -> times(2), "total" -> getLatency(0)))) } } } {"google":343,"yahoo":3043,"bing":1608,"total":3048} 48 Thursday, March 28, 13 48
  • 49. Test Massimiliano Dessì & Alberto Quario GTUG Sardegna class ApplicationSpec extends Specification { "Application" should { "send 404 on a bad request" in { running(FakeApplication()) { route(FakeRequest(GET, "/boum")) must beNone } } "render the index page" in { running(FakeApplication()) { val home = route(FakeRequest(GET, "/")).get status(home) must equalTo(OK) contentType(home) must beSome.which(_ == "text/html") contentAsString(home) must contain ("Your new application is ready.") } } } } 49 Thursday, March 28, 13 49
  • 50. Test /2 Massimiliano Dessì & Alberto Quario GTUG Sardegna class IntegrationSpec extends Specification { "Application" should { "work in a server" in { running(TestServer(3333)) { await(WS.url("http://localhost:3333").get).status must equalTo(OK) } } "work from within a browser" in { running(TestServer(3333), HTMLUNIT) { browser => browser.goTo("http://localhost:3333/") browser.pageSource must contain("Your new application is ready.") } } } } 50 Thursday, March 28, 13 50
  • 51. Deploy Massimiliano Dessì & Alberto Quario GTUG Sardegna 51 Thursday, March 28, 13 51
  • 52. Deploy /2 Massimiliano Dessì & Alberto Quario GTUG Sardegna Welcome to Play 2.1.0! These commands are available: ----------------------------- classpath Display the project classpath. clean Clean all generated files. compile Compile the current application. console Launch the interactive Scala console (use :quit to exit). dependencies Display the dependencies summary. dist Construct standalone application package. exit Exit the console. h2-browser Launch the H2 Web browser. license Display licensing informations. package Package your application as a JAR. play-version Display the Play version. publish Publish your application in a remote repository. publish-local Publish your application in the local repository. reload Reload the current application build file. run <port> Run the current application in DEV mode. test Run Junit tests and/or Specs from the command line eclipse generate eclipse project file idea generate Intellij IDEA project file sh <command to run> execute a shell command start <port> Start the current application in another JVM in PROD mode. update Update application dependencies. 52 Thursday, March 28, 13 52
  • 53. Massimiliano Dessì & Alberto Quario GTUG Sardegna spray is an open-source toolkit for REST/HTTP and low-level network IO on top of Scala and Akka. aka Scala -IKEA VMWare and Ebay use spray for some internal projects 53 Thursday, March 28, 13 53
  • 54. Routing Massimiliano Dessì & Alberto Quario GTUG Sardegna class PingServiceActor extends Actor { def receive = { case HttpRequest(GET, "/ping", _, _, _) => sender ! HttpResponse(200, "PONG") } } 54 Thursday, March 28, 13 54
  • 55. Routing Massimiliano Dessì & Alberto Quario GTUG Sardegna path with name order => directive route get and put => are inner route ~ =>route concatenation class MyServiceActor extends Actor with Routing { def receive = receiveFromRoute { path("order" / HexIntNumber) { id => get { completeWith { "Received GET for order " + id } } ~ put { completeWith { "Received PUT for order " + id } } } } } 55 Thursday, March 28, 13 55
  • 56. Routing Massimiliano Dessì & Alberto Quario GTUG Sardegna trait LongerService extends HttpService with MyApp { val simpleCache = routeCache(maxCapacity = 1000, timeToIdle = Duration("30 min")) val route = { path("orders") { authenticate(BasicAuth(realm = "admin area")) { user => get { cache(simpleCache) { encodeResponse(Deflate) { complete { getOrdersFromDB } } } } ~ post { (decodeRequest(Gzip) | decodeRequest(NoEncoding)) { entity(as[Order]) { order => detachTo(singleRequestServiceActor) { complete { // ... write order to DB "Order received" } } } } } } } ~ 56 Thursday, March 28, 13 56
  • 57. Routing Massimiliano Dessì & Alberto Quario GTUG Sardegna pathPrefix("order" / IntNumber) { orderId => path("") { // method tunneling via query param (put | parameter('method ! "put")) { // form extraction from multipart or www-url-encoded forms formFields('email, 'total.as[Money]).as(Order) { order => complete { // complete with serialized Future result (myDbActor ? Update(order)).mapTo[TransactionResult] } } } ~ get { jsonpWithParameter("callback") { produce(instanceOf[Order]) { complete => ctx => processOrderRequest(orderId, complete) } } } } ~ 57 Thursday, March 28, 13 57
  • 58. Non-blocking IO Massimiliano Dessì & Alberto Quario GTUG Sardegna def race() { val start = System.currentTimeMillis() def getLatency(r: Any): Long = System.currentTimeMillis() - start val googleFuture = httpClient.ask(Get("http://www.google.com")) .mapTo[HttpResponse].map(getLatency) val yahooFuture = httpClient.ask(Get("http://www.yahoo.com")) .mapTo[HttpResponse].map(getLatency) val bingFuture = httpClient.ask(Get("http://www.example.com")) .mapTo[HttpResponse].map(getLatency) Future.sequence(Seq(googleFuture, yahooFuture, bingFuture)).map { case times => log.info( "google" + times(0) + " yahoo" + times(1) + " bing" + times(2) + " total: "+getLatency(0)) system.shutdown() // stops all actors } } 58 Thursday, March 28, 13 58
  • 59. Test Massimiliano Dessì & Alberto Quario GTUG Sardegna class DemoServiceSpec extends Specification with Specs2RouteTest with DemoService { def actorRefFactory = system "The DemoService" should { "return a greeting for GET requests to the root path" in { Get() ~> demoRoute ~> check { entityAs[String] must contain("Say hello") } } "return a 'PONG!' response for GET requests to /ping" in { Get("/ping") ~> demoRoute ~> check { entityAs[String] === "PONG!" } } "leave GET requests to other paths unhandled" in { Get("/kermit") ~> demoRoute ~> check { handled must beFalse } } "return a MethodNotAllowed error for PUT requests to the root path" in { Put() ~> sealRoute(demoRoute) ~> check { status === MethodNotAllowed entityAs[String] === "HTTP method not allowed, supported methods: GET" } } } } 59 Thursday, March 28, 13 59
  • 60. Massimiliano Dessì & Alberto Quario GTUG Sardegna Q&A 60 Thursday, March 28, 13 60
  • 61. Agenda Massimiliano Dessì & Alberto Quario GTUG Sardegna Thanks for your attention! Massimiliano: @desmax74 Alberto :@realrealbot 61 Thursday, March 28, 13 61