1.2.5. Webサービスのカスタマイズ

ここでは、作成した Web サービスをカスタマイズする方法について説明します。

1.2.5.1. JAX-WS準拠Webサービスのカスタマイズ

ここでは、JAX-WSアプリケーションのカスタマイズについて説明します。
ハンドラの利用
JAX-WSでは、Webサービスのメッセージを処理するためのプラグインフレームワークとしてハンドラを利用することができます。ハンドラはクライアントおよびサーバで登録でき、登録したハンドラはメッセージの送受信ごとに呼び出されます。
ハンドラにはLogical HandlerとProtocol Handlerの2種類があります。
■ Logical Handler Logical Handlerはjavax.xml.ws.handler.LogicalHandlerを継承して作成します。以下のメソッドを実装する必要があります。
public boolean handleMessage(LogicalMessageContext context);
public boolean handleFault(LogicalMessageContext context);
public void close(MessageContext ctx);
なお、非同期通信でハンドラが呼び出される場合にはhandleMessageおよびhandleFaultの戻り値としてtrueを必ず返却するように実装してください。 Logical Handlerのサンプルは次のようになります。
  HelloLogicalHandler.java
package sample; 

import javax.xml.ws.handler.*; 

public class HelloLogicalHandler implements LogicalHandler<LogicalMessageContext> { 
  public boolean handleMessage(LogicalMessageContext context) { 
    //通常のメッセージの送受信ごとに呼び出されます。 
    return true; 
  } 

  public boolean handleFault(LogicalMessageContext context) { 
    //Faultメッセージの送受信ごとに呼び出されます。
    return true; 
  } 

  public void close(MessageContext context) { 
    //メッセージ、Faultメッセージ、例外をディスパッチする直前に呼び出されます。 
  } 
}

■ Protocol Handler Protocol Handlerはjavax.xml.ws.handler.soap.SOAPHandlerを継承して作成します。以下のメソッドを実装する必要があります。
SOAPHandlerを継承したProtocol Handlerは、以下のメソッドを実装する必要があります。
public Set<QName> getHeaders();
public boolean handleMessage(SOAPMessageContext context);
public boolean handleFault(SOAPMessageContext context);
public void close(MessageContext ctx);
Protocol Handlerのサンプルは次のようになります。
  HelloSOAPHandler.java
package sample;

import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class HelloSOAPHandler implements SOAPHandler<SOAPMessageContext> { 
  public Set<QName> getHeaders() {
    return null; 
  } 

  public boolean handleMessage(SOAPMessageContext context) { 
    //通常のメッセージの送受信ごとに呼び出されます。
    return true;
  }

  public boolean handleFault(SOAPMessageContext context) { 
    //Faultメッセージの送受信ごとに呼び出されます。
    return true;
  }

  public void close(MessageContext context) { 
    //メッセージ、Faultメッセージ、例外をディスパッチする直前に呼び出されます。
  }
}

■ ハンドラの登録 ハンドラの登録には次の2通りの方法あります。


◇ アプリケーションで登録する場合の例
Handler handler = new HelloLogicalHandler(); 
Handler handler2 = new HelloSOAPHandler(); 
List<Handler> handlerList = new ArrayList<Handler>(); 
handlerList.add(handler); 
handlerList.add(handler2); 
Binding binding =((BindingProvider)port).getBinding(); 
binding.setHandlerChain(handlerList);
◇ バインディングファイルに記述して登録する場合の例
  handlers.xml
<?xml version="1.0" encoding="UTF-8"?> 
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee"> 
  <handler-chain>
    <handler>
      <handler-name>HelloLogicalHandler</handler-name>
      <handler-class>sample.HelloLogicalHandler</handler-class>
    </handler>
    <handler>
      <handler-name>HelloSOAPHandler</handler-name>
      <handler-class>sample.HelloSOAPHandler</handler-class>
    </handler>
  </handler-chain>
</handler-chains>
<handler-class>には、登録するハンドラのクラス名を記述します。
上記のバインディングファイルを、javax.jws.HandlerChainアノテーションで指定します。
import javax.jws.HandlerChain;
@HandlerChain(file="handlers.xml")
バインディングファイルは、クラスパスの通った場所、たとえば、WARファイルのWEB_INF/classes/配下などに置いておく必要があります。
複数のハンドラが登録された場合、以下の順番で呼び出されます。
SOAP1.2の利用
JAX-WSはSOAP1.2に対応しています。JAX-WSアプリケーションでSOAP1.2を利用するためには、次のいずれかの設定を行います。
・配備記述子 nec-jaxws.xml の<endpoint>にbinding="http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/"を記述する
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns='http://www.nec.com/WebOTX/xml/ns/jax-ws/ri/runtime'version='2.0'>
  <endpoint
    name='hellows-soap12'
    implementation='sample.Hello'
    binding="http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/"
    url-pattern='/hello'/>
</endpoints>
・Webサービスエンドポイント実装クラスに@BindingType(value="http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/") を記述する
import javax.jws.WebService;
import javax.xml.ws.BindingType;
@WebService
@BindingType(value="http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/")
public class Hello {
       :
}
※ クライアント側については特に指定は不要です。
MTOM (Message Transmission and OptimizationMechanism)の利用
MTOMとは、base64BinaryやhexBinaryなどのXMLバイナリデータの転送を最適化するための仕様です。仕様の詳細についてはhttp://www.w3.org/TR/soap12-mtom/ を参照してください。
■ サーバ側でMTOMを有効にする場合 サーバ側でMTOMを有効にするには、次の(a)〜(d)のいずれかの指定を行ってください。配備記述子とアノテーションでエンドポイントのBindingの値が重複した場合は、配備記述子の設定が優先されます。
◇ 配備記述子nec-jaxws.xml に記述する方法
(a) <endpoint> の属性 enable-mtom に true を指定する
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns='http://www.nec.com/WebOTX/xml/ns/jax-ws/ri/runtime' version='2.0'>
  <endpoint name="Mtom" implementation="sample.HelloImpl" 
   url-pattern="/hello"
   enable-mtom="true"/>
</endpoints>
(b) <endpoint> の属性 binding にMTOM Bindingの値を記述する
<endpoint ...
    binding="http://schemas.xmlsoap.org/wsdl/soap/http?mtom=true"
/>
    SOAP1.2のMTOMメッセージを使用する場合は次のように指定してください。
<endpoint ...
    binding="http://www.w3.org/2003/05/soap/bindings/HTTP/?mtom=true"
 />
◇ Webサービスエンドポイントにアノテーションを記述する方法
(c) アノテーション @MTOM を記述する
import javax.xml.ws.soap.MTOM;
@MTOM
      ※ 前述のSOAP1.2の指定と組み合わせることができます。

(d) アノテーション @BindingTypeでMTOM Bindingの値を記述する
import javax.xml.ws.BindingType;
@BindingType(value="http://schemas.xmlsoap.org/wsdl/soap/http?mtom=true")
    SOAP1.2のMTOMメッセージを使用する場合は次のように指定してください。
import javax.xml.ws.BindingType;
@BindingType(value="http://www.w3.org/2003/05/soap/bindings/HTTP/?mtom=true")
クライアントのカスタマイズ
JAX-WSアプリケーションクライアントのカスタマイズについて説明します。
JAX-WSでは、各種プロパティを指定する方法としてリクエストメッセージ用のコンテキストのプロパティに設定する方法があります。 この場合、具体的な設定方法は以下のようになります。<キー>, <値>にあてはまる内容は以下の説明にある各項目を参照して設定してください。
HelloService service = new HelloService();
Hello port = service.getHelloPort();
((javax.xml.ws.BindingProvider)port).getRequestContext().put(<キー>,<値>);

クライアント側でMTOMを有効にする場合
クライアント側でMTOMを有効にするには次のいずれかの指定を行ってください。
(a) クライアントプロキシからポートを取得する際にMTOMFeatureを引数として渡す
MtomSample port = new MtomService().getMtomPort(new MTOMFeature());
(b) dispatchの作成時にMTOMFeatureを引数として渡す
javax.xml.ws.Service.createDispatch(....,newjavax.xml.ws.soap.MTOMFeature())
(c) クライアントプロキシのSOAPBindingに対してSOAPBinding.setMTOMEnabled(true)を実行する
Hello port = new HelloService.getHelloPort();
SOAPBinding binding = (SOAPBinding)((BindingProvider)port).getBinding();
binding.setMTOMEnabled(true);

リクエスト送信先のアドレス変更方法
リクエスト送信先のアドレスやポートを変更することができます。これは、HTTPプロキシなどを利用した通信内容の確認を行う際に有用です。リクエストメッセージ用のコンテキストのプロパティに次の内容を設定してください。
表1.2.5.1-1
キー 値   既定値  
javax.xml.ws.BindingProvider.ENDPOINT_ADDRESS_PROPERTY http://localhost:8080/hellows/hello など なし  

リクエストタイムアウト の設定方法
Webサービスの接続までの待ち時間 (ConnectTimeout)と応答待ち時間(RequestTimeout)をそれぞれ指定することができます。リクエストメッセージ用のコンテキストのプロパティにそれぞれ次の内容を設定してください。
接続までの待ち時間 (ConnectTimeout)
表1.2.5.1-2
キー 値   既定値  
com.nec.webotx.webservice.xml.ws.client.BindingProviderProperties. CONNECT_TIMEOUT タイムアウト値(単位:ミリ秒) 30000  

応答待ち時間 (RequestTimeout)
表1.2.5.1-3
キー 値   既定値  
com.nec.webotx.webservice.xml.ws.client.BindingProviderProperties. REQUEST_TIMEOUT タイムアウト値(単位:ミリ秒) 300000  


Fast Infoset の設定方法
Fast Infosetを利用するには、次のいずれかの方法で設定します。

(a) リクエストメッセージ用のコンテキストのプロパティに設定する
表1.2.5.1-4
キー 既定値  
com.nec.webotx.webservice.xml.ws.client.BindingProviderProperties. CONTENT_NEGOTIATION_PROPERTY none | pessimistic | optimistic   なし  

(b) クライアント実行時にJavaのシステムプロパティを追加する
[設定例]
-Dcom.nec.webotx.webservice.xml.ws.client.ContentNegotiation=[ none | pessimistic | optimistic ] クライアントクラス

表1.2.5.1-5
意味
none   Fast Infoset を使用しない  
pessimistic   レスポンスメッセージのみFast Infoset を利用する  
optimistic   リクエストメッセージ・レスポンスメッセージの両方でFast Infoset を利用する  


チャンク形式転送の設定方法
チャンク形式転送エンコーディングを使用してメッセージを送信することが可能です。リクエストメッセージ用のコンテキストのプロパティに次の内容を設定してください。
表1.2.5.1-6
キー 値   既定値  
com.nec.webotx.webservice.xml.ws.client.BindingProviderProperties.
HTTP_CLIENT_STREAMING_CHUNK_SIZE
各チャンク内に書き込むバイト数 なし  

1.2.5.2. JAX-RPC準拠Webサービスのカスタマイズ

Memo
JAX-RPCは旧互換のための機能です。


ここではJAX-RPC準拠のWebサービスのカスタマイズについて説明します。
Web形式のカスタマイズ
ここでは、Webサービスの実装形式がWebアプリケーションのときについて、エンドポイントをカスタマイズする方法を説明します。
実装クラスのカスタマイズ
サービスエンドポイントの実装クラスをカスタマイズすると、Webサービスのエンドポイントのインスタンスが作られる、または削除されるタイミングでいろいろな処理を追加することができます。また、コンテキストをビジネスロジックに引き渡して処理したり、コンテキストから取得できる情報を利用してビジネスロジックの呼び出しをコントロールすることもできます。これからカスタマイズするサービスエンドポイントの実装クラスは、ウィザードにより生成された「*SoapBindingImpl」クラスです。次のようにカスタマイズします。
ServletEndpointContextを取得することで、HTTPセッションの取得、SOAPやServletのコンテキストの取得、Principalの取得、SOAP Role(SOAP actor)属性のチェックを行うことができるようになります。これらをビジネスロジックを呼び出しているメソッドの中で利用します。
コーディング例
import javax.xml.rpc.server.ServiceLifecycle;
import javax.xml.rpc.server.ServletEndpointContext;

public class TestSoapBindingImpl implements com.nec.webotx.webservice.director.hello.hello_PortType,ServiceLifecycle {

  private ServletEndpointContext jaxrpcContext;

  public void init(Object context) throws ServiceException {
    jaxrpcContext =(ServletEndpointContext) context;
  }

  public void destroy() {
    jaxrpcContext = null;
  }

  public void getMessageContext() {
    jaxrpcContext.getMessageContext();
  }

}
EJBサービスエンドポイントのカスタマイズ
ここでは、Webサービスの実装形式がEJBのときについて、エンドポイントをカスタマイズする方法を説明します。
実装クラスのカスタマイズ
サービスエンドポイントの実装クラスをカスタマイズすると、クライアントから受け取るSOAPメッセージのコンテキストを取得することができます。こうすることで、取得したコンテキストをビジネスロジックの中で利用することができます。これからカスタマイズするサービスエンドポイントの実装クラスは、ビジネスロジックのEJBです。次のようにカスタマイズします。
クライアントのカスタマイズ
Webサービス作成ウィザードが生成するJAX-RPC準拠のWebサービスのクライアントプログラムは、空の値を渡して返却値をコンソールに表示するというテストを目的とした内容となっています。実際にWebサービスクライアントを運用するには「Mainクラス」をカスタマイズします。Mainクラスでは、クライアントクラスをインスタンス化してWebサービスのオペレーションを呼び出しているだけです。クライアントクラスのコンストラクタの引数で、WebサービスのURLを指定できます。ここでURLを指定することにより、スタブ内でハードコーディングされているURLを無効にすることができます。
添付ファイルを使用する場合
Webサービス化したメソッドの引数に、添付ファイルに対応する型が含まれている場合、型によっては必ずMainクラスをカスタマイズしなければならない場合があります。封入する添付ファイルのパスを指定するコードがある場合、初期値の「"filename"」が入っているためにそのままでは動作しないケースです。その場合、「"filename"」を実際のファイルパスへ置き換えてください。
Fast Infoset の利用方法
Fast Infosetを利用するには、次のうちいずれかの方法で設定します。

(1)Stubクラスのコンストラクタにソースコードを追加する
_setProperty(com.nec.webotx.webservice.xml.rpc.client.StubPropertyConstants.CONTENT_NEGOTIATION_PROPERTY, "***value***");
※クライアントで作成したStubインスタンスに対してこのメソッドを実行する方法もあります。

(2)クライアント実行時にJava VMプロパティを追加する

[設定例]

[foo@webotx ~]$ java -Dcom.nec.webotx.webservice.xml.rpc.client.ContentNegotiation=***value*** クライアントクラス
なお、「***value***」には次のうちいずれかの値を指定します。
表1.2.5.2-1
意味
none Fast Infoset を使用しない
pessimistic レスポンスメッセージのみFast Infoset を利用する
optimistic リクエストメッセージ・レスポンスメッセージの両方でFast Infoset を利用する
 
ビジネスロジックの置換
Webサービスを作成した後でも、Webサービス化したメソッドの インタフェースが変わらなければビジネスロジックだけ置換することができます。ここでは、ビジネスロジックの置換手順について説明します。

Caution
インタフェースが変更になる場合は、Webサービス作成ウィザードをやり直す必要があります。

ビジネスロジックがプロジェクトの場合
Webサービスが生成されたプロジェクト配下の該当するクラスファイルを置換することで変更が反映されます。
ビジネスロジックがJARファイルの場合
ウィザード中で指定したビジネスロジックのJARファイルは、Webサービスが生成されたプロジェクトにコピーされているので、そのファイルを置換すればビジネスロジックを置換することができます。
ビジネスロジックがWAR・EJB-JARファイルの場合
Webサービスを生成したプロジェクト配下の該当するファイルを置換します。
クラスパスに追加するライブラリに指定したJAR・ZIPファイルの置換
ウィザード中で指定したファイルを絶対パスで参照していますので、指定したファイルをそのまま置換してください。
HTML・JSPファイルなどの追加・置換
Webサービスの実装方式をWebアプリケーションにするとき、HTMLやJSPなどのファイルや任意のフォルダを追加することができます。また、ビジネスロジックとしてWARファイルを指定したとき、その中に含まれるHTMLやJSPなどのファイルや任意のフォルダを置換することもできます。