この章では、XMLデータをBPELで操作する方法について、XPath式の使用を含めて説明します。
この章の内容は次のとおりです。
この章では、XMLデータ操作方法を示す様々なユースケースについて説明します。変数、シーケンスおよび配列の使用方法と、数学的計算などのタスクの実行方法に関するトピックが含まれています。 サポートされる仕様に親しめるようになる例を中心に説明しています。
この章の大部分の例では、関連するメッセージ・タイプを定義するWSDLファイルは、RPC形式ではなくドキュメント・リテラル形式であると想定しています。RPC形式のWSDL定義の場合、XPath問合せ文字列の構成方法に違いがあります。RPCのWSDLファイルで定義されたタイプを使用している場合は、「ドキュメント形式とRPC形式のWSDLファイルの違い」を参照してください。
関連項目: サンプル・ファイルは、次の場所にあります。
|
この項の内容は次のとおりです。
BPELプロセスでは、データの全部分がXML書式を取ります。 このようなデータとしては、BPELプロセスがやり取りするメッセージ、外部サービスと交換されるメッセージおよびプロセスで使用されるローカル変数も含まれます。 これらのメッセージおよび変数のタイプは、通常はフローのWSDLファイル、起動するサービスのWSDLファイルまたはこれらのWSDLファイルで参照されるXSDファイル内に、XMLスキーマで定義します。このため、BPEL内のすべての変数がXMLデータであり、BPELプロセスはコードの大半をこれらのXML変数の操作に使用します。このような操作の代表例には、様々なサービスに必要なデータ表現のトランスフォーメーションの実行、およびデータのローカル操作(複数のサービスを起動して得た結果を連結するなど)があります。
BPELのデータ操作は、XPath標準に基づくassignアクティビティが開始点になります。このタイプの操作では多くの場合、XPath問合せ、式および関数が使用されます。また、XQuery、XSLTまたはJavaを必要とするさらに高度な方法も使用できます(通常は、より複雑なデータ・トランスフォーメーションや操作を実行する場合)。
この項では、BPELでのXMLデータの操作方法について一般的な概要を示します。様々な組合せに使用される主要なビルディング・ブロックの概要と、例を示します。この章の残りの各項では、特定のタスクを実行するためにこれらのビルディング・ブロックを適用する方法も説明します。assign
アクティビティを使用すると、1つのXML変数から別のXML変数へデータをコピーしたり、式の値を計算して変数に格納できます。アクティビティ内のコピー要素は、割当てのソースとターゲット(コピー元とコピー先)を指定します。これらのソースとターゲットは、互換性のあるタイプである必要があります。「Business Process Execution Language for Web Services Specification」に示されている正式な構文は次のとおりです。
<assign standard-attributes> standard-elements <copy>+ from-spec to-spec </copy> </assign>
この構文は、その仕様で詳細に説明されています。通常、from-spec
およびto-spec
では、次のように変数または変数パートを指定します。
<assign> <copy> <from variable="c1" part="address"/> <to variable="c3"/> </copy> </assign>
Oracle JDeveloperを使用する場合は、「From」セクションと「To」セクションを含む「コピー操作」ウィンドウでassignアクティビティの詳細を指定します。これにより、前述のBPELソース・コードの構文が反映されます。
この章では、すべての構文詳細を繰り返すのではなく、主にSOA_Oracle_Home
¥bpel¥samples¥references
ディレクトリにあるサンプル・プロジェクトからの抜粋を示して説明します。
XPath標準は、assignアクティビティで主要な役割を果たします。概要として簡単な例を示します。その他のコンテキストでの例と説明は、次の項で示します。
XPath問合せ: XPath問合せは、ソースまたはターゲットの変数パート内のフィールドを選択します。from
句またはto
句には、値がXPath問合せ文字列である問合せ属性を含めることができます。次に例を示します。
<from variable="input" part="payload" query="/p:CreditFlowRequest/p:ssn"/>
XPathバージョン1.0では、問合せ属性の値は必ず1つのノードのみを選択するパスである必要があります。問合せ属性およびXPath標準の構文の詳細は、それぞれ「Business Process Execution Language for Web Services Specification」の項、および「XML Path Language (XPath) Specification」を参照してください。
XPath式: XPath式(from
句のexpression
属性で指定)を使用して、変数に格納する値を指定します。次に例を示します。
<from expression="100"/>
expressionには一般的な式、つまりXPath値タイプと評価されるXPath式を使用できます。XPath式の詳細は、「XML Path Language (XPath) Specification」の項を参照してください。
XPath式内では、次の種類の関数をコールできます。
コアXPath関数: XPathでは、文字列操作関数(concat
など)や数値関数(sum
など)を含む多数の組込み関数がサポートされています。
<from expression="concat('string one', 'string two')"/>
XPath標準に組み込まれている関数の完全なリストは、「XML Path Language (XPath) Specification」の項を参照してください。
BPEL XPath拡張関数: BPELでは、XPath式がプロセスからの情報にアクセスできるように、コアXPathのコア関数にいくつかの拡張関数が追加されています。拡張関数は、標準BPELネームスペースhttp://schemas.xmlsoap.org/ws/2003/03/business-process/
で定義され、接頭辞bpws
:によって指定されます。
<from expression= "bpws:getVariableData('input', 'payload', '/p:value') + 1"/>
詳細は、「Business Process Execution Language for Web Services Specification」の項を参照してください。
Oracle BPEL XPath拡張関数: 新しい関数を追加するためにBPELおよびXPath標準に組み込まれた機能を使用するその他のXPath関数が用意されています。
これらの関数は、ネームスペースhttp://schemas.oracle.com/xpath/extension
で定義され、接頭辞ora:
によって指定されます。
カスタム関数: カスタムXPath関数も作成できます。作成する場合は、BPELプロセス・デプロイメント・ディスクリプタまたは次のXMLファイルにそれらの関数を登録する必要があります。
SOA_Oracle_Home
¥bpel¥system¥config¥xpath-functions.xml
(システム・レベル)
SOA_Oracle_Home
¥bpel¥domains¥default¥config¥xpath-functions.xml
(ドメイン・レベル)
次に、それらを実装するソースをBPELスーツケースまたはOracle BPEL Process Manager起動環境にパッケージ化します。カスタムXPath関数の記述の詳細は、http://www.oracle.com/technology/bpel
を参照してください。
高度なデータ操作をBPELのassignアクティビティやコアXPath関数で実行するのは困難な場合があります。 しかし、複雑なデータ操作やデータ・トランスフォーメーションは、XSLT、Javaまたはassignアクティビティのbpelx
操作(「bpelx拡張要素を使用したXMLデータの操作」を参照)を使用したり、Webサービスとして実行することが可能です。BPEL内からのJavaコードのコールの詳細は、http://www.oracle.com/technology/bpel
の「BPEL Tutorials」リンクを参照してください。XSLTのトランスフォーメーションについては、これらを実行するXPath関数がOracle BPEL Process Managerに用意されています。
関連項目: 次にあるXPathトランスフォーメーションおよびXQueryトランスフォーメーションのコード例を参照してください。
|
次の各項では、例が理解しやすいように、BPELファイルおよびWSDLファイルでの関連定義を示しています。
BPELでは、リテラルXMLを変数に割り当てる方法が役立つことがよくあります。たとえば、動的データを変数に対するXMLデータ・コンテンツ内の特定のフィールドにコピーする前に、変数を初期化する場合などです。また、XMLデータ値をプロセスにハード・コーディングするときのテストにも役立ちます。
この例では、リテラルのresult
要素をoutput
変数のpayload
パートに割り当てます。
<assign> <!-- copy from literal xml to the variable --> <copy> <from> <result xmlns="http://samples.otn.com"> <name/> <symbol/> <price>12.3</price> <quantity>0</quantity> <approved/> <message/> </result> </from> <to variable="output" part="payload"/> </copy> </assign>
関連項目: 次のサンプルを参照してください。
|
変数間のコピーでは、1つの変数(またはパート)から互換性のあるタイプの別の変数に直接コピーします。どちらの変数でも特定のフィールドを指定する必要はありません。つまり、XPath問合せを指定する必要がありません。次の例では、2つの割当て(同じタイプの2つの変数間のコピーと、同じタイプのパートを持つ別の変数への変数パートのコピー)を実行します。
<assign> <copy> <from variable="c1"/> <to variable="c2"/> </copy> <copy> <from variable="c1" part = "address"/> <to variable="c3"/> </copy> </assign>
BPELファイルでは変数を次のように定義します。
<variable name="c1" messageType="x:person"/> <variable name="c2" messageType="x:person"/> <variable name="c3" element="x:address"/>
WSDLファイルでは個人メッセージ・タイプを次のように定義します。
<message name="person" xmlns:x="http://tempuri.org/bpws/example"> <part name="full-name" type="xsd:string"/> <part name="address" element="x:address"/> </message>
関連項目: このコードの例は、「Business Process Execution Language for Web Services Specification」の項を参照してください。 |
ほとんどのWSDLファイルやXSDファイルに定義のタイプが存在する場合は、要素およびメッセージ・タイプに基づいて変数パート内のコピー元またはコピー先フィールドのレベルに移動し、そこでXMLスキーマの複合型を使用する必要があります。このためには、assignアクティビティのfrom
句またはto
句でXPath問合せを指定します。
この例ではCreditFlow
プロセスの入力メッセージのssn
フィールドを、信用格付けサービスの入力メッセージのssn
フィールドにコピーしています。
<assign> <copy> <from variable="input" part="payload" query="/tns:CreditFlowRequest/tns:ssn"/> <to variable="crInput" part="payload" query="/tns:ssn"/> </copy> </assign>
BPELファイルでは、この割当てに必要な変数を次のように定義します。
<variable name="input" messageType="tns:CreditFlowRequestMessage"/> <variable name="crInput" messageType="services:CreditRatingServiceRequestMessage"/>
crInput
変数は、信用格付けサービスへの入力メッセージとして使用されます。そのメッセージ・タイプCreditFlowRequestMessage
は、CreditFlowService.wsdl
で次のように定義されます。
<message name="CreditFlowRequestMessage"> <part name="payload" element="tns:CreditFlowRequest"/> </message>
CreditFlowRequest
は、ssn
という名前のフィールドを持つように定義されます。メッセージ・タイプCreditRatingServiceRequestMessage
は、CreditRatingService.wsdl
で次のように定義されます。
<message name="CreditRatingServiceRequestMessage"> <part name="payload" element="tns:ssn"/> </message>
関連項目: 次のサンプルを参照してください。
|
XPath式では数値を割り当てることができます。次の例は、XPath式に整数値100
を割り当てる方法を示しています。
<assign> <!-- copy from integer expression to the variable --> <copy> <from expression="100"/> <to variable="output" part="payload" query="/p:result/p:quantity"/> </copy> </assign>
関連項目: 次のサンプルを参照してください。
|
次の例の式のように、単純な計算式を使用して、数値を増分させることができます。
この例では、BPEL XPath関数getVariableData
により、増分した値が取得されます。getVariableData
への引数は、from
句の値、パートおよび問合せ属性と同じです(オプションの最後の2つの引数を含む)。
<assign> <copy> <from expression="bpws:getVariableData('input', 'payload', '/p:value') + 1"/> <to variable="output" part="payload" query="/p:result"/> </copy> </assign>
次のように$variable
構文を使用することも可能です。
<assign> <copy> <from expression="$input.payload + 1"/> <to variable="output" part="payload" query="/p:result"/> </copy> </assign>
関連項目: 次のサンプルを参照してください。
|
この例では、文字列リテラル'GE'
から評価される式を、指定された変数パート内のsymbolフィールドにコピーしています。(二重引用符および一重引用符を使用していることに注意してください。)
<assign> <!-- copy from string expression to the variable --> <copy> <from expression="'GE'"/> <to variable="output" part="payload" query="/p:result/p:symbol"/> </copy> </assign>
関連項目: 次のサンプルを参照してください。
|
1つの文字変数(または変数パート、フィールド)の値を別の値にコピーするのではなく、いくつかの文字列を連結するなどの文字列操作を最初に実行できます。次の構文に示す例を参照してください。連結はconcat
という名前のコアXPath関数で実行されます。また、連結に必要な変数値は、BPEL XPath関数getVariableData
によって取得されます。
この例では、getVariableData
がinput
変数のpayload
パートからnameフィールドの値をフェッチします。次に、文字リテラル'Hello '
が、この値の先頭に連結されます。
<assign> <!-- copy from XPath expression to the variable --> <copy> <from expression="concat('Hello ', bpws:getVariableData('input', 'payload', '/p:name'))"/> <to variable="output" part="payload" query="/p:result/p:message"/> </copy> </assign>
XPathで使用可能なその他の文字操作関数は、「XML Path Language (XPath) Specification」の項を参照してください。
関連項目: 次のサンプルを参照してください。
|
このブール値の割当ての例では、from
句のXPath式はXPathのブール関数true
へのコールであり、指定されたapprovedフィールドがtrue
に設定されます。関数false
も使用できます。
<assign> <!-- copy from boolean expression function to the variable --> <copy> <from expression="true()"/> <to variable="output" part="payload" query="/result/approved"/> </copy> </assign>
XPath仕様では、ブール定数値を戻すメソッドとして"true()"
および"false()"
関数を使用するように推奨しています。
かわりに"boolean(true)"
または"boolean(false)"
を使用すると、ブール関数内のtrue
またはfalse
はtrueまたはfalse定数ではなく相対要素ステップとして解釈されます。つまり、現行のXPathコンテキスト・ノードでtrue
という子ノードの選択が試行されます。ほとんどの場合、true
ノードは存在しません。したがって、空の結果ノード・セットが戻され、それがXPath 1.0のboolean()
関数によりfalseの結果に変換されます。この結果は混同される可能性があります。
関連項目: 次のサンプルを参照してください。
|
Oracle BPEL XPath関数のgetCurrentDate
、getCurrentTime
またはgetCurrentDateTime
を使用して、日付または時刻フィールドの現在値を割り当てることができます。 また、日時の値が標準のXSD形式の場合、Oracle BPEL XPath関数formatDate
をコールして、出力に適した文字列に変換できます。詳細は、「Business Process Execution Language for Web Services Specification」の項を参照してください。
<!-- execute the XPath extension function getCurrentDate() --> <assign> <copy> <from expression="ora:getCurrentDate()"/> <to variable="output" part="payload" query="/invoice/invoiceDate"/> </copy> </assign>
次の例では、XSD形式で与えられた日時の値をformatDate
関数が文字列'Jun 10, 2005'
に変換し、文字列フィールドformattedDate
に割り当てています。
<!-- execute the XPath extension function formatDate() --> <assign> <copy> <from expression="ora:formatDate('2005-06-10T15:56:00', 'MMM dd, yyyy')"/> <to variable="output" part="payload" query="/invoice/formattedDate"/> </copy> </assign>
関連項目: 次のサンプルを参照してください。
|
XML属性として定義されているものとの間で、コピーすることが必要になる場合があります。XPath問合せ構文では、@
記号は子要素のかわりに属性を参照します。
次のコード例では、このXMLデータからcustId
属性をフェッチし、コピーしています。
<invalidLoanApplication xmlns="http://samples.otn.com"> <application xmlns = "http://samples.otn.com/XPath/autoloan"> <customer custId = "111" > <name> Mike Olive </name> ... </customer> ... </application> </invalidLoanApplication>
次の例はcustomerフィールドのcustId
属性を選択し、変数custId
に割り当てています。
<assign> <!-- get the custId attribute and assign to variable custId --> <copy> <from variable="input" part="payload" query="/tns:invalidLoanApplication/autoloan:application /autoloan:customer/@custId"/> <to variable="custId"/> </copy> </assign>
この例のネームスペース接頭辞は、必須ではありません。WSDLファイルは次のように、属性としてcustId
が定義された型を持つように顧客を定義します。
<complexType name="CustomerProfileType"> <sequence> <element name="name" type="string"/> ... </sequence> <attribute name="custId" type="string"/> </complexType>
関連項目: 次のサンプルを参照してください。
|
assignアクティビティでXMLデータに対して各種操作を実行できます。 この機能は、次のbpelx
拡張タイプにより提供されます。
assignアクティビティでbpelx:append
拡張要素を使用すると、BPELプロセスは1つの変数、式またはXMLフラグメントの内容を別の変数の内容に追加できます。
<bpel:assign> <bpelx:append> <bpelx:from ... /> <bpelx:to ... /> </bpelx:append> </bpel:assign>
bpelx:append
内のfrom-spec
問合せでは、0(ゼロ)個以上のノードが取得されます。 ノード・リストは、to-spec
問合せで指定したターゲット・ノードに子ノードとして追加されます。
to-spec
問合せでは、単一L-Value要素ノードを1つ取得する必要があります。 それ以外の場合は、bpel:selectionFailure
フォルトが生成されます。 to-spec
問合せではパートナ・リンクを参照できません。
次の例では、1つのBOMの複数のb:part
を連結BOMのb:part
に追加することで、複数の部品表を1つの部品表に連結しています。
<bpel:assign> <bpelx:append> <from variable="billOfMaterialVar" query="/b:bom/b:parts/b:part" /> <to variable="consolidatedBillOfMaterialVar" query="/b:bom/b:parts" /> </bpelx:append> </bpel:assign>
assignアクティビティでbpelx:insertBefore
拡張要素を使用すると、BPELプロセスは1つの変数、式またはXMLフラグメントの内容を別の変数の内容の前に挿入できます。
<bpel:assign> <bpelx:insertBefore> <bpelx:from ... /> <bpelx:to ... /> </bpelx:insertBefore> </bpel:assign>
bpelx:insertBefore
内のfrom-spec
問合せでは、0(ゼロ)個以上のノードが取得されます。 ノード・リストは、to-spec
問合せで指定したターゲット・ノードに子ノードとして追加されます。
insertBefore
操作のto-spec
問合せは、1つ以上の単一L-Valueノードを指します。 複数のノードが返された場合は、最初のノードが参照ノードとして使用されます。 参照ノードは要素ノードである必要があります。 参照ノードの親も要素ノードである必要があります。 それ以外の場合は、bpel:selectionFailure
フォルトが生成されます。 from-spec
問合せの選択により生成されたノード・リストは、参照ノードの前に挿入されます。 to-spec問合せではパートナ・リンクを参照できません。
次の例に、<insertBefore>
の実行前の構文を示します。 addrVar
の値は次のとおりです。
<a:usAddress> <a:state>CA</a:state> <a:zipcode>94065</a:zipcode> </a:usAddress>
BPELプロセス・ファイルで次の構文を実行します。
<bpel:assign>
<bpelx:insertBefore>
<bpelx:from>
<a:city>Redwood Shore></a:city>
</bpelx:from>
<bpelx:to "addrVar" query="/a:usAddress/a:state" />
</bpelx:insertBefore>
</bpel:assign>
addrVarの値は次のようになります。
<a:usAddress>
<a:city>Redwood Shore</a:city>
<a:state>CA</a:state>
<a:zipcode>94065</a:zipcode>
</a:usAddress>
assignアクティビティでbpelx:insertAfter
拡張要素を使用すると、BPELプロセスは1つの変数、式またはXMLフラグメントの内容を別の変数の内容の後に挿入できます。
<bpel:assign> <bpelx:insertAfter> <bpelx:from ... /> <bpelx:to ... /> </bpelx:insertAfter> </bpel:assign>
この操作は「bpelx:insertBefore」で説明した機能に似ていますが、次の違いがあります。
to-spec
問合せで複数のL-Valueノードが返される場合は、最後のノードが参照ノードとして使用されます。
参照ノードの前にノードが挿入されるかわりに、参照ノードの後にソース・ノードが挿入されます。
この操作は、conditional-switch
+
(append
またはinsertBefore
)のマクロとみなすこともできます。
次の例に、<insertAfter>
の実行前の構文を示します。 addrVar
の値は次のとおりです。
<a:usAddress> <a:addressLine>500 Oracle Parkway</a:addressLine> <a:state>CA</a:state> <a:zipcode>94065</a:zipcode> </a:usAddress>
BPELプロセス・ファイルで次の構文を実行します。
<bpel:assign>
<bpelx:insertAfter>
<bpelx:from>
<a:addressLine>Mailstop 1op6</a:addressLine>
</bpelx:from>
<bpelx:to "addrVar" query="/a:usAddress/a:addressLine[1]" />
</bpelx:insertAfter>
</bpel:assign>
addrVar
の値は次のようになります。
<a:usAddress>
<a:addressLine>500 Oracle Parkway</a:addressLine>
<a:addressLine>Mailstop 1op6</a:addressLine>
<a:state>CA</a:state>
<a:zipcode>94065</a:zipcode>
</a:usAddress>
bpelx:insertAfter
内のfrom-spec
問合せでは、0(ゼロ)個以上のノードが取得されます。 ノード・リストは、to-spec
問合せで指定したターゲット・ノードに子ノードとして追加されます。
assignアクティビティでbpelx:remove
拡張要素を使用すると、BPELプロセスは変数を削除できます。
<bpel:assign> <bpelx:remove> <bpelx:target variable="ncname" part="ncname"? query="xpath_str" /> </bpelx:append> </bpel:assign>
XPath式で指定したノード削除がサポートされます。 XPath式では複数のノードを指定できますが、いずれもL-Valueである必要があります。 この親からは、テキスト・ノード、属性ノードおよび要素ノードを削除できます。
XPath式では、1つ以上のノードを返すことができます。 XPath式で0(ゼロ)子のノードが返される場合は、bpel:selectionFailure
フォルトが生成されます。
bpelx:target
の構文は、copy
操作のto-spec
に類似しており、そのサブセットです。
次の例にaddrVar
を示します。値は次のとおりです。
<a:usAddress> <a:addressLine>500 Oracle Parkway</a:addressLine> <a:addressLine>Mailstop 1op6</a:addressLine> <a:state>CA</a:state> <a:zipcode>94065</a:zipcode> </a:usAddress>
BPELプロセス・ファイルで次の構文を実行すると、Mailstop
の2番目のアドレス行が削除されます。
<bpel:assign>
<bpelx:remove>
<target variable="addrVar"
query="/a:usAddress/a:addressLine[2]" />
</bpelx:remove>
</bpel:assign>
BPELプロセス・ファイル内で次の構文を実行すると、両方のアドレス行が削除されます。
<bpel:assign>
<bpelx:remove>
<target variable="addrVar"
query="/a:usAddress/a:addressLine" />
</bpelx:remove>
</bpel:assign>
assignアクティビティでbpelx:rename
拡張要素を使用すると、BPELプロセスはXSDタイプ・キャストを使用して要素名を変更できます。
<bpel:assign> <bpelx:rename elementTo="QName1"? typeCastTo="QName2"?> <bpelx:target variable="ncname" part="ncname"? query="xpath_str" /> </bpelx:rename> </bpel:assign>
bpelx:target
の構文は、copy
操作のto-spec
に類似しており、そのサブセットです。 ターゲットはさらに1つの要素ノードのリストを返す必要があります。 それ以外の場合は、bpel:selectionFailure
フォルトが生成されます。 from-spec
で指定した要素ノードが、elementTo
属性で指定したQName
に名前変更されます。 その要素ノードにxsi:type
属性が追加され、それらの要素がtypeCastTo
属性で指定したQName
タイプにキャストされます。
次の従業員リストがあるとします。
<e:empList> <e:emp> <e:firstName>John</e:firstName><e:lastName>Dole</e:lastName> <e:emp> <e:emp xsi:type="e:ManagerType"> <e:firstName>Jane</e:firstName><e:lastName>Dole</e:lastName> <e:approvalLimit>3000</e:approvalLimit> <e:managing /> <e:emp> <e:emp> <e:firstName>Peter</e:firstName><e:lastName>Smith</e:lastName> <e:emp> <e:emp> <e:firstName>Mary</e:firstName><e:lastName>Smith</e:lastName> <e:emp> </e:empList>
プロモーションの変更が従業員リストのPeter Smith
に適用されます。
<bpel:assign> <bpelx:rename typeCastTo="e:ManagerType"> <bpelx:target variable="empListVar" query="/e:empList/e:emp[./e:firstName='Peter' and ./e:lastName='Smith'" /> </bpelx:rename> </bpel:assign>
前述のキャスト(名前変更)の実行後は、Peter Smith
にxsi:type
情報が追加され、データは次のようになります。
<e:empList>
<e:emp>
<e:firstName>John</e:firstName><e:lastName>Dole</e:lastName>
<e:emp>
<e:emp xsi:type="e:ManagerType">
<e:firstName>Jane</e:firstName><e:lastName>Dole</e:lastName>
<e:approvalLimit>3000</e:approvalLimit>
<e:managing />
<e:emp>
<e:emp xsi:type="e:ManagerType">
<e:firstName>Peter</e:firstName><e:lastName>Smith</e:lastName>
<e:emp>
<e:emp>
<e:firstName>Mary</e:firstName><e:lastName>Smith</e:lastName>
<e:emp>
</e:empList>
<approvalLimit>
および<managing>
が欠落しているため、Peter Smith
の従業員データは無効になっています。 したがって、その情報を追加するために<append>
が使用されます。
<bpel:assign> <bpelx:rename typeCastTo="e:ManagerType"> <bpelx:target variable="empListVar" query="/e:empList/e:emp[./e:firstName='Peter' and ./e:lastName='Smith'" /> </bpelx:rename> <bpelx:append> <bpelx:from> <e:approvalLimit>2500</e:approvalLimit> <e:managing /> </bpelx:from> <bpelx:to variable="empListVar" query="/e:empList/e:emp[./e:firstName='Peter' and ./e:lastName='Smith'" /> </bpelx:append> </bpel:assign>
rename
およびappend
の両方を実行すると、対応するデータは次のようになります。
<e:emp xsi:type="e:ManagerType"> <e:firstName>Peter</e:firstName><e:lastName>Smith</e:lastName> <e:approvalLimit>2500</e:approvalLimit> <e:managing /> <e:emp>
assignアクティビティでbpelx:copyList
拡張要素を使用すると、BPELプロセスは1つの変数、式またはXMLフラグメントの内容に対して別の変数へのcopyList
操作を実行できます。
<bpel:assign> <bpelx:copyList> <bpelx:from ... /> <bpelx:to ... /> </bpelx:copyList> </bpel:assign>
from-spec
問合せでは、すべての属性ノードまたはすべての要素ノードのリストを取得できます。 to-spec
問合せでは、L-valueノード(すべての属性ノードまたはすべての要素ノード)のリストを取得できます。
to-spec
問合せで返される要素ノードは、すべて同じ親要素を持つ必要があります。 to-spec
問合せで要素ノードのリストが返される場合、すべての要素ノードが連続している必要があります。
from-spec
問合せで属性ノードが返される場合、to-spec
問合せでは属性ノードが返される必要があります。 同様に、from-spec
問合せで要素ノードが返される場合、to-spec
問合せでは要素ノードが返される必要があります。 それ以外の場合は、bpws:mismatchedAssignmentFailure
フォルトがスローされます。
from-spec
問合せでは0(ゼロ)個のノードを返すことができますが、to-spec
問合せではノードを1個以上返す必要があります。 from-spec
問合せで0(ゼロ)個のノードが返される場合、copyList
操作の効果はremove
操作と同様になります。
copylist
操作には、次の機能があります。
to-spec
問合せが指すノードがすべて削除されます。
to-spec
問合せで要素ノードのリストが返され、そのノードが削除された後に子ノードが残っている場合、from-spec
問合せで返されたノードはto-spec
問合せで指定した最後の要素と同レベルの次の要素の前に挿入されます。 残りの子ノードがなければ、append
操作が実行されます。
to-spec
問合せで属性ノードのリストが返される場合は、その属性が親要素から削除されます。 次に、from-spec
問合せで返された属性が親要素に追加されます。
bpelx:validate
関数を使用すると、コードを検証して無効なXMLデータを識別できます。 この拡張要素の使用方法は次のとおりです。
assign
アクティビティのvalidate
属性内では、次のように使用します。
<assign bpelx:validate="yes|no">
...
</assign>
<bpelx:validate>
内で、assign
アクティビティなしで使用可能なスタンドアロン拡張アクティビティとして次のように使用します。
<bpelx:validate variables="NCNAMES" />
たとえば、次のようになります。
<bpelx:validate variables="myMsgVariable myPOElemVar" />
XMLデータの妥当性を検証するには、Oracle BPEL Controlの「BPELドメインの管理」ウィンドウでvalidateXMLプロパティをtrueに設定します。
データ・シーケンスは、XMLで使用される最も基本的なデータ・モデルの1つです。しかし、データ・シーケンスの操作がポイントになる場合があります。BPELプロセスで使用される最も一般的なデータ・シーケンス・パターンの1つが配列です。XMLスキーマに基づき、データ・シーケンス定義はその属性maxOccurs
から識別できます。この属性が、1より大きい値に設定されているか、unboundedとしてマークされています。詳細は、XMLスキーマ仕様http://www.w3.org/TR
を参照してください。
この項では、BPELでのデータ・シーケンス操作の基本方法の例をいくつか示しています。ただし、ループやエンドポイントの動的参照の実行など、その他の要件が存在します。その他のコード例およびBPELでのデータ・シーケンス操作に関する実際の使用例は、http://www.oracle.com/technology/bpel
を参照してください。次の各項では、データ・シーケンス操作の特定の要件について説明します。すべてのデータ・シーケンスを説明するコード例は、ArraySample.bpel
を参照してください。ここでは、入力としてデータ・シーケンスを受け取り、ループして、各データ・シーケンス要素の個々の明細項目を合計値として加算します。
関連項目: ArraySample.bpel サンプル・ファイルは、次の場所にあります。
|
必要な要素索引が設計時にわかっているとき、XPath機能を使用してデータ・シーケンス要素を選択する方法を次の2つの例で示します。これらのケースでは、最初の要素です。
次の例では、addresses[1]
はaddressesデータ・シーケンスの最初の要素を選択します。
<assign> <!-- get the first address and assign to variable address --> <copy> <from variable="input" part="payload" query="/tns:invalidLoanApplication/autoloan:application /autoloan:customer/autoloan:addresses[1]"/> <to variable="address"/> </copy> </assign>
この問合せでは、addresses[1]
はaddresses[position()=1]
と同じです。ここで、position
はコアXPath関数の1つです(「XML Path Language (XPath) Specification」の項を参照)。次の例の問合せでは、position関数を明示的にコールしてaddressesデータ・シーケンスの最初の要素を選択します。次に、そのアドレスのstreet
要素(アクティビティで変数street1
に割り当てられたもの)を選択します。
<assign> <!-- get the first address's street and assign to street1 --> <copy> <from variable="input" part="payload" query="/tns:invalidLoanApplication/autoloan:application /autoloan:customer/autoloan:addresses[position()=1] /autoloan:street"/> <to variable="street1"/> </copy> </assign>
WSDLファイルで入力変数の定義とそのペイロード・パートを確認する際、addressesフィールドの定義に到達するまでに、いくつかのレベルを下っていきます。そこでmaxOccurs="unbounded"
属性を確認できます。2つのXPath索引付けメソッドは機能的には同じなので、どちらを使用してもかまいません。
関連項目: 次のサンプルを参照してください。
|
データ・シーケンスの実行時のサイズ、つまりシーケンス内のノードまたはデータ項目の数を知る必要がある場合、XPath組込み関数count()
とBPEL組込み関数getVariableData()
を組み合せて使用することで取得できます。
この例では、item
シーケンスの要素数を計算し、整変数lineItemSize
に割り当てています。
<assign> <copy> <from expression="count(bpws:getVariableData('outpoint', 'payload', '/p:invoice/p:lineItems/p:item')"/> <to variable="lineItemSize"/> </copy> </assign>
関連項目: 次のサンプルを参照してください。
|
データ・シーケンスへの索引付けに動的な値が必要になることがよくあります。つまり、シーケンスのn
番目のノード(n
の値は実行時に定義)の取得が必要な場合です。この項では、式の末尾にXPathを適用して動的な索引付けを行う、次のような方法について説明します。
ここに示す動的索引付けの方法では、XPathをbpws:getVariableData()
の最後の引数として使用するのではなく、bwps:getVariableData()
の結果の末尾にXPathを適用します。末尾のXPathは、位置述語内の整数型の索引変数(つまり、[...]
)を参照します。
<variable name="idx" type="xsd:integer"/> ... <assign> <copy> <from expression="bpws:getVariableData('input','payload' )/p:line-item[bpws:getVariableData('idx')]/p:line-total" /> <to variable="lineTotalVar" /> </copy> </assign>
実行時に、idx
整変数の値として2
が格納されるとします。前述のfrom
内の式は、次の式と同じです。
<from expression="bpws:getVariableData('input','payload' )/p:line-item[2]/p:line-total" />
XPathがbwps:getVariableData()
関数の末尾に使用される場合とこの関数内で使用される場合では、XPathの使用方法に多少の違いがあります。同じ例(payload
が要素p:invoice
のメッセージ・パートである例)を使用すると、XPathをgetVariableData()
関数内で使用する場合は、ルート要素名(/p:invoice
)をXPathの先頭に指定する必要があります。
たとえば、次のようになります。
bpws:getVariableData('input', 'payload','/p:invoice/p:line-item[2]/p:line-total')
XPathをbwps:getVariableData()
関数の末尾に使用する場合、ルート要素名をXPath内に指定する必要はありません。
たとえば、次のようになります。
bpws:getVariableData('input', 'payload')/p:line-item[2]/p:line-total
これは、getVariableData()
関数で返されるノードがすでにルート要素であるためです。ルート要素名をXPathで再指定すると重複になりますが、こちらがXPathの標準セマンティクスです。
assign
アクティビティでbpelx:append
拡張要素を使用すると、BPELプロセスは既存の親要素に新しい要素を追加できます。
<assign name="assign-3"> <copy> <from expression="bpws:getVariableData('idx')+1" /> <to variable="idx"/> </copy> <bpelx:append> <bpelx:from variable="partInfoResultVar" part="payload" /> <bpelx:to variable="output" part="payload" /> </bpelx:append> ... </assign>
この例のbpelx:append
ロジックにより、partInfoResultVar
変数のペイロード要素が、output
変数のペイロード要素に子として追加されます。つまり、output
変数のペイロード要素が親要素として使用されます。
関連項目: 次のサンプルを参照してください。
|
2つのシーケンスを単一のデータ・シーケンスにマージできます。このパターンは、データ・シーケンスが配列内にある場合(つまり、互換性のあるタイプのデータ項目のシーケンスの場合)によく使用されます。次のassign
の下の2つのappend
操作は、データ・シーケンスのマージ方法を示しています。
<assign> <!-- initialize "mergedLineItems" variable to an empty element --> <copy> <from> <p:lineItems /> </from> <to variable="mergedLineItems" /> </copy> <bpelx:append> <bpelx:from variable="input" part="payload" query="/p:invoice/p:lineItems/p:lineitem" /> <bpelx:to variable="mergedLineItems" /> </bpelx:append> <bpelx:append> <bpelx:from variable="literalLineItems" query="/p:lineItems/p:lineitem" /> <bpelx:to variable="mergedLineItems" /> </bpelx:append> </assign>
関連項目: ArraySample.bpel サンプル・ファイルは、次の場所にあります。
|
シーケンスへの動的な索引付けを行うXPath問合せを2ステップ・プロセスで作成するかわりに、XPath関数getElement
を使用できます。この関数はシーケンスと索引(変数などの動的値も可)を受け取り、適切なシーケンス要素を返します。
<variable name="lineItemIndex" type="xsd:int"/> ... <!-- execute the XPath extension function getElement(arrayOfElements[], index) to fetch one element from an array of elements --> <assign> <copy> <from expression="ora:getElement('output', 'payload', '/invoice/lineItems/item', bpws:getVariableData('lineItemIndex'))"/> <to variable="myLineItem"/> </copy> </assign>
注意: XPath関数getElement は、将来のリリースで廃止される予定です。
|
関連項目: 次のサンプルを参照してください。
|
genEmptyElem
関数では、空要素の配列と等価の機能がXML構造に生成されます。 この関数は、次の引数をとります。
genEmptyElem('ElemQName',int?, 'TypeQName'?, boolean?)
次の問題に注意してください。
最初の引数では、空要素のQName
を指定します。
2番目の引数はオプションで整数型であり、空要素の数を指定します。指定されていない場合、デフォルトのサイズは1
です。
3番目の引数はオプションで、生成される空の名前のxsi:type
となるQName
を指定します。 このxsi:type
パターンは、SOAPENC:Array
に相当します。 指定されていないか、空の文字列である場合、xsi:type
属性は生成されません。
4番目の引数は、オプションでブール型であり、生成される空の要素において、xsd:nillableがtrueの場合に、xsi:nil
をtrueにするかどうかを指定します。 デフォルト値はfalse
です。 指定されていないか、false
である場合、xsi:nil
は生成されません。
次の例に、po
の下で10
個の空の<lineItem>
要素を使用して発注書(PO)を初期化するappend
文を示します。
<bpelx:assign> <bpelx:append> <bpelx:from expression="ora:genEmptyElem('p:lineItem',10)" /> <bpelx:to variable="poVar" query="/p:po" /> </bpelx:append> </bpelx:assign>
この例のgenEmptyElem
関数は、次のように埋込みXQuery式で置き換えることができます。
ora:genEmptyElem('p:lineItem',10) == for $i in (1 to 10) return <p:lineItem />
この関数により生成される空要素は、通常は無効なXMLデータです。 空要素の作成後に、さらにデータの初期化を実行します。 前述と同じ例を使用して、次の操作を実行できます。
空のlineItem
要素に属性要素と子要素を追加します。
copy
操作を実行して空要素を置き換えます。 たとえば、flowNアクティビティの下で、この等価配列内の個別エントリにWebサービスの結果からコピーします。
Oracle BPEL Process Managerでは、SOAPでエンコードされた配列(soapenc:arrayType
)をサポートしていません。
次のいずれかの解決策を使用してください。
Apache Axisは、ドキュメント・リテラル形式のサービスをサポートしています。つまり、サービスを変更してsoapenc:arrayType
を使用しないようにすることが可能です。
サービスをラッパーで囲むと(ここでもApache Axisを使用)、BPELプロセスがドキュメント・リテラル・ラッパー・サービスと通信するようになり、ラッパー・サービスによりsoapenc:arrayTypeを使用する基盤サービスがコールされます。
soapenc:arrayType
を持つサービスをBPELからコールします。ただし、XMLメッセージはBPELコード内に手動で構成します(手動による構成部分が増えます)。この方法では、サービスの変更やラップを回避できます。ただし、そのサービスをBPELからコールするたびに、余分な手順が必要になります。
サービスは文字列を返すように定義されることがありますが、文字列の内容は実際にはXMLデータです。問題は、BPELではXMLデータの操作(XPath問合せや式などを使用)はサポートされていますが、変数またはフィールドが文字列型の場合にこの機能が使用できないことです。Javaでは、Document Object Model(DOM)関数を使用して文字列を構造化されたXMLオブジェクト・タイプに変換します。同じことが、BPEL XPath関数parseEscapedXML
を使用して実行できます。この関数はXMLデータを受け取り、DOMによって解析し、型付けされたBPEL変数に割り当てることができる構造化XMLデータを返します。たとえば、次のようになります。
<!-- execute the XPath extension function parseEscapedXML('<item>') and assign to a variable --> <assign> <copy> <from expression="ora:parseEscapedXML( '<item xmlns="http://samples.otn.com" sku="006"> <description>sun ultra sparc VI server </description> <price>1000 </price> <quantity>2 </quantity> <lineTotal>2000 </lineTotal> </item>')"/> <to variable="escapedLineItem"/> </copy> </assign>
関連項目: 次のサンプルを参照してください。
|
前述のすべての例はドキュメント形式のWSDLファイルに対応しており、メッセージは次の例のようにXMLスキーマのelementで定義されています。
<message name="LoanFlowRequestMessage"> <part name="payload" element="s1:loanApplication"/> </message>
これは、次のようにメッセージがXMLスキーマのtype
で定義される、RPC形式のWSDLファイルとは異なります。
<message name="LoanFlowRequestMessage"> <part name="payload" type="s1:LoanApplicationType"/> </message>
2つのWSDLメッセージ形式ではXPath問合せの構成方法に違いがあるため、これはこの章の記述に影響します。RPC形式のメッセージの場合、最上位要素(およびXPath問合せ文字列の最初のノード)はパート名(前の例ではpayload
)です。ドキュメント形式の場合、最上位ノードは要素名(loanApplication
など)です。次の例は、BPELデモ・アプリケーション(LoanFlow
など)で使用されるLoanServices
がRPC形式の場合にXPath問合せ文字列がどのように記述されるかを示しています。
RPC形式のWSDLファイルの場合
<message name="LoanServiceResultMessage"> <part name="payload" type="s1:LoanOfferType"/> </message> <complexType name="LoanOfferType"> <sequence> <element name="providerName" type="string"/> <element name="selected" type="boolean"/> <element name="approved" type="boolean"/> <element name="APR" type="double"/> </sequence> </complexType>
RPC形式のBPELファイルの場合
<variable name="output" messageType="tns:LoanServiceResultMessage"/> ... <assign> <copy> <from expression="9.9"/> <to variable="output" part="payload" query="/payload/APR"/> </copy> </assign>
関連項目: 次のサンプルを参照してください。
|
次のタスクを実行して、Oracle BPEL Process ManagerにカスタムWSIFプロバイダを追加できます。
Apache WSIFパッケージに含まれているJava WSDL拡張機能に従って、WSDL拡張オブジェクト・モデルを作成します。 WSDL拡張機能を登録するには、extensionRegistry
クラス(WSIF Javaパッケージ内のJavaExtensionRegistry.java
など)が必要です。
存在しない場合は、SOA_Oracle_Home
¥bpel¥system¥classes¥WSDLExtensions
ファイルを作成します。
クラス名をファイル内の固有の行に追加します。
My.package.MyWSDLExtensionRegistry
このファイルはWSDLリーダーで使用され、WSDLの解析時にカスタムWSDL拡張機能が認識可能になります。
Apache WSIFパッケージに含まれているプロバイダの例に従って、カスタムWSIFプロバイダを開発します。
SOA_Oracle_Home
¥bpel¥system¥config¥collaxa-config.xml
ファイル内でwsif-providers
エントリを次のように変更します。
<property id="wsif-providers"> <name>Custom WSIF providers for Oacle BPEL server</name> <value>provider-class-name</value> <comment> <![CDATA[The value should be a comma separated list of WSIF provider class names.]]> </comment> </property>
Oracle BPEL Serverを起動します。
次の場所にあるOracle BPEL Admin Consoleにアクセスします。
http://localhost:port/BPELAdmin/server.jsp
プロンプトが表示された時点で、oc4jadmin
/password
としてログインします。
「WSIF」タブをクリックします。
ロードされたWSIFプロバイダが表に表示されます。
Oracle BPEL Process Managerでは、WSIFを使用してWebサービスをコールします。 WSIF APIの起動は容易です。 Webサービス操作を起動するときに、operation.invoke(input, output)
を実行します。
ただし、入力メッセージや出力メッセージには、トランスポート・レイヤーで転送される情報の一部が含まれていないことがあります。 この場合、簡素化されすぎたWSIF APIが表示されます。 ただし、WSIFにはMessageContext
が用意されており、実行する操作を設定できます。 コンテキストに追加情報(SOAPヘッダーとHTTPヘッダー)をバインドでき、WSIFプロバイダはこの情報をサービスに送信できます。
Oracle BPEL Process ManagerのWebサービス起動レイヤーには、次のヘッダー・ハンドラが用意されています。
inputHeaderHandler
は、WSIFプロバイダのコール前に起動されます。
outputHeaderHandler
は、WSIFプロバイダのコール後に起動されます。
図3-1に、この機能を示します。
入力ハンドラと出力ハンドラでは、次のインタフェースを実装する必要があります。
public interface HeaderHandler { invoke(CXPartnerLink partnerLink, String operationName, Map payload, Map headers, Map callProps); }
ペイロードは、入力メッセージまたは出力メッセージです。 ヘッダーは、SOAPヘッダーとして使用されるメッセージを含むマップです。
partnerLink
はオブジェクト・モデルです。 入力ヘッダー・ハンドラは、partnerLink
から情報を取得してコンテキストに設定できます。 出力ヘッダー・ハンドラは、コンテキストから情報を抽出してpartnerLink
にバインドできます。
次の例に、RequestHeaderHandler
の使用方法を示します。
public class MyTestRequestHeaderHandler { public void invoke(CXPartnerLink partnerLink, String operationName, Map payload, Map header, Map callProps) { System.out.println("in MyTestRequestHeaderHandler ..."); Map httpHeaders = (Map) callProps.get("http-request-headers"); if (httpHeaders == null) { httpHeaders = new HashMap(); callProps.put("httpRequestHeaders", httpHeaders); } httpHeaders.put("myHeader1", partnerLink.getProperty("myHeader1")); httpHeaders.put("myHeader2", partnerLink.getProperty("myHeader2")); } }
コンテキストにバインドされたヘッダー情報は、トランスポートが不明であるという点で引き続き抽象的です。 基礎となるWSIFプロバイダは、コンテキストからのこの情報を認識し、トランスポート・レイヤーで正しく設定および取得する必要があります。
ヘッダー・ハンドラの登録は、bpel.xml
デプロイメント・ディスクリプタ・ファイル内で実行されます。
<BPELSuitcase> <BPELProcess src="QuoteConsumer.bpel" id="QuoteConsumer"> <partnerLinkBindings> <partnerLinkBinding name="client"> <property name="wsdlLocation">QuoteConsumer.wsdl</property> </partnerLinkBinding> <partnerLinkBinding name="StockQuoteService"> <property name="wsdlLocation"> http://glennmi:9700/orabpel/default/StockQuoteService/StockQuoteServ ice?wsdl </property> <property name="requestHeaderHandlers"> my.custom.MyRquestHeaderHandler </property> <property name="responseHeaderHandlers"> my.custom.MyResponseHeaderHandler </property> </partnerLinkBinding> </partnerLinkBindings> <configurations> <!-- Optional property used to customize the BPEL console test form. --> <property name="testIntroduction"> This sample shows how to use the BPEL invoke activity to invoke a synchronous stock quote service. </property> </configurations> </BPELProcess> </BPELSuitcase>
ヘッダーは、partnerLink
にバインドされています。 一部のユースケースでは、BPELプロセスでpartnerLink
プロパティを取得して設定する必要があります。 「Business Process Execution Language for Web Services Specification」にはpartnerLink
プロパティに関する説明がありませんが、拡張機能で次のタスクを実行できます。
<process …> <assign> <copy> <from partnerLink="p1" bpelx:property="sessionId"/> <to partnerLink="p2" bpelx:property="sessionId"/> </copy> <copy> <from variable="var"/> <to partnerLink="p2" bpelx:property="sessionId"/> </copy> </BPELProcess> </process>
BPELの通信アクティビティ(invoke、receive、replyおよびonMessage)は、指定のメッセージ変数を介してメッセージを送受信します。 これらのデフォルト・アクティビティでは、各方向で1つの変数の操作が許可されます。 たとえば、invokeアクティビティにはinputVariable
およびoutputVariable
属性があります。 この2つの属性にそれぞれ変数を1つ指定できます。 関連する特定の操作で使用するペイロード・メッセージが各方向で1つのみの場合は、これで十分です。
ただし、WSDLは1つの操作における複数のメッセージをサポートしています。 SOAPの場合、SOAPヘッダーとしてメイン・ペイロード・メッセージとともに複数のメッセージを送信できます。 ただし、BPELのデフォルトの通信アクティビティは、追加のヘッダー・メッセージに対応できません。
Oracle BPEL Process Managerでは、デフォルトのBPEL通信アクティビティをbpelx:headerVariable
拡張要素で拡張することで、この問題を解決しています。 拡張要素の構文は、次のとおりです。
<invoke bpelx:inputHeaderVariable="inHeader1 inHeader2 ..." bpelx:outputHeaderVariable="outHeader1 outHeader2 ..." .../> <receive bpelx:headerVariable="inHeader1 inHeader2 ..." .../> <onMessage bpelx:headerVariable="inHeader1 inHeader2 ..." .../> <reply bpelx:headerVariable="inHeader1 inHeader2 ..." .../>
この項では、SOAPヘッダーを受信するBPELファイルとWSDLファイルの作成方法を、例を挙げて説明します。
ヘッダー・メッセージとそれをSOAPリクエストにバインドするSOAPバインディングを宣言するWSDLファイルを作成します。
<message name="MessageIDHeader"> <part name="MessageID" element="wsa:MessageID"/> </message> <message name="ReplyToHeader"> <part name="ReplyTo" element="wsa:ReplyTo"/> </message> <!-- custom header --> <message name="CustomHeaderMessage"> <part name="header1" element="tns:header1"/> <part name="header2" element="tns:header2"/> </message> <binding name="HeaderServiceBinding" type="tns:HeaderService"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="initiate"> <soap:operation style="document" soapAction="initiate"/> <input> <soap:header message="tns:ReplyToHeader" part="ReplyTo" use="literal"/> <soap:header message="tns:MessageIDHeader" part="MessageID" use="literal"/> <soap:header message="tns:CustomHeaderMessage" part="header1" use="literal"/> <soap:header message="tns:CustomHeaderMessage" part="header2" use="literal"/> <soap:body use="literal"/> </input> </operation> </binding>
ヘッダー・メッセージ変数を宣言し、bpelx:headerVariable
を使用してヘッダーを受信するBPELソース・ファイルを作成します。
<variables> <variable name="input" messageType="tns:HeaderServiceRequestMessage"/> <variable name="event" messageType="tns:HeaderServiceEventMessage"/> <variable name="output" messageType="tns:HeaderServiceResultMessage"/> <variable name="customHeader" messageType="tns:CustomHeaderMessage"/> <variable name="messageID" messageType="tns:MessageIDHeader"/> <variable name="replyTo" messageType="tns:ReplyToHeader"/> </variables> <sequence> <!-- receive input from requestor --> <receive name="receiveInput" partnerLink="client" portType="tns:HeaderService" operation="initiate" variable="input" bpelx:headerVariable="customHeader messageID replyTo" createInstance="yes"/>
この項では、SOAPヘッダーの送信方法を例を挙げて説明します。
bpel.xml
にpartnerLinkBinding
を定義してHeaderService
WSDLを参照します。
カスタム・ヘッダー変数を定義し、操作し、bpelx:inputHeaderVariable
を使用して送信します。
<variables> <variable name="input" messageType="tns:HeaderTestRequestMessage"/> <variable name="output" messageType="tns:HeaderTestResultMessage"/> <variable name="request" messageType="services:HeaderServiceRequestMessage"/> <variable name="response" messageType="services:HeaderServiceResultMessage"/> <variable name="customHeader"messageType="services:CustomHeaderMessage"/> </variables> ... <!-- initiate the remote process --> <invoke name="invokeAsyncService" partnerLink="HeaderService" portType="services:HeaderService" bpelx:inputHeaderVariable="customHeader" operation="initiate" inputVariable="request"/>
次の2つの方法で、SOAPコールの不透明データを転送できます。
データの埋込み
この方法では、不透明データを要素または属性コンテンツとして埋め込みます。XMLでは、base64または16進テキスト・エンコーディングを使用して不透明データをコンテンツとしてサポートします。この方法では、XMLスキーマの2つのバイナリ・データ型、xs:base64Binary
およびxs:hexBinary
が使用されます。不透明データは、基本XMLスキーマ型に変換されるので、標準のBPELアクティビティにおける割当て、送信および受信に関しては、BPELプロセスの他のXMLデータと同様に操作できます。
base64形式でエンコードされたデータは、元の1.33倍のサイズに増えます。16進でエンコードされたデータは、2倍に増えます。ここでは、どちらの形式でも、基礎となるテキスト・エンコーディングとしてUTF-8
が使用されると想定しています。UTF-16
が基礎となるテキスト・エンコーディングとして使用される場合は、これらの数値は2倍になります。SOAPレイヤーとBPEL実行レイヤーの両方のパフォーマンスを向上させるには、SOAPを介した転送時に元のデータをそのまま使用します。次に示す2番目の方法である添付付きSOAPは、これを可能にする技法です。
添付付きSOAPは、HTTPとともにMultipurpose Internet Mail Extensions(MIME)またはDirect Internet Message Encapsulation(DIME)プロトコルを使用することでサポートされます。SOAPエンベロープおよび不透明データは、MIMEまたはDIMEセクションでラップされます。
次の例は、MIMEプロトコル経由で添付付きSOAPを使用しているメッセージを示しています。添付は、コピーされるのではなく、識別キーを通じて参照で渡されます。MIMEでは、XMLパートとバイナリ・パートは異なるパートにある必要があることに注意してください。XMLパートには、バイナリ添付パートへの参照が含まれています。この点がDIMEと異なり、DIMEにはこの制限がありません。
MIME-Version: 1.0 Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml; start="<mymessage.xml@collaxa.com>" Content-Description: A SOAP Envelope with pdf --MIME_boundary Content-Type: text/xml; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-ID: <mymessage.xml@collaxa.com> <s:Envelope xmlns:s='http://www.w3.org/2002/12/soap-envelope' > <s:Body> <m:applyLoan xmlns:m='http://samples.Collaxa.com/MIMEService' > <customerName>John Doe</customerName> <pdf data="1234567890" /> </m:applyLoan> </s:Body> </s:Envelope> --MIME_boundary Content-Type: application/pdf Content-Transfer-Encoding: binary Content-Location: 1234567890 fd a5 8a 29 aa 46 1b 24 --MIME_boundary
バイナリ・データは同じくbase64binary
またはhexBinary
と型付けされています。なお、データはトランスポートおよび処理の間もバイナリ形式のままです。エンコーディングおよびデコーディングによるオーバーヘッドは発生しません。
注意: Oracle Database LiteでSOAPメッセージに大きいバイナリ添付ファイルを使用すると、BPELプロセスが処理を完了できず、システム・メモリーをすべて使用する原因になることがあります。Oracle Database Liteは主にテスト用です。SOAPメッセージに大きいバイナリ添付ファイルを使用するには、デハイドレーション・ストアとしてOracle Databaseを使用します。 |
この項では、ユースケースを示し、設計実装上の問題について説明します。現在のところ、Oracle JDeveloperを介して添付付きSOAPメッセージをモデリングできません。必要なBPELおよびWSDLファイルを手動で編集する必要があります。
このユースケースの内容は次のとおりです。
BPELプロセスが、添付付きSOAPメッセージの受信とリプライを行うサービスとして動作します。
BPELプロセスが、添付付きSOAPメッセージとの間でレスポンスを送受信するクライアントとして動作します。
バイナリ・データが別の変数に割り当てられます。
バイナリ・データがURLから読み取られます。
バイナリ・データがローカル・ファイルに保存されます。
次の2つのBPELプロセスが構成されます。
MIMEServiceは、基本的に、添付付きSOAPメッセージのエコー・サービスです。このプロセスは、次の処理を行います。
添付付きSOAPメッセージを受信し、不透明データをローカル・ファイルに保存します。
不透明データを出力変数に割り当てます。
出力変数を使用して、インボーカへの添付付きSOAPメッセージにリプライします。
MIMERequesterは、最初のサービスのクライアントです。このプロセスは、次の処理を行います。
バイナリ・データをURLから読み取って変数に割り当てます。
変数を入力として使用して、最初のプロセスを起動します。
添付付きSOAPメッセージを受信します。
次のWSDLファイルにより、MIMEServiceが定義されます。このファイルでは、WSDLバインディングのMIME拡張を使用して、添付付きSOAPメッセージを定義しています。
<?xml version="1.0" encoding="UTF-8"?> <definitions . . . . . . <types> . . . . . . <schema xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://schemas.xmlsoap.org/ws/2003/03/addressing" schemaLocation="http://gmi-pc:9700/orabpel/xmllib/ws-addressing.xsd" /> </schema> </types> <message name="ReplyToHeader"> <part name="ReplyTo" element="wsa:ReplyTo" /> </message> <message name="MessageIDHeader"> <part name="MessageID" element="wsa:MessageID" /> </message> <message name="RelatesToHeader"> <part name="RelatesTo" element="wsa:RelatesTo" /> </message> <message name="MIMEServiceRequestMessage"> <part name="payload" type="xsd:int"/> <part name="bin" type="xsd:anyType"/> </message> <message name="MIMEServiceResponseMessage"> <part name="payload" type="xsd:int"/> <part name="bin" type="xsd:anyType"/> </message> <portType name="MIMEService"> <operation name="initiate"> <input message="tns:MIMEServiceRequestMessage"/> </operation> <operation name="process"> <input message="tns:MIMEServiceRequestMessage"/> <output message="tns:MIMEServiceResponseMessage"/> </operation> </portType> <portType name="MIMEServiceCallback"> <operation name="onResult"> <input message="tns:MIMEServiceResponseMessage"/> </operation> </portType> <binding name="MIMEServiceBinding" type="tns:MIMEService"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="initiate"> <soap:operation style="rpc" soapAction="initiate"/> <input> <mime:multipartRelated> <mime:part> <soap:header message="tns:MessageIDHeader" part="MessageID" use="literal"/> <soap:header message="tns:ReplyToHeader" part="ReplyTo" use="literal"/> <soap:body parts="payload" use="literal"/> </mime:part> <mime:part> <mime:content part="bin" type="binary"/> </mime:part> </mime:multipartRelated> </input> </operation> <operation name="process"> <soap:operation style="rpc" soapAction="process"/> <input> <mime:multipartRelated> <mime:part> <soap:header message="tns:RelatesToHeader" part="RelatesTo" use="literal"/> <soap:body parts="payload" use="literal"/> </mime:part> <mime:part> <mime:content part="bin" type="binary"/> </mime:part> </mime:multipartRelated> </input> <output> <mime:multipartRelated> <mime:part> <soap:body parts="payload" use="literal"/> </mime:part> <mime:part> <mime:content part="bin" type="binary"/> </mime:part> </mime:multipartRelated> </output> </operation> </binding> <binding name="MIMEServiceCallbackBinding" type="tns:MIMEServiceCallback"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="onResult"> <soap:operation style="rpc" soapAction="onResult"/> <input> <mime:multipartRelated> <mime:part> <soap:header message="tns:RelatesToHeader" part="RelatesTo" use="literal"/> <soap:body use="literal" /> </mime:part> <mime:part> <mime:content part="bin" type="binary"/> </mime:part> </mime:multipartRelated> </input> </operation> </binding> <plnk:partnerLinkType name="MIMEService"> <plnk:role name="MIMEServiceProvider"> <plnk:portType name="tns:MIMEService"/> </plnk:role> <plnk:role name="MIMEServiceRequester"> <plnk:portType name="tns:MIMEServiceCallback"/> </plnk:role> </plnk:partnerLinkType> </definitions>
このWSDLでは、バイナリ・データのスキーマ型はxsd:anyType
です。 このため、xsd:anyType
をMIMEまたはDIMEデータと一緒に使用した場合に、ペイロード検証が確実に成功します。
MIMERequester.bpel
ファイルでは、BPELでのバイナリ・データの使用方法が示されています。
<process . . . . . . . . . <sequence> <!-- receive input from requestor --> <receive name="receiveInput" partnerLink="client" portType="tns:MIMERequester" operation="initiate" variable="input" createInstance="yes"/> <!-- initialize the input of MIMEService --> <assign> <copy> <from variable="input" part="payload" query="/tns:value"/> <to variable="request" part="payload" query="/payload"/> </copy> <copy> <from expression="ora:readBinaryFromFile('request.bin')"/> <to variable="request" part="bin"/> </copy> </assign> <invoke name="invoke" partnerLink="MIMEService" portType="services:MIMEService" operation="initiate" inputVariable="request"/> <receive name="receive" partnerLink="MIMEService" portType="services:MIMEServiceCallback" operation="onResult" variable="response"/> <assign> <copy> <from variable="response" part="payload" query="/payload"/> <to variable="request" part="payload" query="/payload"/> </copy> <copy> <from expression="ora:writeBinaryToFile('response', 'bin', 'C:/Temp/response.bin')"/> <to variable="response" part="bin"/> </copy> <copy> <from expression="ora:readBinaryFromFile('request2.bin')"/> <to variable="request" part="bin"/> </copy> </assign> <invoke name="invoke" partnerLink="MIMEService" portType="services:MIMEService" operation="process" inputVariable="request" outputVariable="response"/> <assign> <copy> <from variable="response" part="payload" query="/payload"/> <to variable="output" part="payload" query="/tns:result"/> </copy> <copy> <from expression="ora:writeBinaryToFile('response', 'bin', 'C:/Temp/response2.bin')"/> <to variable="response" part="bin"/> </copy> </assign> <!-- respond output to requestor --> <invoke name="replyOutput" partnerLink="client" portType="tns:MIMERequesterCallback" operation="onResult" inputVariable="output"/> </sequence> </process>
この例では、XPath拡張関数ora:readBinaryFromFile( )
がバイナリ・ファイルを読み取り、ora:writeBinaryToFile( )
がバイナリ・コンテンツをファイルに書き込みます。
BPELの標準のassignアクティビティを使用して、バイナリ・データを、通常のXML文書と同様に別の変数に割り当てることができます。ここでは、BPELのassignアクティビティは、バイナリ・データに対応するように拡張されています。
MIMEServiceは、Javaクライアントからアクセスできます。次の2つのアクセス・オプションがあります。
Java API for XML-Based RPC(JAX-RPC)
SOAP with Attachments API Java(SAAJ)
例3-1では、AxisのSAAJ実装を使用して、MIMEServiceを起動します。この例は、作成したサービスの相互運用性についてユニット・テストを行っています。この例で送信されているサンプル・リクエストを例3-2に示します。
例3-1 SAAJの例
public boolean initiateUsingSAAJ(String filename) throws Exception { String endPointURLString = "http://localhost:" +opts.getPort() + "/orabpel/default/MIMEService/1.0"; SOAPConnectionFactory soapConnectionFactory = javax.xml.soap.SOAPConnectionFactory.newInstance(); SOAPConnection soapConnection = soapConnectionFactory.createConnection(); MessageFactory messageFactory = MessageFactory.newInstance(); SOAPMessage soapMessage = messageFactory.createMessage(); MimeHeaders hd = soapMessage.getMimeHeaders(); hd.addHeader("SOAPAction", "initiate"); SOAPPart soapPart = soapMessage.getSOAPPart(); SOAPEnvelope requestEnvelope = soapPart.getEnvelope(); SOAPBody body = requestEnvelope.getBody(); SOAPBodyElement operation = body.addBodyElement (requestEnvelope.createName("initiate")); Vector dataHandlersToAdd = new Vector(); dataHandlersToAdd.add(new DataHandler(new FileDataSource(new File(filename)))); javax.xml.soap.SOAPElement element1 = operation.addChildElement(requestEnvelope.createName("payload")); element1.addTextNode("1"); if (dataHandlersToAdd != null) { ListIterator dataHandlerIterator = dataHandlersToAdd.listIterator(); while (dataHandlerIterator.hasNext()) { DataHandler dataHandler = (DataHandler) dataHandlerIterator.next(); javax.xml.soap.SOAPElement element = operation.addChildElement(requestEnvelope.createName("bin")); javax.xml.soap.AttachmentPart attachment = soapMessage.createAttachmentPart(dataHandler); soapMessage.addAttachmentPart(attachment); element.addAttribute(requestEnvelope.createName ("href"), "cid:" + attachment.getContentId()); } } javax.xml.soap.SOAPMessage returnedSOAPMessage = soapConnection.call(soapMessage, endPointURLString); if (returnedSOAPMessage == null) return true; Iterator iterator = returnedSOAPMessage.getAttachments(); if (!iterator.hasNext()) { //The wrong type of object that what was expected. System.out.println("Received problem response from server"); throw new AxisFault("", "Received problem response from server", null, null); } //Still here, so far so good. //Now lets brute force compare the source attachment // to the one we received. DataHandler rdh = (DataHandler) ((AttachmentPart)iterator.next()).getDataHandler(); //From here we'll just treat the data resource as file. String receivedfileName = rdh.getName();//Get the filename. if (receivedfileName == null) { System.err.println("Could not get the file name."); throw new AxisFault("", "Could not get the file name.", null, null); } System.out.println("Going to compare the files.."); boolean retv = compareFiles(filename, receivedfileName); java.io.File receivedFile = new java.io.File(receivedfileName); receivedFile.delete(); return retv; } }
SAAJプログラムで送信されているサンプル・リクエストを例3-2に示します。
例3-2 サンプル・リクエスト
POST /orabpel/default/MIMEService/1.0 HTTP/1.0Content-Type: multipart/related; type="text/xml"; start="<F090DFD56421FD84AAF98C386AD50A44>"; boundary="----=_ Part_0_27211574.1133404205718"Accept: application/soap+xml, application/dime, multipart/related, text/*User-Agent: Axis/1.2.1Host: gmi-pc:1234Cache-Control: no-cachePragma: no-cacheSOAPAction: "initiate"Content-Length: 9307------=_Part_0_ 27211574.1133404205718Content-Type: text/xml; charset=UTF-8Content-Transfer-Encoding: binaryContent-Id: <F090DFD56421FD84AAF98C386AD50A44><?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><initiate xmlns=""><payload xmlns="">1</payload><bin href="cid:1A744998BA8527BD121CAE96C022109F" xmlns=""/></initiate></soapenv:Body></soapenv:Envelope>------=_Part_0_ 27211574.1133404205718Content-Type: application/octet-streamContent-Transfer-Encoding: binaryContent-Id: <1A744998BA8527BD121CAE96C022109F> .....................
関連項目: 次のドキュメントを参照してください。
|
Oracle BPEL Controlでは、optSoapShortcutパラメータ値がデフォルトでtrueに設定されます。この設定により、Direct Internet Message Encapsulation(DIME)プロトコルを介してSOAPメッセージのバイナリ添付を使用するBPELプロセスの添付キーは、プロセス・インスタンスのOracle BPEL Control監査証跡に表示されません。これは、バイナリ添付ファイルがデハイドレーション・データベースに保存されないためです。かわりに、監査証跡にはHTMLファイルが表示されます。たとえば、次のようになります。
<PutCompanyInfo>
. . .
. . .
<report href="C:¥orabpel¥domains¥default¥tmp¥.bpel_DIMERequester_
1.0.jar¥report.html"/> </PutCompanyInfo>
これを回避するには、Oracle BPEL ControlでoptSoapShortcutをfalseに設定します。これにより、ファイルがデハイドレーション・ストアに保存され、添付キーが(HTMLファイルではなく)インスタンスの監査証跡に表示されます。この添付キーをコピーし、監査証跡ウィンドウの下部にある「添付キー」フィールドに貼り付けて、「ダウンロード」をクリックして参照用ファイルとして保存します。この場合、ファイル・ダウンロード・メッセージでは、最初に添付キーをJSPファイル・タイプとして保存するように要求されることに注意してください。かわりに、ファイルをHTMLファイル・タイプとして保存します。