Version 5.0 - 04/08
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

Introduction

Invoking a web service 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 BPEL process that receives and sends messages comprised of complex parts.

This sample reviews the WSDL definitions required to specify complex data and shows how these definitions are used in ActiveVOS to create BPEL variables. The process is then simulated in the Designer to verify its functionality. Finally, using the Web Tools Project plug-in included with ActiveVOS, we'll quickly create a Java client to test the deployed process.

Also discussed are aspects of the WSDL and BPEL definitions that provide WS-I Basic Profile 1.1 compliance. The Basic Profile is a set of guidelines used to improve interoperability between web services running on different platforms, in different environments. The WS-I BP 1.1 Specification may be found here.

The BPEL process receives a message containing one complex part that includes the data elements needed to query the in- or out-of-stock condition on a specific make, model, year, style and color automobile. The reply contains a single complex part with elements for request ID, number of matching vehicles on hand and a boolean in-/out-of-stock indicator.

Objectives

Getting Set Up

The files provided with this sample are contained in ComplexDataExchange.zip. You may extract this archive into a directory of your choosing. The archive contains numerous directories with an ActiveVOS Designer Project including various support files.

We will use ActiveVOS Designer to create, simulate and test the process. Run ActiveVOS Designer, select File / Import / General / Existing Projects into Workspace and navigate to the following project directory

[path to extracted archive]/ComplexDataExchange

This opens a project called ComplexDataExchange, which should appear in the Project Explorer view.

With the project successfully imported, ensure that the Orchestration Nature is applied (look for an "O" adornment on the project's icon in the Project Explorer). If it isn't, right-click on the project folder and select Add Orchestration Nature.

 

'O' on Project Folder

 

Switch to the Interfaces View and verify that the Partner Link Type and Port Type definitions are visible.

 

Interfaces View

 

This indicates that the Orchestration Nature has been successfully applied and that the WSDL file for the service was correctly parsed.

 

WSDL File

Web service definition typically begins with construction of a WSDL file. Among other things, this file can contain the data definitions for the messages the web service uses to communicate. Note that data definitions can also be specified in a schema (.xsd) document, and then imported into the WSDL. Because our data definitions are relatively simple, we define them in-line in the WSDL document.

The WSDL definition for our web service is found in our project as wsdl/ComplexDataExchange.wsdl. Open this file in ActiveVOS Designer to examine the contents. By default the file is displayed graphically - select the Source tab at the bottom of the editor view to see the XML source. The section of interest is the text that begins with <wsdl:types>.

Note that two XML <elements> are defined - BrandYearType and IdAmountInstock - each containing a complexType child element with the individual complex data elements. Note that there are other ways to specify the same data structure. WS-I BP 1.1 specifies communication using either rpc-literal or document-literal bindings. We have chosen to use document-literal - i.e., the run-time web service messages will be XML instance documents. As such, we follow the BP 1.1 recommendation and define our data as an <element>.

 


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

 

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

 

<message name="brandYearTypeMessage">
  <part name="brandYearType" element="cdetypes:BrandYearType"/>
</message>

<message name="idAmountInstockMessage">
  <part name="idAmountInstock" element="cdetypes:IdAmountInstock"/>
</message>

 

The cdetypes prefix is shorthand for the target namespace used in the <wsdl:types> / <schema> section of the WSDL definition.

The BPEL Process

To demonstrate the use of complex data exchange, we provide a BPEL process: ComplexDataExchange.bpel in the bpel subfolder found in the Project Explorer. Double click on this file to open it. This is a simple BPEL process that accepts a message containing one complex part based on the BrandYearType definition in our WSDL file. The process replies with a message containing one complex part – IdAmountInstock.

The two variables used by the interaction activities - receive and reply - were created automatically by dragging the Partner Link Types / complexToBpelPartnerLink / complexTest / complexTest operation from the Interfaces view onto the canvas and using that to create a Receive / Reply pair. This single action is all you need to construct these activities and the associated variables, as the messages, portTypes, etc., are already defined in the WSDL document. The required variables are created by ActiveVOS automatically.

The activities in the process operate as follows:

Receive_BrandYearTypeRequest – accepts the incoming message and places it into the BrandYearType variable.

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

HereIsWhereWeWouldCheckInventory is an Empty activity that acts as a placeholder. If this were a real, working process / web service, this is the point at which we'd probably build and post some query to a database or use a data query web service to actually check the in-stock status of the vehicle described in the initial request. For our purposes here, we simply reply with static data.

PopulateReplyMessage – 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. Be sure to examine this Assign activity closely to see the XPath syntax used when copying data from one complex variable to another.

SendInOutStock_Reply – returns the contents of the IdAmountInstock variable, which contains the result of the preceding copy operations.

Simulating the Process in ActiveBPEL Designer

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_BrandYearTypeReques activity.

As it turns out, creating sample data for process simulation is pretty easy. Double click on the BrandYearType variable in the Process Variables view to open it. Right click on the opened variable name and ensure that View Data is checked - select it if it isn't. Right-click on the opened variable name again and select Generate Sample. Accept the defaults and click Next. Navigate to the ComplexDataExchange/sample-data folder and enter a file name - no extension is needed, as .xml will be added automatically. Click Finish.

The Sample Data File

To view the generated sample data, navigate to the sample-data folder in the Project Explorer and open the file you created. You can edit the file, changing the instances of "string" to something more meaningful. Also change the "1" to the desired model year. Here's an example of the resulting file:


<?xml version="1.0" encoding="UTF-8"?>
<cdetypes:BrandYearType xmlns:cdetypes="http://schemas.active- ... ">
    <cdetypes:brand>Nissan</cdetypes:brand>
    <cdetypes:year>2009</cdetypes:year>
    <cdetypes:style>Maxima SE</cdetypes:style>
    <cdetypes:color>black</cdetypes:color>
    <cdetypes:transmissionType>CVT</cdetypes:transmissionType>
</cdetypes: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 prefix - cdetypes - is 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 definition 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 use the sample data file.

Simulating the Process

Return to ComplexDataExchange.bpel and, in the Process Variables View, right-click on either variable and select the Open All menu item. This displays the process variables and their parts. Ensure that the View Data menu item is checked for both (see above). Right-click on each and select the Expand All menu item. 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 over the initial receive activity, stopping on InitReplyMessageStructure, and note that the BrandYearType variable has been updated with the values just "received" in the sample data message (use Expand All again to view them, if needed).

Step over the Empty activity and note that the IdAmountInstock variable no longer shows "Not loaded". This is because the InitReplyMessageStructure 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 PopulateReplyMessage assign activity. This is the message that will be sent back by the SendInOutStock_Reply 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 shows the results of the simulation.


Process ComplexDataExchange: Instance 1 created.
Process ComplexDataExchange: Executing [/process]
Process Suspended [/process]
Sequence : Executing [/process/sequence]
Receive Receive_BrandYearTypeRequest: Executing [/process/sequence/receive[@name='Receive_BrandYearTypeRequest']]
Receive Receive_BrandYearTypeRequest: Completed normally [/process/sequence/receive[@name='Receive_BrandYearTypeRequest']]
Assign InitReplyMessageStructure: Executing [/process/sequence/assign[@name='InitReplyMessageStructure']]
Assign InitReplyMessageStructure: Completed normally [/process/sequence/assign[@name='InitReplyMessageStructure']]
Empty HereIsWhereWeWouldCheckInventory: Executing [/process/sequence/empty[@name='HereIsWhereWeWouldCheckInventory']]
Empty HereIsWhereWeWouldCheckInventory: Completed normally [/process/sequence/empty[@name='HereIsWhereWeWouldCheckInventory']]
Assign PopulateReplyMessage: Executing [/process/sequence/assign[@name='PopulateReplyMessage']]
Assign PopulateReplyMessage: Completed normally [/process/sequence/assign[@name='PopulateReplyMessage']]
Reply SendInOutStock_Reply: Executing [/process/sequence/reply[@name='SendInOutStock_Reply']]
Reply SendInOutStock_Reply: Completed normally [/process/sequence/reply[@name='SendInOutStock_Reply']]
Sequence : Completed normally [/process/sequence]
Process ComplexDataExchange: Completed normally [/process]

Deploying the Process

To deploy the BPEL process to a running server so that it can be accessed as a web service, follow the standard procedure using the Process Deployment Descriptor / PDD file provided (deploy/ComplexDataExchange.pdd) - or you can create your own - just be sure that the service name is 'ComplexDataExService' and the Binding is set to 'Document Literal' for My Role on the one and only partnerLink (complexToBpelPartnerLink).

 

Partner Link

My Role

 

See the ActiveVOS product documentation for additional details on creating the Process Deployment Descriptor and deploying your process.

Java Test Client Application

We've successfully simulated our BPEL process and the next step is to invoke it as a web service. Once deployed, our process needs to be called by a client. Here we discuss creating a Java client application to do just that.

Web Tools Project Plug-in

Included with ActiveVOS is a copy of the Web Tools Project (WTP). This is an Eclipse plug-in that adds facilities for creating and testing web services. We'll use this plug-in to create a Java application to invoke our service.

Creating the Java Client Application

With WTP we can create a functional web service client in about 5 minutes, provided that we have a valid WSDL file, which in this case we do.

To begin, we'll need an empty Java project into which our client application can be generated, so let's create that first. Select File / New / Project... from the main menu. The New Project wizard appears. Select Java Project and click Next. Enter a project name, e.g., ComplexDataExClient. Accept the defaults for this page and click Next. Optionally, at the bottom of the next page, you can change ComplexDataExClient/bin to ComplexDataExClient/classes. Click Finish to create the new project. If necessary, answer Yes to associate the project with the Java perspective.

Back in the ComplexDataExchange project (in Project Explorer), right-click on wsdl/ComplexDataExchange.wsdl and select Web Services / Generate Client. The Web Service Client wizard appears. To the right of the sequence 'cartoon' in the center of the dialog, click on Client Project:... under Configuration. In the Specify Client Project Settings dialog that appears, select your new project from the drop-down list at the top.

Client

 

Click OK. Next, slide the indicator to the left of the 'cartoon' from Deploy to Assemble. The resulting configuration should look like this:

Assemble

Click Next. If you want to generate class files with specific package names, check the Define custom mapping... checkbox and see the WTP documentation for details. If not, leave the box unchecked - the default settings will use the WSDL target namespace definitions to create Java package names. Click Finish. After about 5-10 seconds, your Java client source files should be generated.

Examine the contents of your new Java Project to find the generated source files. Open BrandYearType.java and note that the member variables correspond to the elements defined in the corresponding complex data element definition (see above):

 

private java.lang.String brand;

private java.math.BigInteger year;

private java.lang.String style;

private java.lang.String color;

private java.lang.String transmissionType;

 

Note that the xsd:integer value, year, is generated as a BigInteger value.

Once the web service client support files are generated, all we need to do is create a class that uses them to invoke our process. Right-click on either of the new packages generated by WTP and select New / Class. The New Java Class wizard appears. Enter a name for the new class, e.g., ComplexDataExClient and click Finish. To this class shell we'll need to add our functionality. This can be as simple or as complex as you like, but the key is to construct a new ComplexTestPTProxy object and, ultimately, call its complexTest() method with the appropriate message arguments. Calling this method corresponds to invoking the complexTest operation, which was exposed when we deployed our BPEL process as a web service.

For an example of a working client, see the ComplexDataExTestClient.java class in the ComplexDataExchange project's test folder.

To invoke the BPEL process, ensure that it has been successfully deployed and that the server is running. Right-click on your client class and select Run As / Java Application. If the process is successfully invoked you should see something like the following message printed at the end of the output console (depending on the message arguments you provided):

 

Result for 2009 Nissan Maxima SE: 42.0 in stock (true)

 

You can ignore any warning messages you may see regarding attachment support.

You can verify the process invocation by opening your ActiveVOS server Admin Console and examining the list of Active Processes. The process at the top should be an instance of ComplexDataExchange. Click on this instance to view the request message details, etc.