官术网_书友最值得收藏!

Core concepts

A BPEL process consists of steps. Each step is called an activity. BPEL supports basic and structured activities. Basic activities represent basic constructs and are used for common tasks, such as those listed below:

  • Invoking other Web Services, using<invoke>
  • Waiting for the client to invoke the business process by sending a message, using<receive> (receiving a request)
  • Generating a response for synchronous operations, using<reply>
  • Manipulating data variables, using<assign>
  • Indicating faults and exceptions, using<throw>
  • Waiting for some time, using<wait>
  • Terminating the entire process, using<exit>

We can then combine these and other basic activities and define complex flows that specify exactly the steps of a business process. To combine basic activities, BPEL supports several structured activities. The most important are:

  • Sequence (<sequence>), for defining a set of activities that will be invoked in an ordered sequence
  • Flow (<flow>), for defining a set of activities that will be invoked in parallel
  • Conditional construct (<if>), for implementing branches
  • While, repeat, and for each (<while>,<repeatUntil>, <forEach>), for defining loops
  • The ability to select one of a number of alternative paths, using<pick>

Each BPEL process will also define partner links, using<partnerLinks>, and declare variables, using<variables>.

To provide an idea of how a BPEL process looks, we show a very simple BPEL process, which selects the best insurance offer from several.

We first declare the partner links to the BPEL process client (called client) and two insurance services (called insuranceA and insuranceB):

<?xml version="1.0" encoding="utf-8"?>
<process name="InsuranceSelectionProcess"
targetNamespace="http://packtpub.com/bpel/example/"
xmlns= "http://docs.oasis-open.org/wsbpel/2.0/process/executable"
xmlns:ins="http://packtpub.com/bpel/insurance/"
xmlns:com="http://packtpub.com/bpel/company/" >
<partnerLinks>
<partnerLink name="client" partnerLinkType="com:selectionLT"
myRole="insuranceSelectionService"/>
<partnerLink name="insuranceA" partnerLinkType="ins:insuranceLT"
myRole="insuranceRequester"
partnerRole="insuranceService"/>
<partnerLink name="insuranceB" partnerLinkType="ins:insuranceLT"
myRole="insuranceRequester"
partnerRole="insuranceService"/>
</partnerLinks>

Next, we declare variables for the insurance request (InsuranceRequest), insurance A and B responses (InsuranceAResponse, InsuranceBResponse), and for the final selection (InsuranceSelectionResponse):

<variables>
<!-- input for BPEL process -->
<variable name="InsuranceRequest" messageType="ins:InsuranceRequestMessage"/>
<!-- output from insurance A -->
<variable name="InsuranceAResponse" messageType="ins:InsuranceResponseMessage"/>
<!-- output from insurance B -->
<variable name="InsuranceBResponse" messageType="ins:InsuranceResponseMessage"/>
<!-- output from BPEL process -->
<variable name="InsuranceSelectionResponse" messageType="ins:InsuranceResponseMessage"/>
</variables>

Finally, we specify the process steps. First we wait for the initial request message from the client (<receive>). Then we invoke both insurance services (<invoke>) in parallel using the<flow> activity. The insurance services return the insurance premium. Then we select the lower amount (<if>) and return the result to the client (the caller of the BPEL process) using the<reply> activity:

<sequence>
<!-- Receive the initial request from client -->
<receive partnerLink="client" portType="com:InsuranceSelectionPT" operation="SelectInsurance" variable="InsuranceRequest" createInstance="yes" />
<!-- Make concurrent invocations to Insurance A and B -->
<flow>
<!-- Invoke Insurance A service -->
<invoke partnerLink="insuranceA" portType="ins:ComputeInsurancePremiumPT" operation="ComputeInsurancePremium" inputVariable="InsuranceRequest" outputVariable="InsuranceAResponse" />
<!-- Invoke Insurance B service -->
<invoke partnerLink="insuranceB" portType="ins:ComputeInsurancePremiumPT"
operation="ComputeInsurancePremium" inputVariable="InsuranceRequest" outputVariable="InsuranceBResponse" />
</flow>
<!-- Select the best offer and construct the response -->
<if>
<condition>
$InsuranceAResponse.confirmationData/ins:Amount &lt;=
$InsuranceBResponse.confirmationData/ins:Amount
</condition>
<!-- Select Insurance A -->
<assign>
<copy>
<from variable="InsuranceAResponse" />
<to variable="InsuranceSelectionResponse" />
</copy>
</assign>
<else>
<!-- Select Insurance B -->
<assign>
<copy>
<from variable="InsuranceBResponse" />
<to variable="InsuranceSelectionResponse" />
</copy>
</assign>
</else>
</if>
<!-- Send a response to the client -->
<reply partnerLink="client" portType="com:InsuranceSelectionPT" operation="SelectInsurance" variable="InsuranceSelectionResponse"/>
</sequence>
</process>

In the coming sections, we will explain the different parts of the BPEL process and the syntax of various BPEL activities.

Note

As BPEL processes are exposed as services, we need a WSDL for the BPEL process.

Because each BPEL process is a service, each BPEL process needs a WSDL document too. This is more or less obvious. As mentioned, a client will usually invoke an operation on the BPEL process to start it. With the BPEL process WSDL, we specify the interface for this operation. We also specify all message types, operations, and port types a BPEL process offers to other partners. We will show WSDL for the BPEL process later in this chapter.

Invoking services

A BPEL process definition is written as an XML document using the<process> root element. Within the<process> element, a BPEL process will usually have the top-level<sequence> element. Within the sequence, the process will first wait for the incoming message to start the process. This wait is modeled with the<receive> construct. Then the process will invoke the related services, using the<invoke> construct. Such invocations can be done sequentially or in parallel. If we want to make them sequential, we simply write an<invoke> for each invocation and the services will be invoked in that order. This is shown in the following code excerpt:

<process ...>
<sequence>
<!-- Wait for the incoming request to start the process -->
<receive ... />
<!-- Invoke a set of related services, one by one --> <invoke ... /> <invoke ... /> <invoke ... />
...
</sequence>
</process>

Here we have not shown the full syntax of<receive>, <invoke>, and other activities, which require that we specify certain attributes. This is explained later in this chapter, after we have become familiar with the basic structure of BPEL documents.

To invoke services concurrently, we can use the<flow> construct. In the example below, the three<invoke> operations would perform concurrently:

<process ...>
<sequence>
<!-- Wait for the incoming request to start the process -->
<receive ... />
<!-- Invoke a set of related services, concurrently --> <flow>
<invoke ... />
<invoke ... />
<invoke ... /> </flow>
</sequence>
</process>

We can also combine and nest the<sequence> and<flow> constructs, which allows us to define several sequences executing concurrently. In the following example we have defined two sequences, one consisting of three invocations, and one with two invocations. Both sequences would execute concurrently:

<process ...>
<sequence>
<!-- Wait for the incoming request to start the process -->
<receive ... />
<!-- Invoke two sequences concurrently -->
<flow>
<!-- The three invokes below execute sequentially -->
<sequence>
<invoke ... />
<invoke ... />
<invoke ... />
</sequence>
<!-- The two invokes below execute sequentially -->
<sequence>
<invoke ... />
<invoke ... />
</sequence>
</flow>
</sequence>
</process>

Invoking asynchronous services

We just explained how to invoke synchronous service operations. There are actually two major types of service operations:

  • Synchronous request/reply service operations: Here we send a request and wait for the reply. Such operations usually do not require much time to process; therefore, it is reasonable for the sender (client) to wait for the reply. They are shown in the following figure:
Invoking asynchronous services
  • Asynchronous service operations: Usually, such operations perform processing that requires a longer time to finish. Therefore, they do not block the sender for the duration of the operation. If such operations require that results are sent back to the client, they usually perform callbacks. This is shown in the following figure:
Invoking asynchronous services

Callbacks usually need to be related to original requests. We call this message correlation. Message correlation can be achieved automatically with WS-Addressing, or with BPEL correlation sets, which we will cover in Chapter 3.

Using the<invoke> construct, we can invoke both types of operations—synchronous and asynchronous. If we invoke a synchronous operation, the business process waits for the reply. We do not need to use an explicit construct to retrieve the reply.

With asynchronous operations,<invoke> only takes care of the first part—for the operation invocation. To receive a result (if one is returned to the client), we need to use a separate construct,<receive>. With<receive>, the business process waits for the incoming message. Between the<invoke> and<receive> we could do some other processing instead of waiting for the reply, as is the case with synchronous operations. The code excerpt below shows how to invoke asynchronous operations:

<process ...>
<sequence>
<!-- Wait for the incoming request to start the process -->
<receive ... /> <!-- Invoke an asynchronous operation --> <invoke ... /> <!-- Do something else... --> <!-- Wait for the callback --> <receive ... />
</sequence>
</process>

Just like synchronous operations, we can use asynchronous<invoke>/<receive> pairs within<flows> to perform several concurrent invocations.

Synchronous/Asynchronous business processes

We have already mentioned that the BPEL-modeled business process is exposed as a service. The BPEL process itself can be synchronous or asynchronous. A synchronous BPEL process returns a response to the client immediately after processing and the client is blocked for the whole duration of the BPEL process execution.

An asynchronous BPEL process, on the other hand, does not block the client. To return a result to the client, an asynchronous process uses a callback, similar to any other service. However, it is not required that such a BPEL process returns a response.

This brings us to the conclusion that the type of BPEL process we choose is very important. Most real-world processes are long running, so we model them as asynchronous. However, there may also be processes that execute in a relatively short time, or processes where we want the client to wait for completion. We model such processes as synchronous.

How do synchronous and asynchronous processes differ in the BPEL specification? We know that both first wait for the initial message, using a<receive>. Both also invoke other services, either synchronously or asynchronously. However, a synchronous BPEL process will return a result after the process has completed. Therefore, we use a<reply> construct at the end of the process, as shown in the following excerpt:

<process ...>
<sequence> <!-- Wait for the incoming request to start the process --> <receive ... />
<!-- Invoke a set of related services -->
... <!-- Return a synchronous reply to the caller (client) --> <reply ... />
</sequence>
</process>

An asynchronous BPEL process does not use the<reply> clause. If such a process has to send a reply to the client, it uses the<invoke> clause to invoke the callback operation on the client's port type. Remember that an asynchronous BPEL process does not need to return anything.

<process ...>
<sequence> <!-- Wait for the incoming request to start the process --> <receive ... />
<!-- Invoke a set of related services --> <!-- Invoke a callback on the client (if needed) --> <invoke ... />
</sequence>
</process>

We will come back to the<invoke>, <receive>, and<reply> activities a little later to describe the whole syntax, including the necessary attributes. First, however, we have to introduce the concept of partner links and partner link types.

Understanding links to partners

From what have we said until now, we can see that BPEL processes interact with external services in two ways:

  • The BPEL process invokes operations on other services.
  • The BPEL process receives invocations from clients. One of the clients is the user of the BPEL process, who makes the initial invocation. Other clients are services, for example, those that have been invoked by the BPEL process but make callbacks to return replies.

Links to all parties BPEL interacts with are called partner links. Partner links can be links to services that are invoked by the BPEL process. These are sometimes called invoked partner links. Partner links can also be links to clients, and can invoke the BPEL process. Such partner links are sometimes called client partner links. Note that each BPEL process has at least one client partner link, because there has to be a client that first invokes the BPEL process.

Usually a BPEL process will also have at least one invoked partner link because it will most likely invoke at least one service. The process invokes other services using the<invoke> activity, where it has to specify the operation name and the port type used for invocation, as we will see later. Invoked partner links may, however, become client partner links. This is usually the case with asynchronous services, where the process invokes an operation. Later the service (partner) invokes the callback operation on the process to return the requested data.

BPEL treats clients as partner links for two reasons. The most obvious reason is support for asynchronous interactions. In asynchronous interactions, the process needs to invoke operations on its clients. This is used for modeling asynchronous BPEL processes. Such processes also invoke the callback on the initial caller, as mentioned in the previous section.

The second reason is based on the fact that the BPEL process can offer services. These services, offered through port types, can be used by more than one client. The process may wish to distinguish between different clients and only offer them the functionality they are authorized to use. For example, an insurance process might offer a different set of operations to car-insurance clients than to real-estate-insurance clients. To sum up, partner links describe links to partners, where partners might be:

  • Services invoked by the process
  • Services that invoke the process
  • Services that have both roles—they are invoked by the process and they invoke the process

We have already described the first two scenarios. Let us now have a closer look at the third scenario—a typical asynchronous callback. Here a service offers a portType A, through which the BPEL process invokes the operations on that service. The BPEL process also has to provide a portType through which the service invokes the callback operation—let us call that portType B. This is shown in the following figure:

Understanding links to partners

From the viewpoint of the BPEL process, the process requires portType A on the service and provides portType B to the service. From the perspective of the service, the service offers portType A to the BPEL process and requires portType B from the process.

Partner link types

Describing situations where the service is invoked by the process, and vice versa, requires selecting a certain perspective. We can select the process perspective and describe the process as requiring the portType A on the service and providing the portType B to the service. Alternatively, we select the service perspective and describe the service as offering portType A to the BPEL process and requiring portType B from the process.

To overcome this limitation, BPEL introduces partner link types. They allow us to model such relationships as a third party. We are not required to take a certain perspective; rather, we just define roles. A partner link type must have at least one role and can have at most two roles. The latter is the usual case. For each role we must specify a portType that is used for interaction.

Note

A partner link type declares how two parties interact and what each party offers.

In the following example, we define a partnerLinkType called insuranceLT. It defines two roles, the insuranceService and the insuranceRequester. The insuranceService offers the ComputeInsurancePremiumPT port type from the namespace ins, qualified by the corresponding URI (the namespace declarations are not shown here). The insuranceRequester offers the ComputeInsurancePremiumCallbackPT port type from the com namespace. As the name implies, the latter port type is used for the callback operation. The following declaration specifies the service and the callback roles:

<partnerLinkType name="insuranceLT" xmlns="http://docs.oasis-open.org/wsbpel/2.0/plnktype">
<role name="insuranceService" portType="ins:ComputeInsurancePremiumPT"/>
<role name="insuranceRequester" portType="com:ComputeInsurancePremiumCallbackPT"/>
</partnerLinkType>

Sometimes we may not need to specify two roles. A typical example is when we use synchronous request/response operations. If the operations in the ComputeInsurancePremiumPT port type returned results immediately, there would be no need for a callback. We would only need a single role, which is done as follows:

<partnerLinkType name="insuranceLT" xmlns="http://docs.oasis-open.org/wsbpel/2.0/plnktype">
<role name="insuranceService" <portType="ins:ComputeInsurancePremiumPT"/>
</partnerLinkType>

If we specify only one role, we express willingness to interact with the service, but do not place any additional requirements on the service. In the first example, however, where we have specified two roles, we require that the insurance service supports the ComputeInsurancePremiumCallbackPT port type.

It is important to understand that the partner link types are not part of the BPEL process specification document. This is reasonable because partner link types belong to the service specification and not the process specification. They can therefore be placed in the WSDL document that describes the partner service or the BPEL process. Partner link types use the WSDL extensibility mechanism, so they can be a part of a WSDL document.

Shown below is a skeleton of the WSDL document with the partnerLinkType section. It specifies types, messages, port types, and partner link types. It does not, however, show the bindings and the service sections because the BPEL execution environment usually automatically generates these:

<?xml version="1.0" encoding="UTF-8" ?>
<definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ins="http://packtpub.com/bpel/insurance/" xmlns:com="http://packtpub.com/bpel/company/" targetNamespace="http://packtpub.com/bpel/company/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:plnk="http://docs.oasis-open.org/wsbpel/2.0/plnktype" >
<import ... />
<types>
<xs:schema ... >
...
</xs:schema>
</types>
<message ... >
<part ... />
...
</message>
<portType name="ComputeInsurancePremiumPT">
<operation name="...">
<input message="..." />
</operation>
</portType>
<portType name="ComputeInsurancePremiumCallbackPT">
<operation name="...">
<input message="..." />
</operation>
</portType>
... <plnk:partnerLinkType name="insuranceLT">
<plnk:role name="insuranceService" portType ="ins:ComputeInsurancePremiumPT"/>
<plnk:role name="insuranceRequester" portType ="ins:ComputeInsurancePremiumCallbackPT"/> </plnk:partnerLinkType>
</definitions>

Note

Sometimes existing services will not define a partner link type. Then we can wrap the WSDL of the service and define partner link types ourselves.

Now that we have become familiar with the partner link types and know where to place their declarations, it is time to go back to the BPEL process definition, more specifically to the partner links.

Defining partner links

We have already described the role of partner links in BPEL process specifications. However, we have not yet explained how to define partner links because we first had to get familiar with partner link types.

Partner links are concrete references to services that a BPEL business process interacts with. They are specified near the beginning of the BPEL process definition document, just after the<process> tag. Several<partnerLink> definitions are nested within the<partnerLinks> element:

<process ...> <partnerLinks> <partnerLink ... /> <partnerLink ... /> ... </partnerLinks>
<sequence>
...
</sequence>
</process>

For each partner link, we have to specify:

  • name: Serves as a reference for interactions via that partner link
  • partnerLinkType: Defines the type of the partner link
  • myRole: Indicates the role of the BPEL process itself
  • partnerRole: Indicates the role of the partner
  • initializePartnerRole: Indicates whether the BPEL engine should initialize the partner link's partner role value. This is an optional attribute and should only be used with partner links that specify partner role.

We define both roles (myRole and partnerRole) only if the partnerLinkType specifies two roles. If the partnerLinkType specifies only one role, the partnerLink also has to specify only one role—we omit the one that is not needed.

Let us go back to our previous example, where we have defined the insuranceLT partner link type. To define a partnerLink called insurance, characterized by the insuranceLT partnerLinkType, we need to specify both roles because it is an asynchronous relation. The role of the BPEL process (myRole) is described as insurance requester and the partner role is described as insurance service. The definition is shown in the following code excerpt:

<partnerLinks>
<partnerLink name="insurance" partnerLinkType="tns:insuranceLT" myRole="insuranceRequester" partnerRole="insuranceService"/>
</partnerLinks>

BPEL process tag

Now that we are more familiar with BPEL, let's focus on the<process> tag. This delimits the root element of the BPEL document. The<process> tag requires that we specify certain attributes. We have to specify the following at least:

Usually, we also specify one or more additional namespaces to reference other involved namespaces, for example, those used by services. Here is a typical process declaration tag:

<process name="InsuranceSelectionProcess" targetNamespace="http://packtpub.com/bpel/example/" xmlns="http://docs.oasis-open.org/wsbpel/2.0/process/executable" xmlns:ins="http://packtpub.com/bpel/insurance/" xmlns:com="http://packtpub.com/bpel/company/" >

We can also specify additional attributes for the<process> tag, including:

  • queryLanguage: Specifies which query language is used for node selection in assignments, properties, and other uses. The default is XPath 1.0 (urn:oasis:names:tc:wsbpel:2.0:sublang:xpatp.0). However, another language can be specified, such as XPath 2.0 or XQuery. The available options are determined by what is supported by a given BPEL engine.
  • expressionLanguage: Specifies which expression language is used in the process. The default is XPath 1.0 (urn:oasis:names:tc:wsbpel:2.0:sublang:xpatp.0).
  • suppressJoinFailure: Determines whether to suppress join failures (yes or no). The default is no. Join failures are explained in Chapter 3.
  • exitOnStandardFault: Defines how the process should behave when a standard fault occurs. We can specify yes if we want the process to exit on a standard fault (other than bpel:joinFailure), or no if we want to handle the fault using a fault handler. The default is no.

Variables

The BPEL business model processes the exchange of messages between involved services. Messages are exchanged as operations are invoked. When the business process invokes an operation and receives the result, we often want to store that result for subsequent invocations, use the result as is, or extract certain data. BPEL provides variables to store and maintain the state.

Note

Variables are used to store messages that are exchanged between business process partners or to hold data that relates to the state of the process.

Variables can also hold data that relates to the state of the process, but will never be exchanged with partners. Specifically, variables can store WSDL messages, XML schema elements, or XML schema simple types. Each variable has to be declared before it can be used. When we declare a variable, we must specify the variable name and type. To specify type we have to specify one of the following attributes:

  • messageType: A variable that can hold a WSDL message
  • element: A variable that can hold an XML schema element
  • type: A variable that can hold an XML schema simple type

The declaration of variables is gathered within the<variables> element. The following example shows three variable declarations. The first one declares a variable with the name InsuranceRequest, which holds WSDL messages of type ins:InsuranceRequestMessage. The second declaration defines a variable PartialInsuranceDescription that can hold XML elements of type ins:InsuranceDescription. The last variable declaration is for variable LastName, which can hold XML schema string type data. The first two declarations assume that the corresponding messageType and element have been declared in the WSDL (these declarations are not shown here):

<variables>
<variable name="InsuranceRequest" messageType="ins:InsuranceRequestMessage"/>
<variable name="PartialInsuranceDescription" element="ins:InsuranceDescription"/>
<variable name="LastName" type="xs:string"/>
</variables>

You can declare variables globally at the beginning of a BPEL process declaration document or within scopes. Here we focus on globally-declared variables and discuss scopes in the next chapter. The following example shows the structure of a BPEL process that uses variables:

<process ...>
<partnerLinks>
...
</partnerLinks> <variables> <variable ... /> <variable ... /> ... </variables>
<sequence>
...
</sequence>
</process>

Providing the interface to BPEL processes: <invoke>, <receive>, and <reply>

At the beginning of this section, we became familiar with the<invoke>, <receive>, and<reply> activities. With<invoke>, the BPEL process invokes operations on other services, while with<receive>, it waits for incoming messages (that is, operation invocations). With<receive>, the business process usually waits for the initial message to start the process. Another typical use of<receive> is to wait for callbacks. With<reply>, a BPEL process can send a response, if the process is modeled as synchronous.

All three activities use the same three basic attributes:

  • partnerLink: Specifies which partner link will be used
  • portType: Specifies the used port type
  • operation: Specifies the name of the operation to invoke (<invoke>), to wait to be invoked (<receive>), or the name of the operation which has been invoked but is synchronous and requires a reply (<reply>)

Note

For each BPEL activity we can specify a name attribute. We use the name attribute to provide names for activities. In most BPEL activities the name attribute is optional, but we can add it to improve the readability of the code.

<invoke>

The<invoke> operation supports two other important attributes. When the business process invokes an operation on the service, it sends a set of parameters. These parameters are modeled as input messages with services. To specify the input message for the invocation, we use the inputVariable attribute and specify a variable of the corresponding type.

If we invoke a synchronous request/response operation, it returns a result. This result is again a message, modeled as an output message. To store it in a variable,<invoke> provides another attribute, called the outputVariable.

The following code excerpt shows an example of the<invoke> clause. We specify that the BPEL process should invoke the synchronous operation ComputeInsurancePremium on port type ins:ComputeInsurancePremiumPT using the insuranceA partner link, providing the input from variable InsuranceRequest, and storing output in the InsuranceAResponse variable:

<invoke partnerLink="insuranceA" portType="ins:ComputeInsurancePremiumPT" operation="ComputeInsurancePremium" inputVariable="InsuranceRequest" outputVariable="InsuranceAResponse" >
message flowmessage flow<invoke> activity</invoke>

<receive>

Let us now take a closer look at the<receive> activity. We have said that<receive> waits for the incoming message (operation invocation), either for the initial to start the BPEL process, or for a callback. Usually, the business process needs to store the incoming message, and it can use the variable attribute to specify a suitable variable.

Another attribute for<receive> activity is the createInstance attribute, which is related to the business process lifecycle and instructs the BPEL engine to create a new instance of the process. Usually, we specify the createInstance="yes" attribute with the initial<receive> activity of the process to create a new process instance for each client. We discuss this attribute in more detail in the next chapter.

Another optional attribute for<receive> activity is messageExchange, which is used to disambiguate the relationship between inbound message activities and<reply> activities. We will discuss message exchange in Chapter 3.

The following example shows a<receive> that waits for the SelectInsurance operation on port type com:InsuranceSelectionPT using the client partner link. Because this is the initial<receive> activity, the createInstance attribute is used. The client request is stored in the InsuranceRequest variable as follows:

<receive partnerLink="client" portType="com:InsuranceSelectionPT" operation="SelectInsurance" variable="InsuranceRequest" createInstance="yes" >
</receive>

<reply>

Finally, let's look at the<reply> clause. As we already know,<reply> is used to return the response for synchronous BPEL processes.<reply> is always related to the initial<receive> through which the BPEL process started. Using<reply>, we can return the answer, which is the normal usage, or we can return a fault message. Returning a fault message using<reply> is discussed in Chapter 3. We can also specify a message exchange.

When we use<reply> to return a response for a synchronous process, we have to define only one additional attribute—the name of the variable where the response is stored. The following example shows a reply on an initial receive operation. It uses the client partner link and provides a response for the SelectInsurance operation on ins:InsuranceSelectionPT port type. The return result is stored in the InsuranceSelectionResponse variable. Please notice that the same partnerLink, portType, and operation name have been used in the initial<receive> clause:

<reply partnerLink="client" portType="com:InsuranceSelectionPT" operation="SelectInsurance" variable="InsuranceSelectionResponse" >
</reply>

The three activities,<invoke>, <receive>, and<reply> support additional functionality. They all support correlations, and<invoke> also supports fault handlers and compensation handlers. We will discuss these in Chapter 3.

Assignments

The variables in the business process hold and maintain the data. We used variables in<invoke>, <receive>, and<reply> to specify the input and output messages for invoking operations on partner services. In this section, we get familiar with how to copy data between variables.

To copy data between variables, expressions, and partner link endpoint references, BPEL provides the<assign> activity. Within it, we can perform one or more<copy> commands. For each<copy>, we have to specify the source (<from>) and the destination (<to>). The syntax of an assignment is presented below:

<assign>
<copy>
<from ... />
<to ... />
</copy>
<copy>
<from ... />
<to ... />
</copy>
...
</assign>

There are several choices for the<from> and<to> clauses. To copy values from one variable to the other, we have to specify the variable attribute in the<from> and<to> elements. This is shown in the following example, where we have copied a value from the InsuranceAResponse variable to the InsuranceSelectionResponse variable:

<assign>
<copy>
<from variable="InsuranceAResponse" />
<to variable="InsuranceSelectionResponse" />
</copy>
</assign>

This copy can be performed only if both variables are of same type, as in our example ins:InsuranceResponseMessage, or if the source type is a subtype of the destination type.

Variables can be of three types:

  • WSDL message types
  • XML schema elements
  • XML schema primitive types

If a variable holds a WSDL message, which is common, we can further refine the copy by specifying the part of the message we would like to copy. WSDL messages consist of parts (more on WSDL can be found at http://www.w3.org/TR/wsdl). Presented below is a simple message (defined in the WSDL document) that consists of two parts—the insuredPersonData part and the insuranceDetails part. Both parts are specified with the corresponding XML schema complex types (not shown here):

<message name="InsuranceRequestMessage">
<part name="insuredPersonData" element="ins:InsuredPersonData" />
<part name="insuranceDetails" element="ins:InsuranceDetails" />
</message>

Now suppose that we get a variable of type ins:InsuredPersonDataType from invoking another service, which has the following message declaration in its WSDL and uses the same namespace:

<message name="InsuredPersonDataRequestMessage">
<part name="insuredPersonData" element="ins:InsuredPersonData" />
</message>

Our BPEL process would declare two variables, InsuranceRequest and InsuredPersonRequest, with the declaration shown below:

<variables>
<variable name="InsuranceRequest" messageType="ins:InsuranceRequestMessage"/>
<variable name="InsuredPersonRequest" messageType="ins:InsuredPersonDataRequestMessage"/>
</variables>

Now we could perform a copy from the InsuredPersonRequest variable to the insuredPersonData part of the InsuranceRequest variable, using the following assignment:

<assign>
<copy>
<from variable="InsuredPersonRequest" part="insuredPersonData" />
<to variable="InsuranceRequest" part="insuredPersonData" />
</copy>
</assign>

We could also perform a copy in the opposite direction. In addition to specifying the part, we can also specify the exact path to the element we require. To specify the path, we have to write a query, using the selected query language specified within the<process> tag.

Note

The default query language is XPath 1.0.

In our previous example, suppose the ins:InsuredPersonData is defined as follows:

<xs:element name="InsuredPersonData">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName" type="xs:string" />
<xs:element name="LastName" type="xs:string" />
<xs:element name="Address" type="xs:string" />
<xs:element name="Age" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:element>

We could perform a copy from the LastName variable to the InsuranceRequest variable, to the message part insuredPersonData, and to the last name:

<assign>
<copy>
<from variable="LastName" />
<to variable="InsuranceRequest" part="insuredPersonData">
<query>ins:LastName</query>
</to>
</copy>
</assign>

The location path must select exactly one node.

We can also use the<assign> activity to copy expressions to variables. Expressions are written in the selected expression language; the default is XPath 1.0. We specify the expression within the<from> element. The following example shows how to copy a constant string to the LastName variable:

<assign>
<copy>
<from>string('Juric')</from>
<to variable="LastName"/>
</copy>
</assign>

We are not restricted to such simple expressions. We can use any valid XPath 1.0 expressions (or the expressions of the selected expression language). For more information, refer to the XPath 1.0 specification: http://www.w3.org/TR/xpath.

Another possibility is to copy a literal XML complex element to the InsuredPersonRequest variable. In this case, we can specify the source XML directly:

<assign>
<copy>
<from>
<literal>
<insuredPersonData
xmlns="http://packtpub.com/bpel/insurance/">
<FirstName>Matjaz B.</FirstName>
<LastName>Juric</LastName>
<Address>Ptuj</Address>
<Age>30</Age>
</insuredPersonData>
</literal>
</from>
<to variable="InsuredPersonRequest" part="insuredPersonData" />
</copy>
</assign>

We can specify two optional attributes for the<copy> activity:

  • keepSrcElementName: Specifies whether the element name of destination will be replaced by the element name of the source. The default is no.
  • ignoreMissingFromData: Specifies whether the BPEL engine should ignore missing data in the<from> part of the copy assignment (and not raise a fault). The default is no.

    We can also specify an optional attribute for the <assign> activity.

  • validate: If set to yes, the assign activity will validate all variables being modified by the<assign>. The default is no.

Validating variables

Sometimes, particularly after assignments (if we did not use validation in assignments), it makes sense to validate the variables against their associated XML schemas and WSDL definitions. We can validate the variables explicitly using the<validate> activity.

It is very simple to validate variables. We just have to list all variable names that we would like to validate. We separate the variable names with space. The syntax is as follows:

<validate variables="BPELVariableNames" />

For example, if we would like to validate variables InsuredPersonRequest, InsuranceRequest, and PartialInsuranceDescription, we would write the following:

<validate variables="InsuredPersonRequest InsuranceRequest PartialInsuranceDescription " />

Accessing variables in expressions

We can access BPEL variables from XPath expressions. This is particularly useful in<copy> assignments, where we would like to access specific nested elements. We access BPEL variables in XPath using the $ operator. We will look at the three types of variables (variables can be of a messageType, element, or type).

Let us first look at messageType variables. Let us assume that we have the following definition of a variable:

<variables>
<variable name="InsuredPersonRequest" messageType="ins:InsuredPersonDataRequestMessage"/>
</variables>

Where the WSDL message and the corresponding XML schema look as follows:

<message name="InsuredPersonDataRequestMessage">
<part name="insuredPersonData" element="ins:InsuredPersonData" />
</message>
<xs:element name="InsuredPersonData">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName" type="xs:string" />
<xs:element name="LastName" type="xs:string" />
<xs:element name="Address" type="xs:string" />
<xs:element name="Age" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:element>

We can access such variables from XPath in the following way:

 $variableName.messagePart/ns:node/ns:node...

For example, if we would like to access the LastName from the InsuredPersonRequest variable, we would need to write:

$InsuredPersonRequest.insuredPersonData/ins:LastName

Let us now look at an example, where the variable contains an XML element. Let us assume that we have the following definition of a variable:

<variables>
<variable name="PartialInsuranceDescription" element="ins:InsuranceDescription"/>
</variables>

Where the XML schema looks as follows:

<xs:element name="InsuranceDescription">
<xs:complexType>
<xs:sequence>
<xs:element name="Code" type="xs:string" />
<xs:element name="Description" type="xs:string" />
<xs:element name="ValidFrom" type="xs:date" />
</xs:sequence>
</xs:complexType> </xs:element>

We can access such variables from XPath in the following way:

 $variableName/ns:node/ns:node...

For example, if we would like to access the Description from the PartialInsuranceDescription variable, we would need to write:

$PartialInsuranceDescription/ins:Description

Finally, let us look at an example, where the variable contains an XML type. Let us assume that we have the following definition of a variable:

<variables>
<variable name="Address" type="ins:AddressType"/>
</variables>

Where the XML schema looks as follows:

<xs:complexType name="AddressType">
<xs:sequence>
<xs:element name="Street" type="xs:string" />
<xs:element name="Number" type="xs:int" />
<xs:element name="City" type="xs:string" />
</xs:sequence>
</xs:complexType>

We can access such variables from XPath in the following way:

$variableName/ns:node/ns:node... 

For example, if we would like to access the Street from the Address variable, we would write:

$Address/ins:Street

XSLT transformations

Using the assignments to copy data from one variable to another is useful. However, if we deal with complex XML schemas and have to perform transformations between different schemas, using the<copy> construct alone would be very time consuming. A much better approach would be to use XSLT transformations.

The<assign> activity provides support for XSLT transformations. We can invoke an XSLT transformation from an assignment using the bpel:doXslTransform() function. The bpel:doXslTransform() is a XPath extension function. The syntax is as follows:

bpel:doXslTransform('style-sheet-URI', node-set, ('xslt-parameter', value)*)

The first parameter is the URI that points to the XSLT stylesheet. We have to provide a string literal and cannot use a variable here because the BPEL server has to statically analyze the XSLT stylesheet.

The second parameter is the node set on which the XSLT transformation should be performed. Here we provide an XPath expression. In most cases, we will provide a variable (as described in the previous section).

Optionally, we can specify XSLT parameters (if our XSLT stylesheet requires parameters). We always specify parameters in pairs: first the name of the parameter, then the value. The value can be an XPath expression (for example, a BPEL variable). We can specify several pairs of parameters.

For example, we can use an XSLT transformation to transform the data stored in the PersonData variable and copy the result of the transformation to the InsuredPersonRequest variable:

<assign>
<copy>
<from>
bpel:doXslTransform( "http://packtpub.com/xslt/person.xsl", $PersonData)
</from>
<to variable="InsuredPersonRequest" />
</copy>
</assign>

Conditions

We have to get familiar with one more construct before we are ready to start developing our BPEL processes. In a business process specification, we usually have to make choices based on conditions. In BPEL, conditional branches are defined with the<if> activity. The<if> activity can have several<elseif> branches and one<else> branch. The following example shows the structure of the<if> activity:

<if>
<condition> boolean-expression </condition>
<!-- some activity -->
<elseif>
<condition> boolean-expression </condition>
<!-- some activity -->
</elseif>
<elseif>
<condition> boolean-expression </condition>
<!-- some activity -->
</elseif>
...
<else>
<!-- some activity -->
</else>
</if>

The Boolean expressions for<condition> elements are expressed in the selected query language. Since the default query language is XPath 1.0, we can use any valid XPath expression that returns a Boolean value.

Variables are usually used in conditions. We access variables in conditions in the same way as in assignments. We have described it in the previous section.

Let us define a conditional branch, based on the age of the insured person. Suppose we want to make three different activities, based on the ages from 0-25, 26-50, and 51 and above. The BPEL would look as follows:

<if>
<condition>
$InsuranceRequest.insuredPersonData/ins:Age &gt; 50
</condition>
<!-- perform activities for age 51 and over -->
<elseif>
<condition>
$InsuranceRequest.insuredPersonData/ins:Age &gt; 25
</condition>
<!-- perform activities for age 26-50 -->
</elseif>
<else>
<!-- perform activities for age 25 and under -->
</else>
</if>

Activity names

For each BPEL activity, such as<if>, <invoke>, <reply>, <sequence>, and so on, we can specify a name by using the name attribute. This attribute is optional and can be used with all basic and structured activities. For instance, the Employee Travel Status web service invocation activity could be named EmployeeTravelStatusSyncInv; this is shown in the code excerpt below. We will see that naming activities is useful on several occasions, for example, when invoking inline compensation handlers or when synchronizing activities.

...
<invoke name="EmployeeTravelStatusSyncInv" partnerLink="employeeTravelStatus" portType="emp:EmployeeTravelStatusPT" operation="EmployeeTravelStatus" inputVariable="EmployeeTravelStatusRequest" outputVariable="EmployeeTravelStatusResponse" />
...

Activity names also improve the readability of BPEL processes.

Documentation

To include documentation into the BPEL code, we can use the<documentation> construct. We can add this construct to any BPEL activity. For example, we could add documentation to the above-mentioned<invoke> activity:

...
<invoke name="EmployeeTravelStatusSyncInv" partnerLink="employeeTravelStatus" portType="emp:EmployeeTravelStatusPT" operation="EmployeeTravelStatus" inputVariable="EmployeeTravelStatusRequest" outputVariable="EmployeeTravelStatusResponse">
<documentation>
Invoking the Employee Travel Status service to get the travel class for an employee.
</documentation>
</invoke>
...

Now we know enough to start writing BPEL business process definitions. In the next section, we will write a sample BPEL business process to get familiar with using the core concepts.

主站蜘蛛池模板: 阳东县| 贵港市| 广德县| 固始县| 阜宁县| 四平市| 礼泉县| 淄博市| 五寨县| 嘉鱼县| 日照市| 沾益县| 军事| 镇远县| 肇庆市| 申扎县| 蓬莱市| 遵义县| 涿鹿县| 尉氏县| 且末县| 西宁市| 孟连| 米林县| 会同县| 延川县| 息烽县| 武汉市| 阳新县| 东港市| 蕉岭县| 肥西县| 柘荣县| 五大连池市| 东乌珠穆沁旗| 辉南县| 从江县| 屯昌县| 翁源县| 资源县| 平塘县|