2010年2月27日土曜日

Oracle BPEL/ParalellSplit (2)

前回同様、Oracle BPEL での ParallelSplit の試行。

以下の環境
・Fusion Middleware 11g + JDeveloper 11g
・SoapUI

前回やってみた結果、Flow アクティビティ内部に置いた他サービスの同期呼び出し(invoke)は、本来は互いに結果受信を待ったりせずに並列実行されるのが望ましいが、実際、そうはならず逐次実行されてしまうことがわかった。つまり、並行する2つのブランチで実行される10秒ずつのサービスが、並列に10秒で実行されるのではなく、1つずつ合計20秒で実行されることになる。また、パートナーリンクの nonBlockingInvoke プロパティを設定しても、結局並列実行にはならなかった。

で、今回は次善の策として、明示的な非同期呼び出しを試した。

■ 試行-パートナーリンク
前回同様、受信XMLに含まれるミリ秒だけ待って、開始終了時間を返す外部サービスを適当に作った(ただし今回は非同期なサービスとした)。これをパートナーリンクで指定して BPEL から呼び出してみる。

まずこれを呼び出す BPEL 定義を、ブランチ一本の Flow アクティビティを使ってやってみる。
まあ、普通に問題なく動いた。

次にこのFlowアクティビティに、同じ構成のブランチを一本追加してみる。
あまり期待していなかったが、やっぱりエラーがでた。
<faultstring>receiveが競合しています.
類似したreceiveアクティビティが同じプロセスで宣言されています。.
別のreceiveアクティビティまたは同等のもの(現在のところ、pickアクティビティのonMessageブランチ)が、partnerLink "WaitAsyncProcess1"、操作名"processResponse"および相関セット"" (または対話ID)ですでに有効になっています。BPEL 1.1仕様の「Appendix A - Standard Faults」によると、このような状況ではフォルトがスローされます。
競合しているreceiveアクティビティを削除してからプロセスを再デプロイしてください。.</faultstring>

なるほど、受信系のアクティビティは、partnerLink、操作名、相関セットの組で一意に識別されるらしい。


というわけで、同じサービスについて別々の partnerLink を定義して、Flowアクティビティ以下の各ブランチで呼ぶようにしてみる。

なるほど上手くいった。

■ 試行2-相関セット
さらに相関セットも試してもみた。
  • まずブランチ1本の Flow から相関セットを指定して非同期呼び出しをやってみて確認。まあ当たり前だが、これは上手く行く。
  • 次に、ブランチを足してみる。試しに上で使ったのと同じ相関セットを指定してみると、「同じ相関セットは2度初期化できない」といった感じのエラーになる。
  • 上の相関セットと同じプロパティを用いて、別の相関セットを追加定義してみる。これは上手くいった。
  • プロパティとプロパティエイリアスを別途追加定義して、上で追加した相関セットに関連付けてみる。例外発生。
    → <detail>java.lang.NullPointerException
    at com.collaxa.cube.engine.delivery.CorrelationProperty.<init>(CorrelationProperty.java:53)
    at com.collaxa.cube.engine.delivery.DeliveryHelper.createCorrelationSet(DeliveryHelper.java:231)
    at com.collaxa.cube.engine.ext.common.ReceiveHandler.handleNormalInput(ReceiveHandler.java:178)
    ・・・以下略
    受信XML の同じ部分に別々のプロパティエイリアスを関連付けるのがNGという事なのか。NullPointerException なのでよく分からない。


■ 結び
結局、ある ParallelSplit の別々の分岐で同じサービスを invoke する場合、(1)パートナーリンクを別途定義する方法と、(2)同一プロパティに相関セットを別途定義する方法があるらしいことが分かった。

ただ、本当に正しいやり方なのか、何となく不安な感じもある(特に相関セットの方)。以外にネット上の言説も少なくて、これらのやり方で良いのか、またどちらのやり方が良いのかなど、確信が得られない。

あと、方法として問題なかったとしても、パートナーリンクや相関セットを定義する都合上、事前に分岐の数が決まっている必要があるので、FlowNでは使えないということになる。

元はといえば、Flow アクティビティの並列実行が、文字通り本当に並列実行できていれば問題ないのだけど、なんだかちょっと面倒くさい事になっている。

Oracle BPEL だからなのか、他製品もそうなのか・・・

2010年2月22日月曜日

Oracle BPEL/ParalellSplit

前回インストールした Fusion Middleware 11g の Oracle BPEL で、workflow pattern の Parallel Split と Synchronizationを実装してみた。

以下のように、Flow アクティビティで実装。

パートナーリンク で指定している WaitProcessサービスは、入力XMLで指定されたミリ秒だけ待ち、開始時刻と終了時刻を文字列として返す。

この WaitProcessサービスに 2000ms を指定して、flow から3本のブランチに分岐させ、分岐が収束した後のアクティビティで 3つのメッセージをまとめて返す。

これを SoapUI から実行すると、こんな感じのレスポンスが返ってきた。
<env:Body>
名前空間省略・・・
<ns0:message>23:22:44:371-23:22:46:372</ns0:message>
<ns0:message>23:22:42:291-23:22:44:292</ns0:message>
<ns0:message>23:22:39:010-23:22:41:011</ns0:message>
</processResponse>
</env:Body>
うーん、思ってたのと違う・・・
3つの invoke が、一つ終わったら次って感じで、逐次的に実行されてる。

検索してみると、nonBlockingInvoke というパートナーリンクのプロパティをtrue にすれば良いというような記述が見つかる。その通りにして、再度試してもみたけど、動作は変わらない。監査を見ると、こんな風になっている。


一応 nonblocking な呼び出しが同時に始まってはいるようだが、本当の実行は逐次実行されているのがわかる。

さらにググってみると、やはり nonBlockingInvoke を設定しても並行で実行されずに困っている人たちの質問が見つかるが、改善策がはっきりしない。辛うじて見つかる記述も 10g の設定で、なんか違う。

これだと外部のサービス呼び出しを並列実行する意味が弱くなる。明示的に非同期なフロー定義にしなければ駄目だとすると、なんだか面倒くさ。ちょっとテンション下がる・・・

2010年2月14日日曜日

Fusion Middleware 11g インストールと確認

ずっと使わず嫌いだった Fusion Middleware をインストールしてみた。

なんか、高い金払わないと使えない先入観があったけど、商用利用でなければ勝手にダウンロードして使っても別に構わないらしい。

■ 環境
  • Windows Vista Home Premium SP2
  • NEC LaVie/Intel Core2 Duo 2.1GHz/4GB RAM
  • Oracle Database 11g Enterprise Edition Release 11.1.0.7.0

■ インストール
参考になりそうな記事を探すと、ちょっとずつ製品やバージョンが違っている惜しい記事がたくさん引っかかるが、この記事が一番参考になった。現時点での最新の製品群のバージョンに一番近くて、なおかつ必要最小限な手順がコンパクトにまとまってた。

やってみて記事どおりに行かなかった点がほんの少しあったので、以下に補足。
  • step1 の RCU を実行してリポジトリを作るところで、processes の設定値が小さいと失敗するので、500以上に設定しておく。
    • alter system set PROCESSES=500 scope=SPFILE;
    • データベース再起動
  • step 4 の config.cmd の実行で、「管理者として実行」から起動しないと、"CFGFWK-60814"エラーが出る。
その他は、ほとんどスクリーンショット通りにやれば上手く行くはず。


■ HelloWorld作成
  • JDeveloper の ファイル/新規/一般/アプリケーション/SOA アプリケーションで、アプリの雛形を作成。
    • アプリケーション名: HelloWorldApp
    • コンポジット名:HelloWorldPrj
    • コンポジット・テンプレート:"BPELを使用するコンポジット"
    ※その他はデフォルト、あるいは適当
  • "BPELプロセスの作成"で以下のように記述
    • 名前:HelloWorldBPEL
    • テンプレート:同期BPELプロセス
  • receiveInput と replyOutput だけを含むBPELのテンプレが生成されているので、以下のように編集する。
    • receiveInput と replyOutput の間に Assign を入れる
    • Assign に以下のようなコピー操作を追加
      • 左辺:式:concat('Hello, ', bpws:getVariableData('inputVariable','payload','/client:process/client:input'))
      • 右辺:Variable:/client:processResponse/client:result
    ※ [適用]ボタンと、[プロセスの検証]ボタンを押して、BPELが正しいことを確認しておく

■ デプロイ
  • ・JDeveloper で ファイル/新規/一般/接続/アプリケーション・サーバー接続で、サーバーを作成する。
  • プロジェクトの右クリメニューから、デプロイ/HelloWorldPrj
    • アプリケーションサーバにデプロイ
    • サーバの選択で、上で作成したサーバを指定
    他はデフォルト
  • ブラウザで http://{ホスト名}:7001/em からコンソールに入って、soa-infra 下に HelloWorldPrj がデプロイされていることを確認
  • HelloWorldPrj をクリックすると、右ペインにプロジェクトの内容が表示されるので、Component Metrics のリストにHelloWorldBPELが含まれていることを確認
  • パズルのピースと地球を組み合わせたような小さいボタンを押すとWSDLのURLがポップアップするのを確認。

■ 実行
  • soapUI で、上記のWSDL URLを指定してプロジェクト作成
  • リクエストの process/input に'BPEL'を指定して、送信
  • のprocessResponse/result のテキストが'Hello, BPEL'であることを確認

以上。

これでいろいろ試せる環境ができた。
にしても重い・・・