CLOVER🍀

That was when it all began.

WildFlyの管理CLIで、InfinispanのCacheContainer/Cacheを定義する

WildFlyでは、設定を行うのは管理CLIからが推奨だと聞いて。

そういえば、これまで設定ファイルを直接編集してしか、InfinispanのCacheContainerやCacheを定義したり追加したりしたことなかったなぁと思いまして。

その他、最近このあたりのサイト・スレッドを見てやってみようかなと思いまして。

Wildfly 8.1, standalone-ha, use of Infinispan (lib mode) - simple clustering- any hints? tips?
https://community.jboss.org/thread/243428?start=0&tstart=0

Using Infinispan with WildFly 8
http://www.mastertheboss.com/infinispan/using-infinispan-with-wildfly-8

Using Infinispan as a persistency solution
http://blog.arungupta.me/2014/08/using-infinispan-as-persistency-solution/

管理CLIを操作するのにあたり、参考にしたのはもちろんWildFlyとInfinispanのドキュメント。

Infinispan Subsystem
https://docs.jboss.org/author/display/WFLY8/Infinispan+Subsystem

15.5. Use a JBoss AS 7 configured cache
http://infinispan.org/docs/6.0.x/user_guide/user_guide.html#_use_a_jboss_as_7_configured_cache

では、始めてみましょう。

はじめに

とりあえず、WildFlyを起動して管理CLIで接続しないと、話が進みません。

起動。

$ wildfly-8.1.0.Final/bin/standalone.sh

管理CLIで接続。

$ wildfly-8.1.0.Final/bin/jboss-cli.sh 
You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands.
[disconnected /] connect
[standalone@localhost:9990 /]

はい。

CacheConatiner/Cacheを定義する

それでは、管理CLIでCacheContainer/Cacheを定義してみましょう。

参考にするのは、こちらです。

Infinispan Subsystem
https://docs.jboss.org/author/display/WFLY8/Infinispan+Subsystem

というか、これないとムリでした。

CacheContainerの定義。

[standalone@localhost:9990 /] /subsystem=infinispan/cache-container=my-cache-container:add()
{"outcome" => "success"}

今回定義するCacheContainerの名前は、「my-cache-container」とします。

「add(」の後でタブ保管しようとすると、いろいろ出るのである程度はなんとかなりそう?

[standalone@localhost:9990 /] /subsystem=infinispan/cache-container=my-cache-container:add(
aliases=                     jndi-name=                   replication-queue-executor=  
default-cache=               listener-executor=           start=                       
eviction-executor=           module=                      statistics-enabled=

この時点で、「wildfly-8.1.0.Final/standalone/configuration/standalone.xml」には以下のような記述が入ります。

            <cache-container name="my-cache-container"/>

では、Cacheの定義へ。

以下まで入力してタブ保管すると、作成するCacheの種類が表示されます。

[standalone@localhost:9990 /] /subsystem=infinispan/cache-container=my-cache-container/
distributed-cache   invalidation-cache  local-cache         replicated-cache    transport

あと、tranportも入ってますか。

今回は「local-cache」を選んで、2つCacheを作成してみます。

[standalone@localhost:9990 /] /subsystem=infinispan/cache-container=my-cache-container/local-cache=my-cache-1:add()
{"outcome" => "success"}
[standalone@localhost:9990 /] /subsystem=infinispan/cache-container=my-cache-container/local-cache=my-cache-2:add()
{"outcome" => "success"}

Cacheの名前は、それぞれ「my-cache-1」と「my-cache-2」とします。

このうち、「my-cache-1」をトランザクション対応しておきましょう。

[standalone@localhost:9990 /] /subsystem=infinispan/cache-container=my-cache-container/local-cache=my-cache-1/transaction=TRANSACTION:add(mode=NON_XA)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}

リロードを求められるようなので、再起動。

[standalone@localhost:9990 /] reload

はい。

できあがったCacheContainer/Cacheの定義は、このようになっています。

            <cache-container name="my-cache-container">
                <local-cache name="my-cache-1">
                    <transaction mode="NON_XA"/>
                </local-cache>
                <local-cache name="my-cache-2"/>
            </cache-container>

それにしても、こういう書き方なんですね…。

[standalone@localhost:9990 /] /subsystem=infinispan/cache-container=my-cache-container/local-cache=my-cache-1/transaction=TRANSACTION:add(mode=NON_XA)

補完は「transaction=」までしかされないので、その後ドキュメントを見ないとわかりませんでしたよ…。

使ってみる

では、定義しただけでは面白くないので、リソースとしてルックアップして使ってみましょう。@Resourceアノテーションでインジェクションして使うところまでを、目標にします。

依存関係の定義。
build.sbt

name := "infinispan-configured-cache"

version := "0.0.1-SNAPSHOT"

scalaVersion := "2.11.2"

organization := "org.littlewings"

scalacOptions ++= Seq("-Xlint", "-deprecation", "-unchecked", "-feature")

incOptions := incOptions.value.withNameHashing(true)

jetty()

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

val jettyVersion = "9.2.2.v20140723"

libraryDependencies ++= Seq(
  "org.eclipse.jetty" % "jetty-webapp" % jettyVersion % "container",
  "org.eclipse.jetty" % "jetty-plus"   % jettyVersion % "container",
  "javax" % "javaee-web-api" % "7.0" % "provided",
  "org.infinispan" % "infinispan-core" % "6.0.2.Final" % "provided" excludeAll(
    ExclusionRule(organization = "org.jgroups", name = "jgroups"),
    ExclusionRule(organization = "org.jboss.marshalling", name = "jboss-marshalling-river"),
    ExclusionRule(organization = "org.jboss.marshalling", name = "jboss-marshalling"),
    ExclusionRule(organization = "org.jboss.logging", name = "jboss-logging"),
    ExclusionRule(organization = "org.jboss.spec.javax.transaction", name = "jboss-transaction-api_1.1_spec")
  ),
  "org.jgroups" % "jgroups" % "3.4.1.Final" % "provided",
  "org.jboss.spec.javax.transaction" % "jboss-transaction-api_1.1_spec" % "1.0.1.Final" % "provided",
  "org.jboss.marshalling" % "jboss-marshalling-river" % "1.4.4.Final" % "provided",
  "org.jboss.marshalling" % "jboss-marshalling" % "1.4.4.Final" % "provided",
  "org.jboss.logging" % "jboss-logging" % "3.1.2.GA" % "provided",
  "net.jcip" % "jcip-annotations" % "1.0" % "provided",
  "org.scala-lang.modules" %% "scala-xml" % "1.0.2"
)

Infinispanの依存関係のスコープは、すべて「provided」にしています。

xsbt-web-pluginが1.0.0-M4になってみたので使ってみたのですが、若干設定方法変わりました?
project/plugins.sbt

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

このあたり。

jetty()

で、@Resourceを使う対象として、Servletを用意しました。
src/main/scala/org/littlewings/infinispan/configuredcache/InfinispanServelt.scala

package org.litltewings.infinispan.configuredcache

import java.io.IOException

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

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

@WebServlet(Array("/cache/access"))
class InfinispanServlet extends HttpServlet {
  @Resource(lookup = "java:jboss/infinispan/container/my-cache-container")
  private var cacheContainer: CacheContainer = _  // CacheContainerで受けても可
  // private var cacheContainer: EmbeddedCacheManager = _  // EmbeddedCacheManagerで受けても可

  @Resource(lookup = "java:jboss/infinispan/cache/my-cache-container/my-cache-1")
  private var cache: Cache[String, Integer] = _

  @throws(classOf[IOException])
  @throws(classOf[ServletException])
  override protected def doGet(req: HttpServletRequest, res: HttpServletResponse): Unit = {
    res.setContentType("text/html; charset=UTF-8")

    val counter =
      cache.get("counter") match {
        case null => 1
        case n => n + 1
      }
    
    cache.put("counter", counter)

    val fromManagerCache = cacheContainer.getCache[String, String]("my-cache-2")

    res.getWriter.write {
      <html>
        <body>
          <p>{s"container = ${cacheContainer}"}</p>
          <p>{s"container class name = ${cacheContainer.getClass.getName}"}</p>
          <p>{s"container have cache names = ${cacheContainer.asInstanceOf[EmbeddedCacheManager].getCacheNames}"}</p>
          <p>{s"injected cache name = ${cache.getName}"}</p>
          <p>{s"injected cache transactionMode  = ${cache.getCacheConfiguration.transaction.transactionMode}"}</p>
          <p>{s"get cache name  = ${fromManagerCache.getName}"}</p>
          <p>{s"get cache transactionMode  = ${fromManagerCache.getCacheConfiguration.transaction.transactionMode}"}</p>
          <p>{s"counter = ${counter}"}</p>
        </body>
      </html>.toString + System.lineSeparator
    }
  }
}

CacheContainerをインジェクションする時は、こんな感じ。

  @Resource(lookup = "java:jboss/infinispan/container/my-cache-container")
  private var cacheContainer: CacheContainer = _  // CacheContainerで受けても可
  // private var cacheContainer: EmbeddedCacheManager = _  // EmbeddedCacheManagerで受けても可

JNDI名は、「java:jboss/infinispan/container/[CacheContainer名]」みたいですね。

型は、CacheContainerまたはEmbeddedCacheManagerでインジェクションすることができます。Infinispanのドキュメントでは、EmbeddedCacheManagerを使用しています。

Cacheをインジェクションする時は、こんな感じ。

  @Resource(lookup = "java:jboss/infinispan/cache/my-cache-container/my-cache-1")
  private var cache: Cache[String, Integer] = _

JNDI名は、「java:jboss/infinispan/cache/[CacheContainer名]/[Cache名]」のようです。

結果表示は、簡単なカウンタとCacheContainerおよびCacheの情報表示。

    res.getWriter.write {
      <html>
        <body>
          <p>{s"container = ${cacheContainer}"}</p>
          <p>{s"container class name = ${cacheContainer.getClass.getName}"}</p>
          <p>{s"container have cache names = ${cacheContainer.asInstanceOf[EmbeddedCacheManager].getCacheNames}"}</p>
          <p>{s"injected cache name = ${cache.getName}"}</p>
          <p>{s"injected cache transactionMode  = ${cache.getCacheConfiguration.transaction.transactionMode}"}</p>
          <p>{s"get cache name  = ${fromManagerCache.getName}"}</p>
          <p>{s"get cache transactionMode  = ${fromManagerCache.getCacheConfiguration.transaction.transactionMode}"}</p>
          <p>{s"counter = ${counter}"}</p>
        </body>
      </html>.toString + System.lineSeparator
    }

トランザクションへの対応状態も出すようにしています。

あと、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.2">
  <deployment>
    <dependencies>
      <module name="org.infinispan" export="true" />
    </dependencies>
  </deployment>
</jboss-deployment-structure>

参考)
Class Loading in WildFly
https://docs.jboss.org/author/display/WFLY8/Class+Loading+in+WildFly
第3章 クラスローディングとモジュール
https://access.redhat.com/documentation/ja-JP/JBoss_Enterprise_Application_Platform/6/html/Development_Guide/chap-Class_Loading_and_Modules.html
3.2. デプロイメントへの明示的なモジュール依存関係の追加
https://access.redhat.com/documentation/ja-JP/JBoss_Enterprise_Application_Platform/6/html/Development_Guide/Add_an_Explicit_Module_Dependency_to_a_deployment.html

これをWARにパッケージングして

> package
[info] Packaging /xxxxx/infinispan-configured-cache/target/scala-2.11/javaee7-web.war ...
[info] Done packaging.
[success] Total time: 8 s, completed 2014/08/09 22:16:17

WildFlyにデプロイします。

$ cp target/scala-2.11/javaee7-web.war /path/to/wildfly-8.1.0.Final/standalone/deployments/

ちなみに、デプロイするとこんな風に警告されます。

22:17:11,768 WARN  [org.jboss.as.dependency.private] (MSC service thread 1-4) JBAS018567: Deployment "deployment.javaee7-web.war" is using a private module ("org.infinispan:main") which may be changed or removed in future versions without notice.
22:17:11,769 WARN  [org.jboss.as.dependency.private] (MSC service thread 1-4) JBAS018567: Deployment "deployment.javaee7-web.war" is using a private module ("org.infinispan:main") which may be changed or removed in future versions without notice.

これ、前も見たことあるんですけどWildFly的にはInfinispanを直接使って欲しくないのかなぁ?確かにモジュール定義上はprivateになってますしね…。

参考)
Class Loading in WildFly
https://docs.jboss.org/author/display/WFLY8/Class+Loading+in+WildFly
Module descriptors
https://docs.jboss.org/author/display/MODULES/Module+descriptors

まあ、それはさておき…ちょっとアクセスしてみましょう。

$ curl http://localhost:8080/javaee7-web/cache/access

結果。

<html>
        <body>
          <p>container = my-cache-container</p>
          <p>container class name = org.jboss.as.clustering.infinispan.DefaultCacheContainer</p>
          <p>container have cache names = [my-cache-1, my-cache-2]</p>
          <p>injected cache name = my-cache-1</p>
          <p>injected cache transactionMode  = TRANSACTIONAL</p>
          <p>get cache name  = my-cache-2</p>
          <p>get cache transactionMode  = NON_TRANSACTIONAL</p>
          <p>counter = 1</p>
        </body>
      </html>

CacheContainerの実体は、DefaultCacheManagerじゃないんですねー。また、CacheContainerに定義したCacheが2つであることと、「my-cache-1」がトランザクションに対応していることがわかります。

なお、繰り返しアクセスするとカウンタが上がっていきます。

<html>
        <body>
          <p>container = my-cache-container</p>
          <p>container class name = org.jboss.as.clustering.infinispan.DefaultCacheContainer</p>
          <p>container have cache names = [my-cache-1, my-cache-2]</p>
          <p>injected cache name = my-cache-1</p>
          <p>injected cache transactionMode  = TRANSACTIONAL</p>
          <p>get cache name  = my-cache-2</p>
          <p>get cache transactionMode  = NON_TRANSACTIONAL</p>
          <p>counter = 2</p>
        </body>
      </html>

とりあえず、基本的なところは大丈夫かな?

今回作成したコードは、こちらに置いています。
https://github.com/kazuhira-r/infinispan-examples/tree/master/infinispan-configured-cache