1.2.6. Webサービスクライアントの作成

ここでは、作成した Web サービスを呼び出す Web サービスクライアントを作成する方法について説明します。

1.2.6.1. JAX-WS準拠のクライアント生成(ウィザード)

Webサービス参照ウィザードを使うと、JAX-WS 準拠の Web サービスクライアントを作成することができます。

Webサービス参照ウィザードの初期設定

1.2.2. Webサービスの作成 の 「Webサービス作成ウィザードを使用する前に」をご覧ください。

Web サービス参照ウィザードの起動

Web サービス参照ウィザードの起動方法は二つあります。

新規ダイアログ

WebOTX Developer (with Developer's Studio) のメニューから ファイル > 新規 > その他 を選択すると、 新規ダイアログが起動します。

Web サービス参照ウィザードを開始するには、 Web サービス > Web サービス参照 を選択し、次へをクリックします。


図1.2.6.1-1

ポップアップメニュー

プロジェクトを選択し、WebOTX Developer (with Developer's Studio) の右クリックメニューから Web サービス > Web サービス参照 を選択すると、 Web サービス参照 ダイアログが起動します。


図1.2.6.1-2

Web サービス参照ウィザード

Web サービス参照ウィザードを使用して、JAX-WS 準拠の Web サービスクライアントを作成する方法を説明します。以下の図は、作成するアプリケーションの概要図です。 アプリケーションは、自動生成されるクライアントコードを用いて Web サービスと通信します。 クライアントコードを利用する呼び出しコードも自動生成することができます。 外部環境プロパティを利用して、WSDL の参照先を切り替えることにより、利用する Web サービスを 例えば本番環境とテスト環境で、切り替えることもできます。


図1.2.6.1-3

Web サービス参照ウィザードを使用して、Web サービス参照をプロジェクトに追加すると、 以下のことができるようになります。

以下では、1.1.1. SOAP Webサービスの作成 で作成した Web サービスを呼び出す例を用いて、説明を行います。


図1.2.6.1-4

Web サービス参照ウィザードを下記の説明を参考に設定します。

表1.2.6.1-1 1.2.6.1-1
項目 説明
ソース・フォルダー クライアントコードを生成するプロジェクトとソース・フォルダーを指定します
WSDL の URL を指定して作成 利用する Web サービスの WSDL の URL を指定します。file:// プロトコルも指定できます。
ワークスペース内の WSDL から作成 利用する Web サービスの WSDL がワークスペース内にある場合にはこちらで指定します。
生成するクライアントのパッケージを指定 「WSDLから作成」にチェックをした場合は、Web サービスのネームスペースからパッケージ名を作成します。 「生成するクライアントのパッケージを指定」にチェックした場合には、任意のパッケージ名を指定できます。
非同期呼び出しを行う クライアントコードを非同期呼び出し対応にする場合にはチェックします。 詳細は、呼び出しコードの生成 で説明します。
WSDL のロケーションを外部環境プロパティに設定する WSDL のロケーションを外部環境プロパティに設定し、切り替え可能にする場合にはチェックします。 指定したソース・フォルダーに外部環境プロパティが設定されており、なおかつ、 ウィザードの他の項目が正しく設定されている場合にチェック可能になります。 外部環境プロパティは、アプリケーション開発ガイド(共通)9. 外部環境プロパティ のマニュアルを 参照してください。。 詳細は、外部環境プロパティの利用 で説明します。

設定が完了したら、完了 ボタンをクリックします。

処理が完了すると、プロジェクトは以下の構成になります。


図1.2.6.1-5

sample.hello パッケージが生成されたクライアントコードです (1)。 Web サービス参照ノード は、設定した Web サービスがサービス名、WSDL、サービス、ポート、オペレーション、 呼び出し方式の順にツリーが生成されます (2)。 references ディレクトリは、読み込んだ WSDL や XSD がコピーされます (3)。

Memo

すでに Web サービス参照が登録されている場合で、新規作成しようとしている Web サービス参照が 以下の条件を満たす場合は、同一 Web サービスとしてみなし、新規作成ではなく更新処理になります。

Memo
Web サービス参照 は SOAP 1.1 のみに対応しています。 SOAP 1.2 には対応していませんので、ご注意ください。

Caution
WSDLのURLにlocalhostを指定した場合、特定の環境では、プロキシー除外設定がうまくいかず、 wsimportコマンドの実行に失敗した旨のエラーが表示されることがあります。 この場合は、localhostではなく、作業マシンのIPアドレスを指定してください。

呼び出しコードの生成

Web サービスの呼び出しコードを生成する方法について説明します。 Web サービスの呼び出しコードを生成するには、プロジェクト・エクスプローラーの Web サービス参照 ノードを利用します。

Memo
Web サービス参照 ノードは プロジェクト・エクスプローラー でのみ表示されます。 Java EE パースペクティブに切り替えて、プロジェクト・エクスプローラーを表示してお使いください。

呼び出したいオペレーションの下の 同期呼び出しノード、 非同期呼び出し(コールバック)ノード、 非同期呼び出し(ポーリング)ノードのいずれかを、 エディタの呼び出しコードを挿入したい場所にドラッグ&ドロップします。


図1.2.6.1-6

ドラッグ&ドロップが完了すると、そのオペレーションを指定した方式で呼び出すのに必要なコードが生成されます。

同期呼び出しの場合:

package main;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
try { // web service reference for HelloService();
	sample.hello.HelloService port = service.getHelloServicePort();
	// TODO initialize arguments
	java.lang.String arg0 = "";
	java.lang.String result = port.sayHello(arg0);
	// TODO process result
	System.out.println(result);
} catch (Exception e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
} // web service reference for HelloService

	}

}

非同期呼び出し(ポーリング)の場合:

package main;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
try { // web service reference for HelloService
	final int WAIT_TIME = 500;
	sample.hello.HelloService_Service service = new sample.hello.HelloService_Service(
			webotx.ds.ExternalEnvironment.getURL("HelloService"),
			webotx.ds.ExternalEnvironment.getService("HelloService"));
	sample.hello.HelloService port = service.getHelloServicePort();
	// TODO initialize arguments
	java.lang.String arg0 = "";
	javax.xml.ws.Response<sample.hello.SayHelloResponse> res = port
			.sayHelloAsync(arg0);
	while (!res.isDone()) {
		Thread.sleep(WAIT_TIME);
	}
	// TODO process response
	System.out.println(res.get().getReturn());
} catch (Exception e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
} // web service reference for HelloService


	}


}

Caution
生成したコード[res.get()]の後に、に手動で[.getXXX()]を追加する必要があります。この例では、[.getReturn()]です。
追加前:
    System.out.println(res.get());
追加後:
    System.out.println(res.get().getReturn());

非同期呼び出し(コールバック)の場合:

package main;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
try { // web service reference for HelloService
	final int WAIT_TIME = 500;
	sample.hello.HelloService_Service service = new sample.hello.HelloService_Service(
			webotx.ds.ExternalEnvironment.getURL("HelloService"),
			webotx.ds.ExternalEnvironment.getService("HelloService"));
	sample.hello.HelloService port = service.getHelloServicePort();
	// TODO initialize arguments
	java.lang.String arg0 = "";
	javax.xml.ws.AsyncHandler<sample.hello.SayHelloResponse> handler = new javax.xml.ws.AsyncHandler<sample.hello.SayHelloResponse>() {
		public void handleResponse(
				javax.xml.ws.Response<sample.hello.SayHelloResponse> res) {
			try {
				// TODO process result
				System.out.println(res.get().getReturn());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	};
	java.util.concurrent.Future<?> result = port.sayHelloAsync(arg0,
			handler);

	while (!result.isDone()) {
		Thread.sleep(WAIT_TIME);
	}
} catch (Exception e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
} // web service reference for HelloService
	}

}

Caution
生成したコード[res.get()]の後に、に手動で[.getXXX()]を追加する必要があります。この例では、[.getReturn()]です。
追加前:
    System.out.println(res.get());
追加後:
    System.out.println(res.get().getReturn());

生成された呼び出しコードのインデントを整えたい場合には、整形したい部分を選択して、 Ctrl + Shift + F を押してください。

生成された呼び出しコードは、引数の部分が設定されていないため、引数を設定します。 下記の例では、同期呼び出しの呼び出しコード上の arg0Bob を設定しています。

package main;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try { // web service reference for HelloService();
			sample.hello.HelloService port = service.getHelloServicePort();
			// TODO initialize arguments
			java.lang.String arg0 = "Bob";
			java.lang.String result = port.sayHello(arg0);
			// TODO process result
			System.out.println(result);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} // web service reference for HelloService

	}

}

ここまで設定を行った後で、main.Main クラスを実行すると Web サービスの呼び出しが行われます。


図1.2.6.1-7

非同期呼び出し

Web サービス参照ウィザードでは、以下の3つの呼び出し方式をサポートしています。

ここでは、それぞれの呼び出し方式について説明します。

同期呼び出し

Web サービスの呼び出しを同期的に行います。Web サービスの呼び出しが完了するまで待つため、 他の処理ができませんが、記述がシンプルになります。

非同期呼び出し(コールバック)

Web サービスの呼び出しを非同期的に行います。Web サービスの呼び出しの完了を待たずに 処理を続けることができます。Web サービスの呼び出しの完了は、作成したスレッドの上のイベントハンドラが受け取ります。 記述は複雑になりますが、非同期呼び出し(ポーリング)のようにサーバに Web サービスの呼び出しの完了確認を定期的に 行う処理の記述をする必要がありません。

非同期呼び出し(ポーリング)

Web サービスの呼び出しを非同期的に行います。Web サービスの呼び出しの完了を待たずに 処理を続けることができます。Web サービスの呼び出しの完了を確認するために、定期的にサーバに問い合わせを行います。 問い合わせ間隔が長くなれば、それだけWeb サービスの呼び出しの完了のタイミングが遅くなりますが、 任意のタイミングで Web サービスの呼び出し結果を取得することができます。

外部環境プロパティの利用

外部環境プロパティを利用して、WSDL のロケーションを変更する方法について説明します。 この機能は、例えば、参照する WSDL の内容が同じで、デプロイ先がテスト環境から本番環境に切り替わった場合に、 Web サービス参照を作り直すことなく、設定を切り替えるだけで対応を可能にすることができます。

Web サービス参照ウィザードで WSDL のロケーションを外部環境プロパティに設定する が有効だった場合、 WSDL のロケーションは外部環境プロパティに設定されます。 下記の例では、ExternalEnvironment.javaotx-env.properties が外部環境プロパティに関するファイルです。 外部環境プロパティが設定されたソース・フォルダーに Web サービス参照を設定した場合、 外部環境プロパティに関するファイルは 上書きされ、Web サービス参照に対応したファイルに変更されます。


図1.2.6.1-8

Web サービスの呼び出しコードを生成すると、以下のようなコードが挿入されます。

同期呼び出しの場合:

package main;

public class Main {

  /**
   * @param args
   */
  public static void main(String[] args) {

    try { // web service reference for HelloService
      sample.hello.HelloService_Service service = new sample.hello.HelloService_Service(
        webotx.ds.ExternalEnvironment.getURL("HelloService"),
        webotx.ds.ExternalEnvironment.getService("HelloService"));
      sample.hello.HelloService port = service.getHelloServicePort();
      // TODO initialize arguments
      java.lang.String arg0 = "";
      java.lang.String result = port.sayHello(arg0);
      // TODO process result
      System.out.println(result);
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } // web service reference for HelloService
  }
}

WSDL のロケーションを変更する場合には、プロジェクトの右クリックメニューから 構成 > 外部環境プロパティの設定 をクリックし、 該当するプロパティの値を変更します。


図1.2.6.1-9

この例では、開発中に切り替えていますが、パッケージを作って後の運用時に外部環境プロパティを変更することもできます。 詳細については、[ アプリケーション開発ガイド(共通) > 9. 外部環境プロパティ ] を参照してください。

Web サービス参照の追加

Web サービス参照の追加機能について説明します。プロジェクト・エクスプローラーの Web サービス参照 ノードの右クリックメニューから Web サービス参照の追加 をクリックすると、Web サービス参照ウィザードが表示されます。 機能は、メニューや、プロジェクトの右クリックメニューから呼び出した場合と違いはありません。


図1.2.6.1-10

Web サービス参照の全削除

Web サービス参照の全削除機能について説明します。プロジェクト・エクスプローラーの Web サービス参照 ノードの右クリックメニューから Web サービス参照の全削除 をクリックすると、確認ダイアログが表示されます。


図1.2.6.1-11


図1.2.6.1-12

はい をクリックした場合には、Web サービス参照に関するファイルである以下のファイルが削除されます。

いいえ をクリックした場合には、キャンセルされます。

Web サービス参照の更新

Web サービス参照の更新機能について説明します。プロジェクト・エクスプローラーの サービス名 ノードの右クリックメニューから Web サービス参照の更新 をクリックすると、確認ダイアログが表示されます。


図1.2.6.1-13


図1.2.6.1-14

はい をクリックした場合には、Web サービス参照に関するファイルである以下のファイルが更新されます。

ドラッグ&ドロップで生成されたサービスの呼び出しコードは更新されませんので、手動で更新してください。

いいえ をクリックした場合には、キャンセルされます。

Web サービス参照の削除

Web サービス参照の削除機能について説明します。プロジェクト・エクスプローラーの サービス名 ノードの右クリックメニューから Web サービス参照の削除 をクリックすると、確認ダイアログが表示されます。


図1.2.6.1-15


図1.2.6.1-16

はい をクリックした場合には、Web サービス参照に関するファイルである以下のファイルが削除されます。

ドラッグ&ドロップで生成されたサービスの呼び出しコードは削除されませんので、手動で削除してください。

いいえ をクリックした場合には、キャンセルされます。

1.2.6.2. JAX-WS準拠のクライアント作成(コマンド)

クライアントアプリケーションは、プロキシ(サービスエンドポイントインタフェースを実装したスタブ)、もしくはDispatchを利用してリモートのWebサービスエンドポイントにアクセスすることができます。ここでは、プロキシを使用したアプリケーションを説明します。
環境設定
環境変数JAVA_HOMEに、JDKインストールディレクトリを指定してください。また、javacコマンドやaptコマンドがコマンド検索パスに加わるよう、環境変数PATHに<JAVA_HOME>/binを追加してください。
また、JAX-WSアプリケーションを作成する場合は次のライブラリをクラスパスに含めてください。
※ tools.jarはビルド時のみ必要です。
また、JAX-WSクライアントを実行する際には、次のJava VMオプションを指定してください。
-Djava.endorsed.dirs=<WebOTX_DIR>/lib/endorsed

Memo
<WebOTX_DIR>はWebOTXのインストールディレクトリに読み替えてください。

プロキシを使用したクライアント
サーバアプリケーションの開発で作成したサンプルのクライアントアプリケーションを作成するためのファイル構成は、以下の通りです。サーバアプリケーションを開発したディレクトリ以外の任意のディレクトリに、次のファイルを作成してください。ファイルの内容については、以下で説明します。
表1.2.6.2-1
ディレクトリ ファイル
src/sample HelloClient.java
クライアントアプリケーションを開発する手順は次のようになります。
1. プロキシの生成
wsimportコマンドを使用してサービスエンドポイントインタフェースのプロキシやサービスエンドポイントインタフェースのリファレンスを取得するためのサービスクラス、Request/Response Beanなどを生成します。
あらかじめ、3のサーバアプリケーション開発で説明したhellowsサンプルをWebOTXに配備したのち、srcディレクトリにて以下のコマンドを実行してください。なお、以下のコマンドを実行する前に、あらかじめ出力ディレクトリclassesを作成しておいてください。
src> wsimport -d ../classes -s . -keep http://localhost/hellows/hello?wsdl
wsimportコマンドの詳細に関しては、 [ 1.2.12. コマンドリファレンス > 1.2.12.1. wsimport ] を参照してください。
これにより、次のファイルが生成されます。(Webサービスエンドポイント実装クラスからサーバアプリケーションを作成した場合)
表1.2.6.2-2
ディレクトリ ファイル
src/sample/ Hello.java Hello_Service.java SayHello.java SayHelloResponse.java ObjectFactory.java package-info.java
classes/sample/ Hello.class Hello_Service.class SayHello.class SayHelloResponse.class ObjectFactory.class package-info.class
2. クライアントアプリケーションの作成
プロキシを使用したクライアントアプリケーションは次のようになります。
HelloClient.java
package sample;

public class HelloClient {
  public static void main(String[] args) {
    Hello_Service service = new Hello_Service();
    Hello port = service.getHelloPort();
    HelloClient client = new HelloClient();
    client.hello(port);
  }

  private void hello(Hello port){
    try {
      System.out.println(port.sayHello("WebOTX"));
    } catch( java.lang.Exception e) {
      e.printStackTrace();
    }
  }
}
上記コードのように、サービスクラスのgetHelloPort()メソッドで、プロキシ(スタブ)を取得することができます。
以上の作業が終了したら、クライアントクラスをコンパイルします。
src> javac -d ../classes sample/HelloClient.java
最後に、クライアントクラスを実行します。classesディレクトリで実行してください。
classes> java sample.HelloClient
正常に実行が完了すれば、次のような結果が出力されます。
Hello WebOTX!
Dispatchを使用したクライアント
Dispatchは動的なWebサービス呼び出しのインタフェースとして利用できます。Dispatchを使用したクライアントアプリケーションを、以下の3つの方法に分けて説明します。
・javax.xml.transform.Sourceを使用する方法
・javax.xml.bind.JAXBContextを使用する方法
・javax.xml.soap.SOAPMessageを使用する方法
以下の例でDispatchオブジェクトを生成している、createDispatchメソッドの第3パラメタで指定するService.Modeには以下を指定します。
表1.2.6.2-3
Service.Modeの値 説明
MESSAGE SOAPメッセージ全体を扱います。SourceおよびSOAPMessageを利用する場合に指定できます。
PAYLOAD SOAPメッセージの本体のみを扱います。SourceおよびJAXBを利用する場合に指定できます。
・javax.xml.transform.Sourceを使用する方法
メッセージをStreamやDOM/SAXで扱う方法です。
HelloClientSource.java
package sample;

import java.io.StringReader;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.Source;

public class HelloClientSource {
public static void main(String[] args) { Service service = new Hello_Service(); QName portQName = new QName("http://sample","HelloPort"); String request = "<ns1:sayHello xmlns:ns1=\"http://sample\">" +"<arg0>WebOTX</arg0></ns1:sayHello>"; try { Dispatch<Source> sourceDispatch = service.createDispatch( portQName,Source.class, Service.Mode.PAYLOAD); Source result = sourceDispatch.invoke( new StreamSource(new StringReader(request))); } catch (Exception e) { e.printStackTrace(); } } }
・javax.xml.bind.JAXBContextを使用する方法
JAXBを利用して、メッセージをシリアライズ/デシリアライズする方法です。
HelloClientJAXBContext.java
package sample;

import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.namespace.QName;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;

public class HelloClientJAXBContext {
  public static void main(String[] args) {
    Service service = new Hello_Service();
    QName portQName = new QName("http://sample","HelloPort");
    try {
      JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
      Dispatch jaxbDispatch = service.createDispatch(portQName,jaxbContext, Service.Mode.PAYLOAD);
      ObjectFactory factory = new ObjectFactory();
      SayHello msg = new SayHello();
      msg.setArg0("WebOTX");
      JAXBElement<SayHello> sayHello = factory.createSayHello(msg);
      JAXBElement<SayHelloResponse> response = (JAXBElement<SayHelloResponse>) jaxbDispatch.invoke(sayHello);
      SayHelloResponse result = response.getValue();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
・javax.xml.soap.SOAPMessageを使用する方法
メッセージをSAAJのSOAPMessageで扱う方法です。
HelloClientSOAPMessage.java
package sample;

import javax.xml.soap.*;
import java.io.StringReader;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.Source;

public class HelloClientSOAPMessage {
  public static void main(String[] args) {
    Service service = new Hello_Service();
    QName portQName = new QName("http://sample","HelloPort");
    String request = "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">" + "<S:Body><ns1:sayHello xmlns:ns1=\"http://sample\"><arg0>WebOTX</arg0>" + "</ns1:sayHello></S:Body></S:Envelope>";
    try {
      SOAPMessage message = null;
      MessageFactory factory = MessageFactory.newInstance();
      message = factory.createMessage();
      message.getSOAPPart().setContent( (Source) new StreamSource(new StringReader(request)));
      message.saveChanges();
      Dispatch<SOAPMessage> dispatch = service.createDispatch( portQName,SOAPMessage.class, Service.Mode.MESSAGE);
      SOAPMessage response = dispatch.invoke(message);
      Source result = response.getSOAPPart().getContent();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Fast Infoset の利用方法
Fast Infosetを利用するには、次のうちいずれかの方法で設定します。
(1)クライアントクラスにソースコードを追加する

[ソースコード例]
Service service = new Service(?);
ServiceEndpointInterface proxy = service.get?();
java.util.Map<String, Object> ctxt = ((javax.xml.ws.BindingProvider)proxy).getRequestContext();
ctxt.put(com.nec.webotx.webservice.xml.ws.developer.
JAXWSProperties.CONTENT_NEGOTIATION_PROPERTY, "***value***");
[ソースコードの説明]
「Service」というクラスはjavax.xml.ws.Serviceをextendsしたクラスです。実際にはwsimportコマンドやWebサービス作成ウィザードで生成されたクラスを使用します。「ServiceEndpointInterface」というクラスはサービスエンドポイントインタフェースです。実際にはwsimportコマンドやWebサービス作成ウィザードで生成されたインタフェースクラスを使用します。***value***には、下の表に示す三つのうちのいずれかの値を指定します。 (2)クライアント実行時にJava VMプロパティを追加する

[設定例]
java -Dcom.nec.webotx.webservice.xml.ws.client.ContentNegotiation=***value*** クライアントクラス
なお、「***value***」には次のうちいずれかの値を指定します。
表1.2.6.2-4
意味
none Fast Infoset を使用しない
pessimistic レスポンスメッセージのみFast Infoset を利用する
optimistic リクエストメッセージ・レスポンスメッセージの両方でFast Infoset を利用する

1.2.6.3. JAX-RPC準拠のクライアント作成(コマンド)

Memo
JAX-RPCは旧互換のための機能です。

スタティック(静的)スタブ方式
WSDLをコンパイルしてサービスエンドポイントインタフェースやスタブコードを生成し、それらを使ってクライアントを作成する方法です。この方法は、Webサービスのクライアントを作成する方法としては最も一般的なものです。ここでは、スタティックスタブ方式のクライアントを開発する方法を順に説明します。
環境変数の準備
次のJARファイルをクラスパスに追加してください。

Memo
<WebOTX_DIR>はWebOTXのインストールルートディレクトリ、<J2SE_DIR>はJ2SE SDKのインストールルートディレクトリのことです。

Javaプロジェクトの準備
WSDLファイルをプロジェクトのルートに置きます。
config.xmlファイルの作成
プロジェクトのルートに「config.xml」という名前でファイルを作成します。内容は、次のようにします。
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
  <wsdl location="Hello.wsdl" packageName="com.nec.webotx.webservice.sample"/>
</configuration>
wsdl要素にコンパイル対象のWSDLの情報を指定します。 location属性は、プロジェクトのルートに置いたWSDLのファイル名を指定します。 packageName属性は、WSDLコンパイラが生成するクラスが属するパッケージの名前を指定します。
wscompileコマンドの実行
メニューから、実行実行を選択し、実行ダイアログを開きます。[新規]ボタンを押して名前を指定し、新しい構成を作成します。「 メイン」タブで、「プロジェクト」に作成しておいたJavaプロジェクトの「メインクラス」に「com.nec.webotx.webservice.xml.rpc.tools.wscompile.Main」を指定します。「メイン・クラスの検索時にシステム・ライブラリーを組み込む」にチェックを入れ、「検索」ボタンを押すと、メインクラスとして選択可能なクラスの一覧が表示されますのでその中から選択してください。「引数」タブで、「プログラム引数」に「-gen:client -d src -keep config.xml」を指定します。以上の設定を確認し、[実行]ボタンを押します。プロジェクトの「src」フォルダ配下に、いくつかのソースコードが生成されます。

生成されたソースコードが表示されていない場合は、「src」フォルダについて「最新表示」を行ってください。
クライアントコードの作成
「static」サンプルのソースコードをベースにして、クライアントコードの作成方法を説明します。
public class HelloClient {
  private javax.xml.rpc.Stub stub; //スタブを定義しておきます。

  //wscompileコマンドが生成したクラスの中でjava.rmi.Remoteを継承したインタフェースが
  //サービスエンドポイントインタフェースです。Webサービスがクライアントに提供している
  //インタフェースを記述したものです。
  private Hello_PortType binding; //サービスエンドポイントインタフェースを定義しておきます。

  public HelloClient() throws Exception {
    //javax.xml.rpc.Serviceを継承したインタフェースは、クライアントが
    //Webサービスを仮想化するために使用するインタフェースです。
    //このインタフェースを実装したクラスからポートを取得し、
    //スタブにキャストしています。
    stub = (javax.xml.rpc.Stub) new Hello_Service_Impl().getHelloPort();

    //スタブをさらにサービスエンドポイントインタフェースでキャストします。
    //これでWebサービスを呼び出す準備は整いました。
    binding = (Hello_PortType)stub;
  }

  //引数でアクセス先のサービスエンドポイントのURLを変更する場合のコンストラクタです。
  public HelloClient(java.lang.String url) throws Exception {
    stub = (javax.xml.rpc.Stub) new Hello_Service_Impl().getHelloPort();
    //スタブのプロパティをセットしてURLを変更します。
    stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,url);
    binding = (Hello_PortType)stub;
  }

  //Webサービスを実行するメソッドです。
  public java.lang.String say_hello_Hello(java.lang.String in0) throws java.rmi.RemoteException {
    //実行したいオペレーションを呼び出します。
    return binding.say_hello_Hello(in0);
  }

  //クライアントを実行するmainメソッドです。
  public static void main(String[] args) throws Exception {
    HelloClient client;
    if(args.length > 0) {
      client =new HelloClient(args[0]);
    } else {
      client =new HelloClient();
    }
    //Webサービスを実行し、結果を表示します。
    System.out.println(client.say_hello_Hello("webotx"));
  }
}
クライアントの実行
メニューから、実行実行を選択し、実行ダイアログを開きます。[新規]ボタンを押して名前を指定し、新しい構成を作成します。「メイン」タブで、「プロジェクト」に作成しておいたJavaプロジェクトを、「メインクラス」に作成したクライアントのクラスを指定します。引数を指定したい場合は、「引数」タブで指定します。以上の設定を確認したら[実行]ボタンを押します。
配布について
クライアントをJAR形式にパッケージングする時は、作成したプロジェクトで右クリックし、エクスポートを選択します。エクスポートダイアログが起動したら、「JARファイル」を選択し、[次へ]ボタンを押します。エクスポートするリソースの選択では、「src」フォルダのみ選択し、エクスポート先を指定して[終了]ボタンを押します。

配布を行う時は、ここで作成したJARファイルとプロジェクトに追加していたライブラリ(tools.jarは除く)を配布するようにしてください。
Fast Infoset の利用方法
Fast Infosetを利用するには、次のうちいずれかの方法で設定します。

(1)Stubクラスのコンストラクタにソースコードを追加する
_setProperty(com.nec.webotx.webservice.xml.rpc.client.StubPropertyConstants.CONTENT_NEGOTIATION_PROPERTY, "***value***");
※クライアントで作成したStubインスタンスに対してこのメソッドを実行する方法もあります。

(2)クライアント実行時にJava VMプロパティを追加する

[設定例]

[foo@webotx ~]$ java -Dcom.nec.webotx.webservice.xml.rpc.client.ContentNegotiation=***value*** クライアントクラス
なお、「***value***」には次のうちいずれかの値を指定します。
表1.2.6.3-1
意味
none Fast Infoset を使用しない
pessimistic レスポンスメッセージのみFast Infoset を利用する
optimistic リクエストメッセージ・レスポンスメッセージの両方でFast Infoset を利用する
ダイナミック(動的)プロキシ方式
公開されているWSDLを参照してクライアントを作成します。WSDLを参照したコーディング方法なので、動的にクライアントを生成して実行することも可能になります。ここでは、「DynamicProxy」サンプルをベースにクライアントコードの作成方法について説明します。また、動的にクライアントを生成して実行するためのアイディアを説明します。
クライアントコードの作成
「DynamicProxy」サンプルをベースにして、クライアントコードの作成方法を説明します。なお、このクライアントをコンパイル、または実行する環境では、次のライブラリがクラスパスに追加されている必要があります。
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;

public class DynamicProxyHelloClient {

  public static void main(String[] args) {

    try {

      /*以下の4つの変数の値は、すべてWSDLから取得することができます。*/
      //(1)definitions要素のtargetNamespace属性の値です。
      String nameSpaceUri = "http://sample/Hello";
      //(2)service要素のname属性の値です。
      String serviceName = "Hello";
      //(3)port要素のname属性の値です。
      String portName = "HelloPort";
      //(4)公開されているWSDLのURLの文字列です。この文字列は、最後に?wsdlが
      //ついているJAX-RPC仕様で定めた形式でなければなりません。
      String urlString= "http://localhost:8080/HelloService/Hello?wsdl";
      /*WSDLから取得できる変数、ここまで*/

      //Webサービスを仮想オブジェクト化します。この部分は汎用的に使えます。
      URL wsdlUrl= new URL(urlString);
      ServiceFactory serviceFactory = ServiceFactory.newInstance();
      Service service=
        serviceFactory.createService(wsdlUrl,new QName(nameSpaceUri,serviceName));

      //Webサービスの仮想オブジェクトからポートを取得し、プロキシを生成します。
      //「Hello_PortType」クラスはサービスエンドポイントインタフェースです。
      Hello_PortType proxy =
        (Hello_PortType) service.getPort(new QName(nameSpaceUri,portName),Hello_PortType.class);

      //Webサービスにアクセスし、結果を出力します。
      System.out.println(proxy.say_hello_Hello("hello"));

    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}

Memo
「DynamicProxy」サンプルは、チュートリアルで作成したWebサービスにアクセスするダイナミックプロキシ方式で作成したクライアントです。

Memo
<WebOTX_DIR>はWebOTXのインストールルートディレクトリ、<J2SE_DIR>はJ2SE SDKのインストールルートディレクトリのことです。

Memo
クライアントコード中で使っているサービスエンドポイントインタフェースは、JNDIなどを使用して取得するか、wscompileコマンドを使用して生成してください。wscompileコマンドについてはスタティックスタブ方式を参照してください。

Fast Infoset の利用方法
Fast Infosetを利用するには、クライアント実行時にJava VMプロパティを設定します。

[設定例]

[foo@webotx ~]$ java -Dcom.nec.webotx.webservice.xml.rpc.client.ContentNegotiation=***value*** クライアントクラス
なお、「***value***」には次のうちいずれかの値を指定します。
表1.2.6.3-2
意味
none Fast Infoset を使用しない
pessimistic レスポンスメッセージのみFast Infoset を利用する
optimistic リクエストメッセージ・レスポンスメッセージの両方でFast Infoset を利用する
DII方式
JAX-RPCのAPIを直接呼出して使い、アクセスするWebサービスの情報を手動で設定しすることによってクライアントを作成する方法です。この方法は、WSDLがない場合やWSDLに依存せずに細かい設定を手動でしたい場合など、ごく限られた用途で使用する特殊な方法で、SOAPやJAX-RPC仕様を理解した上級者向けに用意されたクライアント作成手段であると理解してください。通常、この方法を使うことは推奨されません。ここでは、「DII」サンプルをベースに、クライアントコードの作成方法について簡単に説明します。
環境構築
DII方式で作成したクライアントをコンパイル、実行する環境には、次のライブラリがクラスパスに追加されている必要があります。

Memo
<WebOTX_DIR>はWebOTXのインストールルートディレクトリのことです。

クライアントコードの作成
「DII」サンプルをベースに、クライアントコードの作成方法について簡単に説明します。
import javax.xml.namespace.QName;
import javax.xml.rpc.Call;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;

public class DIIHelloClient {

  //Webサービス名です。
  private static String qnameService = "Hello";
  //ポート名です。
  private static String qnamePort = "HelloPort";
  //Webサービスの名前空間URIです。
  private static String BODY_NAMESPACE_VALUE ="http://sample/Hello";

  //固定値の定義です。
  private static String ENCODING_STYLE_PROPERTY =
    "javax.xml.rpc.encodingstyle.namespace.uri";
  private static String NS_XSD = "http://www.w3.org/2001/XMLSchema";
  private static String URI_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/";

  public static void main(String[] args) {

    try {

      //サービスのインスタンスを作成します。
      ServiceFactory factory = ServiceFactory.newInstance();
      Service service = factory.createService(new QName(qnameService));
      //ポートからCallオブジェクトを作成します。
      QName port = new QName(qnamePort);
      Call call = service.createCall(port);
      //Callオブジェクトに各種設定を行います。
      call.setTargetEndpointAddress("http://localhost:8080/HelloService/Hello");
      call.setProperty(Call.SOAPACTION_USE_PROPERTY,new Boolean(true));
      call.setProperty(Call.SOAPACTION_URI_PROPERTY,"");
      call.setProperty(ENCODING_STYLE_PROPERTY,URI_ENCODING);
      QName QNAME_TYPE_STRING = new QName(NS_XSD,"string");
      call.setReturnType(QNAME_TYPE_STRING);
      call.setOperationName(new QName(BODY_NAMESPACE_VALUE,"say_hello_Hello"));
      call.addParameter("String_1",QNAME_TYPE_STRING,ParameterMode.IN);
      //Webサービスを実行します。
      System.out.println((String)call.invoke(new String[]{"hello"}));

    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}

Memo
「DII」サンプルは、チュートリアルで作成したWebサービスにアクセスするDII方式で作成したクライアントです。

Fast Infoset の利用方法
Fast Infosetを利用するには、次のうちいずれかの方法で設定します。

(1)Callインスタンスにプロパティを設定する
call.setProperty(com.nec.webotx.webservice.xml.rpc.client.dii.CallPropertyConstants.CONTENT_NEGOTIATION_PROPERTY, "***value***");
(2)クライアント実行時にJava VMプロパティを追加する

[設定例]

[foo@webotx ~]$ java -Dcom.nec.webotx.webservice.xml.rpc.client.ContentNegotiation=***value*** クライアントクラス
なお、「***value***」には次のうちいずれかの値を指定します。
表1.2.6.3-3
意味
none Fast Infoset を使用しない
pessimistic レスポンスメッセージのみFast Infoset を利用する
optimistic リクエストメッセージ・レスポンスメッセージの両方でFast Infoset を利用する

 

タイムアウト設定

JAX-RPCクライアントはサーバへの接続に関するタイムアウト時間を設定できます。 この機能を利用することで、一定時間応答のないサーバなどから強制的に切断して、次の処理に移行することができます。

タイムアウトの設定方法は3種類あります。

  1. WebOTX Webサービス(JAX-RPC)のシステムプロパティ
  2. コード内でのsetterメソッド
  3. JDK標準のシステムプロパティ

Memo
通常、接続タイムアウトはサーバ側の設定により制御されます。

Memo
3.の設定についてはWebOTX V8.1以前のJAX-RPCエンジンでも利用できます。

複数の設定を行った場合、以下の優先順位で設定が採用されます。複数の設定を行った場合、優先度の高いものが使用されます。優先度は高いものから以下の順になります。

  1. WebOTX Webサービス(JAX-RPC)のシステムプロパティ
  2. コード内でのsetterメソッド
  3. JDK標準のシステムプロパティ

 

  1. WebOTX Webサービス(JAX-RPC)のシステムプロパティ

java実行時にシステムプロパティとして以下を設定することで、HTTPタイムアウトの制御ができます。3.JDK標準のシステムプロパティと違い、接続するセッションで設定を行っているため他のプログラムへの影響はありません。

表1.2.6.3-4
システムプロパティ名 内容
com.nec.webotx.webservice.http.connect.timeout Webサービスとの接続までの待ち時間です。
com.nec.webotx.webservice.http.read.timeout Webサービスに接続してから応答を待っている時間です。

引数に含める単位はミリ秒です。0を設定した場合、接続を維持してサーバからの応答を待ち続けます。負の値は設定できません。負の値を設定したときは設定が無視されます。

com.nec.webotx.webservice.http.connect.timeoutはクライアントがサーバに接続してコネクションを確立するまでのタイムアウト時間です。 例えばサーバが停止している時など、接続に反応しない場合に何秒でタイムアウトするかを設定できます。

com.nec.webotx.webservice.http.read.timeoutはcom.nec.webotx.webservice.http.connect.timeoutと異なり、接続・リクエスト送信後にレスポンスが返却されるまでの待ち時間を設定できます。 リクエストを送ってもサーバの負荷が高すぎて反応がない場合、強制的に接続を切断したい場合などに利用できます。

[実行例]

[foo@webotx ~]$ java -Dcom.nec.webotx.webservice.http.connect.timeout=10000 -Dcom.nec.webotx.webservice.http.read.timeout=30000 test.Main

この例の場合、サーバへの接続待ち合わせが10秒、接続してからレスポンスメッセージを受信するまで30秒待ちます。

 

  1. コード内でのsetterメソッド

WebOTX Developerのウィザード、またはwscompileコマンドで生成されるStubインスタンスに対して、以下のメソッドを実行することでタイムアウト値を設定できます。

表1.2.6.3-5
メソッド名 内容
_setConnectTimeout(int timeOut) Webサービスとの接続までの待ち時間です。
_setReadTimeout(int setReadout) Webサービスに接続してから応答を待っている時間です。

引数に含めるintの単位はミリ秒です。0を設定した場合接続を維持してサーバからの応答を待ち続けます。 負の値は設定できません。負の値を設定したときは設定が無視されます。

setConnectTimeoutはクライアントがサーバに接続してコネクションを確立するまでのタイムアウト時間です。 例えばサーバが停止している時など、接続に反応しない場合に何秒でタイムアウトするかを設定できます。

setReadTimeoutはsetConnectTimeoutと異なり、接続・リクエスト送信後にレスポンスが返却されるまでの待ち時間を設定できます。リクエストを送ってもサーバの負荷が高すぎて反応がない場合、強制的に接続を切断したい場合などに利用できます。

[設定例]

MessageTest_PortType_Stub stub = (MessageTest_PortType_Stub) new MessageTest_Service_Impl().getMessageTestPort();
stub._setConnectTimeout(10000);←追記
stub._setReadTimeout(10000);←追記
stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, url);
binding = (MessageTest_PortType)stub;

Caution
WebOTX V8.1以前のバージョンのWebOTX Developerで作成したソースコードを流用している場合、内容が異なるためStubインスタンスにメソッドを記述できません。設定例を参考にStubインスタンスを書きかえるか、プロジェクトを再作成してください。

 

  1. JDK標準のシステムプロパティ

java実行時にシステムプロパティとして以下を設定することで、HTTPタイムアウトの制御ができます。

表1.2.6.3-6
システムプロパティ名 内容
sun.net.client.defaultConnectTimeout Webサービスとの接続までの待ち時間です。
sun.net.client.defaultReadTimeout Webサービスに接続してから応答を待っている時間です。

引数に含める単位はミリ秒です。初期値は-1(設定なし)です。0を設定した場合接続を維持してサーバからの応答を待ち続けます。
この値の詳細はSun JDKに記載されています。「JDK 5.0 ドキュメント」-「ネットワーク機能」-「ネットワークプロパティ」

[実行例]

[foo@webotx ~]$ java -Dsun.net.client.defaultConnectTimeout=15000 -Dsun.net.client.defaultReadTimeout=20000 test.Main

この例の場合、サーバへの接続待ち合わせが15秒、接続してからレスポンスメッセージを受信するまで20秒待ちます。

Caution
これらの設定はJAX-RPCクライアントが実行されるJVM全体へ設定されます。他にHTTPプロトコルで接続するプログラムがある場合、影響を受ける場合がありますので注意してください。
例えば、JAX-RPCクライアントをServlet上で動作せる時、動作するWebOTXドメインのプロパティに設定した場合にHTTPクライアントとして動作するプログラム(Servlet, EJBなど)全体に反映されます。

 
メッセージダンプ
WebOTX Webサービス(JAX-RPC)では、クライアント実行時のHTTPメッセージのダンプを取得することが可能です。手順については以下に記載されています。
[1.2.8. Webサービスの実行 > 1.2.8.4. メッセージダンプ (JAX-RPC) ]
 

1.2.6.4. SAAJ APIを使用したクライアント作成

SAAJのAPIを利用し、Webサービスと交換するSOAPメッセージを直接処理するタイプのクライアントを作成できます。
環境構築
SAAJのAPIを利用したクライアントをコンパイル、実行する環境には、次のライブラリがクラスパスに追加されている必要があります。

Memo
<WebOTX_DIR>はWebOTXのインストールルートディレクトリのことです。

クライアントコードの作成
「SAAJ」サンプルをベースに、クライアントコードの作成方法について説明します。
import java.io.OutputStream;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

public class SAAJClient {
  //サービスのURLです。
  private static final String URL = "http://localhost/saaj/sample";
  //SOAPメッセージの作成に使用する値です。
  private static final String NS = "http://sample/WebOTX"; //名前空間
  private static final String PREFIX = "n"; //プレフィックス
  private static final String ELEMENT1 = "data"; //要素名
  private static final String ELEMENT2 = "No"; //要素名

  //メインメソッド
  public static void main(String[] args) throws Exception {
    SAAJClient client = new SAAJClient();

    //Webサービスを実行し、結果をコンソールに表示します。
    //リクエストメッセージはプログラミングにより、1要素ずつ作成します。
    client.invoke(client.createMessage(),System.out);

    //結果表示にあたり、空白行を挿入します。
    System.out.println();
    System.out.println();

    //Webサービスを実行し、結果をコンソールに表示します。リクエストメッセージ
    //は、あらかじめSOAPBodyが記述されているXMLファイルを読み込み、作成します。
    client.invoke(client.createMessage("sample.xml"),System.out);
  }
  //Webサービスを実行します。引数で渡されたSOAPMessageがリクエストメッセージに
  //なります。

  private void invoke(SOAPMessage message, OutputStream out) {
    try {
      //コネクションを張ります。
      SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
      SOAPConnection con = scf.createConnection();

      //Webサービスを実行して、サービスから返されたレスポンスメッセージ
      //を受け取ります。
      SOAPMessage reply = con.call(message, URL);

      //SOAPBodyを取り出します。
      SOAPBody body = reply.getSOAPBody();

      //SOAPBodyのエレメントを取り出します。
      Iterator ite = body.getChildElements();

      //SOAPBodyから取り出したノードをXML形式に整形して
      //出力します。
      while(ite.hasNext()) {
        Node node = (Node) ite.next();
        Source source = new DOMSource(node);
        TransformerFactory factory =
        TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer();
        Result output = new StreamResult(out);
        transformer.transform(source, output);
      }
    //コネクションを閉じます。
    con.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  //SOAPMessageをSAAJプログラミングにより作成します。
  private SOAPMessage createMessage() throws SOAPException {
    //SOAPMessageを作成します。
    MessageFactory mf = MessageFactory.newInstance();
    SOAPMessage message = mf.createMessage();

    //SOAPMessageからSOAPPartを取り出し、さらにSOAPEnvelopeを
    //取り出します。
    SOAPEnvelope env = message.getSOAPPart().getEnvelope();

    //SOAPEnvelopeからSOAPBodyを取り出す
    SOAPBody body = env.getBody();

    //SOAPBodyに各要素を追加します。
    Name name = env.createName(ELEMENT1, PREFIX, NS);
    SOAPBodyElement bodyElement = body.addBodyElement(name);
    name= env.createName(ELEMENT2, PREFIX, NS);
    bodyElement.addChildElement(name).addTextNode("001");

    //作成したSOAPMessageを返します。
    return message;
  }

  //XMLを読み込み、SOAPメッセージを作成します。
  private SOAPMessage createMessage(String filelocation) throws Exception {
    //SOAPMessageを作成します。
    MessageFactory mf = MessageFactory.newInstance();
    SOAPMessage message = mf.createMessage();

    //SOAPMessageからSOAPPartを取り出し、さらにSOAPEnvelopeを
    //取り出します。
    SOAPEnvelope env = message.getSOAPPart().getEnvelope();

    //SOAPEnvelopeからSOAPBodyを取り出します。
    SOAPBody body = env.getBody();

    //DOMを使用して、SOAPBodyが記述されているXMLファイルを読み
    //込み、SOAPBodyに追加します。
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(filelocation);

    //SOAPBodyに追加します。
    body.addDocument(doc);

    //作成したSOAPMessageを返します。
    return message;
  }
}

クライアントの実行
メニューから、実行実行を選択し、実行ダイアログを開きます。[新規]ボタンを押して名前を指定し、新しい構成を作成します。「メイン」タブで、「プロジェクト」に作成しておいたJavaプロジェクトを、「メインクラス」に作成したクライアントのクラスを指定します。引数を指定したい場合は、「引数」タブで指定します。以上の設定を確認したら[実行]ボタンを押します。
 

1.2.6.5. JAX-RS 準拠のクライアント作成

クライアントとして、Webブラウザを利用する場合、特にクライアントを作成する必要はありません。
クライアントを作成する場合については、具体例を、 [1.1. チュートリアル > 1.1.5. Webサービスクライアントの作成 > 1.1.5.2. JAX-RS の場合 ] に記載していますのでご覧ください。