1
votes

I'm starting to learn Play,

and i'm stuck in trying to understand how Action is implemented. I just don't understand the language construct and that really frustrate me.....

I don't understand how one can write ?

val echo = Action { request => Ok("Got request [" + request + "]") }

And have it compile .... What kind of construct is that ? It would be a case class that take as parameter a function, i might have.....

But here is the definition of Action at https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/play/api/mvc/Action.scala

Which basically state that Action is a function object Trait that either takes a requestHeader or a Request by virtue of the apply taken from Essential action and the one that it defines itself....

/**
 * An `EssentialAction` underlies every `Action`. Given a `RequestHeader`, an
 * `EssentialAction` consumes the request body (an `Array[Byte]`) and returns
 * a `Result`.
 *
 * An `EssentialAction` is a `Handler`, which means it is one of the objects
 * that Play uses to handle requests.
 */
trait EssentialAction extends (RequestHeader => Iteratee[Array[Byte], Result]) with Handler {

  /**
   * Returns itself, for better support in the routes file.
   *
   * @return itself
   */
  def apply() = this

}

/**
 * Helper for creating `EssentialAction`s.
 */
object EssentialAction {

  def apply(f: RequestHeader => Iteratee[Array[Byte], Result]): EssentialAction = new EssentialAction {
    def apply(rh: RequestHeader) = f(rh)
  }
}

/**
 * An action is essentially a (Request[A] => Result) function that
 * handles a request and generates a result to be sent to the client.
 *
 * For example,
 * {{{
 * val echo = Action { request =>
 *   Ok("Got request [" + request + "]")
 * }
 * }}}
 *
 * @tparam A the type of the request body
 */
trait Action[A] extends EssentialAction {

  /**
   * Type of the request body.
   */
  type BODY_CONTENT = A

  /**
   * Body parser associated with this action.
   *
   * @see BodyParser
   */
  def parser: BodyParser[A]

  /**
   * Invokes this action.
   *
   * @param request the incoming HTTP request
   * @return the result to be sent to the client
   */
  def apply(request: Request[A]): Future[Result]

  def apply(rh: RequestHeader): Iteratee[Array[Byte], Result] = parser(rh).mapM {
    case Left(r) =>
      Play.logger.trace("Got direct result from the BodyParser: " + r)
      Future.successful(r)
    case Right(a) =>
      val request = Request(rh, a)
      Play.logger.trace("Invoking action with request: " + request)
      Play.maybeApplication.map { app =>
        play.utils.Threads.withContextClassLoader(app.classloader) {
          apply(request)
        }
      }.getOrElse {
        apply(request)
      }
  }(executionContext)

I'm not able to reproduce that myself, with a simple case it does not compile that is damn strange....

2

2 Answers

2
votes

What you need to look at is the Action object and this apply method which it inherits.

1
votes

In scala, we can invoke Action with a function block:

Action { request => ..... }

This is rewritten as:

Action.apply({ request => ... })

You may be wondering what the implicit keyword is doing. It's a shorthand convenince to make the argument to a function available on the implciit scope within the function. In other words:

Action apply { implicit request => ... }

is the same as:

Action apply { request => implicit val _some_random_name_ = request ... }

Quoted from here: https://groups.google.com/forum/#!topic/scala-user/sR-FD3eiUcQ