Embed Jetty - Groovy と Scala で Jetty を組み込み実行

プログラム内での Jetty 組み込み実行を試してみました。
id:fits:20110521 で作成したサンプルの war ファイルを Groovy と Scala から組み込み実行してみます。

使用した Jetty のバージョンは以下の通りです。

  • Jetty 8.0M3

サンプルソースは http://github.com/fits/try_samples/tree/master/blog/20110605/

Groovy の場合

Groovy スクリプトは以下のようになります。
war ファイルをルート / で公開する設定を行い、Jetty サーバーを起動しています。

exec_war_jetty.groovy
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.webapp.WebAppContext

def server = new Server(8080)

def webapp = new WebAppContext()
webapp.contextPath = "/"
webapp.war = args[0]

server.handler = webapp

server.start()
server.join()

ユーザーホームディレクトリの .groovy/lib ディレクトリに Jetty の lib ディレクトリ内の JAR ファイルを配置しておき、以下のように実行します。(Groovy の conf/groovy-starter.conf を編集しても可)

実行例
> groovy exec_war_jetty.groovy scalatra-scalate-morphia-sample_2.9.0-1-1.0.war

http://localhost:8080/ にアクセスするとページが表示されるはずです。

Scala(スクリプト実行)の場合

Scala でスクリプトファイルを直接実行する場合は以下のようになります。(Groovy 版と基本的に同じです)

exec_war_jetty.scala
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.webapp.WebAppContext

val server = new Server(8080)

val webapp = new WebAppContext()
webapp.setContextPath("/")
webapp.setWar(args(0))

server.setHandler(webapp)

server.start
server.join

Jetty の lib ディレクトリ内の JAR ファイルを環境変数 CLASSPATH に予め設定しておき、以下のように実行します。

実行例
> scala exec_war_jetty.scala scalatra-scalate-morphia-sample_2.9.0-1-1.0.war

Scala(sbt 実行)の場合

sbt で実行する場合、プロジェクトファイルは以下のようになります。

project/build/ExeWarJettyProject.scala
import sbt._

class ExeWarJettyProject(info: ProjectInfo) extends DefaultProject(info) {

    val jettyVersion = "8.0.0.M3"

    val jettyWebapp = "org.eclipse.jetty" % "jetty-webapp" % jettyVersion
    val jettySecurity = "org.eclipse.jetty" % "jetty-security" % jettyVersion
    val jettyServlets = "org.eclipse.jetty" % "jetty-servlets" % jettyVersion
    val jettyDeploy = "org.eclipse.jetty" % "jetty-deploy" % jettyVersion

    override def mainClass = Some("fits.sample.Sample")
}

Jetty の起動処理は main メソッド内に実装します。

src/main/scala/Sample.scala
package fits.sample

import org.eclipse.jetty.server.Server
import org.eclipse.jetty.webapp.WebAppContext

object Sample {
    def main(args: Array[String]) = {
        val server = new Server(8080)

        val webapp = new WebAppContext()
        webapp.setContextPath("/")
        webapp.setWar(args(0))

        server.setHandler(webapp)

        server.start
        server.join
    }
}

sbt を使って実行します。(run に実行時引数が渡せます)

実行例
・・・exec_war_jetty_sbt> sbt
・・・
> update
・・・
> run scalatra-scalate-morphia-sample_2.9.0-1-1.0.war

追記1 - JSP を使う場合

  • Jetty 7.4.5

war ファイル内の JSP を動作させるには、jetty-jsp-2.1 や jsp-2.1-glassfish が必要になります。@Grapes を使った Groovy のスクリプト例は以下のようになります。

JSP を使う Groovy スクリプト例
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.webapp.WebAppContext

@Grapes([
  @Grab("org.eclipse.jetty:jetty-webapp:7.4.5.v20110725"),
  @Grab("org.eclipse.jetty:jetty-jsp-2.1:7.4.5.v20110725"),
  @Grab("org.mortbay.jetty:jsp-2.1-glassfish:*")
])
def server = new Server(8080)

def webapp = new WebAppContext()
webapp.contextPath = "/"
webapp.war = args[0]

server.handler = webapp

server.start()
server.join()

追記2 - JNDI を使う場合

  • Jetty 7.4.5

次に、web.xml で以下のように JNDI リソースを参照するように設定している場合、

web.xml
<web-app>
  ・・・
  <resource-ref>
    <res-ref-name>jdbc/testDS</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>
</web-app>

JNDI名とリソースのマッピングを以下のような jetty-env.xml ファイルで指定して Jetty を起動するには、
(古い Jetty を使う場合、パッケージ名が org.eclipse.jetty とは異なるので注意)

jetty-env.xml 例(JNDI 名とリソースのマッピング)
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
  <New id="dataSource" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg>jdbc/testDS</Arg>
    <Arg>
      <New class="oracle.jdbc.pool.OracleConnectionPoolDataSource">
        <Set name="url">jdbc:oracle:thin:@127.0.0.1:1521/XE</Set>
        <Set name="user">TEST</Set>
        <Set name="password">TEST</Set>
      </New>
    </Arg>
  </New>
</Configure>

jetty-plus を @Grapes に追加して configurationClasses の設定を行います。(jetty-env.xml はカレントディレクトリ等のクラスパスが通っている場所に配置しておけばよい模様)

jetty-env.xml を使う Groovy スクリプト例
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.webapp.WebAppContext

@Grapes([
   @Grab("org.eclipse.jetty:jetty-webapp:7.4.5.v20110725"),
   @Grab("org.eclipse.jetty:jetty-jsp-2.1:7.4.5.v20110725"),
   @Grab("org.mortbay.jetty:jsp-2.1-glassfish:*"),
   @Grab("org.eclipse.jetty:jetty-plus:7.4.5.v20110725")
])
def server = new Server(8080)

def webapp = new WebAppContext()
webapp.contextPath = "/"
webapp.war = args[0]

//jetty-env.xml をロードするための設定
webapp.configurationClasses = [
   "org.eclipse.jetty.webapp.WebInfConfiguration",
   "org.eclipse.jetty.webapp.WebXmlConfiguration",
   "org.eclipse.jetty.webapp.MetaInfConfiguration",
   "org.eclipse.jetty.webapp.FragmentConfiguration",
   "org.eclipse.jetty.plus.webapp.EnvConfiguration",
   "org.eclipse.jetty.plus.webapp.PlusConfiguration",
   "org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
   "org.eclipse.jetty.webapp.TagLibConfiguration"
]

server.handler = webapp

server.start()
server.join()