CLOVER🍀

That was when it all began.

Infinispan 5.3.0.FinalをJBoss AS 7.1.1に突っ込む

JBoss ASで、Infinispanを使うための下準備ってことで。まあ、すぐには手をつけないかもしれませんが。

sbtのMANIFEST設定の勉強にも、ちょいとなりましたね。

コミュニティ版のJBoss ASは、7.1.1で止まっているので、サブシステムとして含まれているInfinispanが5.1.2.FINALとなっていて、わりと古い状態です。

なお、デプロイするアプリケーションから組み込み済みのInfinispanを参照するためには、META-INF/MANIFESTに

Manifest-Version: 1.0
Class-Path: org.infinispan services

と書くか、以下のようなXMLファイルをWARに含めます。
src/main/webapp/WEB-INF/jboss-deployment-structure.xml

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
  <deployment>
    <dependencies>
      <module name="org.infinispan" />
    </dependencies>
  </deployment>
</jboss-deployment-structure>

これで、JBoss ASにモジュールとして組み込まれているInfinispanを参照することができます。

sbtで設定すると、依存関係はこんな感じでOKとなります。

  "org.infinispan" % "infinispan-core" % "5.1.2.FINAL" % "provided",
  "net.jcip" % "jcip-annotations" % "1.0" % "provided"

組み込み済みなので、「provided」ですね。
「jcip-annotations」が入っているのは、ScalaとInfinsipanの組み合わせだからです…。
Javaで使う場合は、不要です。

MANIFESTを定義する方法は、こんな感じでした。
*xsbt-war-pluginを適用しています

packageOptions in (Compile, packageWar) +=
  Package.ManifestAttributes(new java.util.jar.Attributes.Name("Dependencies") -> "org.infinispan services")

そんな感じの設定を含んだアプリケーションをJBoss ASにデプロイして、DefaultCacheManagerを初期化した時のInfinispanの起動ログは、こんな感じ。

00:09:23,433 INFO  [org.infinispan.factories.GlobalComponentRegistry] (http--127.0.0.1-8080-1) ISPN000128: Infinispan version: Infinispan 'Brahma' 5.1.2.FINAL

が、これだとちょっと古いので、Infinispanの差し替えを行います。

Infinispanのオフィシャルサイトから、「AS7 Modules」と記載されたディストリビューションをダウンロードします。

Infinispanダウンロードページ
http://infinispan.org/download/

ここで、JBoss AS 7のインストールディレクトリを「$JBOSS_HOME」とすると、以下のディレクトリに移動して

$ $JBOSS_HOME/modules

ここにダウンロードしたZIPファイルをコピーして展開します。ちょっと乱暴ですが。

$ unzip infinispan-as-modules-5.3.0.Final.zip 
Archive:  infinispan-as-modules-5.3.0.Final.zip
   creating: org/jgroups/3.2/
   creating: org/infinispan/tree/
   creating: org/infinispan/tree/5.3/
   creating: org/infinispan/cachestore/jdbc/5.3/
   creating: org/infinispan/cachestore/remote/5.3/
   creating: org/infinispan/5.3/
 extracting: org/jgroups/3.2/jgroups-3.3.1.Final.jar  
  inflating: org/jgroups/3.2/module.xml  
  inflating: org/infinispan/tree/5.3/module.xml  
 extracting: org/infinispan/tree/5.3/infinispan-tree.jar  
  inflating: org/infinispan/cachestore/jdbc/5.3/module.xml  
 extracting: org/infinispan/cachestore/jdbc/5.3/infinispan-cachestore-jdbc.jar  
  inflating: org/infinispan/cachestore/remote/5.3/module.xml  
 extracting: org/infinispan/cachestore/remote/5.3/infinispan-cachestore-remote.jar  
  inflating: org/infinispan/5.3/module.xml  
 extracting: org/infinispan/5.3/infinispan-core.jar

infinispan-coreは、JBoss LoggingとJBoss Marshallingにも依存していて、なおかつJBoss AS 7に含まれているモジュールは5.3.0の依存関係から見るとほんの少し古いのですが、まあいいかなぁと…。

ZIPファイルは、要らないので削除。

$ rm infinispan-as-modules-5.3.0.Final.zip

もちろん、別の場所で展開してmodulesディレクトリに入れる、でもいいと思います。

あ、JBoss AS 7は、再起動した方がよいかと。

さて、展開したInfinispan 5.3.0.Finalに含まれるmodule.xmlは、こんな感じです。
*コメントは端折っています
org/infinispan/5.3/module.xml

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.infinispan" slot="5.3">
    <resources>
        <resource-root path="infinispan-core.jar"/>
        <!-- Insert resources here -->
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
        <module name="javax.xml.bind.api"/>
        <module name="net.jcip"/>
        <module name="org.apache.xerces" services="import"/>
        <module name="org.jboss.jandex"/>
        <module name="org.jboss.logging"/>
        <module name="org.jboss.marshalling"/>
        <module name="org.jboss.marshalling.river" services="import"/>
        <module name="org.jboss.staxmapper" />
        <module name="org.jgroups" slot="3.2"/>
        <module name="sun.jdk"/>
    </dependencies>
</module>

で、これを先ほどの依存関係やMANIFESTとかに反映します。

依存関係の定義は、こんな感じ。

  "org.infinispan" % "infinispan-core" % "5.3.0.Final" % "provided",
  "net.jcip" % "jcip-annotations" % "1.0" % "provided"

MANIFESTは、こうします。

packageOptions in (Compile, packageWar) +=
  Package.ManifestAttributes(new java.util.jar.Attributes.Name("Dependencies") -> "org.infinispan:5.3 services")

生成されたMANIFESTファイル。

Manifest-Version: 1.0
Dependencies: org.infinispan:5.3 services

もしくは、jboss-deployment-structure.xmlにこんな感じで定義します。
src/main/webapp/WEB-INF/jboss-deployment-structure.xml

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
  <deployment>
    <dependencies>
      <module name="org.infinispan" slot="5.3" /> 
    </dependencies>
  </deployment>
</jboss-deployment-structure>

slot付きです。

これで、デプロイしたアプリケーションが使うInfinispanの起動ログに、「5.3.0.Final」と出るようになりました。

00:33:54,772 INFO  [org.infinispan.factories.GlobalComponentRegistry] (http--127.0.0.1-8080-1) ISPN000128: Infinispan version: Infinispan 'Tactical Nuclear Penguin' 5.3.0.Final

なお、jboss-deployment-structure.xml以外のsbtの設定や動作確認に使ったファイルやコードはこちらになります。
build.sbt

name := "infinispan-in-jboss"

version := "0.0.1-SNAPSHOT"

scalaVersion := "2.10.3"

organization := "littlewings"

seq(webSettings: _*)

artifactName := { (version: ScalaVersion, module: ModuleID, artifact: Artifact) =>
  artifact.name + "." + artifact.extension
}

resolvers += "Public JBoss Group" at "http://repository.jboss.org/nexus/content/groups/public-jboss"

libraryDependencies ++= Seq(
  "org.eclipse.jetty" % "jetty-webapp" % "9.0.6.v20130930" % "container",
  "javax" % "javaee-web-api" % "6.0" % "provided",
  "org.infinispan" % "infinispan-core" % "5.3.0.Final" % "provided",
  "net.jcip" % "jcip-annotations" % "1.0" % "provided"
)

packageOptions in (Compile, packageWar) +=
  Package.ManifestAttributes(new java.util.jar.Attributes.Name("Dependencies") -> "org.infinispan:5.3 services")

project/plugins.sbt

addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "0.4.2")

src/main/scala/example/SampleServlet.scala

package example

import java.io.IOException

import javax.servlet.ServletException
import javax.servlet.annotation.WebServlet
import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse}

import org.infinispan.Cache
import org.infinispan.manager.{DefaultCacheManager, EmbeddedCacheManager}

@WebServlet(Array("/*"))
class SampleServlet extends HttpServlet {
  lazy val manager: EmbeddedCacheManager = new DefaultCacheManager
  lazy val cache: Cache[String, Int] = manager.getCache()

  @throws(classOf[IOException])
  @throws(classOf[ServletException])
  override protected def doGet(req: HttpServletRequest, res: HttpServletResponse): Unit = {
    if (cache.containsKey("counter")) {
      cache.put("counter", cache.get("counter") + 1)
    } else {
      cache.put("counter", 1)
    }

    res.getWriter.print(<html><h1>Counter = {cache.get("counter")}</h1></html>.toString)
  }

  override def destroy(): Unit = {
    try {
      cache.stop()
    } finally {
      manager.stop()
    }
  }
}