SOAP を使わずに Web サービスを呼び出す: 第 1 回 Web サービスの現在のクライアント・プログラミング・モデルに対する WSIF の利点

SOAPは、Webサービスにアクセスするための多くのバインディングの1つにすぎませんが、Webサービスとほとんど同義語のようになっています。そのため、Webサービスを利用するアプリケーションの多くは、SOAPの特定のインプリメンテーションに関連するAPIによってWebサービスを利用しています。このシリーズでは、Webサービスを呼び出すためのもっと汎用性の高い、SOAPとは別のアプローチであるWeb Service Invocation Framework (WSIF) について説明します。これは、SOAPなど基本となるアクセス・プロトコルの複雑さを表に出すことなく、特にWeb Services Description Language (WSDL) を使用して記述されるWebサービスを直接呼び出すように設計されています。

Nirmal Mukhi (nmukhi@us.ibm.com), Research Associate, IBM Research

Nirmal K. Mukhi氏は、IBM T Jワトソン研究所のコンポーネント・システム・グループのソフトウェア・エンジニアであり、同研究所で2000年11月以来Webサービスの研究に携わっています。それ以前はインディアナ大学で勉学と研究を行い、1999年5月に同大学より修士号を取得しています。Nirmal氏は、WSDL4J、Web Services Invocation Framework (WSIF)、Web Services Gateway (WSGW)、およびBPWS4JなどのWebサービス・ソフトウェア・プロジェクトを中心に、多くのプロジェクトに参加してきました。氏の連絡先はnmukhi@us.ibm.com です。



2001年 9月 01日

Webサービスにより、簡潔さと柔軟性に重点を置いた、インターネットのための分散コンピューティングの標準規格に基づくプラットフォームが約束されます。1つの重要なWebサービス・テクノロジーは、WSDL (Web Service Description Language) です。開発者はWSDLを使うことによって、抽象的な形でWebサービスを記述できます。これはCORBAなど、他の分散コンピューティング・フレームワークで使用される既存のInterface Description Language (IDL) とよく似ています。また、開発者はWSDLを使うことによって、サービスに対して具体的なバインディングを指定できます。そして、それらのバインディングは、サービスのその抽象的記述が特定のアクセス・プロトコルにどう対応するかを記述するものとなります。WSDLのうちのこの部分は拡張可能です。つまり、だれもが独自のバインディングを考案して、カスタマイズされたプロトコルによりサービスにアクセスできます。

このことはWebサービスの利用における1つの課題となります。同じサービスに対していくつものバインディングが可能です。それらのバインディングのうちのあるものは特定の状況に、別のものは別の状況に適しています。バインディング自体は、抽象的なサービス記述から、サービスにアクセスするための任意のプロトコルへのマッピングを表現するものとなり得ます。サービスの使用方法に複数の選択肢を用意してバインディングの拡張を可能にすることは便利ではありますが、そうなると、クライアント側ではサービスの表示方法の統一という点で困難が生じます。

この記事では、まずクライアント側の現在のAPIとその機能について論じます。そこからWSIF (Web Services Invocation Framework) の必要性を導き、その後、WSIFの概要を説明します。

現在の呼び出しスタイルとその欠点

WebサービスのためのSOAPバインディングは、WSDLの仕様の一部です。このプロトコルには、ほとんどのプログラミング言語で利用可能なインプリメンテーションとツールがあり、その多くはフリーで入手できます。そのようにして開発者は、少ないコストでWebサービスをプラットフォームに依存しないようにすることができます。

したがって、ほとんどの開発者がWebサービスの使用について考える場合、なんらかのSOAPクライアントAPIを使用してSOAPメッセージを構成し、ネットワークを通じてそれをサービスのエンドポイントに送信することを思い浮かべるとしても、不思議ではありません。たとえば、Apache SOAPを使用する場合は、クライアントはCall オブジェクトを作成してそれにデータを入れることになるでしょう。それによって、サービスのエンドポイント、呼び出すSOAP操作の識別、送信するパラメーターなどがカプセル化されます。これはSOAPで動作しますが、次の理由により、Webサービスの呼び出しのための一般的なモデルとしての使用には制限があります。

  • WebサービスはSOAPサービス以上のものである
    Webサービスは、SOAPで提供されるサービスと同義語であると考えられています。それは、Webサービスの偏った見方です。コードのうち機能的な面とアクセス・プロトコルに関するWSDLの記述を含んだ部分は、すべてWebサービスと見なすことができます。WSDLの仕様においてWebサービスのためのSOAPバインディングが定義されてはいますが、RMI/IIOPをアクセス・プロトコルとして使用してEJBをWebサービスとして提供するなど、バインディングの拡張を追加することは原則として可能です。あるいは、ネイティブJava呼び出しをアクセス・プロトコルとし、任意のJavaクラスをWebサービスとして扱うことを考えることさえできるでしょう。このような広義のWebサービスの定義では、サービス呼び出しのためのバインディングに依存しないメカニズムが必要になります。
  • クライアント・コードを特定のプロトコル・インプリメンテーションに結び付けることは制限となる
    クライアント・コードを特定のプロトコル・インプリメンテーションのクライアント・ライブラリーに密接に結び付けてしまうと、メインテナンスの困難なコードになってしまいます。クライアント側でApache SOAP v2.1を使用してWebサービスを呼び出すアプリケーションのことを考えてみてください。v2.2での新しい機能やバグ・フィックスを利用しようと思うなら、クライアント・コードのすべてを更新することが必要になり、通常の移行作業で経験するような時間のかかる煩雑な作業となることでしょう。同じように、Apache SOAPを別のSOAPインプリメンテーションに移行しようとすると、そのプロセスは簡単ではありません。必要なのは、サービス呼び出しのための、プロトコル・インプリメンテーションに依存しないメカニズムです。
  • 新しいバインディングをクライアント・コードに取り込むことは困難
    WSDLには、新しいバインディングを定義するための拡張性があります。それにより開発者は、カスタム・プロトコルを使用するコードがWebサービスとして動作するようなバインディングを定義できます。しかし、実際にそれを実現することは困難です。そのプロトコルを使用するためのクライアントAPIを設計することが必要になります。アプリケーション自体で使用できるのはそのWebサービスの抽象インターフェースだけなので、抽象レイヤーを可能にするスタブを生成するために、いくつかのツールを作成することが必要になります。これも、時間のかかる面倒な作業となります。必要なのは、バインディングを容易に更新したり、新しいバインディングを容易に接続したりできるサービス呼び出しメカニズムです。
  • 複数のバインディングを柔軟に使用できる
    たとえば、複数のバインディングを提供するWebサービスがあり、それを使用するアプリケーションをうまく配置したとしましょう。例をもっと具体的にするため、そのサービスのためのSOAPバインディングがあり、そのローカル・サービス・インプリメンテーション (Javaクラス) をWebサービスとして扱うことを可能にするローカルJavaバインディングがあるとします。明らかに、そのサービスのローカルJavaバインディングを使用できるのは、クライアントがサービス自体と同じ環境に配置されている場合だけですが、もし本当にそうなっているなら、SOAPバインディングを使用するよりも、直接Javaを呼び出してサービスと通信するほうがずっと効率的です。Javaバインディングは、一種のショートカット・アクセス・メカニズムの役割を果たします。クライアントで複数のバインディングを活用するのであれば、実行時の情報に基づいて、実際に使用するバインディングを切り換える機能が必要になります。そのため、複数のバインディングを提供するWebサービスを活用するには、スタブを生成したり再コンパイルしたりすることなく、実行時に利用可能なサービス・バインディングを切り換えることが可能なサービス呼び出しメカニズムが必要です。

WSIFの紹介

Web Service Invocation Framework (WSIF) は、サービスがどこでどのように提供されるかには関係なくWebサービスを呼び出すための簡単なAPIを提供するツールキットです。それには、前述のすべての機能が含まれています。

  • バインディングとは関係なくどんなWebサービスに対してもアクセスを可能にするAPIが含まれています。
  • 抽象サービス・インターフェースを使用した呼び出しを可能にするスタブを生成する、ポート・タイプ・コンパイラーが付属しています。
  • Webサービスのスタブレス (完全に動的な) 呼び出しが可能です。
  • バインディングの更新済みインプリメンテーションを、実行時にWSIFにプラグインできます。
  • 新しいバインディングを、実行時にプラグインできます。
  • バインディングの選択を、実行時まで延期できます。

WSIFクライアントAPIを調べる

ここでの題材として、どこにでもあるような株式相場プログラム、Webサービスでの "Hello World" サンプルを使用することにします。下記のリスト1 に示すWSDLを使用した抽象サービス記述をご覧ください。

リスト1: 株式相場WebサービスのWSDL記述
<?xml version="1.0" ?> 
<definitions targetNamespace="http://www.ibm.com/namespace/wsif/samples/stockquote-interface" 
xmlns:tns="http://www.ibm.com/namespace/wsif/samples/stockquote-interface" 
xmlns:xsd="http://www.w3.org/1999/XMLSchema" 
xmlns="http://schemas.xmlsoap.org/wsdl/"> 
<message name="GetQuoteInput"> 
<part name="symbol" type="xsd:string"/> 
</message> 
<message name="GetQuoteOutput"> 
<part name="quote" type="xsd:float"/> 
</message> 
<portType name="StockquotePT"> 
<operation name="getQuote"> 
<input message="tns:GetQuoteInput"/> 
<output message="tns:GetQuoteOutput"/> 
</operation> 
</portType> 
</definitions>

簡単そのものです。これは、1つのポート・タイプによって提供される1つの操作だけを含むサービスを記述しています。その操作は、株式速報の記号として解釈されるストリング (string) を受け取り、その銘柄の現在の相場をfloatとして戻します。このサービスを実際に使用するためには、アクセス・メカニズムを定義するバインディングと、そのバインディングのためのサービス・エンドポイントが必要です。このサービスのためのSOAPバインディングを、リスト2 に示します。

リスト2: 株式相場WebサービスのSOAPバインディング
<?xml version="1.0" ?> 
<definitions targetNamespace="http://www.ibm.com/namespace/wsif/samples/stockquote" 
xmlns:tns="http://www.ibm.com/namespace/wsif/samples/stockquote" 
xmlns:tns-int="http://www.ibm.com/namespace/wsif/samples/stockquote-interface" 
xmlns:xsd="http://www.w3.org/1999/XMLSchema" 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:java="http://schemas.xmlsoap.org/wsdl/java/" 
xmlns="http://schemas.xmlsoap.org/wsdl/"> 
<import namespace="http://www.ibm.com/namespace/wsif/samples/stockquote-interface" 
location="stockquote-interface.wsdl"/> 
<binding name="SOAPBinding" type="tns-int:StockquotePT"> 
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> 
<operation name="getQuote"> 
<soap:operation soapAction="http://example.com/GetTradePrice"/> 
<input> 
<soap:body use="encoded" 
namespace="urn:xmltoday-delayed-quotes" 
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
</input> 
<output> 
<soap:body use="encoded" 
namespace="urn:xmltoday-delayed-quotes" 
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
</output> 
</operation> 
</binding> 
<service name="StockquoteService"> 
<documentation>Stock quote service</documentation> 
<port name="SOAPPort" binding="tns:SOAPBinding"> 
<soap:address location="http://localhost:8080/soap/servlet/rpcrouter"/> 
</port> 
</service> 
</definitions>

これは、サービスと通信するためのトランスポート・プロトコルとしてRPCスタイルとHTTPを使用する、標準的なSOAPバインディングです。この文書のport セクションには、SOAPバインディングを使用してサービスにアクセスできるURIを定義してあります。リスト3 に、このサービスをApache SOAP 2.2クライアント側APIで使用した場合と、それをWSIFのクライアントAPIで使用した場合との比較を示します。

リスト3: Apache SOAP APIとWSIF APIのサービス・アクセスの比較

Apache SOAP API

// Step 1: identify the service 
Call call = new Call(); 
call.setTargetObjectURI("urn:xmltoday-delayed-quotes"); 
// Step 2: identify the operation 
call.setMethodName("getQuote"); 
call.setEncodingStyleURI(encodingStyleURI); 
// Step 3: identify the parameters 
Vector params = new Vector(); 
params.addElement(new Parameter("symbol", 
  String.class, symbol, null));
call.setParams(params); 
// Step 4: execute the operation 
Response resp = call.invoke(url, 
"http://example.com/GetTradePrice");
// Step 5: extract the result or fault 
if(resp.generatedFault()) 
{ 
Fault fault = resp.getFault(); 
System.out.println("Ouch, the call failed: "); 
System.out.println("  Fault Code   = " +  
fault.getFaultCode()); 
System.out.println("  Fault String = " +  
fault.getFaultString()); 
throw new SOAPException("Execution failed " + fault); 
} 
else 
{ 
Parameter result = resp.getReturnValue(); 
return ((Float) result.getValue()).floatValue(); 
}

WSIF API

// Step 1: identify the service 
Definition def = WSIFUtils.readWSDL(null,wsdlLocation);
// Step 2: identify the operation (choose an 
// appropriate service port) 
WSIFDynamicPortFactory portFactory = 
new  WSIFDynamicPortFactory(def, null, null); 
// Get default port 
WSIFPort port = portFactory.getPort(); 
// The user can also explicitly select a port  
// to use. 
// WSIFPort port =  
//             portFactory.getPort("SOAPPort"); 
// Step 3: identify the parameters 
// Prepare the input message 
WSIFMessage input = port.createInputMessage(); 
input.setPart("symbol",  
new WSIFJavaPart(String.class, symbol));
// Prepare a placeholder for the output value 
WSIFMessage output = port.createOutputMessage(); 
// Step 4: execute the operation 
port.executeRequestResponseOperation("getQuote", 
     input, output, null);
// Step 5: extract the result or fault 
WSIFPart part = output.getPart("quote"); 
return ((Float)part.getJavaValue()).floatValue();

ご覧のように、WSIFのAPIはWSDLの抽象サービス記述によって駆動されます。これは、実際に使用されるバインディングからは完全に切り離されています。この呼び出しAPIはWSDL指向であり、メッセージの各部分や操作に言及するためにWSDLの用語を使用する点で一層自然な形です。WSDL記述を読む直感的な方法としては、必要なポート・タイプをサポートするポートを選んでから、必須部分から構成される必須抽象入力メッセージを提供することにより、操作を呼び出します (メッセージと特定のバインディング・プロトコルの対応を心配する必要はありません)。WSIF APIの設計は、まさにそのようになっています。

上記のApache SOAP APIなどの普通のAPIでは、SOAPの場合のターゲットURIやエンコード・スタイルなどのように、特定のプロトコルの中心となる概念が使用されています。これは、やむをえないことです。というのは、APIはWSDL上に階層化されているわけではなく、特定のプロトコルのために設計されるものだからです。


WSIFを使用した2つの呼び出しモデル

WSIFでは、Webサービスを2種類の方法で呼び出すことができます。1つはスタブレス動的呼び出しであり、WSIF APIを直接使用することが必要です。もう1つは生成されたスタブによる呼び出しであり、その場合、アプリケーションでJavaインターフェース (WSDLポート・タイプに直接対応) を操作することが可能で、WSIF APIが隠蔽されます。

スタブレス (動的) 呼び出し

Webサービスにアクセスするために必要な情報、つまり抽象インターフェース、バインディング、およびサービス・エンドポイントは、すべてWSDLによって利用できます。上記のクライアントAPIの例をよく見ると、ユーザーの提供する情報は、サービスのためのWSDLファイルの位置と、知りたい株式相場に対応する記号だけであることがわかります。実行時にこのサービスをロードして呼び出しを実行するためにWSIF APIを使用するのは、極めて自然なことです。

WSIFの配布ファイルには、WSDLの各操作ごとの実行方法をデモで示すDynamicInvoker が含まれています。これは、WSDLファイルのURIと必須操作パラメーターをコマンド・ライン・パラメーターとし (最初のインプリメンテーションで指定できるのはストリングなどの単純なタイプだけです)、直接WSIF APIを使用して作業を実行します。これを使用して株式相場サービスを呼び出す例を、リスト4 に示します。詳細については、WSIF配布ファイルに含まれるドキュメンテーションをご覧ください。

この種の呼び出しではスタブ・クラスが生成されず、別個のコンパイル・サイクルは不要なので、大変便利です。

リスト4: DynamicInvokerを使用して株式相場サービスにアクセスする
java clients.DynamicInvoker http://services.xmethods.net/soap/urn:
xmethods-delayed-quotes.wsdl getQuote IBM
Reading WSDL document from 'http://services.xmethods.net/soap/urn:
xmethods-delayed-quotes.wsdl'
Preparing WSIF dynamic invocation
Executing operation getQuote
Result:
Result=108.8
Done!

スタブを使用した呼び出し

アプリケーションで、サービスのもっと抽象的なビューが必要とされており、WSIFクライアントAPIの処理をしたくない場合、スタブレス呼び出しは望ましくありません。WSIFにはポート・タイプ・コンパイラーが付属しています。これは、特定のWSDLに対して、各ポート・タイプのためのクライアント・スタブと、使用される複合タイプに相当するJavaの要素 (JavaBeansの形) を生成します。生成されるスタブを使用するアプリケーションでは、抽象サービス・インターフェースを使用することができ、それによってプロトコルやWSIFクライアントAPIからは切り離されます。それらのスタブでは、実際のサービス呼び出しのためにデフォルト・ポートが使用されます。WSIFのポート・タイプ・コンパイラーによって生成されるスタブによって株式相場サービスを使用する例を、リスト5 に示します。

リスト5: WSIF生成によるスタブを使用して、株式相場サービスにアクセスする
StockquotePT service = new StockquotePTStub(WSIFUtils.readWSDL(null, wsdlLocation), 
null, null);
float quote = service.getQuote("IBM");
System.err.println (">> Received quote: "+quote);

アプリケーション・サーバーなど、管理環境にあるスタブの場合は、カスタマイズが可能であることに注意してください。たとえば、該当するポートを戻すことを担当するファクトリーを変更してポート選択アルゴリズムをカスタマイズしたり、実際に呼び出しに使用するポートを変更したりできます。

この記事では、WSIFがなぜ必要かの概要を説明し、高水準APIを通じてバインディングに依存しないサービスにアクセスするというその主要な機能について、また、抽象インターフェースを通じてサービスを使用するためのカスタマイズ可能スタブを生成するポート・タイプ・コンパイラーを使用できることについて説明しました。SOAPクライアントAPIを直接使用したサービス・アクセスと、WSIF APIを使用したサービス・アクセスとを比較すると、WSIFによってWebサービス呼び出しの問題全体が、バインディング中心の視点から、サービスのWSDL記述によるさらに高いレベルの抽象化へと移ることがわかります。これはWSIFの設計原則の1つであり、それによりサービス・バインディングを、特定のプロトコルに従って呼び出しに必要なコード部分と見なすことができます。そして、それらはいつでもプラグインできます。

今後の記事では、WSIFのアーキテクチャーについて調べ、それによって新しいバインディング・インプリメンテーションや更新されたバインディング・インプリメンテーションのプラグインが可能になること、それによってカスタマイズ済みタイプ・システムをWebサービスで使用できるようになること、そして複数のポートから選択するためのカスタマイズ済みヒューリスティックを使用するような実行時環境の実現方法を検討します。

参考文献

  • alphaworksのWSIF配布ファイルをダウンロードし、簡単なサンプルを試してください。これは、WSIFのサポートする複数の異なる呼び出しスタイル、およびプロトコル固有のクライアントAPIと比較した場合のその利点を示す例です。
  • どんな種類の拡張が可能かについては、WSDLの仕様書をご覧ください。また、WebサービスにアクセスするためのSOAPバインディングを定義するのに使用する場合のWSDLの拡張メカニズムはどのようなものかも調べることができます。
  • SOAP仕様書そのものもご覧ください。
  • 今までにWebサービスでのプログラミングをした経験がないなら、Web Services ToolKit は、そのための優れた出発点となります。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=SOA and web services
ArticleID=245542
ArticleTitle=SOAP を使わずに Web サービスを呼び出す: 第 1 回 Web サービスの現在のクライアント・プログラミング・モデルに対する WSIF の利点
publish-date=09012001