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はメッセージコンテキストおよびメッセージの本体を扱うことができます。メッセージのプロトコル固有部分は扱うことができません。
- Protocol Handler
Protocol
Handlerはメッセージコンテキストおよびプロトコル固有メッセージを扱うことができます。
■ 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通りの方法あります。
- アプリケーションでBindingを取得してBinding.setHandlerChain()で登録する
- バインディングファイル(handlers.xml)に記述して登録する
◇ アプリケーションで登録する場合の例
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/配下などに置いておく必要があります。
複数のハンドラが登録された場合、以下の順番で呼び出されます。
- アウトバウンドメッセージの場合
Logical Handlerが登録されていれば、登録された順番に呼び出されます。
その後、Protocol Handlerが登録されていれば、登録された順番に呼び出されます。
- インバウンドメッセージの場合
Protocol Handlerが登録されていれば、登録された逆順で呼び出されます。 その後、Logical
Handlerが登録されていれば、登録された逆順で呼び出されます。
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」クラスです。次のようにカスタマイズします。
-
javax.xml.rpc.server.ServiceLifecycleをimplementsに加える。
- init、destroyメソッドを実装する。
-
initメソッドの引数をjavax.xml.rpc.server.ServletEndpointContextでキャストし、コンテキスト情報などを取り出す。
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です。次のようにカスタマイズします。
- javax.ejb.SessionContextをimplementsに加える。
- getMessageContext()を実装し、コンテキストを取得する。
クライアントのカスタマイズ
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などのファイルや任意のフォルダを置換することもできます。