スタブベースのWebサービスクライアントを実行する場合,WSDLのパスまたはURLが必要になります。このとき,次の条件の組み合わせによって,参照されるWSDLが異なります。
- javax.xml.ws.WebServiceRefアノテーションを利用してインジェクションする場合
インジェクションする場合に参照されるWSDLについては,「19.3.1(2) wsdlLocation要素(javax.xml.ws.WebServiceRef)」を参照してください。
- サービスクラスのコンストラクタを利用してインスタンスを生成する場合
参照されるWSDLは次に示す条件の組み合わせによって異なります。
- 利用するコンストラクタの種類
- cjwsimportコマンドに-wsdllocationオプションを指定して実行したかどうか
条件ごとの参照されるWSDLの対応を次の表に示します。なお,それぞれの条件での例については,「3.6.1(5)(a) サービスクラスをインスタンス化する」を参照してください。
表3-5 条件の組み合わせと参照されるWSDLの対応
項番 | 利用するコンストラクタ | -wsdllocation オプション | 参照されるWSDL |
---|
1 | デフォルトコンストラクタ | × | cjwsimportコマンドの引数に指定したWSDL※1 |
2 | デフォルトコンストラクタ | ○ | -wsdllocationオプションに指定したWSDL※2 |
3 | java.net.URL オブジェクトおよびjavax.xml.namespace.QNameオブジェクトをパラメタに持つコンストラクタ | - | パラメタのURLに指定したWSDL※2 |
- (凡例)
- ○:指定した場合。
- ×:指定しなかった場合。
- -:指定の有無は参照されるWSDLに影響しません。
- 注※1
- Webサービスクライアントを実行する場合,WSDLはcjwsimportコマンド実行時と同じ場所に存在している必要があります。cjwsimportコマンド実行時に相対パスを指定した場合も,WSDLはcjwsimportコマンド実行時と同じ場所に存在している必要があります。
- 注※2
- 絶対URLを指定した場合,Webサービスクライアントの実行時に,WSDLがそのURLが示す場所に存在している必要があります。
- 相対URLを指定した場合,Webサービスクライアントの実行時に,WSDLがカレントディレクトリを基準として相対URLを解決した場所に存在している必要があります。
Webサービスクライアントの実装には,コンストラクタを利用してサービスクラスを生成する方法と,インジェクションを利用する方法があります。ここでは,コンストラクタを利用してサービスクラスを生成する実装の手順を説明します。インジェクションについては,「10.21.1 サービスクラスおよびポートのインジェクション」を参照してください。
スタブベースのWebサービスクライアントを開発する場合,cjwsimportコマンドを使用してWebサービスを呼び出すために必要なJavaソースを生成します。cjwsimportコマンドは,-generateServiceオプションを指定しないで実行してください。
スタブベースのWebサービスクライアントは,次のJavaソースを使用してWebサービスを呼び出します。
- サービスクラス
サービスクラスは,JAX-WS 2.2仕様で規定されたWebサービスを呼び出すためのWSDLのサービス(wsdl:service要素)に対応するクラスです。wsdl:service要素がwsdl:port要素をまとめるように,複数のポートをまとめています。
Webサービスクライアントを実装する場合は,はじめにサービスクラスのインスタンスを生成します。
- ポート
WSDLのポート(wsdl:port要素)に対応するインスタンスで,インタフェースはサービスエンドポイントインタフェース(SEI)です。リモートにある接続先Webサービスのプロキシのように動作するため,Webサービスクライアントがこのポートのメソッドを呼び出すことで,Webサービスのオペレーションを透過的に呼び出せます。
Webサービスクライアントの実装でWebサービスのオペレーションを呼び出す手順は,次のとおりです。
- サービスクラスをインスタンス化する
- ポートを取得する
- ポートのメソッドを呼び出す
ここでは,「5.1 開発例の構成(SEI起点)」に構成を示すWebサービス(足し算をするWebサービス)を呼び出すWebサービスクライアントの実装例を示します。
Webサービスクライアントの実装に使用するクラスおよびメソッドを次の表に示します。必要に応じて,「5.5.1 サービスクラスを生成する」に記載されたサービスクラスの生成物の内容を参照してください。
表3-6 Webサービスクライアントの実装例で使用するクラスおよびメソッド
項番 | 種別 | クラスおよびメソッド |
---|
1 | サービスクラス | AddNumbersImplService |
2 | SEI | AddNumbersImpl |
3 | SEIのメソッド | int add(int, int) |
4 | クライアントのメインクラス | TestClient |
(a) サービスクラスをインスタンス化する
デフォルトのコンストラクタを使用してサービスクラスのオブジェクトを生成する例を次に示します。
// サービスクラスをインスタンス化する
AddNumbersImplService service = new AddNumbersImplService(); |
この場合,cjwsimportコマンドの引数または-wsdllocationオプションに指定したWSDLが参照されます。
cjwsimportコマンドの実行時に-wsdllocationオプションを指定しなかった場合の三つの例を次に示します。
- 実行例1
> "%COSMINEXUS_HOME%¥jaxws¥bin¥cjwsimport.bat" D:¥dev¥development.wsdl |
- D:¥dev¥development.wsdlは,Webサービスクライアント実行時にも存在し,参照できる状態である必要があります。
- 実行例2
> D:
> cd D:¥dev¥
> "%COSMINEXUS_HOME%¥jaxws¥bin¥cjwsimport.bat" relative¥development.wsdl |
- D:¥dev¥relative¥development.wsdlは,Webサービスクライアント実行時にも存在し,参照できる状態である必要があります。
- 実行例3
> "%COSMINEXUS_HOME%¥jaxws¥bin¥cjwsimport.bat" http://sample.com/fromjava/AddNumbersImplService?wsdl |
- http://sample.com/fromjava/AddNumbersImplService?wsdlは,Webサービスクライアント実行時にも存在し,参照できる状態である必要があります。
cjwsimportコマンドの実行時に-wsdllocationオプションを指定した場合の二つの例を次に示します。
- 実行例1
> "%COSMINEXUS_HOME%¥jaxws¥bin¥cjwsimport.bat" -wsdllocation file:/home/wsdl4runtime/master.wsdl D:¥dev¥development.wsdl |
- file:/home/wsdl4runtime/master.wsdlは,Webサービスクライアント実行時にも存在し,参照できる状態である必要があります。D:¥dev¥development.wsdlは,Webサービスクライアント開発時に実装に必要なJavaコードの生成に使用されるだけです。そのため,D:¥dev¥development.wsdlは実行時には存在しない,または参照できない状態でも問題ありません。
- 実行例2
> "%COSMINEXUS_HOME%¥jaxws¥bin¥cjwsimport.bat" -wsdllocation ./wsdl4runtime/master.wsdl D:¥dev¥development.wsdl |
- Webサービスクライアント実行時のカレントディレクトリを<実行時カレントディレクトリ>とした場合,<実行時カレントディレクトリ>/wsdl4runtime/master.wsdlが存在し,参照できる状態である必要があります。
なお,デフォルトのコンストラクタではなく,java.net.URLオブジェクトおよびjavax.xml.namespace.QNameオブジェクトをパラメタに持つコンストラクタを使用する場合は,次の例のようになります。
// サービスクラスをインスタンス化する
java.net.URL wsdlLocation = new java.io.File( "./wsdl4runtime/master.wsdl" ).toURL();
javax.xml.namespace.QName serviceName =
new javax.xml.namespace.QName( "http:/sample.com/", "AddNumbersImplService");
AddNumbersImplService service =
new AddNumbersImplService( wsdlLocation, serviceName ); |
java.net.URLオブジェクトで指定したURLのWSDLが参照されるため,cjwsimportコマンドの引数や-wsdllocationオプションで指定したWSDLは,Webサービスクライアント実行時には存在しない,または参照できない状態でも問題ありません。ただし,Webサービスクライアント実行時のカレントディレクトリを<実行時カレントディレクトリ>とした場合は,<実行時カレントディレクトリ>/wsdl4runtime/master.wsdlが存在し,参照できる状態である必要があります。
(b) ポートを取得する
インスタンス化したサービスクラスからポートを取得する例を次に示します。
// ポートを取得する
AddNumbersImpl port = service.getAddNumbersImplPort(); |
(c) ポートのメソッドを呼び出す
インスタンス化したサービスクラスから取得したポートのメソッドを呼び出す例を次に示します。
// ポートのメソッドを呼び出す
int returnValue = port.add(205, 103) |
この例では,ポートのメソッドの引数に二つの値を渡すと,Webサービスで足し算の処理が行われます。戻り値として足し算の演算結果が返されます。
接続するWebサービスのURL(エンドポイントアドレス)は,デフォルトでは,WSDLのポート(wsdl:port要素)が持つアドレス情報(soap:address子要素のlocation属性)が利用されます。ただし,メッセージコンテキストのjavax.xml.ws.service.endpoint.addressプロパティを利用すると,エンドポイントアドレスを動的に変更できます。
エンドポイントアドレスを動的に変更しない場合,参照されるWSDLのsoap:address子要素のlocation属性に,WebサービスクライアントからアクセスできるURLが記述されているかどうか確認してください。
エンドポイントアドレスを動的に変更する場合,ポートのメソッドを呼び出す前に要求コンテキストを取得し,javax.xml.ws.service.endpoint.addressプロパティの値を変更します。例を次に示します。
// 要求コンテキストを取得する
java.util.Map<String, Object> context =
( ( javax.xml.ws.BindingProvider )port ).getRequestContext();
// エンドポイントアドレスを変更する
// (javax.xml.ws.BindingProvider.ENDPOINT_ADDRESS_PROPERTYは
// "javax.xml.ws.service.endpoint.address"を定義した定数)
context.put( javax.xml.ws.BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://other.remote.org/fromjava/AddNumbersImplService" );
// ポートのメソッドを呼び出す
int returnValue = port.add(205, 103) |
- 注意事項
- サービスクラスの生成やポートの取得には処理コストが掛かるので,一度生成,取得したサービスクラスとポートは再利用することをお勧めします。ポートのWebメソッドを複数回呼び出す場合に,サービスクラスを複数回生成したり,ポートを複数回取得したりする必要はありません。ただし,複数スレッドでポートを共有する場合,共有するポートの要求コンテキストのプロパティに対する変更は,複数スレッドが動作する前に実行してください。複数スレッドの動作中に変更すると,通信が失敗したり,不正なSOAPメッセージが送信されたりすることがあります。
- ポートのメソッドを複数回呼び出す例を次に示します。
// サービスクラスをインスタンス化する
AddNumbersImplService service = new AddNumbersImplService();
// ポートを取得する
AddNumbersImpl port = service.getAddNumbersImplPort();
// ポートのメソッドを複数回呼び出す
for (int i = 0; i < 10; i++) {
int returnValue = port.add(i, i);
} |
JavaアプリケーションのWebサービスクライアントから,サービスクラスを使用してWebサービスを呼び出す処理を実装します。
ここでは,「5.1 開発例の構成(SEI起点)」に構成を示すWebサービス(足し算をするWebサービス)を呼び出すWebサービスクライアントの実装例を示します。Webサービスクライアントの実装に使用するクラスおよびメソッドを次の表に示します。必要に応じて,「5.5.1 サービスクラスを生成する」に記載されたサービスクラスの生成物の内容を参照してください。
表3-7 Webサービスクライアントの実装例で使用するクラスおよびメソッド(JavaアプリケーションのWebサービスクライアントの場合)
項番 | 種別 | クラスおよびメソッド |
---|
1 | サービスクラス | AddNumbersImplService |
2 | ポート | AddNumbersImpl |
3 | ポートのメソッド | int add(int, int) |
4 | Webサービスクライアントのクライアントのメインクラス | TestClient |
Javaアプリケーションの実装例を次に示します。
package com.example.sample.client;
import com.example.sample.AddNumbersImplTestJaxWs;
import com.example.sample.AddNumbersImplTestJaxWsService;
import com.sample.AddNumbersFault_Exception;
// Sample implementation of web service's client
public class TestClient {
public static void main( String[] args ) {
try {
// サービスクラスをインスタンス化する
AddNumbersImplTestJaxWsService service = new AddNumbersImplTestJaxWsService();
// ポートを取得する
AddNumbersImplTestJaxWs port = service.getAddNumbersImplPortTestJaxWs();
// ポートのメソッドを呼び出す
port.jaxWsTest1( ... );
int number1 = 205;
int number2 = 103;
int returnValue = port.add(number1, number2);
// 結果を表示する
System.out.println( "[RESULT] " + number1 + " + " + number2 + " = " + returnValue );
}
catch( Exception e ){
// 例外処理(ここでは単にスタックトレースを出力)
e.printStackTrace();
}
}
} |
プログラムの実行結果を次に示します。
サーブレット形態のWebサービスクライアントから,サービスクラスを使用してWebサービスを呼び出す処理を実装します。
ここでは,「5.1 開発例の構成(SEI起点)」に構成を示すWebサービス(足し算をするWebサービス)を呼び出すWebサービスクライアントの実装例を示します。Webサービスクライアントの実装に使用するクラスおよびメソッドを次の表に示します。必要に応じて,「5.5.1 サービスクラスを生成する」に記載されたサービスクラスの生成物の内容を参照してください。
表3-8 Webサービスクライアントの実装例で使用するクラスおよびメソッド(サーブレットから呼び出す場合)
項番 | 種別 | クラスおよびメソッド |
---|
1 | サービスクラス | AddNumbersImplService |
2 | ポート | AddNumbersImpl |
3 | ポートのメソッド | int add(int, int) |
4 | Webサービスクライアントとなるサーブレット実装クラス | TestClient |
(a) ポートのインジェクション
サーブレットからWebサービスを呼び出す実装では,ポート型のフィールドにjavax.xml.ws.WebServiceRefアノテーションを指定して,サーブレットインスタンスの生成時にポートのインジェクションを実行します。
インジェクションの例を次に示します。
...
public class TestClient extends HttpServlet {
// ポート(AddNumbersImpl)型のフィールドに,ポートをインジェクトする
@WebServiceRef(AddNumbersImplService.class)
AddNumbersImpl port;
@Override
public void init() {
}
...
} |
(b) ポートのメソッド呼び出しによるWebサービスのオペレーション実行
サーブレットのフィールドとして生成したポートを使って,メソッドを呼び出します。
メソッド呼び出しの例を次に示します。
...
public class TestClient extends HttpServlet {
// ポート(AddNumbersImpl)型のフィールドに,ポートをインジェクトする
@WebServiceRef(AddNumbersImplService.class)
AddNumbersImpl port;
...
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
...
int number1 = ...; // requestオブジェクトから取得した値を代入
int number2 = ...; // requestオブジェクトから取得した値を代入
// ポートのメソッドを呼び出す
int returnValue = port.add(number1, number2);
...
}
} |
サーブレットからWebサービスを呼び出す場合の実装例の全体を次に示します。
package com.sample.client;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sample.AddNumbersFault_Exception;
import com.sample.AddNumbersImpl;
import com.sample.AddNumbersImplService;
public class TestClient extends HttpServlet {
// ポート(AddNumbersImpl)型のフィールドに,ポートをインジェクトする
@WebServiceRef(AddNumbersImplService.class)
AddNumbersImpl port;
@Override
public void init() {
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
try {
// Invoke a method of the target web service.
int number1 = ...; // requestオブジェクトから取得した値を代入
int number2 = ...; // requestオブジェクトから取得した値を代入
// ポートのメソッドを呼び出す
int returnValue = port.add(number1, number2);
// 結果を表示する
out.println("<html><body>");
out.println("<h1>RESULT</h1>");
out.println(number1 + " + " + number2 + " = " + returnValue);
out.println("</body></html>");
} catch(AddNumbersFault_Exception e) {
// 例外処理(ここでは単に例外の詳細メッセージを出力)
out.println("<html><body>");
out.println("<h1>" + e.getMessage() + "</h1>");
out.println("</body></html>");
}
}
} |
プログラムの実行結果を次に示します。ブラウザなどからサーブレットに接続すると実行結果が表示されます。
(c) 注意事項
Webサービスクライアント(サーブレット)と接続先のWebサービスが,同じJ2EEサーバ上にデプロイされている環境では,次の場合,J2EEサーバの起動時に例外が発生します。
- initメソッドまたはjavax.annotation.PostConstructアノテーションを指定したメソッドの中で,WebサービスからWSDLを取得してサービスクラスを生成するときに,Webサービスクライアントが含まれるWARファイルのweb.xmlにload-on-startup要素を指定した場合
- javax.xml.ws.WebServiceRefアノテーションを利用して,WebサービスからWSDLを取得してサービスクラスやポートをインジェクトする場合
例外が発生する場合の対策方法を次に示します。
- J2EEサーバを停止する前に,Webサービスクライアントが含まれるWebアプリケーションを停止してください。J2EEサーバを再起動したあとに,Webサービスクライアントが含まれるWebアプリケーションを開始してください。
- WebサービスとWebサービスクライアントを別のJ2EEサーバにデプロイして,WebサービスをデプロイしたJ2EEサーバを起動したあとにWebサービスクライアントをデプロイしたJ2EEサーバを起動してください。
- カタログ機能を使用して,サービスクラスの生成時にローカルに格納したWSDL文書を参照するように設定してください。
- initメソッドまたはjavax.annotation.PostConstructアノテーションを指定したメソッドで,サービスクラスを生成する場合は,URLをパラメタに取るコンストラクタにローカルのWSDL文書を指定してサービスクラスを生成してください。または,web.xmlにload-on-startup要素を指定しないでください。
- javax.xml.ws.WebServiceRefアノテーションを利用する場合は,wsdlLocation要素に相対パスまたは絶対パスで,ローカルに格納したWSDL文書を指定してください。