レベル: 中級 Russell Butek (butek@us.ibm.com), IT Specialist, IBM
2008年 2月 28日 私達は誰しも、WSDL (Web Services Description Language) 障害を定義することは良いことだと考えています (もしそう思わない人がいるなら、その人はおそらくこの記事を読まないでしょう)。WSDL 障害を定義する方法はいくつかありますが、それらのうち、再利用可能な WSDL 障害を提供できるのは一部の方法のみです。この記事では、再利用可能な WSDL 障害のためのテンプレートを示し、このテンプレートをどのように再利用するのか、また避けなければならないいくつかの事項について説明します。
再利用可能な障害 (fault) を定義するためのテンプレート
どうすれば定義済みの障害を再利用可能できるのかを詳しく説明する前に、再利用可能な障害の一例を見てみましょう。リスト 1 は XML スキーマを示しており、またリスト 2 は WSDL を示しています。
リスト 1. 再利用可能な障害のスキーマのテンプレート
<xsd:schema
targetNamespace="urn:SchemaTemplates"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="Fault">
<xsd:sequence>
<xsd:element minOccurs="0" name="reason" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema> |
リスト 2. 再利用可能な障害の WSDL のテンプレート
<wsdl:definitions
targetNamespace="urn:WSDLTemplates"
xmlns:tns="urn:WSDLTemplates"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<xsd:schema
targetNamespace="urn:WSDLTemplates"
xmlns:tns="urn:WSDLTemplates"
xmlns:t="urn:SchemaTemplates"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="urn:SchemaTemplates" schemaLocation="Fault.xsd"/>
<xsd:element name="op1" type="tns:op1"/>
<xsd:complexType name="op1">
<xsd:sequence>
<xsd:element name="input" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="op1Response" type="tns:op1Response"/>
<xsd:complexType name="op1Response">
<xsd:sequence>
<xsd:element name="output" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="fault" type="t:Fault"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="op1RequestMsg">
<wsdl:part name="op1Parameters" element="tns:op1"/>
</wsdl:message>
<wsdl:message name="op1ResponseMsg">
<wsdl:part name="op1Result" element="tns:op1Response"/>
</wsdl:message>
<wsdl:message name="faultMsg">
<wsdl:part name="fault" element="tns:fault"/>
</wsdl:message>
<wsdl:portType name="Interface">
<wsdl:operation name="op1">
<wsdl:input name="op1Request" message="tns:op1RequestMsg"/>
<wsdl:output name="op1Response" message="tns:op1ResponseMsg"/>
<wsdl:fault name="fault" message="tns:faultMsg"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="Binding" type="tns:Interface">
<soap:binding
style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="op1">
<soap:operation soapAction=""/>
<wsdl:input name="op1Request">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="op1Response">
<soap:body use="literal"/>
</wsdl:output>
<wsdl:fault name="fault">
<soap:fault use="literal" name="fault"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="Service">
<wsdl:port name="Port" binding="tns:Binding">
<soap:address location="http://www.example.org/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions> |

 |
再利用のレベル
このパターンに従って WSDL を定義すると、再利用可能な障害が得られます。しかし再利用可能といっても、いくつかのレベルがあり、ここで示すような完全に再利用可能なものにする必要があるわけではありません。ではこれらのレベルを見てみましょう。
WSDL 内での再利用
WSDL 内での再利用は、ローカル・レベルでの再利用、つまりある WSDL ファイル内での再利用です。WSDL 内での再利用を実現するためには、不必要な関連付け、特に障害名の中に操作 (operation) 名を入れることを避けます。これは当然のプラクティスのように思えますが、一部のツールはそうした障害名を作成してしまうのです。例えば、メッセージ名が op1_faultMsg として生成されるかもしれません。ツールやグラフィカル・エディターは大量の単純作業を行ってくれるため、作業は楽になりますが、場合によると、そうしたツールやグラフィカル・エディターが生成するものは皆さんが望むものと正確には同じではないかもしれません。もし障害が操作名を含んでいるとすると、例えば op2 という新しい操作を作成し、op1 の障害を再利用したい場合、op2 が op1_faultMsg を参照するのは少し変に見えます。op1_faultMsg が参照するスキーマ要素と同じスキーマ要素を参照する op2_faultMsg という名前の別の WSDL メッセージを作成することはできますが、それは必要のない余分なオーバーヘッドです。障害メッセージの名前と操作名とが関連しないようにすれば、変に見えることなくそのメッセージを再利用することができます (リスト 3)。
リスト 3. WSDL に op2 を追加する
.
.
.
<wsdl:operation name="op2">
<wsdl:input name="op2Request" message="tns:op2RequestMsg"/>
<wsdl:output name="op2Response" message="tns:op2ResponseMsg"/>
<wsdl:fault name="fault" message="tns:faultMsg"/>
</wsdl:operation>
.
.
.
|
WSDL 間での再利用
WSDL 間での再利用は、複数の WSDL が同じ障害を使用して WSDL 間で再利用しあうということです。この場合には次の 2 つのことを避ける必要があります。
- 当然ですが、WSDL の types 要素の中で障害を定義してはいけません。WSDL の types 要素の中で直接定義されるものは、その WSDL からしか見えず、他の WSDL が再利用することはできません。
- 2 番目はもっと曖昧であり、プログラミング言語へのマッピングを考える必要があります。障害の型を見てください。
fault に含まれるストリング・フィールドは 1 つであるため、皆さんは単純な方法を取ろうとしてストリングを障害要素の中に直接入れてしまい、t:Fault を使ってストリングを利用するということをしないかもしれません。一部のツールはこのような障害を作成してしまいます (リスト 4)。
リスト 4. 単純すぎる障害
.
.
.
<xsd:schema ...>
.
.
.
<xsd:element name="fault" type="xsd:string"/>
</xsd:schema>
.
.
.
<wsdl:message name="faultMsg">
<wsdl:part name="fault" element="tns:fault"/>
</wsdl:message>
.
.
. |
スキーマ要素とスキーマ型を再利用することはできますが、この WSDL がマッピングされるプログラミング言語のことを考えてみてください。言語のマッピング (例えば JAX-RPC (Java™ API for XML-based RPC) など) では、スキーマ型は直接的な方法で言語の構成体にマッピングされます。しかし、要素がどのようにマッピングされるかは必ずしも明白ではありません。JAX-RPC の場合には、障害は例外クラスにマッピングされます。障害が型で定義されている場合には、例外の名前とパッケージは障害の型名と名前空間からマッピングされます。障害が単純に要素として定義されている場合は、例外の名前はメッセージ名からマッピングされ、そしてパッケージはメッセージの名前空間からマッピングされます (リスト 5)。従ってその障害は、そのメッセージを含む名前空間の中でのみ再利用可能であり、どこでも再利用可能なわけではありません。既存の障害要素を再利用する別の障害メッセージを定義することもできますが、JAX-RPC はそれをまた別の例外にマッピングし、既存の例外を再利用しません。
リスト 5. リスト 4 の WSDL の Java シグニチャー
public String op1(String input) throws RemoteException, WSDLTemplates.FaultMsg;
|
オブジェクトの再利用
最後の再利用レベルは、さらにもう少し抽象的です。これまで定義したような方法で障害を定義すると、その障害は単なる障害であるだけではなく、データ型でもあります。これは、SOAP 障害の外で障害データが必要な場合、例えばバッチ処理を行う際などに特に便利です。単純な操作では、1 つの入力 (input) セットと 1 つの出力 (output) セットがあります。この操作をバッチ処理する場合には、その操作には入力セットの配列と出力セットの配列が含まれます。バッチ処理ではない、通常の操作で障害がスローされることもある場合には、障害データを出力配列に格納するための方法を用意する必要があります。この記事のように障害を定義すれば、それは簡単です。リスト 6 と リスト 7 はバッチの例を示しています。この方法はリスト 1 とリスト 2 の XSD (XML Schema Definition) と WSDL の上に構成されており、(batchOp1 という) op1 のバッチ・バージョンと、その追加のデータ型が追加されています。
リスト 6. 障害を持つバッチ操作のための XSD
<xsd:schema
targetNamespace="urn:SchemaTemplates"
xmlns:tns="urn:SchemaTemplates"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="Fault">
<xsd:sequence>
<xsd:element minOccurs="0" name="reason" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Response" abstract="true"/>
<xsd:complexType name="NormalResponse">
<xsd:complexContent>
<xsd:extension base="tns:Response">
<xsd:sequence>
<xsd:element name="response" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="FaultResponse">
<xsd:complexContent>
<xsd:extension base="tns:Response">
<xsd:sequence>
<xsd:element name="fault" type="tns:Fault"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema> |
リスト 7. 障害を持つバッチ操作のための WSDL
<wsdl:definitions
targetNamespace="urn:WSDLTemplates"
xmlns:tns="urn:WSDLTemplates"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<xsd:schema
targetNamespace="urn:WSDLTemplates"
xmlns:tns="urn:WSDLTemplates"
xmlns:t="urn:SchemaTemplates"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="urn:SchemaTemplates" schemaLocation="Fault.xsd"/>
<xsd:element name="op1" type="tns:op1"/>
<xsd:complexType name="op1">
<xsd:sequence>
<xsd:element name="input" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="op1Response" type="tns:op1Response"/>
<xsd:complexType name="op1Response">
<xsd:sequence>
<xsd:element name="output" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="batchOp1" type="tns:batchOp1"/>
<xsd:complexType name="batchOp1">
<xsd:sequence>
<xsd:element name="input" type="xsd:string" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="batchOp1Response" type="tns:batchOp1Response"/>
<xsd:complexType name="batchOp1Response">
<xsd:sequence>
<xsd:element name="output" type="t:Response" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="fault" type="t:Fault"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="op1RequestMsg">
<wsdl:part name="op1Parameters" element="tns:op1"/>
</wsdl:message>
<wsdl:message name="op1ResponseMsg">
<wsdl:part name="op1Result" element="tns:op1Response"/>
</wsdl:message>
<wsdl:message name="faultMsg">
<wsdl:part name="fault" element="tns:fault"/>
</wsdl:message>
<wsdl:message name="batchOp1RequestMsg">
<wsdl:part name="batchOp1Parameters" element="tns:batchOp1"/>
</wsdl:message>
<wsdl:message name="batchOp1ResponseMsg">
<wsdl:part name="batchOp1Result" element="tns:batchOp1Response"/>
</wsdl:message>
<wsdl:portType name="Interface">
<wsdl:operation name="op1">
<wsdl:input name="op1Request" message="tns:op1RequestMsg"/>
<wsdl:output name="op1Response" message="tns:op1ResponseMsg"/>
<wsdl:fault name="fault" message="tns:faultMsg"/>
</wsdl:operation>
<wsdl:operation name="batchOp1">
<wsdl:input name="batchOp1Request" message="tns:batchOp1RequestMsg"/>
<wsdl:output name="batchOp1Response" message="tns:batchOp1ResponseMsg"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="Binding" type="tns:Interface">
<soap:binding
style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="op1">
<soap:operation soapAction=""/>
<wsdl:input name="op1Request">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="op1Response">
<soap:body use="literal"/>
</wsdl:output>
<wsdl:fault name="fault">
<soap:fault use="literal" name="fault"/>
</wsdl:fault>
</wsdl:operation>
<wsdl:operation name="batchOp1">
<soap:operation soapAction=""/>
<wsdl:input name="batchOp1Request">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="batchOp1Response">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="Service">
<wsdl:port name="Port" binding="tns:Binding">
<soap:address location="http://www.example.org/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions> |
batchOp1 は Response の配列を返します。Response は抽象型なので、この配列に具体的な拡張機能を格納する必要があります。Response 配列の要素は NormalResponse オブジェクトまたは FaultResponse オブジェクトを含みます。
 |
このバッチ・モデルの、実際の拡張機能 In a real-world 実際の場合、おそらく複数の障害があるはずです。そうした複数の障害に対応するためには、障害の階層構造を作成し、そしてすべての障害の基本クラスを FaultResponse 型にします。 |
|
まとめ
WSDL 障害を可能な限り拡張可能にすると便利です。その方法をこの記事で学ぶことができたことを願います。
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | |  | Russell Butek は IBM の SOA/Web サービスのコンサルタントです。彼は IBM の WebSphere Web サービス・エンジンの開発者の 1 人であり、JAX-RPC JSR (Java Specification Request) エキスパート・グループのメンバーでもあります。Apache の Axis SOAP エンジンの実装に参加し、Axis 1.0 を JAX-RPC に準拠させるために貢献しました。 |
記事の評価
|