第19章 Remoting

Seam は、 Web ページから AJAX (Asynchronous Javascript and XML) を使用してコンポーネントにリモートアクセスする便利な方法を提供します。 この機能を実現するフレームワークでは、 開発時に労力がかからないようになっています - コンポーネントに必要なものは、 AJAX を通じてアクセス可能とするための単純なアノテーションだけです。 この章では、 AJAX 可能な Web ページを作るために必要なステップについて述べ、 そしてSeam Remoting フレームワークの機能についても詳しく説明します。

19.1. 設定

Remoting の機能を使用するには、 まず web.xml ファイル内で Seam Resource サーブレットを設定する必要があります。

          
  <servlet>
    <servlet-name>Seam Resource Servlet</servlet-name>
    <servlet-class>org.jboss.seam.servlet.ResourceServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Seam Resource Servlet</servlet-name>
    <url-pattern>/seam/resource/*</url-pattern>
  </servlet-mapping>
        
        

次のステップは、 Web ページに必要な JavaScript をインポートすることです。 インポートすべきスクリプトが最低二つあります。 最初の一つは、 Remoting の機能を有効にするクライアントサイドフレームワークの全てのコードを含みます。

          
  <script type="text/javascript" src="seam/resource/remoting/resource/remote.js"></script>
            
        

二つ目のスクリプトは、 呼び出したいコンポーネントに対するスタブと型定義を含みます。 それはコンポーネントのローカルインターフェースを基にして動的に生成され、 インターフェースのリモートメソッドを呼び出すのに使用される全てのクラスに対する型定義を内包しています。 スクリプトの名前はコンポーネントの名前が反映されます。 例えば、 @Name("customerAction") というアノテーション付きのステートレスセッション Bean を持つなら、 スクリプトタグは以下のようになります。

          
  <script type="text/javascript" src="seam/resource/remoting/interface.js?customerAction"></script>
        
        

同じページから一つ以上のコンポーネントにアクセスしたい場合は、 スクリプトタグのパラメータとしてそれらを全て含めます。

          
  <script type="text/javascript" src="seam/resource/remoting/interface.js?customerAction&accountAction"></script>
        
        

19.2. "Seam" オブジェクト

コンポーネントとのクライアントサイドのインタラクションは、 すべて Seam Javascript オブジェクト経由で行われます。 このオブジェクトは remote.js に定義され、 コンポーネントに対する非同期呼び出しにそれを使用します。 それは、2 つの機能に区分されます。 コンポーネントと連携するメソッドを含む Seam.Component そして、リモートリクエストを実行するメソッドを含む Seam.Remoting です。 このオブジェクトに精通する一番容易な方法は、 簡単なサンプルから始めることです。

19.2.1. Hello World サンプル

Seam オブジェクトがどのように動作するかを見るために、 簡単なサンプルを通じて一歩を踏み出してみましょう。 まず最初に、helloAction と呼ばれる新しい Seam コンポーネントを作成しましょう。

          
  @Stateless
  @Name("helloAction")
  public class HelloAction implements HelloLocal {
    public String sayHello(String name) {
      return "Hello, " + name;
    }
  }
          
        

新しいコンポーネントのために、ローカルインタフェースも生成する必要があります。 @WebRemote アノテーションに特に注意してください。 Remoting を通じてのメソッドへのアクセスを可能とするために必要です。

          
  @Local
  public interface HelloLocal {
    @WebRemote
    public String sayHello(String name);
  }
          
        

書く必要があるサーバサイドのコードはこれだけです。 それでは、WEB ページのために - 新しいページを作成して、 以下のスクリプトをインポートしましょう。

          
  <script type="text/javascript" src="seam/resource/remoting/resource/remote.js"></script>
  <script type="text/javascript" src="seam/resource/remoting/interface.js?helloAction"></script>
          
        

完全にインタラクティブなユーザエクスペリエンスとするために、ページにボタンを付けましょう。

          
  <button onclick="javascript:sayHello()">Say Hello</button>
          
        

クリックされたとき、実際にボタンに何かを行わせるためには、もう少しスクリプトを追加する必要があります。

          
  <script type="text/javascript">
    //<![CDATA[

    function sayHello() {
      var name = prompt("What is your name?");
      Seam.Component.getInstance("helloAction").sayHello(name, sayHelloCallback);
    }

    function sayHelloCallback(result) {
      alert(result);
    }

    // ]]>
  </script>
          
        

作業完了です! アプリケーションをデプロイして、ページをブラウズしましょう。 ボタンをクリックして、プロンプトが出たら名前を入力しましょう。 呼び出しの成功を確認するための hello メッセージが、メッセージボックスに表示されます。 少し時間を節約したいのであれば、 Seam の /examples/remoting/helloworld ディレクトリにこの Hello World サンプルのすべてのソースコードがあります。

ところで、このスクリプトのコードは何をするのでしょうか。 もっと細かく分解してみましょう。手始めに、2 つのメソッドを実装した Javascript コードから見ていきましょう。 最初のメソッドはユーザに対して名前を入力するよう促し、リモートリクエストを行うという責務を持ちます。 以下の行から見てみましょう。

  Seam.Component.getInstance("helloAction").sayHello(name, sayHelloCallback);
        

この行の最初の部分 Seam.Component.getInstance("helloAction") は、 helloAction コンポーネントのプロキシ、あるいは"スタブ"を返します。 このスタブに対してコンポーネントのメソッド呼び出しが可能です。 それは、まさにこの行の残りの部分で発生します: sayHello(name, sayHelloCallback);

コード行全体で行っていることは、コンポーネントのsayHelloメソッドの呼び出しと、 パラメータとしてnameを渡すことです。 2 番目のパラメータsayHelloCallbackは、 このコンポーネントの sayHelloメソッドのパラメータではありません。 その代わり、Seam Remoting フレームワークにリクエストへのレスポンスを受けたら、 それを sayHelloCallbackメソッドに渡すべきことを指示します。 このコールバックパラメータは完全にオプションです。 返り値 void のメソッドを呼び出す場合、 あるいは結果を気にしない場合は、 遠慮なくそのままにしてください。

sayHelloCallbackメソッドが、リモートリクエストに対するレスポンスを受信した場合、 メソッド呼び出しの結果を表示するアラートメッセージが現れます。

19.2.2. Seam.Component

Seam.Component Javascript オブジェクトは、 Seam コンポーネントと連携する多くのクライアントメソッドを提供します。 主な 2 つのメソッド、newInstance()getInstance()は、 以降の章にも記述されていますが、 これらの主な違いは、newInstance() は、いつもコンポーネントタイプの新しいインスタンスを生成し、そして、getInstance()は、シングルトンのインスタンスを返すことです。

19.2.2.1. Seam.Component.newInstance()

新しいエンティティ、あるいは JavaBean コンポーネントインスタンスを生成するためにこのメソッドを使用します。 このメソッドにより返されるオブジェクトは、 サーバサイドの対応するものと同じ getter/setter メソッドを持つか、 あるいは、代替として、お望みならば、そのフィールドに直接アクセスが可能です。 例として、以下の Seam エンティティコンポーネントをご覧ください。

  @Name("customer")
  @Entity
  public class Customer implements Serializable
  {
    private Integer customerId;
    private String firstName;
    private String lastName;
    
    @Column public Integer getCustomerId() { 
      return customerId; 
    }
    
    public void setCustomerId(Integer customerId} { 
      this.customerId = customerId; 
    }
    
    @Column public String getFirstName() { 
      return firstName; 
    }
    
    public void setFirstName(String firstName) {
      this.firstName = firstName; 
    }
    
    @Column public String getLastName () {
      return lastName;
    }
    
    public void setLastName(String lastName) {
      this.lastName = lastName;
    }
  }
          

クライアントサイド Customer を生成するために、以下のコードを記述します。

  var customer = Seam.Component.newInstance("customer");
          

そして、ここからは customer オブジェクトのフィールドの設定が可能です。

  customer.setFirstName("John");
  // Or you can set the fields directly
  customer.lastName = "Smith";
          

19.2.2.2. Seam.Component.getInstance()

getInstance()メソッドは、 Seam セッション Bean コンポーネントの、スタブへの参照を取得するために使用されます。 それは、コンポーネントに対してリモートのメソッド実行に使用可能です。 このメソッドは、特定のコンポーネントのシングルトンを返します。 その結果、続けて同じコンポーネント名で 2 回呼び出すと、同じコンポーネントインスタンスが返されます。

前記のサンプルから続けて、 新しいcustomerを生成、保存しようとする場合、customerActionコンポーネントのsaveCustomer()メソッドにそれを渡します。

  Seam.Component.getInstance("customerAction").saveCustomer(customer);          
          

19.2.2.3. Seam.Component.getComponentName()

それがコンポーネントの場合、 オブジェクトをこのメソッドに渡すとコンポーネント名を返します。 また、コンポーネントでない場合、null を返します。

  if (Seam.Component.getComponentName (instance) == "customer")
    alert("Customer");
  else if (Seam.Component.getComponentName (instance) == "staff")
    alert("Staff member");          
          

19.2.3. Seam.Remoting

Seam Remoting の大部分のクライアントサイドの機能は、Seam.Remotingオブジェクトに含まれます。 メソッドを直接呼ぶ必要はほとんどないとはいえ、 言及する価値のある重要なものがあります。

19.2.3.1. Seam.Remoting.createType()

アプリケーションが Seam コンポーネントではない JavaBean を含むか、あるいは、使う場合、 パラメータをコンポーネントメソッドに渡すために、クライアントサイドでこれらのタイプを作成する必要があるかもしれません。 必要なタイプのインスタンスを作成するために、createType()メソッドを使用してください。 パラメータとして、完全修飾の Java クラスを渡してください。

  var widget = Seam.Remoting.createType("com.acme.widgets.MyWidget");          
          

19.2.3.2. Seam.Remoting.getTypeName()

このメソッドは、コンポーネントでない型用であることを別にすれば、Seam.Component.getComponentName()と等価です。 オブジェクトインスタンスにタイプの名前を返します。 また、タイプが既知でない場合、null を返します。 この名前は、タイプの Java クラス完全修飾名です。

19.3. クライアント インターフェース

上記、設定の章では、 インタフェース、あるいは、コンポーネントのための "スタブ" は、seam/remoting/interface.jsを通じてページにインポートされます。

        
  <script type="text/javascript" src="seam/resource/remoting/interface.js?customerAction"></script>
        
      

ページにこのスクリプトをインクルードすることにより、 コンポーネントのためのインタフェース定義に加えて、コンポーネントのメソッドを実行するために必要なその他のコンポーネントとタイプが生成され、 Remoting フレームワークで使用可能になります。

生成されうるクライアントスタブには、二つのタイプがあります。"実行可能" スタブ、そして、"タイプ" スタブです。 実行可能スタブは、振る舞いを持ち、セッション Bean コンポーネントに対するメソッドを実行するために使用されます。 一方、タイプスタブは、状態を保持し、パラメータあるいは結果として返り値として送付可能なタイプを表します。

生成されたクライアントスタブのタイプは、Seamコンポーネントのタイプに依存します。コンポーネントがセッション Bean の場合は実行可能スタブが生成され、 それ以外のエンティティ、またはJavaBeanの場合にはタイプスタブが生成されます。 この規則には 1 つの例外があります。 コンポーネントが JavaBean (つまり、セッション Bean や エンティティ Bean でない場合) で、かつそのメソッドに@WebRemote アノテーションが付けられていた場合は、タイプスタブの代わりに実行可能スタブが生成されます。 これは、セッション Bean にアクセスできない非EJB 環境で、JavaBean コンポーネントのメソッドを呼び出す Remoting を使用可能にします。

19.4. コンテキスト

Seam リモートコンテキストは、 Remoting のリクエスト / レスポンスサイクルの一部として送受信される追加情報を含んでいます。 現段階では対話 ID だけしか含んでいませんが、将来拡張される可能性があります。

19.4.1. 対話 ID の設定と読み込み

対話スコープでリモート呼び出しをしようとする場合、 Seam Remotingコンテキスト内にある対話ID の読み込みと設定が行える必要があります。リモートリクエストの後に対話 ID を読み込むためには、Seam.Remoting.getContext().getConversationId()を呼び出します。 リクエストの前に対話ID を設定するためには、Seam.Remoting.getContext().setConversationId()を呼び出します。

対話ID が明示的に Seam.Remoting.getContext().setConversationId()で設定されない場合、 リモート呼び出しによって返される最初の有効な対話ID が自動的に割り当てられます。 ページ内で複数の対話ID を使用する場合は、それぞれの呼び出しの前に対話IDを明示的に設定する必要があるかもしれません。1つの対話だけを使用する場合は、 特別なことをする必要はありません。

19.5. バッチリクエスト

Seam Remoting は、複数のコンポーネント呼び出しが 1 つのリクエスト内で実行されることを可能にします。 ネットワークトラフィックを減少することが適切であれば、 どこでもこの特徴を使用することを推奨します。

Seam.Remoting.startBatch()メソッド は、 新たなバッチを起動します。 バッチ起動後に実行されたコンポーネント呼び出しは、 即座に送られるのではなく、キューイングされます。 必要とされるすべてのコンポーネント呼び出しがバッチに追加されたとき、Seam.Remoting.executeBatch()メソッドは、 サーバにキューイングされた呼び出しすべてを含む 1 つのリクエストを送信するでしょう。 そして、そこで順番に実行されます。 呼び出しが実行された後、 すべての返り値を含む 1 つのレスポンスは、 クライアントに返され、コールバック機能が (もし、設定されていれば) 実行と同じ順番で起動されます。

startBatch()メソッドを通して新たなバッチを起動したけれど、それを送りたくないと決めたなら、Seam.Remoting.cancelBatch()メソッドは、キューに溜まった全ての呼び出しを破棄して、バッチモードを終了します。

バッチが利用されているサンプルを見るには、/examples/remoting/chatroomを参照ください。

19.6. データタイプの取り扱い

19.6.1. プリミティブ型 / 基本タイプ

この章は、基本データタイプのサポートについて述べています。 サーバサイドではこれらの値は、一般的にプリミティブタイプ、あるいは、対応するラッパクラスと互換性があります。

19.6.1.1. String 型

String パラメータ値を設定する場合は、 単純に Javascript String オブジェクトを使用してください。

19.6.1.2. Number 型

Java でサポートされているすべての数値タイプはサポートされています。 クライアントサイドでは、 数値は常に String 表現としてシリアライズされています。 そして、サーバサイドでは、これらは、正しい目的のタイプに変換されます。 プリミティブ、または、ラッパタイプへの変換は、 Byte、Double、 Float、Integer、Long、 そして、Short タイプをサポートします。

19.6.1.3. Boolean 型

Boolean は、クライアントサイドでは Javascriptの Boolean 値で表現され、サーバサイドでは Java boolean で表現されます。

19.6.2. JavaBeans

一般的に、これらは、Seam エンティティ、JavaBean コンポーネント、または、non-component クラスです。 オブジェクトの新しいインスタンスを生成するためには、適切なメソッドを使用してください。 Seam コンポーネントにはSeam.Component.newInstance()、 また、その他のものにはSeam.Remoting.createType()を使用してください。

パラメータが、このセクションの別の場所で記述されたその他の有効なタイプの 1 つではない場合、 これら 2 つのメソッドのどちらかによって生成されるオブジェクトだけがパラメータ値として使用されるべきであることに気づくことは重要です。 いくつかの状況では、 以下のように厳密にパラメータタイプを決定できないコンポーネントメソッドがあるかもしれません。

  @Name("myAction")
  public class MyAction implements MyActionLocal {
    public void doSomethingWithObject(Object obj) {
      // code
    }
  }
        

この場合、 myWidget コンポーネントのインスタンスを渡したいところですが、 myAction のインターフェースはそのいずれのメソッドからも直接参照されないため myWidget を含みません。 これを回避するには、 MyWidget を明示的にインポートする必要があります。

                  
  <script type="text/javascript" src="seam/resource/remoting/interface.js?myAction&myWidget"></script>
          
        

これにより myWidget オブジェクトが Seam.Component.newInstance("myWidget") で作成されるようになり、 これが myAction.doSomethingWithObject() に渡されます。

19.6.3. 日付と時刻

日付の値は、 ミリ秒単位まで正確な String 表示に連続化されます。 クライアント側では Javascript Date オブジェクトを使って日付値と動作させます。 サーバー側では java.util.Date を使用します (または java.sql.Datejava.sql.Timestamp などの下位クラス)。

19.6.4. Enums

クライアント側では、 enums は Strings と同様に扱われます。 enums パラメータの値を設定する場合は単純に enum の String 表現を使います。 次のコンポーネントを例として参照してください。

  @Name("paintAction")
  public class paintAction implements paintLocal {
    public enum Color {red, green, blue, yellow, orange, purple};

    public void paint(Color color) {
      // code
    }    
  }            
        

paint() メソッドを red の色を使って呼び出すには、 String のままでパラメータ値を渡します。

  Seam.Component.getInstance("paintAction").paint("red");
        

逆も真になります。 つまり、 コンポーネントメソッドが enum パラメータを返す場合 (または返されるオブジェクトグラフのどこかに enum フィールドを含む場合)、 クライアント側では String として表示されます。

19.6.5. 集合

19.6.5.1. Bag

Bag はアレイ、 集合、 一覧、 セットなどすべての集合タイプを対象とし (ただし Map は除く、 これについては次のセクションを参照)、 Javascript アレイとしてクライアント側で実装されます。 パラメータとしてこれらのタイプのいずれかを受け取るコンポーネントメソッドを呼び出す場合、 使用するパラメータは Javascript アレイにします。 コンポーネントメソッドがこれらのタイプのいずれかを返す場合は、 返り値も Javascript アレイになります。 Remoting フレームワークは、 サーバー側で bag をコンポーネントメソッドコールに対して適切なタイプに変換することが可能です。

19.6.5.2. Map

Javascript 内では Map に対するネイティブのサポートはないため、 シンプルな Map 実装が Seam Remoting フレームワークで提供されます。 リモートコールに対するパラメータとして使用できる Map を作成するには、 新たに Seam.Remoting.Map オブジェクトを作成します。

  var map = new Seam.Remoting.Map();          
          

この Javascript 実装では Map と動作することを目的とした基本的なメソッド、 size()isEmpty()keySet()values()get(key)put(key, value)remove(key)contains(key) を提供します。 それぞれのメソッドは Java のそれと同等になります。 メソッドが keySet() 及び values() などの 1 集合を返すと、 そのキーまたは値オブジェクトを含む Javascript Array オブジェクトが返されます。

19.7. デバッグ機能

バグの追跡を支援する目的で、 ポップアップウィンドウ内でクライアントとサーバー間を行ったり来たりするすべてのパケットの内容を表示するデバッグモードを有効にすることができます。 デバッグモードを有効にするには、 次のいずれかを行います。 Javascript 内で setDebug() メソッドを実行する方法は次の通りです。

  Seam.Remoting.setDebug(true);      
      

components.xml を使って設定を行う方法は次のようになります。

<remoting:remoting debug="true"/>

デバッグ機能をオフにするには、 setDebug(false) を呼び出します。 毒のメッセージをデバッグログに書き込みたい場合は、 Seam.Remoting.log(message) を呼び出します。

19.8. メッセージをロードする

画面の上部右端にデフォルトで表示されるローディングメッセージは、 変更、 レンダリングのカスタマイズ、 完全にオフにするなどが可能です。

19.8.1. メッセージを変更する

デフォルトの "Please Wait..." というメッセージを別のメッセージに変更するには、 Seam.Remoting.loadingMessage の値を設定します。

  Seam.Remoting.loadingMessage = "Loading...";        
        

19.8.2. ローディングメッセージを隠す

ローディングメッセージを完全に表示させないようにするには、 displayLoadingMessage() および hideLoadingMessage() を何も行わない機能で上書きします。

  // don't display the loading indicator
  Seam.Remoting.displayLoadingMessage = function() {};
  Seam.Remoting.hideLoadingMessage = function() {};        
        

19.8.3. カスタムのローディングインジケーター

ローディングインジケーターを上書きしてアニメのアイコンの他、 好きなものを表示させることができます。 displayLoadingMessage()hideLoadingMessage() の各メッセージを独自の実装で上書きしてこれを行います。

  Seam.Remoting.displayLoadingMessage = function() {
    // Write code here to display the indicator
  };
  
  Seam.Remoting.hideLoadingMessage = function() {
    // Write code here to hide the indicator
  };
        

19.9. 返されるデータを制御する

リモートメソッドが実行されると、 その結果はクライアントに返される XML レスポンスに連続化されます。 このレスポンスは次にクライアントにより Javascript オブジェクトにアンマーシャルされます。 他のオブジェクトへの参照を含む複雑なタイプの場合 (Javabeans など)、 こした参照されるオブジェクトもすべてレスポンスの一部として連続化されます。 これらのオブジェクトは他のオブジェクトを参照することができ、 またこの他のオブジェクトはその他のオブジェクトを参照できるといった具合になります。 チェックしないままにしておくと、 このオブジェクト「グラフ」はオブジェクト間で存在する関係によっては非常に膨大なものになる可能性があります。 派生的な問題として (レスポンスが冗長となる問題とは別)、 クライアントに対して機密情報が公表されてしまうのを防ぎたい場合もあるかもしれません。

Seam Remoting は、 リモートメソッドの @WebRemote アノテーションの exclude フィールドを指定することでそのオブジェクトグラフを「制約する」シンプルな方法を提供しています。 このフィールドはドット (「.」) 表記を使って指定されるパスまたは複数のパスを含む String アレイを受け取ります。 リモートメソッドを呼び出すと、 これらのパスと一致する結果となるオブジェクトグラフ内のオブジェクトが連続化される結果パケットから除外されます。

すべての例で次の Widget クラスを使用します。

@Name("widget")
public class Widget
{
  private String value;
  private String secret;
  private Widget child;
  private Map<String,Widget> widgetMap;
  private List<Widget> widgetList;
  
  // getters and setters for all fields
}
      

19.9.1. 通常のフィールドを制約する

リモートメソッドが Widget のインスタンスを返すけれど secret フィールドには機密情報が含まれているため公表したくない場合、 次のように制約します。

  @WebRemote(exclude = {"secret"})
  public Widget getWidget();      
        

"secret" の値は返されるオブジェクトの secret フィールドを参照します。 ここで、 クライアントに対してこの特定フィールドが公開されても構わないと仮定します。 返される Widget には child フィールドがあり、 これも Widget になります。 代わりに childsecret 値を隠したい場合はどうしたらよいでしょうか。 ドット表記を使用して結果となるオブジェクトグラフ内のこのフィールドのパスを指定することができます。

  @WebRemote(exclude = {"child.secret"})
  public Widget getWidget();      
        

19.9.2. Map と 集合を制約する

オブジェクトグラフ内にオブジェクトが存在できるその他の場所は Map あるいはなんらかの集合の種類内になります (ListSetArray など)。 集合は簡単で、 その他のフィールドと同様に扱えます。 たとえば、 WidgetwidgetList フィールド内に他の Widget 一覧が含まれていて、 この一覧の Widgetsecret フィールドを制約している場合、 アノテーションは次のようになります。

  @WebRemote(exclude = {"widgetList.secret"})
  public Widget getWidget();      
        

Map のキーまたは値を制約する場合の表記は少し異なります。 Map のフィールド名の後ろに [key] を付け加えると Map のキーオブジェクト値を制約し、 [value] は値オブジェクトの値を制約します。 次の例では widgetMap フィールドに制約された secret フィールドを持たせる方法を示しています。

  @WebRemote(exclude = {"widgetMap[value].secret"})
  public Widget getWidget();      
        

19.9.3. 特定タイプのオブジェクトを制約する

最後に、結果となるオブジェクトグラフ内のどこに出現するかに関係なくオブジェクトタイプのフィールド制約に使用できる表記について説明します。 この表記はコンポーネント名 (オブジェクトが Seam コンポーネントである場合) または完全修飾クラス名 (オブジェクトが Seam コンポーネントではない場合のみ) のいずれかを使用し角括弧を使って表現されます。

  @WebRemote(exclude = {"[widget].secret"})
  public Widget getWidget();      
        

19.9.4. 制約同士を組み合わせる

制約同士はオブジェクトグラフ内で複数のパスからオブジェクトをフィルタするために組み合わせることもできます。

  @WebRemote(exclude = {"widgetList.secret", "widgetMap[value].secret"})
  public Widget getWidget();      
        

19.10. JMS メッセージング

Seam Remoting は JMS メッセージングに対して実験的にサポートを提供しています。 本セクションでは現在実装されている JMS サポートについて記載していますが、 今後、 変更される可能性があるので注意してください。 現在、 この機能を実稼働環境下で使用することは推奨されていません。

19.10.1. 設定

JMS トピックをサブスクライブする前に、 まず Seam Remoting でサブスクライブさせることができるトピック一覧を設定する必要があります。 seam.propertiesweb.xml または components.xmlorg.jboss.seam.remoting.messaging.subscriptionRegistry.allowedTopics 配下にあるトピックを一覧表示させます。

<remoting:remoting poll-timeout="5" poll-interval="1"/>

19.10.2. JMS Topic にサブスクライブする

次の例では JMS Topic へのサブスクライブ方法を示しています。

  function subscriptionCallback(message)
  {
    if (message instanceof Seam.Remoting.TextMessage)
      alert("Received message: " + message.getText ());
  }        
        
  Seam.Remoting.subscribe("topicName", subscriptionCallback);
        

Seam.Remoting.subscribe() メソッドは 2 つのパラメータを受け取ります。 1 つ目はサブスクライブする JMS Topic 名になり、 2 つ目はメッセージが受け取られると呼び出すコールバック機能になります。

サポートされているメッセージは 2 種類で、 テキストメッセージとオブジェクトメッセージです。 コールバック機能に渡されるメッセージタイプのテストを必要とする場合は、 instanceof 演算子を使ってメッセージが Seam.Remoting.TextMessage なのか Seam.Remoting.ObjectMessage であるのかをテストすることができます。 TextMessage はその text フィールドにテキスト値を含み (または代わりに getText() を呼び出す)、 ObjectMessage はその object フィールドにオブジェクト値を含みます (またはその getObject() メソッドを呼び出す)。

19.10.3. トピックのサブスクライブを中止する

トピックのサブスクライブを中止するには、 Seam.Remoting.unsubscribe() を呼び出してトピック名で渡します。

  Seam.Remoting.unsubscribe("topicName");        
        

19.10.4. ポーリングのプロセスを調整する

ポーリングの発生方法を制御するために変更できるパラメータが 2 つあります。 1 つ目は Seam.Remoting.pollInterval で、 新しいメッセージに対して後続ポールが発生する間隔を制御します。 秒単位で表現します、 デフォルト設定は 10 になります。

2 つ目のパラメータは Seam.Remoting.pollTimeout で、 このパラメータも秒単位で表現されます。 サーバーへのリクエストがタイムアウトして空白の応答を送信するまでの新しいメッセージを待機する長さを制御します。 デフォルトは 0秒で、 サーバーがポールされると配信できるメッセージがない場合は空白の応答が直ちに返されます。

pollTimeout 値を高く設定する場合は注意が必要です。 各リクエストがメッセージを待機する必要があるということは、 メッセージが受信されるまでまたはそのリクエストがタイムアウトするまでサーバースレッドが固定されるということになります。 こうしたリクエストが同時に多数発生すると、 大量のスレッドが固定される結果になります。

これらのオプションは components.xml 経由で設定することを推奨しますが、 必要に応じて Javascript で上書きすることができます。 次の例ではポーリングがかなりアグレッシブに発生するよう設定する方法を示しています。 これらのパラメータはご使用のアプリケーションに適切な値を設定してください。

components.xml:

<remoting:remoting poll-timeout="5" poll-interval="1"/>

JavaScript:

  // Only wait 1 second between receiving a poll response and sending the next poll request.
  Seam.Remoting.pollInterval = 1;
  
  // Wait up to 5 seconds on the server for new messages
  Seam.Remoting.pollTimeout = 5;