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());