Business Process Execution Language for Web Services 2nd Edition
上QQ阅读APP看书,第一时间看更新

BPEL Business Process Example

To demonstrate how business processes are described with BPEL, we will define a simple business process for business travels. Let us consider the business travel process. We describe an oversimplified scenario, where the client invokes the business process, specifying the name of the employee, the destination, the departure date, and the return date. The BPEL business process first checks the employee travel status. We will suppose that a web service exists through which such a check can be made. Then the BPEL process will check the price for the flight ticket with two airlines: American Airlines and Delta Airlines. Again we will suppose that both airline companies provide a web service through which such check can be made. Finally, the BPEL process will select the lower price and return the travel plan to the client.

For the purposes of this example we first build a synchronous BPEL process, to maintain simplicity. This means that the client will wait for the response. Later in this chapter, we modify the example and make the BPEL process asynchronous. We will assume that the web service for checking the employee travel status is synchronous. This is reasonable, because such data can be obtained immediately and returned to the caller.

To acquire the plane ticket prices we use asynchronous invocations. Again, this is reasonable, because it might take a little longer to confirm the plane travel schedule. We assume that both airlines offer a web service and that both web services are identical (provide equal port types and operations). This assumption simplifies our example. In real-world scenarios, you will usually not have the choice about the web services, but will have to use whatever services are provided by your partners. If you have the luxury of designing the web services along with the BPEL process, consider which is the best interface. Usually we use asynchronous services for long-lasting operations and synchronous services for operations that return a result in a relatively short time. If we use asynchronous web services, the BPEL process is usually asynchronous as well.

In our example, we first develop a synchronous BPEL process that invokes two asynchronous airline web services. This is legal, but not recommended in real-world scenarios since the client may have to wait an arbitrarily long time. In the real world, the solution would be to develop an asynchronous BPEL process, which we will do later in this chapter.

We invoke both airlines’ web services concurrently and asynchronously. This means that our BPEL process will have to implement the callback operation (and a port type), through which the airlines will return the flight ticket confirmation.

Finally, the BPEL process returns the best airline ticket to the client. In this example, to maintain simplicity, we will not implement any fault handling, which is crucial in real-world scenarios. This topic is discussed in the next chapter.

Let’s start by presenting the BPEL process activities using a UML activity diagram. In each activity, we have used the stereotype to indicate the BPEL operation used:

Although the presented process might seem very simple, it will offer a good start for learning BPEL. To develop the BPEL process, we will go through the following steps:

  • Get familiar with the involved web services
  • Define the WSDL for the BPEL process
  • Define partner link types
  • Define partner links
  • Declare variables
  • Write the process logic definition

Involved Web Services

Before we can start writing the BPEL process definition, we have to get familiar with all web services invoked from our business process. These services are sometimes called partner web services. In our example, three web services are involved:

  • The Employee Travel Status web service
  • The American Airlines web service
  • Delta Airlines web service

Note: The two airline services share equal WSDL descriptions.

The web services used in this example are not real, so we will have to write WSDLs and even implement them to run the example. In real-world scenarios we would obviously use real web services exposed by partners involved in the business process.

Note

The web services and the BPEL process example can be downloaded from http://www.packtpub.com. The example runs on Oracle BPEL Process Manager.

Web services’ descriptions are available through WSDL. WSDL specifies the operations and port types web services offer, the messages they accept, and the types they define. We can also find out whether each web service uses a document or RPC approach and whether it uses literal or SOAP-encoded representation. We will now look at both web services.

Employee Travel Status Web Service

Understanding the web services a business process interacts with is crucial to writing the BPEL process definition. Let’s look into the details of our Employee Travel Status web service. It provides the EmployeeTravelStatusPT port type through which the employee travel status can be checked using the EmployeeTravelStatus operation. The operation will return the travel class an employee can use: economy, business, or first. This is shown in the following figure:

The operation is a synchronous request/response operation as we can see from the WSDL:

<?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:tns=”http://packtpub.com/service/employee/” 
             targetNamespace=”http://packtpub.com/service/employee/” 
             xmlns=”http://schemas.xmlsoap.org/wsdl/”
             xmlns:plnk=”http://schemas.xmlsoap.org/ws/2003/05/partner-link/”>
...
<portType name=”EmployeeTravelStatusPT”>
  <operation name=”EmployeeTravelStatus”>
    <input message=”tns:EmployeeTravelStatusRequestMessage” /> 
    <output message=”tns:EmployeeTravelStatusResponseMessage” /> 
  </operation>
</portType>
...

The EmployeeTravelStatus operation consists of an input and an output message. To maintain simplicity, the fault is not declared. The definitions of input and output messages are also a part of the WSDL:

...
<message name=”EmployeeTravelStatusRequestMessage”>
  <part name=”employee” type=”tns:EmployeeType” /> 
</message>

<message name=”EmployeeTravelStatusResponseMessage”>
  <part name=”travelClass” type=”tns:TravelClassType” />
</message>
...

The EmployeeTravelStatusRequestMessage message has a single part, employee, of type EmployeeType, while the EmployeeTravelStatusResponseMessage has a part called travelClass, of type TravelClassType. The EmployeeType and the TravelClassType types are defined within the WSDL under the <types> element:

...
<types>
  <xs:schema elementFormDefault=”qualified” 
             targetNamespace=”http://packtpub.com/service/employee/”>

    <xs:complexType name=”EmployeeType”>
      <xs:sequence>
        <xs:element name=”FirstName” type=”xs:string” /> 
        <xs:element name=”LastName” type=”xs:string” /> 
        <xs:element name=”Department” type=”xs:string” /> 
      </xs:sequence>
    </xs:complexType> 
...

EmployeeType is a complex type and has three elements: first name, last name, and department name. TravelClassType is a simple type that uses the enumeration to list the possible classes:

...
    <xs:simpleType name=”TravelClassType”>
      <xs:restriction base=”xs:string”>
        <xs:enumeration value=”Economy”/>
        <xs:enumeration value=”Business”/>
        <xs:enumeration value=”First”/>
      </xs:restriction>
    </xs:simpleType> 
  </xs:schema> 
</types>
...

Now let us look at the airline web service.

Airline Web Service

The Airline web service is an asynchronous web service. Therefore, it specifies two port types. The first, FlightAvailabilityPT, is used to check the flight availability using the FlightAvailability operation. To return the result, the web service specifies the second port type, FlightCallbackPT. This port type specifies the FlightTicketCallback operation.

Although the Airline web service defines two port types, it only implements the FlightAvailabilityPT. FlightCallbackPT is implemented by the BPEL process, which is the client of the web service. The architecture of the web service is schematically shown here:

Flight Availability Port Type

FlightAvailability is an asynchronous operation, containing only the input message:

<?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:emp=”http://packtpub.com/service/employee/” 
             xmlns:tns=”http://packtpub.com/service/airline/” 
             targetNamespace=”http://packtpub.com/service/airline/” 
             xmlns=”http://schemas.xmlsoap.org/wsdl/”
             xmlns:plnk=”http://schemas.xmlsoap.org/ws/2003/05/partner-link/”>
...
<portType name=”FlightAvailabilityPT”>
 <operation name=”FlightAvailability”>
 <input message=”tns:FlightTicketRequestMessage” /> 
 </operation>
</portType>
...

The definition of the input message is shown below. It consists of two parts, the flightData part and the travelClass part:

<message name=”FlightTicketRequestMessage”>
  <part name=”flightData” type=”tns:FlightRequestType” /> 
  <part name=”travelClass” type=”emp:TravelClassType” />
</message>

The travelClass part is the same as that used in the Employee Travel Status web service. The flightData part is of type FlightRequestType, which is defined as follows:

...
<types>
  <xs:schema elementFormDefault=”qualified” 
             targetNamespace=”http://packtpub.com/service/airline/”>

    <xs:complexType name=”FlightRequestType”>
      <xs:sequence>
        <xs:element name=”OriginFrom” type=”xs:string” /> 
        <xs:element name=”DestinationTo” type=”xs:string” /> 
        <xs:element name=”DesiredDepartureDate” type=”xs:date” /> 
        <xs:element name=”DesiredReturnDate” type=”xs:date” /> 
      </xs:sequence>
    </xs:complexType>
...

FlightRequestType is a complex type and has four elements, through which we specify the flight origin and destination, the desired departure data, and the desired return date.

Flight Callback Port Type

The Airline web service needs to specify another port type for the callback operation, through which the BPEL process receives the flight ticket response messages. Note that the web service will only specify this port type, which is implemented by the BPEL process.

We define the FlightCallbackPT port type with the FlightTicketCallback operation, which has the TravelResponseMessage input message.

...
<portType name=”FlightCallbackPT”>
  <operation name=”FlightTicketCallback”>
    <input message=”tns:TravelResponseMessage” /> 
  </operation>
</portType>
...

TravelResponseMessage consists of a single part called confirmationData:

...
<message name=”TravelResponseMessage”>
  <part name=”confirmationData” type=”tns:FlightConfirmationType” />
</message>
...

FlightConfirmationType is a complex type used for returning the result. It includes the flight number, travel class, price, departure and arrival date and time, and the approved flag. It is declared as follows:

    <xs:complexType name=”FlightConfirmationType”>
      <xs:sequence>
        <xs:element name=”FlightNo” type=”xs:string” /> 
        <xs:element name=”TravelClass” type=”tns:TravelClassType” /> 
        <xs:element name=”Price” type=”xs:float” /> 
        <xs:element name=”DepartureDateTime” type=”xs:dateTime” /> 
        <xs:element name=”ReturnDateTime” type=”xs:dateTime” /> 
        <xs:element name=”Approved” type=”xs:boolean” /> 
      </xs:sequence>
    </xs:complexType>

  </xs:schema>
</types>

Now that we are familiar with both web services types, we can define the BPEL process. Remember that our BPEL process is an actual web service. Therefore, we first have to write the WSDL for the BPEL process.

WSDL for the BPEL Process

The business travel BPEL process is exposed as a web service. We need to define the WSDL for it. The process will have to receive messages from its clients and return results. So it has to expose a port type that will be used by the client to start the process and get the reply. We define the TravelApprovalPT port type with the TravelApproval operation:

We have already said that the BPEL process is synchronous. The TravelApproval operation will be synchronous request/response type:

<?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:emp=”http://packtpub.com/service/employee/” 
             xmlns:aln=”http://packtpub.com/service/airline/” 
             xmlns:tns=”http://packtpub.com/bpel/travel/” 
             targetNamespace=”http://packtpub.com/bpel/travel/” 
             xmlns=”http://schemas.xmlsoap.org/wsdl/”
             xmlns:plnk=”http://schemas.xmlsoap.org/ws/2003/05/partner-link/”>
...
<portType name=”TravelApprovalPT”>
  <operation name=”TravelApproval”>
    <input message=”tns:TravelRequestMessage” /> 
    <output message=”aln:TravelResponseMessage” /> 
  </operation>
</portType>
...

We also have to define messages. The TravelRequestMessage consists of two parts:

  • employee: The employee data, which we reuse from the employee travel status web service definition
  • flightData: The flight data, which we reuse from the airline web service definition
        ...
        <import namespace=”http://packtpub.com/service/employee/” 
                location=”./Employee.wsdl”/>
    
        <import namespace=”http://packtpub.com/service/airline/” 
                location=”./Airline.wsdl”/>
        ...
        <message name=”TravelRequestMessage”>
          <part name=”employee” type=”emp:EmployeeType” />
          <part name=”flightData” type=”aln:FlightRequestType” /> 
        </message>
        ...

For the output message, we use the same message used to return the flight information from the airline web service: the TravelResponseMessage defined in the aln namespace. This is reasonable, because the BPEL process will get the TravelResponseMessage from both airlines, select the most appropriate (the cheapest) and return the same message to the client. As we have already imported the Airline WSDL, we are done.

When writing the WSDL for the BPEL process we usually do not have to define the bindings (<binding>) and the service (<service>) sections. These are usually generated by the BPEL execution environment (BPEL server).

Before we can start writing the BPEL process, we still need to define partner link types.

Partner Link Types

Partner link types represent the interaction between a BPEL process and the involved parties, which includes the web services the BPEL process invokes and the client that invokes the BPEL process.

In our example, there are three different partners: the client, the employee travel status service, and the airline service. Ideally, each web service should define the corresponding partner link types (in the WSDL). In real-world scenarios, this may not be the case. Then we can wrap the partner web service with a WSDL that imports the WSDL of the web service and defines the partner link types. Alternatively, we can define all partner links in the WSDL of the BPEL process. However, this is not recommended as it violates the principle of encapsulation.

We define three partner link types, each in the corresponding WSDL of the web service:

  • travelLT: This is used to describe the interaction between the BPEL process client and the BPEL process itself. This interaction is synchronous. This partner link type is defined in the WSDL of the BPEL process.
  • employeeLT: This is used to describe the interaction between the BPEL process and the Employee Travel Status web service. This interaction is synchronous too. This partner link type is defined in the WSDL of the Employee web service.
  • flightLT: This describes the interaction between the BPEL process and the Airline web service. This interaction is asynchronous and the Airline web service invokes a callback on the BPEL process. This partner link type is defined in the WSDL of the Airline web service.

We already know that each partner link type can have one or two roles and for each role we must specify the portType it uses. For synchronous operations, there is a single role for each partner link type, because the operation is only invoked in a single direction.

For example, the client invokes the TravelApproval operation on the BPEL process. Because it is a synchronous operation, the client waits for completion and gets a response only after the operation is completed.

Note that if TravelApproval were an asynchronous callback operation, we would have to specify two roles. The first role would describe the invocation of the TravelApproval operation by the client. The second role would describe the invocation of a callback operation. This callback operation would be invoked by the BPEL process and would call the client to return the result. We will make our example process asynchronous later in this chapter. Please remember that there is an asynchronous relation between the BPEL process and the Airline web service.

As we have already figured out, we need three partner link types. The first two have to specify a single role, because they deal with synchronous operations. The third requires us to specify both roles, because it is asynchronous.

Partner link types are defined within a special namespace: http://schemas.xmlsoap.org/ws/2003/05/partner-link/. The reference to this namespace has to be included first:

<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:emp=”http://packtpub.com/service/employee/” 
             xmlns:aln=”http://packtpub.com/service/airline/” 
             xmlns:tns=”http://packtpub.com/bpel/travel/” 
             targetNamespace=”http://packtpub.com/bpel/travel/” 
             xmlns=”http://schemas.xmlsoap.org/wsdl/”
             xmlns:plnk=”http://schemas.xmlsoap.org/ws/2003/05/partner-link/”>
...

Now we can add the definitions for the partner link types. First, we define the travelLT link type in the BPEL process WSDL. This is used by clients to invoke the BPEL process. The only role required is the role of the travel service (our BPEL process). The client uses the TravelApprovalPT port type to communicate with the BPEL service:

...
<plnk:partnerLinkType name=”travelLT”>
  <plnk:role name=”travelService”>
    <plnk:portType name=”tns:TravelApprovalPT” />
  </plnk:role>
</plnk:partnerLinkType>
...

The second link type is employeeLT. It is used to describe the communication between the BPEL process and the Employee Travel Status web service and is defined in the WSDL of the Employee web service. The interaction is synchronous, so we need a single role, called employeeTravelStatusService. The BPEL process uses the EmployeeTravelStatusPT on the Employee web service:

...
<plnk:partnerLinkType name=”employeeLT”>
  <plnk:role name=”employeeTravelStatusService”>
    <plnk:portType name=”tns:EmployeeTravelStatusPT” />
  </plnk:role>
</plnk:partnerLinkType>
...

The last partner link type is flightLT, used to describe the communication between the BPEL process and the Airline web service. This communication is asynchronous. The BPEL process invokes an asynchronous operation on the Airline web service. The web service, after it has completed the request, invokes a callback on the BPEL process. Therefore we need two roles:

  • The first role describes the role of the Airline web service to the BPEL process, which is the airline service (airlineService). The BPEL process uses the FlightAvailabilityPT port type to make the asynchronous invocation.
  • The second role describes the role of the BPEL process to the Airline web services. For the Airline web service, the BPEL process is an airline customer, thus the role name is airlineCustomer. The Airline web service uses the FlightCallbackPT port type to make the callback.

This partner link type is defined in the WSDL of the Airline web service:

...
<plnk:partnerLinkType name=”flightLT”>
  <plnk:role name=”airlineService”>
    <plnk:portType name=”tns:FlightAvailabilityPT” />
  </plnk:role>
  <plnk:role name=”airlineCustomer”>
    <plnk:portType name=”tns:FlightCallbackPT” />
  </plnk:role>
</plnk:partnerLinkType>
...

Understanding partner link types is crucial for developing a BPEL process specification. Sometimes it helps to make a diagram of all the interactions. Once the partner link types are defined, we have finished the preparation phase and are ready to start writing the business process definition.

Business Process Definition

The BPEL business process definition specifies the order of activities that haveto be performed within a business process. Typically, a BPEL process waits for an incoming message, which starts the execution of the business process. This incoming message is usually the client request. Then a series of activities occur, either sequentially or in parallel. These activities include:

  • Invoking operations on other web services
  • Receiving results from other web services
  • Conditional branching, which influences the flow of the business process
  • Looping
  • Fault handling
  • Waiting for certain events to occur

In our example process, we do not cover all these aspects. We will leave loops, faults, and waits for the next chapter. Before we start defining our business process, let’s have a quick look at the sequence diagram. It shows the messages exchanged between the involved parties.

The following parties are involved:

  • The client that will invoke the BPEL process
  • The BPEL process itself
  • The Employee Travel Status web service
  • Two airline web services: American and Delta

The client initiates the BPEL process through sending an input message: TravelRequest. This is a synchronous call. Then the BPEL process invokes the Employee Travel Status web service, sending the EmployeeTravelStatusRequest message. Because this is a synchronous invocation, it waits for the EmployeeTravelStatusResponse message. Then the BPEL process makes concurrent asynchronous invocations of both airline web services by sending them the FlightTicketRequest message. Both airline web services make a callback, sending the TravelReponse message. The BPEL process then selects the more appropriate airline and returns the reply message TravelResponse to the initial client. See the following sequence diagram:

In real-world scenarios, we do not define synchronous BPEL processes that use asynchronous web services since the client may have to wait an arbitrarily long time. We would rather select an asynchronous BPEL process. In this example, we use the synchronous example to maintain simplicity. The next section shows how to define an asynchronous BPEL process.

Note

Understanding and knowing the exact details of a business process is crucial. Otherwise, we will not be able to specify it using BPEL.

Now we are ready to start writing the BPEL process definition. Each BPEL definition contains at least four main parts:

  • The initial <process> root element with the declaration of namespaces
  • The definition of partner links, using the <partnerLinks> element
  • The declaration of variables, using the <variables> element
  • The main body where the actual business process is defined; this is usually a <sequence> that specifies the flow of the process

BPEL Process Outline

We start with an empty BPEL process outline that presents the basic structure of each BPEL process definition document:

<process name=”Travel” ... >
   
   <partnerLinks>
      <!-- The declaration of partner links -->
   </partnerLinks>

   <variables>
      <!-- The declaration of variables -->
   </variables>

   <sequence>
      <!-- The definition of the BPEL business process main body -->
   </sequence>

</process>

Let us first add the required namespaces. Here we have to define the target namespace and the namespaces to access the Employee and Airline WSDLs and the BPEL process WSDL. We also have to declare the namespace for all the BPEL activity tags (here the default namespace so we do not have to qualify each BPEL tag name). The BPEL activity namespace must be http://schemas.xmlsoap.org/ws/2003/03/business-process/:

<process name=”Travel” 
         targetNamespace=”http://packtpub.com/bpel/travel/” 
 xmlns=”http://schemas.xmlsoap.org/ws/2003/03/business-process/”
 xmlns:bpws=”http://schemas.xmlsoap.org/ws/2003/03/business-process/”
 xmlns:trv=”http://packtpub.com/bpel/travel/”
 xmlns:emp=”http://packtpub.com/service/employee/”
 xmlns:aln=”http://packtpub.com/service/airline/” >
...

Partner Links

Next we have to define the partner links. Partner links define different parties that interact with the BPEL process. Each partner link is related to a specific partnerLinkType that characterizes it. Each partner link also specifies up to two attributes:

  • myRole: Indicates the role of the business process itself
  • partnerRole: Indicates the role of the partner

The partner link can specify a single role, which is usually the case with synchronous request/response operations. In our example, we define four roles. The first partner link is called client and is characterized by the travelLT partner link type. The client invokes the business process. We need to specify the myRole attribute to describe the role of the BPEL process. In our case, this is the travelService:

...
   <partnerLinks>
      <partnerLink name=”client” 
                   partnerLinkType=”trv:travelLT”
                   myRole=”travelService”/>
...

The second partner link is called employeeTravelStatus and is characterized by the employeeLT partner link type. It is a synchronous request/response relation between the BPEL process and the web service; we again specify only one role. This time it is the partnerRole, because we describe the role of the web service, which is a partner to the BPEL process:

...
      <partnerLink name=”employeeTravelStatus” 
                   partnerLinkType=”emp:employeeLT”
                   partnerRole=”employeeTravelStatusService”/>
...

The last two partner links correspond to the airline web services. Because they use the same type of web service, we specify two partner links based on a single partner link type, flightLT. Here we have asynchronous callback communication, therefore we need two roles. The role of the BPEL process (myRole) to the airline web service is airlineCustomer, while the role of the airline (partnerRole) is airlineService:

...
      <partnerLink name=”AmericanAirlines” 
                   partnerLinkType=”aln:flightLT”
                   myRole=”airlineCustomer”
                   partnerRole=”airlineService”/>
                   
      <partnerLink name=”DeltaAirlines” 
                   partnerLinkType=”aln:flightLT”
                   myRole=”airlineCustomer”
                   partnerRole=”airlineService”/>
   </partnerLinks>

Variables

Variables are used to store messages and to reformat and transform them. We usually need a variable for every message sent to the partners and received from the partners. Looking at the sequence diagram, this would mean eight variables for our example. However, notice that the messages sent to both airline web services are identical. So, we only need seven variables. Let’s call them TravelRequest, EmployeeTravelStatusRequest, EmployeeTravelStatusResponse, FlightDetails, FlightResponseAA, FlightResponseDA, and TravelResponse.

For each variable we have to specify the type. We can use a WSDL message type, an XML Schema simple type, or an XML Schema element. In our example we use WSDL message types for all variables:

...
   <variables>
      <!-- input for this process -->      
      <variable name=”TravelRequest” messageType=”trv:TravelRequestMessage”/>
      <!-- input for the Employee Travel Status web service -->
      <variable name=”EmployeeTravelStatusRequest” messageType=”emp:EmployeeTravelStatusRequestMessage”/>
      <!-- output from the Employee Travel Status web service -->
      <variable name=”EmployeeTravelStatusResponse” messageType=”emp:EmployeeTravelStatusResponseMessage”/>
      <!-- input for American and Delta web services -->
      <variable name=”FlightDetails” messageType=”aln:FlightTicketRequestMessage”/>
      <!-- output from American Airlines -->
      <variable name=”FlightResponseAA” messageType=”aln:TravelResponseMessage”/>
      <!-- output from Delta Airlines -->
      <variable name=”FlightResponseDA” messageType=”aln:TravelResponseMessage”/>
      <!-- output from BPEL process -->
      <variable name=”TravelResponse” messageType=”aln:TravelResponseMessage”/>
   </variables>
...

BPEL Process Main Body

The process main body may contain only one top-level activity. Usually this is a <sequence> that allows us to define several activities that will be performed sequentially. Other possibilities for this activity include <flow>, through which several activities can be performed concurrently. We can also specify <while> to indicate loops, or <scope> to define nested activities. However, we usually use <sequence> and nest other activities within the sequence.

Within the sequence, we first specify the input message that starts the business process. We do this with the <receive> construct, which waits for the matching message. In our case this is the TravelRequest message. Within the <receive> construct, we do not specify the message directly. Rather we specify the partner link, the port type, the operation name, and optionally the variable that holds the received message for consequent operations.

We link the message reception with the client partner, and wait for the TravelApproval operation to be invoked on port type TravelApprovalPT. We store the received message into the TravelRequest variable:

...
   <sequence>

      <!-- Receive the initial request for business travel from client -->
      <receive partnerLink=”client” 
               portType=”trv:TravelApprovalPT” 
               operation=”TravelApproval” 
               variable=”TravelRequest”
               createInstance=”yes” />
...

As already mentioned, <receive> waits for the client to invoke the TravelApproval operation and stores the incoming message and parameters about the business trip into the TravelRequest variable. Here, the variable name is the same as the message name, but this is not necessary.

Next, we need to invoke the Employee Travel Status web service. Before this, we have to prepare the input for this web service. Looking at the WSDL of the Employee web service, we can see that we have to send a message consisting of the employee part. We can construct such a message by copying the employee part of the message that the client sent. We write the corresponding assignment:

...
      <!-- Prepare the input for the Employee Travel Status Web Service -->
      <assign>
        <copy>
          <from variable=”TravelRequest” part=”employee”/>
          <to variable=”EmployeeTravelStatusRequest” part=”employee”/>
        </copy>
      </assign>
...

Now we can invoke the Employee Travel Status web service. We make a synchronous invocation, for which we use the <invoke> activity. We use the employeeTravelStatus partner link and invoke the EmployeeTravelStatus operation on the EmployeeTravelStatusPT port type. We have prepared the input message in the EmployeeTravelStatusRequest variable. Because it is a synchronous invocation, the call waits for the reply and stores it in the EmployeeTravelStatusResponse variable:

...
      <!-- Synchronously invoke the Employee Travel Status Web Service -->
      <invoke partnerLink=”employeeTravelStatus” 
              portType=”emp:EmployeeTravelStatusPT” 
              operation=”EmployeeTravelStatus”
              inputVariable=”EmployeeTravelStatusRequest” 
              outputVariable=”EmployeeTravelStatusResponse” />
...

The next step is to invoke both airline web services. Again we first prepare the required input message (which is equal for both web services). The FlightTicketRequest message consists of two parts:

  • flightData: This is retrieved from the client message (TravelRequest).
  • travelClass: This is retrieved from the EmployeeTravelStatusResponse variable.

Therefore, we write an assignment with two copy elements:

...
      <!-- Prepare the input for AA and DA -->
      <assign>
        <copy>
          <from variable=”TravelRequest” part=”flightData”/>
          <to variable=”FlightDetails” part=”flightData”/>
        </copy>
        <copy>
          <from variable=”EmployeeTravelStatusResponse” part=”travelClass”/>
          <to variable=”FlightDetails” part=”travelClass”/>
        </copy>
      </assign>
...

The input data includes the data that needs to be passed to the Airline web services. Since it is in the same format, we can pass it directly (using a simple copy). In the real world, we usually need to perform a transformation. We could do that using XPath expressions with <assign>, use a transformation service (such as an XSLT engine), or use the transformation capabilities provided by specific BPEL servers.

Now we are ready to invoke both airline web services. We will make concurrent asynchronous invocations. To express concurrency, BPEL provides the <flow> activity. The invocation to each web service will consist of two steps:

  1. The <invoke> activity is used for the asynchronous invocation.
  2. The <receive> activity is used to wait for the callback.

We use <sequence> to group both activities. The two invocations differ only in the partner link name. We use AmericanAirlines for one and DeltaAirlines for the other. Both invoke the FlightAvailability operation on the FlightAvailabilityPT port type, sending the message from the FlightDetails variable.

The callback is received using the <receive> activity. Again, we use both partner link names. <receive> waits for the FlightTicketCallback operation to be invoked on the FlightCallbackPT port type. We store the result message in the FlightResponseAA and the FlightResponseDA variables respectively:

...
      <!-- Make a concurrent invocation to AA in DA -->
      <flow>
      
        <sequence>
          <!-- Async invoke of the AA web service and wait for the callback-->
        
          <invoke partnerLink=”AmericanAirlines” 
              portType=”aln:FlightAvailabilityPT” 
              operation=”FlightAvailability”
              inputVariable=”FlightDetails” />

          <receive partnerLink=”AmericanAirlines” 
              portType=”aln:FlightCallbackPT” 
              operation=”FlightTicketCallback”
              variable=”FlightResponseAA” />

        </sequence>

        <sequence>
          <!-- Async invoke of the DA web service and wait for the callback-->
        
          <invoke partnerLink=”DeltaAirlines” 
              portType=”aln:FlightAvailabilityPT” 
              operation=”FlightAvailability”
              inputVariable=”FlightDetails” />

          <receive partnerLink=”DeltaAirlines” 
              portType=”aln:FlightCallbackPT” 
              operation=”FlightTicketCallback”
              variable=”FlightResponseDA” />

        </sequence>

      </flow>
...

In this stage of the process, we have two ticket offers. In the next step, we have to select one. For this, we use the <switch> activity.

...
      <!-- Select the best offer and construct the TravelResponse -->
      <switch>
              
        <case condition=”bpws:getVariableData(‘FlightResponseAA’,‘confirmationData’,’/confirmationData/aln:Price’) 
                   &lt;= bpws:getVariableData(‘FlightResponseDA’,‘confirmationData’,’/confirmationData/aln:Price’)”>

                    
           <!-- Select American Airlines -->
           <assign>
             <copy>
               <from variable=”FlightResponseAA” />
               <to variable=”TravelResponse” />
             </copy>
           </assign>
        </case>
                    
        <otherwise>
           <!-- Select Delta Airlines -->
           <assign>
             <copy>
               <from variable=”FlightResponseDA” />
               <to variable=”TravelResponse” />
             </copy>
           </assign>
        </otherwise>
      </switch>
...

In the <case> element, we check whether the offer from American Airlines (FlightResponseAA) is equal or better than the offer from Delta (FlightResponseDA). For this, we use the BPEL function getVariableData and specify the variable name. The price is located inside the confirmationData message part, which is the only message part, but we still have to specify it. We also have to specify the query expression to locate the price element. Here, this is a simple XPath 1.0 expression.

If the American Airlines offer is better than Delta (or equal) we copy the FlightResponseAA variable to the TravelResponse variable (which we finally return to the client). Otherwise we copy the FlightResponseDA variable.

We have come to the final step of the BPEL business process—to return a reply to the client, using the <reply> activity. Here we specify the same partner link as in the initial receive client. We also specify the same port type and operation name. The variable that holds the reply message is TravelResponse:

...
      <!-- Send a response to the client -->
      <reply partnerLink=”client” 
             portType=”trv:TravelApprovalPT” 
             operation=”TravelApproval” 
             variable=”TravelResponse”/>
   </sequence>

</process>

With this, we have concluded our first business process specification in BPEL. You can see that BPEL is not very complicated and allows a relatively easy and natural specification of business processes. The consumption of other web services is also relatively easy if you are familiar with WSDL. In the next section, we modify our BPEL process to make it asynchronous.