BPELプロセスはフォルト処理により、外部Webサービスから返されたエラー・メッセージやその他の例外を処理し、ビジネス・フォルトまたは実行時フォルトに対してエラー・メッセージを生成できます。
この章の内容は次のとおりです。
この章では、信用格付けの数値のかわりにネガティブ情報メッセージを返す信用格付けサービスの例を使用します。また、メッセージを処理するためにBPELプロセスにフォルト・ハンドラを追加する方法も説明します。
|
関連項目: 次のサンプルを参照してください。
|
フォルト・ハンドラは、通常予想される以外のデータ(数値のかわりにエラー・メッセージなど)がWebサービスから返されたときに、BPELプロセスがどのように対応するかを定義します。フォルト・ハンドラの例として、Webサービスで通常返される信用格付けの数値のかわりに、ネガティブ情報メッセージが返された場合を想定します。
図8-1に、フォルト・ハンドラが信用格付け変数を-1000に設定する方法を示します。
次のコード・セグメントは、この操作のフォルト・ハンドラを定義しています。
<faultHandlers>
<catch faultName="services:NegativeCredit" faultVariable="crError">
<assign name="crin">
<copy>
<from expression="-1000">
</from>
<to variable="input" part="payload"
query="/autoloan:loanApplication/autoloan:creditRating"/>
</copy>
</assign>
</catch>
</faultHandlers>
faultHandlersタグには、フォルト処理コードが入ります。フォルト・ハンドラ内はcatchアクティビティで、フォルト名とフォルト変数、およびcreditRating変数を-1000に設定するコピー命令が定義されています。
BPELプロセスに対してWebサービスを選択する際、返される可能性があるフォルトを特定し、それぞれに対してフォルト・ハンドラを設定します。
「Business Process Execution Language for Web Services Specification」では、http://schemas.xmlsoap.org/ws/2003/03/business-process/のネームスペースに次の標準フォルトが定義されています。
selectionFailure
conflictingReceive
conflictingRequest
mismatchedAssignmentFailure
joinFailure
forcedTermination
correlationViolation
uninitializedVariable
repeatedCompensation
invalidReply
標準フォルトの定義は、次のとおりです。
タイプなし。つまり、messageTypesは関連付けられていません。
WSDLメッセージには関連付けられていません。
次のようにフォルト変数なしで捕捉されます。
<catch faultName="bpws:selectionFault">
BPELフォルトには、Qnameというフォルト名(ネームスペースで修飾された名前)と、可能性のあるmessageTypeがあります。 BPELフォルトには次の2つのカテゴリがあります。
ビジネス・フォルト
実行時フォルト
ビジネス・フォルトはアプリケーション固有のフォルトであり、処理されている情報に問題がある場合(社会保障番号がデータベース内で見つからない場合など)に生成されます。ビジネス・フォルトは、アプリケーションがthrowアクティビティを実行したとき、またはinvokeアクティビティがレスポンスとしてフォルトを受け取った場合に発生します。ビジネス・フォルトのフォルト名はBPELプロセスによって指定されます。このような場合、WSDLファイルにmessageTypeが定義されます。 ビジネス・フォルトは、faultNameおよびfaultVariableを使用してfaultHandlerで捕捉できます。
<catch faultName="ns1:faultName" faultVariable="varName">
実行時フォルトは、BPELプロセスまたはWebサービスの実行中に問題(変数名が正しくないためにデータを正しくコピーできないなど)が発生した結果です。 この種のフォルトはユーザー定義ではなく、システムによりスローされます。 プロセスによる値の使用に誤りがある場合、論理エラーが発生する場合(無限ループなど)、SOAPコールでSOAPフォルトが発生する場合、Oracle BPEL Serverにより例外がスローされる場合などに生成されます。
Oracle BPEL Serverには、複数の実行時フォルトが組み込まれています。 これらのフォルトは、http://schemas.oracle.com/bpel/extensionネームスペースにあります。 また、messageType RuntimeFaultMessageに関連付けられています。 次のWSDLファイルによりmessageTypeが定義されます。
<?xml version="1.0" encoding="UTF-8" ?> <definitions name="RuntimeFault" targetNamespace="http://schemas.oracle.com/bpel/extension" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="RuntimeFaultMessage"> <part name="code" type="xsd:string" /> <part name="summary" type="xsd:string" /> <part name="detail" type="xsd:string" /> </message> </definitions>
フォルトの捕捉時に(messageType RuntimeFaultMessageの)faultVariableが使用される場合は、faultVariableからフォルト・サマリーおよび詳細とともにフォルト・コードを問合せできます。
bindingFaultは、起動準備に失敗した場合にアクティビティ内でスローされます。 たとえば、プロセスのWSDLのロードに失敗した場合などです。 bindingFaultは再試行できません。 通常、このタイプのフォルトはユーザー操作により修正する必要があります。 表8-1にフォルト・コードを示します。
表8-1 bindingFaultフォルト・コード
| フォルト・コード | フォルトの説明 |
|---|---|
VersionMismatch
|
処理中のパーティによりSOAPエンベロープ要素に無効なネームスペースが検出されました。 |
MustUnderstand
|
処理中のパーティが認識または準拠しなかったSOAPヘッダー要素の直下の子要素に、値1を持つSOAP MustUnderstand属性が含まれていました。
|
Client.GenericError
|
クライアント側の一般エラー。 |
Client.WrongNumberOfInputParts
|
入力メッセージのパート番号の不一致。 |
Client.WrongNumberOfOutputParts
|
出力メッセージのパート番号の不一致。 |
Client.WrongTypeOfInputPart
|
入力メッセージのパート・タイプ・エラー。 |
Client.WrongTypeOfOutputPart
|
出力メッセージのパート・タイプ・エラー。 |
Server.GenericError
|
サーバー側の一般エラー。 |
Server.NoService
|
サーバーは起動していますが、サービスが存在しません。 |
Server.NoHTTPSOAPAction
|
リクエストにHTTP SOAPアクションが欠落しています。 |
Server.Unauthenticated
|
リクエストが認証されません。 |
Server.Unauthorized
|
リクエストが認可されません。 |
remoteFaultもアクティビティ内でスローされます。 スロー原因は、起動の失敗です。 たとえば、リモート・サービスからSOAPフォルトが返されます。 remoteFaultは再試行するように構成できます。 表8-2にフォルト・コードを示します。
replayFaultは、スコープ内のアクティビティを再実行します。 このフォルトは、スコープ内のいずれかの時点でスコープへと移行されます。 その後、Oracle BPEL Serverによりスコープが最初から再実行されます。
BPEL実行時フォルトは、名前付きのBPELフォルトとして捕捉できます。 bindingFaultおよびremoteFaultはメッセージに関連付けることができます。 これにより、faultHandlerでフォルトの詳細を取得できます。
次の手順は、与えられた例を使用して、フォルトを生成し、それを捕捉するためのフォルト・ハンドラを定義する方法を示します。ここでは、WSDLファイルを変更してフォルトを生成し、捕捉するためのcatch属性を作成します。
RuntimeFault.wsdlをプロセスWSDL(SOA_Oracle_Home¥bpel¥system¥xmllibディレクトリ内)にインポートします。
messageType "bpelx:RuntimeFaultMessage"を使用して変数を宣言します。
次を使用して捕捉します。
<catch faultName="bpelx:remoteFault" | "bpelx:bindingFault" faultName="varName">
可能なフォルトを捕捉できるようにcatchAllアクティビティが用意されています。 ただし、BPELには、取得されたフォルトの詳細情報を取得するためのメソッドが用意されていません。 詳細情報を取得するにはgetFaultAsString() XPath拡張関数を使用します。
<catchAll>
<sequence>
<assign>
<from expression="bpelx:getFaultAsString()"/>
<to variable="faultVar" part="message"/>
</assign>
<reply faultName="ns1:myFault" variable="faultVar" .../>
</sequence>
</catchAll>
scopeアクティビティは、その他のアクティビティのコンテナおよびコンテキストを提供します。また、フォルト、イベント、補正、およびデータ変数と相関セットに対するハンドラを提供します。scopeアクティビティを使用すると、機能構造をグループ化することでBPELフローが単純化されます。これにより、Oracle JDeveloperではそれらを閉じて1つの要素として表示できます。
次のコード例はscopeアクティビティを示しています。ここでは、顧客の社会保障番号に基づいて信用格付けを取得するプロセスが、getCreditRatingというスコープ内に置かれています。これはコードの機能ブロックであり、ビジュアルに切り離されています。Oracle JDeveloperでは、スコープ内のアクティビティを1つのビジュアル要素として閉じることも、必要に応じて開くこともできます。
<scope name="getCreditRating"> <variables> <variable name="crError" messageType="services:CreditRatingServiceFaultMessage"/> </variables> <assign name="assign-2"> <copy> <to variable="input" part="payload" query="/autoloan:loanApplication/autoloan:creditRating"/> </copy> </assign> </sequence> </scope>
scopeアクティビティを追加する手順は、次のとおりです。
scopeアクティビティをクリックしてBPELプロセス・ダイアグラムにドラッグします。
scopeを開くため、それをダブルクリックするかまたは「+」記号を1回クリックします。
コンポーネント・パレットのアクティビティをドラッグしてスコープ内に機能を作成します。
|
関連項目: Oracle JDeveloperでのscopeアクティビティの作成例は、次のドキュメントを参照してください。 |
BPELアプリケーションでは、フォルト・メッセージの生成および受取りができます。throwアクティビティは3つの要素(自身の名前、faultNameの名前およびfaultVariable)を持ちます。throwアクティビティをBPELプロセスに追加した場合、フォルト名とタイプを出力ペイロードにコピーするコピー・ルールが自動的に含まれます。throwアクティビティによってスローされるフォルトは、BPELの内部フォルトになります。throwアクティビティを非同期プロセスで使用してクライアントと通信することはできません。次に、throwアクティビティのコード例を示します。このアクティビティには、フォルト要素、名前、BPELプロセスによるフォルトの送信先となるサービスのパートナ・リンク、およびメッセージをパッケージ化するコピー・ルールが含まれています。
<throw name="delay" faultName="fault-1" faultVariable="fVar"/> <invoke name="invokeStockQuoteService" partnerLink="StockQuoteService"/> <assign> <copy> <from variable="response" part="result" query="/result"/> <to variable="output" part="payload" query="/tns:result"/> </copy> </assign>
|
関連項目: throwアクティビティの作成例は、次のドキュメントを参照してください。
|
BPELプロセスは、内部フォルトをスローするのではなく、フォルトを別のアプリケーションに送信して問題を示すことができます。同期操作では、replyアクティビティがフォルトを返すことができます。非同期操作では、invokeアクティビティがこの機能を実行します。
同期相互作用でフォルトを返すreplyアクティビティの構文は、次のとおりです。
<reply partnerlinke="partner-link-name" portType="port-type-name" operation="operation-name" variable="variable-name" (optional) faultName="fault-name"> </reply>
同期リクエストに対して常にフォルトを返すことはあまり有効ではありません。これよりも、アクティビティを条件分岐に組み込み、リクエストされたデータを使用できる場合に最初のブランチが実行されるようにするほうが効果的です。リクエストされたデータを使用できない場合、BPELプロセスはそのことを示すフォルトを返します。
フォルトが処理されていない場合、フォルト状態が作成されてアプリケーション全体に移行し、プロセス全体がフォルト状態になることがあります。これを防ぐには、フォルトを受け取る可能性があるプロセスの一部をスコープ内に含めます。前述のように、scopeアクティビティにはフォルト処理機能があります。スコープ内ではcatchアクティビティが動作し、プロセス全体がフォルト状態になる前に、フォルトおよび例外を捕捉します。
catchアクティビティで特定のフォルト名を使用し、個々のフォルトに特定の方法で対応できます。名前が指定されたcatchアクティビティで処理されていないすべてのフォルトを捕捉するには、catchAllアクティビティを使用します。
|
関連項目: フォルト処理の作成例は、次のドキュメントを参照してください。
|
何もしないアクティビティが必要になることがよくあります。たとえば、フォルトを捕捉して抑制する必要がある場合などです。この場合、emptyアクティビティを使用すると、操作なしの命令をビジネス・プロセスに挿入できます。emptyアクティビティを使用するための構文は、次のとおりです。
<empty standard-attributes>
standard-elements
</empty>
catchまたはcatchallが選択されていない場合、フォルトが現在のスコープによって捕捉されず、すぐ外側を囲んでいるスコープにスローされます。グローバル・プロセス・スコープでフォルトが発生し(またはグローバル・プロセス・スコープに再スローされ)、グローバル・レベルでフォルトに合うフォルト・ハンドラがない場合、プロセスが異常終了します。これは、terminateアクティビティ(「terminateアクティビティによるビジネス・プロセス・インスタンスの停止」で説明)が実行された場合のような状況です。
次の例を考えてください。
<faulthandlers>
<catch faultName="x:foo">
<empty/>
</catch>
<catch faultVariable="bar">
<empty/>
</catch>
<catch faultName="x:foo" faultVariable="bar">
<empty/>
</catch>
<catchAll>
<empty/>
</catchAll>
</faulthandlers>
x:fooという名前のフォルトがスローされたとします。フォルトがフォルト・データを渡さなければ、最初のcatchが選択されます。フォルトに関連付けられたフォルト・データがある場合、フォルトのデータ・タイプが変数barのタイプに一致すると、3番目のcatchが選択されます。一致しない場合は、デフォルトのcatchAllハンドラが選択されます。最後に、タイプがbarのタイプに一致し、名前がx:fooでないフォルト変数を持つフォルトは2番目のcatchで処理されます。その他のすべてのフォルトはデフォルトのcatchAllハンドラによって処理されます。
補正は、BPELプロセスが一部の操作をすでに完了した後で一連の操作を完了できず、引き返して前に完了したトランザクションを取り消す必要がある場合に行われます。たとえば、レンタカー、ホテルおよびフライトを予約するようにBPELプロセスが設計されている場合、車とホテルは予約でき、その日付のフライトを予約できない場合があります。この場合、BPELフローは戻って車とホテルをキャンセルすることによって、補正を実行します。
補正ハンドラは、compensateアクティビティを使用することによって起動でき、補正が実行されるスコープ(補正ハンドラが起動されるスコープ)を指定します。スコープの補正ハンドラは、スコープが正常に完了した場合にのみ起動できます。インストールされていない補正ハンドラを起動することは、emptyアクティビティ(操作なし)を使用することと同じです。これにより、フォルト・ハンドラは、ネストされたどのスコープが正常に完了したかを判断するために、状態を使用しなくても済むようになります。インストールされた補正ハンドラが複数回起動されているプロセスのセマンティクスは未定義です。invokeアクティビティにインラインで定義された補正ハンドラがある場合、アクティビティの名前はcompensateアクティビティに使用されるスコープの名前です。構文は、次のとおりです。
<compensate scope="ncname"? standard-attributes>
standard-elements
</compensate>
明示的にcompensateアクティビティを起動する機能は、アプリケーション制御のエラー・ハンドリング・フレームワークであるBusiness Process Execution Language for Web Services Specificationの基礎となる機能です。このアクティビティは、ビジネス・プロセスの次の部分でのみ使用できます。
スコープのすぐ外側を囲んでいるスコープのフォルト・ハンドラでは、補正が実行されます。
スコープのすぐ外側を囲んでいるスコープの補正ハンドラでは、補正が実行されます。
たとえば、次のようになります。
<compensate scope="RecordPayment"/>
名前によって補正されているスコープがループでネストされている場合、BPELプロセスは一連の反復内で補正ハンドラ・インスタンスを逆の順序で起動します。
スコープの補正ハンドラがない場合、デフォルトの補正ハンドラは、すぐ内側に囲まれているスコープの補正ハンドラを、これらのスコープの完了と逆の順序で起動します。
補正フォームでcompensateアクティビティのスコープ名が省略されると、このデフォルトの動作が明示的に起動されます。これは、囲んでいるフォルトまたは補正ハンドラで追加の作業(変数の更新や外部通知の送信、および内側のスコープに対するデフォルト補正の実行など)を実行する必要がある場合に便利です。外側のスコープに付加されたフォルトまたは補正ハンドラのcompensateアクティビティにより、そのスコープ内に直接ネストされた完了スコープに対する補正ハンドラがデフォルトの順序で起動されます。このアクティビティは、外側のスコープ内にネストされたスコープの明示的な起動を除く、その他のユーザー指定の動作と一緒に使用できます。外側のスコープ内にネストされたこのスコープの補正を明示的に起動すると、デフォルトの順序の補正は、適切に機能しません。
terminateアクティビティは、terminateアクティビティが実行されるビジネス・プロセス・インスタンスの動作をただちに終了します。現在実行中のすべてのアクティビティは、フォルト処理または補正動作を実行せずにできるだけ早く終了する必要があります。terminateアクティビティは、BPELプロセスのステータスの通知を送信しません。terminateアクティビティを使用する場合は、先に関係ユーザーに通知するようプログラムしてください。
terminateアクティビティの構文は、次のとおりです。
<terminate standard-attributes>
standard-elements
</terminate>
|
関連項目: terminateアクティビティの作成例は、次のドキュメントを参照してください。
|
サンプルResilientDemoは、フェイルオーバーのフォルト処理と再試行のフォルト処理を示しています。フェイルオーバーにより、パートナ・リンクに使用する複数のサービス実装を構成できます。再試行可能な実行時フォルトが発生すると、サーバーは他のサービス実装を試行します。再試行のフォルト処理では、サーバーは指定された再試行間隔および再試行回数に基づいて再試行します。もう1種類のフォルトであるバインディング・フォルトは、Webサービスのアップグレードとインタフェースの変更があった場合に発生することがあります。サンプルResilientDemoでは、バインディング・フォルトが発生すると、ドキュメントがJMSサービスを使用して配達不能キューに置かれます。図8-2にResilientFlow.bpelのダイアグラムを示します。
invokeRatingServiceアクティビティはフェイルオーバー機能を示しています。このinvokeアクティビティのパートナ・リンクには2つの実装候補があり、デプロイメント・ディスクリプタ・ファイル内で次のように構成されています。
<properties id="RatingService">
<property name="wsdlLocation">
http://localhost:8080/axis/services/RatingService1?wsdl
</property>
<property name="location">
http://localhost:1234/axis/services/RatingService1
http://localhost:8080/axis/services/RatingService2
</property>
</properties>
前述のサンプル・コードは、RatingServiceパートナ・リンクについて2つのエンドポイントの場所が構成されていることを示しています。第1のエンドポイントは不正なURLで、第2のエンドポイントは有効なURLです。このようなリモートの例外は再試行可能であり、第2のエンドポイントが存在するため、Oracle BPEL Serverは第2のエンドポイントのコールを試行し、その時点でコールに成功します。
図8-3の展開済invokeFlakyServiceアクティビティは、システムの再試行を示しています。
このinvokeのパートナ・リンクは次のように構成されています。
<properties id="FlakyService">
<property name="wsdlLocation">
http://localhost:8080/axis/services/FlakyService?wsdl</property>
<property name="location">
http://localhost:2222/axis/services/FlakyService</property>
<property name="retryMaxCount">2</property>
<property name="retryInterval">60</property>
</properties>
サービスがポート2222でリスニングしていない場合は、ConnectionRefusedの実行時フォルトで起動に失敗します。 これは再試行可能なフォルトであり、retryMaxCount(2に設定)およびretryIntervalパラメータ(60に設定)が定義されているため、Oracle BPEL Serverは60秒間隔で2回再試行します。2回目の再試行が成功します。