Making Remote Procedure Calls

android用の神経衰弱ゲームを公開しました(・∀・)
The Match-up(Memory) game for android was released!

Google Play:
Mole's Match-up.

Introduction page:
Mole’s Match-upをリリースした∩( ・ω・)∩


http://code.google.com/intl/ja/webtoolkit/doc/latest/tutorial/RPC.html

 

 リモートプロシージャコールの作成

この時点でクライアントサイドのコードで株価データをシミュレートするストックウォッチャー(株価監視)アプリケーションの最初の実装を作成しています?
このセクションでは株価データを返すサーバサイドメソッドへのGWTリモートプロシージャコールを作成します。クライアントから呼び出されるサーバサイドコードはサービスとしても知られます;リモートプロシージャコールを作成するという行為はサービス呼び出しと呼ばれます。
あなたが学ぶであろうことは:
  1. サーバでのサービスの作成
  2. クライアントからのサービス呼び出し
  3. データオブジェクトのシリアライズ(直列化)
  4. 例外処理: チェックされる例外と予期されない例外
Note: GWTアプリケーションでのRPC通信のより広いガイドについてはCommunicate with a Server – Remote Procedure Callsを見てください。

 始める前に

StockWatcher プロジェクト

このチュートリアルはGWTの概念とBuild a Sample GWT Application チュートリアルで作成したStockWatcherアプリケーションを基にしています。 もしGWTアプリケーション作成チュートリアルを終えておらずGWTの概念がある程度わかっているなら(慣れ親しんでいるなら)、ここでStockWatcherプロジェクトをコードとしてインポートすることが出来ます。
  1. StockWatcher projectをダウンロードします。
  2. ファイルを解凍します。
  3. Eclipse へプロジェクトをインポートします。
    1. ファイル メニューから、インポートメニューオプションを選択します。
    2. [一般]-[既存プロジェクトをワークスペースへ]を選択します。次へ(N)ボタンをクリックします。
    3. [ルート・ディレクトリーの選択(T)]でブラウズしStockWatcherのあるディレクトリ(ファイルを解凍した場所から)を選択します。完了(F) ボタンをクリックします。
antを使用している場合は、StockWatcher/build.xmlの何処にGWTを解凍したかを指す gwt.sdk プロパティを編集します

 GWT RPCとは何か?

GWT RPCフレームワークはwebアプリケーションのクライアントとサーバのコンポーネント間でHTTPを利用したJavaオブジェクトを交換することを簡単にします。 クライアントから呼び出されるサーバサイドのコードはしばしばサービスと呼ばれます。GWT RPCサービスの実装は周知のJavaサーブレットアーキテクチャに基づいています。クライアントコード内で、サービスの呼び出しを作成するために自動生成プロクシクラスを使用します。GWTは前後に渡される-メソッド呼び出しと返り値での引数-Javaオブジェクトのシリアライゼーションを処理します?
Important: GWT RPCサービスはSOAPまたはRESTに基づくwebサービスと同じではありません。 これらは単にサーバとクライアント上のGWTアプリケーション間のデータ転送のための軽量な方法です。 アプリケーションへGWT RPCサービスを統合するための単一層と多層のデプロイメントオプションを比較するために? デベロッパガイド Architectural Perspectivesを見てください。

 GWT RPCメカニズムでのJavaコンポーネント

GWT RPCをセットアップする時, リモートサーバ上で動作しているプロシージャの呼び出しに関係する三つの要素に注目します。
  • サーバ上で動作しているサービス(呼び出すメソッド)
  • サービスと関係するクライアントコード
  • クライアント-サーバ間で渡されるJavaデータオブジェクト
    データオブジェクトをサーバ-クライアント間で任意のテキストとして渡すことが出来るようにサーバとクライアントはどちらもデータをシリアル化/デシリアル化する機能を持ちます。

GWT RPC Plumbing

RPCインターフェイスを定義する為に、三つのコンポーネントを書く必要があります:
  1. サービス用のRemoteServicesを継承するインターフェイス(StockPriceService)を定義し、全てのRPCメソッドをリストします。(※サービスインターフェイス)
  2. RemoteServiceServletを継承したクラス(StockPriceServiceImpl)を作成し、1.で作成したインターフェイスをimplementsします。(※サービス実装)
  3. クライアントサイドコードから呼び出されるサービスへの非同期インターフェイス(StockPriceServiceAsync)を定義します。(※サービスインターフェイスの非同期バージョン)
サービス実装はRemoteServiceServletを継承しなければならず、関連するサービスインターフェイスをimplementsしなければなりません。サービス実装はサービスインターフェイスの非同期バージョンをimplementsしないことに注意してください。全てのサービス実装は結局はサーブレットですが、HttpServletを継承するのではなく、代わりにRemoteServiceServletを継承します。RemoteServiceServletは自動的にクライアント-サーバ間で渡され、サービス実装で意図されたメソッドで呼び出されるデータのシリアル化を自動的に処理します。

 1. サーバでのサービスの作成

このチュートリアルでは、refreshWatchListのメソッドにある機能を取り出しクライアントからサーバへ移動します。 現在、refreshWatchListのメソッドへ株のシンボルの配列を渡し、メソッドは一致する株データを返します。それから株データを持つフレックステーブルを配置するためにupdateTableメソッドを呼びます。

現在のクライアントサイドの実装:

/**
   * Generate random stock prices.
   */
  private void refreshWatchList() {
    final double MAX_PRICE = 100.0; // $100.00
    final double MAX_PRICE_CHANGE = 0.02; // +/- 2%

StockPrice[] prices = new StockPrice[stocks.size()];
for (int i = 0; i < stocks.size(); i++) {
double price = Random.nextDouble() * MAX_PRICE;
double change = price * MAX_PRICE_CHANGE
* (Random.nextDouble() * 2.0 – 1.0);

prices[i] = new StockPrice(stocks.get(i), price, change);
}

updateTable(prices);
}

 

サービスを作成するために、あなたは:
  1. サービスインターフェイスを定義します: StockPriceService
  2. サービスを実装します: StockPriceServiceImpl

サービスの定義: StockPriceService インターフェイス

GWTにおいて、RPCサービスはGWT RemoteServiceインターフェイスを継承したインターフェイスによって定義されます。StockPriceServiceインターフェイスに対して、メソッドを一つだけ定義する必要があります:このメソッドは株のシンボルの配列を受け入れ、StockPriceオブジェクトとして全ての株に関連付けられたデータを返します。
  1. クライアントサブパッケージで、インターフェイスを作成しStockPriceServiceと名づけます。
    Eclipseでは、パッケージエクスプローラペインで次のパッケージを選択します。
    com.google.gwt.sample.stockwatcher.client
    Eclipseのメニューバーから[ファイル(F)]-[新規(N)]-[インターフェイス]を選択します。
    Eclipseは”新規 Java インターフェイス”ウィンドウを開きます。
  2. “新規 Java インターフェイス”ウィンドウを埋めます。
    [名前(M)]にStockPriceServiceと入力します。
    その他のフィールドはデフォルト値を受け入れます。
    完了(F)ボタンを押します。
    EclipseはStockPriceServiceインターフェイス用のスタブコードを作成します。

    ※”スタブコードはクライアント側で代理オブジェクトを実現する部分である.”

  3. スタブコードを以下のコードに置換えます。
    package com.google.gwt.sample.stockwatcher.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

@RemoteServiceRelativePath(“stockPrices”)
public interface StockPriceService extends RemoteService {

StockPrice[] getPrices(String[] symbols);
}

実装での注意: @RemoteServiceRelativePath アノテーションに注意してください。これがサービスとモジュールベースURLと関連するデフォルトパスを結び付けます。

 サービスの実装: StockPriceServiceImplクラス

サーバ上で動作するクラス(StockPriceServiceImpl)を作成します。インターフェイスで定義されているので、 StockPriceServiceImplは一つのメソッドだけ含みます。メソッドは株価データを返します。
これを行うために、GWT RemoteServiceServletクラスも継承したクラスを作成することによって、サービスインターフェイスを実装します。RemoteServiceServletはクライアントから入ってくるリクエストのデシリアライズ(復元)とクライアントへ送るレスポンスのシリアライズ(直列化)の処理を行います。

 

 
サーバサイドコードのパッケージング
サービス実装はサーバでJavaバイトコードとして実行されます;Javaスクリプトへ変換(翻訳)されません。従って、サービス実装はクライアントサイドのコードと同じ言語制約を持ちません。クライアント用コードをサーバ用コードと区別しておくために、別個のパッケージに入れておきます。(com.google.gwt.sample.stockwatcher.server)

新しいクラスの作成

(※ここでの操作指示は開始時にcom.google.gwt.sample.stockwatcher.clientが選択状態であり、

com.google.gwt.sample.stockwatcher.server存在していない前提のようです。)

 
  1. StockPriceService用のサービス実装を作成します。
    エクリプスでは、新規Javaクラスウィザードを起動します。 (ファイル(F) > 新規(N) > クラス)
  2. パッケージ(K)で、.client から .serverへ名前を変更します。
    エクリプスは(実際のクラス作成時に同時に)サーバサイドコード用のパッケージを作成します。
  3. 名前(M)に、 StockPriceServiceImplと入力します。
    実装の注意: 慣例により、サービス実装クラスはサービスインターフェイスの名+接尾辞Implで命名されます。だから、新しいクラスはStockPriceServiceImplとなります。
  4. RemoteServiceServlet クラスを継承します。
    スーパークラス(S)に以下の値を入力します。
    com.google.gwt.user.server.rpc.RemoteServiceServlet
  5. StockPriceService インターフェイスを実装します。
    インターフェイス(I)に、以下のインターフェイスを追加します。
    com.google.gwt.sample.stockwatcher.client.StockPriceService
  6. 抽象メソッドを継承します。
  7. 完了(F)をクリックします。
    エクリプスは以下のパッケージを作成します。
    com.google.gwt.sample.stockwatcher.server
    エクリプスはスタブであるStockPriceServiceImpl クラスを作成します。
    package com.google.gwt.sample.stockwatcher.server;

import com.google.gwt.sample.stockwatcher.client.StockPrice;
import com.google.gwt.sample.stockwatcher.client.StockPriceService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class StockPriceServiceImpl extends RemoteServiceServlet implements StockPriceService {

public StockPrice[] getPrices(String[] symbols) {
// TODO Auto-generated method stub
return null;
}

}

サーバサイドの実装を記述する

ランダムな株価を返すクライアントサイド実装を置換えます。
  1. 価格と変更データを初期化するためのインスタンス変数を作成します。
    private static final double MAX_PRICE = 100.0; // $100.00
      private static final double MAX_PRICE_CHANGE = 0.02; // +/- 2%
  2. TODO部分を以下のコードに置換えます。nullではなく価格を返します。
    public StockPrice[] getPrices(String[] symbols) {
        Random rnd = new Random();

StockPrice[] prices = new StockPrice[symbols.length];
for (int i=0; i
double price = rnd.nextDouble() * MAX_PRICE;
double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f – 1f);

prices[i] = new StockPrice(symbols[i], price, change);
}

return prices;
}

エクリプスはRandomに目印を付け(赤波下線エラー)、import宣言を追加するよう提案します。

 

  • com.google.gwt.user.client.ではなく、java.utilのimport宣言を追加します。
    import java.util.Random;
    実装の注意: サービス実装はサーバ上でJavaバイトコードとして実行されるので、Javaスクリプトに変換出来るかどうか悩むことなく、いかなるJavaクラスまたはライブラリを使用できることを思い出してください。このケースではエミュレートされたGWTバージョン(com.google.gwt.user.client.Random)の代わりにJava runtime library (java.util.Random)のRandomクラスを使用することが出来ます。
  • このリストは完成したStockPriceServiceImplクラスを示します。
    package com.google.gwt.sample.stockwatcher.server;

 

import com.google.gwt.sample.stockwatcher.client.StockPrice;
import com.google.gwt.sample.stockwatcher.client.StockPriceService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import java.util.Random;

public class StockPriceServiceImpl extends RemoteServiceServlet implements StockPriceService {

private static final double MAX_PRICE = 100.0; // $100.00
private static final double MAX_PRICE_CHANGE = 0.02; // +/- 2%

public StockPrice[] getPrices(String[] symbols) {
Random rnd = new Random();

StockPrice[] prices = new StockPrice[symbols.length];
for (int i=0; i
double price = rnd.nextDouble() * MAX_PRICE;
double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f – 1f);

prices[i] = new StockPrice(symbols[i], price, change);
}

return prices;
}

}

サーバサイドコードをGWTモジュールに追加する

組み込みサーブレットコンテナ(Jetty)はサービス実装を含むサーブレットをホストすることができます。これはサーバサイドのJavaコードをテストしたりデバッグしている間は開発モードでのアプリケーションの実行を利用することが出来るということを意味します。
これを設定をする為に配備記述子(web.xml)へとの要素を追加し、実装クラス (StockPriceServiceImpl)を指定します。
GWT 1.6で始める場合、サーブレットはGWTモジュール(StockWatcher.gwt.xml)の代わりに配備記述子(web.xml)で定義されるべきです。
要素内で、URLパターンは絶対ディレクトリパスの形式が可能です。(例えば/spellcheck または /common/login)  サービスインターフェイス上で@RemoteServiceRelativePathアノテーションを伴うデフォルトサービスパスを指定した(StockPriceServiceで指定した)場合、url-patternがアノテーションの値と一致するか確かめます。
StockPriceServiceを”stockPrices”へマッピングし、StockWatcher.gwt.xml内の要素のrename-to属性が”stockwatcher”なので、完全なURLは以下のようになります:
http://localhost:8888/stockwatcher/stockPrices
※StockWatcher.gwt.xmlのstockwatcher‘>とweb.xmlの@RemoteServiceRelativePath(“stockPrices“) の緑字部分の連結
  1. 配備記述子を編集します。 (StockWatcher/war/WEB-INF/web.xml)
    greetServletはもはや必要がないので定義を取り除いても大丈夫です。

    
        PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd">
    
    
    
      
      
        StockWatcher.html
      
    
      
      
        stockPriceServiceImpl
        com.google.gwt.sample.stockwatcher.server.StockPriceServiceImpl
      
    
      
        stockPriceServiceImpl
        /stockwatcher/stockPrices
      
    
    
    

 2. クライアントからのサービスの呼び出し

サーバへの非同期呼び出しの作成

全てのサービスメソッドへ非同期コールバックパラメータを追加する必要があります。全てのサービスメソッドへ非同期コールバックパラメータを追加するためには以下の新しいインターフェイスを定義しなければなりません:
  • サービスインターフェイスの名前にAsyncを追加した名前を持たなければなりません。(例えば、 StockPriceServiceAsync)
  • サービスインターフェイスと同じパッケージ内に位置していなければなりません。
  • 各メソッドは同じ名前とサービスインターフェイスのものとは重要な違いを備えたシグネチャを持っていなければなりません:メソッドは返り値の型を持たず、パラメータの最後はAsyncCallbackオブジェクトです。
   
    StockPrice[] getPrices(String[] symbols) → void getPrices(String[] symbols,AsyncCallback<StockPrice[]> callback);
 
  1. クライアントサブパッケージ内で、インターフェイスを作成しStockPriceServiceAsyncと命名します。
  2. スタブコードを以下のコードに置換えます。
    package com.google.gwt.sample.stockwatcher.client;
    
    import com.google.gwt.user.client.rpc.AsyncCallback;
    
    public interface StockPriceServiceAsync {
    
      void getPrices(String[] symbols, AsyncCallback<StockPrice[]> callback);
    
    }
Tip: Eclipse用Googleプラグインは一致する非同期インターフェイスを持たない同期リモートサービスを発見した時、エラーを生成します。自動的に非同期インターフェイスを生成するためにはEclipseでエラー部分で右クリック、クィックフィックスを選択して、”Create asynchronous RemoteService interface”オプションを選びます。

リモートプロシージャコールの作成(※”コールの実行”の方が訳としては正しいかもしれません)

コールバックメソッド

リモートプロシージャを呼び出す時、呼び出し完了時に実行されるコールバックメソッドを指定することが出来ます。サービスプロキシクラスにAsyncCallback オブジェクトを渡すことによってコールバックメソッドを指定します。AsyncCallback オブジェクトは二つのメソッドを含みます。呼び出しが失敗または成功したかどうかによっていずれかが呼ばれます: onFailure(Throwable) and onSuccess(T).
  1. サービスプロキシクラスを作成します。
    StockWatcherクラスでGWT.create(Class)を呼ぶことによってサービスプロキシクラスのインスタンスを作成します.
    private ArrayList stocks = new ArrayList();
      private StockPriceServiceAsync stockPriceSvc = GWT.create(StockPriceService.class);
    エクリプスはGWTに目印を付けます(※赤波下線エラー)
  2. サービスプロキシクラスを初期化し、コールバックオブジェクトのセットアップ、リモートプロシージャへの呼び出しを作成します。
    既存のrefreshWatchListメソッドを以下のコードに置換えます。
    private void refreshWatchList() {
        // Initialize the service proxy.
        if (stockPriceSvc == null) {
          stockPriceSvc = GWT.create(StockPriceService.class);
        }
    
        // Set up the callback object.
        AsyncCallback<StockPrice[]> callback = new AsyncCallback<StockPrice[]>() {
          public void onFailure(Throwable caught) {
            // TODO: Do something with errors.
          }
    
          public void onSuccess(StockPrice[] result) {
            updateTable(result);
          }
        };
    
        // Make the call to the stock price service.
        stockPriceSvc.getPrices(stocks.toArray(new String[0]), callback);
      }
    エクリプスはAsyncCallbackに目印を付けます(※赤波下線エラー)
  3. import宣言を追加します。
    import com.google.gwt.core.client.GWT;
    
    import com.google.gwt.user.client.rpc.AsyncCallback;

リモートプロシージャコールのテスト

この時点で、サービスの作成、モジュールXMLでのその指定、非同期呼び出しを作成する為のメカニズムのセットアップ、サービスを呼び出すためのクライアントサイドでのサービスプロキシの生成が完了しています。 しかしながら問題があります。
  1. Eclipseデバッガを使用して開発モードでStockWatcherを実行します。
  2. 開発シェルウィンドウでエラーログを調べます。
    [ERROR] Type 'com.google.gwt.sample.stockwatcher.client.StockPrice' was not serializable
     and has no concrete serializable subtypes
サービス実装(StockPriceServiceImpl)で、RemoteServiceServletクラスをextendsすることによって,Javaオブジェクトをシリアライズ・デシリアライズするコードを継承します。しかしながら問題はStockPriceクラスがシリアライズ可能であるということを示す為に編集していないことなのです。

 3.Javaオブジェクトのシリアライズ(直列化)

シリアライゼーションはあるアプリケーションから別のアプリケーションへ移動または後で使用する為に貯蔵できるようにするためにするオブジェクトの内容のパッケージング処理です?(※it can be moved?) GWT RPC経由でネットワーク越しにオブジェクトを転送する時は常にオブジェクトはシリアライズされていなければなりません。特にGWT RPCは全てのサービスメソッドパラメータと返される型がシリアライズ可能であることを要求します。
以下の内、一つでもtrueならば、型はシリアライズ可能でサービスインターフェイスで使用することが出来ます:
  • 全てのプリミティブ型 (int, char, boolean, etc.) とそのラッパーオブジェクトはデフォルトでシリアライズ可能です。
  • シリアライズ可能な型の配列は拡張(継承)によってシリアライズ可能です。
  • 以下の三点の要求を満たすクラスはシリアライズ可能です:
    • 直接、またはそれが派生したスーパークラスのいずれかがJava Serializable または GWT IsSerializable インターフェイスのどちらかを実装している?(※becauseがよくわからない)
    • finalでもtransientでもないインスタンスフィールド自身がシリアライズ可能である。(※, and? 何処かの文を流用した名残?)
    • 任意のアクセス修飾子を伴った(引数が0の)デフォルトコンストラクタを持ちます。(例えばprivate Foo(){}は動きます)
GWTはtransientキーワードを尊重します。したがって、このキーワードで指定されたフィールドの値はシリアライズされません。 (したがってRPCコールが使用された時にワイヤー越しに送信されません)
Note: GWTのシリアライズはJavaのSerializableインターフェイスと同じではありません。GWTで何がシリアライズ可能かそうでないかのより詳しい情報については開発者ガイドのSerializable Typesを見てください。

StockPriceのシリアライズ

シリアライゼーションの要求に基づいて、GWT RPCに対する準備をStockPriceクラスにするためには何が必要でしょうか? StockPriceのインスタンスフィールドは全てプリミティブ型なので、この場合、あなたがする必要があることは SerializableまたはIsSeriazableインターフェイスをimplementsすることです。
package com.google.gwt.sample.stockwatcher.client;

import java.io.Serializable;

public class StockPrice implements Serializable {

  private String symbol;
  private double price;
  private double change;

  ...
  1. 開発モードでStockWatcherを更新します。
  2. 株を追加します。
  3. StockWatcher はテーブルに株を追加します;価格とチェンジフィールドはデータを含み、エラーはありません。
    StockWatcherは表面上、全く違いが見えませんが、その下でクライアントサイドで株価を生成する代わりに組み込みサーブレットコンテナ上のサーバサイドのStockPriceServiceサーブレットからその株価の更新を取得します。
この時点で、基本的なRPCメカニズムは動いています。しかしながらTODOが一つ残っています。コールバックが失敗した場合に備えてエラー処理をコード化する必要があります。

 4. 例外の処理

リモートプロシージャの呼び出しに失敗した場合、 原因は2つのカテゴリのうちの一つに分類されます: 予期しない例外(チェックされない例外)またはチェックされる例外。 いずれの場合も例外を処理し、必要に応じてユーザーにフィードバックを供給すべきです。
予期しない例外: 多くの予想外の出来事はリモートプロシージャへの呼び出しの失敗を引き起こすかもしれません: ネットワークはダウンしてるかもしれません; 反対側のHTTPサーバはリスニング(監視)してないかもしれません;DNSサーバは炎上してるかもしれません等等…
GWTがサービスメソッドを呼び出すことが出来る場合、違う型の予期しない例外を起こすことが出来ますが、サービス実装は宣言されていない例外を投げます。例えばバグはNullPointerExceptionを発生させるかもしれません。
サービス実装で予期しない例外が起きた場合、開発モードログのフルスタックトレースを見つけることが出来ます。クライアントサイドでは、onFailure(Throwable) コールバックメソッドが一般的なメッセージを伴ったInvocationExceptionを受け取ります: サーバで呼び出しが失敗した場合は詳細はサーバログを見てください。
チェックされる例外: サービスメソッドがスローするかもしれない特定の例外の型が分かっていて、それをクライアントサイドのコードで処理できるようにしたい場合、チェックされる例外を使用出来ます。必要に応じてサービスインターフェイスメソッドに追加出来るようにGWTはthrowsキーワードをサポートします。RPCサービスメソッドでチェックされる例外が起きた場合、GWTは例外をシリアライズし、処理するためにクライアント上の呼び出し元へ送り返します。

チェックされる例外の作成

RPCでのエラーを処理する方法を学ぶ為に、ユーザーが呼び出しを失敗させる”delisted”とあなたが定義した株コードを追加した場合、エラーを投げます。それからユーザーへエラーメッセージを表示することによって失敗を処理します?  (※delist=証券取引所記載から取り除く保安

例外のチェックとスロー

クラスの作成: DelistedException
  1. delistedの株コードを識別するためのクラスを作成します。
    エクリプスでは、新規Javaクラスウィザードを起動します。 (ファイル(F) > 新規(N) > クラス)
  2. 名前(M)に、DelistedExceptionと入力します。
  3. java.lang.Exception クラスをextend(継承)します。
  4. java.io.Serializable インターフェイスをimplement(実装)します。
    例外はRPCによって送信されるよう設計されています;従ってこのクラスはシリアライズ可能でなければなりません。
  5. 抽象メソッドを継承します。
  6. 完了(F)をクリックします。
    Eclipse はスタブコードのDelistedException クラスを作成します。
  7. スタブコードを以下のコードに置換えます。
    package com.google.gwt.sample.stockwatcher.client;
    
    import java.io.Serializable;
    
    public class DelistedException extends Exception implements Serializable {
    
      private String symbol;
    
      public DelistedException() {
      }
    
      public DelistedException(String symbol) {
        this.symbol = symbol;
      }
    
      public String getSymbol() {
        return this.symbol;
      }
    }
stock price service インターフェイスの更新: StockPriceService
  1. サービスインターフェイスで (StockPriceService)、getPrices(String[]) メソッドへthrows 宣言を付加します。
    StockPriceService.javaで、以下でハイライトされた部分の修正をします。
    package com.google.gwt.sample.stockwatcher.client;
    
    import com.google.gwt.user.client.rpc.RemoteService;
    import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
    
    @RemoteServiceRelativePath("stockPrices")
    public interface StockPriceService extends RemoteService {
    
      StockPrice[] getPrices(String[] symbols) throws DelistedException;
    }
stock price サービス実装の更新: StockPriceServiceImpl
 サービス実装(StockPriceServiceImpl)へ二つの修正を行う必要があります。.
  1. getPrices(String[]) メソッドへ対応する修正を行います。
    throws 宣言を付加します。
    DelistedException用のimport宣言を追加します。
  2. Delisted Exceptionをスローするためにコードを追加します。
    このサンプルのために、コードはシンプルかつ 株シンボル ERRがウォッチリストへ追加された時に例外をスローするだけにします。
  3. このリストは完成したStockPriceServiceImpl クラスを示します。
    import com.google.gwt.sample.stockwatcher.client.DelistedException;
    
    ...
    
      public StockPrice[] getPrices(String[] symbols) throws DelistedException {
        Random rnd = new Random();
    
        StockPrice[] prices = new StockPrice[symbols.length];
        for (int i=0; i<symbols.length; i++) {
          if (symbols[i].equals("ERR")) {
            throw new DelistedException("ERR");
          }
    
          double price = rnd.nextDouble() * MAX_PRICE;
          double change = price * MAX_PRICE_CHANGE * (rnd.nextDouble() * 2f - 1f);
    
          prices[i] = new StockPrice(symbols[i], price, change);
        }
    
        return prices;
      }
この時点で、例外をスローするコードを作成し終えました。StockPriceServiceAsync.javaでサービスメソッドへthrows宣言を追加する必要はありません。StockPriceServiceAsyncのメソッドは常に直接返ってきます。(非同期であることを思い出してください)  代わりにGWTがonFailure(Throwable) コールバックメソッドを呼び出した時にスローされたどんなチェックされる例外も受け取ります。

エラーメッセージの表示

エラーを表示するために、新しいUIコンポーネントが必要です。最初にどうやってエラーを表示したいかについてちょっと考えてください。すぐにわかる解決策はWindow.alert(String)を使用してポップアップを表示することです。これは株コードを入力している間にユーザーがエラーを受け取る場合には実行出来ます。しかしより現実世界に近いサンプルでは、
ユーザーが監視リストへ株を追加した後にdelistedになった場合、何が発生して欲しいか?または複数のエラーを表示する必要がある場合は?これらの場合、ポップアップアラートは最善のアプローチではありません。
だから株データの取得に失敗した如何なるメッセージも表示するために、Label ウィジェットを実装します。
  1. ユーザーの注意を喚起するようにエラーメッセージ用のスタイルを定義します。
    StockWatcher.cssで、エラーメッセージのクラス属性を備えたどんな要素にでも適用されるスタイルルールを作成します。
    .negativeChange {
      color: red;
    }
    
    .errorMessage {
      color: red;
    }
  2. エラーメッセージのテキストを保持するため、Labelウィジェットを追加します。
    StockWatcher.javaで、次のインスタンスフィールドを追加します。
    private StockPriceServiceAsync stockPriceSvc = GWT.create(StockPriceService.class);
      private Label errorMsgLabel = new Label();
  3. StockWatcher実行時にエラーメッセージラベルの初期化をします。
    onModuleLoad メソッドで、エラーメッセージラベルへセカンダリクラス属性を追加し、StockWatcherのロード時には表示しないようにします。
    stocksFlexTable上のMainパネルへエラーメッセージラベルを追加します。
    // Assemble Add Stock panel.
        addPanel.add(newSymbolTextBox);
        addPanel.add(addButton);
        addPanel.addStyleName("addPanel");
    
        // Assemble Main panel.
        errorMsgLabel.setStyleName("errorMessage");
        errorMsgLabel.setVisible(false);
    
        mainPanel.add(errorMsgLabel);
        mainPanel.add(stocksFlexTable);
        mainPanel.add(addPanel);
        mainPanel.add(lastUpdatedLabel);

エラーの処理

エラーを表示するためのLabelウィジェットを構築したので、エラー処理コードの記述を終了することが出来ます。
更にエラーが修正され場合、あなたはエラーメッセージを隠したいでしょう。(例えば、ユーザーが株テーブルからERRコードを取り除いた場合)
  1. コールバックが失敗した場合に講ずる処置を指定します。
    StockWatcher.javaのrefreshWatchListメソッドで、以下のようにonFailureメソッドを埋めます。
    public void onFailure(Throwable caught) {
            // If the stock code is in the list of delisted codes, display an error message.
            String details = caught.getMessage();
            if (caught instanceof DelistedException) {
              details = "Company '" + ((DelistedException)caught).getSymbol() + "' was delisted";
            }
    
            errorMsgLabel.setText("Error: " + details);
            errorMsgLabel.setVisible(true);
          }
  2. エラーが修正された場合、エラーメッセージウィジェットを隠します。
    updateTable(StockPrice[] prices) メソッドで、エラーをクリアします。
    private void updateTable(StockPrice[] prices) {
        for (int i=0; i < prices.length; i++) {
          updateTable(prices[i]);
        }
    
        // Display timestamp showing last refresh.
        lastUpdatedLabel.setText("Last update : " +
            DateTimeFormat.getMediumDateTimeFormat().format(new Date()));
    
        // Clear any errors.
        errorMsgLabel.setVisible(false);
      }

RPCでの例外処理をテスト

この時点で、例外の作成とチェックをしました—delisted 株コード “ERR”。StockWatcherがdelisted 株コード用の株データを取得するためにリモートプロシージャの呼び出しを作成した場合、呼び出しは失敗し、例外がスローされ、エラーメッセージを表示することによって処理します。
  1. 開発モードでStockWatcherを更新します。
  2. 株コード ERRを追加します。
  3. StockWatcherは赤いエラーメッセージを表示します。有効な株コードデータは更新を停止されます。
    screenshot: RPC error message
  4. 株コード  ERRを削除します。
  5. エラーメッセージが除去されます。有効な株コードデータは更新され続けます。

 次は何?

この時点で、サーバから株データを取得するためのリモートプロシージャの呼び出しを作成しました。
GWT RPCのより詳しい情報については、開発者ガイドのRemote Procedure Callsを見てください。

プロダクションへのサービスへのデプロイ

テストの間中、あなたのRPCサービスのサーバサイドコードをテストするために開発モードに組み込まれているサーブレットコンテナを使用することが出来ます-ちょうどこのチュートリアルでやってきたように。GWTアプリケーションをデプロイする場合、あなたのサービスをホストするためにどんなサーブレットコンテナでも使用できます。web.xml設定ファイルでサーブレットにマップされているURLを使用してクライアントコードがサービスを呼び出せるか確かめてください。
プロダクションサーバへのGWT RPCサーブレットをデプロイする方法を学ぶためには、開発者ガイドのDeploying RPCを見てください