WebSphere Application Server V7 での JAX-WS 2.1 による WS-Addressing のサポート

IBM WebSphere Application Server V7 には JAX-WS (Java™ API for XML-Based Web Services) 2.1 仕様のサポートが組み込まれています。JAX-WS 2.1 は、JAX-WS 2.0 仕様で提供されている機能をさまざまな新機能で拡張する JSR (Java Specification Request) 224 のメンテナンス・リリースです。これらの新機能の中で最も重要な機能としては、API (Application Programming Interface) での WS-Addressing (Web Services Addressing) のサポートが挙げられます。この記事では、新しく追加された WS-Addressing のサポートを使用する方法を説明するとともに、この新機能によって Web サービスの開発者がステートフルな Web サービスを容易に作成できるようになる仕組みについても解説します。

Brian T. De Pradine, Staff Software Engineer, WSO2 Inc

Brian DePradine は、英国 Hursley の IBM Software Group に勤務する開発者です。IBM での勤務年数は 11 年を数えます。そのうちの 7 年間は、WebSphere Application Server 開発のメッセージングおよび Web サービス・サポート分野を専門に取り組んできました。彼は Columbia University で応用物理学の理学士号を取得し、Oxford University でソフトウェア・エンジニアリングの修士号を取得しました。



Katherine Sanders, Software Engineer, WSO2 Inc

Katherine Sanders は、英国 Hursley の IBM Software Group に勤務するソフトウェア・エンジニアで、特に WS-Addressing、WS-ReliableMessaging、および WS-Notification を重点にした、WebSphere Application Server の Web サービス機能の開発およびテストに取り組んでいます。彼女は University of Nottingham でコンピューター・サイエンスの理学士号を取得しました。



2010年 1月 12日

はじめに

JAX-WS (Java API for XML-Based Web Services) は、以前の JAX-RPC (Java API for XML based RPC) 標準を継承する標準です。JAX-RPC 1.0 および JAX-RPC 1.1 で定義していたのは RPC (Remote Procedure Call) 形式の Web サービス呼び出しをサポートする API および規約でしたが、その当時から時を経るにつれ、Web サービスはドキュメント指向の形式へと移行してきました。この新しい形式の Web サービスとの対話をサポートするために JAX-WS 2.0 が規定したのは、これまでとはまったく異なる API (Application Programming Interface) と規約です。JAX-WS 2.0 では Web サービス・アプリケーションを作成する際の開発者のエクスペリエンスをシンプルなものにするという点にも重点が置かれました。JAX-WS と JAX-RPC の違いについて詳細に説明している記事へのリンクは、「参考文献」セクションを参照してください。

JAX-WS 2.0 で始まった単純化への流れを引き継いだ JAX-WS 2.1 では、開発者がステートフルな Web サービスを容易に作成できるようになりました。これを可能にしたのは、JAX-WS API に追加された WS-Addressing (Web Services Addressing) の明示的なサポートです。この記事では、新しく追加された API を使用してステートフルな Web サービスを作成する方法を、サンプル・アプリケーションを用いて説明しますが、まずはその前に、これらの新しい WS-Addressing 関連の API について詳しく見ていきます。

本題に入る前に注意しておく点として、JAX-WS 2.1 仕様がサポートしているのは WS-Addressing 1.0 Core 仕様と SOAP (Simple Object Access Protocol) Binding 仕様のみです。ただし、他のバージョンの WS-Addressing 仕様のサポートが必要な場合に備え、JAX-WS 2.1 仕様ではベンダーが API を拡張できるようにもなっています。IBM® WebSphere® Application Server V7 では、古い WS-Addressing Member Submission 仕様をサポートするために、この API 拡張機能を利用しています (「参考文献」を参照)。これらの拡張機能についても、この記事で説明します。


エンドポイント参照

JAX-WS 2.1 仕様では、エンドポイント参照という概念を導入しています。エンドポイント参照は、Web サービス・エンドポイントをターゲットとして適切に参照する上で必要なすべての詳細をカプセル化します。エンドポイント参照を表すために API に導入された新しいクラスは、EndpointReference です。ただし、開発者はこのクラスを直接使用するのではなく、そのサブクラスの 1 つを使用することになっています。

JAX-WS 2.1 API には、EndpointReference のサブクラスの 1 つ、W3CEndpointReference が組み込まれています。このサブクラスは、WS-Addressing 1.0 Core 仕様に従ってエンドポイント参照を表すように作られています。WebSphere Application Server V7 は WS-Addressing Member Submission 仕様に従ってエンドポイント参照を表すためのサブクラスとして SubmissionEndpointReference も提供しています。これらのクラスの相互関係は、図 1 のとおりです。

図 1. エンドポイントの相互関係
エンドポイントの相互関係

JAX-WS 2.1 仕様では、アプリケーションでエンドポイント参照を作成する方法をいくつも定義しています。リスト 1 のコード・スニペットに、そのうちの 1 つとして、W3CEndpointReferenceBuilder クラスを使用する方法を説明します。以降に記載する例では、簡潔にするために詳細を省きますが、記事の終わりでは完全なサンプル・アプリケーションを記載します。

リスト 1. JAX-WS 2.1 の例
import org.w3c.dom.Element;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;

String address = ...
Element referenceParameter = ...

W3CEndpointReferenceBuilder builder =
    new W3CEndpointReferenceBuilder();
builder.address(address);
builder.referenceParameter(referenceParameter);
W3CEndpointReference epr = builder.build();

開発者は W3CEndpointReferenceBuilder を使用して、エンドポイト参照のあらゆるプロパティーを指定することができます。リスト 1 ではアドレスと参照パラメーターしか指定していませんが、アドレスの代わりに WSDL (Web Services Description Language) サービス名およびエンドポイント (ポート) 名を指定することも可能です。ランタイムはサービス名とエンドポイント名の組み合わせによって、参照する必要があるエンドポイントを特定し、正しいアドレスを組み込んだ W3CEndpointReference を返します。

W3CEndpointReference ではなく SubmissionEndpointReference が必要な場合、WebSphere Application Server V7 では SubmissionEndpointReferenceBuilder クラスを使用することができます。リスト 2 のコード・スニペットに、このクラスを記載します。

リスト 2. SubmissionEndpointReference
import org.w3c.dom.Element;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReference;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReferenceBuilder;

String address = ...
Element referenceParameter = ...

SubmissionEndpointReferenceBuilder builder =
    new SubmissionEndpointReferenceBuilder();
builder.address(address);
builder.referenceParameter(referenceParameter);
SubmissionEndpointReference epr = builder.build();

サービス名とエンドポイント名の組み合わせを使用すれば、W3CEndpointReferenceBuilder クラスと SubmissionEndpointReferenceBuilder クラスを使って、同じ Java EE (Java Platform, Enterprise Edition) アプリケーションにデプロイされている任意のエンドポイントに対するエンドポイント参照を作成することができます。これはつまり、エンドポイントが同じアプリケーション内になければ、アドレスを明示的に指定しなければならないことを意味します。ただし、エンドポイントに必要なのが、そのエンドポイント自体への参照だけである場合、JAX-WS 2.1 にはビルダーを使用するよりも簡単な方法があります。それは、エンドポイント参照の作成をサポートするように拡張された WebServiceContext クラスです。このクラスをリスト 3 に記載します。

リスト 3. WebServiceContext クラス
import org.w3c.dom.Element;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

@Resource
private WebServiceContext context;

Element referenceParameter = ...

W3CEndpointReference w3cEPR =
    (W3CEndpointReference) context.getEndpointReference(referenceParameter);

クラスターでエンドポイント参照を作成する場合

アプリケーションがクラスターにデプロイされている場合、ビルダーまたは WebServiceContext のいずれかを使用して作成されたエンドポイント参照は、特定のサーバーまたはエンドポイントへのアフィニティーをサポートしません。ただしそれでも、そのエンドポイント参照を使ったリクエストはプロキシーを介してラウンドロビン方式でクラスターのメンバーに分配されるため、単純なワークロード管理を行うことは可能です。

WebServiceContext を使用する場合、明示的に指定できるプロパティーは唯一、参照パラメーターだけです。アドレス要素については、その他すべてのプロパティーと一緒にランタイムによって入力されます。WebSphere Application Server V7 では、SubmissionEndpointReference が必要な場合には JAX-WS 2.1 が提供する拡張メカニズムを使用することができます。リスト 4 のコード・スニペットに、この拡張メカニズムを記載します。

リスト 4. SubmissionEndpointReference
import org.w3c.dom.Element;
import javax.xml.ws.WebServiceContext;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReference;

@Resource
private WebServiceContext context;

Element referenceParameter = ...

SubmissionEndpointReference epr =
    context.getEndpointReference(SubmissionEndpointReference.class, referenceParameter);

アプリケーションで作成されたエンドポイント参照は、ネットワークを介してクライアントに返すことが可能です。クライアントは必要に応じて、受け取ったエンドポイント参照を使用してエンドポイントを呼び出すことができます。エンドポイント参照に組み込まれた参照パラメーターは、WS-Addressing 仕様に従い、送信される SOAP エンベロープに自動的にヘッダーとして追加されます。JAX-WS 2.1 では、Web サービス・アプリケーションがこれらの参照パラメーターを取得するための手段も用意しています。リスト 5 を見てください。

リスト 5. 参照パラメーターの取得
import org.w3c.dom.Element;    
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;

@Resource
private WebServiceContext context;

List<Element> list =
   (List<Element>) context.getMessageContext().get(MessageContext.REFERENCE_PARAMETERS);

上記コードで取得したリストを詳細に調べることで、参照パラメーターを見つけられます。けれどもアプリケーションが WS-Addressing Member Submission 仕様に従って作成されている場合には、このメカニズムで参照パラメーターを取得することはできません。その場合には代わりの手段として WebSphere Application Server V7 が提供する独自仕様の WS-Addressing API に含まれる EndpointReferenceManager クラスを使用します。リスト 6 にこのクラスを記載します。このクラスを使用する場合、参照パラメーターを取得するには、そのパラメーターの名前を指定する必要があります。

リスト 6. EndpointReferenceManager
import javax.xml.namespace.QName;
import com.ibm.websphere.wsaddressing.EndpointReferenceManager;

QName name = ...
String refParam =
    EndpointReferenceManager.getReferenceParameterFromMessageContext(name);

フィーチャー

JAX-WS 2.1 には、フィーチャーの概念も導入されています。フィーチャーは、クライアント開発者がクライアントの特定の振る舞いをプログラムによって制御できるようにするメカニズムです。すべてのフィーチャーは WebServiceFeature クラスから派生するため、クライアント開発者はクライアント・サイドの API にそれぞれが必要とするタイプの WebServiceFeature を渡すことができます。図 2 に、WS-Addressing 関連のフィーチャーを示します。

図 2. WS-Addressing のフィーチャー
WS-Addressing のフィーチャー

AddressingFeature は、WS-Addressing の使用を制御するために使われるもので、開発者はクライアントによる WS-Addressing の使用/不使用を設定することができます。WS-Addressing を使用する設定にすると、クライアントから送信される SOAP メッセージには WS-Addressing ヘッダーが組み込まれることになります。組み込まれるヘッダーは、WS-Addressing 1.0 Core 仕様の名前空間である http://www.w3.org/2005/08/addressing に属します。WS-Addressing を不使用にする設定にした場合には、WS-Addressing ヘッダーは送信されません。

WebSphere Application Server V7 には SubmissionAddressingFeature クラスも用意されています。このクラスは AddressingFeature と同じように機能しますが、唯一異なる点として、WS-Addressing を使用する設定にした場合にクライアントが送信する WS-Addressing ヘッダーは WS-Addressing Member Submission 仕様の名前空間 http://schemas.xmlsoap.org/ws/2004/08/addressing に属します。WebSphere Application Server V7 にはこの他にも、クライアントで WS-Addressing をサポートするように設定するためのメカニズムがありますが、この記事では取り上げません。これらの代替手段についての詳細は、「参考文献」セクションに記載されているリンクを参照してください。


アノテーション

JAX-WS 2.1 ではサーバー・サイドのアプリケーション開発を単純にするために、アノテーションをフル活用します。@Addressing アノテーションは、サーバー・サイドでの AddressingFeature に相当し、Web サービス・エンドポイントに対して WS-Addressing の使用/不使用を設定するために使われます。WS-Addressing を使用する設定にした場合、ランタイムは受信したリクエストに組み込まれている (http://www.w3.org/2005/08/addressing 名前空間に属する) WS-Addressing ヘッダーを処理します。さらに、レスポンス・メッセージにも WS-Addressing ヘッダーが追加されます。WS-Addressing を使用しない設定にした場合には、受信したリクエストに組み込まれている WS-Addressing ヘッダーは無視されます。

@Addressing アノテーションも、required という名前のプロパティーをサポートします。このプロパティーが true に設定されている場合、Web サービスへのすべてのメッセージには WS-Addressing ヘッダーが組み込まれていなければなりません。組み込まれていない場合は、クライアントにエラーが返されます。required プロパティーは AddressingFeature にもありますが、JAX-WS 2.1 仕様に従って、クライアントはこのプロパティーを無視します。WebSphere Application Server V7 には、@Addressing と同じように機能する @SubmissionAddressing アノテーションもあります。ただし、このアノテーションの場合に関係するのは、http://schemas.xmlsoap.org/ws/2004/08/addressing 名前空間に属する WS-Addressing ヘッダーです。図 3 に、これらのクラスを示します。

図 3. Addressing クラス
Addressing クラス

さらに JAX-WS 2.1 には、WS-Addressing のアクションと WSDL の操作とのマッピングをサポートするための新しいアノテーションとして @Action@FaultAction が追加されています。@Action アノテーションを使用すると、アクションを明示的に WSDL 操作の入力、出力に関連付けることができます。もう一方の @FaultAction は、各エラーをアクションに関連付けるために @Action アノテーションの内部で使用するアノテーションです。図 4 に、これらのクラスを記載します。注意する点として、@Action および @FaultAction アノテーションを使用するには、@Addressing アノテーションが必要です。@Addressing アノテーションがない場合、この 2 つのアノテーションは無視されます。

図 4. Fault および Action クラス
Fault および Action クラス

アプリケーション

ここまでで、JAX-WS 2.1 に導入された WS-Addressing 関連の新しい概念について概説したので、次はこれらの概念をすべてまとめて 1 つの有益なアプリケーションにします。これから紹介する Calculator アプリケーションでは、クライアントが 2 つの数値を加算した結果を求めるために Web サービスにリクエストを送信します。ただし、クライアントはリクエストを送信する前に、Web サービスからチケットを取得する必要があります。このチケットがないと、2 つの数値の加算結果を求めるリクエストを送信することができません。チケットはエンドポイント参照に含まれる参照パラメーターとしてクライアントに送信されます。すると、クライアントは受け取ったポイント参照を使用して、2 つの数値の加算結果を求めるリクエストを送信することができます。

この Calculator アプリケーションは、ダウンロードすることもできます。ダウンロードは .ear ファイルとして入手できるので、IBM Rational® Application Developer V7.5.1 にインポートすることも、WebSphere Application Server V7 にインストールすることもできます。Rational Application Developer で問題なくコンパイルするためには、ダウンロード・ファイルから抽出される CalculatorClient および CalculatorService プロジェクトのクラス・パスに com.ibm.jaxws.thinclient_7.0.0.jar を追加する必要があります。この jar ファイルは、WebSphere Application Server システムの runtimes ディレクトリーにあります。

まずは、Calculator サービスの WSDL から見ていくことにしましょう。リスト 7 に、このサービスの WSDL を記載します。このリストを見ると、このサービスには getTicketaddgetSubmissionTicketaddSubmission という 4 つの操作があることがわかります。getTicket 操作が返すのは、参照パラメーターとしてチケットが含まれるエンドポイント参照です。add 操作は、2 つの数値を加算するために使用します。他の 2 つの操作が実行する関数もこの 2 つと同じですが、これらの操作は、WS-Addressing 1.0 Core 仕様ではなく WS-Addressing Member Submission 仕様を使用しています。

リスト 7. Calculator.wsdl
<?xml version="1.0" encoding="UTF-8"?>
<definitions targetNamespace="http://calculator.jaxws.developerworks"
             name="Calculator"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:tns="http://calculator.jaxws.developerworks"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
    <types>
        <xsd:schema>
            <xsd:import namespace="http://calculator.jaxws.developerworks"
                        schemaLocation="Calculator_schema1.xsd"/>
        </xsd:schema>
    </types>
    <message name="getTicket">
        <part name="parameters" element="tns:getTicket"/>
    </message>
    <message name="getTicketResponse">
        <part name="parameters" element="tns:getTicketResponse"/>
    </message>
    <message name="add">
        <part name="parameters" element="tns:add"/>
    </message>
    <message name="addResponse">
        <part name="parameters" element="tns:addResponse"/>
    </message>
    <message name="getSubmissionTicket">
        <part name="parameters" element="tns:getSubmissionTicket"/>
    </message>
    <message name="getSubmissionTicketResponse">
        <part name="parameters" element="tns:getSubmissionTicketResponse"/>
    </message>
    <message name="addSubmission">
        <part name="parameters" element="tns:addSubmission"/>
    </message>
    <message name="addSubmissionResponse">
        <part name="parameters" element="tns:addSubmissionResponse"/>
    </message>
    <message name="AddNumbersException">
        <part name="fault" element="tns:AddNumbersException"/>
    </message>
    <portType name="Calculator">
        <operation name="getTicket">
            <input message="tns:getTicket"/>
            <output message="tns:getTicketResponse"/>
        </operation>
        <operation name="getSubmissionTicket">
            <input message="tns:getSubmissionTicket"/>
            <output message="tns:getSubmissionTicketResponse"/>
        </operation>
        <operation name="add">
            <input wsaw:Action="http://calculator.jaxws.developerworks/add" 
                   message="tns:add"/>
            <output wsaw:Action="http://calculator.jaxws.developerworks/addResponse" 
                    message="tns:addResponse"/>
            <fault message="tns:AddNumbersException" name="AddNumbersException"
                   wsaw:Action="http://calculator.jaxws.developerworks/addFault"/>
        </operation>
        <operation name="addSubmission">
            <input wsaw:Action="http://calculator.jaxws.developerworks/addSubmission"
                   message="tns:addSubmission"/>
            <output 
               wsaw:Action="http://calculator.jaxws.developerworks/addSubmissionResponse" 
                    message="tns:addSubmissionResponse"/>
            <fault message="tns:AddNumbersException" name="AddNumbersException"
                wsaw:Action="http://calculator.jaxws.developerworks/addSubmissionFault"/>
        </operation>
    </portType>
    <binding name="CalculatorPortBinding" type="tns:Calculator">
        <wsaw:UsingAddressing/>
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <operation name="getTicket">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
        <operation name="getSubmissionTicket">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
        <operation name="add">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
            <fault name="AddNumbersException">
                <soap:fault name="AddNumbersException" use="literal"/>
            </fault>
        </operation>
        <operation name="addSubmission">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
            <fault name="AddNumbersException">
                <soap:fault name="AddNumbersException" use="literal"/>
            </fault>
        </operation>
    </binding>
    <service name="Calculator">
        <port name="CalculatorPort" binding="tns:CalculatorPortBinding">
            <soap:address location="http://localhost:9080/CalculatorService/Calculator"/>
        </port>
    </service>
</definitions>

SEI の生成

リスト 7 の WSDL を使用して SEI を生成した場合、@Action および @FaultAction アノテーションは自動的に追加されません。そのためリスト 8 の SEI では、手動でこれらのアノテーションを追加しています。

上記の WSDL と、アプリケーションの ear ファイルに含まれるスキーマ Calculator_schema1.xsd を使用すれば、SEI (Service Endpoint Interface) を生成することができます。その際、WebSphere Application Sever インストールの bin ディレクトリーにある wsimport ツールが使われます。リスト 8 に、生成された SEI を記載します。この SEI に含まれるメソッドは、getTicket()add()getSubmissionTicket()addSubmission() の 4 つです。getTicket() メソッドは W3CEndpointReference を返す一方、getSubmissionTicket() メソッドは SubmissionEndpointReference を返します。add() および addSubmission() メソッドは int を返します。この 2 つには、@Action アノテーションも付けられています。@Action アノテーションの中で使われている @FaultAction アノテーションが、AddNumbersException をアクションにマッピングします。

リスト 8. Calculator.java
package developerworks.jaxws.calculator;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.Action;
import javax.xml.ws.FaultAction;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReference;

@WebService(name = "Calculator", targetNamespace = 
            "http://calculator.jaxws.developerworks")
@XmlSeeAlso({
    ObjectFactory.class
})
public interface Calculator {

    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "getTicket",
                 targetNamespace = "http://calculator.jaxws.developerworks",
                 className = "developerworks.jaxws.calculator.GetTicket")
    @ResponseWrapper(localName = "getTicketResponse",
                 targetNamespace = "http://calculator.jaxws.developerworks",
                 className = "developerworks.jaxws.calculator.GetTicketResponse")
    public W3CEndpointReference getTicket();

    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "getSubmissionTicket",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.GetSubmissionTicket")
    @ResponseWrapper(localName = "getSubmissionTicketResponse",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.GetSubmissionTicketResponse")
    public SubmissionEndpointReference getSubmissionTicket();

    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "add",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.Add")
    @ResponseWrapper(localName = "addResponse",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.AddResponse")
@Action(input = "http://calculator.jaxws.developerworks/add",
            output = "http://calculator.jaxws.developerworks/addResponse",
            fault = {@FaultAction(className = AddNumbersException.class,
            value = "http://calculator.jaxws.developerworks/addFault")})
    public int add(
        @WebParam(name = "arg0", targetNamespace = "")
        int arg0,
        @WebParam(name = "arg1", targetNamespace = "")
        int arg1)
        throws AddNumbersException_Exception;

    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "addSubmission",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.AddSubmission")
    @ResponseWrapper(localName = "addSubmissionResponse",
                targetNamespace = "http://calculator.jaxws.developerworks",
                className = "developerworks.jaxws.calculator.AddSubmissionResponse")
@Action(input = "http://calculator.jaxws.developerworks/addSubmission",
            output = "http://calculator.jaxws.developerworks/addSubmissionResponse",
            fault = {@FaultAction(className = AddNumbersException.class,
            value = "http://calculator.jaxws.developerworks/addSubmissionFault")})
    public int addSubmission(
        @WebParam(name = "arg0", targetNamespace = "")
        int arg0,
        @WebParam(name = "arg1", targetNamespace = "")
        int arg1)
        throws AddNumbersException_Exception;

}

リスト 9 に記載するのは、Web サービスの実装です。@Addressing@SubmissionAddressing 両方のアノテーションを付けることによって、このアプリケーションが両方の仕様による WS-Addressing を使用できるようにしています。@Addressing@SubmissionAddressing は、SEI ではなく、実装クラスに追加しなければならないことに注意してください。getTicket() メソッドと getSubmissionTicket() メソッドはいずれも、チケットが含まれるエンドポイント参照を作成します。この単純な例では、チケットの役割を果たす String を単純にハードコーティングします。add() および addSubmission() メソッドは、リクエストのチケットをチェックしてから、2 つの数値の加算を許可します。前述のとおり、この単純な例ではチケットの役割を果たす String を単純にハードコーティングしていますが、より実際的なシナリオでは、このチケットが例えばデータベースに保管されたレコードのキーを表すことも考えられます。

リスト 9. CalculatorService.java
package developerworks.jaxws.calculator.impl;

import java.util.List;
import javax.annotation.Resource;
import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.soap.Addressing;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.ibm.websphere.wsaddressing.EndpointReferenceManager;
import com.ibm.websphere.wsaddressing.ReferenceParameterCreationException;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionAddressing;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReference;

import developerworks.jaxws.calculator.AddNumbersException;
import developerworks.jaxws.calculator.AddNumbersException_Exception;
import developerworks.jaxws.calculator.Calculator;

@Addressing
@SubmissionAddressing
@WebService(endpointInterface = "developerworks.jaxws.calculator.Calculator",
            serviceName = "Calculator",
            portName = "CalculatorPort",
            targetNamespace = "http://calculator.jaxws.developerworks")
public class CalculatorService implements Calculator {

    @Resource
    private WebServiceContext context;

    public W3CEndpointReference getTicket() {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        Element element = null;

        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.newDocument();
            element = document.createElementNS(
                          "http://calculator.jaxws.developerworks",
                          "TicketId");
            element.appendChild( document.createTextNode("123456789") );
        } catch (ParserConfigurationException pce) {
            throw new WebServiceException("Unable to create ticket.", pce);
        }

return (W3CEndpointReference) context.getEndpointReference(element);
    }

    public SubmissionEndpointReference getSubmissionTicket() {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        Element element = null;

        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.newDocument();
            element = document.createElementNS(
                          "http://calculator.jaxws.developerworks",
                          "TicketId");
            element.appendChild( document.createTextNode("123456789") );
        } catch (ParserConfigurationException pce) {
            throw new WebServiceException("Unable to create ticket.", pce);
        }

return (SubmissionEndpointReference) context.getEndpointReference(
                SubmissionEndpointReference.class, element);
    }

    public int add(int value1, int value2) throws AddNumbersException_Exception {
List<?> list = (List<?>) context.getMessageContext().get(
                MessageContext.REFERENCE_PARAMETERS);

        if (list.isEmpty())
            throw new AddNumbersException_Exception("No ticket found.",
                new AddNumbersException());

        Element element = (Element) list.get(0);

        if (!"123456789".equals(element.getTextContent()))
            throw new AddNumbersException_Exception("Invalid ticket: "
                    + element.getTextContent(), new AddNumbersException());

        return value1 + value2;
    }

    public int addSubmission(int value1, int value2)
            throws AddNumbersException_Exception {
        String refParam;
        try {
refParam = EndpointReferenceManager
                    .getReferenceParameterFromMessageContext(new QName(
                            "http://calculator.jaxws.developerworks",
                            "TicketId"));
        } catch (ReferenceParameterCreationException e) {
            throw new AddNumbersException_Exception("No ticket found.",
                    new AddNumbersException());
        }
	    
        if (!"123456789".equals(refParam)) {
            throw new AddNumbersException_Exception("Invalid ticket: "
                    + refParam, new AddNumbersException());
        }

        return value1 + value2;
    }
}

WS-Addressing Member Submission 仕様のサポート

wsimport ツールを使用してクライアント・サイドの成果物を生成すると、WS-Addressing Core 1.0 名前空間のエンドポイント参照が W3CEndpointReference クラスに自動的にマッピングされます。その一方、WS-Addressing Member Submission 名前空間のエンドポイント参照を SubmissionEndpointReference クラスにマッピングするためには、ツールに渡す -b パラメーターとして、提供されているバインディング・ファイル SubmissionEndpointReference.xjb を指定しなければなりません。このバインディング・ファイルは、WebSphere Application Server システムの util ディレクトリーにあります。

リスト 10 に、Calculator サービスの使用方法を説明するクライアントを記載します。このクライアントは WS-Addressing 1.0 仕様と WS-Addressing Member Submission 仕様をどちらも使用するように作成されています。両方の仕様を使用できるようにするため、クライアントはまずチケットを取得するためのメソッドを使用して、チケットが参照パラメーターとして含まれるエンドポイント参照を取得します。次に、取得したエンドポイント参照を使用して、対応する add メソッドにリクエストを送信し、2 つの数値を加算します。エンドポイント参照を使用すると、そこに含まれる参照パラメーターが自動的に SOAP ヘッダーとしてリクエストに組み込まれることになります。Web サービスはこの SOAP ヘッダーをチェックしてから、数値を加算して結果を送信します。

リスト 10. CalculatorClient.java
package developerworks.jaxws.calculator.client;

import javax.xml.ws.soap.AddressingFeature;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

import com.ibm.websphere.wsaddressing.jaxws21.SubmissionAddressingFeature;
import com.ibm.websphere.wsaddressing.jaxws21.SubmissionEndpointReference;

import developerworks.jaxws.calculator.Calculator;
import developerworks.jaxws.calculator.Calculator_Service;

public class CalculatorClient {
    /**
     * @param args
     */
    public static void main(String[] args) {
        try {            
            int value0 = Integer.parseInt(args[0]);
            int value1 = Integer.parseInt(args[1]);
	
            Calculator_Service service = new Calculator_Service();
            Calculator port1 = service.getCalculatorPort();

            // Retrieve W3CEndpointRefence ticket
W3CEndpointReference epr = port1.getTicket();
            Calculator port2 = epr.getPort(Calculator.class,
                    new AddressingFeature());
	        
            // Add numbers using W3CEndpointRefence ticket
            int answer = port2.add(value0, value1);
            System.out
                    .println("The answer using a W3CEndpointRefence ticket is: "
                            + answer);
            // Retrieve SubmissionEndpointReference ticket
SubmissionEndpointReference submissionEpr = port1
                    .getSubmissionTicket();
            port2 = submissionEpr.getPort(Calculator.class,
                    new SubmissionAddressingFeature());
	        
            // Add numbers using a SubmissionEndpointReference
            answer = port2.addSubmission(value0, value1);
            System.out
                    .println("The answer using a SubmissionEndpointReference ticket is: "
                            + answer);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

リスト 11 に、getTicket() メソッドを使用してチケットをリクエストするときに送信されるメッセージを記載します。注意する点として、リスト 8 の getTicket() メソッドには @Action アノテーションが設定されていないため、適用するアクションは WS-Addressing のデフォルト・アクション・パターンを使用して決定されます。デフォルト・アクション・パターンは、WSDL 操作のプロパティーに基づいてアクションを決定するために WS-Addressing 仕様で定義されている方法です。

リスト 11. GetTicket リクエスト
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:To>http://localhost:9080/CalculatorService/Calculator</wsa:To>
        <wsa:MessageID>urn:uuid:14C1B8561B19D0B1261258998512414</wsa:MessageID>
        <wsa:Action>
http://calculator.jaxws.developerworks/Calculator/getTicketRequest
        </wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:getTicket
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks"/>
    </soapenv:Body>
</soapenv:Envelope>

上記に対するレスポンス・メッセージはリスト 12 のとおりです。レスポンスとして返される EndpointReferenceReferenceParametersTicketId が組み込まれていること、そしてここでもデフォルト・アクション・パターンが使用されていることに注意してください。また、EndpointReference だけでなく、その EndpointReference を使用した後続のリクエストとレスポンスの WS-Addressing ヘッダーにも WS-Addressing 1.0 Core 仕様の名前空間が使用されるという点にも注意が必要です。

リスト 12. GetTicket レスポンス
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/>
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Action>
http://calculator.jaxws.developerworks/Calculator/getTicketResponse
        </wsa:Action>
        <wsa:RelatesTo>urn:uuid:14C1B8561B19D0B1261258998512414</wsa:RelatesTo>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:getTicketResponse
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing" 
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <return>
                <ns3:Address>
                    http://L32H82K:9080/CalculatorService/Calculator
                </ns3:Address>
                <ns3:ReferenceParameters>
                    <ns4:TicketId
                         xmlns="http://calculator.jaxws.developerworks" 
                         xmlns:wsa="http://www.w3.org/2005/08/addressing">
123456789
                    </ns4:TicketId>
                </ns3:ReferenceParameters>
                <ns3:Metadata>
                    <wsam:ServiceName
                         xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
                         xmlns:axis2ns5="http://calculator.jaxws.developerworks"
                         xmlns:wsa="http://www.w3.org/2005/08/addressing"
                         EndpointName="CalculatorPort">
                        axis2ns5:Calculator
                    </wsam:ServiceName>
                </ns3:Metadata>
            </return>
        </ns4:getTicketResponse>
   </soapenv:Body>

リスト 13 には、add() メソッドを呼び出すときに送信されるメッセージを記載します。TicketId はメッセージ・ヘッダーに組み込まれること、そしてヘッダーに含まれるアクションは、リスト 8 に記載した add メソッドの @Action アノテーションに含まれる入力アクションと同じであることに注意してください。

リスト 13. add リクエスト
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <ns4:TicketId xmlns:ns4="http://calculator.jaxws.developerworks"
             xmlns="http://calculator.jaxws.developerworks"
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             ns3:IsReferenceParameter="true">123456789</ns4:TicketId>
        <wsa:To>http://L32H82K:9080/CalculatorService/Calculator</wsa:To>
        <wsa:MessageID>urn:uuid:14C1B8561B19D0B1261258998516588</wsa:MessageID>
        <wsa:Action>http://calculator.jaxws.developerworks/add</wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:add xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <arg0>1</arg0>
            <arg1>2</arg1>
        </ns4:add>
    </soapenv:Body>
</soapenv:Envelope>

リスト 14 に、期待される結果とリスト 8 で設定した出力アクションを提供する最終的なレスポンス・メッセージを記載します。

リスト 14. add レスポンス
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Action>http://calculator.jaxws.developerworks/addResponse</wsa:Action>
        <wsa:RelatesTo>urn:uuid:14C1B8561B19D0B1261258998516588</wsa:RelatesTo>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:addResponse xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <return>3</return>
        </ns4:addResponse>
    </soapenv:Body>
</soapenv:Envelope>

WS-Addressing Member Submission 仕様の EndpointReference を使用した場合には、上記に対応するメッセージとして、リスト 15 のメッセージが送信されます。

リスト 15. WS-Addressing Member Submission 仕様の場合
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:To>http://localhost:9080/CalculatorService/Calculator</wsa:To>
        <wsa:MessageID>urn:uuid:14C1B8561B19D0B1261258998516636</wsa:MessageID>
        <wsa:Action>
http://calculator.jaxws.developerworks/Calculator/getSubmissionTicketRequest
        </wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:getSubmissionTicket
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks"/>
    </soapenv:Body>
</soapenv:Envelope>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:Action>
http://calculator.jaxws.developerworks/Calculator/getSubmissionTicketResponse
        </wsa:Action>
        <wsa:RelatesTo>urn:uuid:14C1B8561B19D0B1261258998516636</wsa:RelatesTo>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:getSubmissionTicketResponse
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <return>
                <ns2:Address>
                    http://L32H82K:9080/CalculatorService/Calculator
                </ns2:Address>
                <ns2:ReferenceParameters>
                    <ns4:TicketId xmlns="http://calculator.jaxws.developerworks"
                         xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
123456789
                    </ns4:TicketId>
                </ns2:ReferenceParameters>
                <ns2:ServiceName PortName="CalculatorPort">
                    ns4:Calculator
                </ns2:ServiceName>
            </return>
        </ns4:getSubmissionTicketResponse>
    </soapenv:Body>
</soapenv:Envelope>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
        <ns4:TicketId xmlns:ns4="http://calculator.jaxws.developerworks"
             xmlns="http://calculator.jaxws.developerworks"
             xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing">123456789</ns4:TicketId>
        <wsa:To>http://L32H82K:9080/CalculatorService/Calculator</wsa:To>
        <wsa:ReplyTo>
            <wsa:Address>
                http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
            </wsa:Address>
        </wsa:ReplyTo>
        <wsa:MessageID>urn:uuid:14C1B8561B19D0B1261258998516715</wsa:MessageID>
        <wsa:Action>http://calculator.jaxws.developerworks/addSubmission</wsa:Action>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:addSubmission xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <arg0>1</arg0>
            <arg1>2</arg1>
        </ns4:addSubmission>
    </soapenv:Body>
</soapenv:Envelope>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
        <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
        <wsa:MessageID>urn:uuid:A9C31FB6B32D8A45DD1258998519215</wsa:MessageID>
        <wsa:Action>
http://calculator.jaxws.developerworks/addSubmissionResponse
        </wsa:Action>
        <wsa:RelatesTo>urn:uuid:14C1B8561B19D0B1261258998516715</wsa:RelatesTo>
    </soapenv:Header>
    <soapenv:Body>
        <ns4:addSubmissionResponse
             xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:ns3="http://www.w3.org/2005/08/addressing"
             xmlns:ns4="http://calculator.jaxws.developerworks">
            <return>3</return>
        </ns4:addSubmissionResponse>
    </soapenv:Body>
</soapenv:Envelope>

まとめ

この記事では、JAX-WS 2.1 仕様に導入された新しい WS-Addressing 関連の概念を紹介し、これらの概念を使ってステートフルな Web サービス・アプリケーションを作成する方法を具体的なコードで説明しました。また、JAX-WS 2.1 で必要な WS-Addressing 1.0 仕様だけでなく、WS-Addressing Member Submission 仕様をサポートするために、標準 API がどのように拡張されているかについても説明しました。


謝辞

この記事の作成中に参考となるコメントを提供してくれた Esther Dovey 氏、Sara Mitchell 氏に大変感謝いたします。

IBM、WebSphere および Rational は、世界の多くの国で登録された International Business Machines Corp. の商標です。Java およびすべての Java 関連の商標およびロゴは、Sun Microsystems, Inc. の米国およびその他の国における商標です。 他の会社名、製品名およびサービス名等はそれぞれ各社の商標です。


ダウンロード

内容ファイル名サイズ
Sample files for this articleCalculator.ear10KB

参考文献

学ぶために

製品や技術を入手するために

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=SOA and web services, WebSphere
ArticleID=525127
ArticleTitle=WebSphere Application Server V7 での JAX-WS 2.1 による WS-Addressing のサポート
publish-date=01122010