Play Frameworkのソースコードリーディング Action周り

# 今回のゴール

以下のコードの舞台裏を理解することが今回のゴール。


```scala
val hello = Action {
  Ok("hello")
}

def echo = Action { request =>
  Ok("Got [" + request.body + "]")
}
```

なお、対象のPlay Frameworkのバージョンは2.3.2。

# はじめに
Actionがやることは一言でいうとHTTPリクエストを受け取ってHTTPレスポンスを返す、要はこれ。
Play Frameworkでこれを実施するにあたってHTTPリクエストとHTTPレスポンスに該当するものを先に整理しておく。

## HTTPリクエスト
- [play.api.mvc.RequestHeader](http://www.playframework.com/documentation/2.3.0/api/scala/index.html#play.api.mvc.RequestHeader)
- [play.api.mvc.Request](http://www.playframework.com/documentation/2.3.0/api/scala/index.html#play.api.mvc.Request)

RequestはRequestHeaderを継承しており、両者の違いは前者がbodyなし、後者はbodyありということ。
以下のように記述した際のrequestの型はリクエストボディ部のパースが行われた後者のRequest型の方となる。

```
def myAction = Action { request =>
```

※但し、Request型といってもGET時はそもそもbodyが無いので```body.asText```とやっても何も取れない。

## HTTPレスポンス
- [play.api.mvc.Result](http://www.playframework.com/documentation/2.3.0/api/scala/index.html#play.api.mvc.Result)

Resultの定義は以下で、構成要素として主にレスポンスヘッダとバイト配列のボディからなることが分かる。

```scala
case class Result(header: ResponseHeader, body: Enumerator[Array[Byte]], connection: HttpConnection.Connection = HttpConnection.KeepAlive) {
```

Enumeratorでくるまれているのは、通常HTTPレスポンスはArray[Byte]が一発で返るというよりもむしろ複数回に分けて返されることが多いからで、その辺の仕組みが提供されている。
もちろんレスポンスだけでなく、リクエストボディも同様である。
ここについては「やさしいIteratee入門」が分かりやすいので読みましょう。
http://www.slideshare.net/TakashiKawachi/iteratee

# Ok("hello")
さて、```Ok("hello")```の部分から見ていくことにする。

このOkは[Resultsトレイト内](https://github.com/playframework/playframework/blob/2.3.0/framework/src/play/src/main/scala/play/api/mvc/Results.scala#L572-L703)に宣言されているStatusクラスのインスタンスである。

```scala
/** Generates a ‘200 OK’ result. */
val Ok = new Status(OK)
```

この他にもNotFound(404)やServiceUnavailable(503)なども定義されている。

このStatusというクラスは同じくResultsトレイト内にて定義されている。

```scala
class Status(status: Int) extends Result(header = ResponseHeader(status), body = Enumerator.empty, connection = HttpConnection.KeepAlive) {
```

なお、```new Status(OK)```のOKは以下のStandardValues.scalaに宣言されている、Statusの定数。
https://github.com/playframework/playframework/blob/2.3.0/framework/src/play/src/main/scala/play/api/http/StandardValues.scala

StandardValues.scalaにはステータスコードを表すStatus以外にも

- MimeTypes("text/html"や"application/octet-stream"など)
- ContentTypes("text/html; charset=utf-8"など)
- HttpVerbs("GET"や"POST"など)
- HeaderNames("Accept-Language"や"ETag"など)
- HttpProtocols("HTTP/1.1"など)

といった各種定数クラスが用意されている。
これらtraitはControllerにmix-inされているので、使用したい場合はAtion定義時にimportなしで使用することが出来る。覚えておくといいだろう。

```scala
trait Controller extends Results with BodyParsers with HttpProtocol with Status with HeaderNames with ContentTypes with RequestExtractors with Rendering {
```

で、話は戻って```Ok("hello")```、これはStatusインスタンスOkに("hello")とやっているわけで、要はStatus#applyを実行している。

```scala
def apply[C](content: C)(implicit writeable: Writeable[C]): Result = {
  Result(
    ResponseHeader(status, writeable.contentType.map(ct => Map(CONTENT_TYPE -> ct)).getOrElse(Map.empty)),
    Enumerator(writeable.transform(content))
  )
}
```

ここで実際にResultを生成して返している。
statusコード、content-type、レスポンスボディ部が定義される。

Writeableは型パラメータになっているのでコンパイル時に型に応じた適切なものが適用される。
今回は"hello"を渡しているのでcontentはString型となり[Writeable[String]](https://github.com/playframework/playframework/blob/2.3.0/framework/src/play/src/main/scala/play/api/http/Writeable.scala)となる。

この他に、Writeable[JsValue]、Writeable[Xml]、Writeable[Array[Byte]]などがある。

# Action
次にAction部。

```scala
Action {
  Ok("hello")
}
```

これは[object Action](https://github.com/playframework/playframework/blob/2.3.0/framework/src/play/src/main/scala/play/api/mvc/Action.scala#L555-L557)のapplyメソッドを実行している。
Actionオブジェクトの宣言部は以下。

```scala
object Action extends ActionBuilder[Request] {
  def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = block(request)
}
```

ここではapplyが定義されていないので実際は継承元のActionBuilderのapplyが呼ばれている。

```scala
final def apply(block: => Result): Action[AnyContent] = apply(_ => block)
```

applyの引数はResult。
AnyContentなActionインスタンスを返すのがこのapply関数だということが分かる。
さらにチェーンして、

```scala
final def apply(block: R[AnyContent] => Result): Action[AnyContent] = apply(BodyParsers.parse.anyContent)(block)
```

冒頭の例のこっちのタイプなら上記applyから始まる。Requestを受け取ってResultを返す関数が引数。

```scala
Action{ request =>
  Ok("Got [" + request.body + "]")
}
```
さらにチェーンして、

```scala
final def apply[A](bodyParser: BodyParser[A])(block: R[A] => Result): Action[A] = async(bodyParser) { req: R[A] =>
    Future.successful(block(req))
```

bodyParserが登場。ここは最後に取り上げるが、役割はHTTPリクエストのbody部をパースしてArray[Byte]からStringやXmlを生成すること。
さらにチェーンして、

```scala
final def async[A](bodyParser: BodyParser[A])(block: R[A] => Future[Result]): Action[A] = composeAction(new Action[A] {
  def parser = composeParser(bodyParser)
  def apply(request: Request[A]) = try {
    invokeBlock(request, block)
  } catch {
    // NotImplementedError is not caught by NonFatal, wrap it
    case e: NotImplementedError => throw new RuntimeException(e)
    // LinkageError is similarly harmless in Play Framework, since automatic reloading could easily trigger it
    case e: LinkageError => throw new RuntimeException(e)
  }
  override def executionContext = ActionBuilder.this.executionContext
})
```

これがapplyチェーンの最後で、ここでようやくActionインスタンスが生成されて返ることになる。
なお、asyncということで戻りもこれまでのResultからFuture[Result]になっているものの、このapplyが呼ばれる前のapplyで、```Future.successful(block(req))```とやっていることから実行済みFutureを作成しているので(通常呼び出し時は)本スレッドと別にblockが並列実行されるわけではない事がわかる。

ActionインスタンスのinvokeBlockで定義したblockが使われているのが見て取れる。ActionインスタンスにRequestインスタンスが渡ってきた時に定義したblock部が実行される。

## まとめ
一度ここでまとめると、上記でも少し触れたが以下のコードは、

```scala
def echo = Action { request =>
  Ok("Got [" + request.body + "]")
}
```

**object ActionのapplyにRequest => Resultな関数を渡すことでActionインスタンスを生成している**ということ。

実際に処理されるActionクラスの方の[apply](https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/play/api/mvc/Action.scala#L121-L135)を見てみると以下のようになっている。

```scala
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)
```

ここを理解するにはBodyParserを理解する必要がありそうだ。

# BodyParserとAnyContent
長くなったので分けました。
続きは[こちら](http://qiita.com/mtoyoshi/items/a5fcfb01a9bb56b2a492)。