Python Web サービス開発者: 第 6 回: Python SOAP ライブラリー 第 2 回

WSDL を使用する場合と使用しない場合の比較

Mike Olson と Uche Ogbuji は、Python SOAP 実装の検討を進め、SOAP クラスターおよびサーバー・ライブラリーとしての Zolera SOAP Infrastructure (ZSI) の性能を試しました。そして、現時点では、Python のもとで SOAP を使用するためのツールとして、ZSI が最も優れているのではないかと評価しています。

Mike OlsonFourthought, Inc.

Mike Olson 氏は、企業向けの知識管理アプリケーションのための XML ソリューションを専門とするソフトウェア・ベンダーおよびコンサルタント会社である、Fourthought Inc. のコンサルタントであり、共同設立者です。Fourthoughtは、XML ミドルウェア用のオープン・ソース・プラットフォームである 4Suite を開発しています。



Uche Ogbuji, Consultant, Fourthought, Inc.

Uche photoUche Ogbuji 氏は、Fourthought, Inc. のコンサルタント兼共同設立者です。この会社は、企業のナレッジ・マネジメントのための XML ソリューションを専門とするソフトウェア・ベンダー兼コンサルタント会社です。Fourthought では、XML、RDF、およびナレッジ・マネジメント・アプリケーション用のオープン・ソース・プラットフォームである 4Suite を開発しています。Ogbuji 氏は、ナイジェリア出身のコンピューター・エンジニア兼ライターで、現在は、米国コロラド州ボールダーに住み、そこで働いています。



2002年 2月

今月も、Python 用の SOAP 実装について検討を続けます。具体的には、前回まったく触れずにおいた Zolera SOAP Infrastructure (ZSI) について、詳しく調べることにします。ZSI は、Python/XML パッケージのために積極的に貢献し、長年にわたり、インターネットのインフラストラクチャーおよびセキュリティーに関する重要な標準となる業績をいくつも残している、Rich Salz の創案によるものです。ZSI は Python Web Services プロジェクトの一部として SourceForge に追加されています。前回の記事で取り上げたもう 1 つの Python/SOAP パッケージである SOAPy も、SourceForge でホストされています。私たちは、この混乱状態がまもなく解消されるものと期待しています。おそらくは、SOAP パッケージの合併という形を取るのではないかと思います。

ZSI は純粋主義的な SOAP ライブラリーです。特に、低レベルのプロトコルの詳細に関する取り扱いにはほとんど関与せず、データのストリーム (これは、適切にフォーマットされた SOAP メッセージでなければなりません) を扱い、構文解析されたデータに基づいてイベントを Python イベント・ハンドラーにディスパッチします。このように焦点を厳密に絞ったことの利点として、ZSI はおそらく、Python 用の SOAP ライブラリーとして最も完全で、標準に準拠したものとなっています。弱点としては、ZSI ユーザーが自分の Web サービスを実際に運用するために、より多くの作業が必要になる可能性があります。

ZSI の設定

この記事の執筆時点における最新バージョンである ZSI 1.1 をインストールするためには、Python 2.0 以降が必要です。インストール手順書では PyXML 0.6 以降が必要とされていますが、実際には、バージョン 0.6 以降、かつ 0.7 よりも前 のバージョンが必要です。PyXML 0.7 には、ZSI 1.1 の障害となる、いくつかの大幅な API 変更が加えられています。このことは、PyXML に依存するパッケージを扱う際に、一般的な問題となります。例えば、PyXML 0.6 に依存すると記載されているパッケージを使用していて、奇妙なエラーが発生した場合、使用可能な最新バージョンの PyXML を入手している可能性があります。最新バージョンを使用したくなるのは無理もありませんが、残念ながら、それではうまくいかないのです。最近の CVS 活動が示すところを見ると、次期リリースの ZSI は、おそらく PyXML 0.7 以降で使用できるようになると思われます。現在のところは、SourceForge から PyXML 0.6.6 を入手し、アンパックしたうえで、次のようにビルドしてください。

$ python setup.py install

ZSI パッケージをダウンロードし、アンパックして、同じような方法でビルドしてください。

$ python setup.py install

Python の配布ユーティリティー (別称 distutils) では、追加パッケージのインストール方法がこのように統一されています。

すべてがインストールされた後で、doc ディレクトリーを調べてください。このディレクトリーには、HTML、PDF、postscript、および (Python 文書プロジェクトで使用されているものと同じ LaTeX ツールを使用して作成された) TeX 形式による、優れた文書が含まれています。


クライアント特権の呼び出し

私たちはまず最初に、ZSI を SOAP クライアントとして使用してみました。前回の記事では、SOAP.py クライアントを作成し、(漫画タンタン のファンには昔からおなじみの)ハドック船長の悪態を戻す簡単な Web サービスにアクセスしました。同じサーバー用のクライアントを、ZSI を使用して作成しようと思います。残念ながら、その途中で厄介なことが起こってしまいました。最も簡単明快な方法はリスト 1 に示すコードですが、この方法を使用するためには、サーバーがメッセージ・パラメーターをその順序および名前に従って取り扱う必要があることが分かりました。しかし、「ハドック船長」サーバーの実装に使用されている Borland Delphi 実装はそれほど柔軟ではありませんので、一筋縄ではいきません。

リスト 1: ZSI プログラムで「ハドック船長」SOAP サービスにアクセスする試み
#http://xmethods.net/detail.html?id=175
import sys
#Import the ZSI client
from ZSI.client import Binding
u = '/scripts/Haddock.exe/soap/IHaddock'
n = 'urn:HaddockIntf-IHaddock'
b = Binding(url=u, ns=n, host='www.tankebolaget.se', port=80,
            tracefile=sys.stdout)
try:
  lang = sys.argv[1]
except IndexError:
  lang = 'us'
result = b.Curse(lang)
print 'What captain Haddock had to say: "%s"'%result

私たちにとっては期待どおりの結果が得られませんでしたが、この単純な方法は多くの SOAP 1.1 サーバーで使えるはずですので、検討してみましょう。まず最初に、ZSI クライアント・モジュールと Binding クラスをインポートします。Binding クラスは、SOAP リクエストの設定および呼び出しに必要な仕組みを実装するものです。SOAP エンドポイントのアドレスのコンポーネントを設定します。ホスト、URL パス、およびポートを別個に設定することに注意してください。SOAP.py の場合とは異なり、単一 URL を利用することはできません。これらのコンポーネントは、リモート・サーバーとの結合を作成するために使用されます。

最後に、リモートリクエストを送信する結合オブジェクトで Curse メソッドを呼び出し、そのメソッドの戻りによって結果を受け取ります。ただし、すでに述べたように、この単純な方法は私たちの「ハドック船長」サーバーではうまくいきません。LangCode パラメーターをサーバーに伝えるには、これよりも複雑な構造を使用しなければなりません。リスト 2 のコードを使用すると、うまく行うことができます。

リスト 2: 「ハドック船長」SOAP サービスにアクセスするために使用できる ZSI プログラム
import sys
#Import the ZSI client
from ZSI import TC
from ZSI.client import Binding
u = '/scripts/Haddock.exe/soap/IHaddock'
n = 'urn:HaddockIntf-IHaddock'
b = Binding(url=u, host='www.tankebolaget.se', port=80, ns=n)
try:
  lang = sys.argv[1]
except IndexError:
  lang = 'us'
class CurseRequest:
    def __init__(self, langCode):
        self.LangCode = langCode
CurseRequest.typecode=TC.Struct(CurseRequest,
                                [TC.String('LangCode')],
                                'Curse',
                                inline=1)
try:
    result_list = b.RPC(u, 'Curse', CurseRequest(lang), TC.Any(aslist=1))
    #Extract the first returned parameter
    result = result_list[0]
    print 'What captain Haddock had to say: "%s"'%result
except:
    raise
    print 'reply=', b.reply_code
    print 'reply_msg=', b.reply_msg
    print 'headers=', b.reply_headers
    print 'data=', b.data

TypeCode モジュールを使用すると、Python データ型と SOAP データ型の間で、正確で拡張可能なマッピングが行えます。このモジュールには、StringInteger などのための、組み込みクラスのセットが備わっています。また、任意のデータ集合体を定義するための Struct クラスと、特別なクラス Any も定義されています。Any は、任意の組み込み型または派生型を表現するために使用することができるため、動的型定義の基礎となります。後の 2 つのクラスは、SOAP エンコードにおいて、型付きデータを異なる方法でマーシャルおよびアンマーシャルすることに伴って生じる、相互運用性に関する多くの問題を回避するために欠かせません。私たちが取り組んでいる Delphi サーバーに合うように ZSI を調整するためには、避けて通れない苦労もありましたが、少なくとも、ZSI はそのために必要なあらゆる仕組みを提供してくれます。他の Python SOAP 実装を使用した場合には、クライアント・ライブラリー・コードに手を加えなければ、相互運用性の問題を解決することはできませんでした。

その後で、CurseRequest というクラスを作成します。これは、「ハドック船長」サーバーで必要となる形式にマーシャルされます。必須パラメーター LangCode に関するインスタンス属性を定義します。そして、このクラスに、LangCode 値をストリングにマーシャルする ZSI 型コードを割り当てます。ここで注意を要するのは、inline=1 という指定です。これにより、多重参照値を利用したマーシャルが使用できないようになっています。デフォルトでは、ZSI は多重参照を利用して構造をマーシャルします。つまり、ある値を SOAP メッセージの一部で表現し、同じ値をその SOAP メッセージの別の部分で参照することにより、値の重複が回避できるようになっています。SOAP エンコード方式の多重参照値は、単純な値に比べて使用される頻度がはるかに低いものです。ZSI の構造型がデフォルトで多重参照としてマーシャルされるようになっているのは、おかしなことです。

こうしたことなどを細かく見てみると、ZSI の作成者である Rich Salz が私たちに語ったことが、なるほどと思えてきます。「実は、ZSI は主として複雑な Web サービス用に設計されている」というのです。彼は、近いうちに、公開されているサービスの大多数を占めると思われる、おもちゃのようなささやかなサービスに対しても、ZSI をもう少し使いやすくすると約束してくれました。

次に、サンプルのクライアント・コードの使用法を示します。

$ python curse-zsi.py 
What captain Haddock had to say: "Polygraphs!"

ZSI でデバッグとトレースを使用可能にするのは、非常に簡単なことです。tracefile=sys.stdout というパラメーターを Binding 初期化指定子に渡すだけでよいのです。この変更が加えられたサンプル ZSI セッションは、次のようになります。

$ python curse-zsi-trace.py 
_________________________________ Thu Jan 31 10:25:09 2002 REQUEST:
<SOAP-ENV:Envelope
 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"

 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" >
<SOAP-ENV:Body>
<Curse id="822b6dc">
<LangCode id="81089d0" xsi:type="xsd:string">us</LangCode>
</Curse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
_________________________________ Thu Jan 31 10:25:10 2002 RESPONSE:
Server: Microsoft-IIS/5.0
Date: Thu, 31 Jan 2002 17:18:37 GMT
Content-Type: text/xml
Content-Length: 524
Content:
<?xml version="1.0" encoding='UTF-8'?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/1999/XMLSchema" 
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<NS1:CurseResponse xmlns:NS1="urn:HaddockIntf-IHaddock" 
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<NS1:return xsi:type="xsd:string">Sea-lice!</NS1:return>
</NS1:CurseResponse>
</SOAP-ENV:Body></SOAP-ENV:Envelope>
What captain Haddock had to say: "Sea-lice!"

サーバーはお役に立ちますか?

ZSI サーバーの設定は、実に簡単です。リスト 3 は、前回のコラムで SOAP.py 用の例として使用した、単純なカレンダーの SOAP サーバーを表しています。(参考文献を参照してください。)

リスト 3: ZSI カレンダーの SOAP サーバー
#!/usr/bin/env python
import sys, calendar
#Import the ZSI machinery
from ZSI import dispatch
def getMonth(year, month):
  return calendar.month(year, month)
def getYear(year):
  return calendar.calendar(year)
print "Starting server..."
dispatch.AsServer(port=8080)

この方法は、SOAP.py の場合よりもさらに簡単です。それぞれのメソッドごとに関数を定義するだけでよいのです。必須パラメーターとともに用いると、変数およびキーワード引数も、定位置パラメーターおよび名前付きパラメーターとして使用することができます。dispatch.AsServer() 呼び出しは、定義済みのすべての関数を SOAP メソッドとして登録し、指定されたポートで HTTP サーバーを開始します。

問題となることが 1 つあります。ZSI のサーバー・コードは、SOAP リクエストの中で使用されるネームスペースを簡単に調べる方法を備えていないようなのです。ドキュメントによると、リクエストエレメントで使用されていたネームスペースを戻す関数 dispatch.GetNS() があるというのですが、この場合には使えそうにありません。リクエストで使用されるネームスペースは、そのリクエストのきわめて重要な部分ですので、これは、かなり重大な手抜かりです。

次の ZSI クライアント・コードは、私たちが作ったカレンダーを表示します。

リスト 4: ZSI カレンダーの SOAP クライアント
#http://xmethods.net/detail.html?id=175
import sys
#Import the ZSI client
from ZSI.client import Binding
u = ''
n = 'http://uche.ogbuji.net/eg/ws/simple-cal'
b = Binding(url=u, ns=n, host='localhost', port=8080)
result = b.getMonth(2002, 2)
print result[0]
result = b.getYear(2002)
print result[0]

これをテストするには、いずれかのコンソールで "$ python calendar-zsi.py" を使用してサーバーを立ち上げるだけで済みます。

$ python2.1 cal-client.py 
February 2002
Mo Tu We Th Fr Sa Su
           1   2   3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28
2002
       January                  February                    March
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
    1  2  3  4  5  6                   1  2  3                   1  2  3
 7  8  9 10 11 12 13       4  5  6  7  8  9 10       4  5  6  7  8  9 10
14 15 16 17 18 19 20      11 12 13 14 15 16 17      11 12 13 14 15 16 17
21 22 23 24 25 26 27      18 19 20 21 22 23 24      18 19 20 21 22 23 24
28 29 30 31               25 26 27 28               25 26 27 28 29 30 31
        April                      May                      June
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
 1  2  3  4  5  6  7             1  2  3  4  5                      1  2
 8  9 10 11 12 13 14       6  7  8  9 10 11 12       3  4  5  6  7  8  9
15 16 17 18 19 20 21      13 14 15 16 17 18 19      10 11 12 13 14 15 16
22 23 24 25 26 27 28      20 21 22 23 24 25 26      17 18 19 20 21 22 23
29 30                     27 28 29 30 31            24 25 26 27 28 29 30
        July                     August                   September
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
 1  2  3  4  5  6  7                1  2  3  4                         1
 8  9 10 11 12 13 14       5  6  7  8  9 10 11       2  3  4  5  6  7  8
15 16 17 18 19 20 21      12 13 14 15 16 17 18       9 10 11 12 13 14 15
22 23 24 25 26 27 28      19 20 21 22 23 24 25      16 17 18 19 20 21 22
29 30 31                  26 27 28 29 30 31         23 24 25 26 27 28 29
                                                    30
       October                  November                  December
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
    1  2  3  4  5  6                   1  2  3                         1
 7  8  9 10 11 12 13       4  5  6  7  8  9 10       2  3  4  5  6  7  8
14 15 16 17 18 19 20      11 12 13 14 15 16 17       9 10 11 12 13 14 15
21 22 23 24 25 26 27      18 19 20 21 22 23 24      16 17 18 19 20 21 22
28 29 30 31               25 26 27 28 29 30         23 24 25 26 27 28 29
                                                    30 31

結論

前回のコラムでは完全に無視してしまいましたが、ZSI は、Python 用の SOAP ライブラリーとして、最も練り上げられていて、実用に向いているようです。作成者は、まもなくバージョン 1.2 を公開できると期待しています。このバージョンでは、この記事で私たちが訴えた不満のいくつかに対処しています。

Python SOAP パッケージを概観し、そのうちの 2 つを詳しく検討しましたので、次回は、Python SOAP 実装同士の相互運用性を検討してみる予定です。

参考文献

コメント

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=241878
ArticleTitle=Python Web サービス開発者: 第 6 回: Python SOAP ライブラリー 第 2 回
publish-date=022002