 | レベル: 中級 Heshan T. Suriyaarachchi, Undergraduate, University of Colombo
2009年 10月 06日 オープンソースの SOA ソリューションを提供している企業である WSO2 が提供する WSF/Jython (Web Services Framework for Jython) を使用すると、Jython で簡単に Web サービスを作成し、利用できるようになります。このフレームワークは Apache Axis2 Web サービス・エンジンを Jython と統合しており、Jython ユーザーは Axis2 エンジンの強力さと多彩な機能のすべてを利用することができます。このため、Jython ユーザーは数行のコードを作成するだけで、Web サービスを使用する SOA (Service-Oriented Architecture) のメリットを活用することができます。この WSF/Jython フレームワークを利用して作成された Web サービス・クライアントは、WS-Security を必要とするエンタープライズ Web サービスを呼び出すことができます。さらに WSF/Jython では、バイナリーの添付を MTOM として送信することもできます。
SOA (Service-Oriented Architecture) は、疎結合で実装技術に依存しないコラボレーション・サービスを作成するためのアーキテクチャー・スタイルです。SOA の概念は、はるか以前の分散型のモジュール・プログラミングの概念が進化したものです。SOA によって表現されるモデルでは、サービスと呼ばれる個別の単位に機能が分解されます。この場合のサービスは、コンテンツに対して処理ロジックを提供する自動処理アクションと考えることができます。SOA の基本的なビルディング・ブロックはサービスです。Web サービスは標準的なプロトコルを使用して SOA を実行する実装手法です。Web サービスでは、断片化されているミドルウェアの領域を再結合することが意図されているため、相互運用性が最優先されます。クラウド・コンピューティングが急成長する中、業界の向かう方向は、SaaS (Software as a Service)、HaaS (Hardware as a Service)、PaaS (Platform as a Service) の上に構築される、コンポーネント化されたソフトウェア・エコシステムにあるようです。従って、SOA の基本的なビルディング・ブロックを理解し、クラウド・コンピューティングの概念を把握することが非常に重要です。
この記事を読むためには Apache Axis2 の基本を理解している必要があります。Apache Axis2 の基本を理解していると、この記事で説明するソリューションのアーキテクチャーを理解する上で役に立ちます。また、Jython による Web サービスを公開して使用する上で、Axis2 についての予備知識があると役に立ちますが、WSF/Jython を使用することができれば、サービスを公開して使用することはできます。
WSF/Jython のアーキテクチャー
Apache Axis2 は SOAP 処理エンジンです。Apache Axis2 は受信される SOAP メッセージを読み取ることで、情報を取得します。この情報は Web サービスのビジネス・ロジックに渡されます。その後、ビジネス・ロジックから得られた結果から SOAP メッセージが生成され、クライアントに返送されます。しかし、ビジネス・ロジックが Jython で作成されている場合には問題が発生します。
Axis2 で Jython による Web サービスを公開するという要件を実現するためのカギは、Axis2 のプラガブルなデプロイヤーを利用することにあります。デプロイヤーを利用することで、Axis2 の動的な性質を利用してサービスをデプロイすることができます。Jython で作成されたサービスを公開するためには、Jython によるメッセージ・レシーバー (Jython Message Receiver) と共にカスタムのデプロイヤーを作成します。Python のデータ型は動的であり、XML スキーマでの静的なデータ型とは異なります。そのため、デプロイヤーの中で Python のデータ型と XML スキーマのデータ型との間でのマッピングをする必要があります。このプロセスはデータ・バインディングとして知られています。このプロセスの後、データ・バインディングとメソッドのアノテーションを利用して、Jython サービスに対する XML スキーマが生成されます。この XML スキーマは、Axis サービスに関するメタデータと共に Axis 2 エンジンに渡されます。すると Axis 2 エンジンは WSDL (Web Service Description Language) を作成し、Jython サービスが Web サービスとして公開されます。
この特定のソリューションでは、Jython スクリプトと Java™ クラスが通信する必要がありますが、そのために、Python プログラミング言語を Java で実装した Jython が使用されます。Jython は混成型のプログラミング言語であり、両方の親 (つまり Java と Python) の強みが活かされています。Jython は完全に Java で作成されているため、Jython を使用して作成されたスクリプトは、JVM (Java Virtual Machine) の仕様に準拠する任意の JVM 上で実行されます。また Jython インタープリターは、既存の Java ライブラリーを使用できるショートカットも数多くサポートしています。
このアーキテクチャーでは、SOAP プロセッサーは SOAP メッセージの送信と受信という 2 つの基本的なアクションを実行する必要があります。この 2 つの基本的なアクションを実行するために、このアーキテクチャーには 2 つのパイプ (あるいはフローとも言います) が用意されています。この 2 つのパイプを使用してデータの送受信を行いますが、Axis エンジンが実装しているこの 2 つのパイプには In Pipe と Out Pipe という名前がつけられています。複雑な MEP (Message Exchange Pattern) は、この 2 つのパイプを組み合わせて作成されます。
図 1. WSF/Jython のアーキテクチャー
SOAP 処理モデルの拡張には、ハンドラーが使われます。SOAP メッセージの処理が行われているときには、登録されているハンドラーが実行されることになります。これらのハンドラーはグローバルに登録することも、サービスのスコープで登録することも、操作のスコープで登録することもできます。最終的なハンドラー・チェーンは、すべてのスコープのハンドラーの中から組み合わせることで構成されます。
ハンドラーはインターセプターとして動作します。インターセプターは SOAP メッセージの一部を処理し、アドオン・サービスを提供します。通常、ハンドラーは SOAP ヘッダーを処理しますが、SOAP ボディーにアクセスしたり SOAP ボディーを変更したりする場合もあります。
SOAP メッセージがクライアント API をとおして送信されると、Out Pipe が有効になります。Out Pipe はハンドラー群を呼び出した後、Transport Sender を呼び出して終了します。Transport Sender は SOAP メッセージをターゲット・エンドポイントに送信します。SOAP メッセージはターゲット・エンドポイントで Transport Receiver によって受信され、ターゲット・エンドポイントは SOAP メッセージを読み取って In Pipe を起動します。In Pipe はハンドラーで構成され、Jython Message Receiver を呼び出して終了します。Message Receiver は SOAP メッセージを読み取り、アプリケーションに渡します。
要するに、受信される SOAP メッセージは Transport Listener に受信され、ハンドラー・チェーンに渡されます。次に、その SOAP メッセージは Jython Message Receiver に渡され、Jython Message Receiver は AXIOM (AXIs Object Model) 構造をトラバースして必要な情報を取得します。AXIOM は Apache Axis2 のために開発された XML infoset モデルです。この取得された情報は Jython サービスに渡され、この Jython サービスによって、返されたオブジェクトから AXIOM が作成されます。次に、ハンドラー・チェーンと Transport Sender を使用して AXIOM が返送され、Transport Sender はその SOAP メッセージを送信先の SOAP エンドポイントに送信します。上記のプロセスは、交換されるすべての SOAP メッセージで実行されます。
WSF/Jython の特徴
以下は WSF/Jython の特徴をサーバー・サイドとクライアント・サイドの観点で見た一覧です。
サーバー・サイドの特徴
- Jython で作成されたサービスを公開することができます。
- 単純なアノテーション・メカニズムを使用して DataBinding をサポートすることができます。
- WSDL を自動的に生成することができます。
- Axis 2 のすべてのエンタープライズ機能を、Jython で作成されたサービスに公開することができます。
クライアント・サイドの特徴
- 単純で簡潔な方法で Web サービスを呼び出すことができます。
- サービスを呼び出す場合に WS-Addressing を使用することができます。
- WS-Security を必要とするサービスを呼び出すことができます。
- MTOM を使用してバイナリーの添付を送信することができます。
Jython サービスを作成する
ではここで、deduct という名前の簡単な演算を行う簡単な Jython スクリプトを作成しましょう。このスクリプトは 2 つの入力変数を引数に取り、この 2 つの数字の差を返します。XML スキーマを生成する必要があるため、この Jython スクリプトにはアノテーションを追加する必要があります。下記はアノテーションを追加した Jython メソッドの例です。
リスト 1. 簡単なサービス
#@annotate("returns=int", "operationName=deduct", var1="integer", var2="integer")
def deduct(var1,var2):
var3 = var1 - var2
return var3
|
Jython スクリプトにアノテーションを追加するためには、以下の指示に従います。
- アノテーションは
#@annotate で開始します。
- 各属性を二重引用符で囲む必要があります。
return 属性は、このメソッドの戻り型と同じである必要があります。
operationName 属性は、このメソッドの演算名と同じである必要があります。
- 各入力パラメーターは、変数名と値を持つ必要があります。
- 各パラメーターは一意の参照名を持つ必要があります。
リスト 2. アノテーション
#@annotate("returns=int", "operationName=deduct", var1="integer", var2="integer")
|
使用に関する制限
Jython スクリプトをデプロイする際には、以下のガイドラインに従う必要があります。
- スクリプトにアノテーションを追加する場合には、必ず上記の指示に従う必要があります。
- パラメーターの名前 (参照変数) は一意でなければなりません。
- 戻り型がない場合には、戻り型を
hashNone と指定する必要があります。
- axis.xml に以下の行 (リスト 3) を追加する必要があります。
リスト 3. axis.xml に追加するための行
<deployer extension=".py" directory="scripts"
class="org.wso2.wsf.jython.deployer.JythonDeployer">
</deployer>
|
簡単なサービス
アノテーションに関する上記の説明に従うと、簡単な Jython サービスを作成することができ (リスト 4)、作成した Jython サービスを、Jython デプロイヤーを利用して Web サービスとして公開することができます。
リスト 4. サービスの例
#@annotate("returns=double", "operationName=f", a="double")
def f(a):
return a
#@annotate("returns=int", "operationName=add", var1="integer", var2="integer")
def add(var1,var2):
return var1+var2
#@annotate("returns=double", "operationName=deduct", var1="double", var2="double")
def deduct(var1,var2):
return var1-var2
#@annotate("returns=int", "operationName=addTwo", var1="integer", var2="integer",
var3=(a="string", b="integer"))
def addTwo(var1,var2,var3):
return var1+var2
#@annotate("returns=int", "operationName=doComplexStuff", var1="integer",
var2="(a="integer", b="integer")", var3="(a="string", b="integer")")
def doComplexStuff(var1,var2,var3):
return var1
class MyClass:
#@annotate("returns=integer", "operationName=MyClass.multiply", var1="integer",
var2="integer")
def multiply(var1,var2):
return var1*var2
|
Jython Web サービス・クライアントを作成する
ここまでは、Jython で Web サービスを作成する方法を説明しました。今度は、サービスを利用する Jython Web サービス・クライアントを作成する方法を調べてみましょう。このクライアントは、ペイロードを準備し、サービスに対してリクエストを送信し、レスポンスを受信して処理する必要があります。Jython Web サービス・クライアントを実装する際には以下のステップに従います。
- 必要なリクエスト・ペイロードとオプションを設定します。必要なペイロードはプレーン・テキスト形式で設定することも、WSMessage として設定することもできます。
- WSClient インスタンスを作成します。WSClient インスタンスはサービスを利用するために使用します。次にコンストラクターの引数としてオプションを設定します。
- リクエストを送信し、レスポンスを受信します。request() メソッドを呼び出し、メッセージをパラメーターとして渡します。このメソッドは、レスポンス・メッセージを表現する WSMessage インスタンスを返します。
- レスポンスを読み取ります。そのレスポンスを、クライアントのビジネス・ロジックに従って処理します。
リスト 5. リクエスト・メッセージを準備する
req_message = WSMessage(req_payload_string, {"to" :END_POINT})
|
上記のコード・フラグメントでは、リクエストに入れて送信されるペイロードとサービス・エンドポイントを付けて WSMessage インスタンスが作成されています。オプションであるハッシュの “to” 要素は、このサービスのアドレスに置き換えられます。つまり “to” で指定されるアドレスは、このリクエストの送信先を示します。
リスト 6. リクエストを送信し、レスポンスを受信する
client = WSClient({}, LOG_FILE_NAME)
res_message = client.request(req_message)
|
先ほど作成した入力メッセージを持つリクエストを送信するためには、WSClient インスタンスが必要です。サービスに対して送信すべきメッセージを、request() メソッドに渡すと、指定のメッセージに含まれるペイロードが送信されます。レスポンスが受信されると、レスポンス・ペイロードを持つメッセージ・インスタンスが返されます。
WSF/Jython API を使用して Web サービスを利用するために最低限必要なものは、ペイロードと、サービス・エンドポイントの URI です。これらを使用して Web サービスを利用する方法については、上のセクションで説明しました。WSF/Jython 拡張機能を使用するメリットは、単なる SOAP 以上のものがサポートされることであり、Web サービスを利用する際に、WS-Addressing と MTOM、そして WS-Security を使用することができます。また REST スタイルの呼び出しを使用してサービスを呼び出すこともできます。これらのオプションと WSMessage および WSClient との関係を以下に説明します。
SOAP を使用する
クライアント・レベルで “use_soap” オプションを使用すると、どの SOAP バージョンを使用するか指定することができます。
リスト 7. SOAP を使用する
client = WSClient({"use_soap" : "true"}, LOG_FILE_NAME)
|
REST を使用する
Web サービスで REST スタイルの呼び出しを使用するためには、”use_soap” オプションを “false” に設定します。REST スタイルで呼び出す場合には、HTTP POST メソッドまたは HTTP GET メソッドを使用します。
リスト 8. REST を使用する
# REST with HTTP POST
client = WSClient({ "to" : END_POINT,
"http_method" : "POST",
"use_soap" : "false"},
LOG_FILE_NAME)
# REST with HTTP GET
client = WSClient({ "to" : END_POINT,
"http_method" : "GET",
"use_soap" : "false"},
LOG_FILE_NAME)
|
MTOM を使用した添付
リスト 9. MTOM を使用した添付
req_message = WSMessage(req_payload_string, {"to" :END_POINT,
"attachments" : {"myid1" : "first attachment",
"myid2" : "second attachment"}})
|
添付を送信する場合には、クライアントの構成方法により、添付を最適化フォーマットで送信するのか非最適化フォーマットで送信するのかが決まります。バイナリーの最適化フォーマットで送信する場合には、SOAP ボディーからのファイルの内容がそのまま MIME ヘッダーを使用して送信され、ペイロードには XOP:Include 要素が含まれることになります (XOP:Include 要素はバイナリー添付を含む MIME 部分を指定します)。バイナリーの非最適化フォーマットで送信する場合には、添付の内容はペイロード自体の中に入れられ、base64 でエンコードされたストリングとして送信されます。
リスト 10. クライアントを最適化フォーマットまたは非最適化フォーマットに構成する
# send attachments binary optimized
client = WSClient({"use_mtom" : "true"})
# send attachments binary non-optimized
client = WSClient({"use_mtom" : "false"})
|
WS-Addressing を使用する
WSF/Jython によるクライアント・サイドで WS-Addressing を使用する場合の基本的な要求事項として、2 つの内容を指定しなければなりません。第 1 に、メッセージ・レベルで WS-Addressing アクションを指定する必要があります。第 2 に、クライアント・レベルで WS-Addressing を使用するための指定をする必要があります。
リスト 11. WS-Addressing
req_message = WSMessage(req_payload_string,
{"to" : "http://localhost/echo_service_addr/echo",
"action" : "http://jython.wsf.wso2.org/samples/echoString"})
client = WSClient({"use_wsa" : "true"})
|
上記のサンプル・コード・フラグメントでは、WSMessage コンストラクターに渡されるオプションのディクショナリーの “action” 要素を使用して WS-Addressing のアクションを設定しています。また、WSClient コンストラクターに渡される “use_wsa” オプションを使用して WS-Addressing を有効にしています。
アクションの他に、WS-Addressing に関連する他の SOAP ヘッダーもメッセージの中に入れて送信されます。WSF/Jython はこれらのヘッダーを、メッセージ・レベルのプロパティーとして、あるいはクライアント・レベルのオプションとしてサポートしています。下記はその一例です。
リスト 12. メッセージ・レベルのプロパティー、またはクライアント・レベルのオプション
req_message = WSMessage(req_payload_string,
{"to" : "http://www.company.com/order_processing/process",
"action" : "http://jython.wsf.wso2.org/samples/order",
"from" : "http://www.company.com/order_placing/place",
"reply_to" : "http://www.company.com/billing/bill",
"fault_to" : "http://www.company.com/re_odering/order"})
client = WSClient({"use_wsa" : "true"})
|
WS-Security を使用する
セキュリティー・クライアントまたはセキュリティー・サービス実行するためには、WS-Addressing を使用する必要があります。その上でポリシー・オブジェクトを使用してクライアントを作成する必要があることに注意してください。
リスト 13. WS-Security
req_message = WSMessage(req_payload_string,
{"to" : "http://localhost/samples/security_service/callback",
"action" : "http://jython.axis2.org/samples/echoString"})
client = WSClient({"use_wsa" : "true",
"policy" : "Policy_Path"})
res_message = client.request(req_message)
|
サンプルを実行する
クラスパスに Jython の jar と必要な axis2 の jar を追加して環境を設定します。次に WSF/Jython の jar をクラスパスに追加します。適切に環境を設定できると、WSF/Jython API 仕様に準拠する Jython スクリプトを実行できるはずです。WSF/Jython には、この環境設定をしてくれるシェル・スクリプトが同梱されています。それを利用すると、単純にクライアント・スクリプトの絶対パスを指定するだけでクライアント・スクリプトを実行することができます。以下の 3 つのリストはその一例です。
リスト 14. サンプルを実行するためのコマンド
sh wsfjython.sh /home/heshan/wsf-jython/jython/
distribution/target/wsf-jython-SNAPSHOT-bin/samples/amazon.py
|
リスト 15. Amazon Web サービスのクライアント
from org.wso2.wsf.jython.client import WSClient
from org.wso2.wsf.jython.client import WSFault
from org.wso2.wsf.jython.client import WSMessage
req_payload_string = "<ItemSearch><Service>AWSECommerceService</Service>
<SearchIndex>Books</SearchIndex>
<AWSAccessKeyId>XXXXXXXXXXXXXXXXXXX</AWSAccessKeyId>
<Operation>ItemSearch</Operation>
<Keywords>sri lanka travel books</Keywords></ItemSearch>"
LOG_FILE_NAME = "/home/heshan/IdeaProjects/MRclient/src/python_amazon.log"
END_POINT = "http://webservices.amazon.com/onca/xml"
try:
client = WSClient({ "http_method" : "GET",
"use_soap" : "false"},
LOG_FILE_NAME)
req_message = WSMessage(req_payload_string, {"to" :END_POINT})
print " Sending OM : " , req_payload_string
res_message = client.request(req_message)
print " Response Message: " , res_message
except WSFault, e:
e.printStackTrace();
|
リスト 16. レスポンス
<ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05">
<OperationRequest>
<HTTPHeaders><Header Name="UserAgent" Value="Axis2" /></HTTPHeaders>
<RequestId>114HR356NB5H18RR5WNM</RequestId>
<Arguments><Argument Name="SearchIndex" Value="Books" />
<Argument Name="Service" Value="AWSECommerceService" />
<Argument Name="Keywords" Value="sri lanka travel books" />
<Argument Name="Operation" Value="ItemSearch" />
<Argument Name="AWSAccessKeyId" Value="XXXXXXXXXXXXXXXXXXX" />
</Arguments><Errors><Error>
<Code>AWS.InvalidParameterValue</Code>
<Message>XXXXXXXXXXXXXXXXXXX is not a valid value for AWSAccessKeyId.
Please change this value and retry your request.</Message>
</Error></Errors>
</OperationRequest>
</ItemSearchResponse>
|
まとめ
このフレームワーク (WSF/Jython) は Apache Axis2 エンジンと Jython とを統合しているため、Apache Axis2 の Web サービス・ミドルウェア・エンジンの強力さと多機能性を Jython で活用することができます。このフレームワークは「コード・ファースト」手法をサポートしているため、数行のコードを作成するだけで、たいした作業をせずにクライアントとサービスを動作させることができます。このフレームワーク自体は Apache Axis2 に統合されているため、Axis2 がサポートする広範な機能を使用することができます。サポートされている機能には、MTOM による添付、SOAP、REST、そして WS-Addressing や WS-Security などの WS-* 標準があります。さらに、このフレームワークはオープンソースのディストリビューションであるため、ライセンス料や利用料を払う必要はありません。必要な機能がこのフレームワークの中に見つからない場合には、メーリング・リストからその機能を要求することもできますし、あるいは皆さん自身が変更を試み、その成果でコミュニティーに貢献することもできます。
参考文献 学ぶために
製品や技術を入手するために
- IBM 製品の試用版をダウンロードし、DB2® や Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品をお試しください。
著者について  | 
|  | Heshan は University of Colombo School of Computing (UCSC) のコンピューター・サイエンス専攻の学部学生として最終学年に在籍しています。彼の関心領域は、Web サービス、SOA、分散コンピューティング、そして暗号技術です。彼は WSO2 Inc. でインターンとして働く中で WSO2 Web Services Framework for Jython を開発しました。 |
記事の評価
|  |