第1回 SOAPの先進機能を斬る!
SOAPメッセージ・ハンドラーと拡張可能タイプ・マッピング


米持幸寿
2004/6/4


米持先進技術工房 @IT分室では、テクノロジー・エバンジェリスト 米持幸寿氏が、J2EEの最新技術情報を提供します。最新技術の中身をいち早くキャッチアップしたい読者のためのコーナーです。


 昨年(2003年)11月に、次期J2EEの標準仕様となるJ2EE仕様バージョン1.4(以下J2EE 1.4)が公開されました。J2EE 1.4ではさまざまな拡張機能がサポートされることになりますが、最も中心的な拡張がWebサービスの標準サポートです。その中で、JAX-RPCは、XMLを使ったRPC(Remote Procedure Call:遠隔操作呼び出し)を実装するためのJavaの標準仕様で、JCPにてJSR-101として策定されたものです。今回は、JAX-RPCの中から、アプリケーションにWebサービス実装を簡単にプラグインできる仕組みのSOAPメッセージ・ハンドラー。そして、XMLとJavaのマッピングをカスタマイズできる拡張可能タイプ・マッピングをご紹介しましょう。

SOAPメッセージ・ハンドラー

 SOAPはXMLメッセージであり、HTTPなどの何らかのトランスポートで運ばれます。このため、今日のSOAPメッセージを実行するエンジンのほとんどはWebアプリケーションサーバであり、J2EEではWebコンテナがこの役割を行います。

 当然のことながら、SOAPのエンジンはサーブレットとして実装されているのが一般的です。例えば、オープンソースで有名なApache SOAPやApache Axisはサーブレットとしてできています。

 JAX-RPCのエンジンは、サーブレットとして実装されることを前提にはしていませんが、普通に考えればサーブレット上に実装されることになるでしょう。そして、サービス、すなわち実装部分、もうちょっとかみ砕いていうと「機能を提供するためのユーザー・モジュール」は、Java Beanか、Enterprise Beanで実装されることになります。

 SOAPアプリケーションとはいえ、サービスを提供するユーザー・モジュールは、単純に機能を提供することだけに注力することが望ましいといえます。例えば、在庫確認のためのアプリケーション・モジュール(クラス、Bean、Enterprise Bean)は、在庫データベースを検索して結果を返す仕事をします。

 ところが、残念ながら今日のWebサービスは、これだけでは使えないことが多くあります。例えば、HTTPをトランスポートに使う単純なWebサービスの場合、ネットワーク・エラーに弱いという欠点があるため、それに対応したコードを大量に作ることがあります。トランザクションの連携も機能しないため、そういったことも考慮する必要があります。

 例えば、注文を受信するWebサービスの場合、注文が重複していないか、注文が成功した、あるいは失敗したことがリクエスターに正しく伝わるか、さらにリクエスター側から、注文が正しく追加されたかを確認するための機能といったものを提供する必要があったりします。セキュリティに関しても同様のことがいえ、暗号化やデジタル署名をXMLに施している例がたくさんあります。

 こういった機能は、安全・確実にメッセージを届けられ、トランザクション処理に対応した基盤を使う場合には必要のない機能です。しかし、今日のWebサービスではどうしてもこれらの機能をアプリケーションで実装する必要があります。ところが、こういった機能は、将来的にはミドルウェアが提供することになる機能です(そのためにベンダが集まって標準の技術を作っています)。

 将来のアプリケーションサーバでは、安全にトランザクション連携をしたければ、EJBのデプロイメント・ディスクリプタのように「これはRequired」と、トランザクション属性を設定したり、この「チャネルは暗号化、デジタル署名付き」というような設定をしたりするだけでいいのかもしれません。そう考えると、今日開発しているWebサービスに「将来ミドルウェアから提供される機能」そのものや、それらの機能が備わったときに不必要な機能を入れておくことは正しい選択とはいえないでしょう。

 このような理由から、サービス実装=アプリケーションそのものに、追加機能を簡単に付加し、取り外すことができる機構が考案されました。これがSOAPメッセージ・ハンドラーです。SOAPメッセージを処理するモジュールをプラグインするための方式です。

 SOAPメッセージ・ハンドラーのコンセプトは、もともとオープンソースのApache Axisに搭載されていたものがJCPに提案され、採用されたものです。

どのような機能が盛り込まれているのか

 JAX-RPCはJ2EEサーバーに実装されるSOAPエンジンです。SOAPエンジンは、エンドポイント、すなわちサービスを提供するクラス、Java Bean、Enterprise Beanなどに、SOAPメッセージのリクエストをルーティングします。

 このままの考え方だと、単純に以下の処理をすれば良いことになります。

  1. SOAPメッセージ(リクエスト)をHTTPプロトコルで受信する
  2. SOAPメッセージを分解する(XMLのパース)
  3. SOAPのBodyの名前空間や要素名を使い、必要なエンドポイントを探す
  4. エンドポイントの設定情報を確認して適切な処理でBodyの中身をJavaオブジェクトに変換する(デシリアライズ)
  5. 変換されたオブジェクトを使ってエンドポイントを呼び出す
  6. エンドポイントからの戻り値を逆にXMLに変換する(シリアライズ)
  7. SOAPメッセージ(レスポンス)として組み立て直す
  8. レスポンスをHTTPレスポンスとして返す

 ここで、SOAPメッセージを中間処理するモジュール(正確にはクラス)をプラグインするための機構がSOAPメッセージ・ハンドラーです。

 図中のHandler1、Handler2などが、ユーザーが作ることができるハンドラーです。ハンドラーはHandlerインターフェイスを実装(implements)して作成します。

Handlerインターフェイス
package javax.xml.rpc.handler;
public interface Handler {
  boolean handleRequest(MessageContext context);
  boolean handleResponse(MessageContext context);
  boolean handleFault(MessageContext context);
  // ...
}

 中間処理は、リクエストをエンドポイントに届けるまでの中間処理と、エンドポイントで作られたレスポンスがJAX-RPCランタイムから送出されるまでの中間処理があり、それぞれの処理メソッドをハンドラーが持っていることになっています。handleRequestとhandleResponseです。

 ハンドラーは、プロバイダのみではなく、リクエスターにも組み込むことができます。また、GenericHandlerクラスを継承して作ることもできます。この場合、Handlerインターフェイスのメソッドをオーバーライドして作ります。

メッセージにアクセスするには

 それぞれのメソッドの引数として「MessageContext」が指定されています。このMessageContextオブジェクトは、SOAPリクエストが到着するたびに生成・初期化され、JAX-RPC内で処理されていきます。

package javax.xml.rpc.handler;
public interface MessageContext {
  void setProperty(String name, Object value);
  Object getProperty(String name);
  void removeProperty(String name);
  boolean containsProperty(String name);
  java.util.Iterator getPropertyNames();
}

 MessageContextは、抽象化されたメッセージを表現するクラスで、実際には、SOAPMessageContextオブジェクトが渡ってきますので、キャストしてアクセスします。こうすることで、SOAPMessageオブジェクトを取り出すことができ、後はSOAPMessageクラスを使ってメッセージを読み取ったり、変更することができます。

package javax.xml.rpc.handler.soap;
public interface SOAPMessageContext extends MessageContext {
  SOAPMessage getMessage();
  void setMessage(SOAPMessage message);
  // ...
}

 上記のリストがJAX-RPCで規定されているSOAPメッセージ・ハンドラーです。実際には、JAX-RPC仕様にはさらにシステムがハンドラーを処理するためのAPIとして、ランタイムにアクセスするServiceクラス、ハンドラーのハンドラー・システムHandlerRegistry、HandlerChain、ハンドラーの定義情報HandlerInfoなどのクラスが定義されています。これらは、Javaのプログラミングによってハンドラー・チェーンを操作するために使います。J2EEサーバーを実装するベンダのコードが使ったり、クライアント側のプログラムが利用したりすることができます。

 APIを使えばチェーンを操作することはできますが、実際にはJSR-109で規定されているデプロイメント・ディスクリプタを使って構成することができます。APIはどちらかといえば自動生成されるスタブ(プロキシークラス)が使うもので、構成ツールなどを使って設定する場合は、デプロイメント・ディスクリプタの記述が使われることになるでしょう。

1/2

 米持先進技術塾−@IT分室 

第1回 SOAPの先進機能を斬る!
Page1
SOAPメッセージ・ハンドラー
  Page2
拡張可能タイプ・マッピング


Java Solution全記事一覧



Java Agile フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Java Agile 記事ランキング

本日 月間