火曜日 6 27, 2006
火曜日 6 27, 2006
今回は、JAX-WS 2.0仕様に従ったWebサービス・クライアントのコーディングとその実行方法について御紹介します。
Webサービスの呼出し方法には、目的に応じて様々な方法が用意されていますが、ここではもっとも簡単なエンドポイント・インタフェースに基づくプロキシーを用いた同期呼び出しの方法を説明します。
まず、Java EE 5チュートリアル:Webサービス編でデプロイしたCalcサービスのWSDLから、クライアント用のプロキシー(スタブ)コードを生成します。SJS AppServer 9(glassfish)ではこのためのコマンドラインツールとしてwsimportコマンドが用意されていますので、wsimportコマンドの引数にWSDLのURLを指定して以下のように実行します。
$ mkdir work $ cd work $ $ASROOT/bin/wsimport -keep http://localhost:8080/Calc/CalcService?WSDL
ここで、-keepオプションは、生成されたスタブコードのjavaソースも残すことを意味します。-keepオプションがないと、コンパイルされたクラスだけがカレントディレクトリに生成されます。
また、WSDLのURLは、前回のエントリで紹介した管理コンソールのWebサービスCalcのページで、「Test」ボタンを押した時に表示されるテストクライアントのページに(WSDL File)というリンクがありますので、これをブラウザ上で右クリックしてコピーするといいでしょう。wsimportコマンドで生成されるファイルは以下の通りです。
$ find . . ./com ./com/example ./com/example/Add.class ./com/example/Add.java ./com/example/AddResponse.class ./com/example/AddResponse.java ./com/example/Calc.class ./com/example/Calc.java ./com/example/CalcService.class ./com/example/CalcService.java ./com/example/ObjectFactory.class ./com/example/ObjectFactory.java ./com/example/package-info.class ./com/example/package-info.java
Webサービスのメソッドを呼び出す手順は、ポートにマッピングされるエンドポイント・インタフェース(ここではCalcインタフェース)のスタブを取得し、そのインタフェースに定義された目的のメソッド(ここではadd()メソッド)を呼び出すということになります。
それでは、エンドポイント・インタフェースのスタブはどのようにして取得すればいいでしょうか。できればカッコよくリソース・インジェクションを使いたいものです。クライアント・オブジェクトにWebサービス・スタブをインジェクションするには、@WebServiceRefアノーテーションを使用します。以下が、@WebServiceRefを使用したクライアントコードの例です。
import com.example.Calc;
import com.example.CalcService;
import javax.xml.ws.WebServiceRef;
public class Client {
@WebServiceRef
private static CalcService service;
public static void main(String args[]) {
Calc port = service.getCalcPort();
int i = 10;
int j = 20;
System.out.printf("%d + %d = %d%n", i, j, port.add(i, j));
}
}
上記の例では、staticなメンバ変数serviceにCalcサービスがインジェクションされることになります(インジェクションされるのは、クラスがインスタンス化されるときの1回だけですので、インジェクションされるメンバ変数は必ずstaticで宣言します)。CalcServiceクラスには、Calcポートのプロキシーを取得するためのgetCalcPort()メソッドが用意されているためこれを利用して、Calcポートのプロキシーを取得します。プロキシーが取得できたら、後は目的のメソッド(ここではadd(int,int)メソッド)を呼び出すだけです。
また、@WebServiceRefアノーテーションは、Calcポートのプロキシーを直接クライアントのクラスにインジェクションすることもできます。この場合は、@WebServiceRefの属性にそのポートを取得するためのサービスクラス(この場合、CalcServiceクラス)を教えてあげる必要があります。
import com.example.Calc;
import com.example.CalcService;
import javax.xml.ws.WebServiceRef;
public class Client {
@WebServiceRef(CalcService.class)
private static Calc port;
public static void main(String args[]) {
int i = 10;
int j = 20;
System.out.printf("%d + %d = %d%n", i, j, port.add(i, j));
}
}
それでは、このクライアントをコンパイルして実行してみましょう。コンパイルするときには、Java EE 5のAPIが含まれるjavaee.jarをクラスパスに含めます。
$ javac -classpath $ASROOT/lib/javaee.jar:. Client.java
次にクライアントを実行しますが、上記のように@WebServiceRefアノーテーションを使用している場合には、単純にjavaコマンドを使用したのでは正しく実行されません。実は、スタンドアロンクライアントでのリソースインジェクションの機能を使いたい場合は、クライアントをJava EEクライアント・コンテナから起動する必要があります。そうすることで、クライアント・コンテナがリソースインジェクションのアノーテーションを検出し、適切なリソースをインジェクションしてくれるわけです。
J2EE 1.4の頃は、クライアントコンテナを利用するためには、クライアント用のデプロイメント記述子application-client.xmlを記述して、クライアントEARを作成する必要がありました。しかし、Java EE 5では、application-client.xmlに記述すべき<service-ref>に対応する@WebServiceRefがクラスに埋め込まれているため、わざわざapplication-client.xmlを用意する必要はありません。また、SJS AppServer 9(glassfish)では、必ずしもクライアントEARを作成する必要もありません。以下のように、コンパイル済みのクラス名を引数にして、javaコマンドの代わりにappclientコマンドでクライアントを実行するだけです。
$ $ASROOT/bin/appclient Client 10 + 20 = 30
ただし、実際にアプリケーション開発では、クライアント・コンテナを使用しないことが多いと思います。クライアント・コンテナを実行するコマンドは標準化されていないため、ベンダによって異なります。一般に、特定のアプリケーション・サーバー・ベンダのコマンドに依存したクライアント・プログラムのパッケージングはさけた方がいいでしょう。
この問題を避けるには、スタンドアロン・アプリケーションでは@WebServiceRefを使用するのを避け、以下のようなコードを使用するのがいいでしょう。
import com.example.Calc;
import com.example.CalcService;
public class Client {
public static void main(String args[]) {
CalcService service = new CalcService();
Calc port = service.getCalcPort();
int i = 10;
int j = 20;
System.out.printf("%d + %d = %d%n", i, j, port.add(i, j));
}
}
サーバがlocalhostではなく、リモートのホストである場合は、WSDLのURLとサービスのQNameを明示的に指定するもう一つのコンストラクタを使用すればOKです。
URL wsdlLocation = new URL("http://remote.host:8080/Calc/CalcService?WSDL");
QName serviceName = new QName("http://example.com/", "CalcService");
CalcService service = new CalcService(wsdlLocation, serviceName);
今度は、普通にjavaコマンドを使って実行することができます。ただし、クラスパスには、Java EE 5 APIのjavaee.jarとJAX-WSランタイムのappserv-ws.jarをクラスパスに入れる必要があります。
$ java -classpath $ASROOT/lib/javaee.jar:$ASROOT/lib/appserv-ws.jar:. Client 10 + 20 = 30
また、別の実行方法としては、Java SE 6 (Mustang)を利用することも考えられます。MustangにはJAX-WS 2.0のランタイムが含まれていますので、上記のクラスパス設定は不要になります。
$ java -version java version "1.6.0-dp" Java(TM) SE Runtime Environment (build 1.6.0-dp-b82-11) Java HotSpot(TM) Client VM (build 1.6.0-b82-6-release, mixed mode, sharing) $ java Client 10 + 20 = 30
クライアントのコードは、wsimportコマンドにより生成された一連のクラス群に依存していますが、ポータビリティに関しては全く心配がありません。生成されたクラスのソースを見て頂ければ分かりますが、これらは、JAX-WS 2.0およびJAXB 2.0の標準APIのみに依存しています。そのため、JDK 1.5 + Java EE 5、またはJDK 1.6の環境であれば、ベンダに関わらず、上記のWebサービスクライアントは実行可能です。
cool
Posted by wow gold on 11月月 03日, 2008年 at 10:43 午前 JST #