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 through 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
<terminate>
We can then combine these and other basic activities and define complex algorithms that exactly specify 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 - Case-switch construct (
<switch>
) for implementing branches - While (
<while>
) 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 <partnerLink>
, and declare variables, using <variable>
.
To provide an idea of how a BPEL process looks, we show below 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 web services (called insuranceA
and insuranceB
):
<?xml version=”1.0” encoding=”utf-8”?> <process name=”InsuranceSelectionProcess” targetNamespace=”http://packtpub.com/bpel/example/” xmlns=”http://schemas.xmlsoap.org/ws/2003/03/business-process/” xmlns:bpws=”http://schemas.xmlsoap.org/ws/2003/03/business-process/” 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 web services (<invoke>
) in parallel using the <flow>
activity. The insurance web services return the insurance premium. Then we select the lower amount (<switch>
/<case>
) 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 web service --> <invoke partnerLink=”insuranceA” portType=”ins:ComputeInsurancePremiumPT” operation=”ComputeInsurancePremium” inputVariable=”InsuranceRequest” outputVariable=”InsuranceAResponse” /> <!-- Invoke Insurance B web service --> <invoke partnerLink=”insuranceB” portType=”ins:ComputeInsurancePremiumPT” operation=”ComputeInsurancePremium” inputVariable=”InsuranceRequest” outputVariable=”InsuranceBResponse” /> </flow> <!-- Select the best offer and construct the response --> <switch> <case condition=”bpws:getVariableData(‘InsuranceAResponse’,‘confirmationData’,’/confirmationData/ins:Amount’) <= bpws:getVariableData(‘InsuranceBResponse’,‘confirmationData’,’/confirmationData/ins:Amount’)”> <!-- Select Insurance A --> <assign> <copy> <from variable=”InsuranceAResponse” /> <to variable=”InsuranceSelectionResponse” /> </copy> </assign> </case> <otherwise> <!-- Select Insurance B --> <assign> <copy> <from variable=”InsuranceBResponse” /> <to variable=”InsuranceSelectionResponse” /> </copy> </assign> </otherwise> </switch> <!-- 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 web services, we need a WSDL for the BPEL process.
Because each BPEL process is a web 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 Web 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 web services, using the <invoke>
construct. Such invocations can be done sequentially or in parallel. If we want to make them sequentially we simply write an <invoke>
for each invocation and the web 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 web 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 web 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 web 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 Web Services
We just explained how to invoke synchronous web service operations. There are actually two major types of web service operations:
- Synchronous request/reply web 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:
- Asynchronous web 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:
Callbacks usually need to be related to original requests. We call this message correlation. Message correlation can be achieved with WS-Addressing, explained in Chapter 2, or with BPEL correlation sets, which we explain in Chapter 4.
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 for 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 web 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 web 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 web 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 web 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 web 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 web services in two ways:
- The BPEL process invokes operations on other web 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 web 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 web 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 web service. The process invokes other web 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 offer them only 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 web service offers a portType
A
, through which the BPEL process invokes the operations on that web service. The BPEL process also has to provide a portType
through which the web service invokes the callback operation—let us call that portType
B
. This is shown in the following figure:
From the viewpoint of the BPEL process, the process requires portType
A
on the web service and provides portType
B
to the web service. From the perspective of the web service, the web 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 web service and providing the portType
B
to the web service. Alternatively, we select the web service perspective and describe the web 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 later port type is used for the callback operation. This declaration specifies the service and the callback roles:
<partnerLinkType name=”insuranceLT” xmlns=”http://schemas.xmlsoap.org/ws/2003/05/partner-link/”> <role name=”insuranceService”> <portType name=”ins:ComputeInsurancePremiumPT”/> </role> <role name=”insuranceRequester”> <portType name=”com:ComputeInsurancePremiumCallbackPT”/> </role> </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:
<partnerLinkType name=”insuranceLT” xmlns=”http://schemas.xmlsoap.org/ws/2003/05/partner-link/”> <role name=”insuranceService”> <portType name=”ins:ComputeInsurancePremiumPT”/> </role> </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 web 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 web 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://schemas.xmlsoap.org/ws/2003/05/partner-link/” > <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”> <plnk:portType name=”ins:ComputeInsurancePremiumPT”/> </plnk:role> <plnk:role name=”insuranceRequester”> <plnk:portType name=”ins:ComputeInsurancePremiumCallbackPT”/> </plnk:role> </plnk:partnerLinkType> </definitions>
Note
Sometimes existing web services will not define a partner link type. Then we can wrap the WSDL of the web 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 linkpartnerLinkType
: Defines the type of the partner linkmyRole
: Indicates the role of the BPEL process itselfpartnerRole:
Indicates the role of the partner
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 come 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 the 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 at least the following:
name
: Specifies the name of the BPEL business processtargetNamespace
: Specifies the target namespace for the business process definitionxmlns
: The namespace used by BPEL, http://schemas.xmlsoap.org/ws/2003/03/business-process/
Usually we also specify one or more additional namespaces to reference other involved namespaces, for example, those used by web services. Here is a typical process declaration tag:
<process name=”InsuranceSelectionProcess” targetNamespace=”http://packtpub.com/bpel/example/” xmlns=”http://schemas.xmlsoap.org/ws/2003/03/business-process/” xmlns:bpws=”http://schemas.xmlsoap.org/ws/2003/03/business-process/” 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. 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.suppressJoinFailure
: Determines how to handle join failures. Join failures are explained in Chapter 4.enableInstanceCompensation
: Determines whether process instances can be compensated by BPEL execution environments. We discuss this option in Chapter 4.abstractProcess
: Specifies whether the process is abstract or executable. The default for this attribute isno
, which means executable process. We specifyyes
if we wish to define an abstract process, which is explainedin Chapter 4.
Variables
BPEL business processes model the exchange of messages between involved web 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 messageelement
: A variable that can hold an XML Schema elementtype
: 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 have become familiar with the <invoke>
, <receive>
, and <reply>
activities. With <invoke>
, the BPEL process invokes operations on other web 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 for <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 usedportType
: Specifies the used port typeoperation
: Specifies the name of the operation to invoke (<invoke>
), to wait for being invoked (<receive>
), or the name of the operation which has been invoked but is synchronous and requires a reply (<reply>
)
<invoke>
The <invoke>
operation supports two other important attributes. When the business process invokes an operation on the web service, it sends a set of parameters. These parameters are modeled as input messages with web 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” > </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.
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:
<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 4.
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 4.
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 invocation of operations on partner web 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” type=”ins:InsuredPersonDataType” /> <part name=”insuranceDetails” type=”ins:InsuranceDetailsType” /> </message>
Now suppose that we get a variable of type ins:InsuredPersonDataType
from invoking another web service, which has the following message declaration in its WSDL and uses the same namespace:
... <message name=”InsuredPersonDataRequestMessage”> <part name=”insuredPersonData” type=”ins:InsuredPersonDataType” /> </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:InsuredPersonDataType
is defined as follows:
<xs:complexType name=”InsuredPersonDataType”> <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>
We could perform a copy from the LastName
variable to the InsuranceRequest
variable, to the message part insuredPersonData
, to the last name:
<assign> <copy> <from variable=”LastName” /> <to variable=”InsuranceRequest” part=”insuredPersonData” query=”/insuredPersonData/ins:LastName” /> </copy> </assign>
The location path must select exactly one node. In the query attribute, we specify an absolute location path, where the root ‘/
’ means the root of the document fragment representing the entire part of the message.
In our examples, we have used the message part name insuredPersonData
as the name of the first step (top-level element). This is because we have used RPC-style web services, which use messages defined as XML types. For example, the InsuranceRequest
variable is of type InsuranceRequestMessage
.
This message has been defined with two parts, each defined by an XML type, as shown on the code excerpt below:
<message name=”InsuranceRequestMessage”> <part name=”insuredPersonData” type=”ins:InsuredPersonDataType” /> <part name=”insuranceDetails” type=”ins:InsuranceDetailsType” /> </message>
If we had used document-style web services, which use messages defined as XML elements, we would have to use a slightly different XPath query expression. Instead of the part name we would use the element name for the first step in the query expression.
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
attribute in the <from>
element. The following example shows how to copy a constant string to the LastName
variable:
<assign> <copy> <from expression=”string(‘Juric’)” /> <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 constant XML complex element to the InsuredPersonRequest
variable. In this case, we can specify the source XML directly:
<assign> <copy> <from> <insuredPersonData xmlns=”http://packtpub.com/bpel/insurance/”> <FirstName>Matjaz B.</FirstName> <LastName>Juric</LastName> <Address>Ptuj</Address> <Age>30</Age> </insuredPersonData> </from> <to variable=”InsuredPersonRequest” part=”insuredPersonData” /> </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 <switch>
activity, where each branch is specified with its own <case>
element, followed by an <otherwise>
branch. The latter is optional. The following example shows the structure of the <switch>
activity:
<switch> <case condition=”boolean-expression”> <!-- some activity --> </case> <case condition=”boolean-expression”> <!-- some activity --> </case> ... <otherwise> <!-- optional --> <!-- some activity --> </otherwise> </switch>
The Boolean conditions for <case>
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. BPEL provides several extensions to built-in XPath functions. The extension related to variable data is the getVariableData
function, which extracts arbitrary values from variables. The function takes up to three parameters. The first, which is required, is the variable name. The second can be the message part name and the third the location path query. The syntax is shown in the following code excerpt:
bpws:getVariableData (‘variable-name’, ‘part-name’, <!-- optional --> ‘location-path’) <!-- optional -->
The location path query is written in the selected query language, and must specify the absolute path, where the root is the root of the document fragment.
The usage is straightforward. The following expression returns the insuredPersonPart
part of the message stored in the InsuranceRequest
variable:
bpws:getVariableData (‘InsuranceRequest’, ‘insuredPersonData’)
The following expression returns the Age
element (see the XML Schema in the previous section):
bpws:getVariableData (‘InsuranceRequest’, ‘insuredPersonData’, ‘/insuredPersonData/ins:Age’)
Let us now 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 expression is:
<switch> <case condition=”bpws:getVariableData(‘InsuranceRequest’, ‘insuredPersonData’, ‘/insuredPersonData/ins:Age’) > 50”> <!-- perform activities for age 51 and over --> </case> <case condition=”bpws:getVariableData(‘InsuranceRequest’, ‘insuredPersonData’, ‘/insuredPersonData/ins:Age’) > 25”> <!-- perform activities for age 26-50 --> </case> <otherwise> <!-- perform activities for age 25 and under --> </otherwise> </switch>
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.