Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Oracle SOA Suite 11g R1 Developer's Guide

You're reading from   Oracle SOA Suite 11g R1 Developer's Guide Service-Oriented Architecture (SOA) is made easily accessible thanks to this comprehensive guide. With a logically structured approach, it gives you the expertise to start using the Oracle SOA suite in real-world applications.

Arrow left icon
Product type Paperback
Published in Jul 2010
Publisher Packt
ISBN-13 9781849680189
Length 720 pages
Edition 1st Edition
Arrow right icon
Toc

Chapter 5. Using BPEL to Build Composite Services and Business Processes

In the previous two chapters, we saw how we can service-enable functionality embedded within existing systems. The next challenge is how to assemble these services to build "composite" applications or business processes. This is the role of the Web Service Business Process Execution Language (WS BPEL) or Business Process Execution Language (BPEL), as it's commonly referred to.

BPEL is a rich XML-based language for describing the assembly of a set of existing web services into either a composite service or a business process. Once deployed, a BPEL process itself is actually invoked as a web service.

Thus, anything that can call a web service, can also call a BPEL process, including of course, other BPEL processes. This allows you to take a nested approach to writing BPEL processes, giving you a lot of flexibility.

In this chapter, we first introduce the basic structure of a BPEL process, its key constructs, and the difference between a synchronous and asynchronous service.

We then demonstrate through the building and refinement of two example BPEL processes (one synchronous the other asynchronous), how to use BPEL to invoke external web services (including other BPEL processes), and to build composite services. During this process, we also take the opportunity to introduce the reader to many of the key BPEL activities in more detail.

Basic structure of a BPEL process

The following image shows the core structure of a BPEL process, and how it interacts with components external to it: either web services that the BPEL process invokes (Service A and Service B in this case) or external clients that invoke the BPEL process as a web service.

From this, we can see that the BPEL process divides into two distinct parts: the partner links (with associated WSDL files, which describe the interactions between the BPEL process and the outside world) and the core BPEL Process itself, which describes the process to be executed at runtime.

Basic structure of a BPEL process

Core BPEL process

The core BPEL process consists of a number of steps or activities as they are called in BPEL.

These consist of simple activities, including:

  • Assign: Used to manipulate variables.
  • Transform: A specialized assign activity that uses XSLT to map data from a source format to a target format.
  • Wait: Used to pause the process for a period of time.
  • Empty: Does nothing. It is used in branches of your process where syntactically an activity is required, but you don't want to perform an activity.

Structured activities that control the flow through the process, these include:

  • While: For implementing loops
  • Switch: Construct for implementing conditional branches
  • Flow: For implementing branches that execute in parallel
  • FlowN: For implementing a dynamic number of parallel branches

And messaging activities (for example, Receive, Invoke, Reply, and Pick)

The activities within a BPEL process can be subdivided into logical groups of activities, using the Scope activity. Along with providing a useful way to structure and organize your process, it also lets you define attributes such as variables, fault handlers, and compensation handlers that just apply to the scope.

Variables

Each BPEL process also defines variables, which are used to hold the state of the process as well as messages that are sent and received by the process. They can be defined at the process level, in which case, they are considered global and visible to all parts of the process, or can be declared within a scope, in which case they are only visible to activities contained within that scope (and scopes nested within the scope to which the variable belongs).

Variables can be one of the following types:

  • Simple type: Can hold any simple data type defined by XML Schema (for example, string, integer, Boolean, and float)
  • WSDL message type: Used to hold the content of a WSDL message sent to or received from partners
  • Element: Can hold either a complex or simple XML Schema element defined in either a WSDL file or a separate XML Schema

Variables are manipulated using the <assign> activity, which can be used to copy data from one variable to another, as well as create new data using XPath expressions or XSLT.

For variables that are WSDL messages or complex elements, we can work with it at the subcomponent level by specifying the part of the variable we would like to work with using an XPath expression.

Partner links

All interaction between a process and other parties (or partners) is via web services, as defined by their corresponding WSDL files. Even though each service is fully described by its WSDL, it fails to define the relationship between the process and the partner, that is, who the consumer of a service is and who the provider is. At first glance, the relationship may seem implicit. However, this is not always the case, so BPEL uses partner links to explicitly define this relationship.

Partner links are defined using the <partnerLinkType>, which is an extension to WSDL (defined by the BPEL standard). Whenever you refer to a web service whose WSDL doesn't contain a <partnerLinkType>, JDeveloper will automatically ask you whether you want it to create one for you. Assuming your answer is yes, it will create this as a separate WSDL document, which then imports the original WSDL.

Messaging activities

BPEL defines three messaging activities <receive>, <reply>, and <invoke>; how you use these depends on whether the message interaction is either synchronous or asynchronous and whether the BPEL process is either a consumer or provider of the service.

Synchronous messaging

With synchronous messaging the caller will block until it has received a reply (or times out), that is, the BPEL process will wait for a reply before moving on to the next activity.

As we can see in the following, Process A uses the <invoke> activity to call a synchronous web service (Process B in this case), once it has sent the initial request, it blocks and waits for a corresponding reply from Process B.

Synchronous messaging

Process B uses the <receive> activity to receive the request. Once it has processed the request, it uses the <reply> activity to send a response back to Process A.

Theoretically, Process B could take as long as it wants before sending a reply, but typically Process A will only wait for a short time (for example, 30 seconds) before it times out the <invoke> operation under the assumption that something has gone wrong. Thus, if Process B is going to take a substantial period of time before replying, then you should model the exchange as an Asynchronous Send-Receive (refer to the following section).

Asynchronous messaging

With asynchronous messaging, the key difference is that once the caller has sent the request, the send operation will return immediately, and the BPEL process may then continue with additional activities until it is ready to receive the reply. At this point, the process will block until it receives the reply (which may already be there).

If we look at the following screenshot, you will notice that just like the synchronous request Process A uses the <invoke> activity to call an asynchronous web service. However, the difference is that it doesn't block waiting for a response, rather it continues processing until it is ready to process the response. It then receives this using the <receive> activity.

Asynchronous messaging

Conversely, Process B uses a <receive> activity to receive the initial request and an <invoke> activity to send back the corresponding response.

While at a logical level, there is little difference between synchronous and asynchronous messaging (especially if there are no activities between the <invoke> and <receive> activity in Process A), at a technical level there is a key difference.

This is because with asynchronous messaging, we have two <invoke>, <receive> pairs, each corresponding to a separate web service operation. One is for the request and the other is for the reply.

From a decision perspective, a key driver as to which to choose is the length of time it takes for Process B to service the request, as asynchronous messaging supports far longer processing times. In general, once the time it takes for Process B to return a response goes above 30 seconds, you should consider switching to asynchronous messaging.

Note

With potentially many instances of Process A and Process B running at the same time, BPEL needs to ensure that each reply is matched (or correlated) to the appropriate request. By default, BPEL uses WS-Addressing to achieve this. We look at this in more detail in Chapter 16, Message Interaction Patterns.

One way messaging

A variation of asynchronous messaging is one way messaging (also known as fire and forget). This involves a single message being sent from the calling process, with no response being returned.

If we look at the following screenshot, you will notice that just like the asynchronous request, Process A uses the <invoke> activity to send a message to Process B.

Once Process A has sent the message, it continues processing until it completes, that is, it never stops to wait for a response from Process B. Similarly, Process B, upon receipt of the message, continues processing until it has completed and never sends any response back to Process A.

One way messaging

A simple composite service

Despite the fact that BPEL is intended primarily for writing long running processes, it also provides an excellent way to build a composite service, that is, a service that is assembled from other services.

Let's take a simple example: say I have a service that gives me the stock quote for a specified company, and that I also have a service that gives me the exchange rate between two currencies. I can use BPEL to combine these two services and provide a service that gives the stock quote for a company in the currency of my choice.

So let's create our stock quote service, we will create a simple synchronous BPEL process which takes two parameters, the stock ticker and the required currency. This will then call two external services.

Creating our StockQuote service

Before we begin, we will create an application (named Chapter05), which we will use for all our samples in this chapter. To do this, follow the same process we used to create our first application in Chapter 2, Writing your First Composite. When prompted to create a project, create an Empty Composite named StockService.

Next, drag a BPEL process from the SOA Component Palette onto our StockService composite. This will launch the Create BPEL Process wizard, specify a name of StockQuote, and select a Synchronous BPEL Process. However, at this stage do not click OK.

Creating our StockQuote service

You may remember when we created our Echo service back in Chapter 2, Writing your First Composite, JDeveloper automatically created a simple WSDL file for our service, with a single input and output field. For our StockQuote service, we need to pass in multiple fields (that is, Stock Ticker and Currency). So, to define the input and output messages for our BPEL process, we are going to make use of a predefined schema StockService.xsd, as shown in the following code snippet (for brevity, only the parts which are relevant to this example are shown. However, the complete schema is provided in the downloadable samples file for the book).

<?xml version="1.0" encoding="windows-1252"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns="http://xmlns.packtpub.com/StockService"
            targetNamespace="http://xmlns.packtpub.com/StockService" 
            elementFormDefault="qualified">

	<xsd:element name="getQuote"         type=" tGetQuote"/>
	<xsd:element name="getQuoteResponse" type=" tGetQuoteResponse"/>

	<xsd:complexType name="tGetQuote">
		<xsd:sequence>
			<xsd:element name="stockSymbol" type="xsd:string"/>
			<xsd:element name="currency" type="xsd:string"/>
		</xsd:sequence>
	</xsd:complexType>

	<xsd:complexType name="tGetQuoteResponse">
		<xsd:sequence>
			<xsd:element name="stockSymbol" type="xsd:string"/>
			<xsd:element name="currency" type="xsd:string"/>
			<xsd:element name="amount" type="xsd:decimal"/>
		</xsd:sequence>
	</xsd:complexType>

   … 
   
</xsd:schema>

Importing StockService schema

To override the default input schema element generated by JDeveloper, click on Browse Input Elements … (the magnifying glass circled in the previous screenshot). This will bring up the Type Chooser , as shown in the following screenshot, which allows you to browse all schemas imported by the composite and select an element from them.

Importing StockService schema

In our case, we have yet to import any schemas, so click on Import Schema File … (circled in the previous screenshot). This will launch the Import Schema File window. Click on the magnifying glass to launch the SOA Resource Browser (in File System mode), which will allow us to search our filesystem for an appropriate schema.

Find the StockService.xsd located in the samples folder for Chapter 5 and select this. Ensure that the option to Copy to Project is selected and click OK; JDeveloper will then bring up the Localize Files window. Keep the default options and click OK. This will cause JDeveloper to create a local copy of our XML Schema and any dependant files (of which there are none in this example) within our project.

JDeveloper will now open the schema browser dialog, containing the imported StockService schema. Browse this and select the getQuote element, as shown in the following screenshot:

Importing StockService schema

Repeat this step for the output schema element, but select the getQuoteResponse element. Click OK and this will create our StockQuote process within our composite, as shown in the following screenshot:

Importing StockService schema

Within the composite, double-click the StockQuote process to open it in the BPEL editor. You will see that, by default, JDeveloper has created a skeleton BPEL process, which contains an initial <receive> activity to receive the stock quote request, followed by a <reply> activity to send back the result (as we discussed in the earlier section – Synchronous Messaging). In addition, it will have created two variables; inputVariable, which contains the initial stockquote request, and outputVariable, in which we will place the result to return to the requestor.

Note

If you look in the Projects section of the Application Navigator, you will see that it contains the file StockQuote.wsdl. This contains the WSDL description (including partner link extensions) for our process. If you examine this, you will see that we have a single operation; process, which is used to call the BPEL process.

Calling the external web services

The next step is to call our external web services. For our stock quote service, we are going to use Xignite's quotes web service, which delivers delayed equity price quotes from all U.S. stock exchanges (NYSE, NASDAQ, AMEX, NASDAQ OTC Bulletin Board, and Pink Sheets).

Note

Before you can use this service, you will need to register with Xignite. To do this, or for more information on this and other services provided by Xignite, go to www.xignite.com.

To call a web service in BPEL, we first need to create a partner link (as discussed at the start of this chapter). So from the Component Palette, expand the BPEL Services section and drag a Partner Link (Web Service / Adapter) component into the Partner Link swim lane in your BPEL process. This will pop up the following screen:

Calling the external web services

First enter a name for the partner link, for example, XigniteQuotes. Next we need to specify the WSDL file for the partner link. JDeveloper provides the following ways to do this:

  • SOA Resource Lookup: Allows us to browse the filesystem for WSDL files or any connected application server for deployed services
  • SOA Service Explorer: Allows us to browse other services that are defined within the composite (for example, other BPEL processes, Mediator, or external services)
  • Define Service: This enables us to define adapter services (refer to Chapter 3, Service-enabling Existing Systems) directly within the context of a BPEL process
  • WSDL URL: Directly enter the URL for the WSDL file into the corresponding field

For our reference, we have a local copy of the WSDL for Xignite's quotes service, called XigniteQuotes.wsdl, which is included with the samples for Chapter 5. Click on the SOA Resource Lookup … icon (circled in the preceding screenshot), then browse to and select this file (select Yes if prompted to create a local copy of the file).

JDeveloper will parse the WSDL, and assuming it is successful, it will pop up a window saying that there are no partner link types defined in the current WSDL and ask if you want to create partner links for the file. Click Yes. JDeveloper will then create one Partner Link Type for each port type defined in the WSDL. In cases where we have multiple partner link types, we will need to specify which one to use within our process. To do this, click on the drop-down list next to Partner Link Type and select the appropriate one. In our case, we have selected XigniteQuotesSoap_PL, as shown in the following screenshot:

Calling the external web services

Finally, we need to specify the Partner Role and My Role. When invoking a synchronous service, there will only be a single role defined in the WSDL, which represents the provider of the service. So specify this for the Partner Role and leave My Role as ----- Not Specified -----.

Note

Best practice would dictate that rather than calling the stock quote service directly from within BPEL, we would invoke it via the Oracle Service Bus. This is an area we look at more closely in Chapter 10, oBay Introduction when we define our blueprint for SOA.

If you look at the composite view, you will see that XigniteQuotes is defined as an External Reference and is wired to our BPEL process.

Calling the web service

Once we have defined a partner link for the web service, the next step is to call it. As this is a synchronous service, we will need to use an <invoke> activity to call it, as we described earlier in this chapter.

On the Component Palette, ensure that the BPEL Activities and Components section is expanded. Then from it, drag an Invoke activity on to your BPEL process.

Next, place your mouse over the arrow next to the Invoke activity. Click and hold your mouse button, drag the arrow over your partner link, and then release, as shown in the following screenshot:

Calling the web service

This will then pop up the Edit Invoke activity window, as shown in the following screenshot:

Calling the web service

We need to specify a number of values to configure the Invoke activity, namely:

  • Name: This is the name we want to assign to the Invoke activity, and can be any value. So just assign a meaningful value such as GetQuote.
  • Partner Link: This is the Partner Link whose service we want to invoke; it should already be set to use XigniteQuotes, as we have already linked this activity to that Partner Link. An alternate approach would be to click on the corresponding spotlight icon, which would allow us to select from any Partner Link already defined to the process.
  • Operation: Once we've specified a Partner Link, we need to specify which of its operations we wish to invoke. This presents us with a drop-down list, listing all the operations that are available, for our purpose, select GetSingleQuote.
  • Input: Here we must specify the variable that contains the data to be passed to the web service that's being invoked. It is important that the variable is of type Message, and that it is of the same message type expected by the Operation (that is, as defined in the WSDL file for the web service).

    The simplest way to ensure this is by getting JDeveloper to create the variable for you. To do this, click on the green plus sign to the right of the input variable field. This will bring up the Create Variable window, as shown in the following screenshot. You will notice that JDeveloper creates a default name for the variable (based on the name you gave the invoke operation and the operation that you are calling). You can override this with something more meaningful (for example, QuoteInput).

  • Output: Finally, we must specify the variable into which the value returned by the web service will be placed. As with the input variable, this should be of the type Message and corresponds to the output message defined in the WSDL file for the selected operation. Again, the simplest way to ensure this is to get JDeveloper to create the variable for you.
    Calling the web service

Once you've specified values for all these fields, as illustrated in the preceding screenshot, click OK.

Assigning values to variables

In our previous step, we created the variable QuoteInput, which we pass to our invocation of GetSingleQuote. However, we have yet to initialize the variable or assign any value to it.

To do this, BPEL provides the <assign> activity, which is used to update the values of variables with new data. The <assign> activity typically consists of one or more copy operations. Each copy consists of a target variable, that is, the variable that you wish to assign a value to and a source (this can either be another variable or an XPath expression).

For our purposes, we want to assign the stock symbol passed into our BPEL process to our QuoteInput variable.

To do this, drag an Assign activity from the Component Palette on to your BPEL process at the point just before our Invoke activity. Then double-click on it to open up the Assign configuration window. Click on the green plus sign and select Copy Operation….

This will present us with the Create Copy Operation window, as shown in the following screenshot:

Assigning values to variables

On the left-hand side, we specify the From variable (that is, the source). Here we want to specify the stock symbol passed in as part of the input variable to the BPEL process. So expand the inputVariable tree, and select /ns2:getQuote/ns2:stockSymbol.

For the target, expand QuoteInput and select /ns1:GetSingleQuote/ns1:Symbol.

You will notice that for both the source and target, JDeveloper has created the equivalent XPath expression (circled in the preceding screenshot).

Note

The source and target can either be a simple type (for example, xsd:int, xsd:date, or xsd:string), as in the preceding example. Or a complex type (for example, ns2:getQuote), but make sure the source and target are either of the same type, or at least compatible.

Testing the process

At this stage, even though the process isn't complete, we can still save, deploy, and run our composite. Do this in the same way as previously covered in Chapter 2, Writing your First Composite. When you run the composite from the console you will notice that it doesn't return anything (as we haven't specified this yet). But if you look at the audit trail, you should successfully see the GetSingleQuote operation being invoked. Assuming this is the case, we know we have implemented that part of the process correctly.

Calling the exchange rate web service

The next step of the process is to determine the exchange rate between the requested currency and the US dollar (the currency used by the GetSingleQuote operation). For this, we are going to use the currency convertor service provided by webserviceX.NET .

For more information on this and other services provided by webserviceX.NET, go to www.webservicex.net.

This service provides a single operation ConversionRate, which gets the conversion rate from one currency to another. The WSDL file for this service can be found at the following URL:

http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

For convenience, we have included a local copy of the WSDL for webserviceX.NET's currency convertor service, called CurrencyConvertor.wsdl. It's included with the samples of Chapter 5.

To invoke the ConversionRate operation, we will follow the same basic steps that we did in the previous section to invoke the GetSingleQuote operation. For brevity, we won't repeat them here, but will allow the reader to do this.

Note

To follow the examples, name the input variable for the exchange rate web service ExchangeRateInput and the output variable ExchangeRateOutput.

Assigning constant values to variables

The operation ConversionRate takes two input values as follows:

  • FromCurrency: This should be set to 'USD'
  • ToCurrency: This should be set to the currency field contained within the inputVariable for the BPEL process.

To set the FromCurrency, create another copy operation. However, for the From value, select Expression as the Type (circled in the following screenshot).

This will replace the variable browser with a free format textbox. Here you can specify any value, within quotes, that you wish to assign to your target variable. For our purposes, enter 'USD', as shown in the following screenshot:

Assigning constant values to variables

To set the value of ToCurrency, create another copy operation and copy in the value of the currency field contained within the inputVariable.

At this stage again, save, deploy, and run the composite to validate that we are calling the exchange rate service correctly.

Using the expression builder

The final part of the process is to combine the exchange rate returned by one service with the stock price returned by the other, in order to determine the stock price in the requested currency and return that to the caller of the composite.

To do this, we will again use an <assign> activity. So drag another <assign> activity onto the process, just after our second invoke activity. Now in our previous use of the <assign> activity, we have just used it to copy a value from one variable to another.

Here, it is slightly different, in that we want to combine multiple values into a single value, and to do that, we will need to write the appropriate piece of XPath. Create a copy operation as before, but for the source type, select Expression from the drop-down list, as shown in the following screenshot:

Using the expression builder

Now, if you want, you can type in the XPath expression manually (into the Expression area), but it's far easier and less error prone to use the Expression Builder. To do this, click on the XPath expression builder icon; the calculator icon, which is circled in the preceding screenshot, will pop up the Expression Builder (shown below):

Using the expression builder

The Expression Builder provides a graphical tool for writing XPath expressions, which are executed as part of the copy operation. It consists of the following areas:

  • Expression: The top textbox contains the XPath expression that you are working on. You can either type data directly in here, or use the Expression Builder to insert XPath fragments to build up the XPath required.
  • BPEL variables: This part of the Expression Builder lets you browse the variables defined within your BPEL process. Once you've located the variable that you wish to use, click on the Insert Into Expression button, and this will insert the appropriate code fragment into the XPath expression.

    Note

    The code fragment is inserted at the point within the expression where the cursor is currently positioned.

  • Functions: This shows you all the different types of XPath functions that are available to build up your XPath expression. To make it easier to locate the required function, they are grouped into categories such as String Functions, Mathematical Functions, and so on.

    The drop-down list lets you select the category that you are interested in (for example, Mathematical Functions, as illustrated in the preceding screenshot), and then the window below that lists all the functions available to that group.

    To use a particular function, select the required function, and click Insert Into Expression. This will insert the appropriate XPath fragment into the XPath Expression (again at the point that the cursor is currently positioned).

  • Content Preview: This box displays a preview of the content that would be inserted into the XPath Expression if you clicked the Insert Into Expression button. For example, if you had currently selected a particular BPEL variable, it would show you the XPath to access that variable.
  • Description: If you've currently selected a function, this box provides a brief description of the function, as well as the expected usage and number of parameters.

So let's use this to build our XPath expression. The expression we want to build is a relatively simple one, namely, the stock price returned by the stock quote service multiplied by the exchange rate returned by the exchange rate service.

To build our XPath expression, carry out the following steps:

First, within the BPEL Variables area, in the variable QuoteOutput, locate the element ns1:GetSingleQuoteResult|ns1:Last, as shown in the following screenshot:

Using the expression builder

Then click Insert Into Expression to insert this into the XPath expression.

Next, within the Functions area, select the Mathematical Functions category, and select the multiply function (notice the description in the Description box, as shown in the following screenshot), and insert this into the XPath expression:

Using the expression builder

Finally, back in the BPEL Variables area, locate the element ConversionRateResult within the variable ExchangeRateOutput, and insert that into the XPath expression.

You should now have an XPath expression similar to the one illustrated below, once you are happy with it, click OK.

Using the expression builder

Finally make sure you specify the target part of the copy operation, which should be the amount element within the outputVariable.

In order to complete the <assign> activity, you will need to create two more copy operations to copy the Currency and StockSymbol specified in the inputVariable into the equivalent values in the outputVariable.

Once done, your BPEL process should be complete. So deploy and run the composite.

Asynchronous service

Following our StockQuote service, another service would be a stock order service, which would enable us to buy or sell a particular stock. For this service, a client would need to specify the stock, whether they wanted to buy or sell, the quantity, and the price.

It makes sense to make this an asynchronous service, as once the order has been placed, it may take seconds, minutes, hours, or even days for the order to be matched.

Now, I'm not aware of any trade services that are free to try (probably for a good reason!). However, there is no reason why we can't simulate one. To do this, we will write a simple asynchronous process.

Drag another BPEL process on to our StockService composite and give it the name StockOrder, but specify that it is an asynchronous BPEL process.

As with the StockQuote process, we also want to specify predefined elements for its input and output. The elements we are going to use are placeOrder for the input and placeOrderResponse for the output, the definitions for which are shown in the following code snippet:

<xsd:element name="placeOrder"         type="tPlaceOrder"/>
<xsd:element name="placeOrderResponse" type="tPlaceOrderResponse"/>

<xsd:complexType name="tPlaceOrder">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="bidPrice"    type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="tPlaceOrderResponse">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="actualPrice" type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

These are also defined in the StockService.xsd that we previously imported into the StockService composite. So, for each field, we click on the magnifying glass to bring up the type chooser and select the appropriate element definitions. Then click OK to create the process. This will create a second BPEL process within our composite, so double-click on this to open it.

You will see that, by default, JDeveloper has created a skeleton asynchronous BPEL process, which contains an initial <receive> activity to receive the stock order request. But this time it's followed by an <invoke> activity to send the result back (as opposed to a <reply> activity used by the synchronous process).

If you look at the WSDL for the process, you will see that it defines two operations: process to call the process, and processResponse, which will be called by the process to send back the result. Thus the client that calls the process operation will need to provide the processResponse callback in order to receive the result (this is something we will look at in more detail in Chapter 15, Message Interaction Patterns.

Now, for the purpose of our simulation, we will assume that the StockOrder request is successful and the actualPrice achieved is always the bid price. So to do this, create an assign operation that copies all the original input values to their corresponding output values. Deploy the composite, and run it from the console.

Note

When you click the Test Web Service button for the StockService composite, you will now be presented with two options: stockorder_client_ep and stockquote_client_ep. These correspond to each of the exposed services we have defined in our composite. Ensure you select stockorder_client_ep, which is wired to our StockOrder process.

This time, you will notice that no result is returned (as it's being processed asynchronously); rather it displays a message to indicate that the service was invoked successfully, as shown in the following screenshot:

Asynchronous service

Click on Launch Message Flow Trace to bring up the trace for the composite, and then select StockOrder to bring up the audit trail for the process. Switch to the flow view, and expand the callbackClient activity at the end of the trace. This will pop up a window showing the details of the response sent by our process, as shown in the following screenshot:

Asynchronous service

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Creating our StockQuote service

Before we begin, we will create an application (named Chapter05), which we will use for all our samples in this chapter. To do this, follow the same process we used to create our first application in Chapter 2, Writing your First Composite. When prompted to create a project, create an Empty Composite named StockService.

Next, drag a BPEL process from the SOA Component Palette onto our StockService composite. This will launch the Create BPEL Process wizard, specify a name of StockQuote, and select a Synchronous BPEL Process. However, at this stage do not click OK.

Creating our StockQuote service

You may remember when we created our Echo service back in Chapter 2, Writing your First Composite, JDeveloper automatically created a simple WSDL file for our service, with a single input and output field. For our StockQuote service, we need to pass in multiple fields (that is, Stock Ticker and Currency). So, to define the input and output messages for our BPEL process, we are going to make use of a predefined schema StockService.xsd, as shown in the following code snippet (for brevity, only the parts which are relevant to this example are shown. However, the complete schema is provided in the downloadable samples file for the book).

<?xml version="1.0" encoding="windows-1252"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns="http://xmlns.packtpub.com/StockService"
            targetNamespace="http://xmlns.packtpub.com/StockService" 
            elementFormDefault="qualified">

	<xsd:element name="getQuote"         type=" tGetQuote"/>
	<xsd:element name="getQuoteResponse" type=" tGetQuoteResponse"/>

	<xsd:complexType name="tGetQuote">
		<xsd:sequence>
			<xsd:element name="stockSymbol" type="xsd:string"/>
			<xsd:element name="currency" type="xsd:string"/>
		</xsd:sequence>
	</xsd:complexType>

	<xsd:complexType name="tGetQuoteResponse">
		<xsd:sequence>
			<xsd:element name="stockSymbol" type="xsd:string"/>
			<xsd:element name="currency" type="xsd:string"/>
			<xsd:element name="amount" type="xsd:decimal"/>
		</xsd:sequence>
	</xsd:complexType>

   … 
   
</xsd:schema>

Importing StockService schema

To override the default input schema element generated by JDeveloper, click on Browse Input Elements … (the magnifying glass circled in the previous screenshot). This will bring up the Type Chooser , as shown in the following screenshot, which allows you to browse all schemas imported by the composite and select an element from them.

Importing StockService schema

In our case, we have yet to import any schemas, so click on Import Schema File … (circled in the previous screenshot). This will launch the Import Schema File window. Click on the magnifying glass to launch the SOA Resource Browser (in File System mode), which will allow us to search our filesystem for an appropriate schema.

Find the StockService.xsd located in the samples folder for Chapter 5 and select this. Ensure that the option to Copy to Project is selected and click OK; JDeveloper will then bring up the Localize Files window. Keep the default options and click OK. This will cause JDeveloper to create a local copy of our XML Schema and any dependant files (of which there are none in this example) within our project.

JDeveloper will now open the schema browser dialog, containing the imported StockService schema. Browse this and select the getQuote element, as shown in the following screenshot:

Importing StockService schema

Repeat this step for the output schema element, but select the getQuoteResponse element. Click OK and this will create our StockQuote process within our composite, as shown in the following screenshot:

Importing StockService schema

Within the composite, double-click the StockQuote process to open it in the BPEL editor. You will see that, by default, JDeveloper has created a skeleton BPEL process, which contains an initial <receive> activity to receive the stock quote request, followed by a <reply> activity to send back the result (as we discussed in the earlier section – Synchronous Messaging). In addition, it will have created two variables; inputVariable, which contains the initial stockquote request, and outputVariable, in which we will place the result to return to the requestor.

Note

If you look in the Projects section of the Application Navigator, you will see that it contains the file StockQuote.wsdl. This contains the WSDL description (including partner link extensions) for our process. If you examine this, you will see that we have a single operation; process, which is used to call the BPEL process.

Calling the external web services

The next step is to call our external web services. For our stock quote service, we are going to use Xignite's quotes web service, which delivers delayed equity price quotes from all U.S. stock exchanges (NYSE, NASDAQ, AMEX, NASDAQ OTC Bulletin Board, and Pink Sheets).

Note

Before you can use this service, you will need to register with Xignite. To do this, or for more information on this and other services provided by Xignite, go to www.xignite.com.

To call a web service in BPEL, we first need to create a partner link (as discussed at the start of this chapter). So from the Component Palette, expand the BPEL Services section and drag a Partner Link (Web Service / Adapter) component into the Partner Link swim lane in your BPEL process. This will pop up the following screen:

Calling the external web services

First enter a name for the partner link, for example, XigniteQuotes. Next we need to specify the WSDL file for the partner link. JDeveloper provides the following ways to do this:

  • SOA Resource Lookup: Allows us to browse the filesystem for WSDL files or any connected application server for deployed services
  • SOA Service Explorer: Allows us to browse other services that are defined within the composite (for example, other BPEL processes, Mediator, or external services)
  • Define Service: This enables us to define adapter services (refer to Chapter 3, Service-enabling Existing Systems) directly within the context of a BPEL process
  • WSDL URL: Directly enter the URL for the WSDL file into the corresponding field

For our reference, we have a local copy of the WSDL for Xignite's quotes service, called XigniteQuotes.wsdl, which is included with the samples for Chapter 5. Click on the SOA Resource Lookup … icon (circled in the preceding screenshot), then browse to and select this file (select Yes if prompted to create a local copy of the file).

JDeveloper will parse the WSDL, and assuming it is successful, it will pop up a window saying that there are no partner link types defined in the current WSDL and ask if you want to create partner links for the file. Click Yes. JDeveloper will then create one Partner Link Type for each port type defined in the WSDL. In cases where we have multiple partner link types, we will need to specify which one to use within our process. To do this, click on the drop-down list next to Partner Link Type and select the appropriate one. In our case, we have selected XigniteQuotesSoap_PL, as shown in the following screenshot:

Calling the external web services

Finally, we need to specify the Partner Role and My Role. When invoking a synchronous service, there will only be a single role defined in the WSDL, which represents the provider of the service. So specify this for the Partner Role and leave My Role as ----- Not Specified -----.

Note

Best practice would dictate that rather than calling the stock quote service directly from within BPEL, we would invoke it via the Oracle Service Bus. This is an area we look at more closely in Chapter 10, oBay Introduction when we define our blueprint for SOA.

If you look at the composite view, you will see that XigniteQuotes is defined as an External Reference and is wired to our BPEL process.

Calling the web service

Once we have defined a partner link for the web service, the next step is to call it. As this is a synchronous service, we will need to use an <invoke> activity to call it, as we described earlier in this chapter.

On the Component Palette, ensure that the BPEL Activities and Components section is expanded. Then from it, drag an Invoke activity on to your BPEL process.

Next, place your mouse over the arrow next to the Invoke activity. Click and hold your mouse button, drag the arrow over your partner link, and then release, as shown in the following screenshot:

Calling the web service

This will then pop up the Edit Invoke activity window, as shown in the following screenshot:

Calling the web service

We need to specify a number of values to configure the Invoke activity, namely:

  • Name: This is the name we want to assign to the Invoke activity, and can be any value. So just assign a meaningful value such as GetQuote.
  • Partner Link: This is the Partner Link whose service we want to invoke; it should already be set to use XigniteQuotes, as we have already linked this activity to that Partner Link. An alternate approach would be to click on the corresponding spotlight icon, which would allow us to select from any Partner Link already defined to the process.
  • Operation: Once we've specified a Partner Link, we need to specify which of its operations we wish to invoke. This presents us with a drop-down list, listing all the operations that are available, for our purpose, select GetSingleQuote.
  • Input: Here we must specify the variable that contains the data to be passed to the web service that's being invoked. It is important that the variable is of type Message, and that it is of the same message type expected by the Operation (that is, as defined in the WSDL file for the web service).

    The simplest way to ensure this is by getting JDeveloper to create the variable for you. To do this, click on the green plus sign to the right of the input variable field. This will bring up the Create Variable window, as shown in the following screenshot. You will notice that JDeveloper creates a default name for the variable (based on the name you gave the invoke operation and the operation that you are calling). You can override this with something more meaningful (for example, QuoteInput).

  • Output: Finally, we must specify the variable into which the value returned by the web service will be placed. As with the input variable, this should be of the type Message and corresponds to the output message defined in the WSDL file for the selected operation. Again, the simplest way to ensure this is to get JDeveloper to create the variable for you.
    Calling the web service

Once you've specified values for all these fields, as illustrated in the preceding screenshot, click OK.

Assigning values to variables

In our previous step, we created the variable QuoteInput, which we pass to our invocation of GetSingleQuote. However, we have yet to initialize the variable or assign any value to it.

To do this, BPEL provides the <assign> activity, which is used to update the values of variables with new data. The <assign> activity typically consists of one or more copy operations. Each copy consists of a target variable, that is, the variable that you wish to assign a value to and a source (this can either be another variable or an XPath expression).

For our purposes, we want to assign the stock symbol passed into our BPEL process to our QuoteInput variable.

To do this, drag an Assign activity from the Component Palette on to your BPEL process at the point just before our Invoke activity. Then double-click on it to open up the Assign configuration window. Click on the green plus sign and select Copy Operation….

This will present us with the Create Copy Operation window, as shown in the following screenshot:

Assigning values to variables

On the left-hand side, we specify the From variable (that is, the source). Here we want to specify the stock symbol passed in as part of the input variable to the BPEL process. So expand the inputVariable tree, and select /ns2:getQuote/ns2:stockSymbol.

For the target, expand QuoteInput and select /ns1:GetSingleQuote/ns1:Symbol.

You will notice that for both the source and target, JDeveloper has created the equivalent XPath expression (circled in the preceding screenshot).

Note

The source and target can either be a simple type (for example, xsd:int, xsd:date, or xsd:string), as in the preceding example. Or a complex type (for example, ns2:getQuote), but make sure the source and target are either of the same type, or at least compatible.

Testing the process

At this stage, even though the process isn't complete, we can still save, deploy, and run our composite. Do this in the same way as previously covered in Chapter 2, Writing your First Composite. When you run the composite from the console you will notice that it doesn't return anything (as we haven't specified this yet). But if you look at the audit trail, you should successfully see the GetSingleQuote operation being invoked. Assuming this is the case, we know we have implemented that part of the process correctly.

Calling the exchange rate web service

The next step of the process is to determine the exchange rate between the requested currency and the US dollar (the currency used by the GetSingleQuote operation). For this, we are going to use the currency convertor service provided by webserviceX.NET .

For more information on this and other services provided by webserviceX.NET, go to www.webservicex.net.

This service provides a single operation ConversionRate, which gets the conversion rate from one currency to another. The WSDL file for this service can be found at the following URL:

http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

For convenience, we have included a local copy of the WSDL for webserviceX.NET's currency convertor service, called CurrencyConvertor.wsdl. It's included with the samples of Chapter 5.

To invoke the ConversionRate operation, we will follow the same basic steps that we did in the previous section to invoke the GetSingleQuote operation. For brevity, we won't repeat them here, but will allow the reader to do this.

Note

To follow the examples, name the input variable for the exchange rate web service ExchangeRateInput and the output variable ExchangeRateOutput.

Assigning constant values to variables

The operation ConversionRate takes two input values as follows:

  • FromCurrency: This should be set to 'USD'
  • ToCurrency: This should be set to the currency field contained within the inputVariable for the BPEL process.

To set the FromCurrency, create another copy operation. However, for the From value, select Expression as the Type (circled in the following screenshot).

This will replace the variable browser with a free format textbox. Here you can specify any value, within quotes, that you wish to assign to your target variable. For our purposes, enter 'USD', as shown in the following screenshot:

Assigning constant values to variables

To set the value of ToCurrency, create another copy operation and copy in the value of the currency field contained within the inputVariable.

At this stage again, save, deploy, and run the composite to validate that we are calling the exchange rate service correctly.

Using the expression builder

The final part of the process is to combine the exchange rate returned by one service with the stock price returned by the other, in order to determine the stock price in the requested currency and return that to the caller of the composite.

To do this, we will again use an <assign> activity. So drag another <assign> activity onto the process, just after our second invoke activity. Now in our previous use of the <assign> activity, we have just used it to copy a value from one variable to another.

Here, it is slightly different, in that we want to combine multiple values into a single value, and to do that, we will need to write the appropriate piece of XPath. Create a copy operation as before, but for the source type, select Expression from the drop-down list, as shown in the following screenshot:

Using the expression builder

Now, if you want, you can type in the XPath expression manually (into the Expression area), but it's far easier and less error prone to use the Expression Builder. To do this, click on the XPath expression builder icon; the calculator icon, which is circled in the preceding screenshot, will pop up the Expression Builder (shown below):

Using the expression builder

The Expression Builder provides a graphical tool for writing XPath expressions, which are executed as part of the copy operation. It consists of the following areas:

  • Expression: The top textbox contains the XPath expression that you are working on. You can either type data directly in here, or use the Expression Builder to insert XPath fragments to build up the XPath required.
  • BPEL variables: This part of the Expression Builder lets you browse the variables defined within your BPEL process. Once you've located the variable that you wish to use, click on the Insert Into Expression button, and this will insert the appropriate code fragment into the XPath expression.

    Note

    The code fragment is inserted at the point within the expression where the cursor is currently positioned.

  • Functions: This shows you all the different types of XPath functions that are available to build up your XPath expression. To make it easier to locate the required function, they are grouped into categories such as String Functions, Mathematical Functions, and so on.

    The drop-down list lets you select the category that you are interested in (for example, Mathematical Functions, as illustrated in the preceding screenshot), and then the window below that lists all the functions available to that group.

    To use a particular function, select the required function, and click Insert Into Expression. This will insert the appropriate XPath fragment into the XPath Expression (again at the point that the cursor is currently positioned).

  • Content Preview: This box displays a preview of the content that would be inserted into the XPath Expression if you clicked the Insert Into Expression button. For example, if you had currently selected a particular BPEL variable, it would show you the XPath to access that variable.
  • Description: If you've currently selected a function, this box provides a brief description of the function, as well as the expected usage and number of parameters.

So let's use this to build our XPath expression. The expression we want to build is a relatively simple one, namely, the stock price returned by the stock quote service multiplied by the exchange rate returned by the exchange rate service.

To build our XPath expression, carry out the following steps:

First, within the BPEL Variables area, in the variable QuoteOutput, locate the element ns1:GetSingleQuoteResult|ns1:Last, as shown in the following screenshot:

Using the expression builder

Then click Insert Into Expression to insert this into the XPath expression.

Next, within the Functions area, select the Mathematical Functions category, and select the multiply function (notice the description in the Description box, as shown in the following screenshot), and insert this into the XPath expression:

Using the expression builder

Finally, back in the BPEL Variables area, locate the element ConversionRateResult within the variable ExchangeRateOutput, and insert that into the XPath expression.

You should now have an XPath expression similar to the one illustrated below, once you are happy with it, click OK.

Using the expression builder

Finally make sure you specify the target part of the copy operation, which should be the amount element within the outputVariable.

In order to complete the <assign> activity, you will need to create two more copy operations to copy the Currency and StockSymbol specified in the inputVariable into the equivalent values in the outputVariable.

Once done, your BPEL process should be complete. So deploy and run the composite.

Asynchronous service

Following our StockQuote service, another service would be a stock order service, which would enable us to buy or sell a particular stock. For this service, a client would need to specify the stock, whether they wanted to buy or sell, the quantity, and the price.

It makes sense to make this an asynchronous service, as once the order has been placed, it may take seconds, minutes, hours, or even days for the order to be matched.

Now, I'm not aware of any trade services that are free to try (probably for a good reason!). However, there is no reason why we can't simulate one. To do this, we will write a simple asynchronous process.

Drag another BPEL process on to our StockService composite and give it the name StockOrder, but specify that it is an asynchronous BPEL process.

As with the StockQuote process, we also want to specify predefined elements for its input and output. The elements we are going to use are placeOrder for the input and placeOrderResponse for the output, the definitions for which are shown in the following code snippet:

<xsd:element name="placeOrder"         type="tPlaceOrder"/>
<xsd:element name="placeOrderResponse" type="tPlaceOrderResponse"/>

<xsd:complexType name="tPlaceOrder">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="bidPrice"    type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="tPlaceOrderResponse">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="actualPrice" type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

These are also defined in the StockService.xsd that we previously imported into the StockService composite. So, for each field, we click on the magnifying glass to bring up the type chooser and select the appropriate element definitions. Then click OK to create the process. This will create a second BPEL process within our composite, so double-click on this to open it.

You will see that, by default, JDeveloper has created a skeleton asynchronous BPEL process, which contains an initial <receive> activity to receive the stock order request. But this time it's followed by an <invoke> activity to send the result back (as opposed to a <reply> activity used by the synchronous process).

If you look at the WSDL for the process, you will see that it defines two operations: process to call the process, and processResponse, which will be called by the process to send back the result. Thus the client that calls the process operation will need to provide the processResponse callback in order to receive the result (this is something we will look at in more detail in Chapter 15, Message Interaction Patterns.

Now, for the purpose of our simulation, we will assume that the StockOrder request is successful and the actualPrice achieved is always the bid price. So to do this, create an assign operation that copies all the original input values to their corresponding output values. Deploy the composite, and run it from the console.

Note

When you click the Test Web Service button for the StockService composite, you will now be presented with two options: stockorder_client_ep and stockquote_client_ep. These correspond to each of the exposed services we have defined in our composite. Ensure you select stockorder_client_ep, which is wired to our StockOrder process.

This time, you will notice that no result is returned (as it's being processed asynchronously); rather it displays a message to indicate that the service was invoked successfully, as shown in the following screenshot:

Asynchronous service

Click on Launch Message Flow Trace to bring up the trace for the composite, and then select StockOrder to bring up the audit trail for the process. Switch to the flow view, and expand the callbackClient activity at the end of the trace. This will pop up a window showing the details of the response sent by our process, as shown in the following screenshot:

Asynchronous service

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Importing StockService schema

To override the default input schema element generated by JDeveloper, click on Browse Input Elements … (the magnifying glass circled in the previous screenshot). This will bring up the Type Chooser , as shown in the following screenshot, which allows you to browse all schemas imported by the composite and select an element from them.

Importing StockService schema

In our case, we have yet to import any schemas, so click on Import Schema File … (circled in the previous screenshot). This will launch the Import Schema File window. Click on the magnifying glass to launch the SOA Resource Browser (in File System mode), which will allow us to search our filesystem for an appropriate schema.

Find the StockService.xsd located in the samples folder for Chapter 5 and select this. Ensure that the option to Copy to Project is selected and click OK; JDeveloper will then bring up the Localize Files window. Keep the default options and click OK. This will cause JDeveloper to create a local copy of our XML Schema and any dependant files (of which there are none in this example) within our project.

JDeveloper will now open the schema browser dialog, containing the imported StockService schema. Browse this and select the getQuote element, as shown in the following screenshot:

Importing StockService schema

Repeat this step for the output schema element, but select the getQuoteResponse element. Click OK and this will create our StockQuote process within our composite, as shown in the following screenshot:

Importing StockService schema

Within the composite, double-click the StockQuote process to open it in the BPEL editor. You will see that, by default, JDeveloper has created a skeleton BPEL process, which contains an initial <receive> activity to receive the stock quote request, followed by a <reply> activity to send back the result (as we discussed in the earlier section – Synchronous Messaging). In addition, it will have created two variables; inputVariable, which contains the initial stockquote request, and outputVariable, in which we will place the result to return to the requestor.

Note

If you look in the Projects section of the Application Navigator, you will see that it contains the file StockQuote.wsdl. This contains the WSDL description (including partner link extensions) for our process. If you examine this, you will see that we have a single operation; process, which is used to call the BPEL process.

Calling the external web services

The next step is to call our external web services. For our stock quote service, we are going to use Xignite's quotes web service, which delivers delayed equity price quotes from all U.S. stock exchanges (NYSE, NASDAQ, AMEX, NASDAQ OTC Bulletin Board, and Pink Sheets).

Note

Before you can use this service, you will need to register with Xignite. To do this, or for more information on this and other services provided by Xignite, go to www.xignite.com.

To call a web service in BPEL, we first need to create a partner link (as discussed at the start of this chapter). So from the Component Palette, expand the BPEL Services section and drag a Partner Link (Web Service / Adapter) component into the Partner Link swim lane in your BPEL process. This will pop up the following screen:

Calling the external web services

First enter a name for the partner link, for example, XigniteQuotes. Next we need to specify the WSDL file for the partner link. JDeveloper provides the following ways to do this:

  • SOA Resource Lookup: Allows us to browse the filesystem for WSDL files or any connected application server for deployed services
  • SOA Service Explorer: Allows us to browse other services that are defined within the composite (for example, other BPEL processes, Mediator, or external services)
  • Define Service: This enables us to define adapter services (refer to Chapter 3, Service-enabling Existing Systems) directly within the context of a BPEL process
  • WSDL URL: Directly enter the URL for the WSDL file into the corresponding field

For our reference, we have a local copy of the WSDL for Xignite's quotes service, called XigniteQuotes.wsdl, which is included with the samples for Chapter 5. Click on the SOA Resource Lookup … icon (circled in the preceding screenshot), then browse to and select this file (select Yes if prompted to create a local copy of the file).

JDeveloper will parse the WSDL, and assuming it is successful, it will pop up a window saying that there are no partner link types defined in the current WSDL and ask if you want to create partner links for the file. Click Yes. JDeveloper will then create one Partner Link Type for each port type defined in the WSDL. In cases where we have multiple partner link types, we will need to specify which one to use within our process. To do this, click on the drop-down list next to Partner Link Type and select the appropriate one. In our case, we have selected XigniteQuotesSoap_PL, as shown in the following screenshot:

Calling the external web services

Finally, we need to specify the Partner Role and My Role. When invoking a synchronous service, there will only be a single role defined in the WSDL, which represents the provider of the service. So specify this for the Partner Role and leave My Role as ----- Not Specified -----.

Note

Best practice would dictate that rather than calling the stock quote service directly from within BPEL, we would invoke it via the Oracle Service Bus. This is an area we look at more closely in Chapter 10, oBay Introduction when we define our blueprint for SOA.

If you look at the composite view, you will see that XigniteQuotes is defined as an External Reference and is wired to our BPEL process.

Calling the web service

Once we have defined a partner link for the web service, the next step is to call it. As this is a synchronous service, we will need to use an <invoke> activity to call it, as we described earlier in this chapter.

On the Component Palette, ensure that the BPEL Activities and Components section is expanded. Then from it, drag an Invoke activity on to your BPEL process.

Next, place your mouse over the arrow next to the Invoke activity. Click and hold your mouse button, drag the arrow over your partner link, and then release, as shown in the following screenshot:

Calling the web service

This will then pop up the Edit Invoke activity window, as shown in the following screenshot:

Calling the web service

We need to specify a number of values to configure the Invoke activity, namely:

  • Name: This is the name we want to assign to the Invoke activity, and can be any value. So just assign a meaningful value such as GetQuote.
  • Partner Link: This is the Partner Link whose service we want to invoke; it should already be set to use XigniteQuotes, as we have already linked this activity to that Partner Link. An alternate approach would be to click on the corresponding spotlight icon, which would allow us to select from any Partner Link already defined to the process.
  • Operation: Once we've specified a Partner Link, we need to specify which of its operations we wish to invoke. This presents us with a drop-down list, listing all the operations that are available, for our purpose, select GetSingleQuote.
  • Input: Here we must specify the variable that contains the data to be passed to the web service that's being invoked. It is important that the variable is of type Message, and that it is of the same message type expected by the Operation (that is, as defined in the WSDL file for the web service).

    The simplest way to ensure this is by getting JDeveloper to create the variable for you. To do this, click on the green plus sign to the right of the input variable field. This will bring up the Create Variable window, as shown in the following screenshot. You will notice that JDeveloper creates a default name for the variable (based on the name you gave the invoke operation and the operation that you are calling). You can override this with something more meaningful (for example, QuoteInput).

  • Output: Finally, we must specify the variable into which the value returned by the web service will be placed. As with the input variable, this should be of the type Message and corresponds to the output message defined in the WSDL file for the selected operation. Again, the simplest way to ensure this is to get JDeveloper to create the variable for you.
    Calling the web service

Once you've specified values for all these fields, as illustrated in the preceding screenshot, click OK.

Assigning values to variables

In our previous step, we created the variable QuoteInput, which we pass to our invocation of GetSingleQuote. However, we have yet to initialize the variable or assign any value to it.

To do this, BPEL provides the <assign> activity, which is used to update the values of variables with new data. The <assign> activity typically consists of one or more copy operations. Each copy consists of a target variable, that is, the variable that you wish to assign a value to and a source (this can either be another variable or an XPath expression).

For our purposes, we want to assign the stock symbol passed into our BPEL process to our QuoteInput variable.

To do this, drag an Assign activity from the Component Palette on to your BPEL process at the point just before our Invoke activity. Then double-click on it to open up the Assign configuration window. Click on the green plus sign and select Copy Operation….

This will present us with the Create Copy Operation window, as shown in the following screenshot:

Assigning values to variables

On the left-hand side, we specify the From variable (that is, the source). Here we want to specify the stock symbol passed in as part of the input variable to the BPEL process. So expand the inputVariable tree, and select /ns2:getQuote/ns2:stockSymbol.

For the target, expand QuoteInput and select /ns1:GetSingleQuote/ns1:Symbol.

You will notice that for both the source and target, JDeveloper has created the equivalent XPath expression (circled in the preceding screenshot).

Note

The source and target can either be a simple type (for example, xsd:int, xsd:date, or xsd:string), as in the preceding example. Or a complex type (for example, ns2:getQuote), but make sure the source and target are either of the same type, or at least compatible.

Testing the process

At this stage, even though the process isn't complete, we can still save, deploy, and run our composite. Do this in the same way as previously covered in Chapter 2, Writing your First Composite. When you run the composite from the console you will notice that it doesn't return anything (as we haven't specified this yet). But if you look at the audit trail, you should successfully see the GetSingleQuote operation being invoked. Assuming this is the case, we know we have implemented that part of the process correctly.

Calling the exchange rate web service

The next step of the process is to determine the exchange rate between the requested currency and the US dollar (the currency used by the GetSingleQuote operation). For this, we are going to use the currency convertor service provided by webserviceX.NET .

For more information on this and other services provided by webserviceX.NET, go to www.webservicex.net.

This service provides a single operation ConversionRate, which gets the conversion rate from one currency to another. The WSDL file for this service can be found at the following URL:

http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

For convenience, we have included a local copy of the WSDL for webserviceX.NET's currency convertor service, called CurrencyConvertor.wsdl. It's included with the samples of Chapter 5.

To invoke the ConversionRate operation, we will follow the same basic steps that we did in the previous section to invoke the GetSingleQuote operation. For brevity, we won't repeat them here, but will allow the reader to do this.

Note

To follow the examples, name the input variable for the exchange rate web service ExchangeRateInput and the output variable ExchangeRateOutput.

Assigning constant values to variables

The operation ConversionRate takes two input values as follows:

  • FromCurrency: This should be set to 'USD'
  • ToCurrency: This should be set to the currency field contained within the inputVariable for the BPEL process.

To set the FromCurrency, create another copy operation. However, for the From value, select Expression as the Type (circled in the following screenshot).

This will replace the variable browser with a free format textbox. Here you can specify any value, within quotes, that you wish to assign to your target variable. For our purposes, enter 'USD', as shown in the following screenshot:

Assigning constant values to variables

To set the value of ToCurrency, create another copy operation and copy in the value of the currency field contained within the inputVariable.

At this stage again, save, deploy, and run the composite to validate that we are calling the exchange rate service correctly.

Using the expression builder

The final part of the process is to combine the exchange rate returned by one service with the stock price returned by the other, in order to determine the stock price in the requested currency and return that to the caller of the composite.

To do this, we will again use an <assign> activity. So drag another <assign> activity onto the process, just after our second invoke activity. Now in our previous use of the <assign> activity, we have just used it to copy a value from one variable to another.

Here, it is slightly different, in that we want to combine multiple values into a single value, and to do that, we will need to write the appropriate piece of XPath. Create a copy operation as before, but for the source type, select Expression from the drop-down list, as shown in the following screenshot:

Using the expression builder

Now, if you want, you can type in the XPath expression manually (into the Expression area), but it's far easier and less error prone to use the Expression Builder. To do this, click on the XPath expression builder icon; the calculator icon, which is circled in the preceding screenshot, will pop up the Expression Builder (shown below):

Using the expression builder

The Expression Builder provides a graphical tool for writing XPath expressions, which are executed as part of the copy operation. It consists of the following areas:

  • Expression: The top textbox contains the XPath expression that you are working on. You can either type data directly in here, or use the Expression Builder to insert XPath fragments to build up the XPath required.
  • BPEL variables: This part of the Expression Builder lets you browse the variables defined within your BPEL process. Once you've located the variable that you wish to use, click on the Insert Into Expression button, and this will insert the appropriate code fragment into the XPath expression.

    Note

    The code fragment is inserted at the point within the expression where the cursor is currently positioned.

  • Functions: This shows you all the different types of XPath functions that are available to build up your XPath expression. To make it easier to locate the required function, they are grouped into categories such as String Functions, Mathematical Functions, and so on.

    The drop-down list lets you select the category that you are interested in (for example, Mathematical Functions, as illustrated in the preceding screenshot), and then the window below that lists all the functions available to that group.

    To use a particular function, select the required function, and click Insert Into Expression. This will insert the appropriate XPath fragment into the XPath Expression (again at the point that the cursor is currently positioned).

  • Content Preview: This box displays a preview of the content that would be inserted into the XPath Expression if you clicked the Insert Into Expression button. For example, if you had currently selected a particular BPEL variable, it would show you the XPath to access that variable.
  • Description: If you've currently selected a function, this box provides a brief description of the function, as well as the expected usage and number of parameters.

So let's use this to build our XPath expression. The expression we want to build is a relatively simple one, namely, the stock price returned by the stock quote service multiplied by the exchange rate returned by the exchange rate service.

To build our XPath expression, carry out the following steps:

First, within the BPEL Variables area, in the variable QuoteOutput, locate the element ns1:GetSingleQuoteResult|ns1:Last, as shown in the following screenshot:

Using the expression builder

Then click Insert Into Expression to insert this into the XPath expression.

Next, within the Functions area, select the Mathematical Functions category, and select the multiply function (notice the description in the Description box, as shown in the following screenshot), and insert this into the XPath expression:

Using the expression builder

Finally, back in the BPEL Variables area, locate the element ConversionRateResult within the variable ExchangeRateOutput, and insert that into the XPath expression.

You should now have an XPath expression similar to the one illustrated below, once you are happy with it, click OK.

Using the expression builder

Finally make sure you specify the target part of the copy operation, which should be the amount element within the outputVariable.

In order to complete the <assign> activity, you will need to create two more copy operations to copy the Currency and StockSymbol specified in the inputVariable into the equivalent values in the outputVariable.

Once done, your BPEL process should be complete. So deploy and run the composite.

Asynchronous service

Following our StockQuote service, another service would be a stock order service, which would enable us to buy or sell a particular stock. For this service, a client would need to specify the stock, whether they wanted to buy or sell, the quantity, and the price.

It makes sense to make this an asynchronous service, as once the order has been placed, it may take seconds, minutes, hours, or even days for the order to be matched.

Now, I'm not aware of any trade services that are free to try (probably for a good reason!). However, there is no reason why we can't simulate one. To do this, we will write a simple asynchronous process.

Drag another BPEL process on to our StockService composite and give it the name StockOrder, but specify that it is an asynchronous BPEL process.

As with the StockQuote process, we also want to specify predefined elements for its input and output. The elements we are going to use are placeOrder for the input and placeOrderResponse for the output, the definitions for which are shown in the following code snippet:

<xsd:element name="placeOrder"         type="tPlaceOrder"/>
<xsd:element name="placeOrderResponse" type="tPlaceOrderResponse"/>

<xsd:complexType name="tPlaceOrder">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="bidPrice"    type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="tPlaceOrderResponse">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="actualPrice" type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

These are also defined in the StockService.xsd that we previously imported into the StockService composite. So, for each field, we click on the magnifying glass to bring up the type chooser and select the appropriate element definitions. Then click OK to create the process. This will create a second BPEL process within our composite, so double-click on this to open it.

You will see that, by default, JDeveloper has created a skeleton asynchronous BPEL process, which contains an initial <receive> activity to receive the stock order request. But this time it's followed by an <invoke> activity to send the result back (as opposed to a <reply> activity used by the synchronous process).

If you look at the WSDL for the process, you will see that it defines two operations: process to call the process, and processResponse, which will be called by the process to send back the result. Thus the client that calls the process operation will need to provide the processResponse callback in order to receive the result (this is something we will look at in more detail in Chapter 15, Message Interaction Patterns.

Now, for the purpose of our simulation, we will assume that the StockOrder request is successful and the actualPrice achieved is always the bid price. So to do this, create an assign operation that copies all the original input values to their corresponding output values. Deploy the composite, and run it from the console.

Note

When you click the Test Web Service button for the StockService composite, you will now be presented with two options: stockorder_client_ep and stockquote_client_ep. These correspond to each of the exposed services we have defined in our composite. Ensure you select stockorder_client_ep, which is wired to our StockOrder process.

This time, you will notice that no result is returned (as it's being processed asynchronously); rather it displays a message to indicate that the service was invoked successfully, as shown in the following screenshot:

Asynchronous service

Click on Launch Message Flow Trace to bring up the trace for the composite, and then select StockOrder to bring up the audit trail for the process. Switch to the flow view, and expand the callbackClient activity at the end of the trace. This will pop up a window showing the details of the response sent by our process, as shown in the following screenshot:

Asynchronous service

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Calling the external web services

The next step is to call our external web services. For our stock quote service, we are going to use Xignite's quotes web service, which delivers delayed equity price quotes from all U.S. stock exchanges (NYSE, NASDAQ, AMEX, NASDAQ OTC Bulletin Board, and Pink Sheets).

Note

Before you can use this service, you will need to register with Xignite. To do this, or for more information on this and other services provided by Xignite, go to www.xignite.com.

To call a web service in BPEL, we first need to create a partner link (as discussed at the start of this chapter). So from the Component Palette, expand the BPEL Services section and drag a Partner Link (Web Service / Adapter) component into the Partner Link swim lane in your BPEL process. This will pop up the following screen:

Calling the external web services

First enter a name for the partner link, for example, XigniteQuotes. Next we need to specify the WSDL file for the partner link. JDeveloper provides the following ways to do this:

  • SOA Resource Lookup: Allows us to browse the filesystem for WSDL files or any connected application server for deployed services
  • SOA Service Explorer: Allows us to browse other services that are defined within the composite (for example, other BPEL processes, Mediator, or external services)
  • Define Service: This enables us to define adapter services (refer to Chapter 3, Service-enabling Existing Systems) directly within the context of a BPEL process
  • WSDL URL: Directly enter the URL for the WSDL file into the corresponding field

For our reference, we have a local copy of the WSDL for Xignite's quotes service, called XigniteQuotes.wsdl, which is included with the samples for Chapter 5. Click on the SOA Resource Lookup … icon (circled in the preceding screenshot), then browse to and select this file (select Yes if prompted to create a local copy of the file).

JDeveloper will parse the WSDL, and assuming it is successful, it will pop up a window saying that there are no partner link types defined in the current WSDL and ask if you want to create partner links for the file. Click Yes. JDeveloper will then create one Partner Link Type for each port type defined in the WSDL. In cases where we have multiple partner link types, we will need to specify which one to use within our process. To do this, click on the drop-down list next to Partner Link Type and select the appropriate one. In our case, we have selected XigniteQuotesSoap_PL, as shown in the following screenshot:

Calling the external web services

Finally, we need to specify the Partner Role and My Role. When invoking a synchronous service, there will only be a single role defined in the WSDL, which represents the provider of the service. So specify this for the Partner Role and leave My Role as ----- Not Specified -----.

Note

Best practice would dictate that rather than calling the stock quote service directly from within BPEL, we would invoke it via the Oracle Service Bus. This is an area we look at more closely in Chapter 10, oBay Introduction when we define our blueprint for SOA.

If you look at the composite view, you will see that XigniteQuotes is defined as an External Reference and is wired to our BPEL process.

Calling the web service

Once we have defined a partner link for the web service, the next step is to call it. As this is a synchronous service, we will need to use an <invoke> activity to call it, as we described earlier in this chapter.

On the Component Palette, ensure that the BPEL Activities and Components section is expanded. Then from it, drag an Invoke activity on to your BPEL process.

Next, place your mouse over the arrow next to the Invoke activity. Click and hold your mouse button, drag the arrow over your partner link, and then release, as shown in the following screenshot:

Calling the web service

This will then pop up the Edit Invoke activity window, as shown in the following screenshot:

Calling the web service

We need to specify a number of values to configure the Invoke activity, namely:

  • Name: This is the name we want to assign to the Invoke activity, and can be any value. So just assign a meaningful value such as GetQuote.
  • Partner Link: This is the Partner Link whose service we want to invoke; it should already be set to use XigniteQuotes, as we have already linked this activity to that Partner Link. An alternate approach would be to click on the corresponding spotlight icon, which would allow us to select from any Partner Link already defined to the process.
  • Operation: Once we've specified a Partner Link, we need to specify which of its operations we wish to invoke. This presents us with a drop-down list, listing all the operations that are available, for our purpose, select GetSingleQuote.
  • Input: Here we must specify the variable that contains the data to be passed to the web service that's being invoked. It is important that the variable is of type Message, and that it is of the same message type expected by the Operation (that is, as defined in the WSDL file for the web service).

    The simplest way to ensure this is by getting JDeveloper to create the variable for you. To do this, click on the green plus sign to the right of the input variable field. This will bring up the Create Variable window, as shown in the following screenshot. You will notice that JDeveloper creates a default name for the variable (based on the name you gave the invoke operation and the operation that you are calling). You can override this with something more meaningful (for example, QuoteInput).

  • Output: Finally, we must specify the variable into which the value returned by the web service will be placed. As with the input variable, this should be of the type Message and corresponds to the output message defined in the WSDL file for the selected operation. Again, the simplest way to ensure this is to get JDeveloper to create the variable for you.
    Calling the web service

Once you've specified values for all these fields, as illustrated in the preceding screenshot, click OK.

Assigning values to variables

In our previous step, we created the variable QuoteInput, which we pass to our invocation of GetSingleQuote. However, we have yet to initialize the variable or assign any value to it.

To do this, BPEL provides the <assign> activity, which is used to update the values of variables with new data. The <assign> activity typically consists of one or more copy operations. Each copy consists of a target variable, that is, the variable that you wish to assign a value to and a source (this can either be another variable or an XPath expression).

For our purposes, we want to assign the stock symbol passed into our BPEL process to our QuoteInput variable.

To do this, drag an Assign activity from the Component Palette on to your BPEL process at the point just before our Invoke activity. Then double-click on it to open up the Assign configuration window. Click on the green plus sign and select Copy Operation….

This will present us with the Create Copy Operation window, as shown in the following screenshot:

Assigning values to variables

On the left-hand side, we specify the From variable (that is, the source). Here we want to specify the stock symbol passed in as part of the input variable to the BPEL process. So expand the inputVariable tree, and select /ns2:getQuote/ns2:stockSymbol.

For the target, expand QuoteInput and select /ns1:GetSingleQuote/ns1:Symbol.

You will notice that for both the source and target, JDeveloper has created the equivalent XPath expression (circled in the preceding screenshot).

Note

The source and target can either be a simple type (for example, xsd:int, xsd:date, or xsd:string), as in the preceding example. Or a complex type (for example, ns2:getQuote), but make sure the source and target are either of the same type, or at least compatible.

Testing the process

At this stage, even though the process isn't complete, we can still save, deploy, and run our composite. Do this in the same way as previously covered in Chapter 2, Writing your First Composite. When you run the composite from the console you will notice that it doesn't return anything (as we haven't specified this yet). But if you look at the audit trail, you should successfully see the GetSingleQuote operation being invoked. Assuming this is the case, we know we have implemented that part of the process correctly.

Calling the exchange rate web service

The next step of the process is to determine the exchange rate between the requested currency and the US dollar (the currency used by the GetSingleQuote operation). For this, we are going to use the currency convertor service provided by webserviceX.NET .

For more information on this and other services provided by webserviceX.NET, go to www.webservicex.net.

This service provides a single operation ConversionRate, which gets the conversion rate from one currency to another. The WSDL file for this service can be found at the following URL:

http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

For convenience, we have included a local copy of the WSDL for webserviceX.NET's currency convertor service, called CurrencyConvertor.wsdl. It's included with the samples of Chapter 5.

To invoke the ConversionRate operation, we will follow the same basic steps that we did in the previous section to invoke the GetSingleQuote operation. For brevity, we won't repeat them here, but will allow the reader to do this.

Note

To follow the examples, name the input variable for the exchange rate web service ExchangeRateInput and the output variable ExchangeRateOutput.

Assigning constant values to variables

The operation ConversionRate takes two input values as follows:

  • FromCurrency: This should be set to 'USD'
  • ToCurrency: This should be set to the currency field contained within the inputVariable for the BPEL process.

To set the FromCurrency, create another copy operation. However, for the From value, select Expression as the Type (circled in the following screenshot).

This will replace the variable browser with a free format textbox. Here you can specify any value, within quotes, that you wish to assign to your target variable. For our purposes, enter 'USD', as shown in the following screenshot:

Assigning constant values to variables

To set the value of ToCurrency, create another copy operation and copy in the value of the currency field contained within the inputVariable.

At this stage again, save, deploy, and run the composite to validate that we are calling the exchange rate service correctly.

Using the expression builder

The final part of the process is to combine the exchange rate returned by one service with the stock price returned by the other, in order to determine the stock price in the requested currency and return that to the caller of the composite.

To do this, we will again use an <assign> activity. So drag another <assign> activity onto the process, just after our second invoke activity. Now in our previous use of the <assign> activity, we have just used it to copy a value from one variable to another.

Here, it is slightly different, in that we want to combine multiple values into a single value, and to do that, we will need to write the appropriate piece of XPath. Create a copy operation as before, but for the source type, select Expression from the drop-down list, as shown in the following screenshot:

Using the expression builder

Now, if you want, you can type in the XPath expression manually (into the Expression area), but it's far easier and less error prone to use the Expression Builder. To do this, click on the XPath expression builder icon; the calculator icon, which is circled in the preceding screenshot, will pop up the Expression Builder (shown below):

Using the expression builder

The Expression Builder provides a graphical tool for writing XPath expressions, which are executed as part of the copy operation. It consists of the following areas:

  • Expression: The top textbox contains the XPath expression that you are working on. You can either type data directly in here, or use the Expression Builder to insert XPath fragments to build up the XPath required.
  • BPEL variables: This part of the Expression Builder lets you browse the variables defined within your BPEL process. Once you've located the variable that you wish to use, click on the Insert Into Expression button, and this will insert the appropriate code fragment into the XPath expression.

    Note

    The code fragment is inserted at the point within the expression where the cursor is currently positioned.

  • Functions: This shows you all the different types of XPath functions that are available to build up your XPath expression. To make it easier to locate the required function, they are grouped into categories such as String Functions, Mathematical Functions, and so on.

    The drop-down list lets you select the category that you are interested in (for example, Mathematical Functions, as illustrated in the preceding screenshot), and then the window below that lists all the functions available to that group.

    To use a particular function, select the required function, and click Insert Into Expression. This will insert the appropriate XPath fragment into the XPath Expression (again at the point that the cursor is currently positioned).

  • Content Preview: This box displays a preview of the content that would be inserted into the XPath Expression if you clicked the Insert Into Expression button. For example, if you had currently selected a particular BPEL variable, it would show you the XPath to access that variable.
  • Description: If you've currently selected a function, this box provides a brief description of the function, as well as the expected usage and number of parameters.

So let's use this to build our XPath expression. The expression we want to build is a relatively simple one, namely, the stock price returned by the stock quote service multiplied by the exchange rate returned by the exchange rate service.

To build our XPath expression, carry out the following steps:

First, within the BPEL Variables area, in the variable QuoteOutput, locate the element ns1:GetSingleQuoteResult|ns1:Last, as shown in the following screenshot:

Using the expression builder

Then click Insert Into Expression to insert this into the XPath expression.

Next, within the Functions area, select the Mathematical Functions category, and select the multiply function (notice the description in the Description box, as shown in the following screenshot), and insert this into the XPath expression:

Using the expression builder

Finally, back in the BPEL Variables area, locate the element ConversionRateResult within the variable ExchangeRateOutput, and insert that into the XPath expression.

You should now have an XPath expression similar to the one illustrated below, once you are happy with it, click OK.

Using the expression builder

Finally make sure you specify the target part of the copy operation, which should be the amount element within the outputVariable.

In order to complete the <assign> activity, you will need to create two more copy operations to copy the Currency and StockSymbol specified in the inputVariable into the equivalent values in the outputVariable.

Once done, your BPEL process should be complete. So deploy and run the composite.

Asynchronous service

Following our StockQuote service, another service would be a stock order service, which would enable us to buy or sell a particular stock. For this service, a client would need to specify the stock, whether they wanted to buy or sell, the quantity, and the price.

It makes sense to make this an asynchronous service, as once the order has been placed, it may take seconds, minutes, hours, or even days for the order to be matched.

Now, I'm not aware of any trade services that are free to try (probably for a good reason!). However, there is no reason why we can't simulate one. To do this, we will write a simple asynchronous process.

Drag another BPEL process on to our StockService composite and give it the name StockOrder, but specify that it is an asynchronous BPEL process.

As with the StockQuote process, we also want to specify predefined elements for its input and output. The elements we are going to use are placeOrder for the input and placeOrderResponse for the output, the definitions for which are shown in the following code snippet:

<xsd:element name="placeOrder"         type="tPlaceOrder"/>
<xsd:element name="placeOrderResponse" type="tPlaceOrderResponse"/>

<xsd:complexType name="tPlaceOrder">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="bidPrice"    type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="tPlaceOrderResponse">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="actualPrice" type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

These are also defined in the StockService.xsd that we previously imported into the StockService composite. So, for each field, we click on the magnifying glass to bring up the type chooser and select the appropriate element definitions. Then click OK to create the process. This will create a second BPEL process within our composite, so double-click on this to open it.

You will see that, by default, JDeveloper has created a skeleton asynchronous BPEL process, which contains an initial <receive> activity to receive the stock order request. But this time it's followed by an <invoke> activity to send the result back (as opposed to a <reply> activity used by the synchronous process).

If you look at the WSDL for the process, you will see that it defines two operations: process to call the process, and processResponse, which will be called by the process to send back the result. Thus the client that calls the process operation will need to provide the processResponse callback in order to receive the result (this is something we will look at in more detail in Chapter 15, Message Interaction Patterns.

Now, for the purpose of our simulation, we will assume that the StockOrder request is successful and the actualPrice achieved is always the bid price. So to do this, create an assign operation that copies all the original input values to their corresponding output values. Deploy the composite, and run it from the console.

Note

When you click the Test Web Service button for the StockService composite, you will now be presented with two options: stockorder_client_ep and stockquote_client_ep. These correspond to each of the exposed services we have defined in our composite. Ensure you select stockorder_client_ep, which is wired to our StockOrder process.

This time, you will notice that no result is returned (as it's being processed asynchronously); rather it displays a message to indicate that the service was invoked successfully, as shown in the following screenshot:

Asynchronous service

Click on Launch Message Flow Trace to bring up the trace for the composite, and then select StockOrder to bring up the audit trail for the process. Switch to the flow view, and expand the callbackClient activity at the end of the trace. This will pop up a window showing the details of the response sent by our process, as shown in the following screenshot:

Asynchronous service

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Calling the web service

Once we have defined a partner link for the web service, the next step is to call it. As this is a synchronous service, we will need to use an <invoke> activity to call it, as we described earlier in this chapter.

On the Component Palette, ensure that the BPEL Activities and Components section is expanded. Then from it, drag an Invoke activity on to your BPEL process.

Next, place your mouse over the arrow next to the Invoke activity. Click and hold your mouse button, drag the arrow over your partner link, and then release, as shown in the following screenshot:

Calling the web service

This will then pop up the Edit Invoke activity window, as shown in the following screenshot:

Calling the web service

We need to specify a number of values to configure the Invoke activity, namely:

  • Name: This is the name we want to assign to the Invoke activity, and can be any value. So just assign a meaningful value such as GetQuote.
  • Partner Link: This is the Partner Link whose service we want to invoke; it should already be set to use XigniteQuotes, as we have already linked this activity to that Partner Link. An alternate approach would be to click on the corresponding spotlight icon, which would allow us to select from any Partner Link already defined to the process.
  • Operation: Once we've specified a Partner Link, we need to specify which of its operations we wish to invoke. This presents us with a drop-down list, listing all the operations that are available, for our purpose, select GetSingleQuote.
  • Input: Here we must specify the variable that contains the data to be passed to the web service that's being invoked. It is important that the variable is of type Message, and that it is of the same message type expected by the Operation (that is, as defined in the WSDL file for the web service).

    The simplest way to ensure this is by getting JDeveloper to create the variable for you. To do this, click on the green plus sign to the right of the input variable field. This will bring up the Create Variable window, as shown in the following screenshot. You will notice that JDeveloper creates a default name for the variable (based on the name you gave the invoke operation and the operation that you are calling). You can override this with something more meaningful (for example, QuoteInput).

  • Output: Finally, we must specify the variable into which the value returned by the web service will be placed. As with the input variable, this should be of the type Message and corresponds to the output message defined in the WSDL file for the selected operation. Again, the simplest way to ensure this is to get JDeveloper to create the variable for you.
    Calling the web service

Once you've specified values for all these fields, as illustrated in the preceding screenshot, click OK.

Assigning values to variables

In our previous step, we created the variable QuoteInput, which we pass to our invocation of GetSingleQuote. However, we have yet to initialize the variable or assign any value to it.

To do this, BPEL provides the <assign> activity, which is used to update the values of variables with new data. The <assign> activity typically consists of one or more copy operations. Each copy consists of a target variable, that is, the variable that you wish to assign a value to and a source (this can either be another variable or an XPath expression).

For our purposes, we want to assign the stock symbol passed into our BPEL process to our QuoteInput variable.

To do this, drag an Assign activity from the Component Palette on to your BPEL process at the point just before our Invoke activity. Then double-click on it to open up the Assign configuration window. Click on the green plus sign and select Copy Operation….

This will present us with the Create Copy Operation window, as shown in the following screenshot:

Assigning values to variables

On the left-hand side, we specify the From variable (that is, the source). Here we want to specify the stock symbol passed in as part of the input variable to the BPEL process. So expand the inputVariable tree, and select /ns2:getQuote/ns2:stockSymbol.

For the target, expand QuoteInput and select /ns1:GetSingleQuote/ns1:Symbol.

You will notice that for both the source and target, JDeveloper has created the equivalent XPath expression (circled in the preceding screenshot).

Note

The source and target can either be a simple type (for example, xsd:int, xsd:date, or xsd:string), as in the preceding example. Or a complex type (for example, ns2:getQuote), but make sure the source and target are either of the same type, or at least compatible.

Testing the process

At this stage, even though the process isn't complete, we can still save, deploy, and run our composite. Do this in the same way as previously covered in Chapter 2, Writing your First Composite. When you run the composite from the console you will notice that it doesn't return anything (as we haven't specified this yet). But if you look at the audit trail, you should successfully see the GetSingleQuote operation being invoked. Assuming this is the case, we know we have implemented that part of the process correctly.

Calling the exchange rate web service

The next step of the process is to determine the exchange rate between the requested currency and the US dollar (the currency used by the GetSingleQuote operation). For this, we are going to use the currency convertor service provided by webserviceX.NET .

For more information on this and other services provided by webserviceX.NET, go to www.webservicex.net.

This service provides a single operation ConversionRate, which gets the conversion rate from one currency to another. The WSDL file for this service can be found at the following URL:

http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

For convenience, we have included a local copy of the WSDL for webserviceX.NET's currency convertor service, called CurrencyConvertor.wsdl. It's included with the samples of Chapter 5.

To invoke the ConversionRate operation, we will follow the same basic steps that we did in the previous section to invoke the GetSingleQuote operation. For brevity, we won't repeat them here, but will allow the reader to do this.

Note

To follow the examples, name the input variable for the exchange rate web service ExchangeRateInput and the output variable ExchangeRateOutput.

Assigning constant values to variables

The operation ConversionRate takes two input values as follows:

  • FromCurrency: This should be set to 'USD'
  • ToCurrency: This should be set to the currency field contained within the inputVariable for the BPEL process.

To set the FromCurrency, create another copy operation. However, for the From value, select Expression as the Type (circled in the following screenshot).

This will replace the variable browser with a free format textbox. Here you can specify any value, within quotes, that you wish to assign to your target variable. For our purposes, enter 'USD', as shown in the following screenshot:

Assigning constant values to variables

To set the value of ToCurrency, create another copy operation and copy in the value of the currency field contained within the inputVariable.

At this stage again, save, deploy, and run the composite to validate that we are calling the exchange rate service correctly.

Using the expression builder

The final part of the process is to combine the exchange rate returned by one service with the stock price returned by the other, in order to determine the stock price in the requested currency and return that to the caller of the composite.

To do this, we will again use an <assign> activity. So drag another <assign> activity onto the process, just after our second invoke activity. Now in our previous use of the <assign> activity, we have just used it to copy a value from one variable to another.

Here, it is slightly different, in that we want to combine multiple values into a single value, and to do that, we will need to write the appropriate piece of XPath. Create a copy operation as before, but for the source type, select Expression from the drop-down list, as shown in the following screenshot:

Using the expression builder

Now, if you want, you can type in the XPath expression manually (into the Expression area), but it's far easier and less error prone to use the Expression Builder. To do this, click on the XPath expression builder icon; the calculator icon, which is circled in the preceding screenshot, will pop up the Expression Builder (shown below):

Using the expression builder

The Expression Builder provides a graphical tool for writing XPath expressions, which are executed as part of the copy operation. It consists of the following areas:

  • Expression: The top textbox contains the XPath expression that you are working on. You can either type data directly in here, or use the Expression Builder to insert XPath fragments to build up the XPath required.
  • BPEL variables: This part of the Expression Builder lets you browse the variables defined within your BPEL process. Once you've located the variable that you wish to use, click on the Insert Into Expression button, and this will insert the appropriate code fragment into the XPath expression.

    Note

    The code fragment is inserted at the point within the expression where the cursor is currently positioned.

  • Functions: This shows you all the different types of XPath functions that are available to build up your XPath expression. To make it easier to locate the required function, they are grouped into categories such as String Functions, Mathematical Functions, and so on.

    The drop-down list lets you select the category that you are interested in (for example, Mathematical Functions, as illustrated in the preceding screenshot), and then the window below that lists all the functions available to that group.

    To use a particular function, select the required function, and click Insert Into Expression. This will insert the appropriate XPath fragment into the XPath Expression (again at the point that the cursor is currently positioned).

  • Content Preview: This box displays a preview of the content that would be inserted into the XPath Expression if you clicked the Insert Into Expression button. For example, if you had currently selected a particular BPEL variable, it would show you the XPath to access that variable.
  • Description: If you've currently selected a function, this box provides a brief description of the function, as well as the expected usage and number of parameters.

So let's use this to build our XPath expression. The expression we want to build is a relatively simple one, namely, the stock price returned by the stock quote service multiplied by the exchange rate returned by the exchange rate service.

To build our XPath expression, carry out the following steps:

First, within the BPEL Variables area, in the variable QuoteOutput, locate the element ns1:GetSingleQuoteResult|ns1:Last, as shown in the following screenshot:

Using the expression builder

Then click Insert Into Expression to insert this into the XPath expression.

Next, within the Functions area, select the Mathematical Functions category, and select the multiply function (notice the description in the Description box, as shown in the following screenshot), and insert this into the XPath expression:

Using the expression builder

Finally, back in the BPEL Variables area, locate the element ConversionRateResult within the variable ExchangeRateOutput, and insert that into the XPath expression.

You should now have an XPath expression similar to the one illustrated below, once you are happy with it, click OK.

Using the expression builder

Finally make sure you specify the target part of the copy operation, which should be the amount element within the outputVariable.

In order to complete the <assign> activity, you will need to create two more copy operations to copy the Currency and StockSymbol specified in the inputVariable into the equivalent values in the outputVariable.

Once done, your BPEL process should be complete. So deploy and run the composite.

Asynchronous service

Following our StockQuote service, another service would be a stock order service, which would enable us to buy or sell a particular stock. For this service, a client would need to specify the stock, whether they wanted to buy or sell, the quantity, and the price.

It makes sense to make this an asynchronous service, as once the order has been placed, it may take seconds, minutes, hours, or even days for the order to be matched.

Now, I'm not aware of any trade services that are free to try (probably for a good reason!). However, there is no reason why we can't simulate one. To do this, we will write a simple asynchronous process.

Drag another BPEL process on to our StockService composite and give it the name StockOrder, but specify that it is an asynchronous BPEL process.

As with the StockQuote process, we also want to specify predefined elements for its input and output. The elements we are going to use are placeOrder for the input and placeOrderResponse for the output, the definitions for which are shown in the following code snippet:

<xsd:element name="placeOrder"         type="tPlaceOrder"/>
<xsd:element name="placeOrderResponse" type="tPlaceOrderResponse"/>

<xsd:complexType name="tPlaceOrder">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="bidPrice"    type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="tPlaceOrderResponse">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="actualPrice" type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

These are also defined in the StockService.xsd that we previously imported into the StockService composite. So, for each field, we click on the magnifying glass to bring up the type chooser and select the appropriate element definitions. Then click OK to create the process. This will create a second BPEL process within our composite, so double-click on this to open it.

You will see that, by default, JDeveloper has created a skeleton asynchronous BPEL process, which contains an initial <receive> activity to receive the stock order request. But this time it's followed by an <invoke> activity to send the result back (as opposed to a <reply> activity used by the synchronous process).

If you look at the WSDL for the process, you will see that it defines two operations: process to call the process, and processResponse, which will be called by the process to send back the result. Thus the client that calls the process operation will need to provide the processResponse callback in order to receive the result (this is something we will look at in more detail in Chapter 15, Message Interaction Patterns.

Now, for the purpose of our simulation, we will assume that the StockOrder request is successful and the actualPrice achieved is always the bid price. So to do this, create an assign operation that copies all the original input values to their corresponding output values. Deploy the composite, and run it from the console.

Note

When you click the Test Web Service button for the StockService composite, you will now be presented with two options: stockorder_client_ep and stockquote_client_ep. These correspond to each of the exposed services we have defined in our composite. Ensure you select stockorder_client_ep, which is wired to our StockOrder process.

This time, you will notice that no result is returned (as it's being processed asynchronously); rather it displays a message to indicate that the service was invoked successfully, as shown in the following screenshot:

Asynchronous service

Click on Launch Message Flow Trace to bring up the trace for the composite, and then select StockOrder to bring up the audit trail for the process. Switch to the flow view, and expand the callbackClient activity at the end of the trace. This will pop up a window showing the details of the response sent by our process, as shown in the following screenshot:

Asynchronous service

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Assigning values to variables

In our previous step, we created the variable QuoteInput, which we pass to our invocation of GetSingleQuote. However, we have yet to initialize the variable or assign any value to it.

To do this, BPEL provides the <assign> activity, which is used to update the values of variables with new data. The <assign> activity typically consists of one or more copy operations. Each copy consists of a target variable, that is, the variable that you wish to assign a value to and a source (this can either be another variable or an XPath expression).

For our purposes, we want to assign the stock symbol passed into our BPEL process to our QuoteInput variable.

To do this, drag an Assign activity from the Component Palette on to your BPEL process at the point just before our Invoke activity. Then double-click on it to open up the Assign configuration window. Click on the green plus sign and select Copy Operation….

This will present us with the Create Copy Operation window, as shown in the following screenshot:

Assigning values to variables

On the left-hand side, we specify the From variable (that is, the source). Here we want to specify the stock symbol passed in as part of the input variable to the BPEL process. So expand the inputVariable tree, and select /ns2:getQuote/ns2:stockSymbol.

For the target, expand QuoteInput and select /ns1:GetSingleQuote/ns1:Symbol.

You will notice that for both the source and target, JDeveloper has created the equivalent XPath expression (circled in the preceding screenshot).

Note

The source and target can either be a simple type (for example, xsd:int, xsd:date, or xsd:string), as in the preceding example. Or a complex type (for example, ns2:getQuote), but make sure the source and target are either of the same type, or at least compatible.

Testing the process

At this stage, even though the process isn't complete, we can still save, deploy, and run our composite. Do this in the same way as previously covered in Chapter 2, Writing your First Composite. When you run the composite from the console you will notice that it doesn't return anything (as we haven't specified this yet). But if you look at the audit trail, you should successfully see the GetSingleQuote operation being invoked. Assuming this is the case, we know we have implemented that part of the process correctly.

Calling the exchange rate web service

The next step of the process is to determine the exchange rate between the requested currency and the US dollar (the currency used by the GetSingleQuote operation). For this, we are going to use the currency convertor service provided by webserviceX.NET .

For more information on this and other services provided by webserviceX.NET, go to www.webservicex.net.

This service provides a single operation ConversionRate, which gets the conversion rate from one currency to another. The WSDL file for this service can be found at the following URL:

http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

For convenience, we have included a local copy of the WSDL for webserviceX.NET's currency convertor service, called CurrencyConvertor.wsdl. It's included with the samples of Chapter 5.

To invoke the ConversionRate operation, we will follow the same basic steps that we did in the previous section to invoke the GetSingleQuote operation. For brevity, we won't repeat them here, but will allow the reader to do this.

Note

To follow the examples, name the input variable for the exchange rate web service ExchangeRateInput and the output variable ExchangeRateOutput.

Assigning constant values to variables

The operation ConversionRate takes two input values as follows:

  • FromCurrency: This should be set to 'USD'
  • ToCurrency: This should be set to the currency field contained within the inputVariable for the BPEL process.

To set the FromCurrency, create another copy operation. However, for the From value, select Expression as the Type (circled in the following screenshot).

This will replace the variable browser with a free format textbox. Here you can specify any value, within quotes, that you wish to assign to your target variable. For our purposes, enter 'USD', as shown in the following screenshot:

Assigning constant values to variables

To set the value of ToCurrency, create another copy operation and copy in the value of the currency field contained within the inputVariable.

At this stage again, save, deploy, and run the composite to validate that we are calling the exchange rate service correctly.

Using the expression builder

The final part of the process is to combine the exchange rate returned by one service with the stock price returned by the other, in order to determine the stock price in the requested currency and return that to the caller of the composite.

To do this, we will again use an <assign> activity. So drag another <assign> activity onto the process, just after our second invoke activity. Now in our previous use of the <assign> activity, we have just used it to copy a value from one variable to another.

Here, it is slightly different, in that we want to combine multiple values into a single value, and to do that, we will need to write the appropriate piece of XPath. Create a copy operation as before, but for the source type, select Expression from the drop-down list, as shown in the following screenshot:

Using the expression builder

Now, if you want, you can type in the XPath expression manually (into the Expression area), but it's far easier and less error prone to use the Expression Builder. To do this, click on the XPath expression builder icon; the calculator icon, which is circled in the preceding screenshot, will pop up the Expression Builder (shown below):

Using the expression builder

The Expression Builder provides a graphical tool for writing XPath expressions, which are executed as part of the copy operation. It consists of the following areas:

  • Expression: The top textbox contains the XPath expression that you are working on. You can either type data directly in here, or use the Expression Builder to insert XPath fragments to build up the XPath required.
  • BPEL variables: This part of the Expression Builder lets you browse the variables defined within your BPEL process. Once you've located the variable that you wish to use, click on the Insert Into Expression button, and this will insert the appropriate code fragment into the XPath expression.

    Note

    The code fragment is inserted at the point within the expression where the cursor is currently positioned.

  • Functions: This shows you all the different types of XPath functions that are available to build up your XPath expression. To make it easier to locate the required function, they are grouped into categories such as String Functions, Mathematical Functions, and so on.

    The drop-down list lets you select the category that you are interested in (for example, Mathematical Functions, as illustrated in the preceding screenshot), and then the window below that lists all the functions available to that group.

    To use a particular function, select the required function, and click Insert Into Expression. This will insert the appropriate XPath fragment into the XPath Expression (again at the point that the cursor is currently positioned).

  • Content Preview: This box displays a preview of the content that would be inserted into the XPath Expression if you clicked the Insert Into Expression button. For example, if you had currently selected a particular BPEL variable, it would show you the XPath to access that variable.
  • Description: If you've currently selected a function, this box provides a brief description of the function, as well as the expected usage and number of parameters.

So let's use this to build our XPath expression. The expression we want to build is a relatively simple one, namely, the stock price returned by the stock quote service multiplied by the exchange rate returned by the exchange rate service.

To build our XPath expression, carry out the following steps:

First, within the BPEL Variables area, in the variable QuoteOutput, locate the element ns1:GetSingleQuoteResult|ns1:Last, as shown in the following screenshot:

Using the expression builder

Then click Insert Into Expression to insert this into the XPath expression.

Next, within the Functions area, select the Mathematical Functions category, and select the multiply function (notice the description in the Description box, as shown in the following screenshot), and insert this into the XPath expression:

Using the expression builder

Finally, back in the BPEL Variables area, locate the element ConversionRateResult within the variable ExchangeRateOutput, and insert that into the XPath expression.

You should now have an XPath expression similar to the one illustrated below, once you are happy with it, click OK.

Using the expression builder

Finally make sure you specify the target part of the copy operation, which should be the amount element within the outputVariable.

In order to complete the <assign> activity, you will need to create two more copy operations to copy the Currency and StockSymbol specified in the inputVariable into the equivalent values in the outputVariable.

Once done, your BPEL process should be complete. So deploy and run the composite.

Asynchronous service

Following our StockQuote service, another service would be a stock order service, which would enable us to buy or sell a particular stock. For this service, a client would need to specify the stock, whether they wanted to buy or sell, the quantity, and the price.

It makes sense to make this an asynchronous service, as once the order has been placed, it may take seconds, minutes, hours, or even days for the order to be matched.

Now, I'm not aware of any trade services that are free to try (probably for a good reason!). However, there is no reason why we can't simulate one. To do this, we will write a simple asynchronous process.

Drag another BPEL process on to our StockService composite and give it the name StockOrder, but specify that it is an asynchronous BPEL process.

As with the StockQuote process, we also want to specify predefined elements for its input and output. The elements we are going to use are placeOrder for the input and placeOrderResponse for the output, the definitions for which are shown in the following code snippet:

<xsd:element name="placeOrder"         type="tPlaceOrder"/>
<xsd:element name="placeOrderResponse" type="tPlaceOrderResponse"/>

<xsd:complexType name="tPlaceOrder">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="bidPrice"    type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="tPlaceOrderResponse">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="actualPrice" type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

These are also defined in the StockService.xsd that we previously imported into the StockService composite. So, for each field, we click on the magnifying glass to bring up the type chooser and select the appropriate element definitions. Then click OK to create the process. This will create a second BPEL process within our composite, so double-click on this to open it.

You will see that, by default, JDeveloper has created a skeleton asynchronous BPEL process, which contains an initial <receive> activity to receive the stock order request. But this time it's followed by an <invoke> activity to send the result back (as opposed to a <reply> activity used by the synchronous process).

If you look at the WSDL for the process, you will see that it defines two operations: process to call the process, and processResponse, which will be called by the process to send back the result. Thus the client that calls the process operation will need to provide the processResponse callback in order to receive the result (this is something we will look at in more detail in Chapter 15, Message Interaction Patterns.

Now, for the purpose of our simulation, we will assume that the StockOrder request is successful and the actualPrice achieved is always the bid price. So to do this, create an assign operation that copies all the original input values to their corresponding output values. Deploy the composite, and run it from the console.

Note

When you click the Test Web Service button for the StockService composite, you will now be presented with two options: stockorder_client_ep and stockquote_client_ep. These correspond to each of the exposed services we have defined in our composite. Ensure you select stockorder_client_ep, which is wired to our StockOrder process.

This time, you will notice that no result is returned (as it's being processed asynchronously); rather it displays a message to indicate that the service was invoked successfully, as shown in the following screenshot:

Asynchronous service

Click on Launch Message Flow Trace to bring up the trace for the composite, and then select StockOrder to bring up the audit trail for the process. Switch to the flow view, and expand the callbackClient activity at the end of the trace. This will pop up a window showing the details of the response sent by our process, as shown in the following screenshot:

Asynchronous service

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Testing the process

At this stage, even though the process isn't complete, we can still save, deploy, and run our composite. Do this in the same way as previously covered in Chapter 2, Writing your First Composite. When you run the composite from the console you will notice that it doesn't return anything (as we haven't specified this yet). But if you look at the audit trail, you should successfully see the GetSingleQuote operation being invoked. Assuming this is the case, we know we have implemented that part of the process correctly.

Calling the exchange rate web service

The next step of the process is to determine the exchange rate between the requested currency and the US dollar (the currency used by the GetSingleQuote operation). For this, we are going to use the currency convertor service provided by webserviceX.NET .

For more information on this and other services provided by webserviceX.NET, go to www.webservicex.net.

This service provides a single operation ConversionRate, which gets the conversion rate from one currency to another. The WSDL file for this service can be found at the following URL:

http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

For convenience, we have included a local copy of the WSDL for webserviceX.NET's currency convertor service, called CurrencyConvertor.wsdl. It's included with the samples of Chapter 5.

To invoke the ConversionRate operation, we will follow the same basic steps that we did in the previous section to invoke the GetSingleQuote operation. For brevity, we won't repeat them here, but will allow the reader to do this.

Note

To follow the examples, name the input variable for the exchange rate web service ExchangeRateInput and the output variable ExchangeRateOutput.

Assigning constant values to variables

The operation ConversionRate takes two input values as follows:

  • FromCurrency: This should be set to 'USD'
  • ToCurrency: This should be set to the currency field contained within the inputVariable for the BPEL process.

To set the FromCurrency, create another copy operation. However, for the From value, select Expression as the Type (circled in the following screenshot).

This will replace the variable browser with a free format textbox. Here you can specify any value, within quotes, that you wish to assign to your target variable. For our purposes, enter 'USD', as shown in the following screenshot:

Assigning constant values to variables

To set the value of ToCurrency, create another copy operation and copy in the value of the currency field contained within the inputVariable.

At this stage again, save, deploy, and run the composite to validate that we are calling the exchange rate service correctly.

Using the expression builder

The final part of the process is to combine the exchange rate returned by one service with the stock price returned by the other, in order to determine the stock price in the requested currency and return that to the caller of the composite.

To do this, we will again use an <assign> activity. So drag another <assign> activity onto the process, just after our second invoke activity. Now in our previous use of the <assign> activity, we have just used it to copy a value from one variable to another.

Here, it is slightly different, in that we want to combine multiple values into a single value, and to do that, we will need to write the appropriate piece of XPath. Create a copy operation as before, but for the source type, select Expression from the drop-down list, as shown in the following screenshot:

Using the expression builder

Now, if you want, you can type in the XPath expression manually (into the Expression area), but it's far easier and less error prone to use the Expression Builder. To do this, click on the XPath expression builder icon; the calculator icon, which is circled in the preceding screenshot, will pop up the Expression Builder (shown below):

Using the expression builder

The Expression Builder provides a graphical tool for writing XPath expressions, which are executed as part of the copy operation. It consists of the following areas:

  • Expression: The top textbox contains the XPath expression that you are working on. You can either type data directly in here, or use the Expression Builder to insert XPath fragments to build up the XPath required.
  • BPEL variables: This part of the Expression Builder lets you browse the variables defined within your BPEL process. Once you've located the variable that you wish to use, click on the Insert Into Expression button, and this will insert the appropriate code fragment into the XPath expression.

    Note

    The code fragment is inserted at the point within the expression where the cursor is currently positioned.

  • Functions: This shows you all the different types of XPath functions that are available to build up your XPath expression. To make it easier to locate the required function, they are grouped into categories such as String Functions, Mathematical Functions, and so on.

    The drop-down list lets you select the category that you are interested in (for example, Mathematical Functions, as illustrated in the preceding screenshot), and then the window below that lists all the functions available to that group.

    To use a particular function, select the required function, and click Insert Into Expression. This will insert the appropriate XPath fragment into the XPath Expression (again at the point that the cursor is currently positioned).

  • Content Preview: This box displays a preview of the content that would be inserted into the XPath Expression if you clicked the Insert Into Expression button. For example, if you had currently selected a particular BPEL variable, it would show you the XPath to access that variable.
  • Description: If you've currently selected a function, this box provides a brief description of the function, as well as the expected usage and number of parameters.

So let's use this to build our XPath expression. The expression we want to build is a relatively simple one, namely, the stock price returned by the stock quote service multiplied by the exchange rate returned by the exchange rate service.

To build our XPath expression, carry out the following steps:

First, within the BPEL Variables area, in the variable QuoteOutput, locate the element ns1:GetSingleQuoteResult|ns1:Last, as shown in the following screenshot:

Using the expression builder

Then click Insert Into Expression to insert this into the XPath expression.

Next, within the Functions area, select the Mathematical Functions category, and select the multiply function (notice the description in the Description box, as shown in the following screenshot), and insert this into the XPath expression:

Using the expression builder

Finally, back in the BPEL Variables area, locate the element ConversionRateResult within the variable ExchangeRateOutput, and insert that into the XPath expression.

You should now have an XPath expression similar to the one illustrated below, once you are happy with it, click OK.

Using the expression builder

Finally make sure you specify the target part of the copy operation, which should be the amount element within the outputVariable.

In order to complete the <assign> activity, you will need to create two more copy operations to copy the Currency and StockSymbol specified in the inputVariable into the equivalent values in the outputVariable.

Once done, your BPEL process should be complete. So deploy and run the composite.

Asynchronous service

Following our StockQuote service, another service would be a stock order service, which would enable us to buy or sell a particular stock. For this service, a client would need to specify the stock, whether they wanted to buy or sell, the quantity, and the price.

It makes sense to make this an asynchronous service, as once the order has been placed, it may take seconds, minutes, hours, or even days for the order to be matched.

Now, I'm not aware of any trade services that are free to try (probably for a good reason!). However, there is no reason why we can't simulate one. To do this, we will write a simple asynchronous process.

Drag another BPEL process on to our StockService composite and give it the name StockOrder, but specify that it is an asynchronous BPEL process.

As with the StockQuote process, we also want to specify predefined elements for its input and output. The elements we are going to use are placeOrder for the input and placeOrderResponse for the output, the definitions for which are shown in the following code snippet:

<xsd:element name="placeOrder"         type="tPlaceOrder"/>
<xsd:element name="placeOrderResponse" type="tPlaceOrderResponse"/>

<xsd:complexType name="tPlaceOrder">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="bidPrice"    type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="tPlaceOrderResponse">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="actualPrice" type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

These are also defined in the StockService.xsd that we previously imported into the StockService composite. So, for each field, we click on the magnifying glass to bring up the type chooser and select the appropriate element definitions. Then click OK to create the process. This will create a second BPEL process within our composite, so double-click on this to open it.

You will see that, by default, JDeveloper has created a skeleton asynchronous BPEL process, which contains an initial <receive> activity to receive the stock order request. But this time it's followed by an <invoke> activity to send the result back (as opposed to a <reply> activity used by the synchronous process).

If you look at the WSDL for the process, you will see that it defines two operations: process to call the process, and processResponse, which will be called by the process to send back the result. Thus the client that calls the process operation will need to provide the processResponse callback in order to receive the result (this is something we will look at in more detail in Chapter 15, Message Interaction Patterns.

Now, for the purpose of our simulation, we will assume that the StockOrder request is successful and the actualPrice achieved is always the bid price. So to do this, create an assign operation that copies all the original input values to their corresponding output values. Deploy the composite, and run it from the console.

Note

When you click the Test Web Service button for the StockService composite, you will now be presented with two options: stockorder_client_ep and stockquote_client_ep. These correspond to each of the exposed services we have defined in our composite. Ensure you select stockorder_client_ep, which is wired to our StockOrder process.

This time, you will notice that no result is returned (as it's being processed asynchronously); rather it displays a message to indicate that the service was invoked successfully, as shown in the following screenshot:

Asynchronous service

Click on Launch Message Flow Trace to bring up the trace for the composite, and then select StockOrder to bring up the audit trail for the process. Switch to the flow view, and expand the callbackClient activity at the end of the trace. This will pop up a window showing the details of the response sent by our process, as shown in the following screenshot:

Asynchronous service

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Calling the exchange rate web service

The next step of the process is to determine the exchange rate between the requested currency and the US dollar (the currency used by the GetSingleQuote operation). For this, we are going to use the currency convertor service provided by webserviceX.NET .

For more information on this and other services provided by webserviceX.NET, go to www.webservicex.net.

This service provides a single operation ConversionRate, which gets the conversion rate from one currency to another. The WSDL file for this service can be found at the following URL:

http://www.webservicex.net/CurrencyConvertor.asmx?wsdl

For convenience, we have included a local copy of the WSDL for webserviceX.NET's currency convertor service, called CurrencyConvertor.wsdl. It's included with the samples of Chapter 5.

To invoke the ConversionRate operation, we will follow the same basic steps that we did in the previous section to invoke the GetSingleQuote operation. For brevity, we won't repeat them here, but will allow the reader to do this.

Note

To follow the examples, name the input variable for the exchange rate web service ExchangeRateInput and the output variable ExchangeRateOutput.

Assigning constant values to variables

The operation ConversionRate takes two input values as follows:

  • FromCurrency: This should be set to 'USD'
  • ToCurrency: This should be set to the currency field contained within the inputVariable for the BPEL process.

To set the FromCurrency, create another copy operation. However, for the From value, select Expression as the Type (circled in the following screenshot).

This will replace the variable browser with a free format textbox. Here you can specify any value, within quotes, that you wish to assign to your target variable. For our purposes, enter 'USD', as shown in the following screenshot:

Assigning constant values to variables

To set the value of ToCurrency, create another copy operation and copy in the value of the currency field contained within the inputVariable.

At this stage again, save, deploy, and run the composite to validate that we are calling the exchange rate service correctly.

Using the expression builder

The final part of the process is to combine the exchange rate returned by one service with the stock price returned by the other, in order to determine the stock price in the requested currency and return that to the caller of the composite.

To do this, we will again use an <assign> activity. So drag another <assign> activity onto the process, just after our second invoke activity. Now in our previous use of the <assign> activity, we have just used it to copy a value from one variable to another.

Here, it is slightly different, in that we want to combine multiple values into a single value, and to do that, we will need to write the appropriate piece of XPath. Create a copy operation as before, but for the source type, select Expression from the drop-down list, as shown in the following screenshot:

Using the expression builder

Now, if you want, you can type in the XPath expression manually (into the Expression area), but it's far easier and less error prone to use the Expression Builder. To do this, click on the XPath expression builder icon; the calculator icon, which is circled in the preceding screenshot, will pop up the Expression Builder (shown below):

Using the expression builder

The Expression Builder provides a graphical tool for writing XPath expressions, which are executed as part of the copy operation. It consists of the following areas:

  • Expression: The top textbox contains the XPath expression that you are working on. You can either type data directly in here, or use the Expression Builder to insert XPath fragments to build up the XPath required.
  • BPEL variables: This part of the Expression Builder lets you browse the variables defined within your BPEL process. Once you've located the variable that you wish to use, click on the Insert Into Expression button, and this will insert the appropriate code fragment into the XPath expression.

    Note

    The code fragment is inserted at the point within the expression where the cursor is currently positioned.

  • Functions: This shows you all the different types of XPath functions that are available to build up your XPath expression. To make it easier to locate the required function, they are grouped into categories such as String Functions, Mathematical Functions, and so on.

    The drop-down list lets you select the category that you are interested in (for example, Mathematical Functions, as illustrated in the preceding screenshot), and then the window below that lists all the functions available to that group.

    To use a particular function, select the required function, and click Insert Into Expression. This will insert the appropriate XPath fragment into the XPath Expression (again at the point that the cursor is currently positioned).

  • Content Preview: This box displays a preview of the content that would be inserted into the XPath Expression if you clicked the Insert Into Expression button. For example, if you had currently selected a particular BPEL variable, it would show you the XPath to access that variable.
  • Description: If you've currently selected a function, this box provides a brief description of the function, as well as the expected usage and number of parameters.

So let's use this to build our XPath expression. The expression we want to build is a relatively simple one, namely, the stock price returned by the stock quote service multiplied by the exchange rate returned by the exchange rate service.

To build our XPath expression, carry out the following steps:

First, within the BPEL Variables area, in the variable QuoteOutput, locate the element ns1:GetSingleQuoteResult|ns1:Last, as shown in the following screenshot:

Using the expression builder

Then click Insert Into Expression to insert this into the XPath expression.

Next, within the Functions area, select the Mathematical Functions category, and select the multiply function (notice the description in the Description box, as shown in the following screenshot), and insert this into the XPath expression:

Using the expression builder

Finally, back in the BPEL Variables area, locate the element ConversionRateResult within the variable ExchangeRateOutput, and insert that into the XPath expression.

You should now have an XPath expression similar to the one illustrated below, once you are happy with it, click OK.

Using the expression builder

Finally make sure you specify the target part of the copy operation, which should be the amount element within the outputVariable.

In order to complete the <assign> activity, you will need to create two more copy operations to copy the Currency and StockSymbol specified in the inputVariable into the equivalent values in the outputVariable.

Once done, your BPEL process should be complete. So deploy and run the composite.

Asynchronous service

Following our StockQuote service, another service would be a stock order service, which would enable us to buy or sell a particular stock. For this service, a client would need to specify the stock, whether they wanted to buy or sell, the quantity, and the price.

It makes sense to make this an asynchronous service, as once the order has been placed, it may take seconds, minutes, hours, or even days for the order to be matched.

Now, I'm not aware of any trade services that are free to try (probably for a good reason!). However, there is no reason why we can't simulate one. To do this, we will write a simple asynchronous process.

Drag another BPEL process on to our StockService composite and give it the name StockOrder, but specify that it is an asynchronous BPEL process.

As with the StockQuote process, we also want to specify predefined elements for its input and output. The elements we are going to use are placeOrder for the input and placeOrderResponse for the output, the definitions for which are shown in the following code snippet:

<xsd:element name="placeOrder"         type="tPlaceOrder"/>
<xsd:element name="placeOrderResponse" type="tPlaceOrderResponse"/>

<xsd:complexType name="tPlaceOrder">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="bidPrice"    type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="tPlaceOrderResponse">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="actualPrice" type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

These are also defined in the StockService.xsd that we previously imported into the StockService composite. So, for each field, we click on the magnifying glass to bring up the type chooser and select the appropriate element definitions. Then click OK to create the process. This will create a second BPEL process within our composite, so double-click on this to open it.

You will see that, by default, JDeveloper has created a skeleton asynchronous BPEL process, which contains an initial <receive> activity to receive the stock order request. But this time it's followed by an <invoke> activity to send the result back (as opposed to a <reply> activity used by the synchronous process).

If you look at the WSDL for the process, you will see that it defines two operations: process to call the process, and processResponse, which will be called by the process to send back the result. Thus the client that calls the process operation will need to provide the processResponse callback in order to receive the result (this is something we will look at in more detail in Chapter 15, Message Interaction Patterns.

Now, for the purpose of our simulation, we will assume that the StockOrder request is successful and the actualPrice achieved is always the bid price. So to do this, create an assign operation that copies all the original input values to their corresponding output values. Deploy the composite, and run it from the console.

Note

When you click the Test Web Service button for the StockService composite, you will now be presented with two options: stockorder_client_ep and stockquote_client_ep. These correspond to each of the exposed services we have defined in our composite. Ensure you select stockorder_client_ep, which is wired to our StockOrder process.

This time, you will notice that no result is returned (as it's being processed asynchronously); rather it displays a message to indicate that the service was invoked successfully, as shown in the following screenshot:

Asynchronous service

Click on Launch Message Flow Trace to bring up the trace for the composite, and then select StockOrder to bring up the audit trail for the process. Switch to the flow view, and expand the callbackClient activity at the end of the trace. This will pop up a window showing the details of the response sent by our process, as shown in the following screenshot:

Asynchronous service

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Assigning constant values to variables

The operation ConversionRate takes two input values as follows:

  • FromCurrency: This should be set to 'USD'
  • ToCurrency: This should be set to the currency field contained within the inputVariable for the BPEL process.

To set the FromCurrency, create another copy operation. However, for the From value, select Expression as the Type (circled in the following screenshot).

This will replace the variable browser with a free format textbox. Here you can specify any value, within quotes, that you wish to assign to your target variable. For our purposes, enter 'USD', as shown in the following screenshot:

Assigning constant values to variables

To set the value of ToCurrency, create another copy operation and copy in the value of the currency field contained within the inputVariable.

At this stage again, save, deploy, and run the composite to validate that we are calling the exchange rate service correctly.

Using the expression builder

The final part of the process is to combine the exchange rate returned by one service with the stock price returned by the other, in order to determine the stock price in the requested currency and return that to the caller of the composite.

To do this, we will again use an <assign> activity. So drag another <assign> activity onto the process, just after our second invoke activity. Now in our previous use of the <assign> activity, we have just used it to copy a value from one variable to another.

Here, it is slightly different, in that we want to combine multiple values into a single value, and to do that, we will need to write the appropriate piece of XPath. Create a copy operation as before, but for the source type, select Expression from the drop-down list, as shown in the following screenshot:

Using the expression builder

Now, if you want, you can type in the XPath expression manually (into the Expression area), but it's far easier and less error prone to use the Expression Builder. To do this, click on the XPath expression builder icon; the calculator icon, which is circled in the preceding screenshot, will pop up the Expression Builder (shown below):

Using the expression builder

The Expression Builder provides a graphical tool for writing XPath expressions, which are executed as part of the copy operation. It consists of the following areas:

  • Expression: The top textbox contains the XPath expression that you are working on. You can either type data directly in here, or use the Expression Builder to insert XPath fragments to build up the XPath required.
  • BPEL variables: This part of the Expression Builder lets you browse the variables defined within your BPEL process. Once you've located the variable that you wish to use, click on the Insert Into Expression button, and this will insert the appropriate code fragment into the XPath expression.

    Note

    The code fragment is inserted at the point within the expression where the cursor is currently positioned.

  • Functions: This shows you all the different types of XPath functions that are available to build up your XPath expression. To make it easier to locate the required function, they are grouped into categories such as String Functions, Mathematical Functions, and so on.

    The drop-down list lets you select the category that you are interested in (for example, Mathematical Functions, as illustrated in the preceding screenshot), and then the window below that lists all the functions available to that group.

    To use a particular function, select the required function, and click Insert Into Expression. This will insert the appropriate XPath fragment into the XPath Expression (again at the point that the cursor is currently positioned).

  • Content Preview: This box displays a preview of the content that would be inserted into the XPath Expression if you clicked the Insert Into Expression button. For example, if you had currently selected a particular BPEL variable, it would show you the XPath to access that variable.
  • Description: If you've currently selected a function, this box provides a brief description of the function, as well as the expected usage and number of parameters.

So let's use this to build our XPath expression. The expression we want to build is a relatively simple one, namely, the stock price returned by the stock quote service multiplied by the exchange rate returned by the exchange rate service.

To build our XPath expression, carry out the following steps:

First, within the BPEL Variables area, in the variable QuoteOutput, locate the element ns1:GetSingleQuoteResult|ns1:Last, as shown in the following screenshot:

Using the expression builder

Then click Insert Into Expression to insert this into the XPath expression.

Next, within the Functions area, select the Mathematical Functions category, and select the multiply function (notice the description in the Description box, as shown in the following screenshot), and insert this into the XPath expression:

Using the expression builder

Finally, back in the BPEL Variables area, locate the element ConversionRateResult within the variable ExchangeRateOutput, and insert that into the XPath expression.

You should now have an XPath expression similar to the one illustrated below, once you are happy with it, click OK.

Using the expression builder

Finally make sure you specify the target part of the copy operation, which should be the amount element within the outputVariable.

In order to complete the <assign> activity, you will need to create two more copy operations to copy the Currency and StockSymbol specified in the inputVariable into the equivalent values in the outputVariable.

Once done, your BPEL process should be complete. So deploy and run the composite.

Asynchronous service

Following our StockQuote service, another service would be a stock order service, which would enable us to buy or sell a particular stock. For this service, a client would need to specify the stock, whether they wanted to buy or sell, the quantity, and the price.

It makes sense to make this an asynchronous service, as once the order has been placed, it may take seconds, minutes, hours, or even days for the order to be matched.

Now, I'm not aware of any trade services that are free to try (probably for a good reason!). However, there is no reason why we can't simulate one. To do this, we will write a simple asynchronous process.

Drag another BPEL process on to our StockService composite and give it the name StockOrder, but specify that it is an asynchronous BPEL process.

As with the StockQuote process, we also want to specify predefined elements for its input and output. The elements we are going to use are placeOrder for the input and placeOrderResponse for the output, the definitions for which are shown in the following code snippet:

<xsd:element name="placeOrder"         type="tPlaceOrder"/>
<xsd:element name="placeOrderResponse" type="tPlaceOrderResponse"/>

<xsd:complexType name="tPlaceOrder">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="bidPrice"    type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="tPlaceOrderResponse">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="actualPrice" type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

These are also defined in the StockService.xsd that we previously imported into the StockService composite. So, for each field, we click on the magnifying glass to bring up the type chooser and select the appropriate element definitions. Then click OK to create the process. This will create a second BPEL process within our composite, so double-click on this to open it.

You will see that, by default, JDeveloper has created a skeleton asynchronous BPEL process, which contains an initial <receive> activity to receive the stock order request. But this time it's followed by an <invoke> activity to send the result back (as opposed to a <reply> activity used by the synchronous process).

If you look at the WSDL for the process, you will see that it defines two operations: process to call the process, and processResponse, which will be called by the process to send back the result. Thus the client that calls the process operation will need to provide the processResponse callback in order to receive the result (this is something we will look at in more detail in Chapter 15, Message Interaction Patterns.

Now, for the purpose of our simulation, we will assume that the StockOrder request is successful and the actualPrice achieved is always the bid price. So to do this, create an assign operation that copies all the original input values to their corresponding output values. Deploy the composite, and run it from the console.

Note

When you click the Test Web Service button for the StockService composite, you will now be presented with two options: stockorder_client_ep and stockquote_client_ep. These correspond to each of the exposed services we have defined in our composite. Ensure you select stockorder_client_ep, which is wired to our StockOrder process.

This time, you will notice that no result is returned (as it's being processed asynchronously); rather it displays a message to indicate that the service was invoked successfully, as shown in the following screenshot:

Asynchronous service

Click on Launch Message Flow Trace to bring up the trace for the composite, and then select StockOrder to bring up the audit trail for the process. Switch to the flow view, and expand the callbackClient activity at the end of the trace. This will pop up a window showing the details of the response sent by our process, as shown in the following screenshot:

Asynchronous service

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Using the expression builder

The final part of the process is to combine the exchange rate returned by one service with the stock price returned by the other, in order to determine the stock price in the requested currency and return that to the caller of the composite.

To do this, we will again use an <assign> activity. So drag another <assign> activity onto the process, just after our second invoke activity. Now in our previous use of the <assign> activity, we have just used it to copy a value from one variable to another.

Here, it is slightly different, in that we want to combine multiple values into a single value, and to do that, we will need to write the appropriate piece of XPath. Create a copy operation as before, but for the source type, select Expression from the drop-down list, as shown in the following screenshot:

Using the expression builder

Now, if you want, you can type in the XPath expression manually (into the Expression area), but it's far easier and less error prone to use the Expression Builder. To do this, click on the XPath expression builder icon; the calculator icon, which is circled in the preceding screenshot, will pop up the Expression Builder (shown below):

Using the expression builder

The Expression Builder provides a graphical tool for writing XPath expressions, which are executed as part of the copy operation. It consists of the following areas:

  • Expression: The top textbox contains the XPath expression that you are working on. You can either type data directly in here, or use the Expression Builder to insert XPath fragments to build up the XPath required.
  • BPEL variables: This part of the Expression Builder lets you browse the variables defined within your BPEL process. Once you've located the variable that you wish to use, click on the Insert Into Expression button, and this will insert the appropriate code fragment into the XPath expression.

    Note

    The code fragment is inserted at the point within the expression where the cursor is currently positioned.

  • Functions: This shows you all the different types of XPath functions that are available to build up your XPath expression. To make it easier to locate the required function, they are grouped into categories such as String Functions, Mathematical Functions, and so on.

    The drop-down list lets you select the category that you are interested in (for example, Mathematical Functions, as illustrated in the preceding screenshot), and then the window below that lists all the functions available to that group.

    To use a particular function, select the required function, and click Insert Into Expression. This will insert the appropriate XPath fragment into the XPath Expression (again at the point that the cursor is currently positioned).

  • Content Preview: This box displays a preview of the content that would be inserted into the XPath Expression if you clicked the Insert Into Expression button. For example, if you had currently selected a particular BPEL variable, it would show you the XPath to access that variable.
  • Description: If you've currently selected a function, this box provides a brief description of the function, as well as the expected usage and number of parameters.

So let's use this to build our XPath expression. The expression we want to build is a relatively simple one, namely, the stock price returned by the stock quote service multiplied by the exchange rate returned by the exchange rate service.

To build our XPath expression, carry out the following steps:

First, within the BPEL Variables area, in the variable QuoteOutput, locate the element ns1:GetSingleQuoteResult|ns1:Last, as shown in the following screenshot:

Using the expression builder

Then click Insert Into Expression to insert this into the XPath expression.

Next, within the Functions area, select the Mathematical Functions category, and select the multiply function (notice the description in the Description box, as shown in the following screenshot), and insert this into the XPath expression:

Using the expression builder

Finally, back in the BPEL Variables area, locate the element ConversionRateResult within the variable ExchangeRateOutput, and insert that into the XPath expression.

You should now have an XPath expression similar to the one illustrated below, once you are happy with it, click OK.

Using the expression builder

Finally make sure you specify the target part of the copy operation, which should be the amount element within the outputVariable.

In order to complete the <assign> activity, you will need to create two more copy operations to copy the Currency and StockSymbol specified in the inputVariable into the equivalent values in the outputVariable.

Once done, your BPEL process should be complete. So deploy and run the composite.

Asynchronous service

Following our StockQuote service, another service would be a stock order service, which would enable us to buy or sell a particular stock. For this service, a client would need to specify the stock, whether they wanted to buy or sell, the quantity, and the price.

It makes sense to make this an asynchronous service, as once the order has been placed, it may take seconds, minutes, hours, or even days for the order to be matched.

Now, I'm not aware of any trade services that are free to try (probably for a good reason!). However, there is no reason why we can't simulate one. To do this, we will write a simple asynchronous process.

Drag another BPEL process on to our StockService composite and give it the name StockOrder, but specify that it is an asynchronous BPEL process.

As with the StockQuote process, we also want to specify predefined elements for its input and output. The elements we are going to use are placeOrder for the input and placeOrderResponse for the output, the definitions for which are shown in the following code snippet:

<xsd:element name="placeOrder"         type="tPlaceOrder"/>
<xsd:element name="placeOrderResponse" type="tPlaceOrderResponse"/>

<xsd:complexType name="tPlaceOrder">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="bidPrice"    type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="tPlaceOrderResponse">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="actualPrice" type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

These are also defined in the StockService.xsd that we previously imported into the StockService composite. So, for each field, we click on the magnifying glass to bring up the type chooser and select the appropriate element definitions. Then click OK to create the process. This will create a second BPEL process within our composite, so double-click on this to open it.

You will see that, by default, JDeveloper has created a skeleton asynchronous BPEL process, which contains an initial <receive> activity to receive the stock order request. But this time it's followed by an <invoke> activity to send the result back (as opposed to a <reply> activity used by the synchronous process).

If you look at the WSDL for the process, you will see that it defines two operations: process to call the process, and processResponse, which will be called by the process to send back the result. Thus the client that calls the process operation will need to provide the processResponse callback in order to receive the result (this is something we will look at in more detail in Chapter 15, Message Interaction Patterns.

Now, for the purpose of our simulation, we will assume that the StockOrder request is successful and the actualPrice achieved is always the bid price. So to do this, create an assign operation that copies all the original input values to their corresponding output values. Deploy the composite, and run it from the console.

Note

When you click the Test Web Service button for the StockService composite, you will now be presented with two options: stockorder_client_ep and stockquote_client_ep. These correspond to each of the exposed services we have defined in our composite. Ensure you select stockorder_client_ep, which is wired to our StockOrder process.

This time, you will notice that no result is returned (as it's being processed asynchronously); rather it displays a message to indicate that the service was invoked successfully, as shown in the following screenshot:

Asynchronous service

Click on Launch Message Flow Trace to bring up the trace for the composite, and then select StockOrder to bring up the audit trail for the process. Switch to the flow view, and expand the callbackClient activity at the end of the trace. This will pop up a window showing the details of the response sent by our process, as shown in the following screenshot:

Asynchronous service

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Asynchronous service

Following our StockQuote service, another service would be a stock order service, which would enable us to buy or sell a particular stock. For this service, a client would need to specify the stock, whether they wanted to buy or sell, the quantity, and the price.

It makes sense to make this an asynchronous service, as once the order has been placed, it may take seconds, minutes, hours, or even days for the order to be matched.

Now, I'm not aware of any trade services that are free to try (probably for a good reason!). However, there is no reason why we can't simulate one. To do this, we will write a simple asynchronous process.

Drag another BPEL process on to our StockService composite and give it the name StockOrder, but specify that it is an asynchronous BPEL process.

As with the StockQuote process, we also want to specify predefined elements for its input and output. The elements we are going to use are placeOrder for the input and placeOrderResponse for the output, the definitions for which are shown in the following code snippet:

<xsd:element name="placeOrder"         type="tPlaceOrder"/>
<xsd:element name="placeOrderResponse" type="tPlaceOrderResponse"/>

<xsd:complexType name="tPlaceOrder">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="bidPrice"    type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="tPlaceOrderResponse">
  <xsd:sequence>
    <xsd:element name="currency"    type="xsd:string"/>
    <xsd:element name="stockSymbol" type="xsd:string"/>
    <xsd:element name="buySell"     type="xsd:string"/>
    <xsd:element name="quantity"    type="xsd:integer"/>
    <xsd:element name="actualPrice" type="xsd:decimal"/>
  </xsd:sequence>
</xsd:complexType>

These are also defined in the StockService.xsd that we previously imported into the StockService composite. So, for each field, we click on the magnifying glass to bring up the type chooser and select the appropriate element definitions. Then click OK to create the process. This will create a second BPEL process within our composite, so double-click on this to open it.

You will see that, by default, JDeveloper has created a skeleton asynchronous BPEL process, which contains an initial <receive> activity to receive the stock order request. But this time it's followed by an <invoke> activity to send the result back (as opposed to a <reply> activity used by the synchronous process).

If you look at the WSDL for the process, you will see that it defines two operations: process to call the process, and processResponse, which will be called by the process to send back the result. Thus the client that calls the process operation will need to provide the processResponse callback in order to receive the result (this is something we will look at in more detail in Chapter 15, Message Interaction Patterns.

Now, for the purpose of our simulation, we will assume that the StockOrder request is successful and the actualPrice achieved is always the bid price. So to do this, create an assign operation that copies all the original input values to their corresponding output values. Deploy the composite, and run it from the console.

Note

When you click the Test Web Service button for the StockService composite, you will now be presented with two options: stockorder_client_ep and stockquote_client_ep. These correspond to each of the exposed services we have defined in our composite. Ensure you select stockorder_client_ep, which is wired to our StockOrder process.

This time, you will notice that no result is returned (as it's being processed asynchronously); rather it displays a message to indicate that the service was invoked successfully, as shown in the following screenshot:

Asynchronous service

Click on Launch Message Flow Trace to bring up the trace for the composite, and then select StockOrder to bring up the audit trail for the process. Switch to the flow view, and expand the callbackClient activity at the end of the trace. This will pop up a window showing the details of the response sent by our process, as shown in the following screenshot:

Asynchronous service

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Using the wait activity

Now you've probably spotted the most obvious flaw with this simulation, in that the process returns a response almost immediately, which negates the whole point of making it asynchronous.

To make it more realistic, we will use the <wait> activity to wait for a period of time. To do this drag the <wait> activity from the Component Palette onto your BPEL process just before the <assign> activity, and then double-click on it to open the Wait activity window, as shown below.

The <wait> activity allows you to specify that the process wait for a specified duration of time or until a specified deadline. In either case, you specify a fixed value or choose to specify an XPath expression to evaluate the value at runtime.

If you specify Expression, and then click the calculator icon to the right of it, this will launch the Expression Builder that we introduced earlier in the chapter. The result of the expression must evaluate to a valid value of xsd:duration for periods and xsd:dateTime for deadlines. The format of xsd:duration is PnYnMnDTnHnMnS, for example. P1M would be a duration of 1 month and P10DT1H25M would be 10 days, 1 hour and 25 minutes.

For deadlines, the expression should evaluate to a valid value of xsd:date.

The structure of xsd:dateTime is YYYY-MM-DDThh:mm:ss+hh:mm, where the +hh:mm is optional and is the time period offset from UTC (or GMT, if you prefer). Obviously, the offset can be negative or positive.

For example, 2010-01-19T17:37:47-05:00 is the time 17:37:47 on January 19th 2010, 5 hours behind UTC (that is, Eastern Standard Time in the US).

Using the wait activity

For our purposes, we just need to wait for a relatively short period of time, so set it to wait for one minute.

Now save, deploy, and run the composite. If you now look at the audit trail of the process, you will see that it has paused on the <wait> activity (which will be highlighted in orange).

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Improving the stock trade service

We have a very trivial trade service, which always results in a successful trade after one minute. Let's see if we can make it a bit more "realistic".

We will modify the process to call the stockQuote service and compare the actual price against the requested price. If the quote we get back matches or is better than the price specified, then we will return a successful trade (at the quoted price). Otherwise we will wait a minute and loop back round and try again.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Creating the while loop

The bulk of this process will now be contained within a while loop, so from the Process Activities list of the Component Palette, drag a While activity into the process.

Click on the plus symbol to expand the While activity. It will now display an area where you can drop a sequence of one or more activities that will be executed every time the process iterates through the loop.

Creating the while loop

We want to iterate through the loop until the trade has been fulfilled, so let's create a variable of type xsd:Boolean called tradeFulfilled and use an <assign> statement before the while loop to set its value to false.

The first step is to create a variable of type xsd:Boolean. Until now, we've used JDeveloper to automatically create the variables we've required, typically as part of the process of defining an Invoke activity. However, that's not an option here.

If you look at the diagram of your BPEL process, you will see that it is surrounded by a light grey dashed box, and on the top left-hand side there are a number of icons. If you click on the top one of these (x), as shown in the following screenshot, this will open a window that lists all the variables defined in the process:

Creating the while loop

At this stage, it will list just the default inputVariable and outputVariable, which were automatically created with the process. Click on the green plus button. This will bring up the Create Variable window, as shown in the following screenshot:

Creating the while loop

Here we simply specify the Name of the variable (for example, tradeFulfilled) and its Type. In our case, we want an xsd:Boolean, so select Simple Type and click the magnifying glass to the right of it.

This will bring up the Type Chooser, which will list all the simple built-in data types defined by XML Schema. Select Boolean and click OK.

We need to initialize the variable to false, so drag an <assign> statement on to your process just before the while loop. Use the function false(), under the category Logical Functions, to achieve this.

Next, we need to set the condition on the while loop, so that it will execute only while tradeFulfilled equals false. Double-click on the while loop. This will open the While activity window, as shown in the following screenshot:

Creating the while loop

We must now specify an XPath expression, which will evaluate to either true or false. If you click on the expression builder icon, which is circled in the preceding screenshot, this will launch the Expression Builder. Use this to build the following expression:

bpws:getVariableData('tradeFullfilled') = false()

Once we are happy with this, click OK.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Checking the price

The first activity we need to perform within the while loop is to get a quote for the stock that we are trading. For this, we will need to invoke the stock quote process we created earlier. As both of these processes are in the same composite, the simplest way to do this is to wire them together.

Switch to the composite view in JDeveloper, next place your mouse over the yellow arrow on the StockOrder process (the one to add a new Reference). Click and hold your mouse button, then drag the arrow onto the blue arrow on the StockQuote process (the one that represents the Service Interface), then release, as shown in the following screenshot:

Checking the price

This will wire these two processes together and create a corresponding partner link in the StockOrder process. From here, implement the required steps to invoke the process operation of the StockQuote process, making sure that they are included within the while loop.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Using the switch activity

Remember our requirement is that we return success if the price matches or is better than the one specified in the order. Obviously, whether the price is better depends on whether we are selling or buying. If we are selling we need the price to be equal to or greater than the asking price; whereas if we are buying, we need the price to be equal to or less than the asking price.

So for this, we will introduce the <switch> activity. Drag a <switch> activity from the Process Activities list of the Component Palette on to your process after the invoke activity for the StockQuote service. Next, click on the plus symbol to expand the <switch> activity. By default, it will have two branches illustrated as follows:

The first branch contains a <case> condition, with a corresponding area where you can drop a sequence of one or more activities that will be executed if the condition evaluates to true.

The second branch contains an <otherwise> subactivity, with a corresponding area for activities. The activities in this branch will only be executed if all case conditions evaluate to false.

Using the switch activity

We want to cater to two separate tests (one for buying the other for selling), so click on the Add Switch Case arrow (highlighted in the preceding screenshot) to add another <case> branch.

Next, we need to define the test condition for each <case>. To do this, click on the corresponding Expression Builder icon to launch the expression builder (circled in the preceding screenshot). For the first one, use the expression builder to create the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Buy' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') >= 
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
	'/ns1:getQuoteResponse/ns1:Amount')

For the second branch, use the expression builder to define the following:

bpws:getVariableData (	'inputVariable','payload',
	'/ns1:PlaceOrder/ns1:BuySell') = 'Sell' and 
bpws:getVariableData (	'inputVariable', 'payload', 
	'/ns1:PlaceOrder/ns1:BidPrice') <=
bpws:getVariableData (	'stockQuoteOutput', 'payload', 
'/ns1:getQuoteResponse/ns1:Amount')

Once we've defined the condition for each case, we just need to create a single <assign> activity in each branch. This needs to set all the values in the outputVariable to the corresponding values in the inputVariable, except for the ActualPrice element, which we should set to the value returned by the StockQuote process. Finally, we also need to set tradeFullfilled to true, so that we exit the while loop.

The simplest way to do this is by dragging the original <assign> we created in the first version of this process onto the first branch and then modify it as appropriate. Then create a similar <assign> activity in the second branch.

Note

You've probably noticed that you could actually combine the two tests into a single test. However, we took this approach to illustrate how you can add multiple branches to a switch.

If we don't have a match, then we have to wait a minute and then circle back round the while loop and try again. As we've already defined a <wait> activity, simply drag this from its current position within the process into the activity area for the <otherwise> activity.

That completes the process, so try deploying it and running it from the console.

Note

The other obvious thing is that this process could potentially run forever if we don't get a stock quote in our favor. One way to solve this would be to put the while activity in a scope and then set a timeout period on the scope so that it would only run for so long.

Summary

In this chapter, we've gone beyond individual services and looked at how we can use BPEL to quickly assemble these services into composite services. By using this same approach, we can also implement end-to-end business processes or complete composite applications (something we will do in the second section of this book).

You may have also noticed that although BPEL provides a rich set of constructs for describing the assembly of a set of existing services, it doesn't try to reinvent the wheel where functionality is already provided by existing SOA standards. Rather, it has been designed to fit naturally with and leverage the existing XML and web services specifications such as XML Schema, XPath, XSLT, and of course, WSDL, and SOAP.

This chapter should have given you a solid introduction to the basic structure of a BPEL process, its key constructs, and the difference between a synchronous and asynchronous service. Building the examples will help to reinforce this as well as give you an excellent grasp of how to use JDeveloper to build BPEL processes.

Even though this chapter will have given you a good introduction to BPEL, we haven't yet looked at much of its advanced functionality such as its ability to handle long running processes, its fault and exception management, and how it uses compensation to undo events in the case of failures. These are areas we will cover in more detail in later chapters of the book.

You have been reading a chapter from
Oracle SOA Suite 11g R1 Developer's Guide
Published in: Jul 2010
Publisher: Packt
ISBN-13: 9781849680189
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime