41.2. サービスプロバイダーでの XML の使用
概要
プロバイダーインターフェイスは、低レベルの JAX-WS API であり、メッセージを生の XML として直接処理するサービスプロバイダーを実装できます。メッセージは、プロバイダーインターフェイスを実装するオブジェクトに渡される前に JAXB オブジェクトにパッケージ化されません。
41.2.1. メッセージングモード
概要
プロバイダーインターフェイスを実装するオブジェクトには、2 つの メッセージングモード があります。
指定するメッセージングモードは、実装に渡されるメッセージングの詳細のレベルを決定します。
メッセージモード
メッセージモード を使用する場合、プロバイダーの実装は完全なメッセージで機能します。完全なメッセージには、バインディング固有のヘッダーとラッパーが含まれます。たとえば、SOAP バインディングを使用するプロバイダー実装は、完全に指定された SOAP メッセージとして要求を受信します。実装から返される応答は、完全に指定された SOAP メッセージである必要があります。
Provider 実装がメッセージモードを使用するように指定するには、例41.9「プロバイダー実装がメッセージモードを使用するように指定する」に示すように、値 java.xml.ws.Service.Mode.MESSAGE を javax.xml.ws.ServiceMode
アノテーションの値として提供します。
例41.9 プロバイダー実装がメッセージモードを使用するように指定する
@WebServiceProvider @ServiceMode(value=Service.Mode.MESSAGE) public class stockQuoteProvider implements Provider<SOAPMessage> { ... }
ペイロードモード
ペイロードモード では、プロバイダーの実装はメッセージのペイロードのみを処理します。たとえば、ペイロードモードで動作するプロバイダー実装は、SOAP メッセージの本文でのみ機能します。バインディングレイヤーは、バインディングレベルのラッパーとヘッダーを処理します。
Apache CXF XML バインディングなど、特別なラッパーを使用しないバインディングを使用する場合は、ペイロードモードとメッセージモードで同じ結果が得られます。
Provider 実装がペイロードモードを使用するように指定するには、例41.10「プロバイダー実装がペイロードモードを使用するように指定する」に示すように、値 java.xml.ws.Service.Mode.PAYLOAD を javax.xml.ws.ServiceMode
アノテーションの値として提供します。
例41.10 プロバイダー実装がペイロードモードを使用するように指定する
@WebServiceProvider @ServiceMode(value=Service.Mode.PAYLOAD) public class stockQuoteProvider implements Provider<DOMSource> { ... }
@ServiceMode
アノテーションの値を指定しない場合、Provider 実装はペイロードモードを使用します。
41.2.2. データ型
概要
これらは低レベルのオブジェクトであるため、プロバイダーの実装では、高レベルのコンシューマー API と同じ JAXB 生成タイプを使用できません。プロバイダーの実装は、次のタイプのオブジェクトで機能します。
ソースオブジェクトの使用
プロバイダー実装は、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 オブジェクトを使用するように Provider オブジェクトを作成する場合、Apache CXF はメッセージを SAXSource
オブジェクトとして返します。
この動作は、エンドポイントの source-preferred-format
プロパティーを使用して変更できます。Apache CXF ランタイムの設定についての情報は、パートIV「Web サービスエンドポイントの設定」 を参照してください。
Source オブジェクトを使用する場合、開発者は、必要なすべてのバインディング固有のラッパーがメッセージに追加されるようにする責任があります。たとえば、SOAP メッセージを期待するサービスと対話する場合、開発者は、必要な SOAP エンベロープが送信要求に追加され、SOAP エンベロープの内容が正しいことを確認する必要があります。
SOAPMessage オブジェクトの使用
以下の条件が満たされる場合、Provider 実装は javax.xml.soap.SOAPMessage
オブジェクトを使用できます。
- プロバイダーの実装は SOAP バインディングを使用しています
- プロバイダーの実装はメッセージモードを使用しています
SOAPMessage
オブジェクトは SOAP メッセージを保持します。これらには、1 つの SOAPPart
オブジェクトと 0 個以上の AttachmentPart
オブジェクトが含まれています。SOAPPart
オブジェクトには、SOAP メッセージの SOAP 固有部分が含まれます。これには、SOAP エンベロープ、SOAP ヘッダー、および SOAP メッセージボディーが含まれます。AttachmentPart
オブジェクトには、アタッチメントとして渡されるバイナリーデータが含まれます。
DataSource オブジェクトの使用
プロバイダーの実装では、次の条件が当てはまる場合に、javax.activation.DataSource インターフェイスを実装するオブジェクトを使用できます。
- 実装は HTTP バインディングを使用しています
- 実装はメッセージモードを使用しています
DataSource オブジェクトは、URL、ファイル、バイト配列など、さまざまなソースからの MIME タイプのデータを操作するためのメカニズムを提供します。
41.2.3. プロバイダーオブジェクトの実装
概要
プロバイダーインターフェイスは、比較的簡単に実装できます。実装する必要があるメソッドが invoke()
の 1 つのみです。さらに、3 つの簡単な要件があります。
-
実装には
@WebServiceProvider
アノテーションが必要です。 - 実装には、デフォルトのパブリックコンストラクターが必要です。
実装は、プロバイダーインターフェイスの型付きバージョンを実装する必要があります。
つまり、Provider<T> インターフェイスを実装することはできません。「データ型」 にリストされている具体的なデータ型を使用するバージョンのインターフェイスを実装する必要があります。たとえば、Provider<SAXSource> のインスタンスを実装できます。
プロバイダーインターフェイスの実装の複雑さは、要求メッセージを処理し、適切な応答を構築するロジックにあります。
メッセージの操作
高レベルの SEI ベースのサービス実装とは異なり、プロバイダー実装は生の XML データとして要求を受信し、生の XML データとして応答を送信する必要があります。これには、開発者が、実装されているサービスで使用されるメッセージについての深い知識を持っている必要があります。これらの詳細は通常、サービスを説明する WSDL ドキュメントに記載されています。
WS-I Basic Profile は、以下を含むサービスによって使用されるメッセージに関するガイドラインを提供します。
リクエストのルート要素は、呼び出される操作に対応する
wsdl:operation
要素のname
属性の値に基づく。警告サービスが doc/literal ベアメッセージを使用する場合、リクエストのルート要素は、
wsdl:operation
要素によって参照されるwsdl:part
要素のname
属性の値に基づきます。- すべてのメッセージのルート要素は名前空間で修飾されています。
サービスが rpc/literal メッセージを使用する場合、メッセージの最上位要素は名前空間で修飾されません。
重要トップレベル要素の子は名前空間で修飾されている可能性がありますが、確実にするには、それらのスキーマ定義を確認する必要があります。
- サービスが rpc/literal メッセージを使用する場合、最上位の要素を null にすることはできません。
- サービスがドキュメント/リテラルメッセージを使用する場合、メッセージのスキーマ定義によって、要素のいずれかが名前空間で修飾されているかどうかが判別されます。
@WebServiceProvider アノテーション
JAX-WS にサービス実装として認識されるためには、Provider 実装に @WebServiceProvider
アノテーションを付ける必要があります。
表41.2「@WebServiceProvider
プロパティー」に、 @WebServiceProvider
アノテーションに設定できるプロパティーを示します。
プロパティー | 説明 |
---|---|
|
サービスのエンドポイントを定義する |
|
サービスのエンドポイントが含まれる |
| サービスの WSDL 定義のターゲットネームスペースを指定します。 |
| サービスを定義する WSDL ドキュメントの URI を指定します。 |
これらのプロパティーはすべてオプションであり、デフォルトでは空です。空のままにすると、Apache CXF は実装クラスからの情報を使用して値を作成します。
invoke() メソッドの実装
Provider インターフェイスには、実装する必要があるメソッド invoke()
が 1 つだけあります。invoke()
メソッドは、実装される Provider インターフェイスの型によって宣言されたオブジェクトの型にパッケージ化された受信リクエストを受け取り、同じ型のオブジェクトにパッケージ化された応答メッセージを返します。たとえば、Provider<SOAPMessage> インターフェイスの実装は、リクエストを SOAPMessage
オブジェクトとして受け取り、応答を SOAPMessage
オブジェクトとして返します。
プロバイダーの実装で使用されるメッセージングモードは、要求メッセージと応答メッセージに含まれるバインディング固有の情報の量を決定します。メッセージモードを使用する実装は、リクエストとともにすべてのバインディング固有のラッパーとヘッダーを受け取ります。また、バインディング固有のラッパーとヘッダーをすべて応答メッセージに追加する必要があります。ペイロードモードを使用する実装は、リクエストの本文のみを受信します。ペイロードモードを使用する実装によって返される XML ドキュメントは、要求メッセージの本文に配置されます。
例
例41.11「Provider<SOAPMessage> の実装」に、メッセージモードの SOAPMessage
オブジェクトで動作する Provider 実装を示しています。
例41.11 Provider<SOAPMessage> の実装
import javax.xml.ws.Provider; import javax.xml.ws.Service; import javax.xml.ws.ServiceMode; import javax.xml.ws.WebServiceProvider; @WebServiceProvider(portName="stockQuoteReporterPort" serviceName="stockQuoteReporter") @ServiceMode(value="Service.Mode.MESSAGE") public class stockQuoteReporterProvider implements Provider<SOAPMessage> { public stockQuoteReporterProvider() { } public SOAPMessage invoke(SOAPMessage request) { SOAPBody requestBody = request.getSOAPBody(); if(requestBody.getElementName.getLocalName.equals("getStockPrice")) { MessageFactory mf = MessageFactory.newInstance(); SOAPFactory sf = SOAPFactory.newInstance(); SOAPMessage response = mf.createMessage(); SOAPBody respBody = response.getSOAPBody(); Name bodyName = sf.createName("getStockPriceResponse"); respBody.addBodyElement(bodyName); SOAPElement respContent = respBody.addChildElement("price"); respContent.setValue("123.00"); response.saveChanges(); return response; } ... } }
例41.11「Provider<SOAPMessage> の実装」 のコードは、以下を行います。
wsdl:service
要素の名前が stockQuoteReporter
で、wsdl:port
要素が stockQuoteReporterPort
という名前のサービスを実装する Provider オブジェクトを以下のクラスが実装することを指定する。
このプロバイダー実装がメッセージモードを使用することを指定します。
必要なデフォルトのパブリックコンストラクターを提供します。
SOAPMessage
オブジェクトを受け取り、SOAPMessage
オブジェクトを返す invoke()
メソッドの実装を提供する。
着信 SOAP メッセージの本文から要求メッセージを抽出します。
要求メッセージのルート要素をチェックして、要求の処理方法を決定します。
応答の構築に必要なファクトリーを作成します。
応答の SOAP メッセージを作成します。
応答を SOAPMessage
オブジェクトとして返す。
例41.12「Provider<DOMSource> の実装」に、ペイロードモードの DOMSource
オブジェクトを使用する Provider 実装の例を示します。
例41.12 Provider<DOMSource> の実装
import javax.xml.ws.Provider; import javax.xml.ws.Service; import javax.xml.ws.ServiceMode; import javax.xml.ws.WebServiceProvider; @WebServiceProvider(portName="stockQuoteReporterPort" serviceName="stockQuoteReporter") @ServiceMode(value="Service.Mode.PAYLOAD") public class stockQuoteReporterProvider implements Provider<DOMSource> public stockQuoteReporterProvider() { } public DOMSource invoke(DOMSource request) { DOMSource response = new DOMSource(); ... return response; } }
例41.12「Provider<DOMSource> の実装」 のコードは、以下を行います。
wsdl:service
要素の名前が stockQuoteReporter
で、wsdl:port
要素が stockQuoteReporterPort
という名前のサービスを実装する Provider オブジェクトをクラスが実装することを指定する。
このプロバイダー実装がペイロードモードを使用することを指定します。
必要なデフォルトのパブリックコンストラクターを提供します。
DOMSource
オブジェクトを受け取り、DOMSource
オブジェクトを返す invoke()
メソッドの実装を提供する。