Webアプリケーションは、図7.1.1.1[Webアプリケーション]のように「Webサーバ」が「Webブラウザ」と通信を行います。
それに対してWebサービスは、図7.1.1.2[Webサービス]のように「Webサーバ」が「プログラム」と通信を行うものです。
言い換えると、Webサービスとは、「Webのブラウザを使わずに、プログラム中からWebにアクセスして必要な情報を取り出せるサービス」ということになります。
Webサービスは、クライアントとは(ネットワーク的に)離れていることが想定されています。しかし、ネットワーク的に離れたサービスにアクセスしようと思っても、たいていのサイトではファイアウォールによってWebとメール以外のポートは閉じられています。
しかし、80番のHTTPはだいたい使えます。そこで、Webサービスでは、トランスポート層のプロトコルとしてHTTPを使うのです。まれに、SMTPを使う場合もあります。
Webサービスで利用されるデータには、後で見るようにXMLが使われています。そのため、Webサービスを構成するプログラムは、どんな言語で記述されても良いのです。
SOAPとは、Webサービスに対する「要求」と、クライアントへの「応答」のフォーマットです。XMLで記述されています。
先ほどの具体例に出てきたGoogle Web APIでは、「こんな言葉を含むページを調べたい」という要求と、「こんなページがありました」という応答がSOAPで記述されています。
WSDLとは、Webサービスの具体的な内容を書いてある文書です。Webサービスを利用するためにはどこにアクセスすればよいのか、またどのようなメソッドが使えるのかなどの情報が記述されています。Java言語でのインタフェースのようなものです。SOAPと同じくWSDLもXMLで記述されています。
Google Web APIでも、このWebサービスの内容を示すWSDL文書が付属しています。
WSDLから、Webサービスにアクセスするクライアントプログラムを生成できます。例えばJavaのWebサービス開発キットであるJWSDPでは、wscompileというツールでWSDLからJavaプログラムを生成します。クライアントプログラムからはメソッドを呼び出すだけであり、具体的な処理内容はWebサービス側にあるので、これでうまくいくのです。
また、既存のプログラムからWSDLを生成することもできます。
RMI (Remote Method Invocation (遠隔メソッド呼び出し))は、あるJava Virtual Machine上のインスタンスが、別のJava Virtual Machine上のメソッドを呼び出す仕組みです。このとき、2つのJava Virtual Machineは、それぞれ別のホスト上にあっても構いません。2つのJava Virtual Machineは、クライアント・サーバモデルによって通信を行います。
RMIを使わない通常のJavaプログラムについて考えてみましょう。例えばHelloクラスのsayHelloメソッドを実行しようとすると、Helloのインスタンスを作成して、このインスタンスのsayHelloメソッドを実行します。
RMIでは、Helloクラスの実装はサーバ側にあります。クライアントでHelloクラスのインスタンスを作成してsayHelloメソッドを呼び出すと、サーバ上のsayHelloメソッドが実行され、返値がクライアントに返されます。
Helloクラスの実装はサーバ側にあるので、クライアントはサーバ側を呼び出すだけでよいのです。このときクライアントは、メソッドを実行するだけでサーバを呼び出せます。
RMIの構成図を図7.2.1.1[RMIの構成図]に示します。
サーバでは、クライアントから呼び出されるメソッドを実装します。クライアントでは、サーバを見つけだして、メソッドを実行します。
RMIでは、サーバとクライアントには通信に必要な具体的な処理は記述されていません。そうした処理は「スタブ」と「スケルトン」というクラスに記述されています。スタブはクライアント側で、スケルトンはサーバ側で処理を行います。RMIでは、直接にはスタブとスケルトンが通信を行うことになります。スタブとスケルトンは、サーバのプログラムからツールで生成されます。
rmiregistryは、サーバの情報を登録しておくための「ネームサーバ」です。クライアントはrmiregistryにアクセスしてサーバのプログラムを探します。
RMIの原型となった技術がRPC (Remote Procedure Call)です。RPCは、別のマシン上にある手続きを実行するためのしくみを提供します。
RPCはもともとSun Microsystemsによって開発され、現在ではUnixやWindowsなどのOSで常用されています。
JAX-RPCは、Javaで「RPC型」のWebサービスを実現するためのAPIです。JAX-RPCは、JavaのWebサービス開発キットであるJWSDPや、J2EEのパッケージに同梱されています。J2SEには入っていません。
JAX-RPCの構成図を図7.2.3.1[JAX-RPCの構成図]に示します。
JAX-RPCを使ったプログラミングスタイルは、RMIとほとんど変わりません。クライアントから利用できるメソッドは、"WSDL"によって定義されています。図を見比べるとわかるように、RMIでの「スケルトン」は、JAX-RPCでは“Tie”となります。また、クライアントプログラムの実行にあたっては、"JAX-RPC Runtime"が必要になります。
サーバとクライアントの通信は、HTTP上のSOAPが使われます。そして、図には載せていませんが、RMIのrmiregistryに代わるものとして、UDDIというものがあります。UDDIについては本講義では扱いません。
もっともよく利用されているWebサービスに、"Google Web APIs"があります。このAPIは、Javaなどのプログラムから、Googleにアクセスするためのものです。プログラムからGoogleにアクセスして、検索結果をプログラムで処理できます。例えば、ある言葉に関するGoogleの検索件数を毎日カウントする、といったプログラムが作成できます。
こうしたプログラムを作成するには、GoogleのWebサービスにアクセスするためのクライアントプログラムと、スタブが必要になります。スタブは、Google Web APIsで用意されているWSDLから生成できます。
では、Google Web APIsを使ってGoogleのWebサービスにアクセスするための手順の概要を紹介しましょう。
まずはじめに、JWSDPをインストールすることが必要になります。JWSDPに、JAX-RPCのAPIやさまざまなツールが含まれています。環境変数とパスの設定が必要です。
Google Web APIsを入手すると、GoogleのWebサービスで利用するWSDLが同梱されています。別にライセンスキーの取得も必要です。
その後で、スタブを生成します。スタブはWSDLから生成します。自分でプログラミングする必要はありません。ただし、スタブの作成に必要なXMLを書かねばなりません。スタブの生成には、JWSDPに含まれているwscompileというツールを使います。
GoogleのWebサービスにアクセスするプログラムを書きます。コンパイルと実行ではAntというツールを使った方が便利になります。必要なjarファイルがあまりに多いためです。
まず、http://java.sun.com/webservices/jwsdp/index.jspからJWSDP 1.3をダウンロードします。
そしてインストールを実行します。
インストールが完了したら、JWSDPをインストールしたディレクトリに、環境変数JWSDP_HOMEを設定します。
また、次の2つのディレクトリにPATHを通します。
http://www.google.com/apis/からGoogle Web APIsをダウンロードします。ダウンロードしたファイルを開くと、GoogleSearch.wsdlというWSDLファイルが見つかるでしょう。ほかにはJavaや.Netのサンプルプログラムなどが含まれています。
Google Web APIsを利用するには、Googleにアカウントを作成する必要があります。http://www.google.com/apis/の“Create Account”をクリックして、必要な項目を入力することで、アカウントが発行されます。
アカウントが発行されると、登録されたメールアドレスにライセンスキーが送られます。ライセンスキーは、メール本文中に次のような形式で書かれています。
Your Google Web APIs license key is xxxxx
この"xxxxx"の部分がライセンスキーになります。このライセンスキーは、Webサービスを呼び出すメソッドの引数として利用します。
GoogleのWebサービスでは、検索できる回数が1日に1,000回までと制限されています。
WSDLからスタブを生成します。
まず、スタブに関する情報を設定するため、XMLを記述する必要があります。
<?xml version="1.0" encoding="UTF-8"?> <configuration xmlns= "http://java.sun.com/xml/ns/jax-rpc/ri/config"> <wsdl location="GoogleSearch.wsdl" packageName= "jp.ac.wakhok.tomoharu.google" /> </configuration>
このXMLでは、wsdl要素のlocaltion属性でWSDLファイルを指定しています。またpackageName属性で、生成されるスタブのパッケージ名を指定しています。
XMLを作成したら、次のコマンドを実行します。
wscompile -gen:client -keep config.xml
このコマンドによってスタブが生成されます。
"-gen:client"というオプションは、スタブを生成することを示します。また、"-keep"オプションで、スタブのソースファイルを残すことを指定します。"config.xml"は先に作成したXMLファイルです。
このコマンドを実行すると、jp\ac\wakhok\tomoharu\googleというパッケージ名で指定されたディレクトリに、スタブやGoogle APIで利用できるインタフェースなど、たくさんのソースファイル・クラスファイルが作成されます。
それでは、クライアントプログラムのソースファイルを示しましょう。
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)スタブにWebサービスのURLを設定する 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(); } } }
このプログラムのポイントを見ていきましょう。
まずは、必要なクラス・インタフェースをインポートします。先ほどwscompileで作成したクラス・インタフェースを忘れずにインポートしましょう。
import javax.xml.rpc.Stub; // wscompile によって生成されたスタブたち import jp.ac.wakhok.tomoharu.google.*;
次に、スタブを生成します。
// (1)スタブの生成 GoogleSearchPort_Stub stub = (GoogleSearchPort_Stub)(new GoogleSearchService_Impl() .getGoogleSearchPort());
そして、生成したスタブにWebサービスのURLを設定します。GoogleのWebサービスは、"http://api.google.com/search/beta2"というURLで提供されていることになります。
// (2)スタブにWebサービスのURLを設定する stub._setProperty( Stub.ENDPOINT_ADDRESS_PROPERTY, "http://api.google.com/search/beta2" );
いよいよ、Googleの検索処理を呼び出す部分です。スタブで定義されているdoGoogleSearchというメソッドを呼び出しています。引数で指定した"xxxxx"という文字列はライセンスキーで、args[0]となっている文字列は検索語です。
// (3)Google の検索処理を呼び出す // “xxxxx” が ライセンスキー // args[0] が検索したい言葉 GoogleSearchResult result = stub.doGoogleSearch( "xxxxx", args[0], 1, 10, false, "", false, "", "", "" );
このdoGoogleSearchというメソッドは、WSDLで定義されているものです。
WSDLの該当箇所を見てみましょう。
<operation name="doGoogleSearch"> <input message="typens:doGoogleSearch"/> <outputmessage= "typens:doGoogleSearchResponse"/> </operation>
operation要素のname属性が"doGoogleSearch"となっています。これは、このWebサービスで"doGoogleSearch"という操作ができることを示しています。WSDLにこうした定義があることにより、wscompileによって生成されたスタブでも、doGoogleSearchというJavaのメソッドが用意されるわけです。
最後に、検索結果を出力する部分です。検索処理を行ったdoGoogleSearchメソッドの返値としてGoogleSearchResultオブジェクトが返されます。このオブジェクトに対してgetResultElementsメソッドを実行すると、ResultElementオブジェクトの配列が返されます。このResultElementオブジェクトが1件の検索結果に該当します。for文の中でResultElementオブジェクトのgetTitleメソッドやgetURLメソッドを実行し、タイトルとURLを出力しています。
// (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(); }
このプログラムは、Antというツールを使ってコンパイルを行います。
Antは、Javaのプログラムをコンパイルしたり実行したりする上で手助けをしてくれるツールです。Unixでのmakeのようなものです。コンパイルにはいくつかのJarファイルが必要になるので、Antを使うのが楽でしょう。Antは単独のパッケージとして配布されていますが、JWSDPにも同梱されています。
Antでは、プログラムのコンパイルや実行の方法をbuild.xmlというファイルに記述します。コンパイルするには、build.xmlがあるディレクトリで次のコマンドを実行します。
ant compile
クライアントプログラムの実行でもAntを利用します。プログラムを実行するには、build.xmlがあるディレクトリで次のコマンドを実行します。
ant run
このプログラムでは、"wakhok"という言葉について、Googleの検索を行い、上位10件のタイトルとURLが表示されます。
検索したい言葉を変更するには、build.xml中の"wakhok"という部分を別の言葉に変更します。
<target name="run" depends="compile"> <java classname="GoogleSearch" > <arg value="wakhok"/> <classpath> <path refid="wspack.classpath"/> </classpath> </java> </target>
クライアントプログラムの実行結果は、次のようになります。
(前略) run: [java] 0 [java] <b>wakhok</b>.TV [java] http://www.ctc-wakhok.tv/ [java] 1 [java] UNIX データベース入門 [java] http://www.wakhok.ac.jp/DB/DB.html [java] 2 [java] Welcome to Wakkanaihokusei Biblion [java] http://www.wakhok.ac.jp/biblion.html [java] 3 [java] STLのページ [java] http://www.wakhok.ac.jp/~sumi/stl/ (後略)
この例では、WSDLからスタブを作成し、スタブの機能を利用するクライアントプログラムを作成しました。
ほかの言語でも、wscompileのようなツールがあれば、その言語用のスタブを作成できます。
こうして、クライアントプログラムからGoogleの機能が利用できるようになりました。