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

表41.2 @WebServiceProvider Properties

プロパティー説明

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() メソッドの実装を提供する。