Webサービスの基軸を構成するのは、SOAP、WSDL、UDDIの3つのテクノロジだ。この連載では、Webサービスの基本的な知識を身に付けるために、この3つのテクノロジの背景と仕様、機能などを分かりやすく解説していく。(編集局)
あるアプリケーションがWebサービスとしてネットワーク上に公開されているとしよう。別のプログラムがそのWebサービスを利用するためには、次に挙げるWebサービスのインターフェイスに関する情報が必要になる。
●そのWebサービスはどこにあるのか
●そのWebサービスは、どんなフォーマットのメッセージを使って利用するのか
●そのWebサービスは、どんな通信プロトコルを使ってメッセージをやり取りするのか
Webサービスのインターフェイスを、人もプログラムも理解できるようにXML形式で記述するために開発された言語が、今回のテーマであるWSDL(Web Services Description Language)だ。CORBAのような分散オブジェクト技術では、インターフェイス記述言語としてIDL(Interface Description Language)が使用されている。Webサービスの世界におけるIDLに相当する言語がWSDLだ。
当初、複数の言語がWebサービスのインターフェイス記述言語として提案されていた。マイクロソフトのSCL/SDL(SOAP Contract Language/Service Description Language)や、IBMのNASSL(Network Accessible Service Specification Language)がそうだ。しかし、2000年9月にそれらの言語はWSDLバージョン1.0に統一されて公開された。さらにその翌年の3月に、改訂されたバージョン1.1(以後、WSDL1.1と呼ぶ)がアリバ・IBM・マイクロソフトからW3Cへ提出され、(勧告ではなく)技術ノートとして公開された。本稿執筆段階で一般に実装されているWSDLは、WSDL1.1だ。
WSDLで記述したXML文書のことをWSDL文書と呼ぶ。Webサービスのために、そのインターフェイスを記述したWSDL文書が用意されていることは、Webサービスの利用者に大きな利得となる。開発ツールにWSDL文書を読み込ませることによって、Webサービスを呼び出すモジュールのコードを自動生成できるようになるからだ。
WebサービスにWSDL文書が用意されていることは、Webサービスの提供者にも利得となることがある。例えば、ある旅行代理店会社が自社のホテル予約アプリケーションをWebサービスとして公開するとしよう。ホテルの部屋の空きを照会したり予約を入れたりするといった業務は、どの旅行代理店でもほぼ共通した内容だ。このような場合、業界団体では、Webサービスとして公開するホテル予約サービスシステムのインターフェイスを標準化することが考えられる。業界団体は、標準化されたインターフェイスの仕様を記述したWSDL文書を作成し、それを一般に公開することになるだろう。自社のホテル予約システムを新たにWebサービス化する企業は、公開されているWSDL文書を開発ツールに読み込ませてインターフェイスを実装するコードを自動生成させるだけで済む。
このようにWSDLは、Webサービスの開発の効率を飛躍的にアップさせる技術だ。またWSDLは、システムが発見したWebサービスと動的に接続することさえ可能にする技術だ。
WSDLによる記述は、ごく簡単なSOAPメッセージのやりとりを表現する場合でも、かなり長くなる。そのため、WSDLの基本構造を知らないまま、いきなりWSDL文書を見ると難解に感じてしまうことがある。
WSDL文書の基本構造を理解するうえで役立つポイントを、以下に3つ述べる。この3つのポイントを知っておくだけで、WSDL文書にずいぶん取り組みやすくなるはずだ。
(1)WSDL文書は抽象的な定義と具体的な定義の、2つのステップで構成されている
WSDLは、大まかにいうと2つのステップに沿ってWebサービスのインターフェイスを定義する。
●インターフェイスを抽象的に定義する
Webサービスを利用するための出入り口のことをWSDLではポートと呼ぶ。WSDLでは、ポートやポートを通してやりとりされるメッセージのフォーマットを、まず抽象的に定義する。抽象的に定義するとは、ポートやメッセージを、特定の通信プロトコルやネットワークアドレスに依存しない形式で定義することだ。
●抽象的なインターフェイスを具体的に定義し直す
続いてWSDLでは、抽象的に定義されたメッセージやポートに具体的な通信プロトコルやネットワークアドレスをバインドすることによって具体的に定義し直す。さらに、関連するポートをまとめたものをサービスとして定義する。
このようにWSDLでは、まずWebサービスのインターフェイスを抽象的に定義しておき、それを具体的なインターフェイスとして定義し直すという、2段構えのインターフェイス記述を行う。これは、抽象的に定義した部分だけを分離して、通信プロトコルやネットワークアドレスの異なる別のWebサービスの定義に再利用するための工夫なのだ。
(2)WSDL文書は中核要素と拡張性要素の2種類の要素で構成されている
基本的にWSDL規格が定めているのは、メッセージやポートタイプなどWebサービスを抽象的に定義する要素・属性だけだ。従って、定義された抽象的なメッセージやポートを具体的な通信プロトコルやメッセージフォーマットにバインドするためには、プロトコル固有の情報を指定する要素・属性を追加する必要がある。WSDL規格では、WSDLの中核となる要素・属性に加えて、特定の通信プロトコルに依存する拡張性要素(extensibility element)を使用することによって、抽象的な定義に具体的な通信プロトコルをバインドすることにしている。
(3)WSDL文書は定義の積み重ねによって構成される
WSDLでは、抽象的に定義してから具体的に定義し直すという2段構えであると述べた。しかし、実際の定義はさらに細かいステップに分かれていて、インターフェイスの最も基本的な単位からスタートし、それを包含する次の単位へと定義を進めていき、最終的にWebサービス全体を定義していく。つまり、WSDL文書は、各レベルにおける定義の積み重ねで構成されているわけだ。
WSDL文書を構成する要素のうち、主要な要素を表1に示す。次回で詳しく説明するが、表1に挙げた要素はすべて、WSDL名前空間(名前空間URIは、「http://schemas.xmlsoap.org/wsdl/」)に属している。本連載では、WSDL名前空間の名前空間接頭辞としてwsdlを使用する。もちろんwsdl以外の文字列を使用しても構わない。
要素名 | 要素の説明 | |
---|---|---|
wsdl:definitions要素 | WSDL文書の最上位要素 | |
wsdl:types要素 | メッセージのフォーマットを定義する際に使用する型を、抽象的に定義する。wsdl:types要素は省略可能だが、メッセージ定義にユーザー定義の型を使用する場合は、ここで型を定義しておく必要がある | |
wsdl:message要素 | Webサービスで使用するメッセージのフォーマットを抽象的に定義する。wsdl:types要素で定義された型はここで使用する | |
wsdl:operation要素 | 入出力メッセージや、エラー情報を通知するために使用するフォルトメッセージのフォーマットとして、wsdl:message要素で定義されたフォーマットを割り当てる。入力と出力とフォルトメッセージ出力を行う処理の1単位である操作(operation)を抽象的に定義する | |
wsdl:portType要素 | 関連する操作をひとまとめにした抽象的なポートである、ポートタイプ(portType)を定義する | |
wsdl:binding要素 | wsdl:portType要素で定義されたポートタイプ内の個々の抽象的な操作に、具体的な通信プロトコルをバインドする。ポートタイプの定義に通信プロトコルをバインドした定義のことをバインディング(binding)と呼ぶ。具体的な通信プロトコルへのバインドは、拡張性要素を使用して記述する | |
wsdl:port要素 | wsdl:binding要素で定義されたバインディングに、通信エンドポイントのネットワークアドレスをバインドして具体的なポートを定義する。ネットワークアドレスのバインドは拡張性要素を使用して記述する | |
wsdl:service要素 | wsdl:port要素で定義したポートのうち、関連するポートをひとまとめにしたサービスを定義する | |
表1 WSDL文書を構成する主要な要素 |
表1の説明を上から順番に丹念に読んでいくと、1つ前の要素によって記述された定義が、次の要素による定義の記述に使用され、さらにそれが次の要素による定義の記述に使用されていることがお分かりいただけるだろう。
抽象的な定義を行う要素の働きは、表1を見ただけではピンとこないかもしれない。Java言語におけるインターフェイス定義を例にして説明すると分かりやすいだろう。まず以下のリストを見ていただきたい。
public interface Estimate { public int getPrice(String Code, int Value); }
これは商品コードCodeと商品の個数Valueを渡すと、価格を返すメソッドを定義しているインターフェイスをJava言語でコーディングしたものだ。このEstimateというインターフェイスに、getPrice というメソッドが定義されている。getPriceメソッドは、StringクラスのCodeという第1パラメータとint型のValueという第2パラメータを持つ。またgetPriceメソッドは、処理結果をint型で返すことが分かるだろう。
このコードによる処理をWSDLで定義するとしたらどうなるだろうか。Javaのインターフェイスに相当する記述を行うのは、WSDLのwsdl:portType要素だ。またインターフェイス内で定義されているメソッドに相当する記述を行うのは、WSDLのwsdl:operation要素だ。すると、メソッドのパラメータの集合に相当するのはwsdl:message要素となる。wsdl:types要素の働きは、パラメータのためにユーザーが型を定義することに似ているだろう。Java言語との対比は、もう一度後述する。
図1には、表1の要素がどのようにWSDL文書を構成しているのかを示すイメージである。
WSDLの主要な要素がどのような包含関係にあるのか、イメージをつかんでいただきたい。
ここまでのところで、WSDL文書の大まかな構造や使用される主な要素の説明をしてきた。では、最後にWSDL文書のソースコードを見ることにしよう。
以下のリストに示すJavaのクラスが、Webサービスとして公開されているとして、そのインターフェイスがどのように記述されるかを示そう。
public class Estimate { public int getPrice(String Code, int Value) { ……ロジックの記述…… } }
このサンプルは、文字列型の商品コード(Code)と整数型の商品の個数(Value)を渡すと価格を返すメソッドをWebサービスとして公開するというものだ。このWebサービスのサービスを要求するためには、HTTPプロトコル上で以下のリストに示すSOAPメッセージを送る。ここでは、商品コードが「code-001」の商品を30個購入する場合の価格を要求している。
POST /axis/services/Estimate HTTP/1.0 Content-Type: text/xml; charset=utf-8 Accept: application/soap+xml, application/dime, multipart/related, text/* User-Agent: Axis/1.1beta Host: localhost Cache-Control: no-cache Pragma: no-cache SOAPAction: "" Content-Length: nnnn <?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <ns1:getPrice soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://unitec-denki.utj.co.jp/schema/2003/"> <Code xsi:type="xsd:string">code-001</Code> <Value xsi:type="xsd:int">30</Value> </ns1:getPrice> </soapenv:Body> </soapenv:Envelope>
上記の要求に対するSOAP応答メッセージは以下のリストに示すとおりになる。価格として「1575(円)」が返されている。
HTTP/1.1 200 OK Content-Type: text/xml; charset=utf-8 Date: Wed, 12 Mar 2003 15:06:08 GMT Server: Apache Coyote/1.0 Connection: close <?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <ns1:getPriceResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://unitec-denki.utj.co.jp/schema/2003/"> <getPriceReturn xsi:type="xsd:int">1575</getPriceReturn> </ns1:getPriceResponse> </soapenv:Body> </soapenv:Envelope>
これらのSOAPメッセージをやりとりするWebサービスのインターフェイスは、以下のリストに示したWSDL文書(ただしwsdl:types要素は省略されている)によって記述することができる。今回の解説記事を思い出しながらWSDL文書を概観して、WSDL文書の大まかな構造のイメージをつかんでいただきたい。
<?xml version="1.0" encoding="shift_jis"?> <wsdl:definitions targetNamespace="http://unitec-denki.utj.co.jp/schema/2003/" xmlns:impl="http://unitec-denki.utj.co.jp/schema/2003/" xmlns:intf="http://unitec-denki.utj.co.jp/schema/2003/" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <wsdl:message name="getPriceRequest"> <wsdl:part name="Code" type="xsd:string"/> <wsdl:part name="Value" type="xsd:int"/> </wsdl:message> <wsdl:message name="getPriceResponse"> <wsdl:part name="getPriceReturn" type="xsd:int"/> </wsdl:message> <wsdl:portType name="Estimate"> <wsdl:operation name="getPrice" parameterOrder="Code Value"> <wsdl:input name="getPriceRequest" message="impl:getPriceRequest"/> <wsdl:output name="getPriceResponse" message="impl:getPriceResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="EstimateSoapBinding" type="impl:Estimate"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getPrice"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getPriceRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://unitec-denki.utj.co.jp/schema/2003/"/> </wsdl:input> <wsdl:output name="getPriceResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://unitec-denki.utj.co.jp/schema/2003/"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="EstimateService"> <wsdl:port name="Estimate" binding="impl:EstimateSoapBinding"> <wsdlsoap:address location="http://localhost:8080/axis/services/Estimate"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
今回は、WSDLの用途やWSDL文書の基本的な構造を説明した。もっとも、初めてWSDLを学ぶ方の場合、この説明でWSDL文書を読んで理解できる、ということにはならなかったかもしれない。そこで次回は、読者が簡単なWSDL文書を読んだり、カスタマイズできるようになることを目標にして、WSDLの各要素について詳細に解説することにしよう。
Copyright © ITmedia, Inc. All Rights Reserved.