BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ アーティクル Apache ODEの紹介

Apache ODEの紹介

Apache ODE (Orchestation Director Engine)(サイト・英語)は、一般的なランタイムコンテキストへの埋め込みに適しているWS-BPEL 2.0 (Web Services Business Process Execution Language)(サイト・英語)を実装することを目標としています。ODEは、最近インキュベーション段階を終えて本格的なトップレベルプロジェクトに昇格し、昇格後初のリリースもしました。この記事では、サンプルを通じてODEに振れて小旅行気分を味わってもらったり、デプロイの形式と単一プロセスの実行における BPELのコンセプトと共にODEの簡単な紹介をします。

ODEの考え方は、状態操作と外部サービスとのメッセージ交換に関するメッセージベースのコミュニケーション機能の組み合わせをどのように実行するかを記述するための言語であるBPELに基づいています。この文や前の段落以外に「business」という単語を使用するつもりはありません。また、 ITとの協調に関する話や、ODEがWebサービスやデータベースのように罪の無い(かつメッキが施されていない)技術であるといったくだらない話もするつもりはありません。どうするかは、あなた次第です。GUIやIDEもなく、ESBでもなく、それ以外の3文字(XMLも含め)の頭文字が必要となります。オーケストレーションエンジンの実装をするということは、興味をかき立てますが困難な作業となります。ODEでは、並列性、耐久性のあるコミュニケーション(デハイドレーション/リハイドレーションとも呼ばれます)、信頼性、リカバリに関する詳細部分をカプセル化しています。ODEが開発者に対しオーケストレーション機能をシステムに組み込もうとする際のベースラインとなり得ることを期待している中で、おそらく最も重要なことは、単なるフレームワークではなくコンポーネントとして利用されることなのです。

正確を期すために、BPEL(例えばBPEL4WS 1.1)の特定のバージョンを指定します。指定していないときは、「BPEL」はWS-BPEL 2.0のことを指します。

オーケストレーションvsそれ以外のもの

WS-BPEL 2.0は標準技術であるWS-*群の一部ですが、SOAPではなくWSDL 1.1だけに依存しており、良くも悪くも、他の技術とは疎結合になっています。(「より悪い」面として挙げられるのは、BPELが有効なアプリケーションドメインにおけるJBIやWSRFといった他の標準のいくつかが、WSDL 1.1ではなくWSDL 2.0に依存するということです。)それ自体は、SOAPスタック、ESB、インテグレーションエンジンなどといった製品カテゴリとBPEL実装がかぶっていたり、補完するものであったりします。つまり、エンジンの一部にWSDLを得て、エンジンに基盤(例えば、状態の永続化やタイマーイベント)を与えることが必要なのです。

ODEは、インテグレーション層の抽象化によって、非常にシンプルな構成を実現しています。ODE のコアは、外部の相手とメッセージをやりとりしたりスレッドなどのリソースへのアクセスを得るために、インテグレーション層の実装を利用しています。 ODEは、Apache AXIS2(ODEプロセスをWebサービスとして公開する)とServiceMix(ODEがJBIのサービスエンジンとして公開される)に対するインテグレーション層の実装を含んでおり、その他多くの実装に関しても活発に開発をしています。

WS-BPEL 2.0:最も新しく、素晴らしい(なおかつ唯一の)BPEL標準

現在のWS-BPEL 2.0は約6年の間で作られており、それらのうちの4つはOASISによるものです。以下に、標準の歴史に関する大まかなタイムラインとそれぞれのドキュメントに関するThe Cover Pagesへのリンク(リンク・英語)を記します。

WSFL, 2001年5月 (IBM) (リンク集・英語)
Webサービスフロー言語
XLANG, 2001年5月 (Microsoft) (リンク集・英語)
全て大文字であるにも関わらず、その名前は頭文字を取ったものではありません。 
BPEL 1.0, 2002年7月 (BEA, IBM, Microsoft) (仕様書・英語)
WSFLとXLANGが融合
BPEL4WS 1.1, 2003年3月 (BEA, IBM, Microsoft, SAP, Siebel) (リンク集・英語)
仕様書がOASISへ提出される
WS-BPEL 2.0, 2007年3月 (OASIS; 39の企業が技術委員のメンバー) (OASIS技術委員会のホームページ・英語)
標準化団体に初の標準として認定される

300以上に及ぶ説明、修正、強化(サイト・英語)が、技術委員会によって完全に(時には完全ではないかもしれませんが)検討され、解決されたので、OASISの4年間は、BPELにとって非常に良いものでした。加えて、多くの企業が実装や言語の利用のために技術委員会への表明をしてくれたことも非常に良いことでした。ポイントごとの比較として、 BPEL4WS 1.1とWS-BPEL 2.0の間はおそらく実装者への関心だけになってしまうものと思われますが、BPELプロセスを書こうとしている全ての人のために、簡単な(かつ精緻でない)一覧を以下に記します。

  • XPath 1.0の多くの操作におけるシンタックスを簡素化。WS-BPEL 2.0では、頭に$-をつけたXSLT慣習を採用しその値がWSDLのメッセージタイプである場合には、そのメッセージを$varName.partNameという形で参照します。BPEL4WS 1.1では、XPath拡張機能としてbpws:getVariableData('itemsShipped')のように使用します。
  • XSLTのインプロセスのサポート。WS-BPEL 2.0は、XPathの拡張機能である与えられた操作をXSLTに変換するためのdoXslTransform(...)があります。BPEL4WS 1.1は、インプロセスの変換を全くサポートしていないので、XSLTの操作には、専用のメカニズムかプロセス外の別のエンドポイントが必要となります。
  • 繰り返しと簡単な動的並行性。BPEL4WS 1.1は、whileの繰り返し構造と、flowによる一定数のアクティビティに対する並列構造があります。WS-BPEL 2.0では、実行時に決定した整数値の範囲で、並列若しくはシーケンシャルな繰り返しをおこなうforEachが加わっています。並列でのforEachにより、BPEL4WS 1.1では扱いにくい若しくは不可能であった動的なscatter/gatherのシナリオを直接サポートすることが可能となります。

さらにリストに追加することはできますが、この辺にしておきます。BPMNのような高度な表記によるBPELを直接マッピングしたグラフィカルな表記、モデル駆動によるXMLへの直接記述、あるいはあまり知られていないが密接に関連している非XML構文などがありますが、BPELプロセスをどのように書くかについては、評価しません。

Jacob: ODEのメッセージパッシングの仮想マシン

BPELエンジンを実装するより挑戦的な側面のうちの2つは、実行プロセスの状態を表し並列性を管理することです。ODEでは、その両方を解決するためにJava Concurrent Objects (通称、"Jacob")と呼ばれるフレームワークを使用します。Jacobのアプローチは、アクターモデルからの考えと、並列性と連続性のためのプロセス代数アプローチの実用的な組み合わせとなっています。

Jacobを通して、ODEはメッセージパッシングのチャネルによってつながっているオブジェクトの集合として、BPELプロセスの状態を表現します。この内容は、メッセージはライトウェイトな内部メッセージ(ちょうど、Javaの型のようなもの) で、エンジンによりメッセージを外部から送受信するような、よりヘビーなWSDLメッセージではありません。オブジェクトがメッセージを受け取ると、新たなチャネルとオブジェクトを生成し、メッセージを送信します。並列性に関しては、(プロセス毎のインスタンスを基本とした)シングルスレッドで処理されたメッセージにより管理されます。

ODEのWikiには、BPELプロセスに関する動機付けとメカニズムの両方をカバーしたJacobのチュートリアル(英語)があります。そして、Jacobのモジュール(source)には、様々なBPELの仕様やより多くの例(source)などが含まれています。例えば、エラトステネスのふるい(英語)の実装(source)があります。興味のある読者は、Scala(英語)によるアプローチ(英語)とJacobのアプローチを比較してみることもできます。

ODEにさわってみよう

ODEのクイックツアーとして、AXIS2のインテグレーション層を経由したウェブサービスで、簡単なプロセスのデプロイとそれへのアクセスを行ってみましょう。このツアーでは、とても小さなdoodleware(source)の考えに基づいた「ハイファイではない」ものを目的としています。JDK (5.0)が必要となり、コマンドライン上だけで作業します。

ODEの入手とセットアップ

サンプルを実行するにはODEのWARディストリビューションと比較的最近のサーブレットコンテナが必要です。TomcatとJettyでうまく動作することが分かっています。Getting ODE(サイト・英語)のWikiページにODE 1.1のディストリビューションのミラーサイト(zip)へのリンクがあります。以下は、Jetty 6.1.5を使用したODEのインストール手順です。

  1. 適当な作業ディレクトリを作成し(便宜上、そのフォルダをworkとします)、ODEとJettyのZIPファイルをそこに解凍します。すると、work/apache-ode-war-1.1work/jetty-6.1.5 ディレクトリが作成されます。
  2. work/jetty-6.1.5/webappsodeディレクトリを作成します。
  3. work/apache-ode-war-1.1/ode.warwork/jetty-6.1.5/webapps/odeディレクトリに展開します。

Unixのコマンドラインの場合、[MIRROR]の部分を推奨されているODEのミラーサイトに置き換えて下さい。

 $ wget http://[MIRROR]/ode/apache-ode-war-1.1.zip
$ wget http://dist.codehaus.org/jetty/jetty-6.1.5/jetty-6.1.5.zip
$ mkdir work && cd work
$ jar xf ../apache-ode-war-1.1.zip
$ jar xf ../jetty-6.1.5.zip
$ mkdir jetty-6.1.5/webapps/ode
$ cd !$ && jar xf ../../../apache-ode-war-1.1/ode.war

簡単な例「マルチカウンタプロセス」

始めの例として、単一ポート上で4つのオペレーションができる、countersというコレクションを実装したプロセスを見てみます。

  • {name} -> init -> {} to create a new counter instance.
  • {name} -> get -> {int} to access the value of a counter.
  • {name} -> getAndIncrement -> {int} to access and increment the value of a counter.
  • {name} -> close -> {} to close an existing counter.

BPELは本来メッセージ指向であり、リクエスト/レスポンスをRPCと混同しないように、上記では-> の表記を使用しています。「オペレーション」という用語はWSDLから引き継いだものですが、BPELプロセスでの意味は、メッセージ受信のアクティビティ(bpel:receivebpel:pickなど)がメッセージを受け取ることを判断するために使用するメタデータとしての意味です。

プロセスのインスタンスとプロセスそれ自身の区別については、本題から外れた話になります。BPELエンジンでは、プロセスはメッセージが送受信されるにつれてプロセスインスタンスがどのように遷移するかを決める一種の原型です。プロセス定義に従い、BPELエンジンは、相関ルール若しくは受信メッセージのために新たに作られたインスタンスをベースにし、特定のインスタンスのためのメッセージルーティングに責任を持ちます。counterプロセスに関して言えば、プロセスインスタンスに相当するそれぞれの「counter」とエンジンが、どのインスタンスがメッセージ中のcounterの名前を利用して、どのインスタンス(もしあるならば)がメッセージを受信すべきかを判断します。

BPELプロセスを実装するのは複雑なことではありませんが、XMLコードを少し書く必要があります(たった100行程度のきれいにフォーマットされたコードです)。リンク先にあるのがBPELプロセスのcounter.bpel(source)とそれに付随するWSDLのcounter.wsdl(source)です。その中では、オペレーション、ポート、パートナーリンク、メッセージプロパティ(以前は相互関係を定義していました)が定義されています。

先に議論したように、ODEはWSDLの抽象的な部分のみを使用しています。つまり、バインディングとサービス定義の部分は無視されます。しかしながら、 AXIS2のインテグレーション層では、SOAP、HTTPを通じて利用可能な、具体的なWebサービスとしてプロセスを公開するために、バインディングとサービス定義を利用することになります。

さらに要約すれば、以下の擬似コードが概略となります。:

receive init(s) and spawn an instance tagged with name = s
set counter = 0
thread 1:
while (true)
receive get(s) for s = name
reply with counter
thread 2:
while (true)
receive getAndIncrement(s) for s = name
reply with counter++
thread 3:
receive close(s) with s = name
die // instance only!

(while(true) 構文により、getgetAndIncrementオペレーションが独断的に何回も呼ばれます。)

以下のBPELコードは重要な記述です。まず初めに、というプロセス定義の一番上位のエレメントは、ODEにWSDLのありかを示すものです。つまり、下記の例ではBPELがWSDLと同じ場所にあるということです。:

<bpel:import importType="http://schemas.xmlsoap.org/wsdl/"
location="counter.wsdl"
namespace="http://example.com/bpel/counter" />

次は、ODEのユーザーメーリングリストでまず初めに聞かれる質問でもある、counter値の初期化の例です。:

<bpel:assign>
<bpel:copy>
<bpel:from>0</bpel:from>
<bpel:to>$counter.value</bpel:to>
</bpel:copy>
</bpel:assign>

BPELでは、変数を使用する前に初期化することが必須(サイト・英語) となります。そうしなければBPELエンジンでbpel:uninitializedVariableフォルトを通知します。

下図ではEclipse BPELエディタ(source)によるグラフィカル表現でプロセスの並列構造が表されています。

(Lomboz(サイト・英語) 3.3RC1 のEclipseディストリビューション(サイト・英語)には、ODEとEclipse BPELツールの統合環境が含まれています(サイト・英語)。)

bpelcコマンドによるプロセスのチェック

ODEディストリビューションには、ODEのBPELコンパイラをラップしたコマンドラインであるbpelcがあります。そのコンパイラは、静的解析によるBPELプロセスの形式かどうかの妥当性チェックや、プロセスとインポートしたWSDLやXMLスキーマ間のクロスリファレンスチェックをフルセットで行います。正確には、コンパイラが生のBPEL XMLを正規化された構造に変換し、その構造は、Jacob仮想マシンによって「実行された」プロセスインスタンスのための原型として順に用いられます。(その正規化の段階では、合成の構造や間接的な構造でも、実行時に必要とされる全てのものを作成します。)

例えば、例に挙げたcounter.bpelプロセスをcounter.wsdl と同じディレクトリに配置した際のコンパイルは以下のようになります。

$ export PATH=`pwd`/work/apache-ode-1.1-war/bin:$PATH
$ bpelc ./counter.bpel

もしコンパイラが問題を検知したら、行数と補足情報と共にエラーメッセージを出力します。-v 若しくは -vv オプションによってより詳細な情報が出力されます。しかし、多くの言語と同様に、コンパイルしたすべてのBPELプロセスが動作するというわけではありません。

コンパイラーはプログラム的に処理することも可能なので、カスタム言語やグラフィカルな表記をXML BPEL若しくはコンパイラの中間フォーマット(「Oモデル」と呼ばれます)や実行時にコンパイルされる形式のものに変換するといった、異なるフロントエンドで実装することができます。アクティビティ名、行数、その他の情報は、コンパイルエラーや実行した際のソースのトレースバックに対応付けるために保持されています。

Counterプロセスのパッケージ、デプロイ、実行

ODE AXIS2ランタイムにプロセスをデプロイするには、BPELプロセスのパートナーリンクが具体的なサービスのポートにマッピング方法を指定するために、追加のアーティファクト(deploy.xml)(source)が必要になります。

<deploy xmlns="http://www.apache.org/ode/schemas/dd/2007/03"
xmlns:tns="http://example.com/bpel/counter">
<process name="tns:counter">
<active>true</active>
<provide partnerLink="operations">
<service name="tns:counter" port="port"/>
</provide>
</process>
</deploy>

別のターミナルを立ち上げ、Jettyを起動します。

$ cd work/jetty-6.1.5
$ ./bin/jetty.sh run

表示されるログを起動後から少しの間見ていると、最後に以下のようなメッセージが表示されます。

INFO - GeronimoLog.info(79) | Process deployment polling started on path
/Users/prb/work/jetty-6.1.5/webapps/ode/WEB-INF/processes.
INFO - GeronimoLog.info(79) | ODE Service Engine has been started.
2007-08-30 00:59:59.761::WARN: Unknown realm: Test JAAS Realm
2007-08-30 00:59:59.830::INFO: Started SelectChannelConnector @ 0.0.0.0:8080

デプロイメントディレクトリのコピーをし、ファイルを移動します。

$ mkdir /tmp/counter
$ cp counter.bpel counter.wsdl deploy.xml /tmp/counter
$ mv /tmp/counter jetty-6.1.5/webapps/ode/WEB-INF/processes

Jettyを起動したウィンドウには、以下のログが表示されているはずです。

DEBUG - GeronimoLog.debug(66) | Created Axis2 service {http://example.com/bpel/counter}counter
DEBUG - GeronimoLog.debug(66) | Activated {http://example.com/bpel/counter}counter-1 myrole operations: EPR is org.apache.ode.bpel.epr.WSAEndpoint@b56444
DEBUG - GeronimoLog.debug(66) | Activated {http://example.com/bpel/counter}counter-1
DEBUG - GeronimoLog.debug(66) | Rehydrating process {http://example.com/bpel/counter}counter-1
INFO - GeronimoLog.info(79) | Activated process {http://example.com/bpel/counter}counter-1.
INFO - GeronimoLog.info(79) | Deployment of artifact counter successful: [{http://example.com/bpel/counter}counter-1]
DEBUG - GeronimoLog.debug(66) | Creating process DAO for {http://example.com/bpel/counter}counter-1 (guid=hqejbhcnphr2jtol7ojc0s)

ODEのためにAXIS2のインテグレーション層に送られるような、AXIS2の設定により単純なHTTP呼び出しのオペレーションをサポートします。curl は、コマンドラインからプロセスを扱うのに十分なものです。(大抵の*nixシステムにはcurl が含まれていると思います。また、Windowsでの実行も可能です(英語) )。以下のコマンドで、「foo」という名前のcounterを生成しインクリメントを2回行います。

$ curl http://localhost:8080/ode/processes/counter/init?name=foo
<axis2ns2:initResponse xmlns:axis2ns2="http://example.com/bpel/counter" />
$ curl http://localhost:8080/ode/processes/counter/get?name=foo
<axis2ns4:getResponse xmlns:axis2ns4="http://example.com/bpel/counter">
<value>0.0</value>
</axis2ns4:getResponse>

$ curl http://localhost:8080/ode/processes/counter/getAndIncrement?name=foo
<axis2ns6:getAndIncrementResponse xmlns:axis2ns6="http://example.com/bpel/counter">
<value>0.0</value>
</axis2ns6:getAndIncrementResponse>

$ curl http://localhost:8080/ode/processes/counter/getAndIncrement?name=foo
<axis2ns8:getAndIncrementResponse xmlns:axis2ns8="http://example.com/bpel/counter">
<value>1.0</value>
</axis2ns8:get
AndIncrementResponse>

(GET でリソースを作るので、厳密に言うとこれはRESTfulではありません。しかし、コマンドライン上でcurlを使用することで一緒にまとめて、SOAPメッセージをPOSTしています。)

運用管理の体験

ODEには、永続層とAXIS2のインテグレーション層を通じて処理されるインスタンスとプロセスを管理する機能を持っており、多くのオペレーションが Webサービスを通して公開されています。例えば、デプロイされたプロセスの全てをリスト表示するには以下のようにします。

$ curl http://localhost:8080/ode/processes/ProcessManagement/listAllProcesses

若しくは、もっと見やすい表示にしたければブラウザの中で開くか、xmllint(英語)をパイプでつなげます。

$ curl -s -o - http://localhost:8080/ode/processes/ProcessManagement/listAllProcesses | \
xmllint --format -
<ns:process-info-list xmlns:ns="http://www.apache.org/ode/pmapi/types/2006/08/02/">
<ns:process-info>

<ns:pid>{http://example.com/bpel/counter}counter-1</ns:pid>
; <ns:status>ACTIVE</ns:status>
<ns:version>1</ns:version>
[...]

そして、作成したインスタンスを一覧表示します。:

$ curl -s http://localhost:8080/ode/processes/counter/init?name=bar
$ curl -s http://localhost:8080/ode/processes/counter/init?name=baz
$ curl -s http://localhost:8080/ode/processes/counter/init?name=qux
$ curl -s -o - http://localhost:8080/ode/processes/InstanceManagement/listAllInstances | \
xmllint --format -
<ns:instance-info-list xmlns:ns="http://www.apache.org/ode/pmapi/types/2006/08/02/">
<ns:instance-info>
<ns:iid>57</ns:iid>
<ns:pid>{http://example.com/bpel/counter}counter-1</ns:pid>
<ns:process-name xmlns:coun="http://example.com/bpel/counter">coun:counter</ns:process-name>
<ns:root-scope siid="58" status="ACTIVE" name="__PROCESS_SCOPE:counter" modelId="8"/>
[...]

次のステップへ

今回は、ODEの表面的な部分をざっくりと書きました。しかし、BPELとコンポーネントとしてのパッケージングにおけるODEの達観した物の見方の鍵となる部分を強固なものにする必要があります。

ODEはオープンソースなので、次のステップは参加することです。

  1. ユーザーのメーリングリスト(英語)に加わり、質問をしたり、それに答えたりして下さい。
  2. デベロッパーのメーリングリスト(英語)に加わり、ODEの実装や(彼らをとりまとめる)リーダーとして貢献して下さい。新しいインテグレーションレイヤー(例えば、SCA(英語))、BPELの拡張(英語) 、新しい式/クエリー(英語)言語(例えば、E4X(英語))、ODEの静的解析(英語)の可用性を強化したもの、若しくは単純に尖った部分を取り除いたもの(例えば、JPAのプロセスやインスタンス管理)については、コントリビュートを歓迎している分野です。
  3. プロジェクト、製品、若しくはSaaSとしてODEを組み込んでいる場合は、コミュニティへのフィードバックをして下さい。ODEは、フレームワークよりも広いオーケストレーションコンポーネントとして設計、構築されています。ODEを利用した製品やSaaSにおいて、商用面でのサクセスストーリーが既にあります。

著者について

Paul Brown氏(英語)は、ODEプロジェクトのコミッタであり、次世代のビッグアイデアを見据えている起業家でもあります。

原文はこちらです:http://www.infoq.com/articles/paul-brown-ode

この記事に星をつける

おすすめ度
スタイル

BT