Articles
第4回:BPELにおける同期/非同期の概念 (1)
前回は、BPELの概要をご紹介し、1つのWebサービスを呼び出すだけのシンプルなビジネス・プロセスを、BPELを使って定義しました。
今回から2回にわたって、BPELを理解する上で重要な概念の1つである同期型/非同期型の考え方のポイントをご紹介していきましょう。 前回説明を割愛したパートナ・リンクについても取り上げていきます。
前回作成したBPELプロセスは、BPELプロセス自体のWSDLを持っていましたね。 これは、BPELプロセス自体が1つのWebサービスになる、ということを表しています。 また、 前回行ったようにBPELプロセスから外部のWebサービスを呼び出すこともできます。
この2つの事実を考え合わせると、BPELプロセスがBPELプロセスを呼び出すことが可能なことが分かりますね。 つまり、より粒度の細かいサービスを組み合わせることで、より粒度の粗いサービス(コンポジット・アプリケーション)を構築できるのです。 まるで、開けても開けてもより小さな人形が入っている、ロシア人形マトリョーシカのようですね。 とはいえ、サービスの粒度の細かくし過ぎる(たとえば、Javaの各クラスの持つメソッドをすべてWebサービス化する)のは、あまりお薦めできません。 最低でも、何かしらの「サービス」を意味する粒度にしておくのがいいでしょう。WebサービスやSOA(サービス指向アーキテクチャ)では、 「分散オブジェクト」ではなく「サービス」という言葉が敢えて選択されているのも、こういった考えが根底にあるように思います。 ちなみに、Oracle BPEL Process Managerでは、WSIF(Web Services Invocation Framework)というテクノロジを活用することで、 Webサービス以外の各種リソース、たとえば、ローカルJavaクラス、EJB、JMS、J2CA(Java 2 Connector Architecture)などを あたかもWebサービスかのように扱うことができます。上の図で「(Web)サービス」と表記しているのは、Webサービス以外の「サービス」も 利用できることを意味しています。 これにより、統合したいものをすべてWebサービス化しなくても、BPELプロセスを用いて統合していくことが容易になりますね。 SOA(サービス指向アーキテクチャ)がWSOA(Webサービス指向アーキテクチャ)という名前ではないのは、このような背景があるのです。
さて、 前回説明を割愛した概念の1つに、パートナ・リンクというものがありましたね。 パートナ・リンクとは、パートナとのリンクを表します……といっても何のことやら意味不明ですね。 パートナとは、BPELプロセスから見た、インタラクションをする相手のことです。たとえば、BPELプロセスから呼び出す外部のサービス、 あるいはBPELプロセスを呼び出す外部のクライアントがパートナです。
WSDLでは、(抽象的な)WSDLポート・タイプに対して、パートナ・リンク・タイプとロールが割り当てられます。 これは、WSDLの拡張要素です。一方、BPELでは、特定のパートナ・リンク・タイプを指定して、パートナ・リンクが定義されます。 定義方法やその意味は、具体例を見た方が分かりやすいので、後ほどサンプルとともに再び取り上げることにしましょう。
ここでは、BPELにおいて同期型サービスがどのように表現されるかをご紹介します。 次の図の右側は同期型のBPELプロセス、左側は同期型サービスを呼び出すBPELプロセスを示しています。
右側の同期型BPELプロセスでは、 <receive>アクティビティでクライアントからのリクエストを受け取り、 必要に応じて何らかのアクティビティを実行した後、 <receive>アクティビティでクライアントへのレスポンスを返します。 この図では、同期型BPELプロセスのクライアントがBPELプロセスになっていますが、必ずしもそうである必要はありません。 たとえば、JAX-RPCや.NETで実装したWebサービス・クライアントでも構わないのです。 一方、左側の同期型サービスを呼び出すBPELプロセスは、同期型サービスから見ればクライアントとなります。 この図では、BPELプロセスが呼び出す同期型サービスが別のBPELプロセスになっていますが、必ずしもそうである必要はなく、 任意のWebサービスでも構いません。BPELプロセスで同期型サービスを呼び出すには、 <invoke>アクティビティを使います。 同期型はリクエスト/レスポンス・スタイルであり、リクエスト送信後はレスポンスを受信するまでブロックされ、 次のアクティビティに進めないことに注意しましょう。 同期型BPELプロセスのクライアントがブロックされることを考えれば、同期型BPELプロセスでは、 <receive>アクティビティと <receive>アクティビティとの間(つまりリクエストとレスポンスとの間)に、 長時間にわたるアクティビティを実行すべきではありません。 長時間にわたる可能性があるアクティビティを実行したい場合は、次に紹介する非同期型のBPELプロセスとして実装する方が適切です。 ここまでの説明を踏まえて、 前回作成した為替計算プロセスを見直してみましょう。 最初の <receive>アクティビティと最後の <reply>アクティビティを見れば、 為替計算プロセス自体が同期型であることが分かりますね。 また、 <invoke>アクティビティで、同期型のCurrency Exchange Rateサービスを呼び出していることも分かるでしょう。
続いて、BPELにおいて非同期型サービスがどのように表現されるかについても見てみましょう。次の図の右側は非同期型のBPELプロセス、左側は非同期型サービスを呼び出すBPELプロセスを示しています。同期型の場合と同様、BPELプロセスが相互作用する相手は必ずしもBPELプロセスである必要はありません。
右側の非同期型BPELプロセスでは、 <receive>アクティビティでクライアントからのリクエストを受け取ります。 これは同期型の場合と同様ですが、同期型のレスポンスを返す <reply>アクティビティは登場しません。 代わりに、クライアントへのコールバックを表す <invoke>アクティビティを使います。 同期型では1対のリクエスト/レスポンス・メッセージで相互作用していたのですが、 非同期型では2つの別個の一方向メッセージによって相互作用する、ということです。 一方、左側の非同期型サービスを呼び出すBPELプロセスでは、 <invoke>アクティビティを使ってサービスを 呼び出しています。これは、同期型サービスを呼び出す場合と同様です。 ただし、非同期型サービスを呼び出す <invoke>アクティビティでは、レスポンスを待ってブロックされることはなく、 即座に次のアクティビティに進むことができます。呼び出した非同期型サービスからの結果を受け取るには、 <receive>アクティビティを使います。これは、非同期型サービスからのコールバックを受け取ることを意味します。 先に述べた通り、長時間にわたる可能性があるアクティビティを実行したい場合は、非同期型のBPELプロセスとして実装する方が適切です。 数分、数時間あるいは数日にわたるアクティビティを配置したい場合には、非同期型BPELプロセスの(クライアントからの) <receive>アクティビティと(クライアントへのコールバックである) <invoke>アクティビティとの間に 配置するといいでしょう。 長時間にわたる可能性があるアクティビティとしては、(上司の承認のような)人間が介在するヒューマン・ワークフローを BPELプロセスに組み込む場合が考えられます。 余談ですが、BPEL仕様自体はサービス/システム間の連携を想定しており、ヒューマン・ワークフローに対する特別な機能は存在しません。 一方、Oracle BPEL Process Managerはヒューマン・ワークフローもサポートしており、サービス/システム間連携と ヒューマン・ワークフローを容易に統合することができます。 しかも、ワークフロー機能自体をWebサービスとして提供しているため、BPELを独自拡張することなしにワークフローもサポートするという 賢い作りになっている点も見逃せません。
さて、今回はサンプルとして単純な旅行予約プロセスを作っていきます。(個人の国内出張を想定した)この旅行予約プロセスは、 出発する空港、到着する空港、出発日、到着日を受け取り、往復の飛行機チケットとホテルの部屋を予約します。 その際、旅行予約プロセスは、Webサービスとして実装されている飛行機予約サービスとホテル予約サービスを呼び出す、という シナリオにします。飛行機予約サービスは同期型BPELプロセス、ホテル予約サービスは非同期型BPELプロセスとして実装してみましょう。
サンプルの開発と実行には、BPELプロセスの実行環境Oracle BPEL Process Managerと、BPELプロセスの ビジュアル開発環境Oracle BPEL Designerを使います。本稿では、本稿執筆時点での最新版である Oracle BPEL Process Manager 2.1.2を使用します。OTNより無償でダウンロードできるので、是非お試しください。
Oracle BPEL Process ManagerとOracle BPEL Designerのインストール方法や詳しい使い方については、次のページにあるチュートリアルなどを参照してください。
まずは、同期型BPELプロセスである飛行機予約サービスを作ってみましょう。 Oracle BPEL Designerを起動し、 Oracle BPEL Projectを新規作成します。BPELプロセス名に FlightService、 名前空間に http://otn.oracle.co.jp/columns/j2ee_webservices/flightを設定し、 テンプレートとして Sync BPEL Process (同期型BPELプロセス)を選択します。
すると、プロジェクトには次の5つのファイルが生成されるはずです。
このうち特に重要なのは、BPELプロセスの実際の定義が含まれているBPELファイルと、 BPELプロセス自体のWebサービス・インタフェースを定義するWSDLファイルです。
Oracle BPEL Designerは、BPELプロセスをグラフィカルに表現したビジュアル・エディタとしてのビューである BPEL Designer - Overview、BPEL Designer - Process Map、BPELファイルのソースを表示する テキスト・エディタのビューである BPEL Sourceという3つの方法でBPELファイルを編集できます。 実際には、ほとんどの場合ビジュアル・エディタで事足りるので、BPELファイルのソースを直接編集する機会は少ないでしょう、 とはいえ、ビジュアル・エディタで編集するにせよ、ある程度はBPELの概念を理解し、BPELのソースを読める必要があるので、 本稿ではBPELのソースも適宜取り上げつつ進めていきます。 まず、WSDLファイル FlightService.wsdlを見てみましょう。自動生成された FlightService.wsdlには、 次のようなXML Schema定義が含まれているはずです(コメントなどを削除し、インデントを修正しています)。 これを見ると分かるように、デフォルトで生成されるBPELプロセスは、入出力のどちらも string型の要素を1つだけ持つ XMLドキュメントとなります。
今回作成したい飛行機予約サービスでは、より多くの情報を必要とするので、XML Schemaを書き換える必要があります。 WSDLの <types>要素内で、インラインでXML Schemaを書き換えてもいいのですが、今回は別途XML Schemaファイルを作成し、 WSDLでそれをインポートすることにしましょう。 XML Schemaファイルはマニュアルで作成してももちろん構わないのですが、Oracle JDeveloper 10gの XML Schemaビジュアル・エディタを活用すれば、コンポーネントをドラッグ&ドロップして、簡単にXML Schemaを 作成することができます。 上の図では、J2EE 1.4やJSFをサポートしたJDeveloper の最新版Oracle JDeveloper 10g 10.1.3 Developer Previewを用いて、 XML Schemaを作成しています。
作成したXML Schemaファイル flight.xsdの内容は、次の通りです。
ここでは、往復チケットの予約リクエストを表す <roundTripFlightRequest>要素と、 予約結果を表す <roundTripFlight>要素を定義していますね。これらの要素の名前空間は、 http://otn.oracle.co.jp/columns/j2ee_webservices/flight/typesとしています。 XML Schemaファイル flight.xsdを FlightService.wsdlと同じディレクトリにコピーし、 自動生成されている FlightService.wsdlの内容を、次のように書き換えます。
<types>要素の中に定義されているXML Schema定義を削除し、代わりに <import>要素で XML Schemaファイル flight.xsdをインポートします。また、 <part>要素の element属性で指定する要素名も、 flight.xsdで定義した要素名にします。 flight.xsdのターゲット名前空間を接頭辞 typesの 名前空間として指定していることに注意しましょう。 WSDLのポート・タイプも確認しておきましょう。 <input>要素と <output>要素、つまりリクエスト/レスポンス・スタイルの同期型のオペレーション processが定義されていますね。WSDLの意味が分からない場合は、 本連載の 第1回、 第2回 をご覧ください。 <plnk:partnerLinkType>要素は、WSDLの拡張要素として定義されたBPELのパートナ・リンク・タイプです。 この FlightServiceパートナ・リンク・タイプでは、 {http://otn.oracle.co.jp/columns/j2ee_webservices/flight}FlightService ポート・タイプに対して、 FlightServiceProviderロールを割り当てています。 ロールは、BPELプロセスとパートナとの間に存在する「役割」を表します。ここでは、同期型の processオペレーションを提供する FlightServiceポート・タイプが、(BPELプロセスのクライアントから見て) サービスを提供する役割を持っていることを意味しているわけです。 後ほど登場する非同期型のWSDLでは、パートナ・リンク・タイプの定義が多少異なったものになります。 さて、続いてはBPELプロセスを編集していきましょう。BPELプロセスの Overview画面は、次のようになっています。 左側にある clientのボックスは、実はパートナ・リンクを示しています。BPELファイルの冒頭には、 <partnerLinks> 要素以下に、パートナ・リンクが定義されています。ここでは、このBPELプロセスが {http://otn.oracle.co.jp/columns/j2ee_webservices/flight}FlightService パートナ・リンク・タイプで、BPELプロセス側のロール( myRole属性)が FlightServiceProviderである、 ということを示しています。後ほど登場する非同期型のBPELでは、パートナ・リンクの定義も多少異なったものになります。
次に、BPELの Process Map画面を表示し、BPELプロセス内のアクティビティを定義していきます。 BPELプロセス自体は同期型なので、 <receive>アクティビティと <reply>アクティビティは デフォルトで作成済みです。 ここでは、BPEL Paletteから、 <assign>アクティビティをドラッグし、 <receive>アクティビティと <reply>アクティビティとの間にドロップします。 <assign>アクティビティは、BPELプロセスの変数の値を代入するためのものです。 ここでは、入力変数の値や固定の値を出力変数にコピーするために使います。 <assign>アクティビティをダブル・クリックし、 Assign Grid Wizardで、次の図のように、 出力変数の各要素に対して、入力変数の値を示すXPath式(名前、空港名、日付)、固定の文字列(フライト番号、座席番号)、 固定の数値(価格)、固定の時間(出発時間、到着時間)を指定します。 XPath式の入力には右側のプルダウン・ボタンをクリックして選択できる Variable Pickerを使うのが便利でしょう。 本来であれば、飛行機予約システムやデータベースなどにアクセスして、実際に飛行機の予約処理をすべきですが、 ここではシンプルにするために、固定のフライト番号、座席番号、時間、価格で予約できたことにしてしまっているわけです。 これで、(単純ではありますが)1つのBPELプロセスが完成しました。実際のBPELの定義は次のようになります。 <variables>要素には、BPELプロセスで使う変数が定義されています。 デフォルトではBPELプロセス自体のWSDLの入出力メッセージに対応する変数が定義されます。 <sequence>要素は、その子要素をシーケンシャルに実行するという意味を持ちます。 このBPELプロセスでは、 <receive>、 <assign>、 <reply>という3つの要素が シーケンシャルに実行されるというわけです。 BPEL Desginerの Process Map画面は、これをグラフィカルに表してくれるので、直感的に理解しやすいですね。 <assign>アクティビティの中には、1対のコピー元( <from>要素)とコピー先( <to>要素)からなる <copy>要素が複数定義されていますね。これは、先ほど Assign Grid Wizardで定義したものに対応しています。
BPELプロセスが完成したら、BPELプロジェクトを検証します。エラーがなければ、BPELプロジェクトをビルドしましょう。ビルドすると、デフォルト構成ではローカル・マシンで起動しているOracle BPEL Process Managerに対して、BPELプロセスがデプロイされ実行可能となります。 BPELコンソールをオープンしログインします(デフォルトのパスワードは bpelです)。 Dashboardタブでは、デプロイ済みのBPELプロセスの一覧が表示されます。一覧の中の FlightServiceを クリックすると、BPELプロセスのテスト・ページに進みます。 BPELプロセスをテストするために、BPELプロセスのWebサービスのクライアント・プログラムを毎回作成するとなると かなり大変ですが、このテスト・ページを使えば、BPELプロセスを簡単にテストできます。 入力パラメータを送信すると、結果ページに進みます。同期型BPELプロセスの場合は、結果ページにBPELプロセスが 返すXMLドキュメントが表示されます(なお、Oracle BPEL Process Manager 2.1.2では、結果ページに表示される XMLドキュメント内の日本語文字は文字化けしてしまいます)。 Visual Flow、 Audit Instance、 Debug Instanceのリンクをクリックすると、 様々な方法で実行済み(あるいは実行中の)BPELプロセスのインスタンスの情報を参照できます。 たとえば、次の図は、 Visual Flowで <reply>アクティビティの情報を表示した様子です。 予想通りに、飛行機の往復チケットの予約結果を表すXMLドキュメントが返されていることが確認できますね。
今回は、パートナ・リンクや同期型/非同期型の考え方について説明し、同期型BPELプロセスのサンプルを作成しました。 次回は、引き続き非同期型BPELプロセスも作成し、これら2つのプロセスを呼び出すBPELプロセスも作成していくことで、BPELの概念に触れていきます。
[リファレンス]
|