Web サービス・プログラミングのヒントと秘訣

シンプルで実用的な Web サービスのデザイン・パターンを学習 その 4

メッセージ・バス・パターンを理解そして実装

Comments
0

メッセージ・バス・パターン

Message-Oriented Middleware(MOM)の方式のインフラストラクチャーの中では、メッセージ・バス・パターンは最も重要なアーキテクチャー設計の一つです。Message Busの概念の中心に位置するは、(全てのメッセージが信頼性高くかつ効率的に行くべき場所に行くことを保証する)メッセージ配布のエンジンに全てのビジネス・アプリケーションが接続されると言う考え方です。それぞれのビジネス・アプリケーションは、イベント・ドリブンのメッセージ・バスを介した他のアプリケーションのピア(Peer)です。バスが受信するそれぞれのメッセージは、どのピアがイベントからの影響を受けたかを判断するためにバスが処理するイベントです。(換言すれば、メッセージを受信そして処理する必要があるのです。)

図1. メッセージ・バス・パターン
図1. メッセージ・バス・パターン

Message Bus のパターンの実装はベンダーに依存し、多種多様にわたりますが、いくつかの中核をなす概念は同じです。

  • メッセージ・チャネル: メッセージ・バスのコンポーネントは、主にメッセージを受けわたすのに使える複数ある個々のチャネルからなります。チャネルは以下の特性を持つ事が出来ます。
    • チャネルはアプリケーション固有またはメッセージ固有である可能性があります。
    • チャネルは単一方向または双方向になる事ができます。
    • チャネルはブロードキャスト指向(全てのメッセージが全てのアプリケーションに行きわたる)、Point-to-Point(メッセージが特定のアプリケーションに送信される)、またはサブスクリプション・ベース(メッセージが関係する特定のアプリケーションに送信される)にもなりえます。
  • メッセージ・ブローカー: メッセージ・バスは(どこにメッセージがルーティングされるかを、多種多様なビジネスの基準をもとに判断する)メッセージ・ブローカーを含むかも知れません。ベースのパターンではブローカーはオプションですが、企業システムでそれが重要な部分をしめるのはよくあることです。
  • チャネル・フィルター: フィルターとは(ロギング、変換、コンテキスト操作などのオペレーションのようなものを実行するために)チャネルにてメッセージを透過的にインターセプトするコンポーネントです。ブローカーの場合と同様に、理論上フィルターはオプションですが、多くの場合実際には重要なのです。
図2. 一般的なメッセージ・バスのコンポーネント
図2. 一般的なメッセージ・バスのコンポーネント

アプリケーションは1つまたは複数のチャネルを介してメッセージ・バスと通信します。チャネルはメッセージをメッセージ・バスに、そしてメッセージ・バスから動かします。アプリケーションがバスからメッセージを受信する方法は2つあります(プッシュまたはプル)。(イベント通知としても知られる)プッシュ交換(push exchanges)では、待機中のアプリケーションへのメッセージの転送をバスは開始します。プル交換(pull exchanges)ではバスに要求の一種を送信し、応答として1つまたは複数のキューされたメッセージを受信することによりアプリケーションは転送を開始します。プッシュ・モデルは、メッセージがプッシュさせられるのに介されるlistenチャネルまたは一定の接続を維持する機能を持つアプリケーションには理想的です。プル・モデルは、バスとの永続的(persistent)な接続に向かずバスと断続的にしか接続しないアプリケーションには理想的です。

図3. アプリケーションからメッセージへのバス接続のオプション
図3. アプリケーションからメッセージへのバス接続のオプション

(宛先がどこにあるか、またはどのようにそれが実装されているかに関係なく)1つのアプリケーションにより送信されるメッセージが適切な宛先に手堅く配信されるという事実が、バス・パターンに特徴をあたえます。それはMessage Busがどのように実装されているか、使用されるチャネルの種類、またはメッセージ配信のモデルに関係ありません。メッセージの受信者は、メッセージを送信するアプリケーションと同一のマシンにて存在できますし、全く別のマシンでも可能です。(同一の開発技術またはプログラム言語を使用して)受信者が実装されるかも知れませんし、そうはいかないかも知れません。メッセージを配信するアプリケーションがメッセージが配信されることに対して確信を持てる事が要点なのです。(特にプル・モデルの配信の場合においては)配信は直ぐに実行されるとは限りませんが、メッセージは行くべきところに到達します。

メッセージ・バスを実装

メッセージ・バスを実装する方法にもいくつかあり、メッセージ・バスの実装を簡単にするためにあるようなベンダーのツールがいくつかあります。例えば、Java Messaging Service のAPI標準を中心そしてベースにしたWebSphere® MQそしてWebSphere Business Integration Message Brokerの製品を、IBM®は提供します。共にそれらの製品は、企業品質に達し確固とした(たいがいのビジネス・ケースでのニーズに応えられる)メッセージ・バスのアーキテクチャーを提供します。また別の重要な点は、イベントそして通知をベースにしたサービスを実装するモデルを提供するWebサービスの標準のセットを定義するのに多くの労力が費やされたことです。WS-Notification の系列の仕様(参考文献を参照)は、(メッセージ・バスのスタイルのサービスを実装するように推進される)Webサービスの総合的なモデルを定義します。しかしながら、この記事では(根源的なデザイン・パターンがどのようにしてうまくかみ合うかを図解することに専念しますので)基本的にはOpenJMS のオープン・ソースのJMS実装とJavaサーブレットを使用して独自の実装を作成し、標準や製品を全く気に留めません。

この実装は3つのJMSトピック(JMS topics)から成ります(パブリッシュ/サブスクライブ・モデルのチャネル)。

  • メッセージがMessage Busにプッシュされるときに介する、Webサービス・インターフェース
  • Webサービス・インターフェースを介する応答メッセージのプル・モデル配信を実装するのに使われるJMS Queue
  • メッセージ・バスにプッシュされるメッセージを処理しlistenするコンポーネントの一群
図4. メッセージ・バスの一例
図4. メッセージ・バスの一例

Webサービスは2つのオペレーション(sendreceive)を公開するインターフェースからなります。sendオペレーションは(メッセージ・バスが取り扱いアプリケーション固有の簡素なメッセージ・タイプを表記する)CaseModelと呼ばれるオブジェクトを入力として受信します。WebサービスのWSDL記述をリスト1に示します。

リスト1. MessageBusService.wsdl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
  targetNamespace="http://four.wspattern.developerworks.ibm.com"
  xmlns:impl="http://four.wspattern.developerworks.ibm.com"
  xmlns:intf="http://four.wspattern.developerworks.ibm.com"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <wsdl:types>
  <schema
    targetNamespace="http://four.wspattern.developerworks.ibm.com"
    xmlns="http://www.w3.org/2001/XMLSchema"
    xmlns:impl="http://four.wspattern.developerworks.ibm.com"
    xmlns:intf="http://four.wspattern.developerworks.ibm.com"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <complexType name="CaseModel">
    <sequence>
     <element name="text" nillable="true" type="xsd:string"/>
    </sequence>
   </complexType>
   <element name="CaseModel" nillable="true" type="impl:CaseModel"/>
  </schema>
 </wsdl:types>
 
   <wsdl:message name="receiveResponse">
      <wsdl:part name="receiveReturn" type="intf:CaseModel"/>
   </wsdl:message>
 
   <wsdl:message name="sendRequest">
      <wsdl:part name="model" type="intf:CaseModel"/>
   </wsdl:message>
 
   <wsdl:message name="receiveRequest">
   </wsdl:message>
 
   <wsdl:message name="sendResponse">
   </wsdl:message>
 
   <wsdl:portType name="MessageBusService">
      <wsdl:operation name="receive">
         <wsdl:input message="intf:receiveRequest" name="receiveRequest"/>
         <wsdl:output message="intf:receiveResponse" name="receiveResponse"/>
      </wsdl:operation>
 
      <wsdl:operation name="send" parameterOrder="model">
         <wsdl:input message="intf:sendRequest" name="sendRequest"/>
         <wsdl:output message="intf:sendResponse" name="sendResponse"/>
      </wsdl:operation>
   </wsdl:portType>
 
   <wsdl:binding name="MessageBusServiceSoapBinding" type="intf:MessageBusService">
      <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
 
      <wsdl:operation name="receive">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="receiveRequest">
            <wsdlsoap:body
              namespace="http://four.wspattern.developerworks.ibm.com"
              use="literal"/>
         </wsdl:input>
         <wsdl:output name="receiveResponse">
            <wsdlsoap:body
              namespace="http://four.wspattern.developerworks.ibm.com"
              use="literal"/>
         </wsdl:output>
      </wsdl:operation>
 
      <wsdl:operation name="send">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="sendRequest">
            <wsdlsoap:body
              namespace="http://four.wspattern.developerworks.ibm.com"
              use="literal"/>
         </wsdl:input>
 
         <wsdl:output name="sendResponse">
            <wsdlsoap:body
              namespace="http://four.wspattern.developerworks.ibm.com"
              use="literal"/>
         </wsdl:output>
 
      </wsdl:operation>
   </wsdl:binding>
 
 
   <wsdl:service name="MessageBusServiceService">
      <wsdl:port
          binding="intf:MessageBusServiceSoapBinding"
          name="MessageBusService">
         <wsdlsoap:address
            location="http://localhost:9080/WSPattern4/services/MessageBusService"/>
      </wsdl:port>
   </wsdl:service>
 
</wsdl:definitions>

このWebサービス・インターフェースにおいて心に留めるべきことは、これが特に驚愕に値するものでも何でもないことです。これはそこら辺にある他の単純なWebサービス・インターフェースそのままです。リスト2にて示されるサービスの実装は、同様に平凡です。

リスト2. MessageBusService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package com.ibm.developerworks.wspattern.four;
 
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Iterator;
 
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.naming.Context;
import javax.servlet.http.HttpServlet;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.server.ServiceLifecycle;
 
public class MessageBusService
  implements ServiceLifecycle {
 
  Context context = null;
  QueueConnection connection = null;
  TopicConnection tconnection = null;
  QueueSession session = null;
  TopicSession tsession = null;
   
  public void init(Object serviceContext)
    throws ServiceException {
      try {
        context = JNDIHelper.getInitialContext();
        connection = JNDIHelper.getQueueConnection(context);
        session = JNDIHelper.getQueueSession(connection);
        tconnection = JNDIHelper.getTopicConnection(context);
        tsession = JNDIHelper.getTopicSession(tconnection);
      } catch (Exception e) {}
  }
 
  public void destroy() {
    try {
      tsession.close();
      session.close();
      tconnection.close();
      connection.close();
    } catch (Exception e) {}
  }
   
  public void send(CaseModel model) {
    sendMessage(JNDIHelper.INPUT_TOPIC, model);
  }
 
  public CaseModel receive() {
    return receiveMessage(JNDIHelper.OUTPUT_QUEUE);
  }
  
  private void sendMessage(String topicName, CaseModel model) {
    try {
      ObjectMessage message = tsession.createObjectMessage(model);
      Topic topic = JNDIHelper.getTopic(context, topicName);
      TopicPublisher publisher = JNDIHelper.getTopicPublisher(tsession, topic);
      publisher.publish(message);
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage());
    }
  }
  
  private CaseModel receiveMessage(String queueName) {
    CaseModel model = null;
    try {
      Queue queue = JNDIHelper.getQueue(context, queueName);
      QueueReceiver receiver = JNDIHelper.getQueueReceiver(session, queue);
      Message message = receiver.receiveNoWait();
      if (message != null && message instanceof ObjectMessage) {
        ObjectMessage objMessage = (ObjectMessage)message;
        Serializable obj = objMessage.getObject();
        if (obj instanceof CaseModel) {
          model = (CaseModel)obj;
        }
      }
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage());
    }
    return model;   
  }
 
}

この例が実装するモデルは単刀直入です。Webサービスはsend 要求を受信して入力のJMSトピックにモデルをパブリッシュします。4つの異なるアプリケーション・コンポーネントがそのトピックにlistenしてそのメッセージへの応答としてアクションを実行します。それらのコンポーネントのうちの2つは、出力のJMSトピックへ配信される応答メッセージを生成します。そのWebサービス・クライアントが直接的かつ永続的なJMSトピックへのパブリッシュ/サブスクライブ接続を保持する機能を持ちませんので、特殊なlistenerが出力のトピックからメッセージを受信してJMS応答キューの中にそれらのメッセージを保管します。Webサービス・クライアントがinvokeメッセージを呼び出せば、そのキューにて待機中の応答は配信されます。

入力のトピックにlistenするアプリケーションのうち、2つはメッセージに対する応答としてアプリケーション固有のプロセスを実行(すなわち、受信されたテキストをそれぞれ大文字と小文字に変換)します。最初のはstdout コンソール・アプリケーションへメッセージ受信をログして、2つ目はリモートのWebサービス・エンドポイントへ通知メッセージを送信します。

リスト3は、(メッセージ・バスを介して配信されたCaseModel を受信して供給されたテキストを大文字または小文字に変換する)2つのlistenerのうちの1つにあるコードを示します。両方とも、JMSMessageListener インターフェースを実装する簡素なHTTPサーブレットとして実装されます。別の方法として、それぞれをJMS Message Driven Beansとして実装するのも可能でしたが、それが招くアプリケーションの些細な複雑化への懸念のため、そうしないことに決めました。

リスト3. UppercaseTopicListenerServlet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.ibm.developerworks.wspattern.four;
 
import java.io.Serializable;
 
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Topic;
import javax.jms.TopicPublisher;
import javax.servlet.Servlet;
 
public class UppercaseTopicListenerServlet
  extends TopicListenerServlet
  implements Servlet {
 
  protected String getTopic() {
    return JNDIHelper.INPUT_TOPIC;
  }
 
  protected String getSelector() {
    return "";
  }
 
  public void onMessage(Message message) {
    try {
      if (message instanceof ObjectMessage) {
        ObjectMessage objMessage = (ObjectMessage) message;
        Serializable obj = objMessage.getObject();
        if (obj instanceof CaseModel) {
          CaseModel model = (CaseModel)obj;
          if (model.getText() != null) {
            model.setText(model.getText().toUpperCase());
          }
          ObjectMessage response = session.createObjectMessage(model);
          Topic responseTopic = JNDIHelper.getTopic(context, JNDIHelper.OUTPUT_TOPIC);
          TopicPublisher responsePublisher =
            JNDIHelper.getTopicPublisher(session, responseTopic);
          responsePublisher.publish(response);
        }
      }
    } catch (Throwable t) {}
  }
 
}

実行されるtoUpperCase()オペレーションそしてtoLowerCase()オペレーションを除き、これらのlistenerは全ての面において瓜二つです。変換されたテキストを含むCaseModel オブジェクトを含有するresponse メッセージを、それぞれが生成します。それぞれがその応答(response)メッセージを出力のJMSトピックに配信します。

リスト4にて示されるまた別のlistenerは、出力のトピックにてメッセージがパブリッシュされるのを待ち、Webサービス・クライアントへの配信に対する応答キューにそれらのメッセージを配置します。

リスト4. ResponseTopicListenerServlet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.ibm.developerworks.wspattern.four;
 
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
 
public class ResponseTopicListenerServlet
  extends TopicListenerServlet
  implements Servlet {
 
    protected QueueConnection qconnection;
    protected QueueSession qsession;
    protected Queue queue;
 
    protected String getTopic() {
      return JNDIHelper.OUTPUT_TOPIC;
    }
 
    protected String getSelector() {
      return "";
    }
 
    public void init() throws ServletException {
      super.init();
      try {
        qconnection = JNDIHelper.getQueueConnection(context);
        qsession = JNDIHelper.getQueueSession(qconnection);
        queue = JNDIHelper.getQueue(context, JNDIHelper.OUTPUT_QUEUE);
      } catch (Exception e) {}
    }
 
    public void destroy() {
      super.destroy();
      try {
        qsession.close();
        qconnection.close();
      } catch (Exception e) {}
    }
 
    public void onMessage(Message message) {
      try {
        QueueSender sender = JNDIHelper.getQueueSender(qsession, queue);
        sender.send(message);
      } catch (Exception e) {}
    }
 
}

(メッセージ・バスを介して配信された応答メッセージをキューするのに使える)この保管/転送のテクニックは、待機中のWebサービス・クライアントが全てのメッセージをメッセージ・バスを介して配信された時と同じ順番で受信できることを保証します。ここで注意すべきは、この実装においては、Webサービス・クライアントが(自分たち、そして自分たちのみに配信される予定である)メッセージのみを受信することを保証していないことです。換言すれば、このモデルの実世界での実装においては、相応しい人々のみが適当なメッセージを受信することを確証するために、適切なセキュリティーとルーティングのコンストレイント(制約)を強化する必要があります。

リスト5は、入力そして出力のJMSトピックにlistenする2つあるアプリケーション・コンポーネントのうちの1つを説明します。メッセージ・バスからメッセージを受信する段階で、これらのコンポーネントはリモートのWebサービス・エンドポイントに対して呼び出し、メッセージ受信を通知します。異なるJMSトピックにlistenすることを除き、これらのコンポーネントは瓜二つです。

リスト5. RequestTopicListenerNotifierServlet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.ibm.developerworks.wspattern.four;
 
import java.io.Serializable;
 
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Topic;
import javax.jms.TopicPublisher;
import javax.servlet.Servlet;
import javax.xml.namespace.QName;
import javax.xml.rpc.Call;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.encoding.TypeMapping;
import javax.xml.rpc.encoding.TypeMappingRegistry;
 
import com.ibm.ws.webservices.engine.encoding.ser.BeanDeserializerFactory;
import com.ibm.ws.webservices.engine.encoding.ser.BeanSerializerFactory;
 
public class RequestTopicListenerNotifierServlet
  extends TopicListenerServlet
  implements Servlet {
 
  private static final String NSURI =
    "http://four.wspattern.developerworks.ibm.com";
 
  protected String getTopic() {
    return JNDIHelper.INPUT_TOPIC;
  }
 
  protected String getSelector() {
    return "";
  }
 
  public void onMessage(Message message) {
    try {
      if (message instanceof ObjectMessage) {
        ObjectMessage objMessage = (ObjectMessage) message;
        Serializable obj = objMessage.getObject();
        if (obj instanceof CaseModel) {
          CaseModel model = (CaseModel)obj;
          ServiceFactory factory = ServiceFactory.newInstance();
          Service service =
            factory.createService(
              new QName(
                NSURI,
                "RemoteService"
              )
            );
             
          QName cmq = new QName(NSURI,"CaseModel"); 
          TypeMappingRegistry tmreg = service.getTypeMappingRegistry();
          TypeMapping tm = tmreg.createTypeMapping();
          tm.register(
            CaseModel.class,
            cmq,
            new BeanSerializerFactory(
              CaseModel.class,
              cmq),
            new BeanDeserializerFactory(
              CaseModel.class,
              cmq));
          tmreg.register("", tm);
 
          Call call = service.createCall();
          call.setTargetEndpointAddress(
            "http://localhost:9080/WSPattern4/services/RemoteService");
          call.addParameter(
            "model",
            cmq,
            CaseModel.class,
            ParameterMode.IN);
          call.invoke(
            new QName(
              NSURI,
              "notifyRequest"),
              new Object[] {model}
          );
        }
      }
    } catch (Throwable t) {}
  }
 
}

メッセージ・バスに接続される最後のアプリケーション・コンポーネントは、(入力または出力のJMSトピックへメッセージが配信される場合にstdout 通知を表示する)簡素なコンソール・アプリケーションです。

リスト6. ListenerApp.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.ibm.developerworks.wspattern.four;
 
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Serializable;
 
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.naming.Context;
 
public class ListenerApp
  implements MessageListener {
 
  private static Context context;
  private static TopicConnection connection;
  private static TopicSession session;
  private static Topic requestTopic;
  private static Topic responseTopic;
  private static TopicSubscriber requestSubscriber;
  private static TopicSubscriber responseSubscriber;
 
  public static void main(String[] args) throws Exception {
     
    ListenerApp listener = new ListenerApp();
    context = JNDIHelper.getInitialContext();
    connection = JNDIHelper.getTopicConnection(context);
    session = JNDIHelper.getTopicSession(connection);
    requestTopic = JNDIHelper.getTopic(context, JNDIHelper.INPUT_TOPIC);
    responseTopic = JNDIHelper.getTopic(context, JNDIHelper.OUTPUT_TOPIC);
    requestSubscriber = JNDIHelper.getTopicSubscriber(session, requestTopic);
    responseSubscriber = JNDIHelper.getTopicSubscriber(session, responseTopic);
    requestSubscriber.setMessageListener(listener);
    responseSubscriber.setMessageListener(listener);
     
    String input = "";
    while (!"exit".equalsIgnoreCase(input)) {
      BufferedReader br =
        new BufferedReader(
          new InputStreamReader(
            System.in));
      System.out.print("> ");
      input = br.readLine();
    }
  
    requestSubscriber.close();
    responseSubscriber.close();
    session.close();
    connection.close();   
  }
 
  public void onMessage(Message message) {
    synchronized(System.out) {
      try {
        if (message instanceof ObjectMessage) {
          ObjectMessage objMessage = (ObjectMessage) message;
          Serializable obj = objMessage.getObject();
          if (obj instanceof CaseModel) {
            CaseModel model = (CaseModel) obj;
            System.out.println("\nMessage Received: " + model);
            System.out.println("\tSent To: " + message.getJMSDestination());
            System.out.print("> ");
          }
        }
      } catch (Exception e) {}
    }
  }
 
}

この特定のコンポーネントの目的は、メッセージ・バスのモデルにある生来の柔軟性を実例で示すことです。メッセージ・バスが機能する方法から、アプリケーション・コンポーネントはいつ何時アプリケーション・アーキテクチャーに接続されたりそれから外されたりされてもおかしくはありませんので、そのシステムの能力と守備範囲を拡張することになります。Webサービスの活動中にコンソール・アプリケーションをシャットダウンすることは、メッセージ・バスの機能に決して影響を及ぼしません。

まとめ

この記事にて網羅された題材は、メッセージ・バス・パターンの基本的な実装への大雑把なおさらいのみを提供しました。セキュリティー、適切なメッセージのルーティング(ブローカリング)、配信のモデル、そしてその他など、重要ではあってもこの「シンプルで実用的なWebサービスのデザイン・パターンを学習」シリーズの守備範囲からは外れる論題が数多くあり、実世界での実装はそれらに対処しなくてはなりません。この記事、そして同じ「シンプルで実用的なWebサービスのデザイン・パターンを学習」シリーズの流れをくむその3本の前編での目的は、Webサービスの実装方法についての思考に刺激を与えることでした。簡素なRPC-Style Stock Quotes のサービスは、仕様と標準のWebサービスの系列に秘められる真の力を表わしません。

非同期照会、コマンド、ルーティング、そしてメッセージ・バスのモデルのようなパターンは、(Webサービスを実装して異なるタイプのアプリケーションを構築するうえで)驚愕に値するほどの量の柔軟性を提供します。このようなパターンを推進する事は、無数のWebサービスの仕様、標準、そして入手可能な製品から最大限の能力を確保する鍵となります。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。


    この記事にはコメントがありません
    static.content.url=http://www.ibm.com/developerworks/js/artrating/
    SITE_ID=60
    Zone=SOA and web services
    ArticleID=245079
    ArticleTitle=Web サービス・プログラミングのヒントと秘訣: シンプルで実用的な Web サービスのデザイン・パターンを学習 その 4
    publish-date=12142004
    url=https://www.ibm.com/developerworks/jp/webservices/library/ws-tip-altdesign4/index.html