7 min read

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 article 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.

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.–>
</messageExchanges>
<variables>
<!– Variable definitions local to scope. –>
</variables>
<correlationSets>
<!– Correlation sets local to scope.–>
</correlationSets>
<faultHandlers>
<!– Fault handlers local to scope. –>
</faultHandlers>
<compensationHandler>
<!– Compensation handlers local to scope.–>
</compensationHandler>
<terminationHandler>
<!– Termination handler local to scope. –>
</terminationHandler>
<eventHandlers>
<!– Event handlers local to scope. –>
</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, which is 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 article 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 rethrown 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 rethrown 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 to if it reached an <exit> activity). If we do not set this attribute, it inherits the value from its enclosing <scope> or <process>.

How scopes can be used in BPEL processes

To demonstrate how scopes can be used in BPEL processes, we will rewrite our asynchronous travel process example and introduce three scopes:

  • In the first scope, we will retrieve the employee travel status(RetrieveEmployeeTravelStatus)
  • In the second scope, we will check the flight availability with both airlines(CheckFlightAvailability)
  • In the third scope, we will call back to the client (CallbackClient)

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 article. 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/”

>
<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” />

LEAVE A REPLY

Please enter your comment!
Please enter your name here