9.20.3. クライアント側

クライアント側について詳細に説明する前に、Web サービスの中心となる分離の概念を理解することが重要となります。このような方法で利用可能ですが、Web サービスは内部 RPC に対して最も適応しているわけではなく、これに関しては (CORBA や RMI など)さらに優れた技術が存在します。Web サービスは相互運用性のある粗粒子の通信向けに開発されています。Web サービスのやりとりを行うパーティシパントが、特定の場所で特定のオペレーティングシステムを使用し、もしくは特定のプログラミング言語で記述されているとの前提、保証はありません。そのため、 クライアントとサーバーの実装を明確に分離することが重要となります。 抽象コントラクトの定義のみを共通になるようにするだけでいいのです。何らかの理由でソフトウェアがこの原理に従わない場合は、Web サービスを使用すべきではありません。 このような理由により、クライアントが同じサーバーで稼働している場合でも、クライアントの開発技法としてトップダウンアプローチを用いることが推奨されます。
wsprovide によってオフラインで生成されたものではなくデプロイされた WSDL を使用して、 トップダウンの項のプロセスを再度確認してみましょう。soap:address に対する正しい値を取得するためだけにこれを実行します。 この値はコンテナ設定の内容が基になるため、 デプロイ時に算出されなければなりません。WSDL ファイルを編集することもできますが、 パスが正しくなるよう注意してください。
オフラインバージョン:
<service name='EchoService'>
   <port binding='tns:EchoBinding' name='EchoPort'>
      <soap:address location='REPLACE_WITH_ACTUAL_URL'/>
   </port>
</service>
オンラインバージョン:
<service name="EchoService">
   <port binding="tns:EchoBinding" name="EchoPort">
      <soap:address location="http://localhost.localdomain:8080/echo/Echo"/>
   </port>
</service>
wsconsume を用いてオンラインでデプロイしたバージョンを使用する:
$ wsconsume -k http://localhost:8080/echo/Echo?wsdl
echo/Echo.java
echo/EchoResponse.java
echo/EchoService.java
echo/Echo_Type.java
echo/ObjectFactory.java
echo/package-info.java
echo/Echo.java
echo/EchoResponse.java
echo/EchoService.java
echo/Echo_Type.java
echo/ObjectFactory.java
echo/package-info.java
EchoService.java は top-down セクションでは確認しなかったクラスでした。 WSDL の取得先となる場所を格納する方法に注目してください。
@WebServiceClient(name = "EchoService", targetNamespace = "http://echo/", wsdlLocation = "http://localhost:8080/echo/Echo?wsdl")
public class EchoService extends Service
{
   private final static URL ECHOSERVICE_WSDL_LOCATION;
  
   static
   {
      URL url = null;
      try
      {
         url = new URL("http://localhost:8080/echo/Echo?wsdl");
      }
      catch (MalformedURLException e)
      {
         e.printStackTrace();
      }
      ECHOSERVICE_WSDL_LOCATION = url;
   }
  
   public EchoService(URL wsdlLocation, QName serviceName)
   {
      super(wsdlLocation, serviceName);
   }
  
   public EchoService()
   {
      super(ECHOSERVICE_WSDL_LOCATION, new QName("http://echo/", "EchoService"));
   }
  
   @WebEndpoint(name = "EchoPort")
   public Echo getEchoPort()
   {
      return (Echo)super.getPort(new QName("http://echo/", "EchoPort"), Echo.class);
   }
}
ご覧のように、 上記は JAX-WS、 javax.xml.ws.Service 内のメインクライアントエントリポイントを拡張するクラスを生成しました。 Service を直接使用できる一方、 設定情報を提供してくれるためこちらの方がずっと簡単になります。 本当に注意しなければならないメソッドは getEchoPort() メソッドのみで、 Service Endpoint Interface のインスタンスを返します。 これであらゆる WS オペレーションが返されるインターフェースでメソッドを呼び出すだけで呼び出し可能になります。

注記

実稼働アプリケーションでリモート WSDL URL へ参照することは推奨されません。 参照すると Service Object をインスタンス化する度にネットワーク I/O が発生するためです。 保存したローカルコピーに対してツールを使用するか、 URL バージョンのコンストラクタを使用して新しい WSDL の場所を提供するようにします。
あとはクライアントを記述してコンパイルするだけです。
import echo.*;
..
public class EchoClient
{
   public static void main(String args[])
   {
      if (args.length != 1)
      {
         System.err.println("usage: EchoClient <message>");
         System.exit(1);
      }
  
      EchoService service = new EchoService();
      Echo echo = service.getEchoPort();
      System.out.println("Server said: " + echo.echo(args[0]));
   } 
}
これで wsrunclient ツールを使って簡単に実行できるようになります。 これは必要なクラスパスで java を呼び出す便利なツールです。
$ wsrunclient EchoClient 'Hello World!'
Server said: Hello World!
起動時のオペレーションのエンドポイントアドレス変更は簡単です。 以下のように ENDPOINT_ADDRESS_PROPERTY を設定します。
...
EchoService service = new EchoService();
Echo echo = service.getEchoPort();
  
/* Set NEW Endpoint Location */
String endpointURL = "http://NEW_ENDPOINT_URL";
BindingProvider bp = (BindingProvider)echo;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);
  
System.out.println("Server said: " + echo.echo(args[0]));
...