第7章 高度なトピック

JBoss Enterprise Service Bus 関連の高度なコンセプトについては本章を参照してください。

7.1. フェールオーバーと負荷分散のサポート

ミッションクリティカルなシステムでは、冗長性を念頭に置いた設計が重要となります。 JBoss Enterprise Service Bus にはビルトインのフェールオーバー、負荷分散そして堅固なアーキテクチャーの構築に役立つ遅延メッセージ再配信機能が含まれます。SOA を使用する場合、サービスはビルディングユニットとなることを意味します。JBoss Enterprise Service Bus では多くのノードにわたりまったく同一となるサービスのリプリケーションが可能になります。各ノードは JBossESB のインスタンスを実行している仮想のマシンまたは物理マシンになり得ます。こうした JBossESB 全インスタンスの集合はバスと呼ばれます。このバス内のサービスはメッセージの交換に異なる配信チャンネルを使用します。ESB 用語では、こうしたチャンネルは JMS、 FTP、 HTTP などになります。 このような異なる「プロトコル」はシステムにより外部的に ESB の JMS プロバイダーや FTP サーバーなどに提供されます。サービスは 1 つのプロトコルまたは複数のプロトコルをリッスンするよう設定可能です。リッスンするよう設定される各プロトコルに対して、ESB は registry 内にエンドポイント参照 (EPR) を作成します。

7.1.1. サービス、エンドポイント参照 (EPR)、リスナー、アクション

jboss-esb.xml ファイル内では、各サービス要素は 1 つ以上のリスナーやアクションで構成されています。以下の設定 (一部) は、JBossESBHelloworld の例では、ある程度これをベースとしています。サービスが初期化されると、カテゴリ、名前、説明を UDDI registry に登録します。そして、各リスナー要素に対して ServiceBinding を UDDI に登録します。エンドポイント参照にこれらを保存します。
...
<service category="FirstServiceESB" name="SimpleListener" description="Hello World">
    <listeners>
        <jms-listener name="helloWorld" busidref="quickstartEsbChannel" maxThreads="1"/>
    </listeners>
    <actions>
        <action name="action1" class="org.jboss.soa.esb.actions.SystemPrintln"/>
    </actions>
</service>
...
カテゴリとサービス名が渡されると、別のサービスが Hello World registry を検索して、メッセージを送信できます。JMSEPR を受け取り、それを使ってメッセージを送信できます。こうした負荷の大きい作業はすべて ServiceInvoker クラスで行われます。HelloWorld サービスが quickstartEsbChannel 経由でメッセージを受け取ると、pipeline の最初のアクションである SystemPrintln に所属するプロセスメソッドに渡します。

7.1.2. 複製されたサービス

この例では、サービスは Node1 で実行しています。helloworld.esb ファイルを取り、 Node2 にもデプロイした (下例を参照) 場合、Node2 側で FirstServiceESB - SimpleListener サービスがすでに登録されていることがわかります。そのため、2 つ目の ServiceBinding をこのサービスに追加して、複製します。Node1 が失敗すると、Node2 が継続して機能します。
異なるノードにある 2 つのサービスインスタンス

図7.1 異なるノードにある 2 つのサービスインスタンス

両方のサービスインスタンスが同じキューをリッスンするため負荷分散機能を得ることになります。ただし、まだこのセットアップでは単一障害点があることになります。このため、次のセクションで説明するプロトコルクラスタリングがひとつの選択肢となります。
このタイプのレプリケーションを使用してサービスの利用度を向上したり負荷分散機能を提供することができます。詳しく説明するため、論理サービス (アプリケーションサービス) を持つ以下の図を見てください。実際には 4 つの個別なサービスから構成され、それぞれ同じ機能を提供し同じサービス規定に準じています。異なるのは同じトランスポートプロトコルを共有する必要がないということだけです。しかし、アプリケーションサービスのユーザーに関する限り、ユーザーにはサービス名とカテゴリで識別される単一のサービスしか見えません。ServiceInvoker はアプリケーションサービスが実際には 4 つのサービスから構成されているという事実をクライアントには見えないようにしています。これにより個別サービスの障害が隠され、複製されるサービスグループの少なくとも 1 インスタンスが利用できる状態にある限りクライアントは先に進むことができます。

重要

このタイプのレプリケーションはステートレスのサービスにのみ使用してください。
プロバイダーはサービスコンシューマー側のサービスを自主的に複製する場合があります。しかし、サービスが自動的にリジストリ内で定義された代替サービスにフェールオーバーされるのを好まない場合があります。自動的なフェイルオーバーを防ぐにはメッセージプロパティ org.jboss.soa.esb.exceptionOnDeliverFailuretrue に設定します。このプロパティを設定すると、メッセージを再送信する代わりに ServiceInvoker によって MessageDeliverException がスローされます。すべてのメッセージにこれを指定するには、 JBoss Enterprise Service Bus property ファイルの Core セクションでこのプロパティを設定します。

7.1.3. プロトコルのクラスタリング

JMS プロバイダーの中にはクラスター化が可能なものがあります。JBossMessaging もこうしたプロバイダーのひとつで、Enterprise Service Bus の JMS プロバイダーとしてこれを使用するのもその理由です。JMS をクラスター化することでアーキテクチャーから単一障害性を排除します。次の図を参照してください。
JMS を使用したプロトコルクラスタリングの例

図7.2 JMS を使用したプロトコルクラスタリングの例

JMS クラスタリングを有効にしたい場合は JBossMessaging のクラスタリングに関するドキュメントをお読みください。JBossESB レプリケーションと JMS クラスタリングは以下の図に示すように一緒に使用することができます。この例では、サービス A が単一の JMSEpr によりレジストリ内で指定されています。しかし、クライアントには不透明にその JMSEpr はクラスター化された JMS キューを参照し、これは 3 つのサービスをサポートするため別々に設定されています。利用度や負荷分散機能に対する連合的な手段となります。 実際、サービスのレプリケーションをユーザー (JBossESB レプリケーションの方法の場合はクライアントであり、JMS クラスタリングの場合は JBossESB) に見えないようにするのは SOA の原則と一致しています。これら実装の詳細をサービスエンドポイントの背後に隠し規定レベルでは公開しません。

注記

JMS クラスタリングをこの方法で使用している場合、明らかに設定が正しく行われているかを確認する必要があります。たとえば、ESB サービスをすべて JMS クラスター内に配置する場合は ESP レプリケーションの利点を生かすことはできません。
プロトコルクラスタリングの別の例としては FileSystem プロトコルの NAS (Network Attached Storage) がありますが、ご使用のプロバイダーが単純にクラスタリングをまったく提供できない場合はどうでしょう。このような場合には、サービスに複数のリスナーを追加し、複数の (JMS) プロバイダーを使用することができます。ただし、これにはフェールオーバーと負荷分散機能がプロバイダー全体に必要となります。それでは、これについて次のセクションで見ていくことにします。

7.1.4. クラスタリング

クラスター内の複数のノードで同じサービスを実行したい場合、サービスが完全にクラスター化された環境で動作する前にサービスレジストリキャッシュの再検証を待たなければなりません。このキャッシュ再検証のタイムアウトは deploy/jbossesb.sar/jbossesb-properties.xml でセットアップできます。
<properties name="core">
<property name="org.jboss.soa.esb.registry.cache.life" value="60000"/>
</properties>

デフォルトのタイムアウトは 60 秒です。

7.1.5. チャンネルのフェールオーバーと負荷分散機能

HelloWorld サービスはプロトコル 1 つ以上のリッスンが可能です。以下では FTP チャンネルを追加しています。
...
<service category="FirstServiceESB" name="SimpleListener" description="Hello World">
    <listeners>
        <jms-listener name="helloWorld"  busidref="quickstartEsbChannel" maxThreads="1"/>
        <jms-listener name="helloWorld2" busidref="quickstartFtpChannel2" maxThreads="1"/>
    </listeners>
...
これでサービスは 2 つの JMS キューを同時にリッスンしていることになります。これらのキューは物理的に異なるマシンで JMS プロバイダーにより提供することができます。つまり、2 つのサービス間の冗長な JMS 接続を確立したということになります。この設定ではプロトコルを混合することも可能なため、FTP リスナーを追加することもできます。
2 つの FTP サーバーをその混合に追加する

図7.3 2 つの FTP サーバーをその混合に追加する

...
<service category="FirstServiceESB" name="SimpleListener"
 description="Hello World">
 <listeners>
  <jms-listener name="helloWorld" busidref="quickstartEsbChannel"
 maxThreads="1"/>
  <jms-listener name="helloWorld2" busidref="quickstartJmsChannel2"
 maxThreads="1"/>
  <ftp-listener name="helloWorld3" busidref="quickstartFtpChannel3"
 maxThreads="1"/>
  <ftp-listener name="helloWorld4" busidref="quickstartFtpChannel3"
 maxThreads="1"/>
 </listeners>
...
ServiceInvoker がサービスにメッセージを配信する場合、 8 個の EPR から選択することになります (Node1 から 4 EPR, Node2 から 4 EPR)。 どれを使用するのかどのように決定するのでしょう。 これについてはポリシーを設定することができます。jbossesb-properties.xml で「org.jboss.soa.esb.loadbalancer.policy」を設定することができます。ここでは 3 つのポリシーが提供されています。また、独自のポリシーを作成することも可能です。
  • 1 番目に利用可能。問題のない ServiceBinding が見つかるとそれが終了しない限り使用され、一覧内の次の EPR に移動します。このポリシーは 2 つのサービスインスタンス間での負荷分散は提供しません。
  • ラウンドロビン。一般的な負荷分散ポリシーで、各 EPR は一覧の順でヒットされます。
  • ランダムロビン。他のロビンと似ていますがランダムになります。
ポリシーが動作する EPR 一覧は、終了した EPR が (キャッシュされた) 一覧から削除されていくため小さくなっていく場合があります。一覧が空になった場合または一覧のキャッシュの time-to-live を越えた場合、ServiceInvoker はレジストリから真新しい EPR の一覧を取得します。org.jboss.soa.esb.registry.cache.life は jbossesb-properties ファイルで設定でき、デフォルトでは 60,000 ミリ秒に設定されます。その時点で動作している EPR がない場合はメッセージ再配信サービスを利用することができます。

7.1.6. メッセージ再配信

EPR の一覧に終了した EPR 以外何も含まれていない場合、ServiceInvoker は以下の 2 つのうちいずれかを行うことができます。
  • メッセージを同期的に配信しようとしている場合、メッセージを DeadLetterService に送信します。デフォルトでは DLQ MessageStore に格納し、 呼び出し側にエラーを返送します。処理は停止します。たとえば、JMS キューに送りたい、あるいは通知を受け取りたい場合などは、jbossesb.esb 内の DeadLetterService を設定することができます。
  • メッセージを非同期的に送信しようとしている場合 (推奨)、この場合もメッセージを DeadLetterService に送信しますがそのメッセージは RDLVR MessageStore に格納されます。再配信サービス (jbossesb.esb) は再配信試行の最大数に達するまでメッセージ送信の再試行を行います。最大数に達すると、メッセージは DLQ MessageStore に格納され処理は停止します。
メッセージ再配信

図7.4 メッセージ再配信

注記

DeadLetterService はデフォルトでは、オンとなっていますが、jbossesb-properties.xml で、org.jboss.soa.esb.dls.redeliver を "false" にするとオフにできます。メッセージベースでこれを管理するには、各メッセージのプロパティで org.jboss.soa.esb.dls.redeliver プロパティを設定してください。グローバル設定より優先して、Message プロパティが使用されます。デフォルトは、設定ファイルに設定された値を使用します。

7.2. サービスのスケジュール

JBoss は 2 種類のプロバイダーをサポートしています。
  1. バスプロバイダー、JMS や HTTP などメッセージングプロトコルを介してアクション処理パイプラインにメッセージを供給します。このプロバイダータイプは基礎となるメッセージングプロバイダーにより起動されます。
  2. スケジュールプロバイダー、スケジュール駆動のモジュールに基づいてアクション処理パイプラインにメッセージを供給します。つまり、基礎となるメッセージ配信のメカニズム (ファイルシステムなど) はメッセージが処理可能になる場合に ESB 起動に対するサポートを提供せず、スケジューラーが定期的にリスナーを起動して新しいメッセージをチェックします。
JBoss ESB は <schedule-listener> の他、 2 つの <schedule-provider> タイプ、<simple-schedule> と <cron-schedule> を提供しています。<schedule-listener> は「composer」クラスで設定され、org.jboss.soa.esb.listeners.ScheduledEventMessageComposer インターフェースの実装になります。

7.2.1. Simple Schedule

このスケジュールタイプは次の属性に基づく簡単なスケジュール機能を提供します。
scheduleid
スケジュール用の固有の識別子文字列になります。 リスナーからスケジュールを参照するために使用されます。
frequency
すべてのスケジュールリスナーが起動されるべき頻度 (秒単位) になります。
execCount
スケジュールが実行されるべき回数になります。
startDate
スケジュールの開始日と時間です。 この属性値の形式は XML スキーマタイプの「dateTime」になります。dateTime を参照してください。
endDate
スケジュールの終了日と時間です。 この属性値の形式は XML スキーマタイプの「dateTime」になります。dateTime を参照してください。
例:
<providers>
        <schedule-provider name="schedule">
		<simple-schedule scheduleid="1-sec-trigger" frequency="1" execCount="5" />
        </schedule-provider>
</providers>

7.2.2. Cron Schedule

このスケジュールタイプは Quartz Scheduler CronTrigger 式に基づいたスケジュール機能を提供します。このスケジュールタイプの属性は以下の通りです。
scheduleid
スケジュール用の一意識別子の文字列になります。リスナーからスケジュールを参照するために使用されます。
cronExpression
これは、Quartz Scheduler CronTrigger 式です。
startDate
スケジュールの開始日と時間です。この属性値の形式は XML スキーマタイプの「dateTime」になります。
endDate
スケジュールの終了日と時間です。この属性値の形式は XML スキーマタイプの「dateTime」になります。
以下に例を示します。
<providers>
	<schedule-provider name="schedule">
		<cron-schedule scheduleid="cron-trigger" cronExpression="0/1 * * * * ?" />
        </schedule-provider>
</providers>
この例は、毎分 1 秒目にスケジュールがトリガーされます。

7.2.3. Scheduled Listener

<scheduled-listener> または <cron-schedule> の設定に基づいてスケジュールされたタスクを実行するには <scheduled-listener> を使用することができます。
event-processor クラスで設定され、org.jboss.soa.esb.schedule.ScheduledEventListener または org.jboss.soa.esb.listeners.ScheduledEventMessageComposer のいずれかの実装になります。
ScheduledEventListener
このインターフェースを実装するイベントプロセッサーは単純に「onSchedule」メソッドで起動されます。 アクション処理パイプラインは実行されません。
ScheduledEventMessageComposer
このインターフェースを実装するイベントプロセッサーはリスナーに関連付けられるアクション処理パイプラインのメッセージを「composing」する機能があります。
このリスナーの属性は次の通りです。
  1. name: リスナーインスタンスの名前です。
  2. event-processor: 各スケジュール起動で呼び出されるイベントプロセッサークラスです。実装詳細については上記を参照してください。
  3. いずれかひとつ
    1. name: リスナーインスタンスの名前です。
    2. scheduleidref: このリスナーの起動に使用するスケジュールの scheduleid です。
    3. schedule-frequency: スケジュールの頻度 (秒単位) です。直接リスナーで簡単にスケジュールを指定する便利な方法になります。

7.2.4. 設定例

<scheduled-listener> と <cron-schedule> に関連する設定例を示します。
<?xml version = "1.0" encoding = "UTF-8"?>
<jbossesb xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd">

    <providers>
        <schedule-provider name="schedule">
            <cron-schedule scheduleid="cron-trigger" cronExpression="0/1 * * * * ?" />
        </schedule-provider>
    </providers>

    <services>
        <service category="ServiceCat" name="ServiceName" description="Test Service">

            <listeners>
                <scheduled-listener name="cron-schedule-listener" scheduleidref="cron-trigger" 
                     event-processor="org.jboss.soa.esb.schedule.MockScheduledEventMessageComposer" />
            </listeners>

            <actions>
                <action name="action" class="org.jboss.soa.esb.mock.MockAction" />
            </actions>			
        </service>
    </services>

</jbossesb>

7.2.5. カスタムのゲートウェイの作成

本章では、Enterprise Service Bus のカスタムリスナーを構築する際に使用可能なメソッド 3 つについて説明しています。
  1. AbstractThreadedManagedLifecycle/AbstractManagedLifecycle Listener: スレッド/非スレッドリスナーを作成するために、ベースリスナー API を使用するリスナー。管理ライフサイクルベースで実行
  2. Schedule Driven Listener: 設定したスケジュールを元にトリガーするために ScheduledEventListener を使用し、Service Action pipeline のメッセージを生成するリスナー
  3. Groovy Scripted Event Driven Listener: 外部プロセスでトリガーするイベントを元に起動して、Service Action Pipeline のメッセージを生成するリスナー (例:JMS キューで受信するメッセージ)

7.2.5.1. AbstractThreadedManagedLifecycle/AbstractManagedLifecycle リスナー

ESB リスナーはすべて AbstractThreadedManagedLifecycle か、AbstractManagedLifecycle クラスを使用して実装します。これらのクラスの継承は単純です。
public class MyCustomGateway extends AbstractThreadedManagedLifecycle {
 
    private ConfigTree listenerConfig;
    private Service service;
    private ServiceInvoker serviceInvoker;
 
    public MyCustomGateway(final ConfigTree config) throws ConfigurationException {
        super(config);
        this.listenerConfig = config;
 
        String serviceCategory = listenerConfig.getRequiredAttribute(ListenerTagNames.TARGET_SERVICE_CATEGORY_TAG);
        String serviceName = listenerConfig.getRequiredAttribute(ListenerTagNames.TARGET_SERVICE_NAME_TAG);
 
        service = new Service(serviceCategory, serviceName);
    }
 
    protected void doInitialise() throws ManagedLifecycleException {
        // Create the ServiceInvoker instance for the target service....
        try {
            serviceInvoker = new ServiceInvoker(service);
        } catch (MessageDeliverException e) {
            throw new ManagedLifecycleException("Failed to create ServiceInvoker for Service '" + service + "'.");
        }
    }
 
    protected void doRun() {
        while(isRunning()) {
            // Wait for a message....
            Object payloadObject = waitForPayload();
 
            // Send the message to the target service's Action Pipeline via
            // the ServiceInvoker...
            try {
                Message esbMessage = MessageFactory.getInstance().getMessage();
 
                esbMessage.getBody().add(payloadObject);
                serviceInvoker.deliverAsync(esbMessage);
            } catch (MessageDeliverException e) {
                e.printStackTrace();
            }
        }
    }
 
    private Object waitForPayload() {
        // Wait for a message...
    }
}

このゲートウェイは、AbstractThreadedManagedLifecycle クラスを継承して、doRun メソッド (Thread method) を実装します。実行ループの反復時において、doRun メソッドがリスナーの実行ステータスを確認する方法に注目してください。
スレッド化されたリスナーを必要としない場合、リスナーは AbstractManagedLifecycle を継承する必要があります。
このようにカスタムのゲートウェイを設定するには、基盤となる設定タイプのバスプロバイダーバスおよびリスナーを以下のように使用する必要があります。
<?xml version = "1.0" encoding = "UTF-8"?>
<jbossesb xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd"
          parameterReloadSecs="5">

    <providers>
        <bus-provider name="CustomProvider">
            <property name="provider-property" value="buprovider-prop-value" />

            <bus busid="custom-bus">
                <property name="bus-property" value="bus-prop-value" />
            </bus>
        </bus-provider>
    </providers>

    <services>
        <service category="Custom" name="Listener" description="" invmScope="GLOBAL">
            <listeners>
                <listener name="custom-listener" busidref="custom-bus" is-gateway="true">
                    <property name="gatewayClass" value="com.acme.listeners.MyCustomGateway" />
                    <property name="listener-property" value="listener-prop-value" />
                </listener>
            </listeners>
            <actions mep="OneWay">
                ...
            </actions>
        </service>
    </services>

</jbossesb>

7.2.5.2. スケジュール駆動型リスナー

simple-schedule or cron-schedule の設定に基づいてスケジュールされたタスクを実行するには scheduled-listener を使用することができます。
scheduled-listener は“event-processor”クラスで設定され、以下のインターフェースの実装になりえます。
  • ScheduledEventListener: このインターフェースを実装するイベントプロセッサーは単純に「onSchedule」メソッドで起動されます。アクション処理パイプラインは実行されません。
  • ScheduledEventMessageComposer: このインターフェースを実装するイベントプロセッサーはリスナーに関連付けられるアクション処理パイプラインのメッセージを「composing」する機能があります。
このリスナーの属性は次の通りです。
  1. name: リスナーインスタンスの名前です。
  2. event-processor: 各スケジュール起動で呼び出されるイベントプロセッサークラスです。実装詳細については上記を参照してください。
  3. いずれかひとつ
  • scheduleidref: このリスナーの起動に使用するスケジュールの scheduleid です (プロバイダー内で設定)。
  • schedule-frequency: スケジュールの頻度 (秒単位) です。直接リスナーで簡単にスケジュールを指定する便利な方法になります。
この例では、「order」ファイルが必要で、ESB に同梱されているファイルリスナーのコンポーネントではニーズが満たされないと仮定します。この場合、ScheduledEventMessageComposer インターフェースを実装することで、独自のカスタムファイルリスナーを記述することができます。
Public class OrderFileListener implements ScheduledEventMessageComposer {
 
    public void initialize(ConfigTree config) throws ConfigurationException {
        // TODO: Initialise File filters etc, using the config to access properties configured on the listener...
    }
 
    public Message composeMessage() throws SchedulingException {
        Message message = MessageFactory.getInstance().getMessage();
 
        // TODO: Read one or more order files and populate the data into the ESB message for pipeline processing...
 
        return message;
    }
 
    public Message onProcessingComplete(Message message) throws SchedulingException {
        // TODO: Post pipeline processing...
        return message;
    }
 
    public void uninitialize() {
        // TODO: Any relevant cleanup tasks...
    }
}

ESB サービスに変換するには、このコードを使用します。
<?xml version = "1.0" encoding = "UTF-8"?>
<jbossesb xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd">

    <providers>
        <schedule-provider name="schedules">
            <simple-schedule scheduleid="ordersPole" frequency="5" frequencyUnits="seconds" />
        </schedule-provider>
    </providers>

    <services>
        <service category="OrderManagement" name="OrderProcessing" description="Order Processing Service">

            <listeners>
                <scheduled-listener name="orderFileListener" scheduleidref="ordersPole" event-processor="com.acme.OrderFileListener"/>
            </listeners>

            <actions>
                <action name="action1" class="..."/>
                <action name="action2" class="..."/>
                <action name="action3" class="..."/>
            </actions>
        </service>
    </services>

</jbossesb>

7.2.5.3. Groovy スクリプトのイベント駆動型リスナー

JBoss ESB でイベント駆動型リスナーをより簡単に実装するには、Groovy スクリプトと groovy-listner 設定経由でリスナーとつなぎます。
groovy-listener の設定は非常に簡単です。以下の設定属性をとります。
  1. name: リスナーインスタンスの名前です。
  2. script: Groovy スクリプトへのパス (クラスパス上)。
Groovy スクリプトは、事実上ゲートウェイになり、以下のスクリプト変数のバインディングにアクセスできます。
  1. config: リスナーの設定 (ConfigTree)。ネスト化されたプロパティ要素の値。これは、アクションパイプラインの構築に必要です。
  2. gateway: 基盤の GroovyGateway リスナー (Java) への参照。これにより、リスナーのライフサイクルにアクセスできます。
JBoss ESB 提供の JMS リスナー実装が要件を満たさない場合、Groovy スクリプトと groovy-listener でカスタムの JMS リスナーを組み込むことができます。
javax.jms.MessagListener を実装することで開始します。
public class OrderListener implements MessageListener {
    
    public void onMessage(final Message message) {
        if(message instanceof ObjectMessage) {
            Order order = ((ObjectMessage) message).getObject();
 
            // Create and populate an ESB message with the order....
            Message esbMessage = MessageFactory.getInstance().getMessage();
            esbMessage.getBody().add(order);
 
            // TODO: Add code to forward the ESB message to the Action Pipeline...
        }
    }
}
ESB で機能するようにリンクを追加する必要があります。リスナーのライフサイクルの管理、アクションパイプラインインスタンス (およびその他のリソース) の作成用に start と stop メソッドを作成する必要があります。
public class OrderListener implements MessageListener {
 
    private ActionProcessingPipeline pipeline;
 
    public void start(ConfigTree config) throws ConfigurationException {
        // Create and initialize the pipeline..
        pipeline = new ActionProcessingPipeline(config);
        pipeline.initialise();
 
        // TODO: Add JMS code for connecting this JMS MessageListener to the JMS Queue... 
    }
 
    public void onMessage(final Message message) {
        if(message instanceof ObjectMessage) {
            Order order = ((ObjectMessage) message).getObject();
 
            // Create and populate an ESB message with the order....
            Message esbMessage = MessageFactory.getInstance().getMessage();
            esbMessage.getBody().add(order);
           
            // Forward the ESB message to the Action Pipeline...
            boolean success = pipeline.process(message);            
            if(!success) {
                // TODO: Handle error....
            }
        }
    }
 
    public void stop() {
        try {
            // TODO: Add JMS code for disconnecting from JMS Queue....
        } finally {
            if(pipeline != null) {
                pipeline.destroy() ;
            }            
        }
    }
}

注記

ActionProcessingPipeline クラス経由で直接アクションパイプラインを実行できるように ServiceInvoker を使用できます。これは、本書にて前述した AbstractThreadedManagedLifecycle の例と同じです。これは、メッセージに対応するリスナーをサービス上にインストールする必要があり (InVM リスナーで問題なし)、パイプラインが実装済みのリスナースレッドとは非同期で実行されることになります。
OrderListener を ESB にリンクする Groovy スクリプトを実装し、ライフサイクルを管理する (開始と停止) 必要があります。
import com.acme.OrderListener;
 
OrderListener orderListener = new OrderListener();
 
// Start the listener (passing the config)...
orderListener.start(config);
 
// Wait until the Groovy Gateway is signaled to stop...
def stopped = false;
while(!stopped) {
    stopped = gateway.waitUntilStopping(200);
}
 
// Now stop the listener...
orderListener.stop();
最後に、Groovy スクリプトを ESB サービスに設定するには、以下のコードを使用します。
<?xml version = "1.0" encoding = "UTF-8"?>
<jbossesb xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd">

    <services>
        <service category="OrderManagement" name="OrderProcessing" description="Order Processing Service">

            <listeners>
                <groovy-listener name="orderJmsListener" script="/com/acme/OrderListener.groovy">
                    <property name="queueName" value="..."/>
                </groovy-listener>
            </listeners>

            <actions>
                <action name="action1" class="..."/>
                <action name="action2" class="..."/>
                <action name="action3" class="..."/>
            </actions>
        </service>
    </services>

</jbossesb>