レベル: 上級 Wangming Ye (yme@us.ibm.com), Software Engineer, IBM
2004年 12月 21日 Webサービスをつなぎ合わせ、組織間にまたがるビジネス・プロセスを構築するためには、プログラムに参加する関係者が同一の標準モデルに従い、独自の実装を外部に露出しないようにする必要があります。長年に渡るプロトコル標準化に向けての共同作業を通して、ベンダー間でのインターオペレビリティーを推進するための努力がなされた結果、大きな前進が見られています。しかしながら、Webサービスが継ぎ目なくやり取りできるという究極の目標は相変わらず常に困難を伴い、また大きな議論の元にもなっています。この記事では、プラットフォームにまたがってWebサービスを統合する上で問題となる、インターオペレビリティーにまつわる幾つかの共通原因を探ります。そして .NETとJ2EE技術の間にまたがる、やり取りのスタイルや基本データ型、構造、そして名前空間などの問題を著者と共に考えます。問題を回避し、統合の成功に導くためのベスト・プラクティスを、Wangming Yeが解説して行きます。シリーズ第1回の今回は、WSDL設計の重要性を強調し、またWebサービスのインターオペレビリティーにおいて一般的な、RPC/エンコード方式の強みと落とし穴を解析します。
最初に
Webサービス技術は、本質的に異なるアプリケーションを継ぎ目なく統合することを約束し、そのための希望を与えています。しかし企業アプリケーションは異なった技術やプラットフォームを元に構築されており、様々なビジネスにまたがって統合するということは、決して単純な課題ではありません。比較的最近登場した、Webサービス用のBPEL(Business Process Execution Language)は、Webサービスの振る舞いを規定するための高水準な記述言語です。BPELでは、Webサービスをビジネス・プロセスとして調和させるための、標準的で移植性のある言語を提供しています。主なベンダーがBPELを支持しているため、IBM® WebSphere® Studio Application Developer Integration Edition (Application Developer) など、ビジネス・プロセス設計を自動化するIDEツールが市場に登場しています。このツールを利用することによってWebサービスの統合にまつわる膨大な量のコーディングが不要になり、またWSDLファイルをこのツールの中にドラッグ・アンド・ドロップするだけで、ビジネス・プロセスを構築できるようになります。このツールは、対象のWebサービスに対するクライアント・スタブを自動生成すると期待されています。そのためWebサービス統合の成否は今や、下にある高度なツールのサポートに大きく依存することになります。これはつまり、対象となるWebサービスのインターオペレビリティーを確実に最初から確保するために、開発者がベスト・プラクティスに従うよう、今まで以上に強く求められていることを意味しています。
今回と今後の記事でこれから説明するように、次のような幾つかの問題に注目する必要があります。
- WSDLでのWebサービス意味体系を実装コードから得るために、ベンダー・ツールを使うと便利です。ところがそれは、異種構成の環境(例えばJ2EE技術と.NETなど)におけるWebサービスのインターオペラビリティーにとって中心となる、メッセージ・スキーマの設計を無視してしまうことになります。
- 一般的なRPC/エンコード方式は容易かつ柔軟であり、また開発者が慣れているため、魅力的な選択肢となっています。ところが抽象的なSOAPエンコーディングのデータ・モデル実装はベンダー間で異なり、それをそろえることは困難なため、Webサービスのインターオペレビリティーにとって大きな障害になります。
- 弱く型定義されたコレクション・オブジェクトやヌル要素を含む配列、また、ある種のネイティブ・データ型はどれも、インターオペレビリティーに関して特別な問題を提起します。具体的には下記のような問題です。
- 弱く型定義されたコレクション・オブジェクトを表すXML Schemasを正確に解釈し、正しいネイティブ・データ型にマップすることは、ベンダー・ツールでは不可能
- ヌル要素を含む配列のXML表現は、.NETとWebSphereとの間で異なる
- ネイティブ・データ型とXSDデータ型は一対一のマッピングを共有しないため、変換の過程で情報や正確さが失われる可能性がある
- .NETとJava技術では名前付けの規則が異なるため、名前空間の競合が起きる可能性があり、また相対URI参照の使い方でも同様です。
まずはWSDLから
Webにおけるインターオペラビリティーの問題は、究極的にWSDLファイルに行き着きます。WSDLはWebサービスでのインターフェース定義言語(IDL: interface definition language)であり、クライアントとサーバーの間での契約とも言えるものです。サービスの意味体系、つまりメッセージ・タイプやデータ型、WSDLファイルでのやり取り形式などは、疎結合のシステムを構築する上での鍵となります。WSDLでは特定な型システムを強制してはいませんが、Webサービスのコミュニティーでは、XSD(XML Schema data types)が広く使われています。
XSDでは広範な種類のプリミティブ型を組み込みで持っており、さらにサービス・プロバイダーが、カスタムの複合型を定義することもできるようになっています。XSD型システムは、いかなるプログラミング言語の型システムよりも洗練され、かつ強力です。そしてさらに重要なことは、言語に依存しないということです。そのためWebサービスの意味体系を定義する上で、WSDLは合理的な出発点となっています。
理想的には、COMやCORBAでのIDLと同じように、まずWSDLを作って編集すべきです。つまりWebサービスとそのクライアントを特定な実装言語で構築する前に、WSDLでのサービス意味体系に基づいて、インターフェースやメッセージ、データ型を定義すべきなのです。
 |
Webサービスのインターオペラビリティーにおけるベスト・プラクティスの要約
- まずXSDとWSDLを設計し、それからスキーマとインターフェースに対してプログラムする。
- できるだけ、RPC/エンコード方式を使わないようにする。
- 弱く型定義されたコレクション・オブジェクトはどれも、Webサービス・メソッドへのシグニチャーとして、具象型の単純配列でラップする。。
- Webサービスのクライアントとサーバーとの間で、ヌル要素を持つ配列を渡し合わないようにする。
- Webサービス・メソッドでは、符号なしの数字データ型を露出しない。このデータ型を露出して伝送する場合には、ラッパー・メソッドを作ることを考える。
- XSD型を、ある言語で値型にマップし、別の言語で参照型にマップする場合には、十分注意する。複合型を定義して値型をラップし、その複合型をヌルに設定してヌル値を表すようにする。
- WSDL文書ではベースURIが厳密に定義されないので、名前空間宣言では相対URI参照を使わないようにする。
- 名前付けの規約がベンダー間で異なることによる競合を避けるために、各Webサービスに対して固有のドメイン名を与える。一部のツールではこの問題を解決するために、パッケージに対して名前空間をカスタム・マッピングしたり、パッケージ名をリファクタリングしたりできるようになっています。
- WS-I(Web Services Interoperability Organization) 準拠を検証するための、総合的なテスト・スイートを開発する。
|
|
ところが実際には、熟練したプログラマーでさえ、逆のことをしがちです。彼らはJavaインターフェースなど、実装言語特有のインターフェースから始め、ベンダーのツールに依存することによって、その実装コードからWSDLでのサービス意味体系を引き出そうとします。そして、どのようにWebサービスを呼ぶべきかをWSDLから割り出すように、Webサービスのクライアントに任せてしまうのです。結局彼らは、高度なWebサービスを構築して実行する前に、WSDLについて知る必要すらありません。自分たちのクライアントとサーバーを、同質の環境で実行するだけで済ませてしまうかも知れないのです。つまりJ2EEプラットフォームまたは.NETプラットフォームのどちらかのみで実行し、両方では実行しないかもしれない、ということです。
今日のベンダーのIDEツールは、すべてを自動生成でき、WSDLを含めて、全くコードを書く必要がなくなるような方向に向かっています(少なくとも多くの人がそのように宣伝し、またそのように望まれています)。その方が生産的であり、また(ツールが適切で堅牢であれば)人がコーディングするよりもエラーが少なくなるため、この傾向は魅力的です。Webサービスとクライアントが同じツールキットを使う単一のプラットフォームでは、インターオペラビリティーは問題になりません。
ところが、異種構成の環境にまたがってインターオペレビリティーが要求されるようになると、危険性が顕在化します。つまりよく考えないと、Webサービスのやり取りに鍵となる成果物を実装言語から生成し、プラットフォーム依存のツールを使って、WSDLでの、言語に依存しない成果物にマップすることになるのです。この、ツールが生成したWSDLから、クライアント・プラットフォームのツールがサービス・プロキシーを生成すると、別のレベルのマッピングが起こります。このプロセスは、WSDLがWebサービスでのIDLであるという厳格な事実から外れていることになります。言語に依存しないWSDLこそが共通の基盤となるべきなのであって、ツールをこのように使うことは、マッピングの課程で情報が失われる可能性を倍加させることになります。
これはツールを捨てるべきだとか、ベンダーはツールの生産やマーケティングを中止すべきだ、ということではありません。今日の企業アプリケーション開発の現場で、自動化は極めて重要になっています。ツールは強力です。ポイントは、その力をどのように利用するか、なのです。こうしたツールを使って骨格だけのWSDLを生成し、これを出発点としたりテンプレートとしたりすることができます。ただしスキーマやメッセージ部分、データ・バインディングは、WS-I勧告に従って注意深く設計する必要があります。データベースを効率化したいからといって、データベース・スキーマをツールに生成させたりしないのと同じように、効率的なWebサービス・メッセージやデータ型を手動で設計することを忘れるべきではありません。時には要素名であっても、相手となるプラットフォームが使う名前付けの規則を考慮に入れて、注意深く選択する必要があります。WSDLはWebサービスのインターオペラビリティーにとって唯一の、そして最も重要な成果物なのです。プログラマーは生のXMLメッセージに対するプログラム方法を学ぶ必要があり、また少なくともXSDやWSDL、それにSOAPメッセージの読み方も学ぶ必要があります。
まだRPC/エンコード方式を使っているのですか?
WS-I Basic Profile 1.0ではインターオペラビリティーのために、リテラルXMLを使うように推進しており、soap:Envelopeにsoap:encodingStyle属性を使ったりsoap:Body要素の下層(descendents)を使ったりすることを禁止しています。ですからWS-I標準がサポートしているのは、RPC/literal andRPC/リテラルと、文書/リテラルという、2つのフォーマットのみです。ただし、RPC/リテラルをサポートするWebサービス・ツールキットはあまり多くないので、現実的にはインターオペラビリティーの標準として、文書/リテラルが唯一のものだ、ということになります。
ところがRPC/エンコード方式による方法は、XML Schema やWSDLが登場するはるか以前から使われていました。その当時でも、一部のエンコード・ルールはXSDで表現することができませんでした。SOAPエンコーディングはWebサービスにおけるインターオペラビリティー問題の主な原因の一つとして認識されおり、ASP.NET WebMethodインフラでは文書/リテラルをデフォルトとしているという事実もありながら、大部分のJ2EE Webサービス・ツールでは、最近までRPC/エンコード方式がデフォルトになっていたのです。
RPC/エンコード方式に人気があるのは主に、リモート・プロシージャー・コールの流儀に慣れた開発者にとって単純なプログラミング・モデルであるためです。RPCバインディング・スタイルでは、メソッドの名前とパラメーターを使って、メソッドのコール・スタックを表す構造を生成します。そのためWebサービスは、すべてがSOAP RPCスタックで処理される、またカプセル化されたオブジェクトを持つ、一つの論理要素のように見えることになります。XMLベースのSOAPメッセージの直列化/非直列化を含めて、開発者が何から何まで行う必要のある文書/リテラルと比較すると、これは対照的です。
さらにSOAPエンコーディング・ルールでは、プログラム的な型をXMLに簡単にマップできる標準を定義しています。このエンコーディング・ルールは非常に柔軟であり、データ・グラフや多形性(polymorphism)を表現できるようになっています。これは、データ・オブジェクトを表現するために自然なツリー構造に依存する文書/リテラル・モデルよりも、間違いなく優れています。
RPC/エンコード方式モデルでできること、できないことを見るために、一例を挙げましょう。リスト1にあるような、それ自身のfriendを定義するSerializable Personクラスを考えてみてください。
リスト1. 自己参照を持つPersonクラス
public class Person implements java.io.Serializable {
private Person friend;
private String name;
public Person getFriend() {
return this.friend;
}
public void setFriend(Person friend) {
this.friend = friend;
}
<!-- Other setter and getter methods -->
}
|
AとBという2つのPersonをインスタンス化し、Person AをPerson Bのfriendとし、またPerson BをPerson Aのfriendとすると、循環オブジェクト・グラフを作ることになります。
リスト2. makeFriendメソッド
public Person makeFriend(Person A, Person B) {
A.setFriend(B);
B.setFriend(A);
return A;
}
|
リスト2のパブリック・メソッドを、文書/リテラルのWebサービスとして露出しようとすると、循環グラフはXMLでどのように表現されるのでしょう?
文書/リテラルの手法では簡単に行かないことが分かります。その理由は次の通りです。文書/リテラルの手法では、XML Schemaに基づいて、メッセージ・タイプを具象型として定義します。そしてXML SchemaはXSDプリミティブ型をリーフ・ノードとして、自然なツリー構造を表現します。ですから循環オブジェクト・グラフをツリー構造に変換することはできません。この場合では、Personクラスのオブジェクト・インスタンスAとBの間に循環参照があるために、オブジェクトAとBの直列化は再帰ループに入ってしまいます。例えばWith WebSphere Studioでは、最終的にスタック・オーバーフロー例外が発生することになります。これは文書/リテラルの手法では不可能というわけではありませんが、開発者は非常に大きな努力を強いられることを意味します。
メッセージ・バインディングとしてSOAPエンコーディングを使用する場合には、多重参照アクセス機構(multireference accessor)を使って循環グラフにSOAPエンコーディング・ルールを適用でき、循環参照は簡単に表現することができます。一例として、WebSphereプラットフォームで実行している、Webサービスで直列化されたXMLペイロードを見てください。これは、JohnとJasonをお互いに友達(friend)にしようとするSOAPリクエストへのレスポンスです。リスト3は、循環グラフがいかに簡単に表現できるかを示しています。
リスト3. WebSphere からの、SOAPエンコードされたレスポンス・メッセージ
<soapenv:Body soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<makeFriendResponse xmlns="http://cyclic.test">
<makeFriendReturn href="#id0"/>
</makeFriendResponse>
<multiRef id="id0" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns-
520570027:Person" xmlns:ns-520570027="http://cyclic.test">
<name xsi:type="xsd:string">John</name>
<friend href="#id1"/>
</multiRef>
<multiRef id="id1" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns-
520570027:Person" xmlns:ns-520570027="http://cyclic.test">
<name xsi:type="xsd:string">Jason</name>
<friend href="#id0"/>
</multiRef>
</soapenv:Body >
|
エンコードされた要素、Person A (John)とPerson B (Jason) に対する固有の識別子を規定するために、ID型でローカルの、unqualified属性、id0とid1をSOAPがどのように使っているかに注意してください。そしてこうした2つのID値への参照を規定するために、もう一つ別の、ローカルで、unqualified属性hrefが使われていることにも注意してください。柔軟なSOAPエンコーディング・ルールのおかげで、Object AとObject Bの間の循環参照が簡単に表現できています。
RPC/エンコード方式モデルは、J2EEや.NETなど、単一の構成領域の中でプログラミングすることに慣れた伝統的オブジェクト指向のプログラマーにとっては、非常に魅力的でした。エンコードされたSOAPメッセージを理解するための同期スタブを、SOAPメッセージを書く人と読む人の両方が持つ、という単一プラットフォームにスコープが限定されていた頃には、RPC/エンコード方式モデルを使うことによってWebサービスの設計者や実装者が非常に楽になったのです。ところがWebサービスがグローバルになるにつれ、大きな代償を要求されるようになってきました。その強力さが、プラットフォームにまたがるインターオペラビリティーに対する要求の前に、弱点になってしまったのです。インターオペラビリティーの問題を説明するために、先のWebサービス(サイドファイルのリスト4を見てください)からApplication Developerが生成したWSDLファイルを調べてみましょう。
WSDL文書では、makeFriendという操作の出力メッセージmakeFriendResponseには、Person型のメッセージ部分makeFriendReturnがあります。このスキーマによると、Person複合型はxsd:string型の直接子要素名とPerson型のfriendを持つ必要があり、それ以外の型や属性はないはずです。ところが直列化されたSOAPレスポンス・メッセージ(リスト3)は明らかに、このルールに合致しません。レスポンス・メッセージのhref属性は、定義の中に存在しません。この矛盾の中で、メッセージ受信側に対して要素AとBはPersonクラスのインスタンスであると伝えるには、どうすればよいのでしょう?
実際、このWebサービスと通信するように.NETクライアントをコード化すると、.NETクライアントはWebSphereのレスポンスを非直列化するのに失敗します。これをリスト3に示します。.NETクライアントが期待しているのは、JohnとJasonがfreindであることを表現する、次のようなレスポンス・メッセージなのです。
リスト5. SOAPエンコードされた、.NETからのレスポンス・メッセージ
<soap:Body
soap:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/"><tns:makeFriendsResponse>
<makeFriendsResult href="#id1" />
</tns:makeFriendsResponse>
<types:Person id="id1" xsi:type="types:Person">
<name xsi:type="xsd:string">John</name>
<friend href="#id2" />
</types:Person>
<types:Person id="id2" xsi:type="types:Person">
<name xsi:type="xsd:string">Jason</name>
<friend href="#id1" />
</types:Person></soap:Body>
|
このように、多重参照アクセス機構エンコーディングは強力なのですが、XSDで表現するのは簡単ではありません。そのためリスト3とリスト5を見れば分かる通り、プラットフォームによって、わずかに実装が異なります。この例では、SOAPエンコーディングとXML Schema検証との差を表しています。文書/リテラルの手法では、リテラル文書をパス・スルーし、XML SchemaによってオブジェクトのXML表現の検証と非直列化を行います。一方RPC/エンコード方式モデルではそれとは異なり、SOAPエンコーディング・ルールを使って抽象SOAPデータ・モデルを表現し、その抽象SOAPデータ・モデルの具体的な実装に関しては、ベンダーのSOAPライブラリーに頼るのです。従って、非常にプラットフォーム依存となります。その間を埋める中間的な仕様は何もありません。その結果この手法では、ベンダーによって実装が異なるままになっています。SOAPは確かに標準なのですが、SOAPの実装(Application Developer V4とV5用の、DOMベースのApache SOAPライブラリーやSAXベースのApache AXISライブラリー、そしてMS SOAP toolkit for MS .NET Framework 1.1など)は、XML Schemaがサポートされていないために僅かずつ異なるのです。
WS-I Conformance Testing Toolによるテスト準拠
WS-I Basic Profileでは、インターオペラビリティーを確保したWebサービスの構築に向けて、Web Services仕様に準拠するための指針を提供しています。WS-I Working Groupsでは、開発者が自分たちの開発するWebサービスがProfile指針に準拠しているかどうかを判定できるように、WS-I Conformance Testing Toolを開発しました。WS-I Testing Tool Analyzerを使用するとProfile Conformance Reportが生成でき、準拠している旨をWSDL文書の中に記述することもできます。現在は、C#とJava版のテスト・ツールがダウンロードで入手できます。テスト・ツールを実行することによって、WS-I Basic Profile 1.0に明らかに違反している点の大部分はレポートされます。リスト4に示すWSDL文書に対して準拠チェックを行った結果の違反レポートを、リスト6に示します。
リスト6. WS-I Testing Toolによる違反レポート
Result: failed
Failure Message: The use attribute of a soapbind:body, soapbind:fault,
soapbind:header and soapbind:headerfault does not have value
of "literal".
Failure Detail Message:
SOAPBody ({http://schemas.xmlsoap.org/wsdl/soap/}body):
required=null
use=encoded
encodingStyles=[http://schemas.xmlsoap.org/soap/encoding/]
namespaceURI=http://cyclic.test
Element Location:
lineNumber=87
|
違反メッセージは自明でしょう。soapbind:bodyやsoapbind:fault、soapbind:header、あるいはsoapbind:headerfaultにある"use=encoded"は、WS-I Profileに準拠とは見なせません。"use=literal" を使うべきなのです。文書/エンコードには何も意味はないので、RPC/エンコード方式を使うべきではない、と言っているのと同じことになります。
WS-I Conformance Testing Toolは、現実のWebサービスのインターオペラビリティーで問題となりうる全ての問題を捉えるわけではありませんが、強力なツールであることは事実です。Webサービスの開発と並行して、潜在的なインターオペラビリティー問題を捉えるための総合テスト・スイートを徐々に開発することが、ベスト・プラクティスと言えます。このツールの詳細については、参考文献に挙げた記事を参照してください。
まとめ
この記事で著者は、WSDLでWebサービスの意味体系を設計するにあたって、実装前に注意深く設計することが重要であると強調しました。またRPC SOAPエンコーディングが、なぜWebサービスのインターオペラビリティーでの大きな障害になるのかを説明し、そしてWS-I Profile準拠をテストする総合テスト・スイートを構築することの重要さを示しました。今後はインバウンド・データ型とアウトバウンド・データ型にまつわるインターオペラビリティーの問題と、名前空間の規約に関して説明する予定です。
参考文献
著者について  | |  | Wangming YeはIBM認定のEnterprise Developerであり、またSun認定のEnterprise Architect for J2EE Technologyです。Transarc Corporation(後にIBMが吸収)のDCE/DFS部門での開発者を出発点として、その後はWebSphere Edge ServerグループのWebSphere Content Distribution Frameworkの主要メンバーとして開発に従事してきました。現在はIBM Business Partner Technical Enablement組織の中のWebSphere Competency Centerで、WebSphereビジネス・パートナーに対して技術的使用可能性を提供する業務を行っています。Wangming Ye氏とのコンタクトは、yme@us.ibm.comでどうぞ。 |
記事の評価
|