第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 オブジェクトを使用してリモートサービスを呼び出すには、次の手順に従う必要があります。
ディスパッチオブジェクトの作成
Dispatch オブジェクトを作成するには、次のようにします。
-
Dispatch オブジェクトが呼び出しを行うサービスを定義する
wsdl:service
要素を表すService
オブジェクトを作成します。「Serivce オブジェクトの作成」を参照してください。 例41.1「
createDispatch()
メソッド」 に示すように、Service
オブジェクトのcreateDispatch()
メソッドを使用して、Dispatch オブジェクトを作成します。例41.1
createDispatch()
メソッドpublic
Dispatch<T>
createDispatch
QName
portName
java.lang.Class<T>
type
Service.Mode
mode
WebServiceException注記JAXB オブジェクトを使用している場合、
createDispatch()
のメソッド署名は publicDispatch<T>
createDispatch
QName
portName
javax.xml.bind.JAXBContext
context
Service.Mode
mode
WebServiceException です。表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()
メソッド
T
invoke
T
msg
WebServiceException
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>
invokeAsync
T
msg
WebServiceException
非同期呼び出しにポーリングアプローチを使用する方法の詳細については、「ポーリングアプローチを使用した非同期クライアントの実装」 を参照してください。
コールバックアプローチを使用する場合は、invokeAsync()
メソッドは、応答が返される時に処理する AsyncHandler 実装を受け取ります。例41.6「コールバックを使用した Dispatch.invokeAsync()
メソッド」 は、コールバックアプローチを使用して非同期呼び出しを行うために使用されるメソッドのシグネチャーを示しています。
例41.6 コールバックを使用した Dispatch.invokeAsync()
メソッド
Future<?>
invokeAsync
T
msg
AsyncHandler<T>
handler
WebServiceException
非同期呼び出しにコールバックアプローチを使用する方法の詳細については、「コールバックアプローチを使用した非同期クライアントの実装」 を参照してください。
同期 invoke()
メソッドと同様に、応答の型およびリクエストの型は、Dispatch オブジェクトの作成時に決定されます。
一方向の呼び出し
リクエストが応答を生成しない場合は、Dispatch オブジェクトの invokeOneWay()
を使用してリモート呼び出しを行います。例41.7「Dispatch.invokeOneWay()
メソッド」 は、このメソッドのシグネチャーを示しています。
例41.7 Dispatch.invokeOneWay()
メソッド
invokeOneWay
T
msg
WebServiceException
リクエストのパッケージ化に使用されるオブジェクトのタイプは、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);