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 アノテーションに設定できるプロパティーを示します。

表41.2 @WebServiceProvider プロパティー

プロパティー説明

portName

サービスのエンドポイントを定義する wsdl:port 要素の name 属性の値を指定します。

serviceName

サービスのエンドポイントが含まれる wsdl:service 要素の name 属性の値を指定します。

targetNamespace

サービスの WSDL 定義のターゲットネームスペースを指定します。

wsdlLocation

サービスを定義する 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() メソッドの実装を提供する。