Perl で XML-RPC を始めよう 第 1 回:Web サービスに XML-RPC を使用する

Perl で XML-RPC Web サービスを作成することは、CGI スクリプトと同じくらい簡単です。本稿では、XML-RPC とは何か、そして Perl のFrontier::RPC ライブラリーを使用して簡単なクライアントとサーバーを作成する方法について簡単に説明します。

Joe Johnston, Senior Software Engineer, O'Reilly and Associates

Joe Johnston は、昼間は O'Reilly and Associates でプログラマーとして勤務しています。愛猫がキーボードの上にいないときには、Perl Journal、use.perl.org、www.perl.com、および O'Reilly Network のために記事を書いています。



2001年 3月 01日

アプリケーション・ゲートウェイ

HTML フォームを初めて作成したときの感動を思い出しましょう。おそらく、フォームの内容を電子メールで自分に送ったり、ユーザーが情報を入力する別の HTML ページを表示したりしたことでしょう。何をしたにしろ、情報通信の専門家が言うところの2 層またはクライアント / サーバーシステムを作成したのです。ちょっと作業を追加すれば、Web フォームから集めた情報をデータベースに格納することができます。このように、複数のクライアントは、ブラウザーだけを使用して、単一のデータベースとやり取りすることができます。データベースに格納された情報は、CGI スクリプトからの要求があり次第、適切な HTML 形式に変換することができます。この種のアーキテクチャーを使用している代表的な Web アプリケーションとして、SlashDot のような Web ログがあります(参考文献参照)。HTML ページを生成するコードのことをフロントエンドと言い、データベースとビジネス・ロジックを含む部分のことをバックエンドと言います。

このシステムは、データベースや Web サーバーのいずれかがトラフィックを処理できなくなるまで、正常に実行し続けます。ボトルネックが Web サーバーにある場合は、ネットワークに単に Web マシンを追加するだけで解決できます。フロントエンドでのネイティブのアプリケーション・プログラミング・インターフェース (API) コールによってデータベースに接続していると、バックエンドの実装を変更することが難しくなります。データベース・ベンダーを切り換えたり、データベース・サーバーをクラスター化したりするということは、すべてのフロントエンド・コードを変更するという意味になります。解決策は、フロントエンドのプレゼンテーション・ロジックをバックエンドのビジネス・ロジックから切り離すことです。ただし、接続する必要はあります。フロントエンドとバックエンド間の橋渡しをするソフトウェアのことをミドルウェアと言います。Web アプリケーションで正しく動作する非常に簡単なオープン・アーキテクチャー・ミドルウェア・プロトコルの 1 つが、XML-RPC です。


XML と RPC

リモート・プロシージャー・コール (RPC) は新しい概念ではありません。クライアント/サーバー・システム、RPC は、従来は 1 台のマシン上のプログラム内で呼び出されるプロシージャーであり、ネットワークを介して RPC サーバーに送られました。呼び出されたプロシージャーを実際に実装するのは、この RPC サーバーです。RPC サーバーは、プロシージャーの結果をまとめ、その結果を呼び出し側に送り戻します。これで、呼び出し側のプログラムは実行を続けます。このシステムは大量のオーバーヘッドと待ち時間を必要としますが、処理能力の低いマシンでも高い処理能力のリソースを利用することができます。また、アプリケーションは、マシンのネットワークという強力な演算能力を活用することができます。このタイプの分散コンピューティングのおなじみの例が、SETI@Home プロジェクトです(参考文献参照)。

Frontier と Userland で名声を博した Dave Winer (参考文献参照) は、XML と HTTP を使って RPC の概念を拡張することに成功しました。XML-RPC は、RPC 要求を XML にエンコードし、それを標準の HTTP 接続を介してサーバーすなわちリスナー部分に送ることで動作します。リスナーは、XML をデコードし、要求されたプロシージャーを実行して、その結果を XML にパッケージし、ネットワークを介してクライアントに送り戻します。クライアントは、XML をデコードし、結果を標準言語のデータ型に変換して、実行を続けます。図 1 は、クライアント (get_account_info RPC を要求) とリスナー (そのプロシージャーの結果を戻す) 間の実際の XML-RPC 変換を示す図です。

図 1. XML-RPC 変換の例

XML-RPC のおもしろい部分は、プログラミング言語とオペレーティング・システム・プラットフォームにまたがって、クライアントとサーバーを別々の言語で作成して一緒に動作させることができる点です。Perl クライアントは Java サーバーとやり取りすることができます。Python リスナーは PHP 要求に応えることができます。昔の役立たずの C で XML-RPC プログラムを作成することさえ可能です。XML-RPC の扱いが非常に簡単なのは、XML 変換の詳細がユーザーから隠されているからです。ただし、もちろん、ユーザー独自の XML-RPC ライブラリーを実装していないことが前提です。

このプロトコルには、ミドルウェアを作成する場合に注意しなければならない重要な面が 2 つあります。XML-RPC は HTTP で作成され、通常の Web トラフィックのように、そのステートレスな変換は要求や応答に多様性があることです。トランザクションや暗号化に対する組み込みサポートはありません。もう 1 つの覚えておくべき重要なことは、XML-RPC には、有限のデータ型があることです。クライアント・プロシージャーの引き数とリスナーの戻り値は、拡張不可能な XML サブセットにマップされます。ただし、実際には、XML-RPC のデータ型には、複雑なタスクを実行できる程度の柔軟性はあります。

表 1に、XML-RPC のデータ型をすべてリストします。このうちの 4 つは、他のデータ型よりもかなり使用されています。単一値のデータ型については、ストリング・データを示す<sting> と、整数データを示す <int> が、ほとんどの XML-RPC プログラムで使用されます。

また、コレクション・データ型も 2 種類あります。任意のデータ型の簡単なシーケンスは、<array> タグで示します。レコード、構造体、および結合配列は、<struct> タグで示します。XML-RPC の構造体は、Perl、Python、PHP のコーダーでは当然のことですが、キーと値のペアから成り立ちます。

表 1. XML-RPC のデータ型
XML-RPC タグ説明
<string>文字のシーケンス
<int>符号付きまたは符号なしの 32 ビット整数値
<boolean>真 (1) または 偽 (0)
<double>符号付き倍精度浮動小数点数
<dateTime.iso8601>日付および時刻 (ただし、時間帯はない)
<base64>base64 エンコード・ストリング
<array>データ型のシーケンスのコンテナー
<struct>キーと値のペアのコンテナー

リモート合計処理機能: 例

では、XML-RPC の具体的な例を紹介しましょう。初心者向けの多くのコンピューター言語の書籍では、ストリングのコンパイルと印刷以上のことはほとんど実行しない、"helloworld" というプログラムを作成します。初心者向けの XML-RPC プログラムでは、もっとしっかりしたフレームワークが必要です。XML-RPC 作業の多くはクライアントを扱うので、sum() プロシージャーを定義する XML-RPC リスナーとやり取りするクライアントを作成しましょう。このプロシージャーは、当然ですが、プロシージャーに渡された 2 つの整数の合計を戻します。XML-RPC クライアントを作成するときの言語にかかわらず、常に次の情報を把握していなければなりません。

  • リスナーの URL と TCP ポート
  • リモート・プロシージャーの名前
  • プロシージャーが受け取る引き数の種類と数
  • 戻り値の種類と数

これは、XML-RPC リスナーに対する API を定義する類の情報です。残念ながら、XML-RPC 仕様には、リスナーがこの情報を転送するための標準的な発見方法は用意されていません。表 2 のような簡単な Web ページを使用することをお勧めします。

表 2. sum() の XML-RPC API
URL:http://marian.daisypark.net/RPC2ポート:1080
プロシージャー定義
プロシージャー名入力出力説明
sum<int>, <int><int>2 つの提供された整数の合計は <int> として戻される

この情報があれば、クライアントを作成することができます。後で PHP クライアントの詳しい例を紹介するので、Perl のFrontier::RPC モジュールを見てみましょう。名前にごまかされてはいけません。これは本当に Perl の XML-RPC ライブラリーです。歴史的な理由から、このような予想外の名前が付いているのです。このライブラリーは、XML::Parser に依存しており、XML::Parser は expat XML パーサーに依存します。どちらの Perl モジュールも、お近くの CPAN(参考文献 参照) ミラーにありますが、expat ソースの場合は SourceForge を参照する必要があります(参考文献 参照)。うれしいことに、expat はほとんどの Unix システム上で正常にコンパイルするので、インストールはそれほど難しくありません。SourceForge の expat ページで、オペレーティング・システムがどのようにサポートされているかを確認してください。


sum() クライアント

Frontier::RPC をインストールし終えると、XML-RPC コールの作成に必要なコードがいかに少ないかに驚くかもしれません。リスト 1 は、2 つのハードコーディングした整数引き数で RPC を作成し、その結果を出力するスクリプトです。

リスト 1: Perl の XML-RPC クライアント・テスト sum()
     1	#!/usr/bin/perl 
     2	# Testing sum()
     3	
     4	use strict;
     5	use warnings;
     6	use Frontier::Client;
     7	
     8	my $url  = "http://marian.daisypark.net:1080/RPC2";
     9	my @args = (2,5);
    10	
    11	my $client = Frontier::Client->new( url   => $url,
    12					    debug => 0,
    13					  );
    14	
    15	print "$args[0] + $args[1] = ", $client->call('sum', @args), "\n";

このスクリプトの先頭は、システムの Perl インタープリターを指す、永遠に存在する"shbang" 行です。4 行目と 5 行目は、警告をオンにします。use strict はご存知かもしれませんが、use warnings はあまりなじみがないかもしれません。これは、中心的な Perl ディストリビューションに最近追加されたものです。これは、-w フラグが実行するのと同じ種類のエラーがないかどうかチェックするものですが、エラーを報告する方法については、より細かく制御することができます。6 行目は、XML-RPC ライブラリーに入ります。8 行目は、ポート番号も含まれているリスナーの URL を保持する変数を作成します。9 行目は、リモート・プロシージャーに渡す引き数の簡単なリストです。

本当に大事なのは、新しい XML-RPC クライアント・オブジェクトが作成される 11 行目です。このオブジェクトは、ネットワーク接続はまだ確立されていませんが、URL で初期設定されます。このクラスは、非常に便利なデバッグ機能も提供します。この機能をオンにすると、call() メソッドの内側で発生する XML 要求と応答が出力されます。

call() メソッドについて言えば、15 行目で、RPC が標準の Perl コードにいかに問題なく適合するかが示されます。call() の 1 つ目の引き数は、その引き数のリストの後に続くリモート・プロシージャーの名前です。配列や構造体など、複雑な変数を引き渡す方法については、後で説明します。リモート・プロシージャーからの戻り値は、call によって標準の Perl スカラーに変換され、出力されます。

52 が整数であることを把握する、Frontier::RPC ライブラリー内の Perl の Do What I Mean (DWIM) 属性 surface にお気付きかと思います。XML-RPC オブジェクトでデバッグをオンにして、これを検証することができます。そのデータ型を強制するときのために、Frontier::RPC ライブラリーは、この型キャストに対するオブジェクト指向のインターフェースを提供します。リスト 2 に、値2 をストリングとして送信することを強制する方法を示すコードを示します。

リスト 2: Frontier::RPC での強制的な型キャスト
     1	use Frontier::RPC2;
     2	
     3	my $coder = Frontier::RPC2->new;
     4	my @args;
     5	
     6	push @args, $coder->string("2");

お分かりのように、Frontier::Client の基本クラスである、Frontier::RPC2 クラスを持ってくる必要があります。このクラスのインスタンス・オブジェクトは、データのオブジェクト・コンテナーを作成することにより、値を必要なデータ型に強制的に変換することができます。これらのオブジェクトは、call() メソッドが処理してくれるので、ユーザーはプログラミングする必要はありません。


sum() サーバー

一般に、Perl の XML-RPC リスナーの作成は、クライアントの作成よりも簡単です。リスト 3 を見れば分かります。

リスト 3: Perl の XML-RPC リスナー
     1	#!/usr/bin/perl
     2	# sum() server
     3	
     4	use strict;
     5	use warnings;
     6	use Frontier::Daemon;
     7	
     8	my $d = Frontier::Daemon->new(
     9				      methods => {
    10						  sum => \&sum,
    11						 },
    12				      LocalAddr => 'marian.daisypark.net',
    13				      LocalPort => 1080,
    14				      );
    15	
    16	sub sum {
    17	  my ($arg1, $arg2) = @_;
    18	
    19	  return $arg1 + $arg2;
    20	}

1?5 行目については、すでに紹介したとおりです。クラスはFrontier::Daemon で、HTTP::Daemon のサブクラスです。このクラスのオブジェクトのインスタンスを作成すると、メソッドは戻りません。その代わりに、プログラムは、while ループに入って、新しい接続を待機します。サブクラス化という離れ業で、HTTP::Daemon そのものがIO::Socket::INET から派生されます。これにより、LocalPort 属性を設定することによって TCP ポートを聴取するように、Frontier::Daemon オブジェクトを構成することができます。このスクリプトの実行環境である Linux システムは、数多くの IP アドレスに応答します。繰り返しますが、IO::Socket::INET の属性を使用することにより、このリスナーをLocalAddr 属性を持つ特定の IP に制限することができます。

XML-RPC リスナーの中心は、methods 属性です。この属性は、必要な作業を実行する実際の Perl サブルーチンの参照に API プロシージャー名をマップする匿名ハッシュを指します。表 2 の API は、リスナーにsum() というプロシージャーがあることを示していることを思い出しましょう。Perl の XML-RPC ライブラリーに、sum() という Perl 関数がなければならないという要件はありません。 sum() サブルーチンは直接的な方法で実装されます。運用コードのエラー・チェックを実行することもできます。sum() は、ネイティブの Perl スカラーを処理して、Perl スカラーを戻すことに注意してください。ライブラリーは、再び、気付かれないように XML への変換を行います。


簡単で強力

Eric Raymond は、XML-RPC は「Unix 精神にたけている (very much in the Unixspirit)」という表現を使っています (参考文献 参照)。そのシンプルさにより、お兄さん格の SOAP よりも利用しやすくなっています。XML-RPC では、リモート・ユーザーがアプリケーションにアクセスするためのゲートウェイを作成できるだけでなく、どのような言語を使っても自由に作成することができます。

次回は、もっと複雑で実践的な XML-RPC の例を紹介いたします。多くの Web サイトは、アカウント名とパスワードを使ってログインすることをユーザーに要求しています。一般に、ユーザーには、後で特定のアプリケーション状態を再呼び出しする場合に使用できるセッション ID が発行されます(カートに入っているものを覚えていなければならないショッピング・カート・アプリケーションを考えましょう)。次回は、アカウント情報が格納されているバックエンドの MySQL システムからフロントエンドの PHP コードを隠す Web サービスを作成します。

参考文献

  • XML-RPC のホーム・ページで、XML-RPC の仕様を参照し、XML-RPC ライブラリーへのリンクを探してください。
  • Dave Winer (Frontier ライブラリーの作成者) は、Userland コミュニティーを運営しています。
  • SETI@Home プロジェクトは、分散コンピューティングの代表的な例です。
  • SourceForge からexpat のソース・コードを入手してください。
  • Slashdot.org は、開発者向けの人気の高い Web ログです。

コメント

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=245555
ArticleTitle=Perl で XML-RPC を始めよう 第 1 回:Web サービスに XML-RPC を使用する
publish-date=03012001