第41章 生の XML メッセージの使用

概要

高レベルの JAX-WSAPI は、データを JAXB オブジェクトにマーシャリングすることにより、開発者がネイティブ XML メッセージを使用するのを防ぎます。ただし、ネットワーク上を通過する生の XML メッセージデータに直接アクセスする方がよい場合があります。JAX-WS API は、生の XML へのアクセスを提供する 2 つのインターフェイスを提供します。Dispatch インターフェイスはクライアント側インターフェイスであり、Provider インターフェイスはサーバー側インターフェイスです。

41.1. コンシューマーでの XML の使用

概要

Dispatch インターフェイスは、生のメッセージを直接操作できる低レベルの JAX-WSAPI です。DOM オブジェクト、SOAP メッセージ、JAXB オブジェクトなど、さまざまな種類のメッセージまたはペイロードを受け入れて返します。これは低レベルの API であるため、Dispatch インターフェイスは、高レベルの JAX-WS API が実行するメッセージの準備を実行しません。Dispatch オブジェクトに渡すメッセージまたはペイロードが適切に構築されていること、および呼び出されているリモート操作に意味があることを確認する必要があります。

41.1.1. 使用モード

概要

ディスパッチオブジェクトには 2 つの 使用モード があります。

Dispatch オブジェクトに指定する使用モードによって、ユーザーレベルのコードに渡される詳細の量が決まります。

メッセージモード

メッセージモード では、Dispatch オブジェクトは完全なメッセージで機能します。完全なメッセージには、バインディング固有のヘッダーとラッパーが含まれます。たとえば、SOAP メッセージを必要とするサービスと対話するコンシューマーは、Dispatch オブジェクトの invoke() メソッドに完全に指定された SOAP メッセージを提供する必要があります。invoke() メソッドも、完全に指定された SOAP メッセージを返します。コンシューマーコードは、SOAP メッセージのヘッダーと SOAP メッセージのエンベロープ情報を完成させて読み取る責任があります。

JAXB オブジェクトを操作する場合、メッセージモードは理想的ではありません。

Dispatch オブジェクトがメッセージモードを使用するように指定するには、Dispatch オブジェクトを作成するときに値 java.xml.ws.Service.Mode.MESSAGE を指定します。Dispatch オブジェクトの作成方法は 「ディスパッチオブジェクトの作成」 を参照してください。

ペイロードモード

メッセージペイロードモードとも呼ばれる ペイロードモード では、Dispatch オブジェクトはメッセージのペイロードのみを処理します。たとえば、ペイロードモードで動作する Dispatch オブジェクトは、SOAP メッセージの本文でのみ機能します。バインディングレイヤーは、バインディングレベルのラッパーとヘッダーを処理します。invoke() メソッドから結果が返されると、バインディングレベルのラッパーとヘッダーはすでに取り除かれ、メッセージのボディーのみが残ります。

Apache CXF XML バインディングなど、特別なラッパーを使用しないバインディングを使用する場合は、ペイロードモードとメッセージモードで同じ結果が得られます。

Dispatch オブジェクトがペイロードモードを使用することを指定するには、Dispatch オブジェクトを作成するときに値 java.xml.ws.Service.Mode.PAYLOAD を指定します。Dispatch オブジェクトの作成方法は 「ディスパッチオブジェクトの作成」 を参照してください。

41.1.2. データ型

概要

Dispatch オブジェクトは低レベルのオブジェクトであるため、高レベルのコンシューマー API と同じ JAXB 生成タイプを使用するように最適化されていません。ディスパッチオブジェクトは、次のタイプのオブジェクトで機能します。

ソースオブジェクトの使用

Dispatch オブジェクトは、javax.xml.transform.Source インターフェイスから派生したオブジェクトを受け入れて返します。ソースオブジェクトは、メッセージモードまたはペイロードモードのいずれかで、任意のバインディングによってサポートされます。

ソースオブジェクトは、XML ドキュメントを保持する低レベルのオブジェクトです。各 Source 実装は、保存された XML ドキュメントにアクセスし、その内容を操作するメソッドを提供します。次のオブジェクトは、ソースインターフェイスを実装します。

DOMSource
XML メッセージを Document Object Model (DOM) ツリーとして保持します。XML メッセージは、getNode() メソッドを使用してアクセスされる Node オブジェクトのセットとして保存されます。ノードは、setNode() メソッドを使用して更新または DOM ツリーに追加できます。
SAXSource
XML メッセージを Simple API for XML (SAX) オブジェクトとして保持します。SAX オブジェクトには、未加工のデータを保持する InputSource オブジェクトと、未加工のデータを解析する XMLReader オブジェクトが含まれます。
StreamSource
XML メッセージをデータストリームとして保持します。データストリームは、他のデータストリームと同じように操作できます。

汎用 Source オブジェクトを使用するように Dispatch オブジェクトを作成する場合、Apache CXF はメッセージを SAXSource オブジェクトとして返します。

この動作は、エンドポイントの source-preferred-format プロパティーを使用して変更できます。Apache CXF ランタイムの設定についての情報は、パートIV「Web サービスエンドポイントの設定」 を参照してください。

SOAPMessage オブジェクトの使用

以下の条件が満たされる場合、Dispatch オブジェクトは javax.xml.soap.SOAPMessage オブジェクトを使用できます。

  • Dispatch オブジェクトは SOAP バインディングを使用しています
  • Dispatch オブジェクトはメッセージモードを使用しています

SOAPMessage オブジェクトは SOAP メッセージを保持します。これらには、1 つの SOAPPart オブジェクトと 0 個以上の AttachmentPart オブジェクトが含まれています。SOAPPart オブジェクトには、SOAP メッセージの SOAP 固有部分が含まれます。これには、SOAP エンベロープ、SOAP ヘッダー、および SOAP メッセージボディーが含まれます。AttachmentPart オブジェクトには、アタッチメントとして渡されるバイナリーデータが含まれます。

DataSource オブジェクトの使用

ディスパッチオブジェクトは、次の条件が当てはまる場合に、javax.activation.DataSource インターフェイスを実装するオブジェクトを使用できます。

  • Dispatch オブジェクトは HTTP バインディングを使用しています
  • Dispatch オブジェクトはメッセージモードを使用しています

DataSource オブジェクトは、URL、ファイル、バイト配列など、さまざまなソースからの MIME タイプのデータを操作するためのメカニズムを提供します。

JAXB オブジェクトの使用

Dispatch オブジェクトは、生のメッセージを操作できる低レベルの API を目的としていますが、JAXB オブジェクトを操作することもできます。JAXB オブジェクトを操作するには、使用中の JAXB オブジェクトをマーシャリングおよびアンマーシャリングできる JAXBContext を Dispatch オブジェクトに渡す必要があります。Dispatch オブジェクトの作成時に JAXBContext が渡されます。

JAXBContext オブジェクトによって認識される任意の JAXB オブジェクトを、パラメーターとして invoke() メソッドに渡すことができます。返されたメッセージを JAXBContext オブジェクトによって認識される JAXB オブジェクトにキャストすることもできます。

JAXBContext オブジェクト作成の詳細は、39章JAXBContext オブジェクトの使用 を参照してください。

41.1.3. ディスパッチオブジェクトの操作

手順

Dispatch オブジェクトを使用してリモートサービスを呼び出すには、次の手順に従う必要があります。

  1. Dispatch オブジェクトを 作成 します。
  2. リクエストメッセージを 設定 します。
  3. 適切な invoke() メソッドを呼び出します。
  4. 応答メッセージを解析します。

ディスパッチオブジェクトの作成

Dispatch オブジェクトを作成するには、次のようにします。

  1. Dispatch オブジェクトが呼び出しを行うサービスを定義する wsdl:service 要素を表す Service オブジェクトを作成します。「Serivce オブジェクトの作成」を参照してください。
  2. 例41.1「createDispatch() メソッド」 に示すように、 Service オブジェクトの createDispatch() メソッドを使用して、Dispatch オブジェクトを作成します。

    例41.1 createDispatch() メソッド

    publicDispatch<T>createDispatchQNameportNamejava.lang.Class<T>typeService.ModemodeWebServiceException

    注記

    JAXB オブジェクトを使用している場合、createDispatch() のメソッド署名は publicDispatch<T>createDispatchQNameportNamejavax.xml.bind.JAXBContextcontextService.ModemodeWebServiceException です。

    表41.1「createDispatch() のパラメーター」で、createDispatch() メソッドのパラメーターを説明します。

    表41.1 createDispatch() のパラメーター

    パラメーター説明

    portName

    Dispatch オブジェクトが呼び出しを行うサービスプロバイダーを表す wsdl:port 要素の QName を指定します。

    type

    Dispatch オブジェクトによって使用されるオブジェクトのデータ型を指定します。「データ型」を参照してください。JAXB オブジェクトを操作する場合、このパラメーターは JAXB オブジェクトのマーシャリングおよびアンマーシャリングに使用される JAXBContext オブジェクトを指定します。

    mode

    Dispatch オブジェクトの使用モードを指定します。「使用モード」を参照してください。

例41.2「ディスパッチオブジェクトの作成」に、ペイロードモードで DOMSource オブジェクトと連携する Dispatch オブジェクトを作成するコードを示します。

例41.2 ディスパッチオブジェクトの作成

package com.fusesource.demo;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;

public class Client
{
public static void main(String args[])
  {
    QName serviceName = new QName("http://org.apache.cxf", "stockQuoteReporter");
    Service s = Service.create(serviceName);

    QName portName = new QName("http://org.apache.cxf", "stockQuoteReporterPort");
    Dispatch<DOMSource> dispatch = s.createDispatch(portName,
                                                  DOMSource.class,
                                                  Service.Mode.PAYLOAD);
    ...

リクエストメッセージの作成

Dispatch オブジェクトを操作する場合、リクエストは最初から作成する必要があります。開発者は、Dispatch オブジェクトに渡されるメッセージが、対象のサービスプロバイダーが処理できる要求と一致することを確認する責任があります。これには、サービスプロバイダーが使用するメッセージと、サービスプロバイダーが必要とするヘッダー情報 (ある場合) に関する正確な知識が必要です。

この情報は、メッセージを定義する WSDL ドキュメントまたは XML スキーマドキュメントによって提供されます。サービスプロバイダーは大きく異なりますが、従うべきガイドラインがいくつかあります。

  • リクエストのルート要素は、呼び出される操作に対応する wsdl:operation 要素の name 属性の値に基づく。

    警告

    呼び出されるサービスが doc/literal ベアメッセージを使用する場合、リクエストのルート要素は、wsdl:operation 要素によって参照される wsdl:part 要素の name 属性の値に基づきます。

  • リクエストのルート要素は名前空間で修飾されています。
  • 呼び出されるサービスが rpc/literal メッセージを使用する場合、リクエストの最上位要素は名前空間で修飾されません。

    重要

    トップレベル要素の子は、名前空間で修飾されている場合があります。確実にするには、それらのスキーマ定義を確認する必要があります。

  • 呼び出されるサービスが rpc/literal メッセージを使用する場合、最上位の要素を null にすることはできません。
  • 呼び出されるサービスが doc/literal メッセージを使用する場合、メッセージのスキーマ定義によって、要素のいずれかが名前空間で修飾されているかどうかが判別されます。

サービスが XML メッセージを使用する方法の詳細については、WS-I 基本プロファイル を参照してください。

同期呼び出し

応答を生成する同期呼び出しを行うコンシューマーの場合は、例41.3「Dispatch.invoke() メソッド」に記載されている Dispatch オブジェクトの invoke() メソッドを使用します。

例41.3 Dispatch.invoke() メソッド

TinvokeTmsgWebServiceException

invoke() メソッドに渡される応答とリクエストの両方の型は、Dispatch オブジェクトの作成時に決定されます。たとえば、createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE) を使用して Dispatch オブジェクトを作成する場合、応答とリクエストの両方が SOAPMessage オブジェクトになります。

注記

JAXB オブジェクトを使用する場合、応答とリクエストの両方は、提供された JAXBContext オブジェクトがマーシャリングおよびアンマーシャリングできる任意の型にすることができます。また、応答と要求は異なる JAXB オブジェクトにすることができます。

例41.4「ディスパッチオブジェクトを使用した同期呼び出しの作成」に、DOMSource オブジェクトを使用してリモートサービスで同期呼び出しを行うコードを示します。

例41.4 ディスパッチオブジェクトを使用した同期呼び出しの作成

// Creating a DOMSource Object for the request
DocumentBuilder db = DocumentBuilderFactory.newDocumentBuilder();
Document requestDoc = db.newDocument();
Element root = requestDoc.createElementNS("http://org.apache.cxf/stockExample",
                                          "getStockPrice");
root.setNodeValue("DOW");
DOMSource request = new DOMSource(requestDoc);

// Dispatch disp created previously
DOMSource response = disp.invoke(request);

非同期呼び出し

ディスパッチオブジェクトは、非同期呼び出しもサポートします。40章非同期アプリケーションの開発 で説明されている高レベルの非同期 API と同様に、ディスパッチオブジェクトは、ポーリングアプローチとコールバックアプローチの両方を使用できます。

ポーリングアプローチを使用する場合、invokeAsync() メソッドは、応答が到達しているかどうかを確認するためにポーリングできる Response<t> オブジェクトを返します。例41.5「ポーリング用の Dispatch.invokeAsync() メソッド」 は、ポーリングアプローチを使用して非同期呼び出しを行うために使用されるメソッドのシグネチャーを示しています。

例41.5 ポーリング用の Dispatch.invokeAsync() メソッド

Response <T>invokeAsyncTmsgWebServiceException

非同期呼び出しにポーリングアプローチを使用する方法の詳細については、「ポーリングアプローチを使用した非同期クライアントの実装」 を参照してください。

コールバックアプローチを使用する場合は、invokeAsync() メソッドは、応答が返される時に処理する AsyncHandler 実装を受け取ります。例41.6「コールバックを使用した Dispatch.invokeAsync() メソッド」 は、コールバックアプローチを使用して非同期呼び出しを行うために使用されるメソッドのシグネチャーを示しています。

例41.6 コールバックを使用した Dispatch.invokeAsync() メソッド

Future<?>invokeAsyncTmsgAsyncHandler<T>handlerWebServiceException

非同期呼び出しにコールバックアプローチを使用する方法の詳細については、「コールバックアプローチを使用した非同期クライアントの実装」 を参照してください。

注記

同期 invoke() メソッドと同様に、応答の型およびリクエストの型は、Dispatch オブジェクトの作成時に決定されます。

一方向の呼び出し

リクエストが応答を生成しない場合は、Dispatch オブジェクトの invokeOneWay() を使用してリモート呼び出しを行います。例41.7「Dispatch.invokeOneWay() メソッド」 は、このメソッドのシグネチャーを示しています。

例41.7 Dispatch.invokeOneWay() メソッド

invokeOneWayTmsgWebServiceException

リクエストのパッケージ化に使用されるオブジェクトのタイプは、Dispatch オブジェクトの作成時に決定されます。たとえば、createDispatch(portName, DOMSource.class, Service.Mode.PAYLOAD) を使用して Dispatch オブジェクトが作成されている場合、リクエストは DOMSource オブジェクトにパッケージ化されます。

注記

JAXB オブジェクトを使用する場合、応答とリクエストは、提供された JAXBContext オブジェクトがマーシャリングおよびアンマーシャリングできる任意の型にすることができます。

例41.8「ディスパッチオブジェクトを使用して一方向の呼び出しを行う」 は、JAXB オブジェクトを使用してリモートサービスで一方向の呼び出しを行うためのコードを示しています。

例41.8 ディスパッチオブジェクトを使用して一方向の呼び出しを行う

// Creating a JAXBContext and an Unmarshaller for the request
JAXBContext jbc = JAXBContext.newInstance("org.apache.cxf.StockExample");
Unmarshaller u = jbc.createUnmarshaller();

// Read the request from disk
File rf = new File("request.xml");
GetStockPrice request = (GetStockPrice)u.unmarshal(rf);

// Dispatch disp created previously
disp.invokeOneWay(request);