ヘッダーをスキップ
Oracle® Fusion Middleware Oracle WebLogic Server JAX-WS Webサービスの高度な機能のプログラミング
11g リリース1(10.3.6)
B61633-04
  目次へ移動
目次

前
 
次
 

19 XMLメッセージ・レベルでの操作

この章では、Java API for XML Web Services(JAX-WS)を使用したWebLogic Webサービスで、XMLメッセージ・レベルで処理を行うWebサービス・プロバイダベース・エンドポイントおよびディスパッチ・クライアントを開発する方法を説明します。

この章の内容は以下のとおりです。

Webサービス・プロバイダベース・エンドポイントおよびディスパッチ・クライアントの概要

JAXB生成のクラスを使用する方が単純で処理速度が速く、エラーになる可能性も低いですが、場合によってはXMLメッセージ・コンテンツを直接処理するために独自のビジネス・ロジックを生成する必要があります。メッセージレベルのアクセスは、サーバー側ではWebサービス・プロバイダベース・エンドポイントを使用して、クライアント側ではディスパッチ・クライアントを使用して実行できます。

Webサービス・プロバイダベース・エンドポイントは、Javaサービス・エンドポイント・インタフェース(SEI)ベースのエンドポイントにかわる動的なエンドポイントを提供します。JavaオブジェクトとそのXML表現の変換の詳細を概念化するSEIベースのエンドポイントとは異なり、プロバイダ・インタフェースでは、JAXBバインディングなしでXMLメッセージ・レベルのコンテンツに直接アクセスできます。Webサービス・プロバイダベース・エンドポイントは、javax.xml.ws.Provider<T>またはcom.sun.xml.ws.api.server.AsyncProvider<T>インタフェースのそれぞれを使用して、同期的または非同期的に実装できます。Webサービス・プロバイダベース・エンドポイントの開発に関する詳細は、「Webサービス・プロバイダベース・エンドポイントの開発(Javaから始める場合)」を参照してください。

javax.xml.ws.Dispatch<T>インタフェースを使用して実装されるWebサービスのディスパッチ・クライアントは、クライアントがXMLレベルでメッセージを処理できるようにします。Webサービスのディスパッチ・クライアントを開発する手順は、「Webサービス・ディスパッチ・クライアントの開発」で説明します。

プロバイダ・エンドポイントとディスパッチ・クライアントは、WSDLが使用できるかぎり、次のような他のWebLogic Webサービス機能と連動して使用できます。

また、ディスパッチ・クライアントは、非同期クライアント・トランスポート機能および非同期クライアント・ハンドラ機能と組み合せて使用できます。これらの機能の詳細は第4章「Webサービスの非同期呼出し」を、コード例は「ディスパッチ・インスタンスの作成」を参照してください。

XMLレベルでの処理のための使用モードとメッセージ・フォーマット

プロバイダベース・エンドポイントまたはディスパッチ・クライアントを使用してXMLレベルでメッセージを処理するとき、次の表に定義する使用モードの1つを使用します。使用モードは、「使用モードの指定(@ServiceModeアノテーション)」の説明に従ってjavax.xml.ws.ServiceModeアノテーションを使用して定義します。

表19-1 XMLメッセージ・レベルでの処理のための使用モード

使用モード 説明

メッセージ

メッセージ全体を直接処理します。たとえば、SOAPバインディングが使用される場合、SOAPエンベロープ全体にアクセスします。

ペイロード

メッセージのペイロードのみを処理します。たとえば、SOAPバインディングが使用される場合、SOAP本体にアクセスします。


プロバイダベース・エンドポイントとディスパッチ・クライアントは、表19-2に定義されているメッセージ・フォーマットの1つを使用してメッセージを送受信できます。この表では、構成されているバインディング・タイプ(SOAP over HTTPまたはXML over HTTP)に対応する有効なメッセージ・フォーマットと使用モードの組合せも定義されます。

表19-2 XMLメッセージ・レベルでの処理でサポートされるメッセージ・フォーマット

メッセージ・フォーマット SOAP/HTTPバインディングでサポートされる使用モード XML/HTTPバインディングでサポートされる使用モード

javax.xml.transform.Source

メッセージ・モード: SOAPエンベロープ

ペイロード・モード: SOAP本体

メッセージ・モード: SourceとしてのXMLコンテンツ

ペイロード・モード: SourceとしてのXMLコンテンツ

javax.activation.DataSource

SOAP/HTTPバインディングの添付ファイルはSOAPMessageフォーマットを使用して送信されるため、どちらのモードでも有効ではありません。

メッセージ・モード: DataSourceオブジェクト

添付ファイルの送信にDataSourceが使用されるため、ペイロード・モードでは有効ではありません。

javax.xml.soap.SOAPMessage

メッセージ・モード: SOAPMessageオブジェクト

ペイロードのみではなくSOAPメッセージ全体が受信されるため、ペイロード・モードでは有効ではありません。

クライアントがSOAP以外のメッセージをXML/HTTPバインディングで送信できるため、どちらのモードでも有効ではありません。


Webサービス・プロバイダベース・エンドポイントの開発(Javaから始める場合)

次の項で説明されているように、同期および非同期のWebサービス・プロバイダベース・エンドポイントのどちらも開発できます。


注意:

WSDLから始めて、ポートをWebサービス・プロバイダとして設定するには、「Webサービス・プロバイダベース・エンドポイント(WSDLから始める場合)」を参照してください。

同期プロバイダベース・エンドポイントの開発

javax.xml.ws.Provider<T>を使用して実装されるWebサービス・プロバイダベース・エンドポイントでは、JAXBバインディングを使用せずXMLメッセージ・レベルでコンテンツに直接アクセスできます。Providerインタフェースはメッセージを同期的に処理するため、サービスはレスポンス処理を待機し、その後処理を続行します。javax.xml.ws.Provider<T>インタフェースの詳細は、http://download.oracle.com/javaee/5/api/javax/xml/ws/Provider.htmlを参照してください。

次の手順では、同期Webサービス・プロバイダベース・エンドポイントを実装するJWSファイルをプログラミングするための一般的な手順を説明します。

表19-3 同期Webサービス・プロバイダベース・エンドポイントを開発する手順

#
手順 説明

1

Webサービス・プロバイダベースJWSファイルで使用するJWSアノテーションをインポートします。

Webサービス・プロバイダベースJWSファイルの標準JWSアノテーションの内容は次のとおりです。

import javax.xml.ws.Provider;
import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.ServiceMode;

必要であれば他のアノテーションをインポートします。サポートされるすべてのJWSアノテーションのリストは、『Oracle WebLogic Server WebLogic Webサービス・リファレンス』の"Webサービスのアノテーションのサポートに関する項を参照してください。

2

プロバイダベースの実装クラスを開発するときは、表19-2に定義されている、サポート対象のメッセージ・フォーマットの1つを指定します。

「メッセージ・フォーマットの指定」を参照してください。

3

必須の標準@WebServiceProvider JWSアノテーションをクラス・レベルで追加して、JavaクラスがWebサービス・プロバイダを公開することを指定します。

「JWSファイルによるWebサービス・プロバイダの実装の指定(@WebServiceProviderアノテーション)」を参照してください。

4

標準@ServiceMode JWSアノテーションをクラス・レベルで追加して、Webサービス・プロバイダがメッセージ・レベルまたはメッセージ・ペイロード・レベルで情報にアクセスすることを指定します。(オプション)

「使用モードの指定(@ServiceModeアノテーション)」を参照してください。

サービス・モードのデフォルトはService.Mode.Payloadです。

5

invoke()メソッドを定義します。

invoke()メソッドは呼び出されると、指定のメッセージ・フォーマットを使用するメソッドにメッセージまたはメッセージ・ペイロードを入力として提供します。「同期プロバイダベース・エンドポイントのinvoke()メソッドの定義」を参照してください。


次のJWSファイルのサンプルでは、簡単な同期Webサービス・プロバイダベース・エンドポイントの実装方法を示します。同期Webサービス・プロバイダベース・エンドポイントの開発手順の詳細は後の項で説明します。サンプル全体の中でこのJWSファイルを確認するには、Oracle WebLogic Serverに含まれるWebサービス・サンプルのJava EEのためのJAX-WS Webサービスの作成に関する項を参照してください。


注意:

RESTfulなWebサービスは、XML/HTTPバインディングのプロバイダベース・エンドポイントを使用して構築できます。RESTfulなWebサービスでのプロバイダベース・エンドポイントのプログラミング例は、「XML over HTTPを使用するWebサービスのプログラミング」を参照してください。

例19-1 同期プロバイダベース・エンドポイントを実装するJWSファイルの例

package examples.webservices.jaxws;
 
import org.w3c.dom.Node;
 
import javax.xml.transform.Source;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Provider;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.Service;
import java.io.ByteArrayInputStream;
 
 
/**
 * A simple Provider-based Web service implementation.
 *
 * @author Copyright (c) 2010, Oracle and/or its affiliates. 
 * All Rights Reserved.
 */
// The @ServiceMode annotation specifies whether the Provider instance 
// receives entire messages or message payloads.
@ServiceMode(value = Service.Mode.PAYLOAD)

// Standard JWS annotation that configures the Provider-based Web service.
@WebServiceProvider(portName = "SimpleClientPort",
    serviceName = "SimpleClientService",
    targetNamespace = "http://jaxws.webservices.examples/",
    wsdlLocation = "SimpleClientService.wsdl")
public class SimpleClientProviderImpl implements Provider<Source> {
 
  //Invokes an operation according to the contents of the request message.
  public Source invoke(Source source) {
    try {
      DOMResult dom = new DOMResult();
      Transformer trans = TransformerFactory.newInstance().newTransformer();
      trans.transform(source, dom);
      Node node = dom.getNode();
      // Get the operation name node.
      Node root = node.getFirstChild();
      // Get the parameter node.
      Node first = root.getFirstChild();
      String input = first.getFirstChild().getNodeValue();
      // Get the operation name.
      String op = root.getLocalName();
      if ("invokeNoTransaction".equals(op)) {
        return sendSource(input);
      } else {
        return sendSource2(input);
      }
    }
    catch (Exception e) {
      throw new RuntimeException("Error in provider endpoint", e);
    }
  }
 
  private Source sendSource(String input) {
    String body =
        "<ns:invokeNoTransactionResponse
             xmlns:ns=\"http://jaxws.webservices.examples/\"><return>"
            + "constructed:" + input
            + "</return></ns:invokeNoTransactionResponse>";
    Source source = new StreamSource(new ByteArrayInputStream(body.getBytes()));
    return source;
  }
 
  private Source sendSource2(String input) {
    String body =
        "<ns:invokeTransactionResponse 
            xmlns:ns=\"http://jaxws.webservices.examples/\"><return>"
            + "constructed:" + input
            + "</return></ns:invokeTransactionResponse>";
    Source source = new StreamSource(new ByteArrayInputStream(body.getBytes()));
    return source;
  }
 
}

非同期プロバイダベース・エンドポイントの開発

Providerインタフェースを使用する場合と同様に、com.sun.xml.ws.api.server.AsyncProvider<T>インタフェースを使用して実装されるWebサービス・プロバイダベース・エンドポイントでは、JAXBバインディングを使用せずXMLメッセージ・レベルでコンテンツに直接アクセスできます。ただし、AsyncProviderインタフェースはメッセージを非同期に処理します。そのため、サービスはスレッドをブロックすることなく処理を続行し、リクエストが使用可能になった時点でそのリクエストを処理できます。

次の手順では、非同期Webサービス・プロバイダベース・エンドポイントを実装するJWSファイルをプログラミングするための一般的な手順を説明します。

表19-4 非同期Webサービス・プロバイダベース・エンドポイントを開発する手順

#
手順 説明

1

Webサービス・プロバイダベースJWSファイルで使用するJWSアノテーションをインポートします。

非同期Webサービス・プロバイダベースJWSファイルの標準JWSアノテーションの内容は次のとおりです。

import com.sun.xml.ws.api.server.AsyncProvider;
import com.sun.xml.ws.api.server.AsyncProviderCallback;
import javax.xml.ws.ServiceMode;

必要であれば他のアノテーションをインポートします。サポートされるすべてのJWSアノテーションのリストは、『Oracle WebLogic Server WebLogic Webサービス・リファレンス』の"Webサービスのアノテーションのサポートに関する項を参照してください。

2

プロバイダベースの実装クラスを開発するときは、表19-2に定義されている、サポート対象のメッセージ・フォーマットの1つを指定します。

「メッセージ・フォーマットの指定」を参照してください。

3

必須の標準@WebServiceProvider JWSアノテーションをクラス・レベルで追加して、JavaクラスがWebサービス・プロバイダを公開することを指定します。

「JWSファイルによるWebサービス・プロバイダの実装の指定(@WebServiceProviderアノテーション)」を参照してください。

4

標準@ServiceMode JWSアノテーションをクラス・レベルで追加して、Webサービス・プロバイダがメッセージ・レベルまたはメッセージ・ペイロード・レベルで情報にアクセスすることを指定します。(オプション)

「使用モードの指定(@ServiceModeアノテーション)」を参照してください。

サービス・モードのデフォルトはService.Mode.Payloadです。

5

invoke()メソッドを定義します。

invoke()メソッドは呼び出されると、指定のメッセージ・フォーマットを使用するメソッドにメッセージまたはメッセージ・ペイロードを入力として提供します。「非同期プロバイダベース・エンドポイントのinvoke()メソッドの定義」を参照してください。

6

レスポンスを処理するための非同期ハンドラのコールバック・メソッドを定義します。

このメソッドは、レスポンスが返されたときにそのレスポンスを処理します。「非同期プロバイダベース・エンドポイントのコールバック・ハンドラの定義」を参照してください。


次のJWSファイルのサンプルでは、簡単な非同期Webサービス・プロバイダベース・エンドポイントの実装方法を示します。非同期Webサービス・プロバイダベース・エンドポイントの開発手順の詳細は後の項で説明します。

例19-2 非同期プロバイダベース・エンドポイントを実装するJWSファイルの例

package asyncprovider.server;
 
import com.sun.xml.ws.api.server.AsyncProvider;
import com.sun.xml.ws.api.server.AsyncProviderCallback;
 
import javax.xml.bind.JAXBContext;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceProvider;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
 
@WebServiceProvider(
    wsdlLocation="WEB-INF/wsdl/hello_literal.wsdl",
    targetNamespace = "urn:test",
    serviceName="Hello")

public class HelloAsyncImpl implements AsyncProvider<Source> {
 
    private static final JAXBContext jaxbContext = createJAXBContext();
    private int bodyIndex;
 
    public javax.xml.bind.JAXBContext getJAXBContext(){
        return jaxbContext;
    }
    
    private static javax.xml.bind.JAXBContext createJAXBContext(){
        try{
            return javax.xml.bind.JAXBContext.newInstance(ObjectFactory.class);
        }catch(javax.xml.bind.JAXBException e){
            throw new WebServiceException(e.getMessage(), e);
        }
    }
 
    private Source sendSource() {
        System.out.println("**** sendSource ******");
 
        String[] body  = {
            "<HelloResponse xmlns=\"urn:test:types\">
              <argument xmlns=\"\">foo</argument>
              <extra xmlns=\"\">bar</extra>
             </HelloResponse>",
            "<ans1:HelloResponse xmlns:ans1=\"urn:test:types\">
               <argument>foo</argument>
               <extra>bar</extra>
             </ans1:HelloResponse>",
        };
        int i = (++bodyIndex)%body.length;
        return new StreamSource(
            new ByteArrayInputStream(body[i].getBytes()));
    }
 
    private Hello_Type recvBean(Source source) throws Exception {
        System.out.println("**** recvBean ******");
        return (Hello_Type)jaxbContext.createUnmarshaller().unmarshal(source);
    }
 
    private Source sendBean() throws Exception {
        System.out.println("**** sendBean ******");
        HelloResponse resp = new HelloResponse();
        resp.setArgument("foo");
        resp.setExtra("bar");
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        jaxbContext.createMarshaller().marshal(resp, bout);
        return new StreamSource(new ByteArrayInputStream(bout.toByteArray()));
    }
 
    public void invoke(Source source, AsyncProviderCallback<Source> cbak, 
                       WebServiceContext ctxt) {
        System.out.println("**** Received in AsyncProvider Impl ******");
        try {
             Hello_Type hello = recvBean(source);
             String arg = hello.getArgument();
             if (arg.equals("sync")) {
                 String extra = hello.getExtra();
                 if (extra.equals("source")) {
                        cbak.send(sendSource());
                 } else if (extra.equals("bean")) {
                        cbak.send(sendBean());
                 } else {
                        throw new WebServiceException("Expected extra =
                             (source|bean|fault), Got="+extra);
                 }
             } else if (arg.equals("async")) {
               new Thread(new RequestHandler(cbak, hello)).start();
             } else {
                throw new WebServiceException("Expected Argument = 
                  (sync|async), Got="+arg);
             }
        } catch(Exception e) {
          throw new WebServiceException("Endpoint failed", e);
        }
    }
 
    private class RequestHandler implements Runnable {
        final AsyncProviderCallback<Source> cbak;
        final Hello_Type hello;
        public RequestHandler(AsyncProviderCallback<Source> cbak, Hello_Type hello) {
            this.cbak = cbak;
            this.hello = hello;
        }
 
        public void run() {
            try {
                Thread.sleep(5000);
            } catch(InterruptedException ie) {
                  cbak.sendError(new WebServiceException("Interrupted..."));
                  return;
            }
            try {
                String extra = hello.getExtra();
                if (extra.equals("source")) {
                    cbak.send(sendSource());
                } else if (extra.equals("bean")) {
                    cbak.send(sendBean());
                } else {
                    cbak.sendError(new WebServiceException(
                     "Expected extra = (source|bean|fault), Got="+extra));
                }
           } catch(Exception e) {
                cbak.sendError(new WebServiceException(e));
           }
       }
    }
}

メッセージ・フォーマットの指定

プロバイダベースの実装クラスを開発するときは、表19-2に定義されている、サポート対象のメッセージ・フォーマットの1つを指定します。

たとえば、例19-1「同期プロバイダベース・エンドポイントを実装するJWSファイルの例」に示したProviderの実装例では、SimpleClientProviderImplクラスがProvider<Source>インタフェースを実装し、入力と出力の両方の型がjava.xml.transform.Sourceオブジェクトであることを示しています。

public class SimpleClientProviderImpl implements Provider<Source> {
. . .
}

同様に、例19-2「非同期プロバイダベース・エンドポイントを実装するJWSファイルの例」に示したAsyncProviderの実装例では、HelloAsyncImplクラスがAsyncProvider<Source>インタフェースを実装し、入力と出力の両方の型がjava.xml.transform.Sourceオブジェクトであることを示しています。

public class HelloAsyncImpl implements AsyncProvider<Source>  {
. . .
}

JWSファイルによるWebサービス・プロバイダの実装の指定(@WebServiceProviderアノテーション)

次のコードの抜粋のように、標準のjavax.xml.ws.WebServiceProviderアノテーションを使用して、JWSファイルがWebサービス・プロバイダを実装することをクラス・レベルで指定します。

@WebServiceProvider(portName = "SimpleClientPort",
    serviceName = "SimpleClientService",
    targetNamespace = "http://jaxws.webservices.examples/",
    wsdlLocation = "SimpleClientService.wsdl")

この例では、サービス名はSimpleClientServiceであり、生成されるWSDLファイルのwsdl:service要素にマップされます。ポート名はSimpleClientPortであり、生成されるWSDLファイルのwsdl:port要素にマップされます。生成されるWSDLで使用されるターゲット・ネームスペースはhttp://jaxws.webservices.examples/で、WSDLの場所はWebサービス・プロバイダに対して局所的であり、SimpleClientService.wsdlにあります。

@WebServiceProviderアノテーションの詳細は、https://jax-ws.dev.java.net/nonav/2.1.5/docs/annotations.htmlを参照してください。

使用モードの指定(@ServiceModeアノテーション)

javax.xml.ws.ServiceModeアノテーションを使用して、Webサービス・プロバイダベース・エンドポイントが、メッセージ全体を受信するか(Service.Mode.MESSAGE)、メッセージ・ペイロードのみを受信するか(Service.Mode.PAYLOAD)を指定します。

例:

@ServiceMode(value = Service.Mode.PAYLOAD)

指定しない場合、@ServiceModeアノテーションのデフォルトはService.Mode.PAYLOADです。

有効なメッセージ・フォーマットと使用モードの組合せのリストは、表19-2を参照してください。

@ServiceModeアノテーションの詳細は、https://jax-ws.dev.java.net/nonav/2.1.4/docs/annotations.htmlを参照してください。

同期プロバイダベース・エンドポイントのinvoke()メソッドの定義

Provider<T>インタフェースによって、実装クラスに定義する必要がある1つのメソッドが定義されます。

T invoke(T request)

Webサービス・リクエストが受信されると、invoke()メソッドが呼び出され、指定のメッセージ・フォーマットを使用するメソッドにメッセージまたはメッセージ・ペイロードを入力として提供します。

たとえば、「同期プロバイダベース・エンドポイントを実装するJWSファイルの例」のProviderの実装例では、次の抜粋に示すように、invokeメソッドの入力としてSourceパラメータを受け取り、Sourceレスポンスを返すようにクラスが定義されています。

  public Source invoke(Source source) {
    try {
      DOMResult dom = new DOMResult();
      Transformer trans = TransformerFactory.newInstance().newTransformer();
      trans.transform(source, dom);
      Node node = dom.getNode();
      // Get the operation name node.
      Node root = node.getFirstChild();
      // Get the parameter node.
      Node first = root.getFirstChild();
      String input = first.getFirstChild().getNodeValue();
      // Get the operation name.
      String op = root.getLocalName();
      if ("invokeNoTransaction".equals(op)) {
        return sendSource(input);
      } else {
        return sendSource2(input);
      }
    }
    catch (Exception e) {
      throw new RuntimeException("Error in provider endpoint", e);
    }
  }

非同期プロバイダベース・エンドポイントのinvoke()メソッドの定義

AsycnProvider<T>インタフェースによって、実装クラスに定義する必要がある1つのメソッドが定義されます。

void invoke(T request, AsyncProviderCallback<t> callback, WebserviceContext context))

メソッドを呼び出すには、次のパラメータを渡します。

  • 指定のフォーマットのリクエスト・メッセージまたはメッセージ・ペイロード。

  • レスポンスが返されたときにそのレスポンスを処理するcom.sun.xml.ws.api.server.AsyncProviderCallback実装。詳細は、「非同期プロバイダベース・エンドポイントのコールバック・ハンドラの定義」を参照してください。

  • 処理されるリクエストのメッセージ・コンテキストを定義するjavax.xml.ws.WebServiceContext。非同期プロバイダベース・エンドポイントでは、注入されたWebServiceContextは使用できません。これは、情報を返す必要のあるリクエストを判別する際に呼び出し側スレッドに依存するためです。かわりに、WebServiceContextオブジェクトを渡します。このオブジェクトは、AsyncProviderCallbackを呼び出すまで使用できます。

たとえば、例19-2「非同期プロバイダベース・エンドポイントを実装するJWSファイルの例」のAysncProviderの実装例では、次の抜粋に示すように、このクラスのinvokeメソッドが次のように定義されています。

    public void invoke(Source source, AsyncProviderCallback<Source> cbak, 
                       WebServiceContext ctxt) {
        System.out.println("**** Received in AsyncProvider Impl ******");
        try {
             Hello_Type hello = recvBean(source);
             String arg = hello.getArgument();
             if (arg.equals("sync")) {
                 String extra = hello.getExtra();
                 if (extra.equals("source")) {
                        cbak.send(sendSource());
                 } else if (extra.equals("bean")) {
                        cbak.send(sendBean());
                 } else {
                        throw new WebServiceException("Expected extra =
                             (source|bean|fault), Got="+extra);
                 }
             } else if (arg.equals("async")) {
               new Thread(new RequestHandler(cbak, hello)).start();
             } else {
                throw new WebServiceException("Expected Argument = 
                  (sync|async), Got="+arg);
             }
        } catch(Exception e) {
          throw new WebServiceException("Endpoint failed", e);
        }
    }
 

非同期プロバイダベース・エンドポイントのコールバック・ハンドラの定義

AsyncProviderCallbackインタフェースには、非同期レスポンスを受信したときにそのレスポンスを処理するためのコールバック・ハンドラを定義できます。

たとえば、例19-2「非同期プロバイダベース・エンドポイントを実装するJWSファイルの例」から抜粋した次のAysncProviderの実装例では、RequestHandlerメソッドでAsyncProviderCallbackコールバック・ハンドラを使用して非同期レスポンスを処理しています。

    private class RequestHandler implements Runnable {
        final AsyncProviderCallback<Source> cbak;
        final Hello_Type hello;
        public RequestHandler(AsyncProviderCallback<Source> cbak, Hello_Type hello) {
            this.cbak = cbak;
            this.hello = hello;
        }
 
        public void run() {
            try {
                Thread.sleep(5000);
            } catch(InterruptedException ie) {
                  cbak.sendError(new WebServiceException("Interrupted..."));
                  return;
            }
            try {
                String extra = hello.getExtra();
                if (extra.equals("source")) {
                    cbak.send(sendSource());
                } else if (extra.equals("bean")) {
                    cbak.send(sendBean());
                } else {
                    cbak.sendError(new WebServiceException(
                     "Expected extra = (source|bean|fault), Got="+extra));
                }
           } catch(Exception e) {
                cbak.sendError(new WebServiceException(e));
           }
       }
    }
}

Webサービス・プロバイダベース・エンドポイントの開発(WSDLから始める場合)

プロバイダベース・エンドポイントがWSDLファイルから生成される場合、<provider> WSDL拡張を使用してポートをプロバイダとしてマークできます。例:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<bindings wsdlLocation="SimpleClientService.wsdl" 
  xmlns="http://java.sun.com/xml/ns/jaxws">
<bindings node="wsdl:definitions" > 
    <package name="provider.server"/>    
   <provider>true</provider>
</bindings>

プロバイダベース・エンドポイントでのSOAPハンドラの使用

プロバイダベース・エンドポイントは、メッセージのリクエストやレスポンスの追加処理において、SOAPメッセージにアクセスしなければならないときがあります。SEIベース・エンドポイントに実行する場合と同様に、SOAPメッセージ・ハンドラを作成し、プロバイダベース・エンドポイントがSOAPメッセージに対してこの追加処理を実行できるようにすることができます。SOAPハンドラの作成に関する詳細は、「SOAPメッセージ・ハンドラの作成」を参照してください。

表17-1「WebサービスへのSOAPメッセージ・ハンドラの追加手順」には、WebサービスにSOAPハンドラを追加する場合に必要な手順が順に記載されています。これらの手順は、Webサービス・プロバイダベース・エンドポイントにも適用できます。

例:

  1. SOAPメッセージ・ハンドラを設計し、それらを1つのハンドラ・チェーンにグループ化します(「SOAPメッセージ・ハンドラおよびハンドラ・チェーンの設計」を参照)。

  2. ハンドラ・チェーン内のハンドラごとに、SOAPメッセージ・ハンドラ・インタフェースを実装するJavaクラスを作成します(「SOAPメッセージ・ハンドラの作成」を参照)。

    SOAPハンドラの例、MyHandlerを次に示します。

    package provider.rootpart_charset_772.server; 
     
    import javax.activation.DataHandler;
    import javax.activation.DataSource;
    import javax.xml.namespace.QName;
    import javax.xml.soap.AttachmentPart;
    import javax.xml.soap.SOAPMessage;
    import javax.xml.ws.WebServiceException;
    import javax.xml.ws.handler.MessageContext;
    import javax.xml.ws.handler.soap.SOAPHandler;
    import javax.xml.ws.handler.soap.SOAPMessageContext;
    import java.io.InputStream;
    import java.io.OutputStream;.import java.io.ByteArrayInputStream;
    import java.util.Set;
     
    public class MyHandler implements SOAPHandler<SOAPMessageContext> { 
       
        public Set<QName> getHeaders() {
            return null;     
        } 
        
        public boolean handleMessage(SOAPMessageContext smc) {
            if (!(Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY))            
                return true;
            try {
                SOAPMessage msg = smc.getMessage();
                AttachmentPart part = msg.createAttachmentPart(getDataHandler());           
                part.setContentId("SOAPTestHandler@example.jaxws.sun.com");             
                msg.addAttachmentPart(part);
                msg.saveChanges();
                smc.setMessage(msg);
            } catch (Exception e) {
                throw new WebServiceException(e);
            }
            return true;
        }
        
        public boolean handleFault(SOAPMessageContext context) {
            return true;
        } 
         
        public void close(MessageContext context) {}
        
        private DataHandler getDataHandler() throws Exception {
            return new DataHandler(new DataSource() {
                public String getContentType() {
                    return "text/xml";
                }
               
                public InputStream getInputStream() { 
                    return new ByteArrayInputStream("<a/>".getBytes());           
                }
                
                public String getName() {
                    return null; 
                }  
                
                public OutputStream getOutputStream() {
                    throw new UnsupportedOperationException();
                }
            }); 
        } 
    }
    
  3. @javax.jws.HandlerChainアノテーションをProvider実装に追加します(「JWSファイルでのハンドラ・チェーンの構成」を参照)。

    例:

    package provider.rootpart_charset_772.server;  
     
    import javax.jws.HandlerChain;
    import javax.xml.soap.MessageFactory;
    import javax.xml.soap.SOAPMessage;
    import javax.xml.transform.Source;
    import javax.xml.transform.stream.StreamSource;
    import javax.xml.ws.*; 
    import java.io.ByteArrayInputStream;
     
    @WebServiceProvider(targetNamespace="urn:test", portName="HelloPort", serviceName="Hello")
    @ServiceMode(value=Service.Mode.MESSAGE)
    @HandlerChain(file="handlers.xml")
    public class SOAPMsgProvider implements Provider<SOAPMessage> { 
        
        public SOAPMessage invoke(SOAPMessage msg) {
            try {
        // keeping white space in the string is intentional
                String content = "<soapenv:Envelope
                    xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">
                    <soapenv:Body>  <VoidTestResponse
                    xmlns=\"urn:test:types\">
                    </VoidTestResponse></soapenv:Body></soapenv:Envelope>";
                Source source = new StreamSource(new 
                    ByteArrayInputStream(content.getBytes()));
                MessageFactory fact = MessageFactory.newInstance();
                SOAPMessage soap = fact.createMessage();
                soap.getSOAPPart().setContent(source);
                soap.getMimeHeaders().addHeader("foo", "bar");
                return soap;
            } catch(Exception e) {
                throw new WebServiceException(e);
            }   
        }  
    }
    
  4. ハンドラ・チェーン構成ファイルを作成します(「ハンドラ・チェーン構成ファイルの作成」を参照)。

    ハンドラ・チェーン構成ファイルの例(handlers.xml)を次に示します。

    <handler-chains xmlns='http://java.sun.com/xml/ns/javaee'>  
       <handler-chain>    
          <handler>      
             <handler-name>MyHandler</handler-name>      
             <handler-class>
                 provider.rootpart_charset_772.server.MyHandler
             </handler-class> 
          </handler>   
       </handler-chain>
    </handler-chains>
    
  5. ハンドラ・チェーン内のすべてのハンドラ・クラスをコンパイルし、Webサービスを再ビルドします(「Webサービスのコンパイルと再ビルド」を参照)。

Webサービス・ディスパッチ・クライアントの開発

javax.xml.ws.Dispatch<T>インタフェースを使用して実装されるWebサービス・ディスパッチ・クライアントでは、クライアントがXMLレベルでメッセージを処理できます。

次の手順では、Webサービス・ディスパッチ・クライアントをプログラミングするための一般的な手順を説明します。

表19-5 Webサービス・プロバイダベース・エンドポイントを開発する手順

#
手順 説明

1

Webサービス・プロバイダベースJWSファイルで使用するJWSアノテーションをインポートします。

Webサービス・プロバイダベースJWSファイルの標準JWSアノテーションの内容は次のとおりです。

import javax.xml.ws.Service;
import javax.xml.ws.Dispatch;
import javax.xml.ws.ServiceMode;

必要であれば他のアノテーションをインポートします。サポートされるすべてのJWSアノテーションのリストは、『Oracle WebLogic Server WebLogic Webサービス・リファレンス』の"Webサービスのアノテーションのサポートに関する項を参照してください。

2

Dispatchインスタンスを作成します。

「ディスパッチ・インスタンスの作成」を参照してください。

3

Webサービス操作を呼び出します。

Webサービス操作は同期(一方向または双方向)または非同期(ポーリングまたは非同期ハンドラ)で呼び出すことができます。「Webサービス操作の呼出し」を参照してください。


Webサービス・ディスパッチ・クライアントの例

次のサンプルは、基本的なWebサービス・ディスパッチ・クライアントがどのように実装されるかを示します。このサンプルの詳細は後の項で説明します。

例19-3 Webサービス・ディスパッチ・クライアントの例

package jaxws.dispatch.client;
 
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.URL;
 
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import javax.xml.ws.soap.SOAPBinding;
 
public class WebTest extends TestCase {
   private static String in_str = "wiseking";
   private static String request = 
      "<ns1:sayHello xmlns:ns1=\"http://example.org\"><arg0>"+in_str+"</arg0></ns1:sayHello>";
 
   private static final QName portQName = new QName("http://example.org", "SimplePort");
   private Service service = null;

   protected void setUp() throws Exception {
 
      String url_str = System.getProperty("wsdl");
      URL url = new URL(url_str);
      QName serviceName = new QName("http://example.org", "SimpleImplService");
      service = Service.create(serviceName);
      service.addPort(portQName, SOAPBinding.SOAP11HTTP_BINDING, url_str);
      System.out.println("Setup complete.");
 
   }
 
   public void testSayHelloSource() throws Exception {
      setUp();
      Dispatch<Source> sourceDispatch = 
         service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
      System.out.println("\nInvoking xml request: " + request);
      Source result = sourceDispatch.invoke(new StreamSource(new StringReader(request)));
      String xmlResult = sourceToXMLString(result);
      System.out.println("Received xml response: " + xmlResult);
      assertTrue(xmlResult.indexOf("HELLO:"+in_str)>=0);
   }
 
   private String sourceToXMLString(Source result) {
      String xmlResult = null;
      try {
         TransformerFactory factory = TransformerFactory.newInstance();
         Transformer transformer = factory.newTransformer();
         transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
         transformer.setOutputProperty(OutputKeys.METHOD, "xml");
         OutputStream out = new ByteArrayOutputStream();
         StreamResult streamResult = new StreamResult();
         streamResult.setOutputStream(out);
         transformer.transform(result, streamResult);
         xmlResult = streamResult.getOutputStream().toString();
      } catch (TransformerException e) {
         e.printStackTrace();
      }
      return xmlResult;
   }
 
}

ディスパッチ・インスタンスの作成

javax.xml.ws.Serviceインタフェースは、Dispatchインスタンスの作成でファクトリとして機能します。ディスパッチ・インスタンスを作成するには、まずServiceインスタンスを作成する必要があります。その後、Service.createDispatch()メソッドを使用してディスパッチ・インスタンスを作成します。

次のパラメータから1つ以上のパラメータをcreateDispatch()メソッドに渡すことができます。

  • ターゲット・サービス・エンドポイントの修飾された名前(QName)またはエンドポイント参照。

  • タイプ・パラメータTのクラス。この例では、javax.xml.transform.Sourceフォーマットが使用されます。有効な値は、表19-2を参照してください。

  • 使用モード。この例では、メッセージ・ペイロードが指定されます。有効な使用モードは、表19-1を参照してください。

  • プロキシで構成するWebサービス機能のリスト。

  • メッセージまたはメッセージ・ペイロードのマーシャルまたはアンマーシャルに使用されるJAXBコンテキスト。

Service.createDispatch()メソッドの呼出しに使用できる有効なパラメータの詳細は、javax.xml.ws.Service Javadoc(https://jax-ws.dev.java.net/nonav/2.1.1/docs/api/javax/xml/ws/Service.html)を参照してください。

例:

...
      String url_str = System.getProperty("wsdl");
      QName serviceName = new QName("http://example.org", "SimpleImplService");
      service = Service.create(serviceName);
      service.addPort(portQName, SOAPBinding.SOAP11HTTP_BINDING, url_str);
      Dispatch<Source> sourceDispatch = 
        service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
...

前の例では、createDispatch()メソッドは次の3つのパラメータを取ります。

  • ターゲット・サービス・エンドポイントの修飾された名前(QName)。

  • タイプ・パラメータTのクラス。この例では、javax.xml.transform.Sourceフォーマットが使用されます。有効な値は、表19-2を参照してください。

  • 使用モード。この例では、メッセージ・ペイロードが指定されます。有効な使用モードは、表19-1を参照してください。

次の例では、Webサービス機能のリストを渡す方法を示します。具体的には、非同期クライアント・トランスポート機能と非同期クライアント・ハンドラ機能を渡します。これらの機能の詳細は、第4章「Webサービスの非同期呼出し」を参照してください。

...
  protected Dispatch createDispatch(boolean isSoap12, Class dateType,
               Service.Mode mode, AsyncClientHandlerFeature feature) 
               throws Exception {
    String address = publishEndpoint(isSoap12);
    Service service = Service.create(new URL(address + "?wsdl"), 
               new QName("http://example.org", "AddNumbersService"));
    QName portName = new QName("http://example.org", "AddNumbersPort");
    AsyncClientTransportFeature transportFeature = new
         AsyncClientTransportFeature("http://localhost:8238/clientsoap12/" + 
               UUID.randomUUID().toString());
    Dispatch dispatch = service.createDispatch(portName, dateType, mode, 
         feature, transportFeature);
    return dispatch;
  }
...

Webサービス操作の呼出し

Dispatchインスタンスが作成されたら、それを使用してWebサービス操作を呼び出します。Webサービス操作は、同期(一方向または双方向)または非同期(ポーリングまたは非同期ハンドラ)で呼び出すことができます。同期および非同期の呼出し方法の詳細は、javax.xml.ws.Dispatch Javadoc(https://jax-ws.dev.java.net/nonav/2.1.1/docs/api/javax/xml/ws/Dispatch.html)を参照してください。

たとえば、次のコードの抜粋では、XMLメッセージはjavax.xml.transform.stream.StreamSourceオブジェクトとしてカプセル化され、同期invoke()メソッドに渡されています。レスポンスXMLはresult変数でSourceオブジェクトとして返され、XMLに変換されます。メッセージをXMLに戻すために使用されるsourcetoXMLString()メソッドは、例19-3に示しています。

...
private static String request = "<ns1:sayHello xmlns:ns1=\"http://example.org\"><arg0>"+in_str+"</arg0></ns1:sayHello>";
Source result = sourceDispatch.invoke(new StreamSource(new StringReader(request)));
String xmlResult = sourceToXMLString(result);
...