2014/7

[Xitrumことはじめ][基本編] 4.XitrumアプリケーションのScaffoldのソースコードリーディング

Xitrumことはじめ (基本編)

Xitrumことはじめシリーズでは、Xitrumを使ったWebアプリケーション開発を勉強します。

目次はこちら

記事とサンプルコードはMITライセンスでgithubで公開します。

4. XitrumアプリケーションのScaffoldのソースコードリーディング

前回XitrumのScaffoldプロジェクトを動かすところまでやったので、
今回はScaffoldのプロジェクトがどのようなコードで動いているのかを確認していきます。

Xitrumサーバー起動時に以下のようなログが出力されました。

[INFO] Normal routes:
              GET  /  quickstart.action.SiteIndex
              [INFO] Error routes:
              404  quickstart.action.NotFoundError
              500  quickstart.action.ServerError
              

また、ブラウザからサーバにアクセスした時には以下のようなログが出力されました。

[INFO] 0:0:0:0:0:0:0:1 GET / -> quickstart.action.SiteIndex -> 200, 6 [ms]
              [INFO] 0:0:0:0:0:0:0:1 GET /app.css?V0CGnmnzXFV6l7a-UkY_7w -> 200 (static file)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/xitrum/3.16/xitrum.css?mhIAFrxv3tBMQXtHcoYT7w -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/jquery/2.1.1/jquery.js?dAMGCVD0oTvjs9_eBJDuBQ -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/bootstrap/3.2.0/css/bootstrap.css?4pWKTr6RZtuqbFkxGygQIQ -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /whale.png?n0kYGVwRhnQKFvpqLLmf6w -> 200 (static file)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/jquery-validation/1.12.0/additional-methods.js?VMrHLE7MT-YZGBg3T6jSGA -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/sockjs-client/0.3.4/sockjs.js?G6ezG627D2WKnJ3F55SoNQ -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/jquery-validation/1.12.0/jquery.validate.js?MoZJHtxFQR8TR6gNokHx2w -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /xitrum/xitrum.js?BMfHCVrVdosDpgtIlbqZWw -> xitrum.js, queryParams: {BMfHCVrVdosDpgtIlbqZWw: } -> 200, 1 [ms]
              [INFO] 0:0:0:0:0:0:0:1 GET /favicon.ico?BjK0shXmVIuSRS0IsYBdHA -> 200 (static file)
              

quickstart.action.SiteIndexという処理が実施されているように思われます。
試しに存在しないページにリクエストを投げてみます。

> curl http://localhost:8000/unknown
              

以下のような404ページがレスポンスとして帰ってきました。

<!DOCTYPE html>
              <html>
                <head>
                  <meta name="csrf-token" content="0c628c30-967f-4c24-9e9d-234c7ed31a8f"/>
                  <link href="/webjars/xitrum/3.16/xitrum.css?mhIAFrxv3tBMQXtHcoYT7w" type="text/css" rel="stylesheet" media="all"/>
                  <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
                  <title>My new Xitrum project</title>
                  <link rel="shortcut icon" href="/favicon.ico?BjK0shXmVIuSRS0IsYBdHA"/>
                  <link type="text/css" rel="stylesheet" media="all" href="/webjars/bootstrap/3.2.0/css/bootstrap.css?4pWKTr6RZtuqbFkxGygQIQ"/>
                  <link type="text/css" rel="stylesheet" media="all" href="/app.css?V0CGnmnzXFV6l7a-UkY_7w"/>
                </head>
                <body>
                  <div class="container">
                    <h1>
                      <a href="/">My new Xitrum project</a>
                    </h1>
                    <div id="flash">
              
                    </div>
                    <p>This is custom 404 page</p>
              
                  </div>
              
                        <script type="text/javascript" src="/webjars/jquery/2.1.1/jquery.js?dAMGCVD0oTvjs9_eBJDuBQ"></script>
                        <script type="text/javascript" src="/webjars/jquery-validation/1.12.0/jquery.validate.js?MoZJHtxFQR8TR6gNokHx2w"></script>
                        <script type="text/javascript" src="/webjars/jquery-validation/1.12.0/additional-methods.js?VMrHLE7MT-YZGBg3T6jSGA"></script>
              
                        <script type="text/javascript" src="/webjars/sockjs-client/0.3.4/sockjs.js?G6ezG627D2WKnJ3F55SoNQ"></script>
                        <script type="text/javascript" src="/xitrum/xitrum.js?BMfHCVrVdosDpgtIlbqZWw"></script>
              
              
                </body>
              </html>
              

今度はコンソール上のログには以下のようなログが出力されました。
quickstart.action.NotFoundErrorという処理が実施されたようです。

[INFO] 0:0:0:0:0:0:0:1 GET /unknown -> quickstart.action.NotFoundError -> 404, 156 [ms]
              

サーバー起動時に表示されたルーティング情報が意味するところは

  • / というルートはquickstart.action.SiteIndexという処理が対応している
  • 404エラーは、quickstart.action.NotFoundErrorという処理が対応している
  • 500エラーは、quickstart.action.ServerErrorという処理が対応している

ということになります。quickstart.action.SiteIndexとは何でしょうか。
ソースツリー上にはsrc/main/scala/quickstart/actionというディレクトリ内にSiteIndex.scalaというファイルがあります。
ということはquickstart.action.SiteIndexというのはパッケージ名とクラス名ですね。

4-1. Action

では実際にソースコードを見てみます。

SiteIndex.scala

まず、SiteIndex.scalaを見てみます。

package quickstart.action
              
              import xitrum.annotation.GET
              
              @GET("")
              class SiteIndex extends DefaultLayout {
                def execute() {
                  respondView()
                }
              }
              

パーケージ、インポート宣言の他、
SiteIndexというクラスが定義されています。クラス宣言の直前には@GET("")というアノテーションがあります。
メソッドはexecuteというメソッドが1つあり、respondViewという処理を実行するだけです。
SiteIndexDefaultLayoutを継承しているようなのでDefaultLayout.scalaも見てみます。

package quickstart.action
              
              import xitrum.Action
              
              trait DefaultLayout extends Action {
                override def layout = renderViewNoLayout[DefaultLayout]()
              }
              

DefaultLayoutというクラスはxitrum.ActionというAPIを継承し、layoutメソッドをoverrideで指定しています
このクラスはtraitのため、実質的な処理は行っていないようです。

では、Xitrum.Actionとはどういったクラスなのでしょうか。
ソースおよびAPIドキュメントには

abstract def execute(): Unit

Called when the HTTP request comes in. Actions have to implement this method.

とあります。
受け付けたリクエストに対する処理はexecuteメソッドの中に記載すればよいようです。

以上のことをまとめると

  • @GET("") というアノテーションがついたSiteIndexというクラスがある。
  • SiteIndexxitrum.Actionを継承している。
  • SiteIndexexecuteメソッドでrespondViewを実行する。

ということになります。

Error.scala

次にError.scalaを見てみます。
Error.scalaにはNotFoundErrorServerErrorというクラスが定義されています。

package quickstart.action
              
              import xitrum.annotation.{Error404, Error500}
              
              @Error404
              class NotFoundError extends DefaultLayout {
                def execute() {
                  respondView()
                }
              }
              
              @Error500
              class ServerError extends DefaultLayout {
                def execute() {
                  respondView()
                }
              }
              

SiteIndexと同様にアノテーションがあり、xitrum.Actionを継承してexecuteメソッドが実装されています。
ただし、アノテーションはそれぞれ@Error404@Error500となっています。

リクエストを処理するクラスがわかったので、では次にどうやってレスポンスを返しているのかを見てみます。
これまでに見た各Actionはexecuteメソッドの最後にrespondViewという処理を行っています。
なお、executeメソッド自体は:Unitなので返り値ではないようです。

respondViewについてAPIドキュメントおよび、公式ガイドを確認してみます。

def respondView[T <: Action]()(implicit arg0: Manifest[T]): ChannelFuture
              

respondView: レイアウトファイルを使用または使用せずに、Viewテンプレートファイルを送信します

実際のXitrumのソースコードでは

/**
               * @param options specific to the configured template engine
               */
              def respondView(customLayout: () => Any, location: Class[_ <: Action], options: Map[String, Any]): ChannelFuture = {
                val string = renderView(customLayout, location, options)
                respondText(string, "text/html")
              }
              
              def respondView[T <: Action : Manifest](customLayout: () => Any, options: Map[String, Any]): ChannelFuture = {
                respondView(customLayout, getActionClass[T], options)
              }
              
              def respondView[T <: Action : Manifest](customLayout: () => Any): ChannelFuture = {
                respondView(customLayout, getActionClass[T], Map.empty)
              }
              
              def respondView[T <: Action : Manifest](options: Map[String, Any]): ChannelFuture = {
                respondView(layout _, getActionClass[T], options)
              }
              
              def respondView[T <: Action : Manifest](): ChannelFuture = {
                respondView(layout _, getActionClass[T], Map.empty)
              }
              

とあります。
すこし難しいですが、最終的にはrespondText(string, "text/html")にたどり着くようです。
respondTextの処理
レスポンスのContent-typeを指定してボディにstringを設定してクライアントに返していると捉えることができます。

このstringrenderView(customLayout, location, options)の処理結果です。
この時customeLayoutにはDefaultLayout.scalaでoverrideしているrenderViewNoLayout[DefaultLayout]()が、locationにはSiteIndexのクラスが、optionにはMap.emptyが渡されています。

ではrenderViewNoLayoutrenderViewは何をしているのかというと、以下の様な処理があります。(コメントの①、②などは本シリーズの説明用に追記)

https://github.com/xitrum-framework/xitrum/blob/master/src/main/scala/xitrum/view/Renderer.scala#L44-L72

/**
               * Renders the template associated with an action to "renderedTemplate",
               * then calls the layout function.
               *
               * @param options specific to the configured template engine
               */
              def renderView(customLayout: () => Any, location: Class[_ <: Action], options: Map[String, Any]): String = {
                Config.xitrum.template match {
                  case Some(engine) =>
                    renderedView = engine.renderView(location, this, options)  // ①
                    customLayout.apply().toString                              // ②
              
                  case None =>
                    log.warn("No template engine is configured")
                    ""
                }
              }
              

https://github.com/xitrum-framework/xitrum/blob/master/src/main/scala/xitrum/view/Renderer.scala#L76-L92

def renderViewNoLayout(location: Class[_ <: Action], options: Map[String, Any]): String =
                Config.xitrum.template match {
                  case Some(engine) =>
                    val ret = engine.renderView(location, this, options)       // ③
                    renderedView = ret
                    ret
              
                  case None =>
                    log.warn("No template engine is configured")
                    ""
                }
              

いずれもテンプレートエンジンを使用して、Viewを文字列として返却しています。
デフォルトのテンプレートエンジンはxitrum-scalateです。
実際の処理は以下の用になっています。

/**
               * Renders the template at the location identified by the given action class:
               * {{{<scalateDir>/<class/name/of/the/location>.<templateType>}}}
               *
               * Ex:
               * When location = myapp.SiteIndex,
               * the template path will be:
               * src/main/scalate/myapp/SiteIndex.jade
               *
               * @param location      Action class used to identify the template location
               * @param currentAction Will be imported in the template as "helper"
               * @param options       "type" -> "jade"/"mustache"/"scaml"/"ssp", "date" -> DateFormat, "number" -> NumberFormat
               */
              def renderView(location: Class[_ <: Action], currentAction: Action, options: Map[String, Any]): String = {
                val tpe     = templateType(options)
                val relPath = location.getName.replace('.', File.separatorChar) + "." + tpe
                renderMaybePrecompiledFile(relPath, currentAction, options)
              }
              

つまり、テンプレートエンジンはlocationに指定されたActionのクラス名から、テンプレートファイルを探しだしてrenderMaybePrecompiledFileを実行して返しています。
このActionのクラス名とテンプレートファイルのファイル名を一致させることがXitrumの数少ない規約の一つであると考えることができます。
(厳密にはXitrum本体というよりは、Xitrum-scaateの機能といったほうが正確かもしれません。)

4-2. View

ではテンプレートエンジンに渡すViewのテンプレートは実際にどのようなものか見てみます。

└── src
                  └── main
                      └── scalate
                          └── quickstart
                              └── action
                                  ├── DefaultLayout.jade
                                  ├── NotFoundError.jade
                                  ├── ServerError.jade
                                  └── SiteIndex.jade
              

scalateディレクトリ以下に、パッケージ名およびActionのクラス名に対応した.jadeファイルが有ります。

SiteIndex.jade

p
                img(src={publicUrl("whale.png")})
              
              p
                | This is a skeleton for a new
                a(href="http://xitrum-framework.github.io/") Xitrum
                | project.
              
              p If you're new to Xitrum, you should visit:
              
              ul
                li
                  a(href="http://xitrum-framework.github.io/") Xitrum Homepage
                li
                  a(href="http://xitrum-framework.github.io/guide/") Xitrum Guide
              
              p
                | This is a skeleton project, you should modify it to suit your needs.
                | Some important parts of the skeleton:
              
              ul
                li
                  | The program's entry point (
                  code main
                  | function) is in
                  a(href="https://github.com/xitrum-framework/xitrum-new/tree/master/src/main/scala/quickstart/Boot.scala") src/main/scala/quickstart/Boot.scala
                li
                  | Controller actions are in
                  a(href="https://github.com/xitrum-framework/xitrum-new/tree/master/src/main/scala/quickstart/action") src/main/scala/quickstart/action
                  | directory.
                li
                  | View templates are in
                  a(href="https://github.com/xitrum-framework/xitrum-new/tree/master/src/main/scalate/quickstart/action") src/main/scalate/quickstart/action
                  | directory.
                li
                  | Configurations are in
                  a(href="https://github.com/xitrum-framework/xitrum-new/tree/master/config") config
                  | directory.
              

paulliなどScalateテンプレートのシンタックスでhtmlが表現されています。
2行目にあるpublicUrlというのはxitrum.ActionのAPIです。
どうしてxitrum.ActionのAPIがテンプレート内で使えるのか、その仕組はxitrum-scalateテンプレートエンジンにありますが、ここでは一旦その秘密の魔法には目を瞑りましょう。

renderedView = engine.renderView(location, this, options)  // ①
              

①の結果には上記のテンプレートを元に生成したhtml文字列が格納されることがわかりました。
続いて②の処理

customLayout.apply().toString                              // ②
              

の実態は、DefaultLayoutクラス内のoverride def layoutなのでrenderViewNoLayout内の③

val ret = engine.renderView(location, this, options)       // ③
              

になります。
ここではlocationにはDefaultLayoutが指定されているので、テンプレートファイルにはDefaultLayout.jadeが使用されます。

DefaultLayout.jade

- import quickstart.action._
              
              !!! 5
              html
                head
                  != antiCsrfMeta
                  != xitrumCss
              
                  meta(content="text/html; charset=utf-8" http-equiv="content-type")
                  title My new Xitrum project
              
                  link(rel="shortcut icon" href={publicUrl("favicon.ico")})
              
                  link(type="text/css" rel="stylesheet" media="all" href={webJarsUrl("bootstrap/3.2.0/css", "bootstrap.css", "bootstrap.min.css")})
                  link(type="text/css" rel="stylesheet" media="all" href={publicUrl("app.css")})
              
                body
                  .container
                    h1
                      a(href={url[SiteIndex]}) My new Xitrum project
              
                    #flash
                      !~ jsRenderFlash()
                    != renderedView        //④
              
                  != jsDefaults
                  != jsForView
              

こちらのテンプレートもScalateのシンタックスで記述されています。
SiteIndex.jadeはページのコンテンツだけだったのに対し、こちらはhtmlヘッダタグ等の記述もあります。
!=!~に続く部分や、{}で囲まれたコードは、Scalaのコードであるため、値やメソッドの実行結果が入ります。
先ほど①の処理でrenderViewという変数に格納されたSiteIndex.jadeの変換後の文字列を、
このテンプレート内のbodyタグの中で呼び出しています。(④)

図にしてみると以下の様な感じでしょうか。

+-----------------+
              | Layout          |
              |                 |
              | +-------------+ |
              | | Content     | |
              | |             | |
              | +-------------+ |
              +-----------------+
              

SiteIndexrespondViewはレイアウトとしてDefaultLayout.jadeを使用します。
DefaultLayout.jadeによって出力される内容は、HTMLの一番外側なのでこれ以上レイアウトファイルは必要ないため、
renderViewNoLayoutが使用されているということになります。

デフォルトのlayoutメソッド

def layout = renderedView
              

なので、overrideしない場合は上記の図でいうContentのみが返却されることになります。

respondView: レイアウトファイルを使用または使用せずに、Viewテンプレートファイルを送信します

はそういったことを意味していました。

実際に返却されるレスポンスを見てみます。

> curl http://localhost:8000/
              <!DOCTYPE html>
              <html>
                <head>
                  <meta name="csrf-token" content="7c8da946-1b53-47de-8a62-b2d361e96510"/>
                  <link href="/webjars/xitrum/3.16/xitrum.css?mhIAFrxv3tBMQXtHcoYT7w" type="text/css" rel="stylesheet" media="all"/>
                  <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
                  <title>My new Xitrum project</title>
                  <link rel="shortcut icon" href="/favicon.ico?BjK0shXmVIuSRS0IsYBdHA"/>
                  <link type="text/css" rel="stylesheet" media="all" href="/webjars/bootstrap/3.2.0/css/bootstrap.css?4pWKTr6RZtuqbFkxGygQIQ"/>
                  <link type="text/css" rel="stylesheet" media="all" href="/app.css?V0CGnmnzXFV6l7a-UkY_7w"/>
                </head>
                <body>
                  <div class="container">
                    <h1>
                      <a href="/">My new Xitrum project</a>
                    </h1>
                    <div id="flash">
              
                    </div>
                    <p>
                      <img src="/whale.png?n0kYGVwRhnQKFvpqLLmf6w"/>
                    </p>
                    <p>
                      This is a skeleton for a new
                      <a href="http://xitrum-framework.github.io/">Xitrum</a>
                      project.
                    </p>
                    <p>If you're new to Xitrum, you should visit:</p>
                    <ul>
                      <li>
                        <a href="http://xitrum-framework.github.io/">Xitrum Homepage</a>
                      </li>
                      <li>
                        <a href="http://xitrum-framework.github.io/guide/">Xitrum Guide</a>
                      </li>
                    </ul>
                    <p>
                      This is a skeleton project, you should modify it to suit your needs.
                      Some important parts of the skeleton:
                    </p>
                    <ul>
                      <li>
                        The program's entry point (
                        <code>main</code>
                        function) is in
                        <a href="https://github.com/xitrum-framework/xitrum-new/tree/master/src/main/scala/quickstart/Boot.scala">src/main/scala/quickstart/Boot.scala</a>
                      </li>
                      <li>
                        Controller actions are in
                        <a href="https://github.com/xitrum-framework/xitrum-new/tree/master/src/main/scala/quickstart/action">src/main/scala/quickstart/action</a>
                        directory.
                      </li>
                      <li>
                        View templates are in
                        <a href="https://github.com/xitrum-framework/xitrum-new/tree/master/src/main/scalate/quickstart/action">src/main/scalate/quickstart/action</a>
                        directory.
                      </li>
                      <li>
                        Configurations are in
                        <a href="https://github.com/xitrum-framework/xitrum-new/tree/master/config">config</a>
                        directory.
                      </li>
                    </ul>
              
                  </div>
              
                        <script type="text/javascript" src="/webjars/jquery/2.1.1/jquery.js?dAMGCVD0oTvjs9_eBJDuBQ"></script>
                        <script type="text/javascript" src="/webjars/jquery-validation/1.12.0/jquery.validate.js?MoZJHtxFQR8TR6gNokHx2w"></script>
                        <script type="text/javascript" src="/webjars/jquery-validation/1.12.0/additional-methods.js?VMrHLE7MT-YZGBg3T6jSGA"></script>
              
                        <script type="text/javascript" src="/webjars/sockjs-client/0.3.4/sockjs.js?G6ezG627D2WKnJ3F55SoNQ"></script>
                        <script type="text/javascript" src="/xitrum/xitrum.js?BMfHCVrVdosDpgtIlbqZWw"></script>
              
              
                </body>
              </html>
              

bodyタグの中にSiteIndexが展開されているのがわかります。
それ以外にもScalaのコードが展開されて出力されていることがわかります。

4-3. Xitrum-Scalate

では、.jadeのテンプレートファイルに書かれていたScalaのコードの実態は何かを確認します。
1つめは前述した、paulliなどScalateテンプレートの機能
こちらはhtmlタグを出力します。
そしてそれ以外のpublicUrlantiCsrfMetaなどはXitrum-ScalateエンジンによってバインドされたXitrumの機能となります。

jadeファイルはhtmlとして出力されるまえにScalaのコードに変換されています。
そういえばsbtでコンパイル時に以下のログが出力されていました。

[info] Compiling Templates in Template Directory: /Users/oshidatakeharu/Dropbox/DEV/xitrum-tutorial/app/myApp/src/main/scalate
              

先ほどrenderMaybePrecompiledFileという処理が先ほど出てきましたが、このPrecompiledFileこそが、
上記のコンパイルによって生成されたScalaのコードになります。
target/scala-2.11/src_managed/main/scalate/scalate/quickstart/action/以下にあります。

DefaultLayout_jade.scala(抜粋)

/* NOTE this file is autogenerated by Scalate : see http://scalate.fusesource.org/ */
              package scalate.quickstart.action
              
              object $_scalate_$DefaultLayout_jade {
                def $_scalate_$render($_scalate_$_context: _root_.org.fusesource.scalate.RenderContext): Unit = {
                  import _root_.org.fusesource.scalate.support.RenderHelper.{sanitize=>$_scalate_$_sanitize, preserve=>$_scalate_$_preserve, indent=>$_scalate_$_indent, smart_sanitize=>$_scalate_$_smart_sanitize, attributes=>$_scalate_$_attributes}
                  ;{
                    val helper: xitrum.Action = $_scalate_$_context.attribute("helper")
                    import helper._
                    ;{
                      val context: _root_.org.fusesource.scalate.RenderContext = $_scalate_$_context.attribute("context")
                      import context._
              
              
                              import quickstart.action._
              
                      $_scalate_$_context << ( "<!DOCTYPE html>\n<html>\n  <head>\n    " );
                      $_scalate_$_context << ( $_scalate_$_indent ( "    ", $_scalate_$_context.valueUnescaped(
                         antiCsrfMeta
                      ) ) );
              

自動生成されたコードのため人間の目で読むのは困難ですが、
helperと呼ばれる何かがインポートされていることがわかります。
これらはXitrum-Scalateによって自動で挿入されたコードになります。
(紛らわしいですが、import quickstart.action._というのはDefaultLayout.jadeに直接記載された処理になります。)

このhelperというのは、
①の処理でengine.renderView(location, this, options)
に渡したthisに該当し、すなわち現在のActionがバインドされることになります。

そのためJadeファイル内では、ActionのAPIを使用することができるというわけです。

テンプレートエンジンについては今日のところはここまでにしておきます。
Xitrum-Scalateおよびテンプレートエンジンについてはこのシリーズの後半で詳しく掘り下げたいと思います。

4-4. Annotation

さて、ActionがHTMLを返すところ処理の流れがわかったので、
各Actionクラスに使用されているアノテーションについて見てみます。

Scaffoldで使用されているアノテーションは、

  • @GET("")
  • @Error404
  • @Error500

の3種類がありました。

これらはいずれもxitrum.annotation.Routes.scalaパッケージに含まれています。
xitrum.annotationパッケージにはRoutes.scalaの他、Caches.scalaSwagger.scalaがあります。
Routes.scalaにはルーティングに関するアノテーションとして、

  • GET,POST等のHTTPメソッドに由来するアノテーションや、
  • WebSocketおよび、SockJSに関連するもの、
  • FirstLastといった優先順位を制御するもの、
  • Error404Error500
    が定義されています。

Caches.scalaには、
CacheActionDayCachePageHourなど、キャッシュ時間設定に関わるアノテーションが定義されています。

Swagger.scalaには、
SwaggerAPIを使用したドキュメンテーション作成を行うためのアノテーションが定義されています。

Xitrumは起動時にクラスパス内のこれらのルーティングアノテーションをスキャンし、ルーティングテーブルの作成などを行います。
Annotationは1つのクラスに複数使用することもできます。
具体的な使い方は、このシリーズ内で見て行きたいと思います。

4-5. Bootファイル(mainクラス)

Scaffoldに含まれるソースコードはActionとView以外にBoot.scalaというものがあります。

Boot.scala

package quickstart
              
              import xitrum.Server
              
              object Boot {
                def main(args: Array[String]) {
                  Server.start()
                }
              }
              

JVM上で動くScalaプロセス(Javaプロセス)のエントリーポイントはこのmainクラスになります。
実行内容はシンプルでxitrum.Serverstartしているだけとなります。
Xitrumの標準起動は基本はこれだけです。
また、引数としてカスタマイズしたChannelInitializerを渡すこともできます。

4-6. publicディレクトリ

さて、srcディレクトリ以下にどのようなものが含まれるかわかったので、他のディレクトリを見ていきます。
publicディレクトリには静的リソースが含まれています。
ブラウザからhttp://localhost:8000/whale.pngにアクセスするとわかるように
publicディレクトリはURLのルートにマッピングされます。
ちなみにXitrumの静的ファイル配信スピードはNginxに匹敵します。

プログラム中から静的リソースのURLを取得するにはpublicUrlというAPIが提供されています。
SiteIndex.scala内では

img(src={publicUrl("whale.png")})
              

として使用されていました。

そのほか、404.html500.htmlといったファイルがあります。
Scaffoldでは@Error400@Error500アノテーションを使用してカスタムエラーページを作成しているため
これらのファイルが使用されることはありませんが、これらのエラーアノテーションがプロジェクトで使用されていない場合、
エラー発生時にXitrumがpublicディレクトリ内の404.htmlまたは500.htmlを自動的にレスポンスします。

試しに、Errors.scalaから@Error404アノテーションをコメントアウトしてXitrumを再起動してみます。

INFO] Normal routes:
              GET  /  quickstart.action.SiteIndex
              [INFO] Error routes:
              500  quickstart.action.ServerError
              [INFO] Xitrum SockJS routes:
              xitrum/metrics/channel  xitrum.metrics.XitrumMetricsChannel  websocket: true, cookie_needed: false
              

起動時のログには404ルートが含まれていません。
この状態で存在しないルートにリクエストを行うと、404.htmlがレスポンスされます。

> curl http://localhost:8000/notfound
              

4-7. configディレクトリ

最後はconfigディレクトリを見てみます。

├── config
                  ├── akka.conf
                  ├── application.conf
                  ├── flash_socket_policy.xml
                  ├── logback.xml
                  ├── ssl_example.crt
                  ├── ssl_example.key
                  └── xitrum.conf
              

Xitrumは起動時にconfig/application.confというファイルをクラスパス上から探します。
configディレクトリは起動スクリプトでクラスパスに含まれるようになっています。

.conf拡張子はTypeSafeのconfig形式の設定ファイルです。
application.confakka.confxitrum.confをインクルードしています。
ScaffoldプロジェクトはAkkaによるクラスタリングは行わないので、akka.confはログ設定のみとなっています。
xitrum.confがXitrum本体の設定となります。

例えばportについての設定ではhttpサーバーとhttpsがそれぞれ8000,4430を使用するように指定されています。

各設定の詳細やカスタマイズはこのシリーズの後半で詳しく見て行きたいと思います。

confファイルの他には、ログ出力設定用のlogback.xmlがあります。
これはXitrum特有のものではなく一般的な設定となります。


非常に長くなってしまいましたが、Scaffoldのソースコードリーディングはこれで終了です。
次回からは実際にコードを書いていきたいと思います。

[Xitrumことはじめ][基本編] 3.XitrumアプリケーションのScaffoldとプロジェクト構成

Xitrumことはじめ (基本編)

Xitrumことはじめシリーズでは、Xitrumを使ったWebアプリケーション開発を勉強します。

目次はこちら

記事とサンプルコードはMITライセンスでgithubで公開します。

3. XitrumアプリケーションのScaffoldとプロジェクト構成

今回はXitrumアプリケーションのScaffoldを準備するところを紹介します。

3-1. Xitrum-newプロジェクト

Xitrumプロジェクトには開発者が簡単にアプリケーション開発を進めるためのScaffoldとして、
Xitrum-newプロジェクトが用意されています。
では早速ダウンロードします。

> curl -L https://github.com/xitrum-framework/xitrum-new/archive/master.zip -o /tmp/master.zip
              > unzip -d /path/to/workspace/ /tmp/master.zip
              

解凍したファイルはxitrum-new-masterというディレクトリになっているので
任意のアプリケーション名に変更しておきます。

> mv /path/to/workspace/xitrum-new-master /path/to/workspace/myApplicationName
              

プロジェクトはgitリポジトリで管理されているので git clone https://github.com/xitrum-framework/xitrum-new でも取得することができます。

3-2. プロジェクト構成

プロジェクトディレクトリの構成を見てみます。

> cd myApplicationName
              > tree
              .
              ├── README.rst
              ├── build.sbt
              ├── config
              │   ├── akka.conf
              │   ├── application.conf
              │   ├── flash_socket_policy.xml
              │   ├── logback.xml
              │   ├── ssl_example.crt
              │   ├── ssl_example.key
              │   └── xitrum.conf
              ├── project
              │   ├── build.properties
              │   └── plugins.sbt
              ├── public
              │   ├── 404.html
              │   ├── 500.html
              │   ├── app.css
              │   ├── favicon.ico
              │   ├── robots.txt
              │   └── whale.png
              ├── sbt
              │   ├── sbt
              │   ├── sbt-launch-0.13.5.jar
              │   └── sbt.bat
              ├── screenshot.png
              ├── script
              │   ├── runner
              │   ├── runner.bat
              │   ├── scalive
              │   ├── scalive-1.2.jar
              │   └── scalive.bat
              └── src
                  └── main
                      ├── scala
                      │   └── quickstart
                      │       ├── Boot.scala
                      │       └── action
                      │           ├── DefaultLayout.scala
                      │           ├── Errors.scala
                      │           └── SiteIndex.scala
                      └── scalate
                          └── quickstart
                              └── action
                                  ├── DefaultLayout.jade
                                  ├── NotFoundError.jade
                                  ├── ServerError.jade
                                  └── SiteIndex.jade
              
              13 directories, 34 files
              

プロジェクトルートには、
README.rstbuild.sbtscreenshot.png があります。

READMEファイル

README.rstscreenshot.pngはXitrum-newプロジェクト用のドキュメントなので削除します。

> rm README.rst screenshot.png
              

必要に応じてこれから作成するアプリケーションのREADMEファイルを作成しましょう。
拡張子/書式はrstでもmdでも好きなもので構いません。

今回はマークダウン形式のREADMEにします。

> echo "#My Xitrum Application" > README.md
              

build.sbt

build.sbt はsbtプロジェクトの設定ファイルとなります。
以下の(説明)コメントはこの資料用に記載したものとなります。

> cat build.sbt
              
              // (説明)organization,name,versionはプロジェクトの情報に合わせて編集します
              organization := "jp.co.my.company"
              
              name         := "My-Xitrum-Application"
              
              version      := "1.0-SNAPSHOT"
              
              //(説明)scala,javaに関する設定はデフォルトのままでOK
              
              scalaVersion := "2.11.1"
              //scalaVersion := "2.10.4"
              
              scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked")
              
              // Xitrum requires Java 7
              javacOptions ++= Seq("-source", "1.7", "-target", "1.7")
              
              //------------------------------------------------------------------------------
              
              // (説明)libraryDependencies += に続く行はプロジェクトの依存ライブラリが記載されています
              
              // (説明)xitrum
              libraryDependencies += "tv.cntt" %% "xitrum" % "3.16"
              
              // (説明)log出力用にlogbackを使用します。
              // Xitrum uses SLF4J, an implementation of SLF4J is needed
              libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.1.2"
              
              // (説明)logbackの設定をxmlで使用するためのライブラリ
              // For writing condition in logback.xml
              libraryDependencies += "org.codehaus.janino" % "janino" % "2.7.4"
              
              // (説明)デフォルトではbootstrapが内包されています
              libraryDependencies += "org.webjars" % "bootstrap" % "3.2.0"
              
              
              // (説明)デフォルトではテンプレートエンジンはxitrum-scalateを使用します
              // Scalate template engine config for Xitrum -----------------------------------
              
              libraryDependencies += "tv.cntt" %% "xitrum-scalate" % "2.1"
              
              // (説明)Xitrum-Scalateを使用するための設定が記載されています
              // Precompile Scalate templates
              seq(scalateSettings:_*)
              
              ScalateKeys.scalateTemplateConfig in Compile := Seq(TemplateConfig(
                file("src") / "main" / "scalate",
                Seq(),
                Seq(Binding("helper", "xitrum.Action", true))
              ))
              
              // (説明)i18N国際化対応を行うためのxgettextの設定が記載されています
              // xgettext i18n translation key string extractor is a compiler plugin ---------
              
              autoCompilerPlugins := true
              
              addCompilerPlugin("tv.cntt" %% "xgettext" % "1.0")
              
              scalacOptions += "-P:xgettext:xitrum.I18n"
              
              
              // (説明)アプリケーション起動時にconfigディレクトリをクラスパスにふくめるための設定が記載されています
              // Put config directory in classpath for easier development --------------------
              
              // For "sbt console"
              unmanagedClasspath in Compile <+= (baseDirectory) map { bd => Attributed.blank(bd / "config") }
              
              // For "sbt run"
              unmanagedClasspath in Runtime <+= (baseDirectory) map { bd => Attributed.blank(bd / "config") }
              
              // Copy these to target/xitrum when sbt xitrum-package is run
              XitrumPackage.copy("config", "public", "script")
              

build.sbt編集時の注意点として、各行は空行区切りとなっている必要があります。
また、任意のsbt処理を追加することもできます。
詳しくはsbtドキュメントを参考にしてください。

configディレクトリ

configディレクトリには、アプリケーションの各種設定ファイルが含まれます。
最初はデフォルト設定のままで大丈夫です。
設定ファイルにはJSON、properties、conf形式のファイルを使用することができます
新たに設定ファイルを作成する場合configディレクトリに保存します。

projectディレクトリ

sbtの設定、プラグイン設定などが含まれます。
sbtプラグインを追加した場合などに編集します。

publicディレクトリ

フロントエンドの静的リソースが含まれます。
静的ファイルを配信する場合はこのディレクトリに保存します。

sbtディレクトリ

sbtコマンドがバンドルされています。

scriptディレクトリ

アプリケーション起動用のスクリプトや、デバッグツールのScaliveがバンドルされています。

srcディレクトリ

アプリケーションのソースコードが含まれます。
デフォルトではquickstartというパッケージ名で、インデックスページとエラーページが含まれています。
アプリケーション開発時にはこのディレクトリ以下にパッケージ、クラス、テンプレートを保存します。

3-3. アプリケーションの起動とsbtコマンドについて

開発時のコンパイルやプロジェクトに必要なライブラリのダウンロードなどはsbtコマンドから実行できます。(IDEについては後述)
sbtの起動ファイルと本体はXitrum-newプロジェクトにバンドルされているものを使います。

sbtコンソールの起動

> sbt/sbt
              [info] Loading project definition from /Users/oshidatakeharu/Dropbox/DEV/xitrum-tutorial/app/myApp/project
              [info] Updating {file:/Users/oshidatakeharu/Dropbox/DEV/xitrum-tutorial/app/myApp/project/}myapp-build...
              [info] Resolving org.fusesource.jansi#jansi;1.4 ...
              [info] Done updating.
              [info] Set current project to My-Xitrum-Application (in build file:/Users/oshidatakeharu/Dropbox/DEV/xitrum-tutorial/app/myApp/)
              > help
              

では早速動かしてみましょう。
build.sbtの内容からXitrum本体を含め、依存ライブラリのダウンロードがはじまります。
初回はこれに少し時間がかかります。

> run
              [info] Updating {file:/Users/oshidatakeharu/Dropbox/DEV/xitrum-tutorial/app/myApp/}myapp...
              [info] Resolving org.slf4j#slf4j-api;1.6.1 ...
              [info] downloading http://repo1.maven.org/maven2/tv/cntt/xitrum_2.11/3.16/xitrum_2.11-3.16.jar ...
              

依存ライブラリのダウンロードが完了するとまずはテンプレートのコンパイルが行われます。

[info]     [SUCCESSFUL ] org.codehaus.janino#commons-compiler;2.7.4!commons-compiler.jar (722ms)
              [info] Done updating.
              [info] Compiling Templates in Template Directory: /Users/oshidatakeharu/Dropbox/DEV/xitrum-tutorial/app/myApp/src/main/scalate
              

次はソースコードのコンパイルが行われます。

[info] Compiling 8 Scala sources to /Users/oshidatakeharu/Dropbox/DEV/xitrum-tutorial/app/myApp/target/scala-2.11/classes...
              

コンパイルが終了すると、アプリケーションのMainメソッドが実行されます。
ScaffoldのMainメソッドはquickstartというパッケージのBootというクラスに記載されています。
Xitrumは起動時にルーティングを収集し(キャッシュが存在する場合はキャッシュから)、収集されたルーティングがログ表示されます。
ScaffoldにはSiteIndexという通常のルートと(Normal routes:)、404、500のエラールート(Error routes:)、そしてXitrumが提供するルート(Xitrum routes:)が含まれています。
ルーティングの収集が終わるとサーバが起動します。
デフォルトでは 8000(http)と4430(https)ポートが使用されていますので

[info] Running quickstart.Boot
              [INFO] Slf4jLogger started
              [INFO] Load routes.cache or recollect routes...
              [WARN] Cannot introspect on class loader: sbt.classpath.ClasspathFilter@6cbebc49 of type sbt.classpath.ClasspathFilter
              [INFO] Glokka actor registry "xitrum.sockjs.SockJsAction$" starts in local mode
              [INFO] Glokka actor registry "metrics" starts in local mode
              [INFO] Normal routes:
              GET  /  quickstart.action.SiteIndex
              [INFO] Error routes:
              404  quickstart.action.NotFoundError
              500  quickstart.action.ServerError
              [INFO] Xitrum SockJS routes:
              xitrum/metrics/channel  xitrum.metrics.XitrumMetricsChannel  websocket: true, cookie_needed: false
              [INFO] Xitrum routes:
              GET        /xitrum/xitrum.js                                           xitrum.js
              GET        /webjars/swagger-ui/2.0.17/index                            xitrum.routing.SwaggerUiVersioned
              GET        /xitrum/metrics/channel                                     xitrum.sockjs.Greeting
              GET        /xitrum/metrics/channel/:serverId/:sessionId/eventsource    xitrum.sockjs.EventSourceReceive
              GET        /xitrum/metrics/channel/:serverId/:sessionId/htmlfile       xitrum.sockjs.HtmlFileReceive
              GET        /xitrum/metrics/channel/:serverId/:sessionId/jsonp          xitrum.sockjs.JsonPPollingReceive
              POST       /xitrum/metrics/channel/:serverId/:sessionId/jsonp_send     xitrum.sockjs.JsonPPollingSend
              WEBSOCKET  /xitrum/metrics/channel/:serverId/:sessionId/websocket      xitrum.sockjs.WebSocket
              POST       /xitrum/metrics/channel/:serverId/:sessionId/xhr            xitrum.sockjs.XhrPollingReceive
              POST       /xitrum/metrics/channel/:serverId/:sessionId/xhr_send       xitrum.sockjs.XhrSend
              POST       /xitrum/metrics/channel/:serverId/:sessionId/xhr_streaming  xitrum.sockjs.XhrStreamingReceive
              GET        /xitrum/metrics/channel/info                                xitrum.sockjs.InfoGET
              WEBSOCKET  /xitrum/metrics/channel/websocket                           xitrum.sockjs.RawWebSocket
              GET        /xitrum/metrics/viewer                                      xitrum.metrics.XitrumMetricsViewer
              GET        /xitrum/metrics/channel/:serverId/:sessionId/websocket      xitrum.sockjs.WebSocketGET
              GET        /xitrum/metrics/channel/:iframe                             xitrum.sockjs.Iframe
              POST       /xitrum/metrics/channel/:serverId/:sessionId/websocket      xitrum.sockjs.WebSocketPOST
              [INFO] HTTP server started on port 8000
              [INFO] HTTPS server started on port 4430
              [INFO] Xitrum 3.16 started in development mode; routes and classes in directories List(/Users/oshidatakeharu/Dropbox/DEV/xitrum-tutorial/app/myApp/target/scala-2.11/classes, /Users/oshidatakeharu/Dropbox/DEV/xitrum-tutorial/app/myApp/config) will be reloaded
              [WARN] *** For security, change secureKey in config/xitrum.conf to your own! ***
              

ブラウザで http://localhost:8000/にアクセスしてみましょう。
Indexページが表示されればXitrumは正常に稼働しています。

コンソール上には以下のようなログが出力されます。
ルートへのGETリクエスト後にページ内のCSSやJavaScriptを取得するリクエストが発生していることがわかります。

[INFO] 0:0:0:0:0:0:0:1 GET / -> quickstart.action.SiteIndex -> 200, 6 [ms]
              [INFO] 0:0:0:0:0:0:0:1 GET /app.css?V0CGnmnzXFV6l7a-UkY_7w -> 200 (static file)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/xitrum/3.16/xitrum.css?mhIAFrxv3tBMQXtHcoYT7w -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/jquery/2.1.1/jquery.js?dAMGCVD0oTvjs9_eBJDuBQ -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/bootstrap/3.2.0/css/bootstrap.css?4pWKTr6RZtuqbFkxGygQIQ -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /whale.png?n0kYGVwRhnQKFvpqLLmf6w -> 200 (static file)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/jquery-validation/1.12.0/additional-methods.js?VMrHLE7MT-YZGBg3T6jSGA -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/sockjs-client/0.3.4/sockjs.js?G6ezG627D2WKnJ3F55SoNQ -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /webjars/jquery-validation/1.12.0/jquery.validate.js?MoZJHtxFQR8TR6gNokHx2w -> 200 (JAR resource)
              [INFO] 0:0:0:0:0:0:0:1 GET /xitrum/xitrum.js?BMfHCVrVdosDpgtIlbqZWw -> xitrum.js, queryParams: {BMfHCVrVdosDpgtIlbqZWw: } -> 200, 1 [ms]
              [INFO] 0:0:0:0:0:0:0:1 GET /favicon.ico?BjK0shXmVIuSRS0IsYBdHA -> 200 (static file)
              

その他のsbtコマンドについて

使用可能なsbtコマンドはsbtコンソールで<タブキー>を2回押すことで一覧表示可能です。

> <tab><tab>
              > Display all 289 possibilities? (y or n) y
              

sbtコマンドに続けてコマンドを入力することでsbtコンソールを省略することができます。
また、;や~をオプションとして使用することもできます。

; <command> (; <command>)*              Runs the provided semicolon-separated commands.
              ~ <command>                             Executes the specified command whenever source files change.
              

Xitrumアプリケーション開発で主に使用するsbtコマンドはあまり多くないので以下のコマンドさえ覚えておけば問題ありません。

  • clean
  • compile
  • run
  • xitrum-package
  • console

3-4. IDE向け設定ファイルの生成

コマンドラインとテキストエディタのみでも開発を行うことは可能ですが、
このシリーズではIDEとしてScala IDE(Eclipse)を使用します。
IDEでインポートするためにメタファイルが必要となりますが、sbtで生成することができます。

Eclipse向けの.projectディレクトリを生成するには

> sbt eclipse
              

InteliiJ iDE向けの .ideaディレクトリを生成するには

> sbt gen-idea
              

を実行することで各IDEからインポートすることが可能となります。

3-5. gitリポジトリの初期化

以下のような.gitignoreファイルを作成します。

.*
              log
              project/project
              project/target
              routes.cache
              target
              tmp
              

リポジトリを初期化します。

> git init
              > git add -A
              > git commit -m "Happy to start Xitrum development!"
              

あとはgithubやbitbucketに追加するなりご自由に。

[Xitrumことはじめ][基本編] 2.Xitrumアプリケーション開発環境の構築

Xitrumことはじめ (基本編)

Xitrumことはじめシリーズでは、Xitrumを使ったWebアプリケーション開発を勉強します。

目次はこちら

記事とサンプルコードはMITライセンスでgithubで公開します。

2. Xitrumアプリケーション開発環境の構築

Xitrumを使ったWebアプリケーション開発を行うための環境構築をおこないます。

2014/07/25現在の

  • Xitrumの安定バージョンは 3.16(π)
  • Scalaの安定バージョンは 2.11.2

を使用していきます。
また、筆者はMacOSXを使用しています。WindowsやLinux環境で実施する場合は、コマンドやパスなど適宜変更してください。

2-1. 前提条件

本シリーズを進める上でGitやJDK、Scalaのインストール手順については細かく触れません。
以下の参考資料をもとに適宜インストールしてください。

Javaについては今回はJava7を使用します。ただし、Java8でも動くことでしょう。
また、OracleJDKを使用します。OpenJDKでも動作はしますが、
FileMonitorに関わる機能や、ScaliveなどOracleJDKでしか使用できない機能があるため、OracleJDKを使用することを推奨します。

2-2. Scala IDEのインストール

今回はEclipseベースのScala IDEを使用します。
ダウンロードページに各マシン環境向けのzipファイルがあるため、For Scala 2.11.2というところから
ダウンロードします。
インストールは簡単です。ダウンロードしたzipファイルを展開して、eclipseというフォルダ内のEclipse.appを起動するだけです。

wget http://downloads.typesafe.com/scalaide-pack/3.0.4.vfinal-211-20140723/scala-SDK-3.0.4-2.11-2.11-macosx.cocoa.x86_64.zip
              unzip scala-SDK-3.0.4-2.11-2.11-macosx.cocoa.x86_64.zip
              rm scala-SDK-3.0.4-2.11-2.11-macosx.cocoa.x86_64.zip
              mv -R eclipse Applications/ScalaIDE
              

2014/07/26現在の最新版は3.0.4で以下の内容が含まれます。

Content

  • Eclipse 4.3.1 (Kepler)
  • Scala IDE 3.0.3/3.0.4
  • Sbt 0.13.2
  • Scala Worksheet 0.2.3
  • Play Framework support 0.4.3 (Scala 2.10 only)
  • m2eclipse-scala Maven connector 0.4.3
  • access to the full Scala IDE ecosystem

Scala IDEの他にもScalaの開発環境はEclipseIntelligent IDEActivatorなどがあり、どれを使用しても開発を行うことは可能です。
ちなみに、Xitrum作者のNgocが主に使用しているのはEclipseです。

さあこれでScala開発をおこなう準備が完了しました。
基本的にはXitrumアプリケーションの開発にはこれ以外に特別な準備は必要ありません。
以降必要な外部ライブラリなどはsbtでダウンロードを行うことになります。

2-3. 実行環境の準備

Xitrumアプリケーションは基本的にはJVM(Java7+)がある環境であればどこでも動かすことができます。
開発時はローカルマシン上での動作確認を行うことができます。
その他のミドルウェアの準備は必要ありません。(サンプルアプリケーション作成時にMongoDBが必要になります。)
もちろんNginxやHAProxyをリバースプロキシとしてXitrumと併用することも可能です。

ちなみにVXiMはXitrum(とMongoDB)を簡単に動かすVagrantBOXとなりますので、
興味があれば使ってみてください。

サーバーへデプロイする場合も基本的にはJVM以外は必要ありませんし、OSの制約もありません
Xitrumをプロダクション環境へで使用しているサービスには、
オンプレミスで運用しているケース、Amazon EC2の他、Google Compute EngineHerokuCloudNなどのクラウドサービス上で動いているものがあります。

[Xitrumことはじめ][基本編] 1.Xitrumと関連プロジェクトについて

Xitrumことはじめ (基本編)

Xitrumことはじめシリーズでは、Xitrumを使ったWebアプリケーション開発を勉強します。

目次はこちら

記事とサンプルコードはMITライセンスでgithubで公開します。

1. Xitrumと関連プロジェクトについて

今回はXitrumと関連プロジェクトについて簡単に紹介します。

1-1. Xitrumについて

Xitrumは NettyAkka をベースに構築された非同期でスケーラブルなHTTP(S) WEBフレームワークです。

NettyやAkkaといった低レイヤの強力なライブラリをWebアプリケーション開発者が使用しやすいカタチで提供してくれ、
Webアプリケーション構築に必要な機能(例えばルーティング)をとても簡単なAPIで実現することができます。
非同期処理やルーティングなど、難しいことはXitrumに任せてアプリケーション開発者は、
アプリケーションロジックにのみ集中して取り組むことができます。

このシリーズでもXitrumが内部で何をやっているかにはあまり触れず、Xitrumが提供するAPIの使い方を中心に紹介したいと思います。

また、XitrumはいわゆるMVCフレームワークではありません。そのため、Ruby on Railsのような規約はほとんどありません。
クラスはXitrumの提供するクラスを継承してさえいれば、自由につくることができます。
Actionの中にhtmlを書いてしまうこともできますし、テンプレートファイル内にロジックを含めることもできます。
また、XitrumにはHibernateやActiveRecordのようなORマッパー機能は含まれません。
あくまでもXitrumはルーティングを元にリクエスト・レスポンスを処理するサーバー機能にフォーカスされており、
アプリケーションロジックやプログラミングのスタイルについては開発者に委ねられています。

そのほかのXitrumの特徴は公式ページにまとめられています。

1-2. 関連プロジェクト

Project リポジトリにはいくつかの関連プロジェクトとして、
デモアプリケーションプロジェクトの他、Xitrumが内部で使用しているライブラリ、テンプレートライブラリ、プラグイン、デバッグツールなどとなどがあります。

開発者がXitrumアプリケーションを作成し始める時に必要となるプロジェクトは、
Project スケルトンであるXitrum-newとなります。

Xitrum-newプロジェクトのbuild.sbtにはアプリケーションが直接依存するライブラリが記載されています。
このなかにXitrumが含まれています。
Xitrumプロジェクト本体のbuild.sbtにはXitrumが依存するライブラリが記載されています。

1-3. リンク

Project リポジトリ
公式ページ
公式ガイド
APIドキュメント
デモページ
コミュニティ

[Xitrumことはじめ] 目次

Xitrumことはじめ

このシリーズでは、Xitrumを使ったWebアプリケーション開発を勉強します。

目次(随時更新)

0. はじめに

このシリーズはXitrumを使ったWebアプリケーション開発を通じて
Xitrumの普及、筆者自身のScala/Xitrum/Web開発スキルアップを目指します。

2014/07/25現在の

  • Xitrumの安定バージョンは 3.16
  • 2014/08/02 Xitrumの安定バージョンは 3.17
  • 2014/08/27 Xitrumの安定バージョンは 3.18
  • Scalaの安定バージョンは 2.11.2

を対象としていますが、バージョンアップがあった場合は適宜対応したいと考えています。

シリーズの構成はRuby on Rails チュートリアルのようなユーザー管理ができるブログアプリケーション作成をメインに
Xitrumガイドのトピックや筆者自身が勉強・紹介したい項目を随時追加していきます。

ライセンス

記事とサンプルコードはMITライセンスでgithubで公開します。
Copyright © 2014 by Takeharu.Oshida.

  • Jul
  • 9
  • 2014

IT

Xitrum 3.16

Xitrum 3.16 Released!

https://groups.google.com/d/msg/xitrum-framework/r_Dtq1F4Ipg/2Ejtp1bDqfgJ

  • AutoReload機能に起因するJSONシリアライズ/デシリアライズに伴う不具合を修正しました。(https://github.com/xitrum-framework/xitrum/issues/428)
  • AutoReload機能の改修が含まれます。これはdevモードではtarget/<scala-version>/xitrum以下だけでなく、クラスパスに含まれる全ての.classファイルを監視することができるように成りました。これによってマルチモジュールなSBTプロジェクトの依存性を解決できるように成りました。

Xitrum 3.15から3.16へのアップデート

build.sbt

  • xitrumバージョンを3.16に変更します

例:
https://github.com/xitrum-framework/xitrum-new/commit/dd920dc75d1999816a02144430c8623649c05df1

  • Jul
  • 6
  • 2014

Xitrum 3.15

Xitrum 3.15 Released!

https://groups.google.com/d/msg/xitrum-framework/sN10h-p785Y/sXA43G2uJk4J

  • デベロップメントモードでのクラスファイルのオートリロードと、ルーティングの再収集機能の改善
  • date型とnumber型において、Scalateテンプレートエンジンが、現在の言語環境のデフォルトフォーマットを使用するようになりました。
  • NettyとAkkaの最新安定バージョンへの対応



Xitrum 3.14から3.15へのアップデート

build.sbt

  • xitrumバージョンを3.15に変更します
  • xitrum-scalateを2.1に変更します(Scalateテンプレートエンジンを使用している場合)
config/xitrum.conf

  • "tmpDir = ./tmp" を追記します
  • "tmpUploadDir = ./upload" を削除します

project/plugins.sbt

  • xitrum-packageを1.8に変更します(xitrum-packageはSBTのマルチモジュールプロジェクトをサポートしています)

例:
https://github.com/xitrum-framework/xitrum-new/commit/cc401b77cec6bb4b558e5c4f6980dcfbfd8f85ef