Powered by SmartDoc

WSDL と JAX-RPC

Google Web APIs とスタブの生成

Google Web APIsを利用してGoogleのWebサービスにアクセスするには、クライアントプログラムと、スタブが必要になります。

まず、スタブを生成します。Google Web APIsで用意されているWSDLからスタブを生成できます。自分でプログラミングする必要はありません。スタブの生成には、JWSDPに含まれているwscompileというツールを使います。wscompileを実行すると、次のような32個のクラスファイルが生成されます。

クライアントプログラムでは、スタブを利用してGoogleのWebサービスにアクセスします。

クライアントプログラムとWSDLの対応

それでは、クライアントプログラムとWSDLとの対応関係について調べてみましょう。まずは、クライアントプログラムを示します。

クライアントプログラム

import javax.xml.rpc.Stub;
// wscompile によって生成されたスタブたち
import jp.ac.wakhok.tomoharu.google.*;

public class GoogleSearch {

    public static void main(String[] args) {
        try {

            // (1)スタブの生成
            GoogleSearchPort_Stub stub = 
                (GoogleSearchPort_Stub)(new GoogleSearchService_Impl()
                .getGoogleSearchPort());

            // (2)スタブにエンドポイントを設定する
            stub._setProperty(
                Stub.ENDPOINT_ADDRESS_PROPERTY,
                "http://api.google.com/search/beta2"
            );

            // (3)Google の検索処理を呼び出す
            // “xxxxx” が ライセンスキー
            // args[0] が検索したい言葉
            GoogleSearchResult result =
                stub.doGoogleSearch(
                    "xxxxx", args[0],
                    1, 10, false, "", false, "", "", ""
                );

            // (4)検索結果の出力
            ResultElement[] elements = result.getResultElements();
            for (int i=0; i<10; i++) {
                System.out.println(i);
                System.out.println(elements[i].getTitle());
                System.out.println(elements[i].getURL());
                System.out.println();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

WSDLの全体的な構造

次に、前回の復習です。

WSDLの全体的な構造は、次のようになります。

<definitions>
        <types>     ……    </types>
        <message>   ……    </message>
        <portType>  ……    </portType>
        <binding>   ……    </binding>
        <service>   ……    </service>
</definitions>

各要素の役割は、次のようになります。

スタブの生成

まず、スタブの生成部分について見てみましょう。

            // (1)スタブの生成
            GoogleSearchPort_Stub stub = 
                (GoogleSearchPort_Stub)(new GoogleSearchService_Impl()
                .getGoogleSearchPort());

この部分を(省略せずに)詳しく記述すると、次のようになります。

            GoogleSearchService service = new GoogleSearchService_Impl();
            GoogleSearchPort port = service.getGoogleSearchPort();
            GoogleSearchPort_Stub stub = (GoogleSearchPort_Stub)port;

1行目のGoogleSearchServiceは、WSDLのservice要素のname属性の値となっている名前です。

<service name="GoogleSearchService">
    <port name="GoogleSearchPort" binding="typens:GoogleSearchBinding">
        <soap:address location="http://api.google.com/search/beta2"/>
    </port>
</service>

GoogleSearchServiceはインタフェースです。このインタフェースの実装クラスがGoogleSearchService_Implになります。

2行目では、GoogleSearchServiceインタフェースのgetGoogleSearchPortメソッドを使って、GoogleSearchPortオブジェクトを取得しています。

GoogleSearchPortは、WSDLのportType要素のname属性の値となっている名前です。

<portType name="GoogleSearchPort">
  ......
  <operation name="doGoogleSearch">
    <input message="typens:doGoogleSearch"/>
    <output message="typens:doGoogleSearchResponse"/>
  </operation>
</portType>

GoogleSearchPortはインタフェースです。3行目で、GoogleSearchPortを、このインタフェースの実装クラスであるGoogleSearchPort_Stubにキャストしています。

この後は、このGoogleSearchPort_Stubオブジェクトを操作して、GoogleのWebサービスにアクセスすることになります。

スタブにエンドポイントを設定する

スタブにエンドポイントを設定します。

            // (2)スタブにエンドポイントを設定する
            stub._setProperty(
                Stub.ENDPOINT_ADDRESS_PROPERTY,
                "http://api.google.com/search/beta2"
            );

エンドポイントとは、Webサービスを提供しているURLのことです。エンドポイントは、service要素中の、soap:address要素のlocation属性で指定されています。

<portType name="GoogleSearchPort">
  ......
  <operation name="doGoogleSearch">
    <input message="typens:doGoogleSearch"/>
    <output message="typens:doGoogleSearchResponse"/>
  </operation>
</portType>

このWebサービスは、http://api.google.com/search/beta2というURLにアクセスするということです。

このURLをstubオブジェクトに設定します。

Googleの検索処理を呼び出す

いよいよ、Googleの検索処理を呼び出します。

            // (3)Google の検索処理を呼び出す
            // “xxxxx” が ライセンスキー
            // args[0] が検索したい言葉
            GoogleSearchResult result =
                stub.doGoogleSearch(
                    "xxxxx", args[0],
                    1, 10, false, "", false, "", "", ""
                );

先ほど述べたように、GoogleSearchPort_Stubクラスは、GoogleSearchPortインタフェースを実装しています。そして、GoogleSearchPortインタフェースは、WSDLのportType要素に対応しているのです。

<portType name="GoogleSearchPort">
  ......
  <operation name="doGoogleSearch">
    <input message="typens:doGoogleSearch"/>
    <output message="typens:doGoogleSearchResponse"/>
  </operation>
</portType>

GoogleSearchPortインタフェースでは、WSDLのportType要素の中にあるoperation要素がそれぞれのメソッドに対応しています。例えば、operation要素のname属性であるdoGoogleSearchという名前が、インタフェースではメソッドとして登場します。

public interface GoogleSearchPort extends java.rmi.Remote {
    public byte[] doGetCachedPage(......) throws RemoteException;
    public String doSpellingSuggestion(......) throws RemoteException;
    public GoogleSearchResult doGoogleSearch(
        String key, String q, int start, int maxResults,
        boolean filter, String restrict, boolean safeSearch,
        String lr, String ie, String oe) throws RemoteException;
}

では、このdoGoogleSearchメソッドの引数を見てみましょう。このメソッドでは、10個の引数が定義されています。

WSDLでは、operation要素の中にあるinput要素がメソッドの引数に対応します。

  <operation name="doGoogleSearch">
    <input message="typens:doGoogleSearch"/>
    <output message="typens:doGoogleSearchResponse"/>
  </operation>

input要素のmessage属性には、"typens:doGoogleSearch"と記述されています。引数の具体的な内容は、このdoGoogleSearchという名前を持つmessage要素に書かれているのです。

では、message要素を見てみましょう。

<message name="doGoogleSearch">
  <part name="key"	 type="xsd:string"/>
  <part name="q"	     type="xsd:string"/>
  <part name="start"	 type="xsd:int"/>
  ......
</message>

先のdoGoogleSearchメソッドの10個の引数の定義は、このmessage要素の中にあるのです。

part要素のtype属性で指定されているxsd:stringはJavaのString型に、xsd:intはJavaのint型にそれぞれ変換されます。

このようにして、WSDLとの対応関係によってdoGoogleSeachメソッドの引数が定義されるのです。

    public GoogleSearchResult doGoogleSearch(
        String key, String q, int start, int maxResults,
        boolean filter, String restrict, boolean safeSearch,
        String lr, String ie, String oe) throws RemoteException;

次に、返値について見てみましょう。

    GoogleSearchResult result = stub.doGoogleSearch(...);

GoogleSearchResult型のオブジェクトが返値となっています。引数のときと同様に、operation要素の中にあるoutput要素がメソッドの返値に対応します。

  <operation name="doGoogleSearch">
    <input message="typens:doGoogleSearch"/>
    <output message="typens:doGoogleSearchResponse"/>
  </operation>

message要素を見ると

<message name="doGoogleSearchResponse">
  <part name="return"
           type="typens:GoogleSearchResult"/>           
</message>

とあります。メソッドの返値として、GoogleSearchResultという型が定義されることになります。実際の定義は、types要素の中でなされます。

types要素では、

<types>
    <xsd:schema xmlns=
       "http://www.w3.org/2001/XMLSchema" 
       targetNamespace="urn:GoogleSearch">
    <xsd:complexType name="GoogleSearchResult">
       <xsd:all>
         <xsd:element name="documentFiltering" 
                      type="xsd:boolean"/>
         <xsd:element name="resultElements"              
                      type="typens:ResultElementArray"/>
         ......
       </xsd:all>
         ......
    </xsd:complexType>
         ......
</types>

というような定義があります。

wscompileによって、types要素で指定されたGoogleSearchResult型のJavaオブジェクトが生成されます。

検索結果の出力

最後に、検索結果を出力する部分です。

            // (4)検索結果の出力
            ResultElement[] elements = result.getResultElements();
            for (int i=0; i<10; i++) {
                System.out.println(i);
                System.out.println(elements[i].getTitle());
                System.out.println(elements[i].getURL());
                System.out.println();
            }

ここでは、まずresultオブジェクトのgetResultElementsメソッドを呼び出しています。

types要素で定義されたGoogleSearchResultには、いくつかの子要素があります。そうした子要素は、JavaオブジェクトのGoogleSearchResultではプロパティとなっています。こうしたプロパティには、JavaBeansのように、getter (get +子要素名のメソッド)でアクセスできます。

この例の場合、GoogleSearchResult要素の子要素にresultElements要素があります。従って、JavaのオブジェクトであるGoogleSearchResultオブジェクトには、getResultElementsメソッドがあることになります。

    <xsd:complexType name="GoogleSearchResult">
       <xsd:all>
         ......
         <xsd:element name="resultElements"              
                      type="typens:ResultElementArray"/>
         ......
       </xsd:all>
         ......
    </xsd:complexType>

このgetResultElementsメソッドの返値は、ResultElementの配列となっています。もう一度WSDLでの定義を見てみると、resultElementsの型はResultElementArrayとなっています。これは、types要素で定義されているResultElement型の配列です。

         <xsd:element name="resultElements"              
                      type="typens:ResultElementArray"/>

では、ResultElementの定義を見てみましょう。URLやtitleといった子要素があります。

<xsd:complexType name="ResultElement">
  <xsd:all>
    <xsd:element name="URL" type="xsd:string"/>
    <xsd:element name="title" type="xsd:string"/>
    ......
  </xsd:all>
</xsd:complexType>

このResultElement要素も、またwscompileによってJavaのオブジェクトになっています。次の部分で、ResultElementのURLプロパティ、またtitleプロパティの値を出力しています。

                System.out.println(elements[i].getTitle());
                System.out.println(elements[i].getURL());