Version 4.1 -  Sept. 2007
Exchanging Messages Containing Complex Data Types
Introduction
Getting Set Up
WSDL File
The BPEL Process
Simulating the Process
Java Test Client

Exchanging Messages Containing Complex Data Types

Introduction

Testing a BPEL process that receives or replies with messages containing complex parts can be confusing. There are a lot of pieces to get right and more than one correct way to get the job done. This sample provides a detailed walkthrough for testing a relatively simple process that uses complex data parts. We'll cover both simulation (in ActiveBPEL® Designer) and test of a deployed process running in the ActiveBPEL® engine using a Java application as a client / test driver. While the files included with this sample are designed for use with the Eclipse IDE and ActiveBPEL Designer, much of the information is also generally applicable to testing BPEL processes in other development and deployment environments.

Our simple process receives a message containing two parts: a string part and a complex part. The complex part has elements to determine an in- or out-of-stock condition on a specific make, model, year, style and color automobile. The response message contains a single complex part with elements containing a request ID, the number of matching vehicles on hand and a boolean in-/out-of-stock indicator.

For simulation test purposes, we'll create an XML sample data file based on the WSDL that defines the Web Services provided by the process. You may skip this portion if you're not using ActiveBPEL Designer to simulate your BPEL Process.

For live test purposes – and as an example of a simple client application – we'll implement a Java client application to exercise the deployed process once we've successfully simulated it in the Designer.

Objectives

Getting Set Up

The files provided with this sample are contained in complex_exchange.zip. You may extract this archive into a directory of your choosing. The archive contains numerous directories with an Eclipse Java Project, an ActiveBPEL Designer BPEL Project and various support and deployment files.

If you plan to use ActiveBPEL Designer to create, simulate or test your process, run ActiveBPEL Designer, select File / Import / General / Existing Projects into Workspace and navigate to the following ActiveBPEL Designer project directory

/complex_exchange

This opens an ActiveBPEL Designer project called complex_exchange, which should appear in the Navigator View.

With the project successfully imported, switch to the Web References View and select the Add a Web Reference icon. Select the Browse Projects... button and navigate to the wsdl directory under complex_exchange. Add the complex_exchange.wsdl file that you see there. It then appears in the Web References View.

If you're using Eclipse for your client application development, run Eclipse, select File / Import / General / Existing Projects into Workspace and navigate to the following Eclipse project directory

/complex_exchange

This will open a Java project called complex_exchange, with various supporting directories. The project is self-sufficient and contains the necessary source files needed to build your test client application.

One manual step you may need to perform is to create an AESAMPLES_LIB variable for the project's Java Build Path (i.e., you may see "Unbound classpath variable"; errors for the project). See the Sample on Java Library Dependencies for more information as it applies to your platform.

If you're not using Eclipse, you can still use the Java client in this sample. There is a build.xml Ant script in the project directory root that contains build targets for compiling the source and running the client application - all described in detail below. Here's the archive's directory structure:

complex_exchange     < build.xml
├─── doc
├─── src
│    └─── org
│         └─── activebpel
│              └─── samples
│                   └─── complex_exchange  \
│                        ├─── client        } < Source Files for
│                        └─── type         /     Java test client
└─── support
     └─── bpel_process
          ├─── bpel    < BPEL source complex_exchange.bpel
          └─── wsdl    < Web Service definition complex_exchange.wsdl

WSDL File

As is typical when designing BPEL processes that implement Web Services, our work here begins by examining the WSDL file for the process we wish to create: complex_exchange.wsdl. We won't cover every detail of the file here – only the portions we'll need later when designing our test data file and Java test client application.

wsdl:definitions

Make a note of the targetNamespace attribute here:

http://docs.active-endpoints.com/activebpel/sample/wsdl/complex_exchange/2006/09/complex_exchange.wsdl

wsdl:types

This element is probably the one of most interest here, as it defines the structure of the complex data parts we're going to be using in our messages into and out of the process, as well as the structure of the sample data we'll create for simulation.


<complexType name="Type">
  <sequence>
    <element name="style" type="xsd:string"/>
    <element name="color" type="xsd:string"/>
    <element name="transmissionType" type="xsd:string"/>
  </sequence>
</complexType>
<complexType name="BrandYearType">
  <sequence>
    <element name="brand" type="xsd:string"/>
    <element name="year" type="xsd:integer"/>
    <element name="type" type="tns:Type"/>
  </sequence>
</complexType>
<complexType name="IdAmountInstock">
  <sequence>
    <element name="id" type="xsd:string"/>
    <element name="amount" type="xsd:float"/>
    <element name="instock" type="xsd:boolean"/>
  </sequence>
</complexType>

The new complex types we're defining here are highlighted above in blue italics. BrandYearType is the message part type we'll be sending to the process as a request. Note that its third element is the complex type called Type, which creates a hierarchy of complex parts. The IdAmountInstock type will be used to define the message part in the response we'll get from the process.

wsdl:message

These two elements define the messages we'll be using for input to and output from our process.

<message name="brandYearTypeMessage">
  <part name="simpleString" type="xsd:string"/>
  <part name="brandYearType" type="tns:BrandYearType"/>
</message>

<message name="idAmountInstockMessage">
  <part name="idAmountInstock" type="tns:IdAmountInstock"/>
</message>

Note the references to our new complex types in these message definitions. Also note, if you're entering type names, etc., by hand, the slight difference in case between idAmountInstock and IdAmountInstock.

wsdl:portType and wsdl:operation

These elements define the programming interface to our process, that is, the portType and operation our client application calls.


<wsdl:portType name="complexTestPT">
  <wsdl:operation name="complexTest">
    <wsdl:input message="tns:brandYearTypeMessage"/>
    <wsdl:output message="tns:idAmountInstockMessage"/>
  </wsdl:operation>
</wsdl:portType>

Note that our input message (i.e., the message sent to the BPEL Process) is defined as brandYearTypeMessage and the output message is defined as idAmountInstockMessage.

The BPEL Process

To demonstrate the use of complex data exchange, we provide a BPEL process. If you've imported the ActiveBPEL Designer project as described earlier, you can locate complex_exchange.bpel in the bpel subfolder found in the Navigator View. Double click on this file to open it in the Designer. This is a simple BPEL process that accepts a message containing two parts – a simple xsd:string and our new, complex BrandYearType – and returns a message containing one complex part – IdAmountInstock. The activities in the process operate as follows:

Receive_BrandYearTypeMessage – accepts the incoming message and places it into the brandYearTypeMessage variable.

Init_idAmountInstockMessage – initializes the idAmountInstockMessage variable. Remember that all variables containing complex parts must be initialized before they can be used.

Populate_idAmountInStockMessage – copies some data from the incoming message to create a request ID and fills in the other elements in preparation for returning a response to the client.

Send_inStockReply – returns idAmountInstockMessage with the result of the preceding copy operations.

Note that in a more real-world implementation of this process, an invoke activity would likely be added after the initial receive. This invoke activity would query another service to determine the actual in-stock status corresponding to the vehicle described in the incoming message.

Simulating the Process in ActiveBPEL Designer

If you're not using ActiveBPEL Designer for BPEL process development, you can skip to the next section.

Simulation requires that we somehow provide sample data to our process, when needed, to mimic the incoming messages that will normally be sent to the process once it's deployed. In the case of our process, we'll need to define sample data for the message received by the Receive_BrandYearTypeMessage activity. This message has two parts – a simple xsd:string and a complex part of our own design.

Sample data for the string part can be defined easily enough – simply open up the Web References View in ActiveBPEL Designer and expand the complex_exchange.wsdl Web Reference to view the brandYearType and simpleString parts for brandYearTypeMessage. Right-click on simpleString and select the Add Sample menu item. Enter any string you like into the dialog that appears, and click OK. This string will be part of the request "ID" that is created and returned by the process.

Because it is a complex part, creating and applying sample data for brandYearType is a bit more, well, complex.

The Sample Data File

Sample data for for brandYearType is provided in an XML file named BrandYearTypeRequest.xml, which is located in the project root folder, and its contents is shown below.


<?xml version="1.0" encoding="ISO-8859-1"?>
<brandYearType xmlns:tns="http://docs.active-endpoints.com/
   activebpel/sample/wsdl/complex_exchange/2006/09/complex_exchange.wsdl"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:type="tns:BrandYearType">
  <brand>Honda</brand>
  <year>2007</year>
  <type>
    <style>Hatchback</style>
    <color>Corsair Blue</color>
    <transmissionType>5-Speed</transmissionType>
  </type>
</brandYearType>

Note that the root element of the message brandYearType matches the name of the complex part for which we're providing sample data. Its type, of course, is the one we defined in our WSDL: BrandYearType. The namespace references are added in-line to resolve the name and type we've specified.

Inside the root element, the child elements follow our WSDL's complex data definitions exactly, and values are assigned to each. You may change these values to anything you like as long as the XML structure is preserved. Note that the year element is defined in our WSDL as xsd:integer, and so the value there should resolve to a numeric integer value or an XML parsing error occurs when you attempt to add the sample data file.

Once you've located and/or edited this file, right-click on the brandYearType message part in Web References and select the Add Sample menu item. In the dialog that appears, select Project and click OK, then navigate to and select BrandYearTypeRequest.xml, then click OK again. This opens and parses the XML file to add the data for simulation. Click the Refresh icon (in the Web References View caption bar) to make your newly added sample data available to the process.

Simulating the Process

Open complex_exchange.bpel in ActiveBPEL Designer if you haven't done so already. Open the Process Variables View, right-click on either variable and select the Open All menu item. This displays the process variables and their parts. Right-click in the brandYearTypeMessage's variable window and ensure that the View Data menu item is checked. Right-click there again and select the Expand All menu item. Note that the values shown match those in the sample data XML file. We're now ready to simulate.

Click anywhere in the blank area of the process canvas to select the process and select the Run / Simulate Process menu item. Note that the two variables in the Process Variables View change to "Not loaded". Step past the initial receive activity, stopping on Init_idAmountInstockMessage, and note that brandYearTypeMessage has been updated with the values just "received" in the sample data message (use Expand All again to view them, if needed).

Step again and note that the idAmountInstockMessage variable no longer shows "Not loaded". This is because the Init_idAmountInstockMessage assign activity has just initialized the data structure with empty values. Step once more and note that the values are filled in by the copy operations in the Populate_idAmountInStockMessage assign activity. This is the message that will be sent back by the Send_inStockReply activity. We'll be able to verify this later when we run our test client.

Select Run / Resume (or press the F8 key) to finish the simulation. Your Console View should show the results of the simulation.


Process complex_exchange: Instance 1 created.
Process complex_exchange: Executing [/process]
Sequence : Executing [/process/sequence]
Receive Receive_BrandYearTypeMessage: Executing
[/process/sequence/receive[@name='Receive_BrandYearTypeMessage']]
Receive Receive_BrandYearTypeMessage: Completed normally
[/process/sequence/receive[@name='Receive_BrandYearTypeMessage']]
Assign Init_idAmountInstockMessage: Executing
[/process/sequence/assign[@name='Init_idAmountInstockMessage']]
Assign Init_idAmountInstockMessage: Completed normally
[/process/sequence/assign[@name='Init_idAmountInstockMessage']]
Assign Populate_idAmountInStockMessage: Executing
[/process/sequence/assign[@name='Populate_idAmountInStockMessage']]
Assign Populate_idAmountInStockMessage: Completed normally
[/process/sequence/assign[@name='Populate_idAmountInStockMessage']]
Reply Send_inStockReply: Executing
[/process/sequence/reply[@name='Send_inStockReply']]
Reply Send_inStockReply: Completed normally
[/process/sequence/reply[@name='Send_inStockReply']]
Sequence : Completed normally [/process/sequence]
Process complex_exchange: Completed normally [/process]

Deploying the Process

To deploy the BPEL process, you need to follow the normal ActiveBpel process deployment procedure using the enclosed PDD file. If you want to re-generate the PDD file, please make sure you specify "RPC Encoded" as the binding style for the myRole of the partner link "complexToBpelPartnerLink". If necessary, see the ActiveBPEL Designer Tutorial for an example of how process deployment is done.

NOTE: if you have deployed BPEL Process for the custom_functions sample, un-deploy that process before attempting to deploy this one, as they may conflict.

Java Test Client Application

We've successfully simulated our process and the next step is to run it using the ActiveBPEL Engine. Once deployed, our process needs to be called by a client. Here we discuss a Java client application to do just that.

Required jars

To implement a Java client that interacts with a Web Service / BPEL Process, we'll need resources that are defined in a number of Java library archives. These dependencies are discussed here.

Java Client Application Sample Source Code

If you've imported the Eclipse project as described earlier, open that project now. Navigate to and open TestClient.java. Alternately, you can open this source file in any text editor. This source file contains the main() for our test client application. It also has two other important methods of interest. Before examining these, you may want to peruse Type.java, TypeUtil.java, IdAmountInstock.java and BrandYearType.java to see how they support the type and message definitions in our WSDL. The correlations should be self-explanatory.

In TestClient.java, we have createCall(), which builds the Call object used to invoke our process as a Web Service. In addition to setting the endpoint, operation, parameters, etc., this method also registers the serialization information needed to send and receive the complex data structures defined in our WSDL and implemented in our java client. Note the calls to the register(...) method, which is defined at the end of the file. This serializer registration is a non-intuitive aspect of our client application implementation, so we point it out here.

The callService() method is responsible for invoking the BPEL process with the Call object constructed by createCall(). Note that the invocation passes an Object[], initialized to "testing" and byt. These two array elements correspond to the two parts defined in our WSDL for the brandYearTypeMessage message, i.e., the simple xsd:string and the complex BrandYearType type.

The invoke() call returns the data structure corresponding to the single complex part (which is of the WSDL message part type IdAmountInstock) in the idAmountInstockMessage message. When the response message arrives, the previously registered serializer converts this to an instance of class IdAmountInstock, whose toString() method is called here to provide the output from our test client. Note that this method accesses the individual complex part's elements as Java types.

To invoke the BPEL Process using this client application, deploy the complex_exchange.bpel process to a running ActiveBPEL Engine (see above).  Then compile and run TestClient.java. When complete, you should see the following output.


IdAmountInstock[id=testing:Honda:2004;amount=42.0;inStock=true]

Most useful would probably be to run TestClient.java in your debugger and step through to see how the messages are serialized, sent, returned, deserialized and accessed.