サービスインタフェースにおけるスキーマ定義型による XML ドキュメントの記述

Sean BrydonSmitha KangathSameer Tyagi

課題

クライアントとサービスが XML ドキュメントを交換する Web サービスとの対話のデザインでは、サービスインタフェース内の XML ドキュメントを記述する型を選択する必要があります。この型の選択は、多くのことに影響します。選択された型は、サービスを記述した WSDL ファイルばかりでなく、サービス実装のコードにも反映されます。J2EE 1.4 アプリケーションでは、注文書や請求書などの XML ドキュメントの交換、JAX-RPC を使用します。サービスインタフェースをデザインするときの XML ドキュメントを記述する型の選択肢は数多くあります。 これらの対処法については、ドキュメント指向サービスのデザインに関するカタログエントリを参照してください。

この課題の対処法では、スキーマファイルで定義した型を用いて XML ドキュメントを記述する際のデザイン時の考慮事項に焦点を当てています。この場合、それらスキーマは個々のアプリケーションに固有のこともあれば、垂直的な業界規格団体によって定義されることもあります。たとえばアプリケーションは、対応する purchaseorder.xsd スキーマファイルを持つ purchaseorder.xml ドキュメントを使用する必要があるかもしれません。この場合に大切なことは、スキーマファイルに定義されているこの型は、WSDL ファイルによって、そのサービスの一部として、公開され、標準的なスキーマによって定義された型ではないということです。通常、この型は、標準のスキーマ型を使用した複合型として定義されます。

対処法

クライアントサービスの間で交換される XML ドキュメントを、スキーマ定義型を用いて記述する際の問題点をいくつか考えてみましょう。

ここでは、クライアントから、注文書を受け取るサービスに PurchaseOrder XML ドキュメントを渡す例を使用して、この対処法を説明します。交換される注文書は、注文書 ID や連絡先情報、購入する商品の品目などのデータを含む一般的な注文書です。

対処法: スキーマ定義型による XML ドキュメントの記述

この対処法の場合、PurchaseOrder 構造はインタフェースの一部として公開され、このため、サービスインタフェースアーティファクト (WSDL ファイル、Java インタフェース、実装) には、その全詳細情報が含まれます。document-literal な書式で配備された場合、このような Web サービスは、SOAP メッセージの本体で XML ドキュメントを渡します。WSDL の場合、このことは、スキーマのすべての要素を WSDL ファイルに埋め込むか、ドキュメントのスキーマを別のファイルに定義しておいて、WSDL ファイルにインポートできることを意味します。対応する Java インタフェースの場合、このことは、すべての PurchaseOrder スキーマ要素が、PurchaseOrder を記述するために、対応する Java 型を必要とすることを意味します。WSDL から見ると、これは、このオペレーションで交換されるドキュメントのスキーマに対する WSDL の結合です。

スキーマ定義を WSDL ファイルに直接埋め込む選択をした場合、このことは、ドキュメントの構造用のフィールドおよび型の全詳細がインタフェースに含まれることを意味します。この後のコード例 1 の WSDL の抜粋やインタフェースおよび実装クラスには、インタフェースに埋め込まれる注文書詳細を示しています。実際には、注文書の型が WSDL に含まれるため、保守が困難になる可能性があります。

<?xml version="1.0" encoding="UTF-8" ?>
<definitions xmlns="http://schema.xmlsoap.org/wsdl/" xmlns:tns="urn:ObjectPurchaseOrderService" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schema.xmlsoap.org/wsdl/soap/" name="ObjectPurchaseOrderService" targetNamespace="urn:ObjectPurchaseOrderService">
<types>
<schema xmlns:soap11-enc="http://schema.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://schema.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:ObjectPurchaseOrderService">
     <xsd:complexType name="Address">
        <xsd:sequence>
            <xsd:element name="street" type="xsd:string" nillable="false"/>
            <xsd:element name="city" type="xsd:string" nillable="false"/>
            <xsd:element name="state" type="xsd:string" nillable="false"/>
            <xsd:element name="postalCode" type="xsd:string" nillable="false"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="LineItem">
        <xsd:sequence>
            <xsd:element name="itemId" type="xsd:string" nillable="false"/>
            <xsd:element name="price" type="xsd:float" nillable="false"/>
            <xsd:element name="quantity" type="xsd:int" nillable="false"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="PurchaseOrder">
        <xsd:sequence>
            <xsd:element name="poId" type="xsd:string" nillable="false"/>
            <xsd:element name="createDate" type="xsd:date" nillable="false"/>
            <xsd:element name="shipTo" type="Address" nillable="false"/>
            <xsd:element name="billTo" type="Address" nillable="false"/>
            <xsd:element name="items" type="LineItem" nillable="false" minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence>
    </xsd:complexType>

</schema>
</types>
<message name="PurchaseOrderServiceSEI_submitPO">
  <part name="PurchaseOrder_1" type="tns:PurchaseOrder" />
</message>
   ...
</definitions>

コード例 1: WSDL ファイルの抜粋 - パラメータ型の定義として注文書スキーマ定義が WSDL に埋め込まれている

WSDL 内にドキュメントスキーマ定義を埋め込まずに、独立したファイルで型を定義し、それを WSDL ファイルにインポートする方法もあります。この方法では、維持が容易になります。この方法で、purchaseorder.xsd スキーマファイルを作成するとしましょう。WSDL ファイルで、この型を WSDL にインポートします。このあとは、サービスオペレーションに対する入力パラメータに使用するだけです。コード例 2 は、この方法の具体例です。

<types>
   <schema targetNamespace="urn:SchemaDefinedPurchaseOrderService"
   xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"> 
    <xsd:import namespace="http://java.sun.com/blueprints/ns/po" schemaLocation="PurchaseOrder.xsd"/>
    <element name="submitPO">
        <complexType>
            <sequence>
            <element name="inputDoc" type="pons:PurchaseOrder" nillable="true"/>                       
      </sequence>
    </complexType>
      </element>  
    ...                  
  </schema>
</types>
<message name="SchemaDefinedPurchaseOrderServiceSEI_submitPO">
    <part name="parameters" element="tns:submitPO"/>
</message>
  ...
<portType name="SchemaDefinedPurchaseOrderServiceSEI">
    <operation name="submitPO">
      <input message="tns:SchemaDefinedPurchaseOrderServiceSEI_submitPO"/>
       ...
    </operation>
</portType>
コード例 2: WSDL からの抜粋 - 注文書スキーマをインポート

これらの 2 通りの WSDL ファイルから生成される Java ファイルを考えてみましょう。WSDL ファイルが注文書に指定された詳細情報をすべて持たなければならないのと同じで、注文書を記述するには、Java インタフェースにも、すべての型が必要になります。

//The service endpoint java interface(either generated or hand rolled)
package com.sun.j2ee.blueprints.objectposervice;
import java.rmi.*;
public interface PurchaseOrderServiceSEI extends Remote {
    public String submitPO(PurchaseOrder inputDoc) throws
        InvalidPOException, RemoteException;
}

コード例 3: サービスの WSDL ファイルに対応する PurchaseOrderServiceSEI Java インタフェース

Address.java や LineItem.java などの、その参照先のクラスの型同様、PurchaseOrder.java はクラス内で定義されることに注意してください。

public class PurchaseOrder{
   private String poId;
   private Calendar createDate;
   private Address shipTo;
   private Address billTo;
   private LineItem[] items;
   ...

}
コード例 4: サービスの WSDL ファイル内の型定義に対応する注文書 Java クラス

同様に、エンドポイント実装 (この例では EJB) も、そのメソッド署名で PurchaseOrder.java を使用します。このコンポーネントは、EJB ではなく Web コンポーネントでもよく、同じ問題が該当することに注意してください。XML ドキュメントの型の選択では、サービスインタフェースの実装に Web コンポーネントまたは EJB コンポーネントのどちらを使用しても違いはありません。

public class PurchaseOrderServiceBean implements SessionBean {
  ...
  public String submitPO(PurchaseOrder po) throws
InvalidPOException, RemoteException {
    //see code for details
  }
  ...

}
コード例 5: 注文書のサービスエンドポイント実装クラス

つまり、エンドポイントは、WSDL ファイルと Java インタフェース、PurchaseOrder スキーマに定義されている構造と型を持つ PurchaseOrder を受け付ける submitPO メソッドを含む Java 実装クラス 1 つずつと、必要に応じて、PurchaseOrder を記述するためのいくつかのヘルパー Java クラスを必要とします。これは、オブジェクトを渡すことに似ているため、多くの Java プログラマにとって当然のインタフェースのように見え、また快適な方法です。この対処法は、ドキュメントに対して綿密に定義されたスキーマがあり、そのスキーマに基づいてサービスを作成する必要があるケースに十分に通用します。たとえば垂直的な業界規格の請求書ドキュメントに関係するサービスを作成する場合などです。この対処法には、JAX-RPC の自動的なスキーマ検査を利用できるという利点があります。たとえば PurchaseOrder ドキュメントが受信されると、JAX-RPC 実行時環境は、サービス実装クラスを送信する前に、その PurchaseOrder ドキュメントと PurchaseOrder スキーマとを自動的に照合するため、開発者はその分コーディングの手間を省くことができます。また、この対処法では、JAX-RPC が提供する Java オブジェクトとの自動的なバインドという利点が得られることもあります。たとえば上記の注文書例では、XML PurchaseOrder ドキュメントは、submitPO メソッドの署名で使用可能な PurchaseOrder.java オブジェクトに自動的にバインドされます。これにより、開発者は、受信した XML ドキュメントから Java オブジェクトを作成するためのコードを作成する手間を省くことができます。

ドキュメントの記述はサービスインタフェースに密に結合されていることに注意してください。このため、ドキュメントの定義を変更しようとすると、インタフェースまたは WSDL の変更が必要になることがあります。これは、インタフェースの進化に影響することがあります。この対処法の場合、サービスオペレーションが 1 つのドキュメントのスキーマに密にバインドされるため、多種のドキュメントを受け付けるメソッドを使用してより汎用的なサービスを作成することが難しいことがあります。たとえば垂直型の業界定義スキーマなど、交換するドキュメントの型が判明している場合、スキーマ定義型を使用するこの対象は、非常にうまく機能します。これは、一般的な対処法でもあります。

参考資料

この項目に関するさらに詳しい情報としては、次の資料を推奨します。

© Sun Microsystems 2005. All of the material in The Java BluePrints Solutions Catalog is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.