ヘッダーをスキップ
Oracle Application Server Web Servicesアドバンスト開発者ガイド
10g(10.1.3.1.0)
B31869-02
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

1 相互運用可能なWebサービスの実現

この章の内容は、次のとおりです。

相互運用の必要性

Webサービス・アークテクチャの目標は、異機種のビジネス・アプリケーションが円滑に連携することです。アーキテクチャは疎結合されXML標準に基づいています。Webサービスは、サービス規約としてWeb Service Description Language(WSDL)ファイルを定義することで、その背後にあるオペレーティング・システムや開発技術にかかわらず相互に連携するよう設計されています。ただし、サービス規約が複雑なため、WSDLやSOAPなどの標準の解釈が曖昧になっています。また、ベンダー固有の機能強化や拡張が全体的な相互運用性の妨げとなっています。

ビジネス・アプリケーションは、お互いのサービスを起動する必要があります。これらのサービスが異なるテクノロジで実装されていることもあります。Webサービスの複雑さが増すと、相互運用がうまくいかないケースも増える傾向にあります。一般に公開されているWebサービスを運用しているとしたら、様々なツールキットを使用している世界中のクライアントがそのWebサービスを正常に使用できることを希望するでしょう。同じように、ビジネス・アプリケーションにも、既存のレガシー・システム上に構築されていて、インタフェースの設計があまり一般的でない他ベンダーのWebサービスとの統合または連携が必要な場合もあります。

相互運用性の問題は、プロトコル・スタックのどのレイヤーからも生じる可能性があります。トランスポート・レイヤーでは、メッセージ交換に関わるどちらの側でも、特定の物理的な転送メカニズムについて合意している必要があります。たとえば、Java以外のプラットフォームを使用している相手にJMSトランスポートの使用を期待することはできません。基本的なHTTPプロトコルを使用した方が、相互運用性が高まる理由はここにあります。メッセージ・レイヤーでは、任意のデータ・エンコーディングの使用がSOAPで事実上許可されているため相互運用は難しくなります。たとえば、Javaプラットフォームの標準のArrayListは、.NETプラットフォームのSystem.collections.ArrayListには自動的には変換されません。また、相互運用性の問題は、基本的なWSDLやSOAPのレベルでも発生します。高度なWebサービスの開発者は、セキュリティ、信頼性、トランザクション・サービスなどのQuality of Service(QOS)機能の実装を開始すると、その他にも様々な難題に直面するでしょう。

相互運用性の実現は難しい問題です。ただし、適切なガイドラインがあれば、Oracle Webサービスはその他のJ2EEベンダーのプラットフォームや、Microsoft .NETなどのJava以外のプラットフォームとシームレスに連携できます。

Webサービスの相互運用性に関わる組織

Webサービスのコミュニティで相互運用性の重要度が増すにつれ、その目標を達成するために多くの組織が設立されました。

SOAPBuildersコミュニティ

SOAPBuildersは、SOAP実装間のテストを行う相互運用性のテストベッド確立に向けて活動する開発者の、緩やかに組織化されたフォーラムです。フォーラムの参加者によって共同で定義された基準となる一連のテストを実装することで、相互運用性が証明されます。

SOAPBuildersコミュニティによって開発されたテストは、全般的にベンダーの慣例に基づいています。ただし、慣例は時とともに変わります。Webサービス・ベンダー、Webサービス開発者およびWebサービスの利用者には、正式にまとめられた、不要なものの混じっていないはっきりとしたルールが必要です。


関連資料:

SOAPBuilderテストの詳細は、http://www.whitemesa.net/を参照してください。


WS-Interoperability

Web Services Interoperability(WS-I)は、Webサービス間の相互運用可能なメッセージ交換のための一般的なプロトコルの作成、普及、サポートを行う業界のオープンな組織です。WS-Iプロファイルは、標準の適用方法に関するガイドラインおよび推奨事項です。これらのプロファイルは、基礎となる仕様に契約を追加して曖昧さをなくすことを目的としています。

WS-Iの成果物は、プロファイル、一般的なプラクティスまたはベスト・プラクティス、シナリオ、テスト・ソフトウェアおよびテスト資料です。

Webサービスは、WS-I Basic Profileに準拠するように設計する必要があります。WS-Iに準拠したサービスは明瞭な規約に同意しており、相互運用性を実現する可能性が高くなります。

たとえば、WS-I Basic Profileに準拠しているWebサービスでは、次の機能を使用する必要があります。


関連資料:

WS-Iプロファイルおよびプロファイルで定義されるルールの詳細は、http://www.ws-i.org/を参照してください。


OracleはWS-Iのメンバーで、顧客が相互運用性を実現する手助けとなるよう取り組んでいます。Oracle Application Server Web Servicesプラットフォームは非常に柔軟性が高く、相互運用性のあるWebサービスの作成を支援します。

相互運用可能なWebサービス作成の一般的なガイドライン

一般的なガイドラインの1つ目は、可能な場合にはWS-Iに準拠したWebサービスを作成することです。

ただし、WS-Iプロファイルですべての相互運用性の問題が解決するわけではありません。WS-Iプロファイルが存在する以前から、多くのWebサービスが実装されていました。また、Webサービスとして有効化しているレガシー・システムにより、設計が制限される場合もあります。

そのため、可能な場合には、開発プロセスの初期段階からWebサービス設計の秘訣を取り入れることです。次の項で、それらのガイドラインを説明します。

Webサービスをトップダウン方式で設計する

WSDLからのトップダウン方式を採用することにより、プラットフォームや言語に固有の特徴に制限されないサービス規約でWebサービスを設計できます。WSDLが既存のレガシーAPIに影響される可能性が低くなります。

最初はXSDを使用してデータ型を設計する

可能な場合には、XSDスキーマ・エディタを使用してスキーマ型を持つデータ型を設計します。.NETのDataSetデータ型やJavaコレクションなど、プラットフォーム固有のデータ型の使用は避けます。

データ型はシンプルにする

xsd:choiceなどの不必要に複雑なスキーマ・データ型の使用は避けます。最高の相互運用性はシンプルなデータ型により実現され、パフォーマンスの向上という利点ももたらします。

NULL値に注意する

NULL値を使用するケースを決定します。たとえば、配列型にNULL値を許可しますか。NULL文字列または空の文字列を使用しますか。プラットフォーム全体にNULL値を送信すると、受信者側で例外の原因となりますか。

可能な場合は、NULL値を送信しないようにします。アプリケーションでNULL値を使用する必要がある場合は、NULL値が許可されていることが明確にわかるようにスキーマ型を設計します。

WSDLの検証にコンプライアンス・テスト・ツールを使用する

WebサービスがWS-Iに準拠するよう設計されている場合は、WS-Iモニタリング・ツールを使用してメッセージを記録し、分析ツールを使用して準拠しているかどうかを検証します。


関連資料:

http://www.ws-i.org/deliverables/workinggroup.aspx?wg=testingtools/からWS-Iツールを無料でダウンロードできます。


各プラットフォームにネイティブのデータ型の違いを理解する

xsd:unsignedshortおよびxsd:unsignedintなどのスキーマ型には、常にネイティブのデータ型のダイレクト・マッピングがあるわけではありません。たとえば、Javaプラットフォームには等価のunsigned型はありません。xsd:doublexsd:floatおよびxsd:decimalなどのスキーマの数値型は、一度プラットフォームにネイティブのデータ型にマッピングされると精度が変更される可能性があります。また、xsd:string型には制限があります。文字列には無効なXML文字を含めることはできず、\r(キャリッジ・リターン)文字は\n(改行)文字にマッピングされます。

rpc-encodedメッセージ書式は使用しない

rpc-encodedメッセージ書式自体に、他のプラットフォームやクライアントとの相互運用性がないわけではありません。今日稼働しているWebサービスの多くは、rpc-encodedです。rpc-encodedメッセージ書式の使用を避ける理由は、基礎となる仕様の解釈や実装の選択の違いが相互運用性の妨げになるという問題を回避するためです。これらの問題の例には、疎配列、マルチディメンション配列、カスタム障害コードQName、タイプ付きでないペイロードなどの扱いが含まれます。

相互運用性の問題の診断および解決に関する一般的なヒント

相互運用性の問題の多くは、WSDL、ワイヤ書式、データ表現の有効性の関係を理解することで認識および解決できます。問題の原因を特定できれば、修正するのは簡単です。

図1-1に、クライアント・スタックとサービス・スタック間の相互作用を示します。WSDLはクライアント・アーティファクトの生成に使用されます。JAX-RPCまたは.NETプラットフォームに実装可能なクライアント・アプリケーションは、XML SOAPリクエスト・メッセージを生成します。アプリケーションによりそのリクエストがシリアライズされ、HTTP経由でサービスに渡されます。JAX-RPCまたは.NETプラットフォームに実装可能なサービスは、リクエストをデシリアライズして処理します。

クライアント・リクエストを処理すると、サービス・アプリケーションによってXML SOAPリクエスト・メッセージが生成され、シリアライズされてHTTP経由でクライアントに渡されます。クライアント・アプリケーションによって、レスポンスがデシリアライズされ、結果が処理されます。

図1-1 相互運用に失敗する可能性のある箇所

図1-1の説明が続きます
「図1-1 相互運用に失敗する可能性のある箇所」の説明

図の番号とアルファベットは、クライアント・サイドから見た、相互運用に失敗する可能性のある箇所を示しています。サーバー・サイドでも失敗する箇所は類似しています。次のリストでこれらの問題のカテゴリを説明します。

  1. クライアント・アーティファクトを生成するユーティリティが、WSDL(規約)の処理に失敗します。WSDLがWS-Iプロファイルに準拠していないため無効であるか、クライントのプラットフォームでサポートされていません。たとえば、.NET 1.1ではrpc-literalスタイルのWebサービスはサポートされていません。

    このタイプの失敗の詳細は、「無効または書式が不適切なWSDL」で説明されています。

  2. クライアント・アーティファクトを生成するユーティリティによりWSDLが正常に処理されますが、使用できない、または使用しにくいアーティファクトが生成されます。WSDLにツールが処理できない独自のスキーマ拡張が含まれている場合などがこのケースに該当します。

    このタイプの失敗の詳細は、「独自のデータ・バインディング拡張が含まれるWSDL」で説明されています。

  3. 実行時、実際にペイロードが処理される前に、クライアント・アプリケーションに例外がスローされます。通常、エラーは、障害コード・セットがSOAP 1.1ではClientに、SOAP 1.2ではSenderに設定されているSOAP障害に変換されます。サービスのエンドポイントが使用できないか、認証ネゴシエーションに失敗したことが理由です。

    このタイプの失敗の例は、「無効なXML文字」で説明されています。

  4. 次に示すいずれかの理由のため、サーバー・サイドからSOAP障害がスローされます。

    1. リクエストが正しい操作にルーティングされません。SOAP障害コードは、SOAP 1.1ではClient、SOAP 1.2ではSenderに設定されます。

      このタイプの失敗の例は、「同期外れのSOAPAction値」で説明されています。

    2. リクエストが正常にデシリアライズされません。SOAP障害コードは、SOAP 1.1ではClient、SOAP 1.2ではSenderに設定されます。

      このタイプの失敗の詳細は、「SOAPメッセージのNULL値」および「unsignedスキーマ数値型」で説明されています。

    3. リクエストがアプリケーション・コードで処理されません。スローされる内部例外は、未処理例外か、ビジネス・ロジック・レベルのアプリケーション固有のSOAP障害です。サーバー・アプリケーションで入力パラメータの検証に関連するエラーとみなされないかぎり、SOAP障害コードはServerまたはReceiverに設定されます。

    4. レスポンスがシリアライズされません。SOAP障害コードは、ServerまたはReceiverに設定されます。

  5. 実行時、レスポンスをデシリアライズしてSOAPエンベロープのコンテンツをJavaインスタンスに変換する際に、クライアントによって例外がスローされます。

    このタイプの失敗の例は、「精度の欠落」で説明されています。

これ以降の各項では、それぞれの箇所で起こりうる失敗の詳細と例を説明します。

無効または書式が不適切なWSDL

相互運用は、WSDLの処理中に発生するエラーが原因で失敗する場合があります。これは、図1-1の1に当たります。ツールキットが異なると、WSDLの処理方法も異なります。たとえば、書式が不適切なWSDLは、あるツールキットでは問題なく受け入れられ、別のツールキットでは拒否される場合があります。

次のコード・サンプルでは、書式が不適切なWSDLがどのようにして相互運用失敗の原因となるかを示します。

例1-1に、書式が不適切なWSDLのフラグメントを示します。フラグメントには、名前が不適切な入力パラメータgetQuoteが含まれます。portTypeoperationgetQuoteという名前の入力パラメータが定義されていますが、対応するバインディング操作に入力名または出力名が指定されていないことに注意してください。デフォルトのネーミング・パターン(<operationName>Requestおよび<operationName>Response)を使用して指定されていないバインディング操作の入力名および出力名を作成すると、getQuote操作の入力パラメータに一貫性がなくなるためWSDLが無効になります。

例1-1 名前が不適切な入力パラメータが含まれるWSDLフラグメント

<portType name="qotdPortType">
  <operation name="getQuote">
    <input name="getQuote" message="tns:getQuoteRequest"/>
    <output name="getQuoteResponse" message="tns:getQuoteResponse"/>
  </operation>
</portType>
<binding name="qotdBinding" type="tns:qotdPortType">
  <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
  <operation name="getQuote">
    <soap:operation soapAction="urn:xmethods-qotd#getQuote"/>
    <input>
      <soap:body use="encoded"
                 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                 namespace="urn:xmethods-qotd"/>
    </input>
    <output>
      <soap:body use="encoded"
                 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                 namespace="urn:xmethods-qotd"/>
    </output>
  </operation>
</binding>

このWSDLからクライアント・プロキシ・クラスの生成を試行すると、.NETプラットフォームであるかOracleAS Web Servicesプラットフォームであるかにかかわらず問題が発生します。.NETプラットフォームでクライアント・プロキシC#クラスの生成を試行すると、一致するバインディングがないためにWSDLが拒否されるエラーが発生します。ただし、Oracle Application Server Web Servicesプラットフォームでは、Javaクライアント・プロキシ・クラスを生成すると、WSDLに不適切な入力名または出力名が使用されているという警告が出力されます。

WSDL仕様には、入力名および出力名が指定されていない場合、バインディング操作にportType操作のデフォルトのネーミング・パターンを使用する必要があるということが明確に指定されていません。WSDLを拒否するかどうかが明確ではありません。OracleAS Web ServicesツールキットではこのようなWSDLを受け入れ、警告を出力します。

この例で示されている起こりうる相互運用の問題は、バインディング操作とportTypeの入力にname属性を指定することで修正できます。

独自のデータ・バインディング拡張が含まれるWSDL

図1-1の2は、ツールキットが指定されたWSDLから使用可能なアーティファクトを生成できないために失敗する箇所を示しています。この問題は、WSDLに独自のデータ・バインディング拡張が含まれる場合に発生します。

次のコード・サンプルでは、独自のデータ・バインディング拡張が含まれるWSDLを処理することがどのようにして相互運用失敗の原因となるかを示します。


注意:

次のコード・サンプルでは、相互運用失敗の原因となる独自のデータ・バインディングの例として、ADO.NET System.Data.DataSetデータ型を使用しています。ただし、XMLは本質的に拡張可能であるため、これ以外の独自のデータ・バインディングを処理する際にも同じ問題が発生する可能性があります。

.NETプラットフォーム用のWebサービスを開発していて、System.Data.DataSetデータ型を戻す次のC#メソッドがあるとします。

public System.Data.DataSet ListBooks (  )

例1-2に、メソッドが.NET Webサービスとして公開された場合に、レスポンスの出力要素を表すXMLスキーマ・フラグメントを示します。

例1-2 .NET WebサービスのXMLスキーマ・フラグメント

<s:element name="ListBooksResponse">
   <s:complexType>
    <s:sequence>
      <s:element minOccurs="0" maxOccurs="1" name="ListBooksResult">
        <s:complexType>
        <s:sequence>
          <s:element ref="s:schema"/>
          <s:any/>
        </s:sequence>
        </s:complexType>
       </s:element>
      </s:sequence>
    </s:complexType>
</s:element>

WebServicesAssemblerツールを使用して、このWSDLに基づくクライアント・プロキシ・コードを生成する必要があるとします。WebServicesAssemblerはWSDLを正常に処理し、次のJavaメソッドを持つクライアント・コードが含まれる一連のプロキシ・クラスを生成します。

public javax.xml.soap.SOAPElement listBooks(ListBooks parameters) throws java.rmi.RemoteException

OracleAS Web Servicesでは、スキーマ定義からそれ以上詳細な情報を推測できないため、レスポンスはSOAPElementとして戻されます。例1-2の.NET WSDLのスキーマには、.NET DataSetデータ型を表すワイヤで受信するペイロードが完全に説明されていません。スキーマには、SOAPメッセージには2つの部分があるということのみが説明されています。1つ目はペイロードのスキーマ定義で、その後にペイロードが続いています。

例1-3に、クライアントが受信するSOAPメッセージを示します。xs:schema要素の1番目の子(<xs:element name="NewDataSet"...>)で、メッセージのペイロードが説明されています。2番目の子(<diffgr:diffgram ...>)にペイロードが含まれています。

例1-3 .NET DataSetデータ型から生成されるSOAPメッセージ

<soap:Body>
      <ListBooksResponse xmlns="http://francisshanahan.com/">
         <ListBooksResult>
            <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
               <xs:element name="NewDataSet" msdata:IsDataSet="true">
                  <xs:complexType>
                     <xs:choice maxOccurs="unbounded">
                        <xs:element name="bible_content">
                           <xs:complexType>
                              <xs:sequence>
                                 <xs:element name="Book" type="xs:string" minOccurs="0"/>
                                 <xs:element name="BookTitle" type="xs:string" minOccurs="0"/>
                              </xs:sequence>
                           </xs:complexType>
                        </xs:element>
                     </xs:choice>
                  </xs:complexType>
               </xs:element>
            </xs:schema>
            <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
               <NewDataSet xmlns="">
                  <bible_content diffgr:id="bible_content1" msdata:rowOrder="0">
                     <Book>01</Book>
                     <BookTitle>The First Book of Moses, called Genesis</BookTitle>
                  </bible_content>
                  <bible_content diffgr:id="bible_content2" msdata:rowOrder="1">
                     <Book>02</Book>
                     <BookTitle>The Second Book of Moses, Called Exodus</BookTitle>
                  </bible_content>
                  …
               </NewDataSet>
            </diffgr:diffgram>
         </ListBooksResult>
      </ListBooksResponse>
   </soap:Body>
</soap:Envelope>

WebServicesAssemblerツールでは、ペイロード・スキーマを捕捉するJava型クラスを特定できません。データセット・レコードを適切に処理するJavaクライアントを記述するにはどうしたらよいでしょうか。

次に示す2つの手順に従うことで解決できます。

  1. スキーマを取得します。コードで受信SOAPElementを解析し、スキーマの子要素を抽出してスキーマ定義を保存する必要があります。

    <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    
  2. 所有するスキーマに基づいて実際のペイロードを処理します。

    JAXBやOracle TopLinkなどのツールを使用してペイロードを処理できます。JAXBにはJava APIおよびコマンドライン・ツールがあり、スキーマから直接Javaの型保証クラスを生成する際に役立ちます。

    Oracle TopLinkは、JAXBのサポートを含むリレーショナル永続性フレームワークへの拡張オブジェクトです。ただし、TopLinkでは、視覚的なマッピング・エディタやその他多数の拡張機能も使用できます。

    好みのツールを使用し、スキーマに基づいてJava型を生成すると、実際のSOAPペイロードを処理し、スキーマに続く任意の要素を抽出できます。この要素にはタグ名diffgrがあり、実際のペイロードは<diffgr>要素の1番目の子として開始されます。

    <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
    

    関連資料:

    TopLinkの詳細は、http://www.oracle.com/technology/products/ias/toplink/index.htmlを参照してください。


無効なXML文字

クライアント・アーティファクトを正常に生成できる完全に有効なWSDLでも、サーバー・サイドに到達する前にアプリケーションが停止する場合もあります。これは、図1-1の3に当たります。この失敗はサービスが使用できない場合に発生します。その他にも、検出の難しい場合があります。たとえば、アプリケーションによりSOAPメッセージに無効なXMLデータが生成される場合があります。また、アプリケーションからXMLでは無効な文字が渡される場合もあります。これらのような場合には、メッセージがWebサービスに到達する前に、サーバーのトランスポート・レイヤーによりすぐに拒否されます。

アプリケーションで、XML解析エラーの原因になる可能性のある特別な文字やデータをSOAP Bodyに含めて送信する必要がある場合は、アプリケーションがBASE64Encodingなどの基本的なエンコーディング・スキーマを使用するように設計されている必要があります。

次のコード・サンプルでは、SOAPメッセージで無効なXML文字を渡すことがどのようにして相互運用失敗の原因となるかを示します。

C#クライアント・アプリケーション・コードによりコマンド文字列が送信され、そのコマンドがサービスによりクライアントに対して実行されるとします。また、コマンドの1つにバックスペース文字(\b)が使用されているとします。

MyCommand request = new MyCommand("\b");
MyCommandResponse response = soapClient.runCommand(request);

クライアント・アプリケーションによりバックスペース文字(\b)を含むコマンド文字列の送信が試行されると、バックスペース文字はXMLでは無効であるためOracleAS Web Servicesにより拒否されます。これにより、HTTPトランスポート・エラー、および次のようなHTMLの応答が戻されます。

<HTML><HEAD><TITLE>Web Service</TITLE></HEAD><BODY><H1>Bad Request</H1><PRE>Error parsing envelope: (2, 237) Invalid char in text.</PRE></BODY></HTML>

同期外れのSOAPAction値

OracleAS Web Servicesでは、WSDL operation要素のsoapAction属性の値は、ターゲット名前空間および操作名から構成されるURIです。

http://<target-namespace>/<operation-name>

SOAPリクエスト・メッセージのこの操作に対するSOAPAction HTTPヘッダーの値にも、これと同じ値が使用されている必要があります。使用されていない場合、予期しない動作をする可能性があります。このタイプの失敗は、図1-1の4aに当たります。

多くのSOAPプロセッサでは、ボディ全体をデコードせずにリクエストを適切な操作にルーティングするための目印として、SOAPAction HTTPヘッダーが使用されています。引用符付き文字列のSOAPAction値をサポートしている実装もあります(""は空の文字列)。SOAPActionがHTTPヘッダーにない場合もあります。相互運用性の問題を回避するためには、常に引用符付き文字列を使用する必要があります。

この問題は、クライアントがサービスによって公開されたWSDLと同期していないことを意味します。この問題を解決するには、クライアントを再生成するとサービスのWSDLと同期します。

次のコード・サンプルでは、WSDL operation要素のsoapAction属性と、この操作に対するSOAPAction HTTPヘッダー間の不一致が、どのようにして相互運用失敗の原因となるかを示します。

WSDLに次に示すadd操作が定義されているとします。

<soapbind:operation soapAction= "http://ws.oracle.com/demo/:add"/>

例1-4に、実行時に送信されるSOAPリクエストを示します。メッセージによってadd操作にmultiply SOAPActionが設定されることに注意してください。

例1-4 SOAPActionの値を説明するSOAPリクエスト・フラグメント

POST http://localhost/khub/MathService.asmx HTTP/1.1

Host: localhost
Proxy-Connection: Keep-Alive
Connection: TE
TE: trailers, deflate, gzip, compress
User-Agent: Oracle HTTPClient Version 10h
SOAPAction: "http://ws.oracle.com/demo/:multiply"
Accept-Encoding: gzip, x-gzip, compress, x-compress
Content-type: text/xml; charset="UTF-8"
Content-length: 347

<?xml version = '1.0' encoding = 'UTF-8'?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns0="http://ws.oracle.com/demo/">
   <env:Body>
      <ns0:addElement>
         <ns0:a>3</ns0:a>
         <ns0:b>2</ns0:b>
      </ns0:addElement>
   </env:Body>
</env:Envelope>

サーバーでSOAPAction HTTPヘッダーの値とSOAP Body要素(<ns0:addElement>)の1番目の子要素に不一致が検出されるため、OracleAS Web Servicesによりエラーがスローされ、処理が停止されます。次のようなエラーが表示されます。

unexpected element name: expected={http://ws.oracle.com/demo/}addElement, actual={http://ws.oracle.com/demo/}multiplyElement

.NET 1.1実装では、SOAPメッセージのディスパッチにデフォルトでSOAPActionヘッダーが使用されているため、add操作ではなくmultiply操作が起動されてしまいます。障害は生成されません。例1-5に、.NETがmultiplyサービスから戻す不適切なレスポンスを示します。間違ったWebサービスが起動されているので障害が戻される必要があります。SOAPActionの無効な値が無視され、リクエストのペイロードに基づき、メッセージがadd操作にルーティングされる可能性もあります。

例1-5 .NETにより戻される不適切なレスポンス

<multiplyResponseElement xmlns="http://ws.oracle.com/demo/">
         <MultiplyResult>0</MultiplyResult>
      </multiplyResponseElement>

Apache Axisプラットフォームは、操作のルーティングでSOAPActionヘッダーに依存しません。SOAP Bodyペイロードの最上位要素を使用して一致する操作を検出します。

soapAction WSDL属性の概要

Webサービスの相互運用で予期しない動作が起こらないようにするには、WSDLのsoapAction属性の値がどのように設定され、SOAPメッセージのSOAPActionヘッダー値への影響を理解することが有効です。次の項では、この属性がどのように設定され、OracleAS Web Servicesおよび.NETプラットフォームでどのように使用されるかを説明します。

OracleAS Web ServicesにおけるsoapActionの値の制御

Oracle WebServicesAssemblerツールを使用してJavaコードからWebサービスをアセンブルすると、WSDLの各operationに一意のsoapAction属性値が生成されます。

ブール型引数emptySoapActionを使用してこの属性の値を制御できます。引数をtrueに設定すると、生成されたWSDLの各SOAP binding操作のsoapAction属性は空の文字列に設定され、SOAPメッセージのSOAPActionヘッダーは引用符("")付き文字列に設定されます。この引数をtrueに設定すると、別のベンダーのツールと相互運用できる可能性が高くなります。

emptySoapAction引数のデフォルト値はfalseです。この場合、soapAction属性の値は、targetNamespaceおよびoperation名が連結されています。この値は、SOAPメッセージのSOAPActionヘッダーの値でもあります。

次のコード・サンプルでは、emptySoapAction引数の値がOracleAS Web ServicesのsoapAction属性値の制御にどのように使用されるかを示します。

getDateTimeサービスを定義する、次のようなTimeService Javaインタフェースがあるとします。

public interface TimeService extends Remote {

    public String getDateTime(String name) throws RemoteException;
}

このインタフェースは、WebServicesAssemblerのassembleコマンドへの入力、またはemptySoapAction引数のないAntタスクとして使用できます。emptySoapAction引数はコマンドやタスクでは使用されないため、その値はデフォルトでfalseであると推測されます。結果のWSDLでは、次のsoapAction値です。

soapAction="http://timeService/getDateTime"

この値は、SOAPメッセージのSOAPActionヘッダーの値でもあります。

.NETプラットフォームにおけるsoapActionの値の制御

.NETプラットフォームでは、XML WebサービスのRoutingStyleSoapActionとして指定できます。WebサービスがdocumentスタイルであるかRPCスタイルであるかによって、SoapDocumentMethodまたはSoapRpcMethod属性のActionパラメータを使用してSoapActionを設定します。デフォルトでは、Actionパラメータの値を次のURIで定義します。

http://<web service-namespace>/MethodName

このURIでは、MethodNameはXMLWebサービス・メソッドの名前です。


注意:

SoapActionパラメータを定義してSOAPメッセージをディスパッチするかわりに、RequestElementパラメータを使用してrequest要素の名前を設定するように.NETプラットフォームを構成できます。これを実行するには、RoutingStyle=SoapServiceRoutingStyle.RequestElementおよび[SOAPDocumentMethod(Action="")]を設定します。

このトピックの詳細は、このマニュアルでは説明しません。RequestElementパラメータの詳細は、.NETプラットフォームのマニュアルを参照してください。


次のコード・サンプルでは、RoutingStyleパラメータを使用して.NET WebサービスのSoapAction値をどのように制御できるかを示します。

例1-6では、XML WebサービスのRoutingStyleSoapServiceRoutingStyle.SoapActionに設定されています。SoapDocumentMethod属性はdocumentスタイルとしてのサービスを識別し、ActionパラメータはmyAddServiceおよびmyMultiplyServiceとしてのWebサービスのURIを識別します。

例1-6 .NETプラットフォームにおけるサービスのRoutingStyleの値の設定

<%@ WebService Language="C#" Class="MathService" %>

using System;
using System.Web.Services;
using System.Web.Services.Protocols;

[SoapDocumentService(SoapBindingUse.Literal,
                 SoapParameterStyle.Wrapped,
                 RoutingStyle=SoapServiceRoutingStyle.SoapAction)]

public class MathService : WebService {
   [SoapDocumentMethod(Action="http://localhost/myAddService")]
   [WebMethod]
   public float Add(float a, float b)
   {
       return a + b;
   }

   [SoapDocumentMethod(Action="http://localhost/myMultiplyService")]
   [WebMethod]
   public float multiply(float a, float b)
   {
       return a * b;
   }
}

SOAPメッセージのNULL値

データ型の不一致は、相互運用失敗の最も一般的な原因です。このタイプの失敗は、サーバーまたはクライアントがSOAPメッセージのデシリアライズを試行する際に発生します。これは、図1-1の4bおよび5に当たります。

データ型の不一致が原因の失敗は、プラットフォームの違いを越えてNULL値が送信された場合に発生します。可能な場合には、NULL値を送信しないようにする必要があります。あるWebサービス・アプリケーションから他のアプリケーションにNULL値を送信する必要がある場合は、別のシステムでそのデータ型が何にマッピングされていて、そのデータ型でNULL値を正しく処理できるかどうかを把握する必要があります。

たとえば、xsd:dateTimeスキーマ型は、.NETプラットフォームではSystem.DateTimeにマッピングされています。Javaプラットフォームでは、java.util.Calendarまたはjava.util.Dateにマッピングされています。JavaプログラムでCalendarまたはDateオブジェクトがNULL値で初期化されている場合は、SOAPメッセージでNULLのxsd:dateTimeが送信されます。.NETプラットフォーム上に作成されたWebサービスでSOAPメッセージを受信すると、System.DateTime型ではNULL値が許可されていないため、そのメッセージは正しくデシリアライズされません。

次のコード・サンプルでは、発信プラットフォームと受信プラットフォーム間でNULL値を送信することがどのようにして相互運用失敗の原因となるかを示します。

nil属性がtrueに設定されている場合、XML要素はNULL要素です。WSDLで、対応する要素のnillable属性をtrueに設定することで対応する必要があります(nillableのデフォルト値はfalseです)。

例1-7のWSDLでは、source要素でnillable属性が省略されています。そのため、このWSDLにはデフォルトでnillable=false属性があるのと同じことになります。

例1-7 source要素でNULL値が許可されていないWSDLフラグメント

<s:element name="Src2html">
    <s:complexType>
    <s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="login" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="passe" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="lan" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="source" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>

クライアント・アプリケーションで、source要素を表すJavaオブジェクトにNULL値が割り当てられているとします。Apache Axisプラットフォームで、このWSDLからクライアント・プロキシ・コードが生成されるとします。例1-8にワイヤ書式の結果のリクエストSOAPメッセージを示します。source要素のxsi:nil属性がtrueに設定されていることに注意してください。

例1-8 xsi:nilがtrueに設定されているリクエスト・メッセージ

<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>
  <Src2html xmlns="http://www.dotnetisp.com/webservices/dotnetisp/src2html.asmx">
   <login>Gigi</login>
   <passe>oracle</passe>
   <lan>C#</lan>
   <source xsi:nil="true"/>
  </Src2html>
 </soapenv:Body>
</soapenv:Envelope>

WSDL定義ではsource要素にnil値を含めることが許可されていないため、OracleAS Web Servicesプラットフォーム上に作成されたWebサービスは、受信したSOAPメッセージのデシリアライズに失敗します。例1-9に、OracleAS Web Servicesにより前述のリクエストに対して生成される、サンプルのSOAP障害レスポンスを示します。

例1-9 OracleAS Web ServicesからのサンプルのSOAP障害レスポンス

<env:Body>
<env:Fault>
    <faultcode>env:Client</faultcode>
    <faultstring>caught exception while handling request: unexpected null</faultstring></env:Fault>
</env:Body>
</env:Envelope>

一方、source要素にNULLを割り当てる同じクライアント・アプリケーションをOracleAS Web Servicesを使用して開発すると、source要素はスキーマでオプションとして定義されるため完全に省略されます。例1-10に、OracleAS Web Servicesを使用して開発されたクライアントにより送信される、ワイヤ書式のリクエストSOAPメッセージを示します。

例1-10 オプションの要素が省略されているリクエスト・メッセージ

<env:Envelope xmlns:env=http://schemas.xmlsoap.org/soap/envelope/
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
    xmlns:ns0="http://www.dotnetisp.com/webservices/dotnetisp/src2html.asmx">
<env:Body>
<ns0:Src2html>
    <ns0:login>Gigi</login>
    <ns0:passe>oracle</passe>
    <ns0:lan>C#</lan>
</ns0:Src2html>
</env:Body>
</env:Envelope>

例1-10のリクエストには無効なNULL要素が含まれていないため、サーバーはエラーのないレスポンスを戻します。例1-11に、このリクエストに対するサンプルのレスポンスを示します。

例1-11 サンプルのSOAPメッセージ

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:ns0="http://www.dotnetisp.com/webservices/dotnetisp/src2html.asmx">
<env:Body>
<ns0:Src2htmlResponse/>
</env:Body>
</env:Envelope>

unsignedスキーマ数値型

図1-1の4bや5で発生する別のタイプのデシリアライズの失敗には、unsignedスキーマ型の使用が関係します。.NETプラットフォームでは、unsigned型はネイティブのunsignedデータ型に直接マッピングされます。一方、Javaプラットフォームでは、unsigned型は定義されていません。その結果、WSDLでunsignedスキーマ型を使用すると、予期しない相互運用失敗の原因になります。

可能な場合には、unsignedShortunsignedIntunsignedDoubleまたはunsignedFloatなどのunsigned数値データ型をクライアント・アプリケーションに使用しないようにします。これらのデータ型を使用した場合、各システムにおけるこれらのデータ型の範囲や精度の制限を確認する必要があります。

次のコード・サンプルでは、クライアント・アプリケーションにunsignedデータ型を使用することがどのようにして予期しない相互運用失敗の原因となるかを示します。

次に示すC# Webメソッドではunsigned入力引数uiを取り、コール元に同じ値を戻します。

[WebMethod]
Public uint getUint(uint ui) {
    Return ui
}

例1-12に、getUnit Webメソッドの入力および出力パラメータを含むWSDLフラグメントを示します。これらのパラメータは、xsd:unsignedInt型に直接マッピングされます。

例1-12 入力および出力パラメータがマッピングされているWSDLフラグメント

...
<s:element name="getUint">
    <s:complexType>
<s:sequence>
         <s:element minOccurs="1" maxOccurs="1" name="ui" type="s:unsignedInt" />
       </s:sequence>
    </s:complexType>
 </s:element> <s:element name="getUintResponse">
    <s:complexType>
        <s:sequence>
         <s:element minOccurs="1" maxOccurs="1" name="getUintResult" type="s:unsignedInt" />
        </s:sequence>
    </s:complexType>
  </s:element>
...

WebServicesAssemblerツールを使用すると、getUnitサービスを消費する、JAX-RPCに準拠したクライアント・コードを生成できます。生成されたクライアント・コードは、request入力型をJavaのネイティブのデータ型longにマッピングします。

例1-13に示されているコード・フラグメントに類似のJavaクライアント・アプリケーションで、相手側のWebサービスで予期される型を把握せずに、非常に大きなlong値を渡すとします。

例1-13 非常に大きな値を渡すクライアント・アプリケーション・フラグメント

...
stubs.Service1SoapClient myPort = new stubs.Service1SoapClient();
System.out.println("calling " + myPort.getEndpoint());
long l1 = 9223372036854775807L;
GetUint request = new GetUint(l1);
GetUintResponse response = myPort.getUint(request);
long l2 = response.getGetUintResult();
...

メッセージがケーブルで送信されると、.NETプラットフォームにより値が拒否され、例1-14に示すようなSOAP障害が戻されます。

例1-14 .NETプラットフォームにより送信されるサンプルのSOAP障害

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  <soap:Body>
    <soap:Fault>
      <faultcode>soap:Client</faultcode>
      <faultstring>Server was unable to read request. --&gt; There is an error in XML document (2, 261). 
       --&gt; Value was either too large or too small for a UInt32.</faultstring>
      <detail />
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

精度の欠落

精度の欠落は、メッセージがデシリアライズされる箇所で発生します。これは、図1-1の4bおよび5に当たります。SOAP障害は必ずスローされるわけではないため、このタイプの失敗は常に明白になるとはかぎりません。

精度の欠落は、XMLデータ型の値を別のプラットフォーム用に変換する際に発生します。たとえば、XML dateTime単純型の値は、Javaおよび.NETプラットフォームでは異なる場合があります。これは、これらのプラットフォームではこのXMLデータの値を変換する際に、異なる精度を使用しているためです。

次のコード・サンプルでは、Javaおよび.NET Webサービス間でxsd:dateTime XML単純型を送信するとどのようにして精度が欠落するかを示します。精度が欠落すると、相互運用性の問題の発生につながります。

次に示すC# Webメソッドは、DateTimeデータ型のSystem MAX_VALUEを戻します。

[WebMethod]
Pubic DateTime getDateTime() {
    Return DateTime.MaxValue;
}

例1-15に、getDateTime .NET WebサービスにアクセスするJavaクライアント・コード・フラグメントを示します。

例1-15 .NET WebサービスにアクセルするためのJavaコード・フラグメント

...
GetDateTime request = new GetDateTime();
GetDateTimeResponse response = myPort.getDateTime(request);
Calendar cal = response.getGetDateTimeResult();
...

例1-16に、Javaクライアントがワイヤ書式で受信するSOAPレスポンスを示します。日付に指定された値に注意してください(太字で強調してあります)。

例1-16 日付を戻す.NET WebサービスからのSOAPレスポンス・メッセージ

<?xml version="1.0" encoding="utf-8" ?>
  <dateTime xmlns="http://tempuri.org/">9999-12-31T23:59:59.9999999-08:00</dateTime>

Javaクライアントにより、レスポンスがjava.util.Calendarクラスにデシリアライズされます。例1-17に、Calendarオブジェクトのコンテンツの出力を示します。dateTime値が、ワイヤ書式で渡された値よりも少し遅くなっていることに注意してください。これは、2つのネイティブのdateTime型で異なる精度が使用されているためです。.NETプラットフォームでは、年の値には4桁の数値が、ミリ秒には7桁の数値が使用されています。Javaプラットフォームでは、年の値には5桁の数値が、ミリ秒には3桁の数値が使用されています。さらに、Java Webサービスではミリ秒の3桁のみが維持され、日付が切り上げられています。受信側の新しい値は、10000年1月1日です。

例1-17 Java Calendarオブジェクトの出力

[java] ERA: 1
[java] YEAR: 10000
[java] MONTH: 0
[java] WEEK_OF_YEAR: 1
[java] WEEK_OF_MONTH: 1
[java] DATE: 1
[java] DAY_OF_MONTH: 1
[java] DAY_OF_YEAR: 1
[java] DAY_OF_WEEK: 7
[java] DAY_OF_WEEK_IN_MONTH: 1
[java] AM_PM: 0
[java] HOUR: 0
[java] HOUR_OF_DAY: 0
[java] MINUTE: 0
[java] SECOND: 0
[java] MILLISECOND: 0
[java] ZONE_OFFSET: -8
[java] DST_OFFSET: 0

相互運用性に対するツールのサポート

前述の項では、Webサービスの相互運用性を調べるための明確な手順があることを説明しました。これらの手順は、取得、再実行、分析プロセスとしてまとめることができます。

Oracleには、各手順を支援するツールが用意されています。どのツールを使用するかは、Webサービスのエンドポイントおよびプロキシを開発している環境によって異なります。これ以降の項では、各手順を支援するツールを説明します。

Webサービス規約の取得

Webサービス規約には、WSDLファイル、SOAPメッセージ・ペイロードおよびHTTPヘッダーが含まれます。

WSDLおよびXSDファイルを取得するには、次のツールを使用できます。

  • Oracle JDeveloperウィザードには、プロジェクト内にWSDLファイルのローカル・コピーを作成するオプションが用意されています。図1-2に、Oracle JDeveloperの「WSDLをプロジェクトにコピー」オプションを示します。

  • WebServicesAssemblerツールには、基底(またはトップレベル)のWSDLファイルと、インポート済/組込み済のすべてのWSDLとスキーマを、指定された出力ディレクトリにコピーするfetchWsdlコマンドが用意されています。このコマンドは、コマンドラインまたはAntタスクで実行できます。

    この引数の詳細は、『Oracle Application Server Web Services開発者ガイド』の「fetchwsdl」を参照してください。

  • 一般的なAntタスクgetを使用してWSDLを戻すことができます。Antタスクを使用する場合は、wsdl:importまたはxsd:importを使用して参照されたすべてのリモート・リソースのローカル・コピーを作成する必要があります。

図1-2 WSDLのローカル・コピーを作成するOracle JDeveloperのオプション

図1-2の説明が続きます
「図1-2 WSDLのローカル・コピーを作成するOracle JDeveloperのオプション」の説明

SOAPペイロードおよびHTTPヘッダーの取得

SOAPペイロードおよびHTTPヘッダーを取得するには、次のツールを使用できます。

  • Oracle JDeveloper 10gに同梱されているHTTPアナライザ・ツールには、サービス・コンシューマとサービス・プロバイダ間のHTTPトラフィックを取得する便利な方法があります。この方法は、2つのノード間に簡単にHTTPプロキシを導入できることを前提としています。クライアントの動作を変更するには、クライアントの稼働中に、http.proxyHostおよびhttp.proxyPortシステム・プロパティを使用する必要があります。

  • HTTPプロキシの導入が現実的でない場合は、受信トラフィックを最終的な宛先にリダイレクトする中間ノードを使用できます。WS-Iモニターが、この方法を実行できるツールの例です。HTTPプロキシとは異なり、中間ノードを使用する場合には、クライアント・サイドのエンドポイントのURLを変更する必要があります。

  • クライアント・コードの変更や、プロキシを介したHTTPトラフィックのルーティングができない場合には、TCP Snifferを設定します。Etherealが、このコンテキストで使用できるUnixおよびWindows用のネットワーク・プロトコル・アナライザの例です。

メッセージ・ペイロードの再実行

ペイロードを取得したら、同じペイロードの再送信、または変更内容の影響を確認するためのペイロードの編集および送信ができる必要があります。

  • 同じペイロードの再送信処理にはJUnitを使用できます。WebServicesAssemblerのgenProxyコマンドにより生成されたテスト・クラスを利用できます。また、Oracle JDeveloper 10gでもこれらのテスト・クラスを生成できます。図1-3に、Oracle JDeveloperのウィザードに表示される、JUnitクラスを生成するためのオプションを示します。

  • Oracle JDeveloper 10gに同梱されているHTTPアナライザ・ツールには、同じペイロードまたは編集済のペイロードを再送信する便利な方法があります。図1-4に、Oracle JDeveloperに同梱されているHTTPアナライザ・ツールの「リクエストの再送信」コマンドを示します。

図1-3 JUnitクラスを生成するOracle JDeveloperのオプション

図1-3の説明が続きます
「図1-3 JUnitクラスを生成するOracle JDeveloperのオプション」の説明

図1-4 JDeveloperに同梱されているHTTPアナライザ・ツールの「リクエストの再送信」コマンド

図1-4の説明が続きます
「図1-4 Oracle JDeveloperに同梱されているHTTPアナライザ・ツールの「リクエストの再送信」コマンド」の説明

相互作用の分析

サービスのコンシューマとプロバイダとの相互作用を分析します。相互作用の分析には、次のツールを使用できます。

  • Oracle JDeveloper 10gのHTTPアナライザを使用すると、IDEから直接WS-I Analyzerを使用できます。IDEからAnalyzerを使用するには、まずWS-IツールのJavaバージョンをダウンロードする必要があります。WS-I AnalyzerによりXML構成ファイルが生成され、レポート生成の進捗状況が表示されます。図1-5に、統合されたWS-I Analyzerコマンドが選択された状態のOracle JDeveloperのHTTPアナライザを示します。

  • WebServicesAssemblerツールには、WSDLの全体スキャンを実行し、このバージョンのWebServicesAssemblerでWSDLを処理できるかどうかを確認するanalyzeコマンドが用意されています。genProxyおよびgenInterfaceコマンドは同じタスクを実行しますが、analyzeはこれらのコマンドとは異なり、コードを生成しません。


    関連資料:

    『Oracle Application Server Web Services開発者ガイド』の「analyze」を参照してください。


    Oracle JDeveloper IDEには、WSDL検証コマンドも統合されています。選択されたリソースのタイプに基づいて、ポップアップ・メニューから使用できます。図1-6に、ファイルを比較するOracle JDeveloperのコマンドを示します。この場合、コマンドでは2つのWSDLファイルが比較されます。

図1-5 WS-I Analyzerコマンドが統合されたOracle JDeveloper

図1-5の説明が続きます
「図1-5 WS-I Analyzerコマンドが統合されたOracle JDeveloper」の説明

図1-6 Oracle JDeveloperのファイルを比較するコマンド

図1-6の説明が続きます
「図1-6 Oracle JDeveloperのファイルを比較するコマンド」の説明

WS-Iツールの入手

この章で説明されたツールの詳細は、次のWebアドレスを参照してください。

WS-Iテスト・ツールの使用方法:

http://www.oracle.com/technology/products/jdev/howtos/10g/WS_WSI/WSI_HowTo.html

WS-I Basic Profile 1.0に準拠したアナライザのデモ:

http://www.oracle.com/technology/products/jdev/viewlets/905p_j2ee_wsi/wsi_webservices_10g_viewlet_swf.html

WS-Iツールのダウンロード:

http://www.ws-i.org/deliverables/workinggroup.aspx?wg=testingtools

制限事項

「相互運用可能なWebサービスの実現」を参照してください。

追加情報

詳細は、次を参照してください。