SOAP での添付オブジェクトの処理

Apache SOAP 2.2 による非 XML オブジェクトの転送

Web サービスでは、プロセス内のサービス間で単なるテキスト・メッセージ以外のデータも転送できる必要があります。たとえば、言語構造体、マルチメディア・ファイル、その他の組み込みメッセージなど、複雑なデータ型を扱わなければならない場合も多くあります。この記事では、SOAP with Attachments 仕様を用いてこのような複雑な情報を転送する方法について取り上げます。また、SOAP サービスでカスタム・データ型のマッピングや添付を処理するプログラミング・サンプルも紹介します。

Joshy Joseph, Senior Engineer, IBM

Joshy Josephは、IBMのOn Demand Architecture and Development組織の中のIBM Software Groupに勤務するSoftware Engineerです。アーキテクト、プログラマーであり、主なスキル、専門領域としては、分散コンピューティングやグリッド・コンピューティング、Webサービス、ビジネス・プロセス、ワークフロー開発などです。2003年にPrentice HallからGrid Computing を出版しています。また、グリッド・コンピューティングやビジネス・プロセス開発、Webサービスなどに関して、数多くの技術記事を執筆しています。



2002年 2月

Webサービスは、多様なプラットフォームやシステムにまたがる複雑な問題を解決し、分散処理を行う手段として、業界で広く受け入れられてきました。Webサービスにおけるこれらの処理は、SOAP、WSDL、およびUDDIといった標準ベースのプロトコルを利用したり、標準化グループでの開発によって、成し遂げられています。これらの標準は、現在も発展し続けていますが、ニーズのあるすべてのエリアに対する完全なソリューションは、まだ提供はされていません。データ構造の配列のようなカスタム・データ型をサービス間でやり取りしたり、バイナリーやその他の複雑なデータ・ファイルを転送する添付オブジェクトを処理することも、ソリューションが必要なエリアの1つです。

この記事では、Webサービスにおいて、カスタム・データのエンコードおよび添付を処理するプロトコルやツールについて説明します。また、「簡単な実装サンプル」セクションでは、既存のツールや標準を使って、ファイルをアップロードしたり、ダウンロードするためのWebサービスの作成方法を紹介します。これらのトピックに移る前に、まずSOAPやWSDLがデータ・エンコードを処理する仕組みについて見ていきましょう。

SOAPとデータ型

SOAPメッセージには、XML文書定義が含まれています。この文書定義を使うことにより、分散環境におけるピア間で、構造化された情報をやり取りすることができます。通常、SOAPメッセージはSOAP仕様のセクション5で定義されている方式でエンコードされます。ただし、アプリケーションによって解釈可能であれば、XML SchemaやRDFなどその他のエンコード・スキームを使用することもできます。たとえば、WSDLで指定されるliteral エンコード方式では、XML Schemaエンコードが使用されています。SOAP仕様のセクション5は、初期バージョンのXML Schemaの型システムの欠陥、特に配列やその他の複雑な型システムのようなSOAPで必要とされる機能を補強する目的で作成されました。しかし、業界および標準化作業グループの間では、XML Schemaが進歩し、SOAPで必要とされるほとんどの機能をサポートしているのに、別の特殊なエンコード・スキームが本当に必要かどうかということについて大きな論争になりました。

SOAPによるメッセージ交換は、リモート・プロシージャー呼び出し (RPC) というモデルによって行われます。リモート・プロシージャー呼び出しでは、明確に定義されたメソッドの呼び出しシグニチャー (つまり、メソッド名とパラメーター) およびその戻り値 / 例外に基づく明確に定義された方法で、メッセージが交換されます。SOAPメッセージは、交換されるDocumentとして見ることもできます。その場合、交換されるデータのセマンティクスは、アプリケーション・レベル (送信者または受信者) でしか確認できません。


WSDL (Webサービス記述言語)

WSDLはSOAPメッセージのセット、およびそれらのメッセージがSOAPプロセッサー間で交換される方法を記述します。これにより、企業はサービスを記述することができます。また、顧客は、SOAPのような下位レベルの交換プロトコル (バインディング) についての知識がなくても、不自由なくサービスを利用できます。このようにサービスを高度に抽象化することにより、人間の手作業が減り、Webサービス用プロキシーの自動生成が可能になります (これは静的プロキシーと動的プロキシーの両方に適用されます)。WSDLでは、文書指向のメッセージとRPC指向のメッセージの両方を記述することができます。

WSDLには、リテラル・エンコードとSOAPエンコードという2種類のメッセージ・エンコード方式があります。リテラル・エンコードでは、メッセージは、XML Schemaに従って構成されます。SOAPエンコードはSOAP仕様のセクション5で指定されている規則に従います。WSDLにおいてもう1つ重要な概念は、メッセージ転送フォーマット です。このフォーマットでは、メッセージは、DocumentパラメーターまたはRPCパラメーターとして転送することができます。Document転送フォーマットでは、メッセージパートがメッセージ・ボディ内に含まれるのに対し、RPC転送フォーマットでは、メッセージパートは、単に特定のシグネチャーを持つ呼び出しのパラメーターであり、XMLエレメントにラップされています。これらの転送フォーマットは、SOAPメッセージ交換のSOAPセマンティックに準拠しています。

これらの概念を踏まえた上で、SOAPおよびWebサービスについて、カスタム型マッピングや添付オブジェクトのサポートなどの興味深い側面について説明します。


型マッピング

SOAPにおける型マッピングは、プログラミング言語においてネイティブなオブジェクトをSOAPメッセージとして転送できるようにするために、これらのネイティブ言語オブジェクトをXMLにマーシャルまたは再フォーマットして転送する方法を決定する際に使用されます。これらの型マッピングは、クライアントおよびサーバーのマッピング・レジストリーに保存されます。ほとんどのツールキットに、プリミティブ型、集合、および場合によってはMIME添付オブジェクト用の、いくつかの定義済み変換プログラムが用意されています。カスタム・クラス・オブジェクトを転送するには、新しいシリアライザーおよびデシリアライザーを作成し、クライアントとサーバーの両方に新しい型マッピングを登録する必要があります。このような型マッピングは、SOAPのencodingStyle 機能に基づいています。

型マッピングには、通常、次のような情報が含まれています。

  • encodingStyle - 使用されるエンコード・スタイルを記述するURI (例: http://schemas.xmlsoap.org/soap/encoding/)
  • XMLエレメントのqname - 特定の型定義に提供されるURI (例: http://www.w3.org/2001/XMLSchema:int)
  • エンコードまたはデコードされるネイティブ言語クラス
  • シリアライザーとして機能するネイティブ言語クラスの名前
  • デシリアライザーとして機能するネイティブ言語クラスの名前

既存のSOAPツールキットのほとんどがSOAPエンコード・スキームおよびXML Schemaに基づく複雑な型マッピングをサポートしています。

Apache SOAP 2.2によるカスタム型マッピングのサポート

カスタム型エンコードを処理するには、サーバーおよびクライアントの両方で、新しい型マッピングを定義する必要があります。Apache SOAP 2.2ツールキットを使ってサーバー・サイドに型マッピングを登録する方法は次の2通りの方法があります。

  • 配置ディスクリプタの使用。
  • 新しい型マッピングによるデフォルトのマッピング・レジストリーの再定義。新しいレジストリーはSOAPMappingRegistryのサブクラスである必要があります。

Apache SOAP 2.2ツールキットを使ってクライアント・サイドに型マッピングを登録する方法も次の2通りあります。

  • SOAPMappingRegistryのインスタンスを作成し、mapTypes() メソッドを用いて新しい型を追加。
  • すべての登録済みマッピングを含むSOAPMappingRegistryのサブクラスの作成。

開発者を支援するために、Apache SOAPには、Java Bean Serializer/Deserializerクラスが用意されています。そのため、カスタム・コードを作成しなくても、JavaBeansテクノロジー標準に組み込まれたすべてのクラスをシリアライズまたはデシリアライズできます。このJavaBeans Serializer/Deserializerクラス、org.apache.soap.encoding.soapenc.BeanSerializer は、型マッピング・レジストリーにおいて、シリアライザーおよびデシリアライザーとして使用できます。

開発者は、org.apache.soap.util.xml.Serializer およびorg.apache.soap.util.xml.Deserializer を個別にインプリメントしてカスタム処理を実行させることにより、カスタム・シリアライザーおよびカスタム・デシリアライザーを作成することもできます。

以下に示すサンプルを使って、このカスタム・エンコードの方法について説明します。


SOAPプロトコルと添付オブジェクト

SOAPメッセージと一緒に、画像、図、XML文書などさまざまな種類の添付オブジェクトを転送しなければならない場合が多くあります。これらのデータは、通常、特定のバイナリー・フォーマットのデータです。SOAP with Attachments 仕様には、MIMEパートを参照するための 'MIME multipart/related ' メディア・タイプおよびURIスキームの使用方法が詳しく記述されています。SOAP添付オブジェクトは、すべてのWebサービス・ツールキットでサポートされているわけではありません。Microsoftでは、DIMEに基づく別の添付ソリューションを提案しています(参考文献を参照)。

ここでは、添付オブジェクト付きのSOAPメッセージの構成方法、およびSOAPメッセージから添付オブジェクトを参照する方法について説明します。

SOAPメッセージ・パッケージ

SOAPメッセージ・パッケージには、XMLフォーマットの基本SOAPメッセージと、SOAPエンベロープには定義されていないが、メッセージに関連したあらゆるデータ・フォーマット (gif, jpg, xmlなど) のその他のエンティティーが含まれます。

図1 に示されるように、SOAPメッセージ・パッケージは、各パートが (Context-Type ヘッダーで定義されている) MIME境界に組み込まれたMIMEのMultipart/relatedメディア・タイプを使って構成されます。各MIMEパートには、Context-TypeContent Transfer-encodingContent-ID、およびContent-Location といったヘッダー情報が含まれています。Context-Type は、このMIMEパートに組み込まれたデータの型を指定し、Content Transfer-encoding は、このMIMEパートに使用されるエンコード方式を指定します。また、Content-IDContent-Location は、MIMEパッケージのあらゆる場所からこのコンテンツを参照するための識別子として使用されます。MIMEメッセージのルートパートに含まれるSOAPエンベロープでは、Content-Type がtext/xml に設定されています。

図1. SOAPメッセージ・パッケージ
図1. SOAPメッセージ・パッケージ

SOAPでの添付オブジェクトの参照

SOAPメッセージのSOAPヘッダーおよびSOAPボディは、メッセージ・パッケージ内のほかのエンティティーを参照する場合があります。SOAP 1.1エンコード規則に基づき、SOAPの 'href' 属性 ( 図1を参照) を使ってリソースを参照することができます。

リソースはContent-ID またはContent-Location を使って参照されます。識別子としてContent-ID を使用している場合、スキーマ属性 (たとえばhref) には、図1 に示されるように、(rfc 2153に基づく) URLスキームCIDを使用する必要があります。識別子としてContent-Location を使用している場合は、SOAP with Attachments 仕様で指定されている以下の規則に基づいて、解決を行う必要があります:

  • 絶対URI参照 - SOAPエンベロープ内のContent-Location と 'href' 属性の両方で絶対URLが指定されます。
  • 相対URI参照 - MIMEメッセージのメイン・ヘッダーのContent-Location で、基本URLが指定されていて、すべての相対URLがこの基本URLを使って参照されます。
  • 基本URIがない相対参照 - メイン・ヘッダーのContent-Location には基本URLが指定されていませんが、メッセージの基本URLが使用され、すべての相対URLがこの基本URLを使って参照されます。

通常、URIを解決する必要があるかどうかを判断するのはSOAPプロセッサーです。また、SOAPエンベロープにURI参照を持たないメッセージ・パッケージ内に添付オブジェクトが存在する場合もあります。

HTTPバインディング
SOAPでHTTPバインディングを使って添付オブジェクトを送信する場合、HTTPヘッダーを変更してSOAP MIMEパッケージ・ヘッダーからのContent-Type 情報を組み込む必要があります。HTTPヘッダーには、MIMEパッケージ・ヘッダーからのその他のヘッダー情報は含まれません。Apacheは、Content-Transfer-Encoding やMIMEのVersion 情報などのヘッダーを無視します。SOAPエンベロープパートやその他の添付オブジェクトを含むすべてのMIMEパートがHTTPボディを形成します。一方、SMTPバインディングの場合、すべてのmultipart MIMEヘッダーがSMTPヘッダーの一部として保存されます。そのため、SOAPプロセッサーおよびSOAPアプリケーションは、種類の異なるSOAPバインディング間のヘッダーの非互換性に対応する必要があります。

添付オブジェクト付きWebサービスを記述するWSDLのサポート
次のWSDL文書に示されるように、バインディング・エレメントの入出力エレメントは、さまざまなMIMEパート (SOAPボディや添付オブジェクト用のMIMEパート) とともに、mime:multipartRelatedの下に拡張され、パッケージされます。添付オブジェクトを含む各MIMEパートには、コンテンツの種類を指定することもできます。

リスト1: MIMEのWSDLバインディングの拡張
 <binding name="DocManagementService_Binding"  ... />
  <operation  name="SubmitArrayOfDocuments">
    <soap:operation soapAction="http://www.DocManagementService.com/SubmitArrayOfData"/>
    <input>
      <mime:multipartRelated>
          <mime:part>
      		<soap:body
	encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
	namespace="urn:DocManagement-service"
	parts="SubmitArrayOfDocuments_inType1 SubmitArrayOfDocuments_inType2"
	use="encoded"/>
          </mime:part>
          <mime:part>
            <mime:content part="SubmitArrayOfDocuments_inType3" type="*/*"/>
          </mime:part>
	</mime:multipartRelated>
    </input>
    <output>
      <soap:body
	encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
	namespace="urn:DocManagement-service" 
	use="encoded"/>
    </output>
  </operation>
</binding>

Apache SOAP 2.2ツールキットによるSOAP with Attachmentsのサポート

Apache SOAPツールキット・バージョン2.2では、W3CのSOAP with Attachments Noteに基づく添付オブジェクト付きSOAPがサポートされています。サービスの種類やきめ細かい制御の必要性に応じて、ツールキットでは、添付オブジェクトを処理するための以下のようなさまざまな技法が使用できます。

  • javax.activation.Datasourceオブジェクトおよびjavax.activation.DataHandlerオブジェクトを使って添付オブジェクトを処理するシリアライザー / デシリアライザーが組み込まれています。これは主にRPCベースのクライアント / サーバー呼び出しに使用されます。
  • 添付オブジェクトの処理をよりきめ細かく制御する必要がある場合、org.apache.soap.messaging.Message、org.apache.soap.rpc.Call、およびorg.apache.soap.rpc.Responseといったクライアント・サイド・クラスや、サーバー・サイドのSoapContextクラスで、メソッド (addBodyPart(..)、findBodyPart(..)、getBodyPart(..) など) を利用することができます。これらのメソッドにより、SOAPメッセージにjavax.mail.internet.MimeBodyPartを追加したり、検索したりすることができます。

添付オブジェクト付きSOAPの使用には、以下のような数多くの問題点があります。

  • SOAP with Attachments 仕様は 'MIME Multipart/related' に基づいています。SOAPコミュニティーでは、'MIME Application/Multiplexed' を使用する際、どのバイナリー・コンテンツをメインのXML文書にインターリーブするか議論になっています。これを使用すると、添付オブジェクトを含むすべてのデータが直ちにメモリーにロードされないため、アプリケーションのスケーラビリティーが向上します。
  • Apache SOAP 2.2やWASPなど、いくつかのツールキットしかSOAP with Attachments 仕様標準をサポートしていません。
  • 現在、多くのSOAPツールキットは添付オブジェクトまたはメッセージとして送信される大容量データを処理するためのストリーミング・モデルをサポートしていません。そのため、SOAPプロセッサーのスケーラビリティーやパフォーマンスが制限されてしまいます。

簡単な実装サンプル

このサンプルの作成について

このWebSphere Application Server 4.0環境の実装サンプルは、Web Services ToolKit 2.4.2およびApache SOAPツールキット2.2を使って作成しました。新しいバージョンのWSTKが既に存在しますが、互換性がないため、古いバージョンを使用しました。ソース・コード、.ear (エンタープライズ・アプリケーション・アーカイブ)、.war (文書マネージャーWebモジュール)、その他のファイル(DD.xmlや .wsdlファイル)、およびインストールに必要な情報('setup.doc' を参照) を含むZIPファイル (DocumentManager.zip) をダウンロードできます。このサンプルには、クライアント・ソース・ファイルやクライアント・クラス・ファイルのサンプルも含まれています (参考文献を参照)。

この実装サンプルでは、Webベース・アプリケーションを作成して、エンド・ユーザーがWebサーバーにファイルをアップロードしたり、Webサーバーからファイルをダウンロードできるようにする方法を紹介します。このアプリケーションは、Webサービス・ベースの呼び出しモデルを提供します。このWebサービス・アプリケーションを使うと、ユーザーは、ファイルを何個でもサーバーにアップロードすることができ、それらのファイルへの参照を取得したり、その参照を使って必要なファイルをダウンロードすることもできます。

このサンプルは、カスタム型マッピング、複数の添付オブジェクトの送信、およびMIME添付オブジェクトをサポートする拡張WSDL文書構成を理解する上で役に立ちます。また、配列のようなカスタム・データを送信したり、検索する方法を理解する上でも役に立ちます。この単純なアプリケーションをグローバルなWebベース・ファイル管理アプリケーションに拡張することも可能です。ただし、このサンプルは、そのような大規模なアプリケーションを開発する上で必ず考慮しなければならないセキュリティー、国際化対応、プライバシー、およびパフォーマンスといったより複雑な問題には対応していません。

フロントエンド・クライアントおよびバックエンド・サーバーのサービス記述 (WSDL) には、文書管理アプリケーションから提示されるサービス情報が含まれます。WSDLバインディングは拡張され、MIMEタイプmultipart/relatedを使用するMIMEフォーマットをサポートしています。バックエンドWSDLファイルをリスト2、フロントエンドWSDLファイルをリスト3 に示します。

リスト2:DocumentManagement-Interface.wsdl
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="DocumentManagementService_Interface"
  targetNamespace=
"http://www.DocumentManagementService.com/DocumentManagementService_interface"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns=
"http://www.DocumentManagementService.com/DocumentManagementService_interface"
  xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:types=
"http://www.DocumentManagementService.com/DocumentManagementService_interface/types/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<types>
  <xsd:schema targetNamespace=
"http://www.DocumentManagementService.com/DocumentManagementService_interface/types/"
   xmlns="http://www.w3.org/2001/XMLSchema/">
    <xsd:complexType name="User">
	<xsd:sequence>
		<xsd:element name="userName" type="xsd:string"/>
		<xsd:element name="password" type="xsd:string"/>
	</xsd:sequence>
    </xsd:complexType>
	<xsd:complexType name="DocumentInformation">
	<xsd:sequence>
		<xsd:element name="userDefinedDocName" type="xsd:string"/>
		<xsd:element name="localPathInfo" type="xsd:string"/>
	</xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="ArrayOfDocumentInformation">
		<xsd:complexContent>
			<xsd:restriction base="SOAP-ENC:Array">
				<xsd:sequence>
					<element minOccurs="0" maxOccurs="unbounded" 
					name="docInfo" type=" DocumentInformation"/>
				</xsd:sequence>
				<xsd:attribute ref="SOAP-ENC:arrayType" 
				wsdl:arrayType="DocumentInformation[]"/>
			</xsd:restriction>
		</xsd:complexContent>
	</xsd:complexType>

	<xsd:complexType name="DocumentReference">
		<xsd:sequence>
			<xsd:element name="docCreateDateTime" type="xsd:datetime"/>
			<xsd:element name="docRefType" type="xsd:string"/>
			<xsd:element name="serverDocPath" type="xsd:string"/>
			<xsd:element name="localPathInfo" type="xsd:string"/>
			<xsd:element name="userDefinedDocName" type="xsd:string"/>
			<xsd:element name="docRef" type="xsd:string"/>
		</xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="ArrayOfDocumentReference">
		<xsd:complexContent>
			<xsd:restriction base="SOAP-ENC:Array">
				<xsd:sequence>
					<element minOccurs="0" maxOccurs="unbounded" 
					name="docRef" 
					type="DocumentReference"/>
				</xsd:sequence>
				<xsd:attribute ref="SOAP-ENC:arrayType" 
				wsdl:arrayType="DocumentReference[]"/>
			</xsd:restriction>
		</xsd:complexContent>
	</xsd:complexType>
    <xsd:complexType name="ArrayOfString">
		<xsd:complexContent>
			<xsd:restriction base="SOAP-ENC:Array">
				<xsd:sequence>
					<element maxOccurs="unbounded" name="docs" 
					type="xsd:string"/>
				</xsd:sequence>
				<xsd:attribute ref="SOAP-ENC:arrayType" 
				wsdl:arrayType="xsd:string[]"/>
			</xsd:restriction>
		</xsd:complexContent>
	</xsd:complexType>
  </xsd:schema>
</types>
<message name="InSubmitArrayOfDocumentsRequest">
  <part name="SubmitArrayOfDocuments_inType1" type="types:User"/>
  <part name="SubmitArrayOfDocuments_inType2" 
type="types:ArrayOfDocumentInformation"/>
  <part name="SubmitArrayOfDocuments_inType3" 
type="types:ArrayOfString"/>
</message>
<message name="OutSubmitArrayOfDocumentsResponse">
  <part name="SubmitArrayOfDocuments_outType" type=
"types:ArrayOfDocumentReference"/>
</message>

<message name="InFetchDocumentsRequest">
 <part name="FetchDocuments_inType1" type="types:User"/>
  <part name="FetchDocuments_inType2" type=
"types:ArrayOfDocumentReference"/>
</message>
<message name="OutFetchDocumentsResponse">
<part name=" FetchDocuments_outType1" type="xsd:string"/>
</message>
<message name="InPingDocumentMangerRequest">
 <part name="PingDocumentManger_inType1" type="xsd:string"/>
</message>
<message name="OutPingDocumentMangerResponse">
  <part name="PingDocumentManger_outType1" type="xsd:string"/>
</message>
<portType  name="DocumentManager_portType">
  <operation  name="SubmitArrayOfDocuments">
    <input message="tns:InSubmitArrayOfDocumentsRequest"/>
    <output message="tns:OutSubmitArrayOfDocumentsResponse"/>
  </operation>
  <operation name="FetchDocuments">
    <input  message="tns:InFetchDocumentsRequest"/>
    <output message="tns:OutFetchDocumentsResponse"/>
  </operation>
  <operation name="PingDocumentManger">
    <input  message="tns:InPingDocumentMangerRequest"/>
    <output message="tns:OutPingDocumentMangerResponse"/>
  </operation>
</portType>
<binding name="DocumentManagementService_Binding_Rpc" type=
"tns:DocumentManager_portType">
  <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
   <operation  name="SubmitArrayOfDocuments">
    <soap:operation soapAction="http://www.DocManagementService.com/SubmitArrayOfData"/>
    <input>
      <mime:multipartRelated>
          <mime:part>
      		<soap:body 
		encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
		namespace="urn:DocumentManagement-service"
		parts="SubmitArrayOfDocuments_inType1 SubmitArrayOfDocuments_inType2"
		use="encoded"/>
          </mime:part>
          <mime:part>
            <mime:content part="SubmitArrayOfDocuments_inType3" type="text/html"/>
          </mime:part>
	</mime:multipartRelated>
    </input>
    <output>
      <soap:body
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="urn:DocumentManagement-service"
      use="encoded"/>
    </output>
   </operation>
   <operation name="FetchDocuments">
    <soap:operation soapAction="http://www.DocManagementService.com/FetchDocuments"/>
    <input>
     <mime:multipartRelated>
          <mime:part>
        	 <soap:body
          		encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
	            namespace="urn:DocManagement-service"
		      parts="FetchDocuments_inType1 FetchDocuments_inType2"
      	      use="encoded"/>
	    </mime:part>
     </mime:multipartRelated>
  </input>
  <output>
       <soap:body 
			encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
			namespace="urn:DocManagement-service" use="encoded"/>
  </output>
</operation>
  <operation name="PingDocumentManger">
    <soap:operation soapAction=
"http://www.DocumentManagementService.com/PingDocumentManger"/>
    <input>
      <soap:body
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="urn:DocumentManagement-service"
          use="encoded"/>
    </input>
    <output>
      <soap:body
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="urn:DocumentManagement-service" use="encoded"/>
    </output>
  </operation>
</binding>
</definitions>
リスト3: DocumentManager.wsdl
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="DocManagementServiceDefinition" 
	xmlns="http://schemas.xmlsoap.org/wsdl/" 
	xmlns:interface=
	http://www.DocumentManagementService.com/DocumentManagementService_interface" 
	xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
	xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
	targetNamespace=
	"http://www.DocManagementService.com/DocManagementService" >
<import location=
"http://joshyjjp:4040/DocumentManager/DocumentManager-Interface.wsdl" 
namespace=
"http://www.DocumentManagementService.com/DocumentManagementService_interface" />
<service name="DocManagementService">
  <documentation>Document Management Web Service: 
This service will allow user to manage their documents 
</documentation>
  <port binding=
"interface:DocumentManagementService_Binding_Rpc" 
name="DocManagementService_RPC">
    <soap:address location=
"http://joshyjjp:4040/dmsoap/servlet/rpcrouter"/>
  </port>
  <port binding="interface:DocumentManagementService_Binding_Message"
name="DocManagementService_Message">
    <soap:address location=
"http://joshyjjp:4040/dmsoap/servlet/messagerouter"/>
  </port>
</service>
</definitions>

バックエンド・サービスの実装

(リスト4 に示す) バックエンド・サービスの実装は、SubmitArrayOfDocumentsFetchDocuments などのパブリックにアクセス可能なサービス・メソッドを用いてDocumentManagementImpl クラスで処理されます。ここでは、SubmitArrayOfDocuments が使用されています。このサービスは、RPCベースのSOAPサービス・メソッドであり、SOAPContext (添付オブジェクトの処理)、User (ユーザー情報)、およびDocumentInfo の配列 (サーバーにサブミットされた添付文書) といったパラメーターが指定されています。FetchDocuments メソッドは、パラメーターとしてユーザー情報と文書参照オブジェクトの両方を持つRPCベースのサービスです。文書参照オブジェクトには、既にサーバーにサブミットされ、保存されている文書に関する情報(docRefId) が含まれています。

リスト4: DocumentManagementImplクラス
 // apache soap
import org.apache.soap.*;
import org.apache.soap.rpc.*;
import org.apache.soap.util.xml.XMLParserUtils;
import org.apache.soap.encoding.SOAPMappingRegistry;
// MIME
import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;
// java
import java.io.*;
import java.util.*;
public class DocumentManagementImpl implements DocumentManagement{
	
/* 
	Submit an array of documents to the Document Manger; Attached data has to 
	be retrieved from the SOAPContext.
	Once the attached data is retrieved it will be saved to the disk at 
	the server and a document reference will	be returned to the user.
	*/
public DocumentReference[] SubmitArrayOfDocuments
(SOAPContext requestContext, User user, DocumentInfo[] localDocInfo) 
throws Exception{
	
	DocumentReference [] refArray = null;
		try{
			// get the document information 
			int docCount = localDocInfo.length;
			if(docCount >0){
				// get attachment count
				int attachmentCount = requestContext.getCount();
// there docCount docs to be saved and if successful there will be 
// that many document reference 
// for the client
			refArray = new DocumentReference[docCount]; 
				
MimeBodyPart mbp = null;
				// Get root part
    				MimeBodyPart rootPart = requestContext.getRootPart();
				// Detach Attachments if present
	   for (int i = 0; i < requestContext.getCount(); i++){
			      // Get next attachment
      	mbp = (MimeBodyPart)requestContext.getBodyPart(i);
	     	if (!(mbp.equals(rootPart))){ 
			// the root element is the soap envelope
      		String type = mbp.getContentType();
    		String Id = mbp.getContentID();
    		String cntType = mbp.getContentType();
String location = mbp.getHeader
(org.apache.soap.Constants.HEADER_CONTENT_LOCATION, null);
		String name = mbp.getFileName();
			Object content = mbp.getContent();
			String classType = content.getClass().getName();
	
			if (mbp.isMimeType("text/*")){
				System.out.println("The MIME data is in text format");
		}else{
				System.out.println("The MIME data is in binary format");
			}
			// save each attachment to the file system
			DocumentReference dofRef = 
			saveDocument(user,localDocInfo[i-1],content);
		refArray[i-1]= dofRef; // set the return document reference
		 }
	}
}		
    		}catch(Exception e){
			System.out.println
			("There is an exception "+ e.toString());
			throw e;
    		}
		return refArray;
	   }
/* Get all the documents that already saved in the server with the respective 
document reference number. All the documents should be send back 
to the user as attachments. */
public  void FetchDocuments (DocumentReference[] docRef){
.............................................................................................
}
private synchronized DocumentReference saveDocument(User user, DocumentInfo 
userDefinedDocName, Object content){
	// save the document in the server and return a reference to the user.
..............................................................................
}	 
}

ここでは、SOAPContextリクエスト・オブジェクトを使って、サービス・コードに示される添付情報を取得しています。このSOAPContextオブジェクトには、SOAPエンベロープを含むルートパートを持つMIMEパートの配列であるボディパートが含まれます。MIMEボディパートから、コンテンツID、コンテンツの種類、および場所といった多くの情報を取得することができます。

カスタム型マッピング・レジストリーは、Deployment Descriptor.xmlファイル (isd:mappingセクションを参照) に示される配置ディスクリプタを使ってセットアップされています。SOAPサーバーは、型マッピング情報および必要なシリアライゼーション・クラスとデシリアライゼーション・クラスをロードし、UserやDocumentInfoなどのカスタムJavaテクノロジー・クラスに型をマーシャルおよびアンマーシャルします。

Documentベースのメソッドを追加して、添付オブジェクトをきめ細かく制御するには、SOAPContext 'reponse' オブジェクトを使ってMIME添付オブジェクトを作成します。このオブジェクトは、'document' ベースのメソッドの呼び出しに対するパラメーターです。このSOAPContextオブジェクトには、SOAPエンベロープを含むルートパートを持つMIMEパートの配列であるボディパートが含まれます。

制御情報 (ユーザー名、アップロードされたファイルの情報、およびファイル参照ID) はXML文書 (DocumentManger.xml) を使用してサーバーに保存されます。

クライアント・サービスの実装

以下に示すように、クライアント・コードは、SOAPMappingRegistry内に型マッピング情報を作成し、User、DocumentInfo、DocumentReferenceなどのJavaテクノロジー・クラスをマーシャルおよびアンマーシャルして、その情報をリクエスト・オブジェクトにバインドします。

// set the SOAP mapping registry
      BeanSerializer beanSer = new BeanSerializer(); 
	// java bean based standard serializer
	SOAPMappingRegistry smr = new SOAPMappingRegistry();
	smr.mapTypes(Constants.NS_URI_SOAP_ENC,new QName
	("urn:xml-docmanger-webservice", "user"),User.class, beanSer, beanSer);	
	
// set the mapping registry
	request.setSoapMappingRegistry(smr);

JavaBeanデザイン・パターンに続くUserなどのクラスのシリアライゼーションおよびデシリアライゼーションにBeanシリアライザー・クラス(BeanSerializer) が使用されています。

Attachments are created using DataSource, DataHandler 
	and MimeBodyPart classes and bind to the request object as show below, 
	// Now create attachments and add to the request
DataSource ds = new ByteArrayDataSource(new File("Compile.bat"), null);

上のサンプルでは、Compile.bat ファイルが添付オブジェクトとして送信されます。

DataHandler dh = new DataHandler(ds);
      MimeBodyPart mbp = new MimeBodyPart();
      mbp.setDataHandler(dh);
      // Add the attachment to the service request
      request.addAttachment(mbp);

クライアントの実装をリスト5 に示します。コードの大部分は説明無しでわかると思います。

リスト5: 文書クライアント・コード
	// Service Implementation URL
     	String wsdlSvcImplURL = Util.formatURL(WSTKConstants.SERVER_HOSTNAME,
                                      WSTKConstants.SERVER_PORT,
                                      svcImplUrl);
     	 // get the WSDL document
	WSDLDocument wsdlDoc = new WSDLDocument(new URL(wsdlSvcImplURL));

    	// Get the service proxy you will use to invoke service based on the WSDL document
    	ServiceProxy serviceProxy = ServiceProxyFactory.getServiceProxy
(serviceName,portName,wsdlDoc);

      	// SubmitArrayOfDocuments RPC based operation expects 2 input arguments
      	Object oArgs = new Object[2];
	
	// the parameters are 
	// 1. user information
	User user = new User (userName,userPassword);
	
	// 2. an array of submited document information
	DocumentInfo[] docInfo = new DocumentInfo[1];
	docInfo[0] = new DocumentInfo("compile.bat","d:\\data");

	// Setting up the type mapping registry to handle custom java objects
	// setup the serializers; 
	BeanSerializer beanSer = new BeanSerializer(); 
	// java bean based standard serializer
	// set the soap mapping registry
	SOAPMappingRegistry smr = new SOAPMappingRegistry();
	// input parameters
	smr.mapTypes(Constants.NS_URI_SOAP_ENC,
            	new QName("urn:xml-docmanger-webservice", "user"),
            User.class, beanSer, beanSer);
	smr.mapTypes(Constants.NS_URI_SOAP_ENC,
            	new QName("urn:xml-docmanger-webservice", "documentinfo"),
            DocumentInfo.class, beanSer, beanSer);
	// output parameters
	smr.mapTypes(Constants.NS_URI_SOAP_ENC,
                       new QName("urn:xml-docmanger-webservice", "documentreference"),
                      DocumentReference.class, beanSer, beanSer);

 // Set input arguments
	 oArgs[0] = user;
	 oArgs[1] = docInfo;

	// Set up the request
    	SoapServiceRequest request = new SoapServiceRequest 
("SubmitArrayOfDocuments", oArgs);
	// set the mapping registry
	request.setSoapMappingRegistry(smr);

	// Now create attachments and add to the request
            DataSource ds = new ByteArrayDataSource(new File("Compile.bat"), null);
      	DataHandler dh = new DataHandler(ds);
	MimeBodyPart mbp = new MimeBodyPart();
	mbp.setDataHandler(dh);
      	mbp.setFileName("Compile.bat");
	mbp.setHeader
	(org.apache.soap.Constants.HEADER_CONTENT_LOCATION, "Attachment-1");

      	// Add the attachment to the service request
	request.addAttachment(mbp);
    	// Invoke the operation
    	ServiceResponse sr = serviceProxy.invoke(request);

	// Pull the soap response object from the results
    	Response response = (Response) sr.getOneResult(1);
	// If the call to the service failed, then display error information
	if (response.generatedFault()){
      		handleFault(response);
	} else {
      	// Get return value
	      Parameter parameter = response.getReturnValue();
	      // Display results
	      	System.out.println("Message returned from service provider: \n");
		retRef = (DocumentReference[])parameter.getValue();
		for(int i=0;i<retRef.length;i++){
			System.out.println("Document reference id = "+retRef[i].getDocRef());
     		}
       }
	
	// Now fetch the documents uploaded to the server by using the document references
........................................................................	
	// Pull the soap response object from the results
    	response = (Response) sr.getOneResult(1);
	// If the call to the service failed, then display error information
	if (response.generatedFault()){
          handleFault(response);
      }else{
      		// Get return value
	      int attachCount = sr.getAttachmentCount();
      		// Display results
     	 	System.out.println("Number of attachments = " +attachCount);
       }
    }

最後に、サービス配置ディスクリプタをリスト6 に示します。

リスト6: 文書管理サービスの配置ディスクリプタ
<root>
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment" 
id="urn:DocumentManagement-service" checkMustUnderstands="false">
  <isd:provider type="java" scope="Application" 
methods="PingDocumentManger SubmitArrayOfDocuments FetchDocuments">
    <isd:java class="DocumentManagementImpl" static="false"/>
  </isd:provider>
 <isd:faultListener>org.apache.soap.server.DOMFaultListener</isd:faultListener>
  <isd:mappings>
    <isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
             xmlns:x="urn:xml-docmanger-webservice" qname="x:user"
             javaType="User"
             java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer"
             xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/>
    <isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
             xmlns:x="urn:xml-docmanger-webservice" qname="x:documentreference"
             javaType="DocumentReference"
             java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer"
             xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/>
    <isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
             xmlns:x="urn:xml-docmanger-webservice" qname="x:documentinfo"
             javaType="DocumentInfo"
             java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer"
             xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/>
  </isd:mappings>    
</isd:service>
</root>

今後の傾向

XML Protocol委員会では、新しいソフトウェア・プラクティスと使用シナリオの定義作業を開始しました。この作業には、複数の非同期メッセージング、キャッシング、ルーティング、および大容量データのストリーミングが含まれます。標準化には時間がかかるかもしれませんが、直接添付による単なるブロック転送ではないデータ・ストリーム機能などの新機能を備えたSOAPプロセッサーの登場が期待できます。新しいプロトコルであるBEEP(Blocks Extensible Exchange Protocol) は、1つのTCP接続で複数のチャネルをサポートしていて、非同期型のデータ通信やストリーミング型のデータ通信に使用できます。

DIME (Direct Internet Message Encapsulation) は、もう1つの軽量なバイナリー・メッセージ・フォーマットです。これを使うと、型およびサイズが任意に指定された、アプリケーション定義の1つまたは複数のペイロードを単一のメッセージ構成にカプセル化することができます。DIMEには、2つの利点があります。送信者は、ペイロードのサイズをあらかじめ計算するか、ペイロードを固定サイズのレコードにまとめます。これにより、サーバー・アプリケーション側では、必要となるメモリーを前もって計算できるため、パフォーマンスが向上します。また、URIメカニズムを使って新しいメディア・タイプを指定する機能により、受け側のアプリケーションで、新しいメディア・タイプ用のハンドラーをロードできます。ただし、これは、大部分がMicrosoftによって定義された仕様です。

Apache SOAPの最新バージョンであるApache AXISは、現在アルファ段階です。しかし、AXISツールキットのソースやサンプル、およびIBMのWSTK 3.0ツールキットを詳しく観察すると、AXISにおける添付オブジェクト付きSOAPの実装の今後の変更点を多少なりとも理解することができます。RPCベースのサービス・メソッドでは、添付オブジェクトはAxis DataHandlerとしてサービスに渡されます。これに対して、Documentベースのサービス・メソッドでは、パラメーターとしてMessageContextオブジェクトが使用されます。このオブジェクトには、MessageオブジェクトやAttachmentsオブジェクトが含まれ、その中に、添付オブジェクトやSOAPデータが 'Parts' として含まれています。

参考文献

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=SOA and web services
ArticleID=244289
ArticleTitle=SOAP での添付オブジェクトの処理
publish-date=022002