Time for action – adding scopes

  1. Let's create two scopes and add those two <invoke> activities into those two scopes separately, so we can define local variables, partner links, and so on, which are only visible within a particular <scope> activity. So drag-and-drop the <scope> activities inside the sequences where the <invoke> activities are, as shown in the following screenshot:
    Time for action – adding scopes
  2. Now we can drag the existing <invoke> activities into the newly added <scope> activities:
    Time for action – adding scopes
  3. Now, the remaining task is to transfer the variables from the global phase to local phase. If you look at the variable hierarchy within the process definition, it looks like the following screenshot:
    Time for action – adding scopes
  4. There is not a straightforward transfer mechanism. So, to transfer what we can do is to clone the definition on the global variable within the <scope> activity and delete the global variable. So, the final variable hierarchy within the process definition will be as shown:
    Time for action – adding scopes
  5. Likewise we can further modify the BPEL process, by adding new <scope> activities to provide different contexts of resources such as variables, partner links, correlation sets, and so on. Also, the handlers that are fault handlers, termination handlers, event handlers, and compensation handlers also can be defined within the scopes.

What just happened?

In the preceding section, we reused the main example defined in Chapter 5, Interaction Patterns in BPEL, and moved global variables, partner links, and invoke activities into scopes. We demonstrated how to encapsulate partner links, variables, correlation sets, and fault handlers related to each service invocation within child scopes. And now we realized that the WS-BPEL 2.0 process can maintain multiple variables with the same name but in different scopes.

How to organize scopes

In the previous section, we gave a general introduction on the <scope> activity and the basic use of it. In this section, we discuss the semantics of the <scope> activity in detail. So, we explain the difference between a <scope> and a <process> activity, and why the <scope> activity is helpful compared to structured activities such as <sequence> or <flow>. Then, we explain how to define a scope within a BPEL process definition.

Using <scope> in place of <process>

As we explained the <scope> activity in the introduction, a <scope> activity is capable of maintaining a set of resources that are local to the particular scope and its enclosed activities. On the other hand, we can define such resources at global level by defining them in the top level <process> construct. However, why do we need to define resources within scopes?

To figure out the answer, let's take an example of a BPEL process that has two different web service invocations (for example, the main example defined in Chapter 5, Interaction Patterns in BPEL). These two invocations need to declare two separate input variables. So, the two <invoke> activities can refer those input variables to send the outgoing request messages to the external web services.

Once we define the two input variables at global level, then both the <invoke> activities can see each other's input variables. This is not a good practice of BPEL programming because these variables are either used by only one <invoke> activity. However, both <invoke> activities can see each other's input variables. Another issue is the global level variables retained in the memory until the BPEL process completes. What if we declare an input variable, relevant partner link, and the associated <invoke> activity within a <scope> activity? Both the <invoke> activities are encapsulated along with the resources that are only associated with the relevant <invoke> activities. A performance improvement is BPEL runtime which now only needs to keep the variables in memory until the scope completes. This improves the readability of the BPEL code and makes the BPEL code more simplified. The overall performance of the execution of BPEL processes is also improved. Generally, the resources should not be declared globally unless it is really necessary.

Another reason is that the <process> construct does not support compensation handler and termination handler. However, in some cases, we may need to define compensation and termination behavior to activities such as <invoke>. In such a scenario, the <scope> activity becomes essential as the enclosing activity of such activities. On the contrary, the <scope> activity doesn't support the <import> and <extensions> declarations. So, the <import> and <extensions> activities should be declared only at the global level.

One other difference is that the <process> is not considered as an activity. And it is only used as the top-level element in a BPEL process definition. There's only one <process> element in a BPEL process definition. On the other hand, the <scope> activity can enclose other child <scope> activities and there can be multiple <scope> activities that are not related to each other.

Based on those explanations, there are significant differences among a <scope> activity and a <process> activity, and in a nutshell, declaring resources at the local level is a best practice compared to global level resources.

Using <scope> in place of <sequence> or <flow>

In the previous section, Using <scope> in place of <process>, we discussed the differences between <process> and the <scope>. In this section, we discuss the difference between the <scope> activity and a structural activity such as <sequence> and <flow>.

We already know that the <scope> is capable of defining local resources such as partner links and variables, but the structural activities do not have such support. In order to define local variables such as resources to a structural activity, the particular structural activity should be enclosed within a scope and define such resources within it as follows:

<scope name="EnclosingScope">
  <variables>...</variables>
  <faultHandlers>
    <catchAll>...</catchAll>
  </faultHandlers>
  <sequence>
    <!-- Prepare the input for external Web Service invocation -->
    <!-- Synchronously invoke the external Web Service -->
  </sequence>
</scope>

What to consider when defining a scope

In the Using <scope> in place of <process> and Using <scope> in place of <sequence> or <flow> sections, we realized some major differences of the <scope> activity compared to <process> and the structural activities. That discussion helps to realize some of the considerations to keep in mind when defining a <scope> activity. Here are some facts that we need to consider when defining a <scope> and determining enclosed activities of that <scope> activity.

Encapsulating a logical unit of work

A <scope> activity can be used to divide a BPEL process into hierarchically organized parts. These parts should encapsulate one logical thing. As an example, suppose a BPEL process that invokes two external web services. There should be two <assign> activities that manipulate the input variables required for two invocations. The BPEL process can be divided by creating two <scope> activities so that each enclose the <assign> and <invoke> activities, as shown in the following code:

<flow>
  <scope name="EnclosingScope1">
    <variables>...</variables>
    <partnerLinks>...</partnerLinks>
    <sequence>
      <!-- Prepare the input for external Web Service 1 invocation -- >
      <!-- Synchronously invoke the external Web Service 1 -->
    </sequence>
  </scope>
  <scope name="EnclosingScope2">
    <variables>...</variables>
    <partnerLinks>...</partnerLinks>
    <sequence>
      <!-- Prepare the input for external Web Service 2 invocation -- >
      <!-- Synchronously invoke the external Web Service 2 -->
    </sequence>
  </scope>
<flow>

Using two scopes, both the service invocations get better encapsulation as they can contain their own local variables, partner links, fault handlers, and so on. If we defined those two service invocations within one <scope> activity, then the variables, partner links, and so on, are visible to both invocations. Also, the fault handling logic has to be defined within a single fault handler.

A unit of work that needs customized compensation or termination

Apart from the better encapsulation, the <scope> activity becomes essential when there is an activity or a set of activities that require compensation or termination. This is because the compensation or termination handlers are only supported by the <scope> activity.

Fault and termination handling within scopes

Previously, we discussed how to add variables, partner links to a <scope> activity. During the remaining part of this chapter, we will discuss about handlers that can be defined within a <scope> activity and the isolated scopes. As a concrete example, let's first realize how to define a fault handler within a scope.

In the section entitled Time for action – adding scopes, we separately enclosed two selected <invoke> activities with two <scope> activities. We moved variables, which are referred only by those <invoke> activities, into those scopes. In the next exercise, we will improve the same BPEL process.

W are going to add an inline fault handler to the <scope> activity that includes an external service invocation. If a fault occurs during the external service execution, the inline fault handler is triggered, as shown in the following screenshot:

Fault and termination handling within scopes

An inline fault handler to signal generated faults to the client

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset