[doc] [toc] [previous] [next]

メッセージ駆動型BeanとJBoss

メッセージ駆動型Bean(MDB)は、EJB 2.0仕様書に追加された新しいタイプのBeanです。これらのBeanが追加された理由は、EJB 1.1では非同期呼び出しを扱う方法が無かったからです。この主たる理由は、EJB Beanに対してリモートインタフェース以外の手段を使って他のオブジェクトから呼びだすことができなかったからです。したがって、これまでBeanは非同期呼び出しのためにリスナとしてそれ自身を登録することはできませんでした。

この制限はメッセージ駆動型Bean(MDB)によって克服されました。MDBはリモートインタフェースを持たないBeanです。コンテナはMDBの非同期呼び出しのためのリスナとしてコンテナ自身を登録して具体的なBeanの呼び出しを処理します。それ以外の点については、MDBはEJB Beanの通常の役割に従います。

メッセージ駆動型Beanは、主にJMSに焦点を合わせています。MDBはトピックまたはキュー サブスクライバです。MDBの優れた機能のひとつは、JMSメッセージ コンシューマのために難解なマルチスレッドのコードをわざわざ書かなくても、誰でも容易にマルチスレッド化したサブスクライバを作れることです。

MDBを使う目的は何でしょう? 基本的に、JMSサブスクライバを作ろうとするときは、いつでもMDBを使えます。MDBを使うような典型的な状況は次の通りです。

メッセージ駆動型Beanのコードを書く方法を知っているなら、JBossにそれをデプロイするのはとても簡単なことです。しなければならない唯一のことは、JBoss固有のデプロイメント記述を追加するか、あるいは、すでにあなたのモジュール用のjboss.xmlデプロイメント記述を持っているなら、それにMDBの部分を追加するだけです。

[2.4.0. 実際には、JBoss固有のデプロイメント記述が無くともMDBをデプロイできるべきです。 しかし、私はこのようなことは勧めません。詳しくは、先を読んでください。]

JBossでMDBの涅槃(nirvana)に至るための5つのステップ

もし、あなたが特別な設定をしていなくて、すでにメッセージ駆動Beanのコードを書く方法を知っているなら、JBossを使ってそれを起動、実行させる5つの簡単なステップがあります。

  1. メッセージ駆動型Beanのソースコードを書きます。

  2. ejb-jar.xmlディスクリプタを書きます。

    これは、Bean管理のトランザクションを使ってキューをリスンするBeanの例です。

    <?xml version="1.0"?>
    <!DOCTYPE ejb-jar>
    <ejb-jar>
      <enterprise-beans>
        <message-driven>
          <ejb-name>HelloQueueBMTMDB</ejb-name>
          <ejb-class>org.jboss.docs.jms.mdb.bean.HelloMDB</ejb-class>
          <message-selector></message-selector>
          <transaction-type>Bean</transaction-type>
          <acknowledge-mode>Auto-acknowledge</acknowledge-mode>
          <message-driven-destination>
            <destination-type>javax.jms.Queue</destination-type>
          </message-driven-destination>
        </message-driven>
      </enterprise-beans>
    </ejb-jar>
    

    そしてコンテナ管理のトランザクションを使った持続的トピックの例です。

    <?xml version="1.0"?>
    <!DOCTYPE ejb-jar>
    <ejb-jar>
      <enterprise-beans>
        <message-driven>
          <ejb-name>HelloTopicDurableMDB</ejb-name>
          <ejb-class>org.jboss.docs.jms.mdb.bean.HelloMDB</ejb-class>
          <message-selector></message-selector>
          <transaction-type>Container</transaction-type>
          <message-driven-destination>
            <destination-type>javax.jms.Topic</destination-type>
            <subscription-durability>Durable</subscription-durability>
          </message-driven-destination>
        </message-driven>
      </enterprise-beans>
      <assembly-descriptor>
        <container-transaction>
          <method>
            <ejb-name>HelloTopicDurableMDB</ejb-name>
            <method-name>*</method-name>
          </method>
          <trans-attribute>Required</trans-attribute>
        </container-transaction>
      </assembly-descriptor>
    </ejb-jar>
    
  3. jboss.xmlデプロイメント記述を書きます。特別な要求を持たないMDBのためにはコンテナ設定の箇所を埋める必要はありませんのでご注意。

    [2.4.0. この設定をしないことも可能です。 その場合、宛先は自動的に作成され、Bean名と同じ名前が付けられます。 これは、ひどく驚かせる結果になるかもしれませんので、私は勧めません。]

    destination-jndi-name要素は、キューを指し示します。

    これはキューBeanの例です(訳注: encodingはUTF-8に修正されるか、または削除されるべきです):

    <?xml version="1.0" encoding="Cp1252"?>
    <jboss>
      <enterprise-beans>
        <message-driven>
          <ejb-name>HelloQueueMDB</ejb-name>
          <configuration-name>Standard Message Driven Bean</configuration-name>
          <destination-jndi-name>queue/testQueue</destination-jndi-name>
        </message-driven>
      </enterprise-beans>
    </jboss>
    

    そして、これが持続的トピックの例です(訳注: encodingはUTF-8に修正されるか、または削除されるべきです):

    <?xml version="1.0" encoding="Cp1252"?>
    <jboss>
      <enterprise-beans>
        <message-driven>
          <ejb-name>HelloTopicDurableMDB</ejb-name>
          <configuration-name>Standard Message Driven Bean</configuration-name>
          <destination-jndi-name>topic/testTopic</destination-jndi-name>
          <mdb-user>john</mdb-user>
          <mdb-passwd>needle</mdb-passwd>
          <mdb-client-id>DurableSubscriberExample</mdb-client-id>
        </message-driven>
      </enterprise-beans>
    </jboss>
    
  4. conf/defaultディレクトリにあるjbossmq.xmlを編集して、キューまたはトピックを追加します。たとえば、次のようになります。

    <Queue>
      <Name>testQueue</Name>
    </Queue>
    

    というのはキューの例で、

    <Topic>
      <Name>testDurableTopic</Name>
    </Topic>
    

    次は、

    <User>
      <Name>john</Name>
      <Password>needle</Password>
      <Id>DurableSubscriberExample</Id>
      <DurableSubscription>
        <Name>DurableSubscriberExample</Name>
        <TopicName>testDurableTopic</TopicName>
      </DurableSubscription>
    </User>
    

    持続的トピックの例です。

    [2.4.1. 宛先の追加は、代わりにjboss.jcmlファイルでおこなわれます。

    <mbean code="org.jbossmq.server.TopicManager"
      name="JBossMQ:service=Topic,name=testTopic"/>
    

    ユーザは、代わりにjbossmq-state.xmlファイルで設定されます。このファイルもconf/defaultにあります。エントリは上に示したのと同じようになります。]

  5. Beanをデプロイします。たとえば、それをJARファイルにパッケージして、それをJBoss deployディレクトリにコピーします。

今、MDBは利用する準備が整いましたので、それにメッセージを送信して起動できます。

メッセージ駆動型Beanを書く

MDBはEJBの中でもまだ最近追加されたばかりなので、まだあまり知られてもいないし、広く利用されてもいません。 そこで、メッセージ駆動型Beanの作り方と使い方の簡単な例をいくつかご紹介することにしましょう。

Hello World MDB

MDBは、典型的なEJB契約(contract)に従います。MDBは、次の二つのインタフェースを実装しなければなりません。

  • javax.ejb.MessageDrivenBean

  • javax.jms.MessageListener

したがって、MDBは、一般的に次の4つのメソッドを含まなければなりません。

図 8.44. メッセージ駆動型Beanが要求するメソッド

public void setMessageDrivenContext(MessageDrivenContext ctx);
public void ejbCreate();
public void ejbRemove();
public void onMessage(Message message);

単純な“Hello World”の完全なプログラムリストは、このようになります。

図 8.45. Hello Worldメッセージ駆動型Beanの例(org/jboss/docs/jms/mdb/beanディレクトリのHelloMDB.javaより)

package org.jboss.docs.jms.mdb.bean;

import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
import javax.ejb.EJBException;

import javax.jms.MessageListener;
import javax.jms.Message;

/**
 * 単純なHellowWorldメッセージ駆動型Bean。デプロイメント記述によって
 * トピックとキューの両方にバインドしているかもしれません。
 *
 * Created: Thu Jul 26 13:20:32 2001
 *
 * @author Peter Antman
 * @version $Revision: 1.1.1.1 $ $Date: 2002/04/08 13:01:19 $
 */
public class HelloMDB implements MessageDrivenBean, MessageListener {

  private MessageDrivenContext ctx = null;

  public HelloMDB() {

  }

  //--- MessageDrivenBean
  public void setMessageDrivenContext(MessageDrivenContext ctx)
    throws EJBException {

    this.ctx = ctx;

  }

  public void ejbCreate() {}

  public void ejbRemove() {ctx=null;}

  //--- MessageListener
  public void onMessage(Message message) {

    System.err.println("Bean got message" + message.toString());

  }

} // HelloMDB

このMDBをJBossへデプロイするには、二つのデプロイメント記述を書かなければなりません。ひとつは標準的なもの(ejb-jar.xml)で、もうひとつはJBoss固有のもの(jboss.xml)です。このBeanをトピック サブスクライバにします。そして、このBeanは大して重要なことをしないのでNotSupported属性を指定したコンテナ管理によるトランザクションを使います(多くの場合これはベストというわけではありませんが)。

図 8.46. トピックHello World MDBのためのejb-jar.xmlデプロイメント記述 (org/jboss/docs/jms/resourcesディレクトリにあるHelloMDB-Topic-ejb-jar.xmlファイルより)

<?xml version="1.0"?>
<!DOCTYPE ejb-jar>
<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <ejb-name>HelloTopicMDB</ejb-name>
      <ejb-class>org.jboss.docs.jms.mdb.bean.HelloMDB</ejb-class>
      <message-selector></message-selector>
      <transaction-type>Container</transaction-type>
      <message-driven-destination>
        <destination-type>javax.jms.Topic</destination-type>
        <subscription-durability>NonDurable</subscription-durability>
      </message-driven-destination>
    </message-driven>
  </enterprise-beans>
  <assembly-descriptor>
    <container-transaction>
      <method>
        <ejb-name>HelloTopicMDB</ejb-name>
        <method-name>*</method-name>
      </method>
      <trans-attribute>NotSupported</trans-attribute>
    </container-transaction>
  </assembly-descriptor>
</ejb-jar>

JBossに固有の小さなデプロイメント記述(jboss.xml)を書くことも必要です。MDBコンテナの設定を沢山指定できるので、これの全部がそろったバージョンはかなり大きなものになります。そこで、これを必要としないほとんどのユーザは、標準設定を使います。そのディスクリプタの最も重要な部分は、宛先の仕様です。testTopicはJBossではいつも利用できるので。これを選択することにします。

図 8.47. トピック Hello World MDBのためのJBoss固有のデプロイメント記述 (org/jboss/docs/jms/resourcesディレクトリにあるHelloMDB-Topic-jboss.xmlファイルより)

<?xml version="1.0" encoding="Cp1252"?>
<jboss>
  <enterprise-beans>
    <message-driven>
      <ejb-name>HelloTopicMDB</ejb-name>
      <configuration-name>Standard Message Driven Bean</configuration-name>
      <destination-jndi-name>topic/testTopic</destination-jndi-name>
    </message-driven>
  </enterprise-beans>
</jboss>

次に、3つのファイルをひとつのJARファイルにまとめます。これはBeanのパッケージを作る方法を示したAntビルドファイルの抜粋です。

図 8.48. MDBをJARファイルにパッケージするAntビルドの例

<target name="hello-topic-jar" depends="compile">
  <delete dir="${build.jms.dir}/META-INF"/>
  <mkdir dir="${build.jms.dir}/META-INF"/>
  <copy file="${jms.resource.dir}/HelloMDB-Topic-ejb-jar.xml"
    tofile="${build.jms.dir}/META-INF/ejb-jar.xml" />
  <copy file="${jms.resource.dir}/HelloMDB-Topic-jboss.xml"
    tofile="${build.jms.dir}/META-INF/jboss.xml" />
  <jar jarfile="${build.jms.dir}/HelloTopicMDB.jar">
    <fileset dir="${build.classes.dir}">
      <include name="org/jboss/docs/jms/mdb/bean/HelloMDB.class" />
    </fileset>
    <fileset dir="${build.jms.dir}">
      <include name="META-INF/ejb-jar.xml" />
      <include name="META-INF/jboss.xml" />
    </fileset>
  </jar>
</target>

MDBをインストールするには、そのJARファイルをJBossのdeployディレクトリへコピーする必要があります。

Beanにメッセージを送るには、JMSパブリッシャが必要です。これには標準的なJMSプログラミングが必要となりますので、例項にあるHelloPublisherのサンプルを使っても結構です。

このBeanのサンプルコードは、org/jboss/docs/jms/mdb/beanディレクトリ中のHelloMDB.javaファイルにあります。 デプロイメント記述の例は、org/jboss/docs/jms/resourcesディレクトリのHelloMDB-Topic-ejb-jar.xmlHelloMDB-Topic-jboss.xmlのファイルから参照できます。 Antビルドファイルを使って例を実行することもできます。

図 8.49. トピックHello World MDBの実行

ant jms-hello-topic

JBossを起動したウィンドウ内の出力は、一般的にはこれと似たようなものになります。

図 8.50. トピックHello World MDBの実行出力

[Auto deploy] Auto deploy of file:/home/pra/jboss/deploy/HelloTopicMDB.jar
[J2EE Deployer Default] Deploy J2EE application: file:/home/pra/jboss/deploy/HelloTopicMDB.jar
[J2EE Deployer Default] Create application HelloTopicMDB.jar
[J2EE Deployer Default] install module HelloTopicMDB.jar
[Container factory] Deploying:file:/home/pra/jboss/tmp/deploy/Default/HelloTopicMDB.jar
[Verifier] Verifying file:/home/pra/jboss/tmp/deploy/Default/HelloTopicMDB.jar/ejb1028.jar
[Container factory] Deploying HelloTopicMDB
[Container factory] Deployed application: file:/home/pra/jboss/tmp/deploy/Default/HelloTopicMDB.jar
[J2EE Deployer Default] J2EE application: file:/home/pra/jboss/deploy/HelloTopicMDB.jar is deployed.
[HelloTopicMDB] Bean got messageTextMessage@Hello World no. 1
[HelloTopicMDB] Bean got messageTextMessage@Hello World no. 2
[HelloTopicMDB] Bean got messageTextMessage@Hello World no. 4
[HelloTopicMDB] Bean got messageTextMessage@Hello World no. 5
[HelloTopicMDB] Bean got messageTextMessage@Hello World no. 3
[HelloTopicMDB] Bean got messageTextMessage@Hello World no. 8
[HelloTopicMDB] Bean got messageTextMessage@Hello World no. 9
[HelloTopicMDB] Bean got messageTextMessage@Hello World no. 7
[HelloTopicMDB] Bean got messageTextMessage@Hello World no. 6
[HelloTopicMDB] Bean got messageTextMessage@Hello World no. 10
[Auto deploy] Auto undeploy of file:/home/pra/jboss/deploy/HelloTopicMDB.jar
[J2EE Deployer Default] Stopping module HelloTopicMDB.jar
[Container factory] Undeploying:file:/home/pra/jboss/tmp/deploy/Default/HelloTopicMDB.jar
[Container factory] Undeployed application: file:/home/pra/jboss/tmp/deploy/Default/HelloTopicMDB.jar
[J2EE Deployer Default] Destroying application HelloTopicMDB.jar

別の設定をした他のサンプルもいくつかあります。すべてのデプロイメント記述ファイルは、HelloMDB-というプリフィックスで開始します。次のAntターゲットは、HelloMDBをベースにしたサンプルを実行するのに使えます。

図 8.51. HelloMDBサンプルのためのAntターゲット

jms-hello-topic
jms-hello-topic-durable
jms-hello-topic-fullconf
jms-hello-queue
jms-hello-queue-bmt

リスナとしてのMDB

ここで、もっと現実的なことをする例をご覧いただきましょう。MDBを使うひとつの良い例は、リスナパターンを実行させることです。通常、リスナはイベントを発行するオブジェクトと一緒に自分自身を登録します。しかし、これはMDBでは不可能です。なぜなら、このBean自身は、イベント(メッセージ)を受信したときに仕事をするだけだからです。 したがって、リスナとしてのMDBの設定は、MDBの外側でおこなわれなければなりません。 これをおこなうには、イベント/メッセージを宛先へパブリッシュさせるために、トピックやキューを定義する程度の簡単な作業と、それをイベントを生成している場所へつなげる作業が必要です。 メッセージ駆動型のコールバックのためにもっと汎用的なフレームワークを作ることも可能です。 それはJMSとJMXを使ってすでに経験済みのことです。 でも、それは別のドキュメントの話です。 代わりにMDBの側から物事を見ていきましょう。

EJB間でロジックを分割するひとつの方法は、(ロジックを含む)実際の仕事をするひとつのBeanを持つことです。それは、たとえば、ステートレスセッションBeanまたはエンティティBeanのような、リスナとして動作する別のBeanです。 このパターンに基づく動作するけれど簡単なバージョンを書いてみましょう。 doWorkというただひとつのメソッドを持つ単純なステートレスセッションBeanから始めましょう。 ことを簡単にするため、それはメソッドの引数としてStringを取ります。 これは直接的です。まず最初にホームインタフェースが必要です。

図 8.52. ワーカーBeanのためのホームインタフェース (org/jboss/docs/jms/mdb/interfacesディレクトリにあるHelloWorkerHome.javaより)

package org.jboss.docs.jms.mdb.interfaces;

import java.rmi.RemoteException;
import javax.ejb.EJBHome;
import javax.ejb.CreateException;

/**
 * HelloWorkerのホーム.
 *
 * Created: Thu Jul 26 16:02:46 2001
 *
 * @author Peter Antman
 * @version $Revision: 1.1.1.1 $ $Date: 2002/04/08 13:01:19 $
 */
public interface HelloWorkerHome extends EJBHome  {

  public HelloWorker create() throws RemoteException, CreateException;

} // HelloWorkerHome

リモートインタフェースも必要です。

図 8.53. ワーカーBeanのためのリモートインタフェース (org/jboss/docs/jms/mdb/interfacesディレクトリにあるHelloWorker.javaより)

package org.jboss.docs.jms.mdb.interfaces;

import java.rmi.RemoteException;
import javax.ejb.EJBObject;

/**
 * HelloWorkerのためのインタフェース.
 *
 * Created: Thu Jul 26 15:50:06 2001
 *
 * @author Peter Antman
 * @version $Revision: 1.1.1.1 $ $Date: 2002/04/08 13:01:19 $
 */
public interface HelloWorker extends EJBObject {

  /**
   * 単なるデモ用のworkメソッド
   */
  public void doWork(String work) throws RemoteException;

} // HelloWorker

そして最後に、そのBeanクラスの実際の実装が必要です:

図 8.54. リスナパターンのワーカーBean (org/jboss/docs/jms/mdb/beanディレクトリにあるHelloWorkerBean.javaより)

package org.jboss.docs.jms.mdb.bean;

import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.CreateException;
import java.rmi.RemoteException;

/**
 * ワーカセッションBeanです。MDBリスナから呼び出されたら、
 * このBeanは、そのMDBがサブスクライバとして設定されたJMSの宛先へ
 * メッセージ送信をすることによって、非同期に呼び出されます。
 *
 * @author Peter Antman
 * @version $Revision: 1.1.1.1 $
 */
public class HelloWorkerBean implements SessionBean {

  private SessionContext ctx;

  public HelloWorkerBean() {

  }

  // 通常のセッションEJBのメソッド
  public void setSessionContext(SessionContext ctx)
    throws RemoteException { this.ctx = ctx; }

  public void unsetSessionContext() throws RemoteException {

    this.ctx = null;

  }

  public void ejbActivate() throws RemoteException {}
  public void ejbPassivate() throws RemoteException {}
  public void ejbRemove() throws RemoteException {}
  public void ejbCreate() throws CreateException {}

  /**
   * 仕事をしましょう。これはMDBリスナから呼び出されます。つまり、このBeanは
   * そのMDBリスナへメッセージ送信することで非同期に呼び出されます。
   */
  public void doWork(String work) {

    System.out.println("WorkerBean doing work: " + work);

  }

} // HelloWorkerBean

リスナと一緒にまとめるので、このBeanのデプロイメント記述は後で書くことにします。

次のステップはリスナBeanを書くことです。これは基本的にひとつのことを追加します。それは、ワーカーBeanをルックアップしてそれを呼び出す能力です。ejb-ref要素によって定義されたJNDI参照を介してBeanをルックアップします。これはejbCreate()によっておこなわれるかもしれません。

図 8.55. ワーカーBeanのルックアップ

Context initCtx = new InitialContext();
workerHome =
  (HelloWorkerHome)initCtx.lookup("java:comp/env/ejb/worker");

onMessage()メソッドでそのメッセージを処理します。たとえば、ここで、リストが知っているある種のオブジェクトを送信できたかもしれません。簡単にするため、TextMessageの内容をワーカースレッドへ送信することを選択します。

図 8.56. onMessage()メソッドからのワーカーBeanの呼び出し

// ワーカを取得します。
HelloWorker worker = workerHome.create();

// メッセージを取得します。ここで既知のクラスのオブジェクトを含むObjectMessageを
// 得るかもしれません。ここでは簡単にするためテキストを使います。
if (message instanceof TextMessage) {

   TextMessage m = (TextMessage)message;

   // ワーカBeanを呼び出します。
   worker.doWork(m.getText());

}

クラスの完全なリスト:

図 8.57. リスナBean (org/jboss/docs/jms/mdb/beanディレクトリにあるHelloListener.java)

package org.jboss.docs.jms.mdb.bean;

import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
import javax.ejb.EJBException;
import javax.ejb.CreateException;

import javax.naming.InitialContext;
import javax.naming.Context;

import javax.jms.MessageListener;
import javax.jms.Message;
import javax.jms.TextMessage;

import org.jboss.docs.jms.mdb.interfaces.HelloWorker;
import org.jboss.docs.jms.mdb.interfaces.HelloWorkerHome;

/**
 * リスナパターンを示した単純なMDB
 * 宛先からメッセージを取得し、ワーカセッションBeanを呼び出します。
 * (実際には、自分自身の仕事もします)
 *
 * Created: Thu Jul 26 13:20:32 2001
 *
 * @author Peter Antman
 * @version $Revision: 1.1.1.1 $ $Date: 2002/04/08 13:01:19 $
 */

public class HelloListener implements MessageDrivenBean, MessageListener {

  /**
   * Session worker bean
   */
  private HelloWorkerHome workerHome = null;

  private MessageDrivenContext ctx = null;

  public HelloListener() {

  }

  //--- MessageDrivenBean
  public void setMessageDrivenContext(MessageDrivenContext ctx)
    throws EJBException {

    this.ctx = ctx;

  }

  public void ejbCreate() throws CreateException{

    // ワーカBeanのホームを取得します。
    try {

      Context initCtx = new InitialContext();
      workerHome =
        (HelloWorkerHome)initCtx.lookup("java:comp/env/ejb/worker");

    } catch(Exception ex) {

      throw new CreateException("Could not get worker: " + ex);

    }

  }

  public void ejbRemove() {ctx=null;}

  //--- MessageListener
  public void onMessage(Message message) {

    System.out.println("HelloListen got message " + message.toString());

    try {

      // ワーカを取得します。
      HelloWorker worker = workerHome.create();

      // メッセージを取得します。ここで既知のクラスのオブジェクトを含むObjectMessageを
      // 得るかもしれません。ここでは簡単にするためテキストを使います。
      if (message instanceof TextMessage) {

        TextMessage m = (TextMessage)message;

        // invoke the worker bean
        worker.doWork(m.getText());

      }

    } catch(Exception ex) {

      // もしも、requiredが指定されたコンテナ管理のトランザクションなら、
      // そのトランザクションコンテキストを継承するものから呼び出された
      // 受信メッセージに加え、すべてのBeanとリソースをロールバックします。

      throw new EJBException("Could not call worker " + ex);

    }

  }

} // HelloListener

このMDBをJBossにデプロイするためには、二つのデプロイメント記述を書くことが必要です。ひとつは標準的なもの、もうひとつはJBoss固有のものです。標準的なものから取り掛かりましょう。使いやすいように両方のBeanをひとつのJARファイルに含めます。メッセージ駆動型Beanでは、それがトピックか否かということと、それが使うべきトランザクションモードの種類、を決定しなければなりません。このケースでは、トピックとコンテナ管理のトランザクションを選択しました。リスナがワーカーBeanのホームをルックアップできるように、ejb-ref要素を指定もしなければなりません。

図 8.58. リスナのためのejb-jar.xmlにおけるメッセージ駆動型Beanの部分

<message-driven>
  <ejb-name>HelloListener</ejb-name>
  <ejb-class>org.jboss.docs.jms.mdb.bean.HelloListener</ejb-class>
  <message-selector></message-selector>
  <transaction-type>Container</transaction-type>
  <ejb-ref>
    <description>The Workers home</description>
    <ejb-ref-name>ejb/worker</ejb-ref-name>
    <ejb-ref-type>Session</ejb-ref-type>
    <ejb-link>HelloWorkerBean</ejb-link>
    <home>org.jboss.docs.jms.mdb.interfaces.HelloWorkerHome</home>
    <remote>org.jboss.docs.jms.mdb.interfaces.HelloWorker</remote>
  </ejb-ref>
  <message-driven-destination>
    <destination-type>javax.jms.Topic</destination-type>
    <subscription-durability>NonDurable</subscription-durability>
  </message-driven-destination>
</message-driven>

ワーカーBeanのエントリの追加もしなければなりません。

図 8.59. リスナのためのejb-jar.xmlにおけるセッションの部分

<session>
  <description>Worker bean</description>
  <display-name>HelloWorkerBean</display-name>
  <ejb-name>HelloWorkerBean</ejb-name>
  <home>org.jboss.docs.jms.mdb.interfaces.HelloWorkerHome</home>
  <remote>org.jboss.docs.jms.mdb.interfaces.HelloWorker</remote>
  <ejb-class>org.jboss.docs.jms.mdb.bean.HelloWorkerBean</ejb-class>
  <session-type>Stateless</session-type>
  <transaction-type>Container</transaction-type>
</session>

これは完全なデプロイメント記述です。それはトランザクションの型の定義も含みます。

図 8.60. リスナBeanのサンプルのためのejb-jar.xml (org/jboss/docs/jms/resourcesディレクトリにある HelloListener-ejb-jar.xml)

<?xml version="1.0"?>
<!DOCTYPE ejb-jar>
<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <ejb-name>HelloListener</ejb-name>
      <ejb-class>org.jboss.docs.jms.mdb.bean.HelloListener</ejb-class>
      <message-selector></message-selector>
      <transaction-type>Container</transaction-type>
      <ejb-ref>
        <description>The Workers home</description>
        <ejb-ref-name>ejb/worker</ejb-ref-name>
        <ejb-ref-type>Session</ejb-ref-type>
        <ejb-link>HelloWorkerBean</ejb-link>
        <home>org.jboss.docs.jms.mdb.interfaces.HelloWorkerHome</home>
        <remote>org.jboss.docs.jms.mdb.interfaces.HelloWorker</remote>
      </ejb-ref>
      <message-driven-destination>
        <destination-type>javax.jms.Topic</destination-type>
        <subscription-durability>NonDurable</subscription-durability>
      </message-driven-destination>
    </message-driven>
    <session>
      <description>Worker bean</description>
      <display-name>HelloWorkerBean</display-name>
      <ejb-name>HelloWorkerBean</ejb-name>
      <home>org.jboss.docs.jms.mdb.interfaces.HelloWorkerHome</home>
      <remote>org.jboss.docs.jms.mdb.interfaces.HelloWorker</remote>
      <ejb-class>org.jboss.docs.jms.mdb.bean.HelloWorkerBean</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
    </session>
  </enterprise-beans>
  <assembly-descriptor>
    <container-transaction>
      <method>
        <ejb-name>HelloListener</ejb-name>
        <method-name>*</method-name>
      </method>
      <trans-attribute>Required</trans-attribute>
    </container-transaction>
    <container-transaction>
      <method>
        <ejb-name>HelloWorkerBean</ejb-name>
        <method-intf>Remote</method-intf>
        <method-name>*</method-name>
      </method>
      <trans-attribute>Required</trans-attribute>
    </container-transaction>
  </assembly-descriptor>
</ejb-jar>

JBoss固有のjboss.xmlデプロイメント記述を書くことも必要です。これが必要なのは、宛先のJNDI名がどこかで定義されなければならないからです。つまり、単にデフォルトを使うことができないということです。

図 8.61. リスナBeanのためのJBossデプロイメント記述 (org/jboss/docs/jms/resourcesディレクトリにあるHelloListener-jboss.xmlより)

<?xml version="1.0"?>
<jboss>
  <enterprise-beans>
    <message-driven>
      <ejb-name>HelloListener</ejb-name>
      <configuration-name>Standard Message Driven Bean</configuration-name>
      <destination-jndi-name>topic/testTopic</destination-jndi-name>
    </message-driven>
    <secure>false</secure>
  </enterprise-beans>
</jboss>

さあ、これらのBeanをコンパイルしなければならない時が来ました。これを成功させるにはクラスパスにいくつかのJARファイルを追加しなければなりません。MDBにとって、中でも特に重要なのは、標準JBossインストレーションのlib/extディレクトリにあるejb2.0.jarです。

[2.4.0. それはclientディレクトリにあるjboss-j2ee.jarです。]

後で、これらのBeanをひとつのJARファイルにまとめて、そのJARファイルをJBossのdeployディレクトリにコピーすることでデプロイする必要があります。メッセージをそのBeanにパブリッシュするために例項にあるサンプルのパブリッシャでHelloPublisherを使うことができます。

サンプルコードは、org/jboss/docs/jms/mdb/beanディレクトリにあるHelloListener.javaHelloWorkerBean.java、それにorg/jboss/docs/jms/mdb/interfacesディレクトリにあるHelloWorker.javaHelloWorkerHome.javaに見つけることができます。デプロイメント記述は、org/jboss/docs/jms/resourcesディレクトリにあるHelloListener-ejb-jar.xmlHelloListener-jboss.xmlのファイルにあります。

Antビルドファイルを使って、そのサンプルを実行することが可能です。

図 8.62. HelloListenerサンプルの実行

ant jms-hello-listener

出力結果はこのような感じになります。

図 8.63. HelloListenerサンプルの実行出力

[Default] WorkerBean doing work: Hello World no. 3
[Default] WorkerBean doing work: Hello World no. 5
[Default] WorkerBean doing work: Hello World no. 2
[Default] WorkerBean doing work: Hello World no. 6
[Default] WorkerBean doing work: Hello World no. 4
[Default] WorkerBean doing work: Hello World no. 1
[Default] HelloListen got messageTextMessage@Hello World no. 7
[Default] WorkerBean doing work: Hello World no. 7
[Default] HelloListen got messageTextMessage@Hello World no. 8
[Default] WorkerBean doing work: Hello World no. 8
[Default] HelloListen got messageTextMessage@Hello World no. 9
[Default] WorkerBean doing work: Hello World no. 9

このサンプルは常に動作するとは限りません。 なぜなら、そのサンプルはそれらのBeanの(コピーによってなされる)デプロイメントに依存していて、それらのBeanはクライアントが起動する前に終了してしまうことがあるからです。 もし動かなかったら、何回か実行してください。

アダプタパターン

MDBを使う別の方法は、たとえば異なるメッセージ システム間のアダプタとして使うことです。これは、特に他のシステムに接続するためのJ2EEコネクタ リソース アダプタを持っているならば、価値あることです。なぜなら、高度なプログラミングをしなくとも、とても効果的なマルチスレッド化された、プール機能を持つシステムを手に入れることになるからです。メッセージング サーバXmlBlasterのためのリソースアダプタを書いたので、ここではJMSをそれに適用させる方法を見ていきましょう。そのソースコードを入手するには、XmlBlasterのソースを調べてください。

そのアダプタは、トピックをサブスクライブするためにMDBを使います。次に、XmlBlaster K2 J2EEコネクタアダプタを使って、XmlBlasterサーバへメッセージを再びサブスクライブします。そのコードはかなり単純です。J2EEコネクタ リソースアダプタはJBossサーバにデプロイされなければなりません。そのアダプタは、次にJDBCリソースを参照したのと同様の方法でそのBean内部から参照されます。このような方法でルックアップをおこないます。

factory = (BlasterConnectionFactory)
  new InitialContext().lookup("java:comp/env/xmlBlaster");

そしてこのように使用します。

con = factory.getConnection();

// Blasterのヘッダを作ります。
String key = "<key oid=\"" + message.getJMSMessageID() +
  "\" contentMime=\"text/xml\"></key>";
String qos = "<qos></qos>";

con.publish(new MessageUnit(key,msg.getBytes(),qos));

完全なBeanは非常に簡単です(たとえば、データベースへ直接書くのとほとんど同じコードが使われます)。

package javaclients.j2ee.k2;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
import javax.ejb.EJBException;

import javax.jms.MessageListener;
import javax.jms.Message;
import javax.jms.TextMessage;
import javax.jms.JMSException;

import javax.resource.ResourceException;

import org.xmlBlaster.j2ee.k2.client.*;

import org.xmlBlaster.util.XmlBlasterException;
import org.xmlBlaster.engine.helper.MessageUnit;

public class JmsAdapter implements MessageDrivenBean, MessageListener{

  private MessageDrivenContext ctx = null;
  private BlasterConnectionFactory factory = null;

  public JmsAdapter() {

  }

  public void setMessageDrivenContext(MessageDrivenContext ctx)
    throws EJBException {

    this.ctx = ctx;

    try {

      factory = (BlasterConnectionFactory)
        new InitialContext().lookup("java:comp/env/xmlBlaster");

    } catch (NamingException ex) {

      throw new EJBException ("XmlBlaster not found: " +
        ex.getMessage());

    } catch(Throwable th) {

      System.err.println("Throwable: " + th);
      th.printStackTrace();
      throw new EJBException("Throwable in setContext: " + th);

    }

  }

  public void ejbCreate() {}

  public void ejbRemove() {ctx=null;}

  public void onMessage(Message message) {

    BlasterConnection con = null;

    try {

      // 処理するメッセージを取得します。
      System.err.println("Got message: " + message);

      if (message instanceof TextMessage) {

        String msg = ((TextMessage)message).getText();

        // 接続を取得します。
        con = factory.getConnection();

        // Blasterのヘッダを作成します - ここで、どうやってキーを扱うのでしょうか?
        String key = "<key oid=\"" + message.getJMSMessageID() +
          "\" contentMime=\"text/xml\"></key>";

        String qos = "<qos></qos>";
        con.publish(new MessageUnit(key,msg.getBytes(),qos));

      } else {

        System.err.println("Got message type I cant handle");

      }

    } catch(ResourceException re) {

      System.err.println("Resource ex: " + re);
      re.printStackTrace();

    } catch(XmlBlasterException be) {

      System.err.println("Blaster ex: " + be);
      be.printStackTrace();

    } catch(JMSException je) {

      System.err.println("JMSException ex: " + je);
      je.printStackTrace();

    } catch(Throwable th) {

      System.err.println("Throwable: " + th);
      th.printStackTrace();

    } finally {

      try {

        if (con != null)
          con.close ();

      }
      catch (Exception ex) {}

    }

  }

} // MessageBeanImpl

このBeanのためのデプロイメント記述は、resource-ref要素のエントリを追加しなければならないということを除いては、一般的なものです。これは標準的なEJBデプロイメント記述です。

<?xml version="1.0"?>
<!DOCTYPE ejb-jar>
<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <ejb-name>JmsAdapter</ejb-name>
      <ejb-class>javaclients.j2ee.k2.JmsAdapter</ejb-class>
      <message-selector></message-selector>
      <transaction-type>Container</transaction-type>
      <resource-ref>
        <res-ref-name>xmlBlaster</res-ref-name>
        <res-type>org.xmlBlaster.j2ee.k2.client.BlasterConnectionFactory</res-type>
        <res-auth>Container</res-auth>
      </resource-ref>
      <message-driven-destination>
        <destination-type>javax.jms.Topic</destination-type>
        <subscription-durability>NonDurable</subscription-durability>
      </message-driven-destination>
    </message-driven>
  </enterprise-beans>
  <assembly-descriptor>
    <container-transaction>
      <method>
        <ejb-name>JmsAdapter</ejb-name>
        <method-name>*</method-name>
      </method>
      <trans-attribute>Required</trans-attribute>
    </container-transaction>
  </assembly-descriptor>
</ejb-jar>

そして、これはJBoss固有のjboss.xmlディスクリプタです。

<?xml version="1.0" encoding="Cp1252"?>

<jboss>
  <resource-managers>
    <resource-manager>
      <res-name>xmlBlaster</res-name>
      <res-jndi-name>java:/XmlBlasterDS</res-jndi-name>
    </resource-manager>
  </resource-managers>
  <enterprise-beans>
    <message-driven>
      <ejb-name>JmsAdapter</ejb-name>
      <configuration-name>Standrad Message Driven Bean</configuration-name>
      <destination-jndi-name>topic/testTopic</destination-jndi-name>
      <resource-ref>
        <res-ref-name>xmlBlaster</res-ref-name>
        <resource-name>xmlBlaster</resource-name>
      </resource-ref>
    </message-driven>
    <secure>false</secure>
  </enterprise-beans>
</jboss>

高度なMDBの設定

JBossでのMDBサポートの実装は、MDBを使うためにユーザはJBossの内部の詳細を知るべきではないという方針で書かれています。jboss.xmlに数行を追加することを除いては、メッセージ駆動型Beanについての標準的な知識だけで十分足ります。

JBossの他の部分の設計と同様に、もしもデフォルトの設定や実装をチューニングしたり変更したいなら、MDB実装も極限まで設定変更をおこなうことが可能です! ここでは、JBossにおいてMDBを設定する方法に関していくつかのちょっとした注意を述べます。

EJBデプロイメント記述

すべてのMDBは、設定を変更することが極めて容易です。ここにあるのは、選ぶことができる基本的な選択肢です。

  • Beanは、javax.jms.Topicまたはjavax.jms.QueueのどちらかのBeanにすることができます。 これはdestination-type要素で指定されます。 2.4.0までは、JBossのこの部分は標準に準拠していませんでした。 message-driven-destination要素は、実際にはejb-jar.xmlのEJB 2.0 DTDではオプション扱いの要素です。しかし、JBossではそれは必須です。なぜなら、JBossがそのBeanがバインドされるべきJMSの宛先の種類を知るすべが他に無いからです。 . [2.4.1]では、これは解決されて、その要素は新たにオプションになりました。 message-driven-destinationが設定されなければ、JBossはjboss.xmlで与えられた宛先からひとつを決めます。これが不可能なら、あるトピックタイプをデフォルトにします。

    <message-driven-destination>
      <destination-type>javax.jms.Queue</destination-type>
      <subscription-durability>NonDurable</subscription-durability>
    </message-driven-destination>
    
    
  • もし、BeanがTopicなら、持続的でない(non-durable)か、持続的(durable)のいずれかで、それはsubscription-durability要素に指定されます。

    <message-driven-destination>
      <destination-type>javax.jms.Topic</destination-type>
      <subscription-durability>Durable</subscription-durability>
    </message-driven-destination>
    
    
  • Beanは、Beanまたはコンテナで管理されたトランザクションを持つことができ、それはtransaction-type要素に指定されます。

    <transaction-type>Container</transaction-type>
    
    
  • Bean管理によるトランザクションを持つBeanは、Auto-acknowledgeDups-ok-acknowledgeのいずれかの確認応答(acknowledgement)のタイプを持つことができます。 これは、JBossでは現在のところサポートされていません。なぜなら、コンテナは常にトランザクションのもとでメッセージを受信しますが、それはacknowledge-mode要素で指定されるからです。

    <transaction-type>Bean</transaction-type>
    <acknowledge-mode>Auto-acknowledge</acknowledge-mode>
    
    
  • コンテナ管理によるトランザクションを持つBeanは、それがトランザクションを要求するか、あるいはサポートしないかのいずれかを指定することができ、それはtrans-attribute要素で指定されます。

    <assembly-descriptor>
      <container-transaction>
        <method>
          <ejb-name>HelloTopicDurableMDB</ejb-name>
          <method-name>*</method-name>
        </method>
        <trans-attribute>Required</trans-attribute>
      </container-transaction>
    </assembly-descriptor>
    
    
  • MDBはJMSセレクタシンタクスに従ったセレクタを使うこともでき、それはmessage-selector要素で指定されます。

    <message-selector>JMSType='activityCompletion'</message-selector>
    
    

もちろん、message-driven内の一連の記述の中では、ejb-refresource-ref要素のような、EJBデプロイメント記述の他の一般的な要素も指定できます。

JBossデプロイメント記述

MDB設定オプションの中身は、jboss.xmlデプロイメント記述にあります。

[2.4.0. このファイルは、このバージョンのJBossで始めるならオプションです。 そのようなケースでは、Beanをバインドする宛先は指定されていないので、JBossはBeanの名前を持ったBeanの宛先を作成します。これはお手軽かもしれませんが、同時に危険でもあります。なぜなら、間違った宛先はあなたを間違った方向へ導くかもしれません。クライアントを一時的に利用可能なだけの宛先へ結び付けなければなりません。もし、そのMDBがアンデプロイされたり、再デプロイされると、その宛先が破壊されてしまうからです。]

このファイルでの設定は、二つの部分に分けられます。特定のBeanを設定する必須の部分と、コンテナを設定するオプションの部分です。それらは、standardjboss.xmlの内容をデフォルトにします。ここで、それらの両方を説明しますが、コンテナ設定は、jboss.xmlファイルの外部のものに関係してくるので、いくつかの部分に分けられます。

Beanでは、第一の部分は、常にJMSの宛先のためのJNDI名を指定しなければなりません。JBossMQでは、これは常にプリフィックスtopic/か、プリフィックスqueue/のいずれかの後に宛先名が続いたものから構成されます。

図 8.64. jboss.xmlでの宛先の定義

<destination-jndi-name>topic/testTopic</destination-jndi-name>

Bean名とコンテナ設定の名前も指定しなければなりません。standardjboss.xmlでの設定を使用するため、Standard Message Driven Beanという名前を与えます。

図 8.65. MDBのためのjboss.xmlの例

<message-driven>
  <ejb-name>HelloTopicMDB</ejb-name>
  <configuration-name>Standard Message Driven Bean</configuration-name>
  <destination-jndi-name>topic/testTopic</destination-jndi-name>
</message-driven>

JBossMQへログインするためにユーザ名とパスワード(conf/default/jbossmq.xmlで設定可能)を使うことも可能です。もしDurableトピックを指定したのなら、それらは要求されますが、さもなければオプション扱いです。もし、ユーザが指定されれば、クライアントIDも指定する必要があります。jbossmq.xmlで既定値を使うと、このようなデプロイメント記述を持つことができます。

図 8.66. 持続的サブスクリプションを持つMDBのためのjboss.xmlの例

<message-driven>
  <ejb-name>HelloTopicDurableMDB</ejb-name>
  <configuration-name>Standard Message Driven Bean</configuration-name>
  <destination-jndi-name>topic/testTopic</destination-jndi-name>
  <mdb-user>john</mdb-user>
  <mdb-passwd>needle</mdb-passwd>
  <mdb-client-id>DurableSubscriberExample</mdb-client-id>
</message-driven>

MDBの標準コンテナ設定は、standardjboss.xmlにあります。しかし、jboss.xmlデプロイメント記述にある他の値を指定することでこの設定を上書きすることも可能です。最初に完全なセットを見て、それから個々のエントリを見ていきましょう。

図 8.67. MDBのコンテナ設定 (org/jboss/docs/jms/resourcesディレクトリにあるHelloMDB-Topic-FullConf-jboss.xmlより)

<?xml version="1.0"?>
<jboss>
  <enterprise-beans>
    <message-driven>
      <ejb-name>HelloTopicMDB</ejb-name>
      <configuration-name>My Message Driven Config</configuration-name>
      <destination-jndi-name>topic/testTopic</destination-jndi-name>
    </message-driven>
  </enterprise-beans>
  <container-configurations>
    <container-configuration>
      <container-name>My Message Driven Config</container-name>
      <call-logging>false</call-logging>
      <container-invoker>org.jboss.ejb.plugins.jms.JMSContainerInvoker</container-invoker>
      <container-interceptors>
        <interceptor>org.jboss.ejb.plugins.LogInterceptor</interceptor>
        <interceptor>org.jboss.ejb.plugins.SecurityInterceptor</interceptor>
        <!-- CMT -->
        <interceptor transaction="Container">org.jboss.ejb.plugins.TxInterceptorCMT</interceptor>
        <interceptor transaction="Container" metricsEnabled="true">org.jboss.ejb.plugins.MetricsInterceptor</interceptor>
        <interceptor transaction="Container">org.jboss.ejb.plugins.MessageDrivenInstanceInterceptor</interceptor>
        <!-- BMT -->
        <interceptor transaction="Bean">org.jboss.ejb.plugins.MessageDrivenInstanceInterceptor</interceptor>
        <interceptor transaction="Bean">org.jboss.ejb.plugins.MessageDrivenTxInterceptorBMT</interceptor>
        <interceptor transaction="Bean" metricsEnabled="true">org.jboss.ejb.plugins.MetricsInterceptor</interceptor>
      </container-interceptors>
      <instance-pool>org.jboss.ejb.plugins.MessageDrivenInstancePool</instance-pool>
      <instance-cache></instance-cache>
      <persistence-manager></persistence-manager>
      <transaction-manager>org.jboss.tm.TxManager</transaction-manager>
      <container-invoker-conf>
        <JMSProviderAdapterJNDI>DefaultJMSProvider</JMSProviderAdapterJNDI>
        <ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI>
        <MaximumSize>15</MaximumSize>
        <MaxMessages>1</MaxMessages>
        <Optimized>True</Optimized>
      </container-invoker-conf>
      <container-pool-conf>
        <MaximumSize>100</MaximumSize>
        <MinimumSize>10</MinimumSize>
      </container-pool-conf>
    </container-configuration>
  </container-configurations>
</jboss>

MDBコンテナの設定可能な属性のいくつかを見てみましょう。

Container invoker

container invoker(訳注: どう訳したらいいの)は、コンテナシステムへメッセージを送るものです。それは、JMSを処理しなければならないすべてのものを扱う責任があります。MDBコンテナの残りの部分は、container invokerが使用するメッセージシステムの種類に関して、基本的に寛容です。したがって、他の種類のメッセージシステムのための新しいcontainer invokerを書くことも可能です。これには現在のところ一つの限界があります。Beanクラスは、MessageListenerインタフェースを実装しなければならないので、invokerはこのインタフェースを採用しなければならないのです。これは、MDBの新しいリリースではプラガブルになるでしょう。

コンテナ インタセプタ

コンテナ インタセプタは、コンテナ システムで絶対必要な部分で、各インタセプタはEJBコンテナ契約(contract)を実行するのに必要な特定のことを遂行します。それらすべてはプラガブルです。それは、新しいインタセプタの実装を書いて、特に必要なBeanにプラグインすることができることを意味します。これはとても高度な仕事と考えるべきであるにもかかわらずです。

Container invokerの設定

これは、おそらく、理解しようするなかで最も興味深い部分です。細部を見ていきましょう。まず、それはJMSProviderAdapterJNDIを定義します。

図 8.68. jboss.xmlでのJMSProviderAdapterJNDIの設定

<JMSProviderAdapterJNDI>DefaultJMSProvider</JMSProviderAdapterJNDI>

それは、プロバイダのアダプタクラスをルックアップできるようにJMX BeanのJNDI名を含むべきです。このクラスは、次にinvokerによって接続ファクトリの名前を探すために使われます。すべてのイニシャル コンテキストのルックアップは、JBossの外部のJMSプロバイダへアクセスできるように、このクラスによっておこなわれます。

デフォルトで使われる名前は、jboss.jcmlのJbossMQProviderにバインドします。それはこのような感じです。

図 8.69. jboss.jcmlでのJMSProviderAdapterの定義

<mbean code="org.jboss.jms.jndi.JMSProviderLoader"
  name=":service=JMSProviderLoader,name=JBossMQProvider">
  <attribute name="ProviderName">DefaultJMSProvider</attribute>
  <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JBossMQProvider</attribute>
</mbean>

[2.4.0. このバージョンでは追加情報があります。]

図 8.70. [2.4.0] jboss.jcmlでのJMSProviderAdapterの定義

<mbean code="org.jboss.jms.jndi.JMSProviderLoader"
  name=":service=JMSProviderLoader,name=JBossMQProvider">
  <attribute name="ProviderName">DefaultJMSProvider</attribute>
  <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JBossMQProvider</attribute>
  <attribute name="QueueFactoryRef">java:/INVMXAQueueConnectionFactory</attribute>
  <attribute name="TopicFactoryRef">java:/INVMXATopicConnectionFactory</attribute>
</mbean>

[2.4.1. JNDI文字列はこのバージョンで変りました。]

図 8.71. [2.4.1] jboss.jcmlでのJMSProviderAdapterの定義

<mbean code="org.jboss.jms.jndi.JMSProviderLoader"
  name=":service=JMSProviderLoader,name=JBossMQProvider">
  <attribute name="ProviderName">DefaultJMSProvider</attribute>
  <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JBossMQProvider</attribute>
  <attribute name="QueueFactoryRef">java:/INVMXAConnectionFactory</attribute>
  <attribute name="TopicFactoryRef">java:/INVMXAConnectionFactory</attribute>
</mbean>

jboss.jcmlにもっとJMSProviderを追加して、それらをコンテナ設定で使うことも可能です。これをする考え得る理由のひとつは、別のJBossサーバのキューやトピックをリスンすることです。そのケースでは、別のプロバイダを定義して、そのコンテキストを設定することができます。これは、属性ProviderUrlをJMSProviderLoader MBean設定に追加することでおこなわれます。次に、これをjboss.jcmlに追加するかもしれません。

図 8.72. jboss.jcmlにあるリモートJMSProviderAdapterの定義

<attribute name="ProviderUrl">remote.com:1099</attribute>

ProviderUrl属性を追加したら、jboss.xmlに次のJMSProviderAdapterJNDIを書き込みます。

図 8.73. jboss.xmlでのリモートJMSProviderAdapterの設定

<JMSProviderAdapterJNDI>RemoteJMSProvider</JMSProviderAdapterJNDI>

この設定オプションを使うもうひとつの別の方法は、別のJMSプロバイダをJBossへ統合することです。これは、OpenJMS実装を使って、実際にMDBが最初にJBossに実装された方法でした。これをするためには、org.jboss.jms.jndi.JMSProviderAdapterインタフェースを実装しなければなりません。しかし、注意してください。そのJMSプロバイダは、完全なJMSアプリケーション サービス ファシリティ(ASF, JMS仕様書 8章)をサポートしていないかもしれません。ProviderAdapterとServerSessionまわりの両方の完全な実装を書かなければならなくなるでしょう。これをおこなうのは、本当に高度なテーマで、おそらくjboss-devメーリングリストにコンタクトを取って扱うべきです。

次に、ServerSessionPoolFactoryJNDI要素があります。

図 8.74. jboss.xmlでのServerSessionPoolファクトリ JNDIの設定

<ServerSessionPoolFactoryJNDI>StdJMSPool</ServerSessionPoolFactoryJNDI>

これは、jboss.jcmlからロードされたクラスも指しています。 それはServerSessionPoolへのエントリポイントです。 プロバイダ固有のプールを書いたり、既存ものをカスタマイズする必要があるなら、 特定のBean向けにそれをロードすることが可能です。 既存のものはjboss.jcmlでこのように定義されます。

図 8.75. jboss.jcmlでのServerSessionPoolファクトリの設定

<mbean code="org.jboss.jms.asf.ServerSessionPoolLoader"
  name=":service=ServerSessionPoolMBean,name=StdJMSPool">
  <attribute name="PoolName">StdJMSPool</attribute>
  <attribute name="PoolFactoryClass">org.jboss.jms.asf.\
StdServerSessionPoolFactory</attribute>
</mbean>

JBossためのMDBの最初の実装は、別のサーバの(特に、OpenJMSのために書かれた)セッション プール ファクトリをベースにしていました。現在は、それは動作していません。動作しているのは、サーバのセッション プール ファクトリがプラグイン可能であるということです。

最後の二つのエントリはこのようになります。

図 8.76. jboss.xmlでのサーバのセッション プールの設定

<MaximumSize>15</MaximumSize>
<MaxMessages>1</MaxMessages>

これらの最初のMaximumSizeは、プールの大きさを入力メッセージのを処理する準備にできたセッションの数で定義しています。二番目のMaxMessagesは、セッションが一度に処理することが許されたメッセージの最大数を設定するのに使われます。私のそのオプションを変更したことはありませんので、JBossMQが実際にそれをサポートしているのかどうかは知りません。 もし使えば、パフォーマンスを改善できるかもしれません。

[doc] [toc] [previous] [next]

Copyright © 2000 2001 JBoss Organization
Copyright © 2001 2002 日本語訳: Neverbird Project