はじめに
今日ではWebサービスのメッセージングやXMLベースのデータ転送が大量に行われているため、これらのメッセージ交換を構造化された方法で表現する必要性が出てきています。この必要性をふまえて開発されたのがWebサービス記述言語(Web services Description Language:WSDL)です。WSDLは、Webサービスを関連メッセージの交換を行うエンドポイント群として記述するためのXML文法を定義しています。WSDL文書はWebサービスを記述するための標準的な手段であり、Webサービスで使用されるデータ型や、そのWebサービスの通信相手となるURL、Webサービスの名前などを定義します。
WSDL文書は、B2Bの相互運用性を実現するための重要な鍵になりつつあります。WSDL文書では、Webサービスの開発に使用したプログラミング言語の種類に関係なく、汎用的なWebサービス記述を行うことができます。開発者はWSDL文書に基づいて、対応するWebサービスと通信するクライアントコードを生成できます。このような汎用的な形式のサービス/コンポーネント記述という手法は、過去にもさまざまなバイナリ形式のインターフェイス記述言語(Interface Description Languages:IDL)という形で試みられてきましたが、WSDLとWebサービスという組み合わせほど普及したものは今までありませんでした。
WSDLベースのサービス記述が成功した1つの理由は、XMLの普及と、実質的にどんなプログラミング言語のどんなデータ型でも汎用的な方法で定義できるというXMLの能力にあります。この記事では、Javaプログラミング言語でカスタムWSDLデータ型を扱う方法について説明します。
WSDLの概要
WSDL文書とは、Webサービスをメッセージ対応またはプロシージャ指向の抽象的なエンドポイント群として記述するXML文書です。これらの操作やメッセージと、それに関連するデータ型は概念的に記述され、その後、必要に応じてネットワークプロトコル、メッセージ形式、プログラミング言語へと具体的にバインドされます。
WSDL文書では、Webサービスを記述するために次の要素を定義します。
- types……データ型定義
- message……転送されるデータの抽象定義
- operation……サービスプロシージャの抽象記述
- portType……1つまたは複数のエンドポイントでサポートされる抽象操作の集まり
- binding……特定のポートタイプに対する具体的なプロトコルとデータ形式
- port……バインディングおよびネットワークアドレスとして定義される1つのエンドポイント
- service……関連するエンドポイントまたはポートの集まり
WSDLとデータ型
Webサービスプロバイダにとっては、非常に幅広い範囲のWebサービスコンシューマに理解してもらえるデータ型システムを公開することは難しい課題です。しかし、効果的な通信を行うためには、Webサービスのコンシューマとプロバイダの双方がデータ型システムを理解していることが不可欠です。各種のプログラミング言語にはそれぞれ独特の表現方法があるため、共通のデータ型システムを作成することが最重要課題になります。
汎用的なIDLや、COM、DCOM、CORBAなどの共通データ型システムといった以前の試みとは異なり、WSDLでは、共通データ型の問題を解決するために、すべてを包含するデータ型標準を作成するのではなく、最大限の柔軟性を実現するという方法を採用しています。つまり、WSDLは1つのデータ型システムにバインドされるものではありません。その代わりに、W3CのXML Schema仕様を基準の型システムとして推奨しており、この非常に広い範囲で使われているデータ型システムを既定のものとして扱っています。
WSDLとXML Schema仕様
WSDLの型定義には任意のエンコーディング形式を使用できますが、WSDLの仕様では、XML Schema Definitions(XSD)を使用することが推奨されています。XSDまたはXML Schemaは、XML文書内の構造を定義するための文書型定義(Document Type Definition:DTD)標準を置き換えることを意図して定められたW3C標準です。XML Schemaでは、プログラミング言語に依存しない、包括的な一連のプリミティブ/単純データ型が定義されており、double
、string
、integer
などに加えて、事前定義された単純型を用いて複雑な型を作成するメカニズムも定義されています(表1を参照)。
単純型 | 例 |
string | This is a string |
normalizedString | This is a normalized string |
token | This is a token |
base64Binary | GpM7 |
hexBinary | 0FB7 |
integer | -1、0、103 |
positiveInteger | 1、2、215 |
negativeInteger | -563、-2、-1 |
nonNegativeInteger | 0、1、2、672 |
nonPositiveInteger | -37 -2、-1、0 |
long | -9223372036854775808、... -1、0、1、... 9223372036854775807 |
unsignedLong | 0、1、... 18446744073709551615 |
int | -2147483648、... -1、0、1、... 2147483647 |
unsignedInt | 0、1、...4294967295 |
short | -32768、... -1、0、1、... 32767 |
unsignedShort | 0、1、... 65535 |
byte | -128、...-1、0、1、... 127 |
unsignedByte | 0、1、... 255 |
decimal | -1.23、0、123.4、1000.00 |
float | -INF、-1E4、-0、0、12.78E-2、12、INF、NaN |
double | -INF、-1E4、-0、0、12.78E-2、12、INF、NaN |
boolean | true、false、1、0 |
duration | P1Y2M3DT10H30M12.3S |
dateTime | 1999-05-31T13:20:00.000-05:00 |
date | 1999-05-31 |
time | 13:20:00.000、13:20:00.000-05:00 |
gYear | 1999 |
gYearMonth | 1999-02 |
gMonth | -05 |
gMonthDay | -05-31 |
gDay | --31 |
Name | shipTo |
QName | po:USAddress |
NCName | USAddress |
anyURI | http://www.example.com/,http://www.example.com/doc.html#ID5 |
language | en-GB、en-US、fr |
WSDLの<types>
要素では、WebサービスコンシューマとWebサービスプロバイダの間で交換されるデータ型を定義します。WSDL文書で定義されるWebサービスが組み込みのXML Schema単純型のみを使用している場合は、<types>
要素を含める必要はありません。一方、独自の型を使用する場合は、この要素を使用して定義できます。リスト1に、<types>
要素を含んだ単純なWSDL文書を示します。
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions 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:types> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:helloworld"> <import namespace= "http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="HelloWorld"> <sequence> <element name="message" type="string" minOccurs="1"/> </sequence> </complexType> </schema> </wsdl:types> <wsdl:message name="HelloWorldResponse"> <wsdl:part name="return" type="HelloWorld"/> </wsdl:message> <wsdl:message name="HelloWorldRequest"> </wsdl:message> <wsdl:portType name="HelloWorldService"> <wsdl:operation name="HelloWorld"> <wsdl:input name="HelloWorldRequest" message="intf:HelloWorldRequest"/> <wsdl:output name="HelloWorldResponse" message="intf:HelloWorldResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="AxisServletSoapBinding" type="intf:HelloWorldService"> <wsdlsoap:binding style="rpc" transport= "http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="HelloWorld"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="HelloWorldRequest"> <wsdlsoap:body use="encoded" encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:helloworld"/> </wsdl:input> <wsdl:output name="HelloWorldResponse"> <wsdlsoap:body use="encoded" encodingStyle= "http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:helloworld"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="HelloWorldService"> <wsdl:port name="HelloWorldServlet" binding="intf:AxisServletSoapBinding"> <wsdlsoap:address location="http://127.0.0.1/services/HelloWorld"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
WSDL文書での新しいデータ型の宣言
XML Schema仕様には、カスタムデータ型を定義するための機能が用意されています。単純なXML Schemaデータ型ではなく、抽象的な方法で表現した方が便利なデータを扱うWebサービスの場合は、その抽象的な方法をWSDLの<types>
要素の中で新しいデータ型として宣言することができます。リスト1の例では、カスタムデータ型を次のように定義していました。
<complexType name="HelloWorld"> <sequence> <element name="message" type="string" minOccurs="1"/> </sequence> </complexType>
この定義では、message
データ型を単純な文字列として表しています。さらに、この新しい型定義では、minOccurs
属性に0より大きな値を設定することで、この要素は必須であるという制約をデータ型に追加しています。
カスタムデータ型のもっと洗練された使い方としては、次のようにユーザーの連絡先情報を含めるという方法が考えられます。
<complexType name="AddressType"> <sequence> <element name="streetName" type="string" minOccurs="1"/> <element name="city" type="string" minOccurs="1"/> <element name="state" type="string" minOccurs="1"/> <element name="zip" type="string" minOccurs="1"/> <element name="phoneNumber" type="string" minOccurs="1"/> </sequence> </complexType>
この例の<AddressType>
では、ユーザーの連絡先情報をカプセル化するカスタムデータ型を定義しています。<state>
要素が単純な文字列として定義されており、その要素には実質的に、どんな長さのどんな内容のテキストも入力できるということに注目してください。堅牢性を高めたい場合は、state
要素に「2文字の略称のみ受け付ける」という制約を課します。そのためには、カスタムのtwo-letter-state
データ型を定義した後で、それを<AddressType>
データ型の中で参照します。2文字に制限したカスタム文字列データ型の定義は次のようになります。
<simpleType name="two-letter-state"> <restriction base="string"> <length value="2"/> </restriction> </simpleType>
コード内で表現されているXSDスキーマ内のデータ型定義とJava(またはその他の言語)内のオブジェクト定義との関係は、比較的容易に見て取ることができます。マッピングソフトウェアを使用すると、この関係を明示することができます。
XSDデータ型とJavaデータ型
Javaプログラミング言語に用意されているデータ型は、標準XSDデータ型の大部分にマッピングすることができます。表2に、XSDデータ型とJavaデータ型のマッピングを示します。
XSDデータ型 | Javaデータ型 |
base64Binary | byte[] |
hexBinary | byte[] |
boolean | Boolean |
byte | Byte |
dateTime | java.util.Calendar |
date | java.util.Calendar |
time | java.util.Calendar |
decimal | java.math.BigDecimal |
double | Double |
float | Float |
hexBinary | byte[] |
int | Int |
unsignedShort | Int |
integer | java.math.BigInteger |
long | Long |
unsignedInt | Long |
QName | javax.xml.namespace.QName |
short | Short |
unsignedByte | Short |
string | java.lang.String |
anySimpleType | java.lang.String |
表2は、単純データ型マッピングの包括的な一覧を示しています。しかし、もっと複雑な抽象化が必要で、カスタム型宣言を伴う拡張XSDデータ型が必要な場合には、Javaデータ型とのマッピングを示す表はもっと複雑になります。このようなカスタム型宣言のマッピングについて説明することがこの記事の目的ですが、その前に、マッピング操作を実装するために使うXMLツールの概要を簡単に見ておきます。