J2EE関連の最新仕様をわかりやすく解説
J2EE Watch [1]

Webサービスの標準サポート「JAX-RPC」

米持幸寿
2004/4/8


J2EE Watchでは、J2EE関連の最新仕様に関するトピックを取り上げ、わかりやすく解説します。(編集局)

 昨年11月に、次期J2EEの標準仕様となるJ2EE仕様バージョン1.4(以下J2EE 1.4)が公開されました。J2EE 1.4ではさまざまな拡張機能がサポートされることになりますが、最も中心的な拡張がWebサービスの標準サポートです。

 J2EE 1.4では、以下のWebサービスに関する拡張を行っています。

  • JAX-RPC v1.1(Java API for XML-based RPC)
  • SAAJ(SOAP with Attachments API for Java)
  • Web Services for J2EE
  • JAXR(Java API for XML Registries)
  • JAX-RPCにおいて、WS-Iへの対応

JAX-RPCとは何か

 JAX-RPCは、XMLを使ったRPC(Remote Procedure Call:遠隔操作呼び出し)を実装するためのJavaの標準仕様で、JCPにてJSR-101として策定されたものです。

 JAX-RPCのスペック(仕様)は、JCPのサイトからダウンロードできます。仕様書の冒頭にある「Design Goal」によれば、この仕様は以下のことを目標としています。

  • JavaプラットフォームでのXMLベースのRPCをサポートするAPIを定義する
  • 基本レベルのプロトコルバインディングを定義する(ほかのプロトコルバインディングを制限する意味ではない)
  • JAX-RPCベースのサービスを定義(提供)、あるいは利用するJavaアプリケーションを開発するための基本APIを定義する
  • ヘテロジーニアス(混合)な環境での相互接続性をサポートする
  • JAX-RPC実装に対する、適合性と相互接続性の検証のための要件を定義する
  • JAX-RPC APIとメカニズムを拡張可能かつモジュラーに保つ

RPCとは何か?

 RPCとは日本語に直訳すると「遠隔操作呼び出し」という意味になります。しかし、知らない人にとってはこれでは何のことだか分からないので、簡単に説明しておきます。

 RPCと同じ意味でRMI(Remote Method Invocation)というのもあります。また、上位技術として分散オブジェクトという技術もあります。例えば、旧来の技術でいうと、DCE-RPC、COM/DCOM、Java-RMIなどはRPC、CORBA、EJBなどは分散オブジェクトの技術です。総称して「分散プログラミング」と呼ばれており、分散システムが流行した1980年代から発展した技術です。

 例を挙げて解説しましょう。分散システムでは、例えば画面操作はクライアントで行い、データベース検索と計算はサーバで行う、というような分散処理を実装します。このとき、画面のプログラムがデータベース検索と計算の処理を「processDB( )」というようなメソッドで実行するようにしたいとすると、以下のようなプログラムを記述すればいいことになります。

クライアント側

サーバ側
int result = processDB(parm); public int processDB(MyParm p) {
  // DB検索と計算
}

 ところで、これは1つのマシン上でなら、普通にコンパイルしてリンクエディット(Javaではクラスローダーの仕事)すればプログラムとして動作しそうですが、分散システムではそうはいきません。なぜなら左側のコンピュータにはprocessDBというメソッドは存在しないからです。

 そこで、中央にミドルウェアを挟んで、これをうまく動作するようにする方式がRPCと呼ばれるものの総称です。そのようなミドルウェアがあれば、上記のようなソフトウェアを記述して、左右を別のマシンで稼働させて実行することが可能となります。

 JAX-RPCでは、Java上でこの処理の連携をXMLで行うことを前提に、APIと動作モデルを定義し、J2EEなどのアプリケーション・サーバに実装していこうという仕様といえます。

なぜ新標準が必要なのか?

 JavaにはJava-RMIやEJBといった、RPCと分散オブジェクト技術が既存しています。なぜいま、新しくRPCの標準が必要なのでしょうか?

 JAX-RPCは、WebサービスのAPIです。つまり、SOAP、WSDL、UDDIといったXMLを使う分散プログラミング・モデルをJavaで実現するための標準であるということになります。Webサービス技術は、2000年から発展してきたXMLを使ったシステム連携技術で、インターネット上でRPCを行うための仕様が含まれています。JavaはJ2EEとしてインターネットで最も多く使われているプログラム開発言語/実行環境なので、現在ほとんどのJ2EEベンダは、何らかの形でWebサービスに対応しています。

 しかし、Webサービスに対応した時期や機能はベンダごとに違い、実装方法もまちまちでした。例えばオープンソースのApache SOAPというランタイムを、そのまま自社のシステムへ移植したベンダもあれば、パッケージ名などを自社のものに変更して搭載しているベンダもあります。まったく独自の方式で実現している例もあります。

 ところでJ2EEのマーケットは、アプリケーションのポータビリティ(可搬制)が実現しているため、アプリケーション・ソフトウェアを売るベンダにとっては大きなマーケットになります。しかしWebサービスのアプリケーションに関しては、これがうまくいきませんでした。なぜなら、各社が独自にAPIや実行モデルを決めてしまったために、Webサービスを実装したアプリケーションがポータブル(可搬)でなくなってしまったのです。一度A社のアプリケーション・サーバ用に開発したアプリケーションは、B社のアプリケーション・サーバでは実行できないのです。

 このような背景から、Webサービスをポータブルにするための仕様案がいくつか提出され、仕様策定作業が行われました。JAX-RPCはそのうちの1つです。

 J2EE 1.4では、JAX-RPCが標準として追加されているので、J2EE 1.4上でJAX-RPC(および、ほかの仕様)を使って正しくWebサービスを作成することにより、今後はWebサービスの実装を含めても、各サーバ/ベンダ間でポータブルなアプリケーションを開発することが可能となります。

JAX-RPCで決めていること

 JAX-RPC仕様では、主に以下のことを決めています。

  • JAX-RPCの使われ方(概要)
  • 前提
  • WSDL/XMLとJava間のマッピング
  • SOAPバインディング
  • 添付付きSOAP
  • コアAPI
  • クライアント・プログラミング・モデル
  • サービス・エンドポイント・モデル
  • サービス・コンテキスト
  • SOAPメッセージ・ハンドラー
  • JAX-RPCランタイム・サービス
  • 相互接続性
  • 拡張可能タイプ・マッピング

 これらに関して、どのようなことが決められているか、概要を解説していきます。

JAX-RPCの概要

 まず、JAX-RPCをサポートするミドルウェアや開発ツール、そしてそれに搭載されるアプリケーションなどの関係を定義しています。JAX-RPCは、RPC仕様であるので、いわゆるWebサービス・アーキテクチャ、すなわち、SOAP、WSDL、UDDIによるデルタモデルを実現するものではありません。利用する技術はSOAPとWSDLであり、発見メカニズムにはJNDIを利用することができます。

 JAX-RPCでは、Webサービスの機能を提供するプログラムコードのことを「サービス・エンドポイント」と呼びます。エンドポイントの機能は、interface句で定義されることになっており、これを「サービス・エンドポイント・インターフェイス(SEI)」といいます。

 サービス・エンドポイントは、J2EEのコンポーネント・モデルに従うとされており、EJBのステートレス・セッションBeanや、Java Beanなどが実装に使われます。サービス・エンドポイントは、J2EEサーバにデプロイ(インストール)されて実行されることになりますが、デプロイのモデルや方法に関してはJAX-RPC内では詳細に規定されていません。実は、J2EE 1.4の中では、別の規約「Web Services for J2EE(JSR-109)」で規定されています。

 JAX-RPCの概観を図1に示します。

図1 JAX-RPCの概観

 JAX-RPCの実装は、現実的にはミドルウェアとクライアント用のAPI(通常はJARファイル)で提供されることになります。ミドルウェア上にはサーバ側の実行環境が、クライアント用のJARファイルにはクライアント用の実行環境が提供されます。図中の灰色部分であり、これらがサーバ・ベンダから提供されます。

 アプリケーション・プログラマは、クライアントとエンドポイント(黄色の部分)をコーディングすることになります。

 仕掛けはこうです。クライアントは、サービス・エンドポイント・インターフェイス(Javaのinterface句)に対してプログラミングを行います。インターフェイスの実装は、スタブです。スタブを呼び出すことにより、クライアント側の実行環境がSOAPでサーバ側の実行環境を呼び出します。サーバ側実行環境は、リクエストをサービス・エンドポイント(Java BeanやエンタープライズBean)にディスパッチ、すなわちメソッドを呼び出します。メソッドの戻り値は、逆のルートを通ってクライアント・アプリケーションへ戻されます。

 図中で赤の「スタブ」は、WSDLから自動生成されるものであり、サーバ・ベンダによって違うものです。しかし、スタブには「サービス・エンドポイント・インターフェイス」が実装されており、クライアント・アプリケーションは、このスタブのインターフェイスに対してプログラミングすることで、サービスの呼び出しを記述することができます。

 開発ツールには、JavaコードとWSDLの変換機能が提供されることになります。以下の3つが考えられるでしょう。

  1. サービス・エンドポイント(ステートレス・セッションBeanなど)が既存する場合に、WSDLを生成する機能
  2. WSDLが既存する場合に、クライアント・スタブとサンプル・クライアントなどを生成する機能
  3. WSDLが既存する場合に、サービス・エンドポイントのひな型(スケルトン)を生成する機能

 JAX-RPCで規定されている範囲だとこうなりますが、実際には、実行環境(ランタイム)に登録するためのデータ(デプロイメント・ディスクリプタ)などを自動生成する機能も提供されます。J2EE 1.4では、JSR-109に従ったものとなります。

 このコンセプトは、オープンソースのApache SOAP、Apache Axisなどや、いままでのJ2EEサーバで実現されていたものとほぼ同じものと考えていいでしょう。

WSDL/XMLとJava間のマッピング

 Webサービスのインターフェイス情報はWSDLで記述されることになっています。JAX-RPCでは「WSDLにこのように記述されていたら、Javaのプログラム上はこういうクラス」あるいは、その逆が詳細に定義されています。これを「マッピング」といいます。マッピングは拡張可能なフレームワークを持っているため、標準マッピングとかデフォルト・マッピングという呼び方をします。マッピングの拡張に関しては別途解説します。

 まず名前のマッピングですが、XMLに付けられた名前(要素名)は、基本的にJavaのクラスや変数名にマッピングされます。Javaで使ってはいけないキーワードには、アンダースコア“_”が前に付加されます。

 型のマッピングはXML SchemaおよびSOAPエンコーディングをサポートすることになっており、その定義は非常に多岐にわたり複雑です。定義のされ方としては、まず基本的なデータの型のマッピングが表で定義され、さらに配列、構造体、複合型、列挙などが例を挙げて解説されています。マッピング機能は、JAX-RPC実装、つまりはJ2EEサーバによって提供されます。つまり、このマッピングで定義されているレベルの基本型、オブジェクト・クラス、配列などを利用するアプリケーションは、J2EEサーバか開発ツールで提供される機能によって、簡単にWebサービス化することが可能なはずです。

SOAPバインディング

 JAX-RPCはバインディングに依存しない仕様ですが、SOAPバインディングに関しては1つの選択肢として定義されています。とはいっても、現状SOAPを使うのが現実的でしょう。

 SOAPの仕様では、スタイルにRPC型とドキュメント型、エンコーディングにSOAPエンコーディングとリテラル型があります。JAX-RPCでは以下の組み合わせのサポートを規定しています。

  • RPC/encoded
  • RPC/literal
  • document/literal

 J2EEサーバはこの3つの組み合わせをサポートすることになります。ここでは、以下のクラスの使い方なども規定しています。

  • javax.xml.soap.SOAPElement
  • javax.xml.soap.SOAPFactory
  • javax.xml.rpc.soap.SOAPFaultException

添付付きSOAP

 SOAPなどのXMLプロトコルでは、バイナリ形式のデータを取り扱いにくいので、添付データを扱う方式として「SOAP Messaging with Attachments」という仕様が決められています。JAX-RPCでは、MIMEを利用する添付データをサポートします。JavaコードからMIME処理を行うために、JavaBeans Activation Frameworkのjavax.activation.DataHandlerを利用します。JAX-RPCをサポートするサーバでは、用意されたハンドラーを使うことで、SOAPメッセージに簡単に添付データを付加することができます。

コアAPI

 クライアント側のプログラムコードが使うAPIとして、以下のクラスやインターフェイスが決められています。

  • javax.xml.rpc.Stubインターフェイス
  • javax.xml.rpc.Callインターフェイス(動的呼び出しモデル)
  • javax.xml.rpc.Serviceインターフェイス
  • javax.xml.rpc.ServiceFactoryクラス
  • javax.xml.rpc.JAXRPCExceptionクラス

 このAPIによれば、クライアントの実装には2つのアプローチを取ることができます。1つ目はスタブ(SOAPでは一般的にプロキシークラスという)を生成、つまりプリビルド型でサービスにバインドする方法です。今日の一般的なWebサービスのクライアントはこの方法で作られることが多いと思います。スタブはStubインターフェイスを実装したものとして作られます。

 もう1つは、ダイナミックにバインドする方法です。これはJavaBeansのリフレクションなどの機能と似たものと考えてよいと思います。この機能を使うことで、ワークフローエンジンなどでサービスをプラグインしたり、開発ツール上でサービスを動的に認識して扱ったりすることができるようになります。ここではCallインターフェイスを使います。

 スタブの生成は一般的には開発ツールが行います。これまでの開発ツールが生成したスタブはベンダ依存のスタブとなってしまい、ポータブルではありませんでした。JAX-RPC仕様のスタブはポータブルであり、どのJ2EEサーバ、あるいは、J2EEクライアント上でも稼働可能なはずです。

 スタブは生成された後、いくつかのプロパティを変更して使う必要が発生することがあります。このため、JAX-RPCではスタブが持つプロパティが持つ標準のプロパティがいくつか定義されています。これらのプロパティはベンダに関係なく必ず存在するので、安心してプログラムコードの中に記述することができます。動的呼び出しに使うCallインターフェイスにも同様のプロパティが定義されています。

 これらのAPIの関係は以下のように考えればよいと思います。まず、ServiceFactory、Service、Callは低レベル・インターフェイスと呼ばれるもので、これらのAPIを使うとJAX-PRCのクライアント・ランタイムに直接アクセスすることができます。

 開発ツールが自動生成するスタブクラスは、Stubを実装し、低レベル・インターフェイスを使った実装が行われます。低レベル・インターフェイスはすべてのJ2EEサーバやJ2EEクライアントで利用可能なので、低レベル・インターフェイスにアクセスするコードや、スタブはポータブルになる、という理論です。

クライアント・プログラミング・モデル

 JAX-RPCのクライアントを実装する際のプログラミングにおいて、最も特徴的なのはサービスに対するポート(インターフェイス)を取得するためにJNDIを使ってルックアップをする方法を定義していることです。

リスト1 スタブの取得(JavaTM API for XML-based RPC JAX-RPC 1.1より転載)
Context ctx = new InitialContext();
com.example.StockQuoteService sqs =
ctx.lookup("java:comp/env/StockQuoteService");
com.example.StockQuoteProvider sqp =
sqs.getStockQuoteProviderPort();
float quotePrice = sqp.getLastTradePrice("ACME");

 EJBをご存じの方は、非常によく似ていることに気が付くと思います。これらを実行するために、デプロイメント・ディスクリプターにservice-ref-nameやservice-ref-typeなどが記述されます。

サービス・エンドポイント・モデル

 サービス・エンドポイント・モデルとは、Webサービスの機能を提供するモジュールをどのような形で実装し、サーバ上に稼働させるか、ということを決めたものと考えればいいでしょう。

 JAX-RPCで規定されているサービス・エンドポイント・モデルは、サーブレット・コンテナ上にデプロイされるJAX-RPCサービスのためのものです。EJBコンテナ上でのJAX-RPCサービスに関しては、JSR-109およびEJB 2.1仕様で規定されています。

 サーブレット・コンテナ上のサービス・エンドポイントは、Javaのクラスであり、WSDLの記述とマッピングされます。WSDLが既存している場合は、マッピングツール(一般的には開発ツール)でひな型を生成し、中身を埋めます。あるいは、既存Javaクラスにインターフェイスを定義し(サービス・エンドポイント・インターフェイス)それを基にWSDLを生成することもできます。

 また、javax.xml.rpc.server.ServiceLifecycleというインターフェイスを実装することで、サービス・エンドポイントのクラスのライフサイクル中にサーバから通知を受けることもできます。通知とは初期化(initメソッド)と破棄(destroy)の2種類です。initメソッドにはObject型のcontextというパラメータが渡されます。サーブレット・ベースのエンドポイントではjavax.xml.rpc.server.ServletEndpointContextクラスが渡ってきます。これによってJAX-RPCサービスは、userPrincipal、MessageContext、HttpSession、ServletContextなどに直接アクセスすることができるため、サーブレットAPIを使ったきめ細やかなプログラミングを行うことができます。例えばステートフル・サービスを、HttpSessionを使って実現することも可能です。

サービス・コンテキスト

 サービス・コンテキストとは、サービスと呼び出し元(つまりクライアント)との間で取り交わされる「状態」を維持するための情報で、実際にはSOAPヘッダで交換されることになります。JAX-RPCではどのようなコンテキストが交換されるか具体的なものは定義していません。

 サービス・コンテキストには「暗黙的」と「明示的」の2種類が定義されています。暗黙的サービス・コンテキストは、セキュリティ情報(ログイン情報など)のようなJ2EEが自動的に運搬するようなもの、としています。

 明示的サービス・コンテキストは、アプリケーションに実装する必要のあるものです。例えば、先に登場したgetStockQuoteでcontextをやりとりする場合には以下のようなコードを実装します。

リスト2 getStockQuoteでcontextをやりとりする場合
package com.example;
  public interface StockQuoteProvider extends java.rmi.Remote {
    float getStockQuote(String tickerSymbol, StringHolder context)
          throws java.rmi.RemoteException;
}

 このコンテキスト情報は、SOAPヘッダに入れられて運ばれます。

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

 JAX-RPCでは、メッセージを処理する「ハンドラー」というモジュールを作り、プラグイン方式でランタイムに組み込むためのフレームワークを定義しています。

JAX-RPCランタイム・サービス

 JAX-RPCのランタイムは、以下の機能をサポートすることが義務付けられています。

  • HTTP基本認証
  • SSL相互認証
  • セッション管理(クッキー、URL再書み込み、SSLセッション)

 SOAPセキュリティ拡張(SOAP-SEC)は必須ではないと定義されています。今後の主流ではないからですね。また、セッション管理は、SOAPの仕様とは直接関係ない仕様ですが、現存するほとんどのSOAP実装がHTTPセッションをサポートすることから、問題なく幅広く使える機能と考えていいでしょう。

相互接続性

 JAX-RPC仕様では、相互接続性(インターオペラビリティ)について、いろいろと解説が書かれています。特に、非J2EE製品との相互接続性に関して細かく指定があります。基本的に、JAX-RPCの相互接続性に関する規定はWS-I Basic Profile 1.0に基づくものとなっています。WS-I Basic Profileとは、Web Services Interoperability Organizationで策定された、SOAPベースのWebサービスの相互接続性を向上するための仕様セットです。JAX-RPCでは、Java→WSDLもしくはWSDL→Javaのマッピングツールが順守すべき項目と、実際のランタイムが順守すべき項目が一覧されています。

 そもそものWS-I Basic Profileは「実装を作る人が順守すべき項目」となっています。JAX-RPCを搭載するJ2EEサーバの世界では、SOAP実装そのものは、ツールが生成するスタブ、スケルトン、デプロイメント・ディスクリプター、そしてJ2EEサーバに搭載されているSOAPランタイムです。となると、それらサーバ実装およびツールがWS-Iに準拠したWebサービスを提供できる必要があるということを示しています。

 ただし、誤解してはならないのはJ2EE上でも「WS-Iから逸脱したサービス」を開発することは可能です。ユーザーが気にして開発しないといけないJ2EEサーバもあれば、意図的にルール違反をしない限りWS-I準拠のWebサービスとなるサーバもあることでしょうから、J2EEサーバ製品の仕様や思想に左右されるところと思われます。

拡張可能タイプ・マッピング

 Java→WSDLあるいはWSDL→Javaの対応を決めた標準マッピングがJAX-PRCには詳細に決められていますが、特定のXML形式などに準拠するニーズがある場合や、定義されていない特殊なデータ型をXMLでサポートしたい場合などに標準マッピングだけでは賄い切れないことがあります。

 JAX-RPCでは、拡張タイプ・マッピングと呼ばれるフレームワークで、「シリアライザー/デシリアライザー」と呼ばれるモジュールを作ることでマッピングを自分で行うことができるようになっています。


 JAX-RPCは、J2EE 1.4に追加されたほかの仕様とともに、J2EE上に実装されるWebサービス関連のプログラムコードをポータブルなものにするためのAPIや動作仕様を定義したものです。今後のJ2EE上でのWebサービス実装を作る開発者には必須のAPIといえます。





Java Solution全記事一覧



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

注目のテーマ

Java Agile 記事ランキング

本日 月間