Google Web APIsを利用してGoogleのWebサービスにアクセスするには、クライアントプログラムと、スタブが必要になります。
まず、スタブを生成します。Google Web APIsで用意されているWSDLからスタブを生成できます。自分でプログラミングする必要はありません。スタブの生成には、JWSDPに含まれているwscompileというツールを使います。wscompileを実行すると、次のような32個のクラスファイルが生成されます。
クライアントプログラムでは、スタブを利用してGoogleのWebサービスにアクセスします。
それでは、クライアントプログラムと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の全体的な構造は、次のようになります。
<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の検索処理を呼び出します。
// (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());