SeamFramework.org Community Documentation

- 前のページ
- 次のページ

## 第25章 リモーティング

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

## 25.1. 設定

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

    <servlet>

      <servlet-name

    >Seam Resource Servlet</servlet-name>

      <servlet-class

    >org.jboss.seam.servlet.SeamResourceServlet</servlet-class>

    </servlet>

    <servlet-mapping>

      <servlet-name

    >Seam Resource Servlet</servlet-name>

      <url-pattern

    >/seam/resource/*</url-pattern>

    </servlet-mapping

    >

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

    <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

    >

代わりに、 必要な Javascript のインポートに `s:remote` を使用することもできます。 インポートするコンポーネントあるいはクラス名をそれぞれコンマで区切ります。

      <s:remote include="customerAction,accountAction"/>

## 25.2. "Seam"オブジェクト

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

### 25.2.1. Hello World サンプル

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

    @Stateless

    @Name("helloAction")

    public class HelloAction implements HelloLocal {

        public String sayHello(String name) {

            return "Hello, " + name;

        }

    }

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

    @Local

    public interface HelloLocal {

      @WebRemote

      public String sayHello(String name);

    }

サーバサイドにおいて実装すべきコードはこれだけです。

## 注意

もし、`@WebRemote`をマークしたメソッドにおいて永続化処理を行うのであれば`@Transactional`アノテーションも当該メソッドにマークする必要があります。そうしなかった場合、メソッドはトランザクション境界の外で実行されます。なぜなら、JSF要求と違って、Seamはリモーティング要求を自動的にトランザクション境界に含めません。

それでは、WEB ページのために - 新しいページを作成して、 `helloAction` コンポーネントをインポートしましょう。

    <s:remote include="helloAction"/>

ユーザーにとって完全にインテラクティブとなるようページにボタンを追加してみます。

    <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 サンプルの全ソースコードがあります。

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

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

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

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

`sayHelloCallback`メソッドが、リモート要求に対する応答を受信した場合、 メソッド呼び出しの結果を表示するアラートメッセージが現れます。

### 25.2.2. Seam.Component

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

#### 25.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";

#### 25.2.2.2. Seam.Component.getInstance()

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

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

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

#### 25.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");

### 25.2.3. Seam.Remoting

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

#### 25.2.3.1. Seam.Remoting.createType()

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

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

#### 25.2.3.2. Seam.Remoting.getTypeName()

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

## 25.3. EL 式を評価する

Seam Remoting は EL 式の評価にも対応します。 サーバからのデータ取得にもうひとつ便利なメソッドを提供します。 `Seam.Remoting.eval()` 関数を使用して、 EL 式をサーバ上で遠隔に評価してその結果値をクライアント側のコールバックメソッドに返すことができます。 この関数は二つのパラメータを受け取ります。 一番目のパラメータは 評価対象となる EL 式となり、 二番目のパラメータはその式の値を付けて呼び出すコールバックメソッドになります。 次に例を示します。

      function customersCallback(customers) {

        for (var i = 0; i < customers.length; i++) {

          alert("Got customer: " + customers[i].getName());

        }

      }

      Seam.Remoting.eval("#{customers}", customersCallback);

この例では、 `#{customers}` の式が Seam によって評価され、 その式の値 (この場合 Customer オブジェクトの一覧) が`customersCallback()` メソッドに返されます。 このようにして返されるオブジェクトは Javascript で動作できるようそれ自体のタイプがインポートされていなければなりません (`s:remote`)。 したがって、 `customer` オブジェクトの一覧と動作させるには、 `customer` タイプをインポートする必要があります。

    <s:remote include="customer"/>

## 25.4. クライアントのインタフェース

上記の設定のセクションでは、 インタフェースまたはコンポーネントの「スタブ」は `seam/resource/remoting/interface.js` 経由でページにインポートするか、 `s:remote` を使用してインポートします。

    <script type="text/javascript"

            src="seam/resource/remoting/interface.js?customerAction"

    ></script

    >

    <s:remote include="customerAction"/>

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

生成可能なクライアントスタブには「実行可能」スタブと「タイプ」スタブの二タイプがあります。 実行可能スタブは動作を持ち、 セッション Bean コンポーネントに対するメソッドの実行に使用されます。 一方、 タイプスタブは状態を保持し、 パラメータとして渡すまたは結果として返すことができるタイプを表します。

生成されるクライアントスタブのタイプは Seam コンポーネントのタイプにより異なります。 コンポーネントがセッション Bean の場合、 実行可能スタブが生成されます。 これ以外、 エンティティや JavaBean となる場合にはタイプスタブが生成されます。 この規則には例外がひとつあります。 コンポーネントが JavaBean (つまり、セッション Bean や エンティティ Bean ではない場合) であり、 そのメソッドのいずれにも @WebRemote アノテーションが付く場合、 タイプスタブではなく実行可能スタブが生成されます。 これにより、 セッション Bean にアクセスできない非 EJB 環境で JavaBean コンポーネントのメソッドを呼び出すリモーティングが使用できるようになります。

## 25.5. コンテキスト

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

### 25.5.1. 対話 ID の設定と読み込み

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

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

### 25.5.2. 現在の対話スコープ内のリモート呼び出し

現在のビューの対話スコープ内でリモート呼び出しを行う必要がある場合があります。 これを行うにはリモート呼び出しを行う前に明示的に対話 ID をビューのそれにセットする必要があります。 この小さな JavaScript によりリモート呼び出しに使用される対話 ID が現在のビューの対話 ID にセットされます。

    Seam.Remoting.getContext().setConversationId( #{conversation.id} );

## 25.6. バッチ要求

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

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

`startBatch()`メソッドで新たなバッチを起動したが要求を送らないことにした場合、 `Seam.Remoting.cancelBatch()`メソッドはキュー待ちしているすべての呼び出しを破棄してそのバッチモードを終了します。

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

## 25.7. データタイプの取り扱い

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

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

#### 25.7.1.1. String 型

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

#### 25.7.1.2. Number 型

Java でサポートされているすべての数値タイプにサポートがあります。 クライアント側では数値は常に String 表現としてシリアライズされ、 サーバ側で適切な目的とするタイプに変換されます。 プリミティブまたはラッパーいずれかのタイプへの変換は、 `Byte`、 `Double`、 `Float`、 `Integer`、 `Long`、 `Short` の各タイプに対してサポートされます。

#### 25.7.1.3. Boolean 型

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

### 25.7.2. JavaBeans

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

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

    @Name("myAction")

    public class MyAction implements MyActionLocal {

      public void doSomethingWithObject(Object obj) {

        // code

      }

    }

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

    <s:remote include="myAction,myWidget"/>

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

### 25.7.3. 日付と時刻

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

### 25.7.4. Enum

クライアント側では、 Enum は String と同様に扱われます。 Enum パラメータの値を設定する場合は単純に 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 として表示されます。

### 25.7.5. 集合

#### 25.7.5.1. Bag

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

#### 25.7.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()` などの一集合を返すと、 そのキーまたは値オブジェクトを含む Javascript Array オブジェクトが返されます。

## 25.8. デバッグ機能

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

    Seam.Remoting.setDebug(true);

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

    <remoting:remoting debug="true"/>

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

## 25.9. 例外処理

リモートコンポーネントメソッド呼び出しにおいて、呼び出し中に発生した例外イベントの応答を処理するための例外ハンドラを指定することが可能です。例外ハンドラの機能を指定するために、JavaScriptコード中でコールバックパラメータの次に例外ハンドラへの参照を含めて下さい。

    var callback = function(result) { alert(result); };
    var exceptionHandler = function(ex) { alert("An exception occurred: " + ex.getMessage()); };
    Seam.Component.getInstance("helloAction").sayHello(name, callback, exceptionHandler);

コールバックハンドラを定義しない場合、必ず`null`を明記して下さい。

    var exceptionHandler = function(ex) { alert("An exception occurred: " + ex.getMessage()); };
    Seam.Component.getInstance("helloAction").sayHello(name, null, exceptionHandler);

例外ハンドラに渡された例外オブジェクトは`getMessage()`メソッドを実装します。このメソッドは`@WebRemote`がマークされたメソッドによりスローされた例外が生成した例外メッセージを返します。

## 25.10. メッセージをロードする

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

### 25.10.1. メッセージを変更する

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

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

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

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

    // don't display the loading indicator

    Seam.Remoting.displayLoadingMessage = function() {};

    Seam.Remoting.hideLoadingMessage = function() {};

### 25.10.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

      };

## 25.11. 戻り値の制御

リモートメソッドが実行されると、 その結果はクライアントに返される 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

    }

### 25.11.1. フィールドの制約

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

    @WebRemote(exclude = {"secret"})

    public Widget getWidget();

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

    @WebRemote(exclude = {"child.secret"})

    public Widget getWidget();

### 25.11.2. Map とコレクションの制約

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

    @WebRemote(exclude = {"widgetList.secret"})

    public Widget getWidget();

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

    @WebRemote(exclude = {"widgetMap[value].secret"})

    public Widget getWidget();

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

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

    @WebRemote(exclude = {"[widget].secret"})

    public Widget getWidget();

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

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

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

    public Widget getWidget();

## 25.12. トランザクションを含む要求

デフォルトではリモート要求中でトランザクションはアクティブではありません、リモート要求中でデータベースの更新を行いたい場合、`@WebRemote`アノテーションと`@Transactional`アノテーションをメソッドに付加する必要があります。

      @WebRemote @Transactional(TransactionPropagationType.REQUIRED)
      public void updateOrder(Order order) {
        entityManager.merge(order);
      }

## 25.13. JMS メッセージング

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

### 25.13.1. 設定

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

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

### 25.13.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()` メソッドは二つのパラメータを受け取ります。 一つ目はサブスクライブする JMS Topic 名になり、 二つ目はメッセージが受け取られると呼び出すコールバック機能になります。

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

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

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

    Seam.Remoting.unsubscribe("topicName");

### 25.13.4. ポーリングのプロセスの調整

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

二つ目のパラメータは `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;

- 前のページ第24章 Webサービス
- 上に戻る
- ホーム
- 次のページ第26章 SeamとGoogle Web Toolkit