corner imagecorner image
IDEPlatformPluginsDocs & SupportCommunityPartners

JAX-WS Web サービスクライアントの開発

このチュートリアルでは、NetBeans IDE が提供する Web サービス機能を使用して、「Spell Checker」という Web サービスを分析してから、このサービスと連動する Web クライアントを構築します。クライアントはサーブレットクラスと JSP ページを使用します。ユーザーは JSP ページからサーブレットに情報を渡します。

目次

このページの内容は NetBeans IDE 6.9-7.1 が対象です

このチュートリアルに従うには、次のソフトウェアとリソースが必要です。

ソフトウェアまたはリソース 必須バージョン
NetBeans IDE Java EE ダウンロードバンドル
Java Development Kit (JDK) version 6 または version 76
警告: NetBeans IDE 6.9 には JDK 6 が必要です
Java EE 互換の Web サーバーまたはアプリケーションサーバー Tomcat Web サーバー 7.0
GlassFish Server Open Source Edition
Oracle WebLogic Server

注意: JDK 6 を使用している場合は、JDK 6 Update 7 以降が必要です。

Tomcat および GlassFish サーバーは、どちらも NetBeans IDE の Web および Java EE の配布とともにインストールできます。または、GlassFish サーバーのダウンロードページApache Tomcat のダウンロードページからダウンロードすることもできます。

重要: Java EE 6 プロジェクトには、Tomcat 7.x、GlassFish Server 3.x、または Oracle WebLogic Server 12c が必要です。

クライアントは次のようなもので、データはすべて Web サービスで取得しています。

Spell Checker のレポート

このチュートリアルを終えると、このアプリケーションで行うのが、チェック対象のテキストの入力、Web サービス上での操作の起動、および結果の描画だけであることがわかります。Web サービスへの接続とテキストの送信に必要なコードは、IDE がすべて生成します。スペルチェッカーの Web サービスが残りを引き受けます。これはスペルミスの単語を識別し、代替の単語を提案します。

このチュートリアルで使用する Spell Checker Web サービスは、CDYNE 社が提供しています。CDYNE は、データ拡張、データ品質、およびデータ分析の各 Web サービスと、ビジネスインテリジェンスを統合する、包括的なスイートを開発、販売、およびサポートしています。Spell Checker Web サービスは、CDYNE が提供する Web サービスの 1 つです。1 つまたは複数の Web サービスに基づくアプリケーションの堅牢さは、Web サービスの可用性と信頼性によって決まります。ただし、CDYNE の FAQ では、CDYNE が「100% の可用性を目標」とし、「自然災害、テロ、その他の災害時に、Web サービスのトラフィックはセカンダリデータセンターに転送される」とあります。CDYNE のおかげでこのチュートリアルを執筆できました。サービスの開発のサポートに感謝します。

Spell Checker Web サービスの使用

ネットワークを介して Web サービスを使用、つまり「消費」するには、Web サービスクライアントを作成する必要があります。Web サービスクライアントの作成のために、NetBeans IDE にはクライアント作成機能が用意されています。これは、Web サービス検索用のコードを生成する、「Web サービスクライアント」ウィザードです。また、作成した Web サービスクライアントを開発する機能もあります。これは「プロジェクト」ウィンドウ上の複数のノードからなる作業領域で行います。これらの機能は NetBeans IDE のインストールの EE バンドルの一部です。これらはそのままの状態で使用でき、プラグインは不要です。

クライアントの作成

この節では、ウィザードを使用して、Web サービスの WSDL ファイルから Java オブジェクトを生成します。

  1. 「ファイル」>「新規プロジェクト」(Windows および Linux では Ctrl-Shift-N、MacOS では ⌘-Shift-N) を選択します。「カテゴリ」から「Java Web」を選択します。「プロジェクト」から「Web アプリケーション」を選択します。「次へ」をクリックします。プロジェクト名を「SpellCheckService」とし、ターゲットサーバーに適切なサーバーを指定していることを確認します。詳細は、「入門」節を参照してください。その他のオプションはデフォルトのままにし、「完了」をクリックします。
  2. 「プロジェクト」ウィンドウで SpellCheckService プロジェクトノードを右クリックし、「新規」>「その他」を選択します。「新規ファイル」ウィザードで、「Web サービス」>「Web サービスクライアント」を選択します。「Web サービスクライアント」ウィザードで、次に示す Web サービスへの URL を指定します。

    http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl

    ファイアウォールを使用している場合、プロキシサーバーの指定が必要になることがあります。そうしないと、WSDL ファイルをダウンロードできません。プロキシサーバーを指定するには、ウィザードの「プロキシを設定」をクリックします。IDE の「オプション」ウィンドウが開き、IDE のプロキシを汎用的に設定できます。

  3. パッケージ名は空にしておきます。デフォルトでは、クライアントクラスのパッケージ名は WSDL から取得されます。今回のケースでは com.cdyne.ws です。
  4. 「プロジェクト」ウィンドウの「Web サービス参照」ノードは、次のようになります。
    Web サービス参照を表示している「プロジェクト」ウィンドウ

この「プロジェクト」ウィンドウは、「check」という Web サービスにより、アプリケーションでいくつかの「CheckTextBody」および「CheckTextBodyV2」操作が利用可能になっていることを示しています。これらの操作は、文字列をチェックしてスペルミスを発見し、クライアントで処理するデータを返します。サービスの V2 バージョンでは認証を必要としません。このチュートリアル全体では、checkSoap.CheckTextBodyV2 操作を使用します。

生成したソース」ノード内に、JAX-WS の「Web サービスクライアント」ウィザードで生成されたクライアントスタブが表示されます。

build ノードのパッケージ構造を示す「ファイル」ビュー

「WEB-INF」ノード、「wsdl」サブノードを展開します。WSDL ファイルのローカルコピーである check.asmx.wsdl があります。

「プロジェクト」ウィンドウで「WEB-INF」内に表示された WSDL のローカルコピーとマッピングファイル

クライアントの作成に使用した WSDL の URL が、jax-ws-catalog.xml 内で WSDL のローカルコピーにマップされています。ローカルコピーへのマップにはいくつかの利点があります。WSDL のリモートコピーがなくてもクライアントを実行できます。また、リモートの WSDL ファイルを解析する必要がないので、クライアントの処理が高速になります。そして、可搬性の実現が簡単です。詳細は、DZone の記事「NetBeans IDE 6.7 を使用して作成した JAX-WS クライアントの移植性とパフォーマンスの改善」を参照してください。

生成された jax-ws-catalog マッピングファイル

クライアントの開発

Web サービスクライアントを実装する方法はいくつもあります。Web サービスの WSDL ファイルは、Web サービスに送信できる情報の種類を制限するとともに、逆に受け取る情報の種類も制限します。ただし、WSDL ファイルは、必要となる情報を送信する方法や、ユーザーインタフェースを構成する内容には制限を設けません。次に構築するクライアント実装は、ユーザーがテキストを入力してチェックできるようにする JSP ページと、そのテキストを Web サービスに送信したあと結果レポートを生成するサーブレットで構成されます。

JSP ページのコーディング

今回の JSP ページは、ユーザーがテキストを入力するテキスト領域と、そのテキストを Web サービスに送信するボタンの構成にします。

  1. 「プロジェクト」ウィンドウで、「SpellCheckService」プロジェクトの「Web ページ」ノードを展開して「index.jsp」をダブルクリックすると、そのファイルがソースエディタで開きます。
  2. 次のコードをコピーし、index.jsp<body> タグにペーストします。
    <body>
      <form name="Test" method="post" action="SpellCheckServlet">
         <p>Enter the text you want to check:</p>
         <p>
         <p><textarea rows="7" name="TextArea1" cols="40" ID="Textarea1"></textarea></p>
         <p>
         <input type="submit" value="Spell Check" name="spellcheckbutton">
      </form>
    </body>

    前出のコードでは、送信ボタンがクリックされるときに、textarea の内容が SpellCheckServlet というサーブレットに送信されることが指定されています。

サーブレットの作成およびコーディング

この節では、Web サービスと相互作用するサーブレットを作成します。ただし、相互作用を実行するコードは IDE が提供します。結果として、開発者が処理する必要があるのはビジネスロジックだけです。つまり、送信するテキストの準備と結果の処理です。

  1. 「プロジェクト」ウィンドウで「SpellCheckService」プロジェクトノードを右クリックし、「新規」>「その他」を選択します。次に、「Web」>「サーブレット」を選択します。「次へ」をクリックします。「新規サーブレット」ウィザードが開きます。
  2. サーブレットの名前を SpellCheckServlet とし、「パッケージ」のドロップダウンに「clientservlet」と入力します。
    サーブレットの名前とパッケージを示す「新規サーブレット」ウィザード
  3. 「次へ」をクリックします。「サーブレット配備を構成」パネルが開きます。このサーブレットの URL マッピングが /SpellCheckServlet であることを確認します。デフォルトを受け入れ、「完了」をクリックします。ソースエディタでサーブレットが開きます。
    ブラウザでの表示
  4. ソースエディタ内の processRequest メソッドの本体内にカーソルを置き、メソッドの直前に新しい行をいくつか加えます。
  5. 前の手順で作成したスペースで右クリックし、「コードを挿入」>「Web サービスオペレーションを呼び出す」を選択します。次に示すように、「呼び出すオペレーションを選択」ダイアログで「checkSoap.CheckTextBodyV2」操作をクリックします。
    Web サービス参照を表示している「プロジェクト」ウィンドウ

    「了解」をクリックします。

    注: このダイアログを呼び出す代わりに、オペレーションのノードを「プロジェクト」ウィンドウからエディタに直接ドラッグ&ドロップすることもできます。

    SpellCheckServlet クラスの末尾に、SpellCheckerV2 サービスを呼び出し、com.cdyne.ws.DocumentSummary オブジェクトを返す非公開メソッドが表示されます。

    private DocumentSummary checkTextBodyV2(java.lang.String bodyText) {
    com.cdyne.ws.CheckSoap port = service.getCheckSoap();
    return port.checkTextBodyV2(bodyText);
    }

    Web サービスのオペレーションを呼び出すのに必要なのはこのメソッドだけです。また、クラスの先頭で次のコード行が宣言されます。

    @WebServiceRef(wsdlLocation = "http://wsf.cdyne.com/SpellChecker/check.asmx?WSDL")
    private Check service;
  6. processRequest() メソッドの try ブロックを次のコードに置き換えます。コード内のコメントは、各行の目的を説明しています。
    try {
        //JSP ページから TextArea を取得
    String TextArea1 = request.getParameter("TextArea1");
    //WS 操作の引数を初期化 java.lang.String bodyText = TextArea1; //結果を処理 com.cdyne.ws.DocumentSummary doc = checkTextBodyV2(bodyText); String allcontent = doc.getBody(); //取得した DocumentSummary から、 //誤ったスペルの単語数を特定: int no_of_mistakes = doc.getMisspelledWordCount(); //取得した DocumentSummary から、 //誤ったスペルの単語の配列を特定: List allwrongwords = doc.getMisspelledWord(); out.println("<html>"); out.println("<head>"); //レポート名をタイトルとしてブラウザのタイトルバーに表示: out.println("<title>Spell Checker Report</title>"); out.println("</head>"); out.println("<body>"); //レポート名をヘッダーとしてレポートの本文に表示: out.println("<h2><font color='red'>Spell Checker Report</font></h2>"); //すべての内容 (正しいスペルおよび間違ったスペル) を引用符の間に表示: out.println("<hr><b>Your text:</b> \"" + allcontent + "\"" + "<p>"); //誤った単語の各配列 (1 つの誤った単語について 1 つの配列) に対し、 //誤った単語、候補の数、および //候補の配列を特定。続いて誤った単語と修正候補の数を表示し、 // 現在の誤った単語に関連する修正候補の配列について、 // それぞれの修正候補を表示: for (int i = 0; i < allwrongwords.size(); i++) { String onewrongword = ((Words) allwrongwords.get(i)).getWord(); int onewordsuggestioncount = ((Words) allwrongwords.get(i)).getSuggestionCount(); List allsuggestions = ((Words) allwrongwords.get(i)).getSuggestions(); out.println("<hr><p><b>Wrong word:</b><font color='red'> " + onewrongword + "</font>"); out.println("<p><b>" + onewordsuggestioncount + " suggestions:</b><br>"); for (int k = 0; k < allsuggestions.size(); k++) { String onesuggestion = (String) allsuggestions.get(k); out.println(onesuggestion); } } // 誤った単語の各配列のあとに水平線を表示: out.println("<hr>"); // 誤った単語の数をまとめた Summary を作成して表示: out.println("<font color='red'><b>Summary:</b> " + no_of_mistakes + " mistakes ("); for (int i = 0; i < allwrongwords.size(); i++) { String onewrongword = ((Words) allwrongwords.get(i)).getWord(); out.println(onewrongword); } out.println(")."); out.println("</font>"); out.println("</body>"); out.println("</html>"); } catch (Exception ex) { out.println("exception" + ex); } finally { out.close(); }
  7. 見つからないクラスを通知するエラーバーや警告アイコンが表示されます。コードのペースト後にインポートを修正するには、Ctrl-Shift-I (Mac の場合は ⌘-Shift-I) を押すか、任意の場所を右クリックしてコンテキストメニューを開き、「インポートを修正」を選択します。(インポートする List クラスを選択できます。デフォルトの java.util.List を選択します。)インポートされるクラスの一覧は、次のとおりです。
    import com.cdyne.ws.Check;
    import com.cdyne.ws.Words;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.List;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.xml.ws.WebServiceRef;

    注: com.cdyne.* クラスが見つからないという警告が表示されても、気にしないでください。この問題は、プロジェクトを構築し、WSDL ファイルが解析されてクラスが検出されると解決されます。

    このコードでは、エラー処理が行われていません。詳細は、応用を参照してください。

クライアントの配備

IDE は、Ant 構築スクリプトを使用して、アプリケーションを構築および実行します。IDE は、プロジェクト作成時にユーザーが入力したオプションに基づいて、構築スクリプトを生成します。このオプションは、プロジェクトの「プロジェクトプロパティー」ダイアログ (「プロジェクト」ウィンドウでプロジェクトノードを右クリックし、「プロパティー」を選択) で微調整できます。

  1. プロジェクトのノードを右クリックし、「実行」を選択します。しばらくすると、アプリケーションが配備され、前の節でコード入力した JSP ページが表示されます。
  2. テキストを入力します。誤ったスペルの単語が含まれるようにします。
    チェックするテキストの入った JSP ページ
  3. 「Spell Check」をクリックして結果を確認します。
    誤りを表示する Spell Checker のレポート

非同期 Web サービスクライアント

デフォルトでは、NetBeans IDE で作成された JAX-WS クライアントは同期クライアントです。同期クライアントは、サービスで要求を呼び出し、その応答を待つ間は処理を中断します。ただし、応答を待たずに、クライアントでほかの処理を続ける場合もあります。たとえば、サービスが要求を処理するのに膨大な時間がかかるような場合です。サービスからの応答を待たずに処理を続行する Web サービスクライアントは、「非同期」と呼ばれます。

非同期クライアントは、サービスに対して要求を開始すると、その応答を待たずに処理を再開します。サービスはクライアント要求を処理し、その後、クライアントが応答を取得して処理を続行する間に応答を返します。

非同期クライアントは、「ポーリング」方式または「コールバック」方式で Web サービスを消費します。「ポーリング」方式では、Web サービスメソッドを呼び出して、結果を繰り返し要求します。ポーリングは、呼び出し側スレッドをブロックするブロッキング動作です。そのため、GUI アプリケーションでは使用しません。「コールバック」方式では、Web サービスメソッドの呼び出し中にコールバックハンドラを渡します。結果が入手可能になると、ハンドラの handleResponse() メソッドが呼び出されます。この方式では応答を待つ必要がないため、GUI アプリケーションに適しています。たとえば、GUI イベントハンドラから呼び出しを行ってもすぐに制御が戻り、ユーザーインタフェースが応答しやすい状態に保たれます。ポーリング方式には、応答がキャッチされたあとで消費されても、キャッチされたことを確認するためにポーリングする必要があるという欠点があります。

NetBeans IDE では、Web サービス参照の「Web サービス属性を編集」でボックスをクリックすることで、非同期クライアントに対するサポートを Web サービスクライアントアプリケーションに追加します。それ以外のクライアント開発は同期クライアントの場合と同じですが、Web サービスをポーリングするメソッドまたはコールバックハンドラを渡して結果を待機するメソッドがある点が異なります。

この節の以降の部分では、Swing グラフィカルインタフェースを作成し、その中に非同期 JAX-WS クライアントを埋め込む方法について説明します。

Swing フォームの作成

ここでは、Swing アプリケーションを作成します。自分で Swing GUI を設計しない場合、設計済みの JFrame をダウンロードして、「非同期クライアントの作成」の節に進んでください。

Swing クライアントは、ユーザーが入力したテキストを取得してサービスに送信し、誤りの数と、誤った単語の一覧を返します。また、このクライアントは、誤った単語とその修正候補を、一度に 1 つずつ表示します。

設計済みの Swing クライアント

Swing クライアントを作成するには、次の手順に従います。

  1. 新しい Java アプリケーションプロジェクトを作成します。「AsynchSpellCheckClient」という名前を付けます。このプロジェクトの Main クラスは作成しないでください。
  2. 「プロジェクト」ビューで、「AsynchSpellCheckClient」プロジェクトノードを右クリックし、「新規」>「JFrame フォーム...」を選択します。
  3. フォームの名前を「MainForm」にして、org.me.forms パッケージに配置します。
  4. JFrame の作成後、プロジェクトのプロパティーを開きます。「実行」カテゴリで、MainForm を主クラスとして設定します。
    MainForm を主クラスとして選択したプロジェクトプロパティー
  5. エディタで、MainForm.java の「デザイン」ビューを開きます。「パレット」から 3 つのスクロール区画を MainForm にドラッグ&ドロップします。スクロール区画を配置してサイズ変更します。ここには、チェック対象の入力テキスト、誤った単語すべて、および誤った単語一つに対する修正候補のためのテキストフィールドが保持されます。
  6. 5 つのテキストフィールドを MainForm にドラッグ&ドロップします。そのうちの 3 つを 3 つのスクロール区画にドロップします。次のように変更します。
    テキストフィールド
    変数名スクロール区画内ですか。編集可能ですか。
    tfYourTextYY
    tfNumberMistakesNN
    tfWrongWordsYN
    tfWrongWord1NN
    tfSuggestions1YN
  7. 進捗バーを MainForm にドラッグ&ドロップします。変数に pbProgress という名前を付けます。
  8. 2 つのボタンを MainForm にドラッグ&ドロップします。最初のボタンに btCheck という名前を付け、そのテキストを「Check Text」または「Check Spelling」に変更します。2 番目のボタンに btNextWrongWord という名前を付け、そのテキストを「Next Wrong Word」に変更し、無効にします。
  9. いくつかのラベルを MainForm にドラッグ&ドロップし、アプリケーションにタイトルを付けたり、テキストフィールドを説明したりします。

JFrame の外観を好みに合わせて調整し、保存します。次に、Web サービスクライアントの機能を追加します。

非同期クライアントの有効化

クライアントの作成」の説明に従って Web サービス参照を追加します。次に、非同期クライアントを有効にするように Web サービスの属性を編集します。

  1. 「プロジェクト」ウィンドウで「AsynchSpellCheckClient」プロジェクトノードを右クリックし、「新規」>「その他」を選択します。「新規ファイル」ウィザードで、「Web サービス」>「Web サービスクライアント」を選択します。「Web サービスクライアント」ウィザードで、次に示す Web サービスへの URL を指定します。

    http://wsf.cdyne.com/SpellChecker/check.asmx?wsdl。デフォルトをすべて受け入れ、「完了」をクリックします。これは、「クライアントの作成」の手順 2 以降で説明されている手順と同じです。

  2. 「Web サービス参照」ノードを展開し、「check」サービスを右クリックします。コンテキストメニューが開きます。
    「Web サービス属性を編集」にカーソルが置かれた状態の、「Web サービス参照」の Check サービスノードのコンテキストメニュー
  3. コンテキストメニューから「Web サービス属性を編集」を選択します。「Web サービス属性」ダイアログが開きます。
  4. 「WSDL カスタマイズ」タブを選択します。
  5. 「ポートタイプオペレーション」ノードを展開します。最初の CheckTextBodyV2 ノードを展開し、「非同期クライアントを有効にする」を選択します。
    ポートタイプオペレーション用の非同期クライアントを有効にするためのオプションが表示された「Web サービス属性」ダイアログ
  6. 「了解」をクリックします。ダイアログが終了します。Web サービス属性を変更するとクライアントノードが更新されることを示す警告が表示されます。
    生成されたクラスと WSDL が更新され、生成されたクラスを使用するアプリケーションに影響が出ることを示す警告
  7. 「了解」をクリックします。警告画面を閉じ、クライアントノードが更新されます。「Web サービス参照」の check ノードを展開すると、CheckTextBody オペレーションのポーリングとコールバックのバージョンがあることがわかります。
    「プロジェクト」ウィンドウの非同期クライアントオペレーション

これで SpellCheck サービスの非同期 Web サービスクライアントが、アプリケーションで有効になりました。

非同期クライアントコードの追加

これで、非同期 Web サービス操作が可能になったので、非同期操作を MainForm.java に追加します。

非同期クライアントコードを追加するには、次の手順に従います。

  1. MainForm で、「ソース」ビューに変更し、次のメソッドを最後の閉じ括弧の直前に追加します。
    public void callAsyncCallback(String text){
                     
    }
  2. 「プロジェクト」ウィンドウで、AsynchSpellCheckClient の「Web サービス参照」ノードを展開し、checkSoap.CheckTextBodyV2 [非同期コールバック] 操作を探します。
  3. CheckTextBodyV2 [非同期コールバック] 操作を空の callAsyncCallback メソッド本体にドラッグします。次の try ブロックが生成されます。この生成されたコードを、同期クライアント用に生成されたコードと比較します。
    try { // Web サービスオペレーションを呼び出す (async. callback)
          com.cdyne.ws.Check service = new com.cdyne.ws.Check();
          com.cdyne.ws.CheckSoap port = service.getCheckSoap();
          // TODO ここで WS 操作の引数を初期化
          java.lang.String bodyText = "";
          javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response> asyncHandler = 
                  new javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response>() {
                public void handleResponse(javax.xml.ws.Response<com.cdyne.ws.CheckTextBodyV2Response> response) {
                      try {
                            // TODO ここで非同期応答を処理
                            System.out.println("Result = "+ response.get());
                      } catch(Exception ex) {
                            // TODO 例外を処理
                      }
                }
          };
          java.util.concurrent.Future<? extends java.lang.Object> result = port.checkTextBodyV2Async(bodyText, asyncHandler);
          while(!result.isDone()) {
                // 何かを実行
                Thread.sleep(100);
          }
          } catch (Exception ex) {
          // TODO ここでカスタム例外を処理
    }

    このコードでは、Web サービスの呼び出しとともに、SpellCheck サービスからの応答が AsynchHandler オブジェクトを介して処理されることがわかります。一方、Future オブジェクトは、結果が返されたかどうかを確認し、その結果が完了するまでスレッドを休眠します。

  4. 「デザイン」ビューに戻ります。「Check Spelling」ボタンをダブルクリックします。ボタンに ActionListener が自動的に追加され、「ソース」ビューに切り替わります。このとき、カーソルは空の btCheckActionPerformed メソッドに置かれます。
  5. btCheckActionPerformed メソッドの本体に次のコードを追加します。このコードは、tfYourText フィールドに入力されたテキストを取得してサーバーを待機していることを示すメッセージを進捗バーに表示し、btCheck ボタンを無効にして、非同期コールバックメソッドを呼び出します。
    private void btCheckActionPerformed(java.awt.event.ActionEvent evt) {                                        
        String text = tfYourText.getText();
        pbProgress.setIndeterminate(true);
        pbProgress.setString("waiting for server");
        btCheck.setEnabled(false);
        callAsyncCallback(text);
    }
  6. MainForm クラスの先頭で、nextWord という名前の ActionListener 非公開フィールドをインスタンス化します。この ActionListener は、誤った単語のリスト内で単語を 1 つ進み、その単語と修正候補を表示する、「Next Wrong Word」ボタン用です。ここで非公開フィールドを作成すると、ActionListener がすでに定義されている場合に登録解除できます。そうしないと、新しいテキストを確認するたびに、追加リスナーを追加するため、複数のリスナーが actionPerformed() を何度も呼び出す結果になります。アプリケーションが正しく動作しなくなる可能性があります。
    public class MainForm extends javax.swing.JFrame {
        
        private ActionListener nextWord;
        ...
  7. callAsyncCallback メソッド全体を次のコードで置き換えます。もっとも外側の try ブロックは削除されます。このブロックが必要ないのは、より具体的な try ブロックがメソッド内に追加されるためです。コードに対するその他の変更は、コードコメントで説明します。
    public void callAsyncCallback(String text) {
    
            
        com.cdyne.ws.Check service = new com.cdyne.ws.Check();
        com.cdyne.ws.CheckSoap port = service.getCheckSoap();
        // ここで WS 操作の引数を初期化
        java.lang.String bodyText = text;
    
        javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response> asyncHandler = new javax.xml.ws.AsyncHandler<com.cdyne.ws.CheckTextBodyV2Response>() {
    
            public void handleResponse(final javax.xml.ws.Response<com.cdyne.ws.CheckTextBodyV2Response> response) {
                SwingUtilities.invokeLater(new Runnable() {
    
                    public void run() {
    
                        try {
                            // 応答を含む DocumentSummary オブジェクトを作成。
                               // com.cdyne.ws.CheckTextBody から直接呼び出される
                               // 同期クライアントと異なり、Response オブジェクトから
                               // getDocumentSummary() が呼び出される
    com.cdyne.ws.DocumentSummary doc = response.get().getDocumentSummary();
    //取得された DocumentSummary から、 //誤ったスペルの単語数を特定
    final int no_of_mistakes = doc.getMisspelledWordCount(); String number_of_mistakes = Integer.toString(no_of_mistakes); tfNumberMistakes.setText(number_of_mistakes);
    // 誤りがないかどうかを確認 if (no_of_mistakes > 0) {
    //取得されたドキュメントの概要から、 //誤ったスペルの単語の配列を特定 (ある場合)
    final List<com.cdyne.ws.Words> allwrongwords = doc.getMisspelledWord();
    //最初の誤った単語を取得 String firstwrongword = allwrongwords.get(0).getWord();
    //すべての誤った単語をコンマで区切った文字列を構築し、これを tfWrongWords に表示
    StringBuilder wrongwordsbuilder = new StringBuilder(firstwrongword); for (int i = 1; i < allwrongwords.size(); i++) { String onewrongword = allwrongwords.get(i).getWord(); wrongwordsbuilder.append(", "); wrongwordsbuilder.append(onewrongword); } String wrongwords = wrongwordsbuilder.toString(); tfWrongWords.setText(wrongwords);
    //最初の誤った単語を表示 tfWrongWord1.setText(firstwrongword);
    //誤った単語に対する修正候補の数を確認 int onewordsuggestioncount = allwrongwords.get(0).getSuggestionCount();
    //修正候補があるかどうかを確認 if (onewordsuggestioncount > 0) {
    //最初の誤った単語用の修正候補の一覧を作成し、それらを文字列に構築 //修正候補を連結した文字列を tfSuggestions1 テキストフィールドに表示
    List<String> allsuggestions = ((com.cdyne.ws.Words) allwrongwords.get(0)).getSuggestions(); String firstsuggestion = allsuggestions.get(0); StringBuilder suggestionbuilder = new StringBuilder(firstsuggestion); for (int i = 1; i < onewordsuggestioncount; i++) { String onesuggestion = allsuggestions.get(i); suggestionbuilder.append(", "); suggestionbuilder.append(onesuggestion); } String onewordsuggestions = suggestionbuilder.toString(); tfSuggestions1.setText(onewordsuggestions); } else { // このミスに対する修正候補はなし tfSuggestions1.setText("No suggestions"); } btNextWrongWord.setEnabled(true);
    // 次の誤った単語と修正候補を取得するための ActionListener が // すでに定義されているかどうかを確認。すでに定義されている場合は登録解除し、一度に登録 // されるアクションリスナーが 1 つだけになるようにする。
    if (nextWord != null) { btNextWrongWord.removeActionListener(nextWord); }
    // ActionListener (非公開フィールドとしてすでにインスタンス化済み) を定義 nextWord = new ActionListener() {
    //allwrongwords 一覧のインデックスを追跡するために変数を初期化 int wordnumber = 1; public void actionPerformed(ActionEvent e) { if (wordnumber < no_of_mistakes) {
    // allwrongwords のインデックス位置 wordnumber の誤った単語を取得 String onewrongword = allwrongwords.get(wordnumber).getWord();
    //次の部分は最初の誤った単語のコードと同じ
    tfWrongWord1.setText(onewrongword); int onewordsuggestioncount = allwrongwords.get(wordnumber).getSuggestionCount(); if (onewordsuggestioncount > 0) { List<String> allsuggestions = allwrongwords.get(wordnumber).getSuggestions(); String firstsuggestion = allsuggestions.get(0); StringBuilder suggestionbuilder = new StringBuilder(firstsuggestion); for (int j = 1; j < onewordsuggestioncount; j++) { String onesuggestion = allsuggestions.get(j); suggestionbuilder.append(", "); suggestionbuilder.append(onesuggestion); } String onewordsuggestions = suggestionbuilder.toString(); tfSuggestions1.setText(onewordsuggestions); } else { tfSuggestions1.setText("No suggestions"); }
    // 1 ずつ増分 wordnumber++;
    } else { // このほかに誤った単語はなし。次の単語ボタンを無効化 // Check ボタンを有効化 btNextWrongWord.setEnabled(false); btCheck.setEnabled(true); } } };
    // ActionListener を登録 btNextWrongWord.addActionListener(nextWord);
    } else { // テキストに誤りはない // Check ボタンを有効化 tfWrongWords.setText("No wrong words"); tfSuggestions1.setText("No suggestions"); tfWrongWord1.setText("--"); btCheck.setEnabled(true); } } catch (Exception ex) { ex.printStackTrace(); }
    // 進捗バーを消去 pbProgress.setIndeterminate(false); pbProgress.setString(""); } }); } }; java.util.concurrent.Future result = port.checkTextBodyV2Async(bodyText, asyncHandler); while (!result.isDone()) { try {
    //アプリケーションがサーバーからの応答を待機していることを示すメッセージを表示 tfWrongWords.setText("Waiting..."); Thread.sleep(100); } catch (InterruptedException ex) { Logger.getLogger(MainForm.class.getName()).log(Level.SEVERE, null, ex); } } }
  8. Ctrl-Shift-I (Mac の場合は ⌘-Shift-I) を押してインポートを修正します。次のインポート文が追加されます。
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.List;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.swing.SwingUtilities;

これで、アプリケーションを構築し、実行できます。このサービスは処理が非常に早いため、サーバーからの応答に大幅な遅延が起こったときにどうなるか、残念ながら確認できません。

応用

これで、はじめての Web サービスクライアントを IDE で完成しました。さらにスキルを伸ばし、目的に合うアプリケーションになるよう改良してみましょう。次に着手できそうなタスクを 2 つ提案します。

  • サーブレットにエラー処理のコードを追加する。
  • Web サービスから返されたデータとユーザーが対話できるように、クライアントのコードを書き直す。


関連項目

NetBeans IDE を使用した Java EE アプリケーションの開発方法についての詳細は、次のリソースを参照してください。

メーリングリストに登録することによって、NetBeans IDE Java EE 開発機能に関するご意見やご提案を送信したり、サポートを受けたり、最新の開発情報を入手したりできます。