Version 5.0 - 06/08
Asynchronous Exchange
<< 1 2 3 4 5 6 >>
Introduction
Synch vs. Asynch Operations
Getting Set Up
Use Case & Implementation
Build & Test the Requester
Build & Test the Initiator
Build & Test the Responder
Using the SOAP ReplyTo Header
Adding Message Correlation

Asynchronous Message Exchange, cont.

Build & Test the Responder

Construction of the Responder process is very similar to the steps used to create the Requester. The difference here is that the Interface definitions we create will be one-way / asynchronous as opposed to the two-way / synchronous operation exposed by the Requester.

Creating the Asynchronous Interface Definitions

As before, start off by defining a new Interface.

Switch back to the ActiveVOS Perspective by selecting Window / Open Perspective / Other / ActiveVOS.
In the Interfaces view, click on the New Interface button, located in its caption bar. The New Interface wizard appears.
Under Message Exchange Pattern, select One-way Operation and click Next.
On the next wizard page - Input From Schema - navigate in the top window to AsynchMessageExchange/schema/AMETypes.xsd and select it. Under Choose an Element:, leave the Document element selected and click Next.

On the Operation and Partner Link page of the wizard, make the following changes to the values displayed:

 

Service Port Type ResponderPT
  Operation getAsynchResponse
  Target Namespace http://docs.activevos.com/wsdl/AME/Responder
Process Partner Link Type ResponderPLT
  Role Name responder

 

Click Next to continue. On the last page of the wizard, enter or navigate to AsynchMessageExchange/wsdl, change the File Name entry to Responder.wsdl and click Finish. The Responder.wsdl file appears in a new editor.

Right-click anywhere in the editor area and select Format from the pop-up menu to rearrange the XML for better readability.

With the above steps, we've defined the Partner Link Type and Port Type for the getAsynchResponse operation that will be exposed by the Responder process. This covers the "request" portion of our message exchange. Asynchronous communication requires an interface definition to be defined for both the request and the response, however, so we need to repeat the above steps, with the following changes.

Start by creating another new interface defined as a One-way Operation that uses the Document element in AMETypes.xsd, just like the one above. On the Operation and Partner Link page of the wizard, make the following changes to the values displayed:

 

Service Port Type ResponderCallbackPT
  Operation invokeResponderCallback
  Target Namespace http://docs.activevos.com/wsdl/AME/Responder
Process Partner Link Type ResponderCallbackPLT
  Role Name responderCallback

 

Once complete, specify a file name of wsdl/ResponderCallback.wsdl.

At this point you've constructed the interfaces needed to modify our Requester process and build the Responder process which, once deployed, acts as a simple service that echoes back data sent to it, appended with identification information to show where the message has been.

Creating the Responder Process

With the necessary interface definitions now specified in Responder.wsdl and ResponderCallback.wsdl, we're now ready to create the asynchronous request-response exchange between our two BPEL processes. It's probably useful to open both of these files first and compare their contents with the new Partner Link Type and Port Type definitions that have been added to the Interfaces view.

The Responder will be very simple: just a Receive, Assign and Invoke activity. The Receive accepts the incoming (one-way) message from the Requester. The Assign activity will add some text to that incoming message to identify where it's been. And the Invoke activity will send the response. Note how this is different from the current configuration of our Requester process, which uses a Reply activity for the synchronous resopnse. This is the characteristic difference between asynchronous and synchronous message exchange implementations in BPEL.

Create a new BPEL file with the following parameters:

Location: AsynchMessageExchange/bpel

Filename: Responder.bpel

Process Name: Responder

Target Namespace: http://docs.activevos.com/bpel/AME/Responder

From the Interfaces view, drag the Partner Link Types/ResponderPLT/Responder/getAsynchResponse operation onto the empty canvas in the new process.
Use the Operation wizard to create a Receive activity, a new Partner Link named ResponderPL (no 'T') and a new Variable named requestValue.

From the Interfaces view, drag the

Partner Link Types/ResponderCallbackPLT/responderCallback/invokeResponderCallback operation onto the empty process canvas.

Use the Operation wizard to create an Invoke activity, a new Partner Link named ResponderCallbackPL (no 'T') and a new Variable named replyValue.
Add an Assign activity to the canvas and link the three activities in the following order: Receive - Assign - Invoke. Use the Auto Layout button in the toolbar to arrange the activities and save the process.
Add a Copy Operation to the Assign activity with the following From and To specs to perform the required initialization (see the ActiveVOS Designer documentation for details on constructing Copy Operations and initialization of complex variables, if needed):

 

From Type Literal
  Literal Contents <types1:Document xmlns:types1="http://docs.activevos.com/schema/AME/AMETypes">
<types1:value />
<types1:InstanceID />
</types1:Document>
To Type Variable
  Variable replyValue

In the Assign activity, add a Copy Operation with the following From and To specs:

 

From Type Expression
  Expression concat( $requestValue/types1:value , ' - Responder: Process ', abx:getProcessId() )
To Type Variable
  Variable replyValue
  Query types1:value

 

This Copy Operation appends the process ID to the incoming data and assigns the result to replyValue.

In the Assign activity, add a Copy Operation with the following From and To specs:

 

From Type Expression
  Type Variable
Variable requestValue
Query types1:InstanceID
To Type Variable
  Variable replyValue
  Query types1:InstanceID

 

This Copy Operation copies the process ID to the replyValue/InstanceID element.

Since the expression we just created is using the ActiveVOS extension function getProcessId() we need to add the ActiveVOS extension namespace to the process.  In the Outline View right click on the namespace node and select Add / Delcaration / Namspace.  Set the following values in the Properties View:

 

Property Value
Prefix: abx
URI: http://www.activebpel.org/bpel/extension

Save the process.

 

Modifying the Requester Process

Recall that, at the moment, our Requester process does nothing more than append to and echo back the incoming request data. We'll need to make some changes to get it to invoke the Responder process. Specifically, we need to add an Invoke activity to invoke the service and then provide an asynchronous callback, which is implemented using a Receive activity. We'll also add a new Empty activity as a placeholder and an Assign activity to carry through the "chain of evidence" data, which will be appended with another copy of the process instance ID to indicate the full, round-trip path taken by the message.

Open Requester.bpel and drag Partner Link Types/ResponderPLT/Responder/getAsynchResponse from the Interfaces view onto the process canvas.
Use the Operation wizard to create an Invoke activity and a new Partner Link named ResponderPL. Use the existing replyValue Variable.
Add an Empty activity to the canvas (e.g., drag from the Palette). Optionally rename this activity DoSomethingInterestingWhileWaiting.
Drag the Partner Link Types/ResponderCallbackPLT/responderCallback/invokeResponderCallback operation from the Interfaces view onto the canvas.
Use the Operation wizard to create a Receive activity and a new Partner Link named ResponderCallbackPL (no 'T'). Use the existing replyValue Variable.

Add a new Assign activity to the canvas, with the following Copy Operation:

 

From Type Expression
  Expression concat( $replyValue/types1:value, ' - Requester out: Process ', abx:getProcessId())
To Type Variable
  Variable replyValue
  Query types1:value

 

Link your four new activities in the following order: Invoke, Empty, Receive, Assign.
Remove the link between the original Assign and Reply activities, and create new links to insert the four new activities between them. The activities should be linked in the following order: Receive, Assign, Invoke, Empty, Receive, Assign, Reply. Save the process.

When you save the process, you should see a Warning icon next to the new Receive activity. If you trace this down to the Problems view, you'll see an indication that it may not work correctly. We'll find out what this means - and what to do about it - later on in this sample. For now, you can ignore it. If there are any other Warnings or Errors (Infos are okay), then you should retrace your steps to determine where the problem occurred.

Testing Your Changes

To test these changes, we need to deploy the Responder and re-deploy the Requester process after making some modifications to its deployment descriptor. Because the Requester is now invoking another service, we'll need to add the endpoint reference binding information required to do that.

Normally, when building a deployment descriptor for a process, you'll need some way to discover the endpoint reference binding details for any services that are invoked. These details are normally discovered by accessing the WSDL for the deployed service. In the case of a BPEL process deployed to the ActiveVOS Server, the form of such a WSDL would be:

http://[hostname]:8080/active-bpel/services/[ServiceName]?wsdl

If the embedded server is still running, you can access the following link in your browser to see the WSDL for the currently deployed version of the Requester (i.e., RequesterService):

http://127.0.0.1:8080/active-bpel/services/RequesterService?wsdl

Recall that when we originally tested our RequesterService, we generated the InitiatorClient source code by using this deployed version of the WSDL. Among many others, one of the things this code generation step did for us was to read the contents of this WSDL definition and discover the endpoint reference binding information, which was then hard-coded into the InitiatorClient support classes. You can find the service endpoint reference URL defined as RequesterServicePort_address in the RequesterServiceLocator.java source file. This is how the InitiatorClient Java program "knew" where to find our deployed Requester service.

With the changes we've just made, however, the services being invoked in these new versions of our processes are not yet deployed. The Responder hasn't been deployed at all, so the Requester won't know where to find the WSDL for it. And the currently deployed version of the Requester doesn't have the callback operation we just added, so the Responder won't be able to locate the WSDL for that either.

To resolve these two issues, we'll simply add information directly to the two process' deployment descriptors (PDDs), as follows..

Using the ActiveVOS perspective, right-click on Responder.bpel in the Project Explorer. Select New / Deployment Descriptor from the cascading pop-up menu.
Select the deploy folder in the project hierarchy, accept the default filename - Responder.pdd - and click Finish. The new PDD appears in the Process Deployment Descriptor editor.
Set Deployment Platform to ActiveVOS Professional and Enterprise.
Select the Partner Links tab at the bottom of the editor window and click on the ResponderPL Partner Link (second from the top).
Below the Partner Links listing, under My Role, change ResponderPLService to simply ResponderService.
Select the ResponderCallbackPL Partner Link at the top of the editor list.
Set the Invoke Handler value to address.

Modify the text in the Endpoint Reference window so that it matches the following:

 

<wsa:EndpointReference
  xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing"
  xmlns:s="http://docs.activevos.com/wsdl/AME/Requester">
  <wsa:Address>
    http://127.0.0.1:8080/active-bpel/services/ResponderCallbackService
  </wsa:Address>
  <wsa:ServiceName PortName="ResponderCallbackPT">
    s:ResponderCallbackService
  </wsa:ServiceName>
</wsa:EndpointReference>

 

Save the PDD.
Deploy the Responder process using the same steps we used earlier to deploy the Requester: right-click on the PDD, select Export..., etc. Be sure to select the deploy folder and change the .bpr and .bprd file names from "Requester" to "Responder" where appropriate.

What we've done here is to manually enter in the endpoint reference information for the callback service that will be available once we deploy the new-and-improved Requester process. This is the information the Responder is going to use at run-time to invoke that callback. By selecting the address Invoke Handler, we tell the server to use the endpoint reference <Address> we've defined here, as opposed to the default behavior, which is to get that information from the deployed WSDL.

For more information on the <EndpointReference> schema definition, see the WSA-Addressing specification.

Next we'll modify the PDD for the Requester and redeploy it.

Double-click on the Requester.pdd file to open it. Select the Partner Links tab and note that two new Partner Links have been added in response to the changes we made to the Requester process: ResponderCallbackPL and ResponderPL. ResponderPL is in an error state because the endpoint reference data for it hasn't been defined yet.
Select the ResponderCallbackPL Partner Link (second from the top) and in the My Role section below, remove the "PL" from the Service value, changing it to just: ResponderCallbackService.

Select the ResponderPL Partner Link, select an Invoke Handler value of address, and modify the text in the Endpoint Reference window so that it matches the following:

 

<wsa:EndpointReference xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing"
  xmlns:s="http://docs.activevos.com/wsdl/AME/Responder">
  <wsa:Address>
    http://127.0.0.1:8080/active-bpel/services/ResponderService
  </wsa:Address>
  <wsa:ServiceName PortName="ResponderPT">
    s:ResponderService
  </wsa:ServiceName>
</wsa:EndpointReference>

 

Again, we've manually entered the endpoint reference info, this time indicating where the Responder may be invoked.

Save the PDD and deploy it by right-clicking, selecting Export..., etc. Again, be sure to select the deploy folder and modify the filenames to change "Responder" to "Requester" where necessary.

With both of our processes successfully deployed, we can now re-test our composite application to verify operation of the Responder. Again, we'll use the InitiatorClient to do this.

Switch to the Java perspective and right-click on the IniatorClient.java file. Select Run As / Java Application from the cascading pop-up menu.

After a moment, the following message appears in the console (again, you can ignore warnings about attachment support, if present):

Success! Requester returned: 'Initiated AME from thread 'main' - Requester #3 - Responder: Process 4 - Requester out: Process 3'

The message displayed reflects the journey of the data, in this case from the InitiatorClient's main() method, to an instance (process #3) of the Requester process, to an instance (process #4) of the Responder process, back to the Requester process (process #3) and then to the InitiatorClient, which displays the message in the console.

Summary, So Far

At this point we've succesfully tested asynchronous communication between two web servcies - in this case, implemented as BPEL processes.

However, there's one important aspect to note about the design of our composite application as it currently stands. The Responder sends its response with an Invoke activity that uses the endpoint reference specified in the Requester's deployed WSDL definition. As a result, the response is hard-coded to be sent only to a single endpoint. We were able to do this because - at design / deployment time - we knew where the Requester could be reached to send the response.

In real-world applications this is only marginally useful, since the designer of a service like the Responder won't always necessarily know - at design or deployment time - what the service client's endpoint reference will be. Furthermore, we may not want to limit the use of this service to only a single client (i.e., at a specific endpoint).

There are a couple of ways to address this problem. We address one of these in the next section.