invoke を使って別 BPEL の同期実行を実施する BPEL プロセスの実行 - Apache ODE を使って
以下の BPMN で表されるようなビジネスプロセスを BPEL で実現してみた。(今回は「レンタカーを予約」のみを別の BPEL として定義した)
- 「予約」処理の概要
- 「ホテルを予約する」と「レンタカーを予約する」を並列実行
- 「レンタカーを予約する」は「レンタカーを予約するか」の条件が「はい」の場合のみ実施
開発・実行環境は前回 id:fits:20080812 と同様に以下のような環境を使用。
なお、今回参考にした書籍は以下。
詳説 ビジネスプロセスモデリング ―SOAベストプラクティス (THEORY/IN/PRACTICE)
- 作者: Michael Havey,長瀬嘉秀(監訳),永田渉(監訳),株式会社テクノロジックアート
- 出版社/メーカー: オライリージャパン
- 発売日: 2006/06/01
- メディア: 単行本
- 購入: 1人 クリック: 55回
- この商品を含むブログ (11件) を見る
「レンタカー予約」BPELプロセスの作成
まず、「レンタカーを予約する」に該当する BPEL プロセスを以下のように作成した。
処理の実装は手抜きして、顧客名の文字列長の先頭に 'resid:' を付けた文字列を「予約ID(reservationId)」として出力するように実装。
なお、createOutput 処理の最初に output 変数の雛形を作成している。
RentalCarReservation.bpel ファイル
<?xml version="1.0" encoding="UTF-8"?> <bpws:process exitOnStandardFault="yes" name="RentalCarReservation" suppressJoinFailure="yes" targetNamespace="http://fits/reservation" xmlns:bpws="http://docs.oasis-open.org/wsbpel/2.0/process/executable" xmlns:tns="http://fits/reservation"> <bpws:import importType="http://schemas.xmlsoap.org/wsdl/" location="RentalCarReservation.wsdl" namespace="http://fits/reservation"/> <bpws:partnerLinks> <bpws:partnerLink myRole="RentalCarReservationProvider" name="client" partnerLinkType="tns:RentalCarReservation"/> </bpws:partnerLinks> <bpws:variables> <bpws:variable messageType="tns:RentalCarReservationRequestMessage" name="input"/> <bpws:variable messageType="tns:RentalCarReservationResponseMessage" name="output"/> </bpws:variables> <bpws:sequence name="main"> <bpws:receive createInstance="yes" name="receiveInput" operation="reserve" partnerLink="client" portType="tns:RentalCarReservation" variable="input"/> <bpws:assign name="createOutput" validate="no"> <!-- output 変数の雛形作成 --> <bpws:copy> <bpws:from> <bpws:literal> <RentalCarReservationResponse xmlns="http://fits/reservation"> <reservationId/> <dateFrom/> <dateTo/> </RentalCarReservationResponse> </bpws:literal> </bpws:from> <bpws:to part="payload" variable="output"/> </bpws:copy> <bpws:copy> <bpws:from part="payload" variable="input"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:dateFrom]]></bpws:query> </bpws:from> <bpws:to part="payload" variable="output"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:dateFrom]]></bpws:query> </bpws:to> </bpws:copy> <bpws:copy> <bpws:from part="payload" variable="input"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:dateTo]]></bpws:query> </bpws:from> <bpws:to part="payload" variable="output"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:dateTo]]></bpws:query> </bpws:to> </bpws:copy> <!-- resid: に customerName の文字列長を付けたものを reservation Id に設定 --> <bpws:copy> <bpws:from><![CDATA[concat('resid:', string-length($input.payload/tns:customerName))]]></bpws:from> <bpws:to part="payload" variable="output"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:reservationId]]></bpws:query> </bpws:to> </bpws:copy> </bpws:assign> <bpws:reply name="replyOutput" operation="reserve" partnerLink="client" portType="tns:RentalCarReservation" variable="output"/> </bpws:sequence> </bpws:process>
RentalCarReservation.wsdl ファイル
<?xml version="1.0"?> <definitions name="RentalCarReservation" targetNamespace="http://fits/reservation" xmlns:tns="http://fits/reservation" xmlns:plnk="http://docs.oasis-open.org/wsbpel/2.0/plnktype" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <types> <schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://fits/reservation" xmlns="http://www.w3.org/2001/XMLSchema"> <element name="RentalCarReservationRequest"> <complexType> <sequence> <element name="customerName" type="xsd:string"></element> <element name="dateFrom" type="xsd:date" /> <element name="dateTo" type="xsd:date"></element> </sequence> </complexType> </element> <element name="RentalCarReservationResponse"> <complexType> <sequence> <element name="reservationId" type="xsd:string" /> <element name="dateFrom" type="xsd:date"></element> <element name="dateTo" type="xsd:date"></element> </sequence> </complexType> </element> </schema> </types> <message name="RentalCarReservationRequestMessage"> <part name="payload" element="tns:RentalCarReservationRequest"/> </message> <message name="RentalCarReservationResponseMessage"> <part name="payload" element="tns:RentalCarReservationResponse"/> </message> <portType name="RentalCarReservation"> <operation name="reserve"> <input message="tns:RentalCarReservationRequestMessage" /> <output message="tns:RentalCarReservationResponseMessage"/> </operation> </portType> <plnk:partnerLinkType name="RentalCarReservation"> <plnk:role name="RentalCarReservationProvider" portType="tns:RentalCarReservation"/> </plnk:partnerLinkType> <binding name="RentalCarReservation" type="tns:RentalCarReservation"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"> </soap:binding> <operation name="reserve"> <soap:operation soapAction="http://fits/reservation/reserve"> </soap:operation> <input> <soap:body use="literal"></soap:body> </input> <output> <soap:body use="literal"></soap:body> </output> </operation> </binding> <service name="RentalCarReservationService"> <port name="RentalCarReservationPort" binding="tns:RentalCarReservation"> <soap:address location="http://localhost:8080/ode/processes/rentalCarReservation" /> </port> </service> </definitions>
「予約」BPELプロセスの作成
メインの BPEL を以下のように作成。「ホテル予約」の処理は手抜きして、このプロセス内で処理を実装している。(固定値を output 変数の hotelReservation に設定する)
主な特徴は以下の通り。
- flow を使ってホテル予約(ReserveHotel)とレンタカー予約(ReserveRentalCar)の並列処理を実装
- if を使って「レンタカー予約」の実行を条件分岐(doCarRental の値が 0 より大きい場合にのみ「レンタカー予約」を実行)
- 別 BPEL で定義した「レンタカー予約」は rentalCar という名称で Partner Link 定義
- InvokeRentalCar で「レンタカー予約」の処理を実行(別 BPEL の処理を実行)
- rentalCar の Partner Link の定義は partnerRole に RentalCarReservationProvider を、myRole は None に設定(同期呼出の場合、MyRole の設定は不要みたい)
- 「レンタカー予約」呼び出しの入力値と出力値を rentalCarInput と rentalCarOutput として Variable 定義
なお、「レンタカー予約」の実行有無を指定する doCarRental の型として xsd:boolean では無く xsd:int を使っているが、これは xsd:boolean での条件判定式が意図したように動作しなかったため。
ちなみに、doCarRental の型が xsd:boolean の場合に条件式 "$input.payload/tns:doCarRental = true()" を
ちなみに、BPEL Visual Designer 上での主な操作は以下のようになる。
- Partner Link(rentalCar)の追加
- Variables(rentalCarInput, rentalCarOutput)の追加
- Variable の追加ボタン押下
- Filter の「Messages」にチェック
- 該当する Message(RentalCarReservationRequestMessage, RentalCarReservationResponseMessage)を選択
TravelReservation.bpel ファイル
<?xml version="1.0" encoding="UTF-8"?> <bpws:process exitOnStandardFault="yes" name="TravelReservation" suppressJoinFailure="yes" targetNamespace="http://fits/reservation" xmlns:bpws="http://docs.oasis-open.org/wsbpel/2.0/process/executable" xmlns:tns="http://fits/reservation"> <bpws:import importType="http://schemas.xmlsoap.org/wsdl/" location="TravelReservation.wsdl" namespace="http://fits/reservation"/> <bpws:import importType="http://schemas.xmlsoap.org/wsdl/" location="RentalCarReservation.wsdl" namespace="http://fits/reservation"/> <bpws:partnerLinks> <bpws:partnerLink myRole="TravelReservationProvider" name="client" partnerLinkType="tns:TravelReservation"/> <bpws:partnerLink name="rentalCar" partnerLinkType="tns:RentalCarReservation" partnerRole="RentalCarReservationProvider"/> </bpws:partnerLinks> <bpws:variables> <bpws:variable messageType="tns:TravelReservationRequestMessage" name="input"/> <bpws:variable messageType="tns:TravelReservationResponseMessage" name="output"/> <bpws:variable messageType="tns:RentalCarReservationRequestMessage" name="rentalCarInput"/> <bpws:variable messageType="tns:RentalCarReservationResponseMessage" name="rentalCarOutput"/> </bpws:variables> <bpws:sequence name="main"> <bpws:receive createInstance="yes" name="receiveInput" operation="reserve" partnerLink="client" portType="tns:TravelReservation" variable="input"/> <bpws:assign name="initOutput" validate="no"> <bpws:copy> <bpws:from> <bpws:literal> <TravelReservationResponse xmlns="http://fits/reservation"> <hotelReservation/> <rentalCarReservation/> </TravelReservationResponse> </bpws:literal> </bpws:from> <bpws:to part="payload" variable="output"/> </bpws:copy> </bpws:assign> <bpws:flow name="Flow"> <bpws:sequence name="ReserveHotel"> <bpws:assign name="createResult" validate="no"> <bpws:copy> <bpws:from> <bpws:literal>id:1001</bpws:literal> </bpws:from> <bpws:to part="payload" variable="output"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:hotelReservation]]></bpws:query> </bpws:to> </bpws:copy> </bpws:assign> </bpws:sequence> <bpws:sequence name="ReserveRentalCar"> <bpws:if name="If"> <bpws:sequence name="Sequence"> <bpws:assign name="createInput" validate="no"> <bpws:copy> <bpws:from> <bpws:literal> <RentalCarReservationRequest xmlns="http://fits/reservation"> <customerName/> <dateFrom/> <dateTo/> </RentalCarReservationRequest> </bpws:literal> </bpws:from> <bpws:to part="payload" variable="rentalCarInput"/> </bpws:copy> <bpws:copy> <bpws:from part="payload" variable="input"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:customerName]]></bpws:query> </bpws:from> <bpws:to part="payload" variable="rentalCarInput"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:customerName]]></bpws:query> </bpws:to> </bpws:copy> <bpws:copy> <bpws:from part="payload" variable="input"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:dateFrom]]></bpws:query> </bpws:from> <bpws:to part="payload" variable="rentalCarInput"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:dateFrom]]></bpws:query> </bpws:to> </bpws:copy> <bpws:copy> <bpws:from part="payload" variable="input"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:dateTo]]></bpws:query> </bpws:from> <bpws:to part="payload" variable="rentalCarInput"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:dateTo]]></bpws:query> </bpws:to> </bpws:copy> </bpws:assign> <bpws:invoke inputVariable="rentalCarInput" name="InvokeRentalCar" operation="reserve" outputVariable="rentalCarOutput" partnerLink="rentalCar" portType="tns:RentalCarReservation"/> <bpws:assign name="createResult" validate="no"> <bpws:copy> <bpws:from><![CDATA[$rentalCarOutput.payload/tns:reservationId]]></bpws:from> <bpws:to part="payload" variable="output"> <bpws:query queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath1.0"><![CDATA[/tns:rentalCarReservation]]></bpws:query> </bpws:to> </bpws:copy> </bpws:assign> </bpws:sequence> <bpws:condition><![CDATA[$input.payload/tns:doCarRental > 0]]></bpws:condition> </bpws:if> </bpws:sequence> </bpws:flow> <bpws:reply name="replyOutput" operation="reserve" partnerLink="client" portType="tns:TravelReservation" variable="output"/> </bpws:sequence> </bpws:process>
TravelReservation.wsdl ファイル
<?xml version="1.0"?> <definitions name="TravelReservation" targetNamespace="http://fits/reservation" xmlns:tns="http://fits/reservation" xmlns:plnk="http://docs.oasis-open.org/wsbpel/2.0/plnktype" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <types> <schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://fits/reservation" xmlns="http://www.w3.org/2001/XMLSchema"> <element name="TravelReservationRequest"> <complexType> <sequence> <element name="customerName" type="xsd:string" /> <element name="dateFrom" type="xsd:date" /> <element name="dateTo" type="xsd:date" /> <element name="doCarRental" type="xsd:int" /> </sequence> </complexType> </element> <element name="TravelReservationResponse"> <complexType> <sequence> <element name="hotelReservation" type="xsd:string" /> <element name="rentalCarReservation" type="xsd:string" /> </sequence> </complexType> </element> </schema> </types> <message name="TravelReservationRequestMessage"> <part name="payload" element="tns:TravelReservationRequest"/> </message> <message name="TravelReservationResponseMessage"> <part name="payload" element="tns:TravelReservationResponse"/> </message> <portType name="TravelReservation"> <operation name="reserve"> <input message="tns:TravelReservationRequestMessage" /> <output message="tns:TravelReservationResponseMessage"/> </operation> </portType> <plnk:partnerLinkType name="TravelReservation"> <plnk:role name="TravelReservationProvider" portType="tns:TravelReservation"/> </plnk:partnerLinkType> <binding name="TravelReservationBinding" type="tns:TravelReservation"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"> </soap:binding> <operation name="reserve"> <soap:operation soapAction="http://fits/reservation/reserve"> </soap:operation> <input> <soap:body use="literal"></soap:body> </input> <output> <soap:body use="literal"></soap:body> </output> </operation> </binding> <service name="TravelReservationService"> <port name="TravelReservationPort" binding="tns:TravelReservationBinding"> <soap:address location="http://localhost:8080/ode/processes/travelReservation" /> </port> </service> </definitions>
デプロイ
以下のような Apache ODE へのデプロイファイルを作成し、前項までに作成した .bpel・.wsdl ファイルと共に任意のディレクトリに配置して Apache ODE にデプロイ。(ディレクトリごと webapps/ode/WEB-INF/processes/ に配置)
deploy.xml ファイル
<?xml version="1.0" encoding="UTF-8"?> <deploy xmlns="http://www.apache.org/ode/schemas/dd/2007/03" xmlns:pns="http://fits/reservation"> <!-- レンタカー予約サービスの定義 --> <process name="pns:RentalCarReservation"> <active>true</active> <provide partnerLink="client"> <service name="pns:RentalCarReservationService" port="RentalCarReservationPort"/> </provide> </process> <!-- 予約サービスの定義 --> <process name="pns:TravelReservation"> <active>true</active> <provide partnerLink="client"> <service name="pns:TravelReservationService" port="TravelReservationPort"/> </provide> <invoke partnerLink="rentalCar"> <service name="pns:RentalCarReservationService" port="RentalCarReservationPort"/> </invoke> </process> </deploy>
動作確認
まず、以下の URL にアクセスして 「レンタカー予約(RentalCarReservation)」が正常に実行できることを確認。
「レンタカー予約」実行 URL
http://localhost:8080/ode/processes/rentalCarReservation/reserve?customerName=abcd&dateFrom=2008-08-18&dateTo=2008-08-19
「レンタカー予約」実行結果
<RentalCarReservationResponse xmlns="http://fits/reservation"> <reservationId>resid:4</reservationId> <dateFrom>2008-08-18</dateFrom> <dateTo>2008-08-19</dateTo> </RentalCarReservationResponse>
次に、以下の URL にアクセスして「予約(TravelReservation)」が正常に実行され、「レンタカー予約(RentalCarReservation)」を呼び出している事を確認。
「レンタカー予約」を実行する「予約」実行 URL
http://localhost:8080/ode/processes/travelReservation/reserve?customerName=abcd&dateFrom=2008-08-18&dateTo=2008-08-19&doCarRental=1
「レンタカー予約」を実行する「予約」実行結果
<TravelReservationResponse xmlns="http://fits/reservation"> <hotelReservation>id:1001</hotelReservation> <rentalCarReservation>resid:4</rentalCarReservation> </TravelReservationResponse>
最後に、以下の URL にアクセスして doCarRental が 0以下の場合に、「レンタカー予約(RentalCarReservation)」を呼び出さない事を確認。
「レンタカー予約」を実行しない「予約」実行 URL
http://localhost:8080/ode/processes/travelReservation/reserve?customerName=abcd&dateFrom=2008-08-18&dateTo=2008-08-19&doCarRental=0
「レンタカー予約」を実行しない「予約」実行結果
<TravelReservationResponse xmlns="http://fits/reservation"> <hotelReservation>id:1001</hotelReservation> <rentalCarReservation /> </TravelReservationResponse>