この章では、BPELプロセス・サービス・コンポーネントでのパラレル・フローの使用方法について説明します。パラレル・フローを使用すると、BPELプロセス・サービス・コンポーネントで複数のタスクを同時に実行できます。パラレル・フローは、時間を要する独立した複数のタスクを実行する必要がある場合に特に役立ちます。
項目は次のとおりです。
SOAコンポジット・アプリケーションでのパラレル・フローの作成方法の詳細は、第3章「SOAサンプル・アプリケーションの概要」で説明されているFusion Order Demoアプリケーションを参照してください。
BPELプロセスでは、複数の非同期ソースからの情報の収集が必要になる場合があります。各コールバックに要する時間(時間数または日数)は明らかでないため、各サービスを一度に1つずつコールするのでは時間がかかりすぎることがあります。複数のコールを1つのパラレル・フローに分解することにより、BPELプロセス・サービス・コンポーネントは複数のWebサービスを同時に起動し、レスポンスが到着するたびに受信できます。この方法は時間の節約に効果的です。
図9-1は、Fusion Order Demoアプリケーションの「Retrieve_QuotesFromSuppliers」flowアクティビティを示しています。「Retrieve_QuotesFromSuppliers」flowアクティビティは、注文情報を社内倉庫(InternalWarehouseService)と外部パートナ倉庫(PartnerSupplierMediator)の2つのサプライヤにパラレルで送信します。2つの倉庫は、注文に対する入札をflowアクティビティに返します。ここでは、2つの非同期コールバックがパラレルで実行されます。一方のコールバックは、もう一方のコールバックが先に完了するまで待機する必要がありません。各レスポンスは異なるグローバル変数に格納されます。
BPELプロセス・サービス・コンポーネントにパラレル・フローを作成するには、flowアクティビティを使用します。flowアクティビティを使用すると、1つ以上のアクティビティを同時に実行するように指定できます。flowアクティビティは同期性も備えています。flowアクティビティは、フロー内のすべてのアクティビティが処理を終了したときに完了します。このアクティビティが完了しても、許可条件がfalseの場合はスキップされている可能性があります。
パラレル・フローを作成する手順は、次のとおりです。
「コンポーネント・パレット」で、「BPELコンストラクト」を展開します。
flowアクティビティをデザイナにドラッグします。
図9-2に示すように、+記号をクリックしてflowアクティビティを開きます。
flowアクティビティには、最初に2つのブランチがあり、各ブランチには機能要素用のボックスがあります。これらのボックスにデータを移入するには、scopeアクティビティの場合のように、機能を作成するか、複数のアクティビティをボックスにドラッグします。flowアクティビティを強調表示し、「シーケンスの追加」アイコンをクリックすることで、ブランチを追加できます。
複数のサービスを同時に起動するには、追加するアクティビティをflowの両側にドラッグして定義します。図9-3に詳細を示します。
完了すると、flowアクティビティの設計は図9-4のようになります。この例は、Fusion Order Demoアプリケーションの「Retrieve_QuotesFromSuppliers」 flowアクティビティを示しています。入札を受け取るために、「InternalWarehouseService」および「PartnerSupplierMediator」の2つのブランチが定義されています。
通常、flowアクティビティには多数のsequenceアクティビティが含まれています。各sequenceはパラレルに実行されます。例9-1は、設計完了後のOrderProcessor.bpel
ファイルのRetrieve_QuotesFromSuppliers
flowアクティビティに対してsequenceが2つある構文を示しています。ただし、flowアクティビティには多数のsequenceを指定できます。flowアクティビティには、他のアクティビティを含めることもできます。例9-1では、flowの各sequenceにassign、invokeおよびreceiveアクティビティが含まれています。
図9-1 flowアクティビティ
<flow name="Retrieve_QuotesFromSuppliers"> <sequence name="Sequence_4"> <assign name="Assign_InternalWarehouseRequest"> <copy> <from variable="gOrderInfoVariable" query="/ns4:orderInfoVOSDO/ns4:OrderId"/> <to variable="lInternalWarehouseInputVariable" part="payload" query="/ns1:WarehouseRequest/ns1:orderId"/> </copy> </assign> <invoke name="Invoke_InternalWarehouse" inputVariable="lInternalWarehouseInputVariable" partnerLink="InternalWarehouseService" portType="ns1:InternalWarehouseService" operation="process"/> <receive name="Receive_InternalWarehouse" createInstance="no" variable="lInternalWarehouseResponseVariable" partnerLink="InternalWarehouseService" portType="ns1:InternalWarehouseServiceCallback" operation="processResponse"/> <assign name="Assign_InterWHResponse"> <bpelx:append> <bpelx:from variable="lInternalWarehouseResponseVariable" part="payload" query="/ns1:WarehouseResponse"/> <bpelx:to variable="gWarehouseQuotes" query="/ns1:WarehouseList"/> </bpelx:append> </assign> </sequence> <sequence name="Sequence_4"> <assign name="Assign_PartnerRequest"> <copy> <from variable="gOrderInfoVariable" query="/ns4:orderInfoVOSDO"/> <to variable="lPartnerSupplierInputVariable" part="request" query="/ns4:orderInfoVOSDO"/> </copy> </assign> <invoke name="Invoke_PartnerSupplier" partnerLink="PartnerSupplierMediator" portType="ns15:execute_ptt" operation="execute" inputVariable="lPartnerSupplierInputVariable"/> <receive name="Receive_PartnerResponse" createInstance="no" variable="lPartnerResponseVariable" partnerLink="PartnerSupplierMediator" portType="ns15:callback_ptt" operation="callback"/> <assign name="Assign_PartnerWHResponse"> <bpelx:append> <bpelx:from variable="lPartnerResponseVariable" part="callback" query="/ns1:WarehouseResponse"/> <bpelx:to variable="gWarehouseQuotes" query="/ns1:WarehouseList"/> </bpelx:append> </assign> </sequence> </flow>
flowアクティビティ内のアクティビティの実行を同期化すると、他のアクティビティが完了した後にのみ特定のアクティビティを実行できるようになります。たとえば、invokeアクティビティverifyFlight
があり、flowの開始時に他のinvokeアクティビティ(verifyHotel
、verifyCarRental
およびscheduleFlight
)と並行して実行されると仮定します。ただし、フライトのスケジュールが必要なのは、フライトが使用可能であることを確認した後のみです。したがって、verifyFlight
invokeアクティビティとscheduleFlight
invokeアクティビティの間にリンクを追加できます。このリンクにより、リンクのターゲットであるアクティビティ(scheduleFlight
)は、リンクのソースであるアクティビティ(verifyFlight
)が完了した場合のみ実行されることを示す、依存関係のレベルが指定されます。
例9-2に詳細を示します。リンク名verifyFlight-To-scheduleFlight
は、ソースverifyFlight
invokeアクティビティおよびターゲットscheduleFlight
invokeアクティビティに割り当てられます。ソースverifyFlight
の実行が完了した後、ターゲットscheduleFlight
が実行されます。
例9-2 ソース・アクティビティとターゲット・アクティビティ間のリンク
<flow ...> <links> <link name="verifyFlight-To-scheduleFlight" /> </links> <documentation> Verify the availability of a flight, hotel, and rental car in parallel </documentation> <invoke name="verifyFlight" ...> <sources> <source linkName="verifyFlight-To-scheduleFlight" /> </sources> </invoke> <invoke name="verifyHotel" ... /> <invoke name="verifyCarRental" ... /> <invoke name="scheduleFlight" ...> <targets> <target linkName="verifyFlight-To-scheduleFlight" /> </targets> </invoke> </flow>
flowアクティビティ内のアクティビティ間に同期を作成する手順は、次のとおりです。
flowアクティビティを作成します。詳細は、第9.2.1項「パラレル・フローの作成方法」を参照してください。
flowアクティビティの「一般」タブで、「追加」アイコンをクリックします。
図9-5に示すように、リンクの名前を入力します。
「適用」→「OK」の順にクリックします。
適切なアクティビティをflowアクティビティにドラッグし、ステップ3で定義したのと同じリンク名を持つソースとして定義します。この例では、A
という名前のassignアクティビティが図9-6でソースとして定義されています。
各ソース・アクティビティは、指定されたリンクをたどるための保護手段として、オプションの「遷移条件」を指定できます。この列の行をクリックして「ブラウザ」アイコンを呼び出し、「式ビルダー」ダイアログにアクセスするか、または条件を作成します。「遷移条件」列を空白のままにすると、trueと評価されると想定されます。
assignアクティビティの適切なコピー・ルールを定義します。
「適用」→「OK」の順にクリックします。
追加のアクティビティをflowアクティビティにドラッグし、ステップ3で定義したのと同じリンク名を持つターゲットとして定義します。この例では、B
という名前の別のassignアクティビティが図9-7でターゲットとして定義されています。
assignアクティビティの適切なコピー・ルールを定義します。
「適用」→「OK」の順にクリックします。
BPELプロセスの設計を続行します。
完了後、設計は図9-8のようになります。
例9-3に、アクティビティ実行を同期化するためのリンクを持つ3つのflowアクティビティの設計が完了した後の.bpel
ファイルを示します。
Flow_1
は、単純なアクティビティ間のリンクを示します。
Flow_1
にはAtoB
という名前のリンクが含まれています。リンクのターゲットであるアクティビティ(assignアクティビティB
)は、リンクのソースであるアクティビティ(assignアクティビティA
)が完了した場合のみ実行されます。
Flow_2
は、単純なアクティビティと複合アクティビティの間のリンクを示します。
Flow_2
にはAtoB
という名前のリンクも含まれています。リンクのターゲットであるアクティビティ(assignアクティビティB
)は、リンクのソースであるアクティビティ(scopeアクティビティscope1
)が完了した場合のみ実行されます。
Flow_3
は、複合アクティビティ間のリンクを示します。
Flow_3
にはAtoB
という名前のリンクも含まれています。リンクのターゲットであるアクティビティ(sequenceアクティビティSequence_1
)は、リンクのソースであるアクティビティ(scopeアクティビティscope2
)が完了した場合のみ実行されます。
例9-3 リンクを含むflowアクティビティ
<!-- link between simple activities --> <flow name=Flow_1> <links> <link name="AtoB"/> </links> <assign name="A"> <sources> <source linkName="AtoB"/> </sources> <copy> <from>concat($output.payload, 'A')</from> <to>$output.payload</to> </copy> </assign> <assign name="B"> <targets> <target linkName="AtoB"/> </targets> <copy> <from>concat($output.payload, 'B')</from> <to>$output.payload</to> </copy> </assign> </flow> <!-- link between simple activity and composite activity --> <flow name=Flow_2> <links> <link name="AtoB"/> </links> <scope name="scope1"> <sources> <source linkName="AtoB"/> </sources> <assign name="A"> <copy> <from>concat($output.payload, 'A')</from> <to>$output.payload</to> </copy> </assign> </scope> <assign name="B"> <targets> <target linkName="AtoB"/> </targets> <copy> <from>concat($output.payload, 'B')</from> <to>$output.payload</to> </copy> </assign> </flow> <!-- link between composite activities --> <flow name=Flow_3> <links> <link name="AtoB"/> </links> <scope name="scope2"> <sources> <source linkName="AtoB"/> </sources> <assign name="A"> <copy> <from>concat($output.payload, 'A')</from> <to>$output.payload</to> </copy> </assign> </scope> <sequence name="Sequence_1> <targets> <target linkName="AtoB"/> </targets> <assign name="B"> <copy> <from>concat($output.payload, 'B')</from> <to>$output.payload</to> </copy> </assign> </sequence> </flow> </sequence>
ターゲット・アクティビティでオプションの結合条件を指定できます。結合条件の値はブール式です。結合条件が指定されていない場合、結合条件は、このアクティビティのすべての着信リンクのリンク・ステータスの分離(つまり、論理OR演算)になります。
Oracle BPELデザイナでは、結合条件を追加するための設計はサポートされていません。結合条件を追加するには、Oracle BPELデザイナの「ソース」ビューの.bpel
ファイルに条件を手動で追加する必要があります。
例9-4に、結合条件の例を示します。
例9-4 ターゲット・アクティビティの結合条件
<flow> <links> <link name="linkStatus2"/> </links> <empty name="E2"> <sources> <source linkName="linkStatus2"> <transitionCondition>false()</transitionCondition> </source> </sources> </empty> <empty name="E2"> <targets> <joinCondition>bpws:getLinkStatus('linkStatus2')=true()</joinCondition> <target linkName="linkStatus2"/> </targets> </empty> </flow>
この項では、次のアクティビティを使用してパラレル・ブランチの数をカスタマイズする方法について説明します。
FlowNアクティビティ(BPELバージョン1.1プロジェクト)
forEachアクティビティ(BPELバージョン2.0プロジェクト)
flowアクティビティでは、BPELコードによってパラレル・ブランチの数が決定されます。ただし、必要なブランチの数は、多くの場合、使用可能な情報に応じて異なります。flowNアクティビティは、N
の値に等しい複数のフローを作成します。この値は、使用可能なデータおよびプロセス内のロジックに基づいて実行時に定義されます。索引変数は、N
の値に到達するまで、新しいブランチが作成されるたびに増分されます。
flowNアクティビティは、任意の数のデータ要素に対してアクティビティを実行します。BPELプロセス・サービス・コンポーネントは、要素の数の変化に応じて適切に調整を実行します。
flowNで作成される各ブランチは、同じアクティビティを実行しますが、異なるデータを使用します。各ブランチは、索引変数を使用して入力変数を参照します。索引変数をXPath式で使用すると、そのブランチに固有のデータを取得できます。
たとえば、データの配列があるとします。BPELプロセス・サービス・コンポーネントは、count
関数を使用して配列内の要素の数を判断します。次に、N
が要素の数に設定されます。索引変数は、事前に設定された値(デフォルトは0(ゼロ))で始まります。flowNは、複数のブランチを作成して配列の各要素を取得し、その要素に含まれるデータを使用してアクティビティを実行します。これらのブランチは、初期索引値とN
の間のすべての値を使用して、パラレルに生成および実行されます。flowNは、索引変数がN
の値に到達すると終了します。たとえば、配列に3
つの要素が含まれている場合、N
は3
に設定されます。索引変数が1で始まるとすると、flowNアクティビティは索引1、2および3を使用して3つのパラレル・ブランチを作成します。
flowNアクティビティでは、Webサービスから取得したデータなど、他のソースのデータも使用できます。
図9-9は、3つのホテルを参照するOracle Enterprise Manager Fusion Middleware ControlコンソールのflowNアクティビティの実行時フローを示しています。この図は、BPELプロセス・サービス・コンポーネントではなく、プロセスを実際に実行する方法を示しているため、ビューそのものではありません。この例では、3つのホテルがありますが、ブランチの数は使用可能なホテルの数に応じて異なります。
図9-9 flowNアクティビティの実行を示すOracle Enterprise Manager Fusion Middleware Controlコンソール・ビュー
flowNアクティビティを作成する手順は、次のとおりです。
「コンポーネント・パレット」で、「Oracle Extensions」を展開します。
flowNアクティビティをデザイナにドラッグします。
+記号をクリックしてflowNアクティビティを開きます。
flowNアクティビティをダブルクリックします。
図9-10は、「FlowN」ダイアログを示しています。
「FlowN」ダイアログでは次のことができます。
アクティビティ名の設定
値またはN
の値(作成するブランチ数)の計算式の入力
索引変数(各ブランチでの待機時間)の定義
追加するアクティビティをflowNアクティビティにドラッグして定義します。
図9-11は、flowNアクティビティと他のアクティビティが表示されている様子を示しています。
次のコードは、flowNアクティビティを使用して任意の数のホテルの情報を参照する.bpel
ファイルを示しています。次のアクションを実行します。
例9-5にsequence名を示します。
例9-5 sequence名
<sequence name="main"> <!-- Received input from requester. Note: This maps to operation defined in NflowHotels.wsdl The requester sends a set of hotels names wrapped into the "inputVariable" -->
receive
アクティビティは、クライアント・パートナ・リンクをコールし、flowN
アクティビティがN
の数を定義してホテル情報を参照するために必要な情報を取得します。例9-6に例を示します。
例9-6 receiveアクティビティ
<receive name="receiveInput" partnerLink="client" portType="client:NflowHotels" operation="initiate" variable="inputVariable" createInstance="yes"/> <!-- The 'count()' Xpath function is used to get the number of hotelName noded passed in. An intermediate variable called "NbParallelFlow" is used to store the number of N flows being executed --> <assign name="getHotelsN"> <copy> <from expression="count($InputVariable.payload/client:HotelName);"/> <to variable="NbParallelFlow"/> </copy> </assign> <!-- Initiating the FlowN activity The N value is initialized with the value stored in the "NbParallelFlow" variable The variable call "Index" is defined as the index variable NOTE: Both "NbParallelFlow" and "Index" variables have to be declared -->
次に、flowN
アクティビティが開始されます。flowN
のアクティビティに名前を定義すると、N
がinputVariable
(ホテル・エントリの数)の値として定義されます。また、このアクティビティは、索引変数としてindex
を割り当てます。例9-7に例を示します。
図9-7 flowNアクティビティ
<bpelx:flowN
name="FlowN" N="bpws:getVariableData('NbParallelFlow')
indexVariable="Index'>
<sequence name="Sequence_1">
<!-- Fetching each hotelName by indexing the "inputVariable" with the
"Index" variable.
Note the usage of the "concat()" Xpath function to create the
expression accessing the array element.
-->
例9-8に示すコピー・ルールで索引変数を使用し、複数のホテル・エントリを1つのリストに連結します。
例9-8 assignアクティビティ
<assign name="setHotelId"> <copy> <from expression= "bpws:getVariableData('inputVariable','payload',concat('/client:Nflo wHotelsProcessRequest/client:ListOfHotels/client:HotelName[', bpws:getVariableData('Index'),']'))"/> <to variable="InvokeHotelDetailInputVariable" part="payload" query="/ns2:hotelInfoRequest/ns2:id"/> </copy> </assign>
invoke
アクティビティは、このホテル情報を使用して、Webサービスから各ホテルの詳細情報を参照します。例9-9に例を示します。
例9-9 invokeアクティビティ
<!-- For each hotel, invoke the web service giving detailed information on the hotel --> <invoke name="InvokeHotelDetail" partnerLink="getHotelDetail" portType="ns2:getHotelDetail" operation="process" inputVariable="InvokeHotelDetailInputVariable" outputVariable="InvokeHotelDetailOutputVariable"/> <!-- This procees does not do anything with the retrieved information. In real life, it could then be used to continue the process. Note: Meanwhile an indexing variable is used. Unlike a while loop, the activities are executed in parallel, not sequentially. --> </sequence> </bpelx:flowN>
最後に、このBPELプロセスは、各ホテルの詳細情報をクライアント・パートナ・リンクに送信します。例9-10に例を示します。
forEachアクティビティを使用すると、アクティビティの複数のセットを順次、または並行して処理できます。forEachアクティビティは、含まれている(子)scopeアクティビティを正確にN+1回実行し、Nは、最終カウンタ値から、「For Each」ダイアログの「カウンタの値」タブで指定する開始カウンタ値を引いた値に等しくなります。flowアクティビティなど、他の構造化アクティビティは、含まれているアクティビティとして任意のタイプのアクティビティを使用できますが、forEachアクティビティにはscopeアクティビティのみ含めることができます。
forEachアクティビティを開始すると、開始カウンタ値と最終カウンタ値に指定した式が評価されます。この2つの値は、返された後、アクティビティのライフサイクルの間は変化しません。どちらの式も、少なくとも1文字を含む値を返す必要があります。これらの式が有効な値を返さない場合、フォルトがスローされます。開始カウンタ値が最終カウンタ値より大きい場合、含まれているscopeアクティビティは実行されず、forEachアクティビティは完了したとみなされます。
各反復中に、「一般」タブの「カウンタ名」フィールドに指定された変数は、forEachアクティビティに含まれているスコープで暗黙的に宣言されます。スコープの最初の反復中に、カウンタ変数は開始カウンタ値で初期化されます。次の反復で、カウンタ変数は開始カウンタ値+1で初期化されます。その後の反復のたびに、前に初期化されたカウンタ変数値が1ずつ増分され、カウンタ値が最終カウンタ値に設定される最後の反復まで繰り返されます。カウンタ変数は、囲まれたscopeアクティビティに対してローカルです。反復中に値を変更できますが、各反復の後にその値は失われます。したがって、カウンタ変数値は次の反復のカウンタ値には影響しません。
forEachアクティビティは、次のループ反復をサポートしています。
順次(デフォルト)
forEachアクティビティは、scopeアクティビティ内で定義されている特定のアクティビティのセットに対して、ループ反復を順番にN回実行します。例として、forEachアクティビティは、注文書メッセージがN個の受注品目で構成される、受信注文書メッセージに対して繰り返されるとします。囲まれたscopeアクティビティはN+1回実行され、各インスタンスは前の反復が完了した後にのみ開始されます。
パラレル
すべてのループ反復は同時に開始され、並行して処理されます。並列反復は、独立したデータのセットが処理される環境、または異なるパートナとの独立した対話が並行して行われる環境で役に立ちます。並列ループを有効にするには、「一般」タブで「パラレル実行」チェック・ボックスを選択します。これらのシナリオでは、含まれているscopeアクティビティのN+1インスタンスが並行して実行されます。scopeアクティビティの各コピーには、順に実行されるforEachアクティビティに指定したのと同じ方法で宣言された、「一般」タブの「カウンタ名」フィールドで指定したものと同じカウンタ変数が使用されます。各インスタンスのカウンタ変数は、開始カウンタ値で始まり、最終カウンタ値まで増える整数値の1つで並行して一意に初期化される必要があります。
flowアクティビティと異なり、forEachアクティビティのパラレル・ブランチの数は設計時には不明です。指定されたカウンタ変数は、パラレル・ブランチ数を使用して繰り返され、開始カウンタ値および最終カウンタ値で制御されます。
「完了」タブで完了条件を指定することもできます。この条件により、forEachアクティビティは条件を実行し、指定されたすべてのブランチを実行または完了しなくても完了できます。例として、並列リクエストを送信し、十分な数の受信者のサブセットが返信したとします。次の状態を回避するために、オプションで完了条件が指定されます。
いくつかの子の実行(順次ケース)
一部の子の強制的な早期終了(パラレル・ケース)
完了条件を指定しない場合、forEachアクティビティは、含まれているscopeが完了したときに完了します。
(フォルトまたはtrue
と評価される完了条件により)早期終了した場合、N+1要件は適用されません。
例9-11に、forEach
アクティビティ構文を示します。
例9-11 forEachアクティビティ
<forEach counterName="MyVariableName" parallel="yes|no" standard-attributes> standard-elements <startCounterValue expressionLanguage="anyURI"?> unsigned-integer-expression </startCounterValue> <finalCounterValue expressionLanguage="anyURI"?> unsigned-integer-expression </finalCounterValue> <completionCondition>? <branches expressionLanguage="anyURI"? successfulBranchesOnly="yes|no"?>? unsigned-integer-expression </branches> </completionCondition> <scope ..>...</scope> </forEach>
forEachアクティビティを作成する手順は、次のとおりです。
「コンポーネント・パレット」で、「BPELコンストラクト」を展開します。
図9-12に示すように、For Eachアクティビティをデザイナにドラッグします。
forEachアクティビティに含まれているscopeアクティビティを確認します。
forEachアクティビティをダブルクリックします。
図9-13に示すように、「一般」タブの「カウンタ名」フィールドにカウンタ値の名前を入力します。
「パラレル実行」チェック・ボックスを確認します。このチェック・ボックスが選択されている場合、すべてのループ反復が同時に開始され、並行して処理されます。
「カウンタの値」タブをクリックします。
図9-14に示すように、開始カウンタ値と最終カウンタ値を入力します。
「完了」タブをクリックします。
forEachアクティビティが条件を実行し、指定されたすべてのブランチを実行または完了しなくても完了できるようにする完了条件を指定する場合は、「式」フィールドの「XPath式ビルダー」アイコンをクリックして、条件を入力します。図9-15に詳細を示します。
「適用」→「OK」の順にクリックします。
ForEachアクティビティに含まれているscopeアクティビティを開きます。
囲まれたscopeアクティビティを設計します。
完了後、forEachアクティビティと含まれているscopeアクティビティは、図9-16のような構造になります。
図9-16 含まれているscopeアクティビティと開いた状態のscopeアクティビティを持つforEachアクティビティ
例9-12に、順に実行されるforEach
アクティビティの設計が完了した後の.bpel
ファイルを示します。
例9-12 forEachアクティビティ - 順次
<faultHandlers> <catch faultName="bpel:invalidBranchCondition"> <sequence> <assign> <copy> <from>'invalidBranchCondition happened'</from> <to>$output.payload</to> </copy> </assign> <reply name="replyOutput" partnerLink="client" portType="tns:Test" operation="process" variable="output"/> </sequence> </catch> </faultHandlers> <sequence> <!-- pick input from requestor --> <receive name="receive" createInstance="yes" partnerLink="client" portType="tns:Test" operation="process" variable="input"/> <assign> <copy> <from>3</from> <to>$request.payload</to> </copy> <copy> <from>''</from> <to>$output.payload</to> </copy> </assign> <forEach counterName="i" parallel="no"> <startCounterValue>$input.payload/tns:startCounter+1</startCounterValue> <finalCounterValue>$input.payload/tns:finalCounter+1</finalCounterValue> <completionCondition> <branches>$input.payload/tns:branches+1</branches> </completionCondition> <scope name="scope1"> <partnerLinks> <partnerLink name="DummyService" partnerLinkType="tns:DummyService" myRole="DummyServiceClient" partnerRole="DummyServiceProvider"/> </partnerLinks> <sequence> <assign> <copy> <from>concat($output.payload, $i, 'A')</from> <to>$output.payload</to> </copy> </assign> <invoke name="invokeDummyService" partnerLink="DummyService" portType="tns:DummyPortType" operation="initiate" inputVariable="request"/> <receive name="receiveFromDummyService" partnerLink="DummyService" portType="tns:DummyCallbackPortType" operation="onResult" variable="response"/> <assign> <copy> <from>concat($output.payload, $i, 'B')</from> <to>$output.payload</to> </copy> </assign> </sequence> </scope> </forEach> <!-- respond output to requestor --> <reply name="replyOutput" partnerLink="client" portType="tns:Test" operation="process" variable="output"/> </sequence>
例9-13に、パラレルforEach
アクティビティの設計が完了した後の.bpel
ファイルを示します。
例9-13 forEachアクティビティ - パラレル
<sequence> <!-- pick input from requestor --> <receive name="receive" createInstance="yes" partnerLink="client" portType="tns:Test" operation="process" variable="input"/> <assign> <copy> <from>$input.payload/tns:value1</from> <to>$request.payload</to> </copy> <copy> <from>''</from> <to>$output.payload</to> </copy> </assign> <forEach counterName="i" parallel="yes"> <startCounterValue>($input.payload/tns:value1 + 1)</startCounterValue> <finalCounterValue>($input.payload/tns:value2 + 2)</finalCounterValue> <scope name="scope1"> <partnerLinks> <partnerLink name="DummyService" partnerLinkType="tns:DummyService" myRole="DummyServiceClient" partnerRole="DummyServiceProvider"/> </partnerLinks> <sequence> <assign> <copy> <from>concat($output.payload, 'A')</from> <to>$output.payload</to> </copy> </assign> <invoke name="invokeDummyService" partnerLink="DummyService" portType="tns:DummyPortType" operation="initiate" inputVariable="request"/> <receive name="receiveFromDummyService" partnerLink="DummyService" portType="tns:DummyCallbackPortType" operation="onResult" variable="response"/> <assign> <copy> <from>concat($output.payload, 'B')</from> <to>$output.payload</to> </copy> </assign> </sequence> </scope> </forEach> <!-- respond output to requestor --> <reply name="replyOutput" partnerLink="client" portType="tns:Test" operation="process" variable="output"/> </sequence>