この章では、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ファイル・タイプとして保存します。