Takuya71 のぶろぐ

外資系ソフトウェア会社で働いてます、認定スクラムマスター

scalatra で作ったプロジェクトを stand alone で使用できるように

scalatra で作ったプロジェクトを jetty の stand alone 環境で使用できるようにする。

jetty を組込み standalone で使いたい。

仕事のチーム内の情報共有用のサイトを scalatra で作ってみたのですが、実際に稼働させるのに jetty の standalone な状態で稼働させたいので scalatra のGuide の deployment -> standalone を参考に設定しました。

まずは jetty ランチャーをドキュメント通りに追加。 次に project/build.scala を これまた ドキュメント通りに変更 その後 プロジェクト全体を一つの jar ファイルにまとめて実行できるように sbt のプラグインである sbt-assembly を組み込む。

project/plugins.sbt に

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.9.0")

を追加

build.sbt

import AssemblyKeys._

import sbtassembly.Plugin._

seq(assemblySettings: _*)

test in assembly := {}

mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
  {
    case PathList("META-INF", xs @ _*) => MergeStrategy.discard
    case _ => MergeStrategy.first
  }
}

mergeStrategy の設定はファイルが重複した場合にどれを優先するかの設定となります。

jar ファイル作成

sbt clean assembly

で target/scala2.10/ の下に **-assembly-**.jar というファイルが作成されました。
作成に結構時間がかかりました。10分ぐらい。

実行

java -jar **-assembly-**.jar

localhost:8080 にアクセスしてみる。
動いているが。。。

問題発生

css がまったく反映されてません。。。
かなり 質素な感じになってます。
Javascript も image も読み込めてませんし。
どうやら
CSS,JS,IMG のディレクトリに格納しているファイルが読めてない
ようです。
そんなの 見たままで当たり前か。

どう設定する

どうやって 使えるようにするのか
今まで tomcat ばかり使っていて jetty 単独で使ったことなかったので
ちょっとはまりましたが jetty のランチャーの設定に {css,js,img}へアクセスできるように
サーブレットの設定を追加するのと、それらをサーブレットがそれらを読み込む設定を行う必要があるようです。

JettyLaunchar.scala を変更

css,js,img については src/main/webapp/{css,js,img} という構造でディレクトリを作っています。

[src]   
 -> [main]   
    -> [webapp]   
       -> [WEB-INF]   
       -> [css]   
       -> [js]   
       -> [img]   

これらの ディレクトリの内容にアクセスできるように、最初にドキュメントの見て作った JettyLaunchar.scala を修正します。

FROM

context.addServlet(classOf[DefaultServlet],"/")
…

TO

context.addServlet(classOf[DefaultServlet],"/")
context.addServlet(new ServletHolder(new DefaultServlet), "/css/*")
context.addServlet(new ServletHolder(new DefaultServlet), "/js/*")
context.addServlet(new ServletHolder(new DefaultServlet), "/img/*")

{css,js,img} 用に addServlet で追加します。

最終的には 上のように 3つ追加するのもアレなので、src/main/webapp/assets を作りそこに {css,js,img} を配置し 下のような1行だけ追加することにしました。

[配置]

[src]   
 -> [main]   
    -> [webapp]   
       -> [WEB-INF]
       -> [assets]   
           -> [css]   
           -> [js]   
           -> [img]   

[変更後のソース]

context.addServlet(new ServletHolder(new DefaultServlet), "/assets/*")

リソースを読み込む為のServletを用意

MyDefaultServlet.scala

package refxml

import org.eclipse.jetty.servlet.DefaultServlet
import org.eclipse.jetty.util.resource.Resource

class MyDefaultServlet extends DefaultServlet {
  override def getResource(resourceString: String): Resource =
  {
    val url = this.getClass().getResource(resourceString)
    Resource.newResource(url)
  }
}

次に JettyLaunchar.scala から 作成した MyDefaultServlet を呼び出すように変更します。
DefaultServlet のところを MyDefaultServlet に変更します。

修正後の JettyLaunchar.scala

package refxml

import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.{DefaultServlet, ServletContextHandler, ServletHolder}
import org.eclipse.jetty.webapp.WebAppContext
import org.scalatra.servlet.ScalatraListener

object JettyLauncher {
  def main(args: Array[String]) {
    val port = if(System.getenv("PORT") != null) System.getenv("PORT").toInt else 8080

    val server = new Server(port)
    val context = new WebAppContext()
    context setContextPath "/"
    context.setResourceBase("src/main/webapp")
    context.addEventListener(new ScalatraListener)
    context.addServlet(classOf[MyDefaultServlet], "/")
    context.addServlet(new ServletHolder(new MyDefaultServlet), "/assets/*")

    server.setHandler(context)

    server.start
    server.join
  }
}

build.sbt も修正

assets をリソースに取り込むように build.sbt に以下の設定を追加

...
resourceGenerators in Compile <+= (resourceManaged, baseDirectory) map { (managedBase, base) =>
  val webappBase = base / "src" / "main" / "webapp"
  for {
    (from, to) <- webappBase ** "*" x rebase(webappBase, managedBase / "main/" )
  } yield {
    Sync.copy(from, to)
    to
  }
}
...

を追加

再度 jar つくって実行

sbt clean assembly
java -jar **-assembly-**

localhost:8080 にアクセス

今度は スタイルシートも反映された期待通りの動作となりました。

ソースはこちらで公開してます。