I was contacted last week to know if I had actually integrated an asynchronous web service in OpenESB, as promised in a previous post. The NetBeans SOA package is sometimes a bit obscure, though there are some explanation about the examples. I took a bit of time to dig this out, and here is then the promised follow-up (except that I won’t use WS-Addressing). I will use
- OpenESB bundled with Glassfish
- NetBeans to author the BPEL process
- SoapUI to test the process
What we want to get
The BPEL process that will be created is a synchronous BPEL process, which calls an asynchronous web service using a correlation set to “resume” the process when the asynchronous response is received. The scenario is not very realistic – a BPEL process that calls an asynchronous WS will itself be asynchronous most of the time. The asynchronous WS may indeed take arbitrary long to respond; the client of the BPEL process would probably time out in this case. This example suffices however to show the underlying principles.
- The BPEL process is synchronous
- But it calls an asynchronous WS service
- We use correlation-set for request/response matching
The BPEL process that we want to obtain at the end is shown below:
Create the PartnerLinks
One or two PartnerLinks?
Communication to and from the asynchronous web service can be realized using a single partner link with two ports or using two partner links with one port each.
From point of view of BPEL an asynchronous request/response is indeed no more than a pair of one-way messages. The request/response matching will anyway be done using correlation set.
As a consequence, the messages can come from “anywhere” and there is therefore not need to have one single partner link. I found it easier to have 2 partner links so that all ports on the left side are the one exposed by the process, and all ports on the right side are the one consumed by the process.
WSDL with one-way PartnerLink
PartnerLinks can be defined in the BPEL process or in the WSDL of the web service. NetBeans has a nice feature to create the PartnerLink in a WSDL therefore I chose to define them there.
A one-way web service is a web service which defines only <input>
or <output>
. I therefore took the WSDL of my previous post and simply removed the <output>
tags so that they become one-way web service. (I also removed anything related to WS-Addressing as it’s not used here).
The PartnerLink can then easily be created with NetBeans using the “Partner” view in the WSDL. The two WSDLs then looked like this:
Create the BPEL process
Add the PartnerLink
Now that the WSDL files of the asynchronous web services are ready, I create a new BPEL process. I then added the following PartnerLinks:
AsynchronousSampleClient
from the SOA sample bundled with NetBeansAsyncTestImplService
created previouslyAsyncTestResponseImplService
create previously
Wire the request/response
Then I wired the request/response as follows. I relied on NetBeans variable creation for each <invoke>
or <receive>
activity. I therefore got the following variables:
- ResponseIn
- SayHelloIn
- OperationAIn
- OperationAOut
Assign the variables
For the purpose of this example I assign the variable between the message like follows. Note that this example make no sense from a business point of view.
Define the correlation set
A receive activity within the process should be assigned a correlation set. The BPEL engine is otherwise unable to match the request/response and resume the right process instance.
I defined a correlation set “correlation” which would use the property “correlationProp”. A correlation property is a value that existing in different message and that can be used to match messages together. The property itself is a “symbolic” name for the value, and the corresponding element in each message is defined using so-called property aliases.
I then added two aliases, one in each WSDL file, and defined how “correlationProp” would map in the “sayHello” and “response” message respectively.
The process can then be built without warnings.
Deployment
The endpoint ports
The process defines 3 ports that can be changed according to your need. In this example the expected endpoints are:
- http://localhost:8888/AsyncTestImplService/AsyncTestImpl
- http://localhost:18182/AsynchronousSampleClient/response
- http://localhost:18182/AsynchronousSampleClient
The corresponding WSDL can be obtain by appending “?wsdl” in the URL.
Note that the address for the asynchronous callback is not passed as parameter from the BPEL process, but should be hard-coded in the web service implementation. It would however be very easy to pass the callback address as an extra parameter so that the asynchronous web service is entirely decoupled of the BPEL process.
Build
Rebuild the process to take the latest change in the port URL.
Create the composite application (CA)
The BPEL process cannot be deployed as-is. You will need to embed the BPEL process into a composite application, which is a deployable unit. This is very easy to do:
- Create a new project of type composite application.
- Drag and drop the BPEL project onto the Service Assembly
- Rebuild the composite application
All that is necessary will be created automatically during the build. After the build is complete, NetBeans will refresh the Service Assembly and it looks then like this:
Deploy
Go in the Glassfish console and deploy the service assembly produced in the previous step.
Import WSDL in SoapUI
Start SoapUI and import the 3 WSDL.
Mock the asynchronous web service
Now that the 3 WSDL have been imported, we will create a mock for the asynchronous web service. This way we can verify if the BPEL process call the asynchronous web service correctly and we can send the callback response manually.
Select the WSDL “AsyncTestImplPortBinding”, and right-click “Generate Mock Service”. Make sure to use
- path = /AsyncTestImplService/AsyncTestImpl?*
- port = 8888
So that it matches the port that the BPEL process will use.
Make sure to start the Mock, in which case SaopUI displays “running on port 8888” at the top-right of the Mock window. The project looks like this:
Test
1 – Invoke BPEL process
Send the following SOAP message to the BPEL process (located at http://localhost:18182/AsynchronousSampleClient):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:asy="http://enterprise.netbeans.org/bpel/AsynchronousSampleSchemaNamespace">
<soapenv:Header/>
<soapenv:Body>
<asy:typeA>
<paramA>dummy</paramA>
<id>123</id>
</asy:typeA>
</soapenv:Body>
</soapenv:Envelope>
2 – Receive the asynchronous invocation
When the Mock service the asynchronous message it displays something like “[sayHello] 4ms”. The message can be opened and should look like:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<sayHello xmlns:msgns="http://ewe.org/" xmlns="http://ewe.org/">
<arg0 xmlns="">123</arg0>
</sayHello>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
3 – Send the callback manually
We simulate manually the behavior of the mock service and send the following message to the callback endpoint (http://localhost:18182/AsynchronousSampleClient/response):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ewe="http://ewe.org/">
<soapenv:Header/>
<soapenv:Body>
<ewe:response>
<!--Optional:-->
<arg0>123</arg0>
</ewe:response>
</soapenv:Body>
</soapenv:Envelope>
4 – Get the synchronous reply
So far, the SOAP request of step #1 was still waiting to receive the synchronous response. After the callback has been sent, the BPEL engine should resume the right instance of the BPEL process (using the correlation value “123”), which should then terminate.
SoapUI will display the time taken for the request/response which will then be something like “response time: 5734 ms”. The time will of course depend on how long you took to perform step 2 and 3. (Note that after some time, the request will timeout if you really take too long to do these steps.)
The SOAP response message should look like:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<typeA
xmlns:msgns="http://enterprise.netbeans.org/bpel/AsynchronousSampleClient"
xmlns="http://enterprise.netbeans.org/bpel/AsynchronousSampleSchemaNamespace">
<id xmlns="">123</id>
</typeA>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Conclusion
This example as-is make little sense from a technical and business point of view; I wish I had also used more meaningul names for the various elements. It however shows the principle of asynchronous web service invocation using OpenESB. The adaption of this example for meaningful use cases should be relatively simple. It’s a matter of changing the message types and assignment rules.