- WS/BPEL 2.0 for SOA Composite Applications with Oracle SOA Suite 11g
- Matjaz B.Juric Marcel Krizevnik
- 1281字
- 2021-04-13 17:13:54
Scopes provide a way to divide a complex business process into hierarchically organized parts—scopes. Scopes provide behavioral contexts for activities. In other words, scopes address the problem that we identified in the previous section and allow us to define different fault handlers for different activities (or sets of activities gathered under a common structured activity, such as<sequence>
or<flow>)
. In addition to fault handlers, scopes also provide a way to declare variables and partner links that are visible only within the scope. Scopes also allow us to define local correlation sets, compensation handlers, event handlers, termination handler, and message exchanges. We will discuss these topics later in this chapter.
The following code excerpt shows how scopes are defined in BPEL. We can specify<partnerLinks>, <messageExchanges>, <variables>, <correlationSets>, <faultHandlers>, <compensationHandler>, <terminationHandler>
, and<eventHandlers>
locally for the scope. All are optional:
<scope> <partnerLinks> <!-- Partner link definitions local to scope. --> </partnerLinks> <messageExchanges> <!-- Message exchanges local to scope. Discussed later in this chapter. --> </messageExchanges> <variables> <!-- Variable definitions local to scope. --> </variables> <correlationSets> scopescopeabout<!-- Correlation sets local to scope. Discussed later in this chapter. --> </correlationSets> <faultHandlers> <!-- Fault handlers local to scope. --> </faultHandlers> <compensationHandler> <!-- Compensation handlers local to scope. Discussed later in this chapter. --> </compensationHandler> <terminationHandler> <!-- Termination handler local to scope. Discussed later in this chapter. --> </terminationHandler> <eventHandlers> <!-- Event handlers local to scope. Discussed later in this chapter. --> </eventHandlers> activity </scope>
Each scope has a primary activity. This is similar to the overall process structure, where we have said that a BPEL process also has a primary activity. The primary activity, often a<sequence>
or<flow>
, defines the behavior of a scope for normal execution. Fault handlers and other handlers define the behavior for abnormal execution scenarios.
The primary activity of a scope can be a basic activity such as<invoke>
, or it can be a structured activity such as<sequence>
or<flow>
. Enclosing the<invoke>
activity with a scope and defining the fault handlers is equivalent to using inline fault handlers. The inline fault handler shown in the previous section is equal to the following scope:
<scope> <faultHandlers> <catch faultName="emp:WrongEmployeeName" > <!-- Perform an activity --> </catch> <catch faultName="emp:TravelNotAllowed" faultVariable="Description" > <!-- Perform an activity --> </catch> <catchAll> <!-- Perform an activity --> </catchAll> </faultHandlers> <invoke partnerLink="employeeTravelStatus" portType="emp:EmployeeTravelStatusPT" operation="EmployeeTravelStatus" inputVariable="EmployeeTravelStatusRequest" outputVariable="EmployeeTravelStatusResponse" > </invoke> </scope>
If the primary activity of a scope is a structured activity, it can have many nested activities where the nesting depth is arbitrary. The scope is shared by all nested activities. A scope can also have nested scopes with arbitrary depth.
The variables defined within a scope are only visible within that scope. Fault handlers attached to a scope handle faults of all nested activities of a scope. By default behavior, faults not caught in a scope are re-thrown to the enclosing scope. Scopes in which faults have occurred are considered to have ended abnormally even if a fault handler has caught the fault and not re-thrown it.
Similarly as for the<process>
, we can define the exitOnStandardFault
for a scope as well. If set to no, which is the default, the scope can handle the faults using the corresponding fault handlers. If set to yes, then the scope must exit immediately if a fault occurs (similarly as if it would reach an<exit>
activity). If we do not set this attribute, it inherits the value from its enclosing<scope>
or<process>
.
To demonstrate how scopes can be used in BPEL processes, we will rewrite our asynchronous travel process example and introduce three scopes:
We will also declare those variables that are limited to a scope locally within the scope. This will reduce the number of global variables and make the business process easier to understand. The major benefit of scopes is the capability to define custom fault handlers, which we will also implement. The high-level structure of our travel process will be as follows:
<process ...> <partnerLinks/>...</partnerLinks> <variables>...</variables> <faultHandlers> <catchAll>...</catchAll> </faultHandlers> <sequence> <!-- Receive the initial request for business travel from client --> <receive .../> <scope name="RetrieveEmployeeTravelStatus"> <variables>...</variables> <faultHandlers> <catchAll>...</catchAll> </faultHandlers> <sequence> <!-- Prepare the input for Employee Travel Status Web Service --> <!-- Synchronously invoke the Employee Travel Status Web Service --> <!-- Prepare the input for AA and DA --> </sequence> </scope> <scope name="CheckFlightAvailability"> <variables>...</variables> <faultHandlers> <catchAll>...</catchAll> </faultHandlers> <sequence> <!-- Make a concurrent invocation to AA and DA --> <flow> <!-- Async invoke the AA web service and wait for the callback --> <!-- Async invoke the DA web service and wait for the callback --> </flow> <!-- Select the best offer and construct the TravelResponse --> </sequence> </scope> <scope name="CallbackClient"> <faultHandlers>...</faultHandlers> <!-- Check if the ticket is approved --> </scope> </sequence> </process>
To signal faults to the BPEL process client, we will use the ClientCallbackFault
operation on the client partner link, which we defined in the previous section. This operation has a string message, which we will use to describe the fault. In real-world scenarios, the fault message is more complex and includes a fault code and other relevant information.
Let us start with the example. The process declaration and the partner links have not changed:
<process name="Travel" targetNamespace="http://packtpub.com/bpel/travel/" xmlns="http://docs.oasis- open.org/wsbpel/2.0/process/executable" xmlns:trv="http://packtpub.com/bpel/travel/" xmlns:emp="http://packtpub.com/service/employee/" xmlns:aln="http://packtpub.com/service/airline/" > <partnerLinks> <partnerLink name="client" partnerLinkType="trv:travelLT" myRole="travelService" partnerRole="travelServiceCustomer"/> <partnerLink name="employeeTravelStatus" partnerLinkType="emp:employeeLT" partnerRole="employeeTravelStatusService"/> <partnerLink name="AmericanAirlines" partnerLinkType="aln:flightLT" myRole="airlineCustomer" partnerRole="airlineService"/> <partnerLink name="DeltaAirlines" partnerLinkType="aln:flightLT" myRole="airlineCustomer" partnerRole="airlineService"/> </partnerLinks> ...
The variables section will now define only global variables. These are TravelRequest, FlightDetails, TravelResponse
, and TravelFault
. We have reduced the number of global variables, but we will have to declare other variables within scopes:
... <variables> <!-- input for this process --> <variable name="TravelRequest" messageType="trv:TravelRequestMessage"/> <!-- input for the Employee Travel Status web service --> <variable name="FlightDetails" messageType="aln:FlightTicketRequestMessage"/> <!-- output from BPEL process --> <variable name="TravelResponse" messageType="aln:TravelResponseMessage"/> <!-- fault to the BPEL client --> <variable name="TravelFault" messageType="trv:TravelFaultMessage"/> </variables> ...
Next, we define the global fault handlers section. Here, we use the<catchAll>
activity, through which we handle all faults not handled within scopes. We will signal the fault to the BPEL client:
... <faultHandlers> <catchAll> <sequence> <!-- Create the TravelFault variable --> <assign> <copy> <from>string('Other fault')</from> <to variable="TravelFault" part="error" /> </copy> </assign> <invoke partnerLink="client" portType="trv:ClientCallbackPT" operation="ClientCallbackFault" inputVariable="TravelFault" /> </sequence> </catchAll> </faultHandlers> ...
The main activity of the BPEL process will still be<sequence>
, and we will also specify the<receive>
activity to wait for the incoming message from the client:
... <sequence> <!-- Receive the initial request for business travel from client --> <receive partnerLink="client" portType="trv:TravelApprovalPT" operation="TravelApproval" variable="TravelRequest" createInstance="yes" /> ...
Now let's define the first scope for retrieving the employee travel status. Here, we will first declare two variables needed for the input and output messages for web service operation invocation:
... <scope name="RetrieveEmployeeTravelStatus"> <variables> <!-- input for the Employee Travel Status web service --> <variable name="EmployeeTravelStatusRequest" messageType="emp:EmployeeTravelStatusRequestMessage" /> <!-- output from the Employee Travel Status web service--> <variable name="EmployeeTravelStatusResponse" messageType="emp:EmployeeTravelStatusResponseMessage" /> </variables> ...
Next, we will define the fault handlers section for this scope. We will use the<catchAll>
activity to handle all faults, including Employee web service WSDL faults, communication faults, and other run-time faults. We will signal all faults to the client, although in real-world scenarios, we could invoke another web service or perform other recovery operations:
... <faultHandlers> <catchAll> <sequence> <!-- Create the TravelFault variable --> <assign> <copy> <from> string('Unable to retrieve employee travel status') </from> <to variable="TravelFault" part="error" /> </copy> </assign> <invoke partnerLink="client" portType="trv:ClientCallbackPT" operation="ClientCallbackFault" inputVariable="TravelFault" /> <exit/> </sequence> </catchAll> </faultHandlers> ...
Next, we will start a sequence (which is the main activity of the scope) and prepare the input variable, invoke the Employee web service, and prepare the input for both airlines' web services:
... <sequence> <!-- Prepare the input for the Employee Travel Status Web Service --> <assign> <copy> <from variable="TravelRequest" part="employee"/> <to variable="EmployeeTravelStatusRequest" part="employee"/> </copy> </assign> <!-- Synchronously invoke the Employee Travel Status Web Service --> <invoke partnerLink="employeeTravelStatus" portType="emp:EmployeeTravelStatusPT" operation="EmployeeTravelStatus" inputVariable="EmployeeTravelStatusRequest" outputVariable="EmployeeTravelStatusResponse" /> <!-- Prepare the input for AA and DA --> <assign> <copy> <from variable="TravelRequest" part="flightData"/> <to variable="FlightDetails" part="flightData"/> </copy> <copy> <from variable="EmployeeTravelStatusResponse" part="travelClass"/> <to variable="FlightDetails" part="travelClass"/> </copy> </assign> </sequence> </scope> ...
In the second scope, we check the flight availability with both airlines' web services. First, we declare two variables for storing output from both web service operations:
... <scope name="CheckFlightAvailability"> <variables> <!-- output from American Airlines --> <variable name="FlightResponseAA" messageType="aln:TravelResponseMessage"/> <!-- output from Delta Airlines --> <variable name="FlightResponseDA" messageType="aln:TravelResponseMessage"/> </variables> ...
Next, we define the fault handlers section, where we use the<catchAll>
activity similar to that in the first scope:
... <faultHandlers> <catchAll> <sequence> <!-- Create the TravelFault variable --> <assign> <copy> <from> string('Unable to invoke airline web service') </from> <to variable="TravelFault" part="error" /> </copy> </assign> <invoke partnerLink="client" portType="trv:ClientCallbackPT" operation="ClientCallbackFault" inputVariable="TravelFault" /> <exit/> </sequence> </catchAll> </faultHandlers> ...
The main activity of the second scope will be a<sequence>
, in which we will first concurrently invoke both airlines' web services using a<flow>
activity and then select the best offer using a<if>
activity:
... <sequence> <!-- Make a concurrent invocation to AA and DA --> <flow> <sequence> <!-- Async invoke of the AA web service and wait for the callback --> <invoke partnerLink="AmericanAirlines" portType="aln:FlightAvailabilityPT" operation="FlightAvailability" inputVariable="FlightDetails" /> <receive partnerLink="AmericanAirlines" portType="aln:FlightCallbackPT" operation="FlightTicketCallback" variable="FlightResponseAA" /> </sequence> <sequence> <!-- Async invoke of the DA web service and wait for the callback --> <invoke partnerLink="DeltaAirlines" portType="aln:FlightAvailabilityPT" operation="FlightAvailability" inputVariable="FlightDetails" /> <receive partnerLink="DeltaAirlines" portType="aln:FlightCallbackPT" operation="FlightTicketCallback" variable="FlightResponseDA" /> </sequence> </flow> <!-- Select the best offer and construct the TravelResponse --> <if> <condition> $FlightResponseAA.confirmationData/aln:Price <= $FlightResponseDA.confirmationData/aln:Price </condition> <!-- Select American Airlines --> <assign> <copy> <from variable="FlightResponseAA" /> <to variable="TravelResponse" /> </copy> </assign> <else> <!-- Select Delta Airlines --> <assign> <copy> <from variable="FlightResponseDA" /> <to variable="TravelResponse" /> </copy> </assign> </else> </if> </sequence> </scope> ...
In the third scope, we call back to the BPEL client. For this scope we do not need additional variables. However, we define a fault handler to handle the TicketNotApproved
fault. Therefore, we explicitly specify the fault name and the fault variable. Note that we do not use the<catchAll>
activity in this fault handlers section, so all unhandled faults will be re-thrown to the main process fault handler:
... <scope name="CallbackClient"> <faultHandlers> <catch faultName="trv:TicketNotApproved" faultVariable="TravelFault"> <!-- Make a callback to the client --> <invoke partnerLink="client" portType="trv:ClientCallbackPT" operation="ClientCallbackFault" inputVariable="TravelFault" /> </catch> </faultHandlers> ...
The main activity of this scope is the<if>
activity, where we check if the flight ticket has been approved:
... <!-- Check if the ticket is approved --> <if> <condition> $TravelResponse.confirmationData/aln:Approved='true' </ condition> <!-- Make a callback to the client --> <invoke partnerLink="client" portType="trv:ClientCallbackPT" operation="ClientCallback" inputVariable="TravelResponse" /> <else> <sequence> <!-- Create the TravelFault variable with fault description --> <assign> <copy> <from>string('Ticket not approved')</from> <to variable="TravelFault" part="error" /> </copy> </assign> <!-- Throw fault --> <throw faultName="trv:TicketNotApproved" faultVariable="TravelFault" /> </sequence> </else> </if> </scope> </sequence> </process>
For each scope we can specify whether we require concurrency control over shared variables, partner links, and dependency links. We will need such control if, in our scenario, more than one instance uses shared variables concurrently. This can occur, for example, if we use a parallel<forEach>
loop, which starts several parallel branches of the same<scope>
.
Scopes that require concurrency control are called isolated scopes. In isolated scopes, it is ensured that the results of the scope will be equal if all conflicting activities on all shared variables and partner links are done in any possible sequence. This guarantees that there will be no conflicting situations if several concurrent scopes access the same set of shared variables. Conflicting operations are in this case all read/write and write-only activities, such as assignments, incoming messages stored in variables, and so on. The semantics of isolated scopes are similar to the serializable transaction isolation level.
We denote a scope as isolated using the optional attribute isolated
and setting it to yes
. The default value of this attribute is no
. Isolated scopes must not contain other isolated scopes (but may contain scopes that are not marked as isolated). The fault handlers (and other handlers) associated with the scope also share the isolation. The following code excerpt shows how to declare a scope as isolated:
<scope isolated="yes" > ... </scope>
- iPad+Procreate數字插畫設計案例教程(全彩微課版)
- ANSYS19.0實例詳解
- Word 2010實戰技巧精粹
- Photoshop CS6中文版從入門到精通(核心技法卷):摳圖、修圖、Camera Raw、調色、銳化、合成
- Tomcat 6 Developer's Guide
- Creo 4.0從入門到精通
- CorelDRAW 2020中文版入門、精通與實戰
- 中文版Photoshop CC基礎培訓教程
- Premiere Pro CC 2015中文版基礎與實例教程(第4版)
- KNIME視覺化數據分析
- 3ds Max影視動畫角色設計技法教程
- Photoshop CC圖形圖像處理實戰教程(微課版)
- 中文版Flash CC實例教程
- jQuery 1.3 with PHP
- 攝影師的后期課:RAW格式技法篇