This article discusses how to implement an asynchronous web service in Java EE. The Java application will expose a one way operation that will process the request and send a response message to a callback Web Service interface that is indicated in the request header through WS Addressing properties (messageID, replyToAddress). The Asynchronous Web Service is subsequently deployed and invoked from SoapUI.
The article starts with nothing but a simple WSDL file that defines the two portTypes: one way call and the [one way] call back:
The main steps are:
- Generate the JAX-WS Client & Proxy for the ThoughtfulGreeterCallback portType (to invoke the callback service in order to send the response)
- Generate the JAX-WS Web Service for the ThoughtfulGreeter portType (to implement the one way web service)
- Edit the generated code for the ThoughtfulGreeter portType in order to create the response and invoke the callback interface – used on WS-Addressing details in the request
When the implementation is thus complete, we create a new project in SoapUI. In this project, we will create a test request to invoke the ThoughtfulGreeter service. We will also create a MockService in SoapUI to act as the callback interface ThoughfulGreeterCallback. In the request from SoapUI to the ThoughtfulGreeter service, we will specify WS-Addressing properties that refer to the MockService.
Finally, when we have SoapUI make the call to the ThoughtfulGreeter service, we will receive a call (back) to the MockService, containing the response.
Note: this article is a cross post from the Oracle SOA Suite Handbook blog.
Generate the JAX-WS Client & Proxy for the ThoughtfulGreeterCallback portType
(to invoke the callback service in order to send the response)
Create a new Java EE Web Application through the New Gallery wizard in JDeveloper:
Set the name of the application – for example to AsynchronousJavaWebService – and the package prefix – for example saibot.airport.services.pr. Press Next.
On page 5, set the name of the View project to WebServices.
Press Finish.
From the New Gallery, select item Web Service Client and Proxy – to generate the objects to invoke a Web Service from Java:
Select the WSDL for the ThoughtfulGreeterService:
The WSDL contains two port types but no service element (it is abstract). A warning will be presented by JDeveloper – about generating a default service element. Press Yes to accept this action.
Accept all defaults. On step 4, JDeveloper indicates it will generate proxies for two port types (or ports) in the web service definition:
Do not generate any asynchronous methods:
The last step presents an overview of what the wizard is about to generate. Press finish.
The proxy we have just created is intended only to invoke the Callback service to return the response to (asynchronously). The classes ThoughtfulGreeterPortClient and ThoughtfulGreeter are not required to the call back – and can be removed from the project.
The usages are presented. Proceed with the removal.
Generate the JAX-WS Web Service for the ThoughtfulGreeter portType
(to implement the one way web service)
Note: To prevent us from having to remove unwanted stuff later on, I have commented out the callback binding and portType in the WSDL document before running the Java Web Service wizard.
Press Finish to have the Java Web Service generated.
The generated objects are added to the project:
Make a small change to the class ThoughtfulGreeterImpl – to see that the one way service has been invoked:
System.out.println("Request received; it contains name= "+payload.getName());
Run the Web Service (which will build and deploy the Web Application to the Integrated WebLogic Server):
When the deployment is complete, the Web Service is available to be invoked:
Click on the URL shown. This will bring up the HTTP Analyzer tool in JDeveloper. This tool will inspect the WSDL document for the web service and present an interface based on the service interface. Enter a value for name and press Send Request:
In the console we can see that the Web Service has been invoked
Edit the generated Java code for the ThoughtfulGreeter portType
in order to create the response and invoke the callback interface – used on WS-Addressing details in the request.Open class ThoughtfulGreeterImpl.
Add @Resource for WebServiceContext.to ThoughtfulGreeterImpl Class
public class ThoughtfulGreeterImpl { @Resource WebServiceContext context; public ThoughtfulGreeterImpl() { }
Add method callbackToHelloFromWorld to ThoughtfulGreeterImpl Class. This method uses the ThoughtfulGreeterCallback Port on the ThoughtfulGreeterService to invoke the callback service. The message context, retrieved from the WebServiceContext, contains the endpoint address at which the invoker of the one way helloToWorld operation suggest the callback interface is exposed. It also contains the messageId that is to be sent in the callback call to allow the consumer of the asynchronous service to complete the correlation of the response with the original request.
private void callbackToHelloFromWorld(GreetingResponseType greetingResponse) { // invoke the generated WebService Proxy to pass back the greeting response HeaderList hl = (HeaderList) context.getMessageContext().get(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY); // gets the addressing informations in the SOAP header WSEndpointReference reference = hl.getReplyTo(AddressingVersion.W3C, SOAPVersion.SOAP_11); String messageId = hl.getMessageID(AddressingVersion.W3C, SOAPVersion.SOAP_11); ThoughtfulGreeterService thoughtfulGreeterService = new ThoughtfulGreeterService(); ThoughtfulGreeterCallback thoughtfulGreeterCallback = thoughtfulGreeterService.getThoughtfulGreeterCallbackPort(); WSBindingProvider bp = (WSBindingProvider) thoughtfulGreeterCallback; bp.setAddress(reference.getAddress()); bp.setOutboundHeaders(Headers.create(AddressingVersion.W3C.relatesToTag, messageId)); System.out.println("Call back address = "+ reference.getAddress()); System.out.println("Message id = "+messageId); System.out.println("call callback now ************************************************************"); thoughtfulGreeterCallback.helloFromWorld(greetingResponse); }
Add lines in method helloToWorld to create the response and invoke callbackToHelloFromWorld:
GreetingResponseType response = new GreetingResponseType(); response.setGreeting("Hello from the world to " + payload.getName()); callbackToHelloFromWorld(response);
Right click on the ThoughtfulGreeterService and select Run from the context menu. This will make the application be built and (re)deployed.
The console then shows (again) the address at which the service is available.
Setup the SoapUI Test Project
SoapUI is a good for testing web services – SOAP and REST – other services as well. It can handle XML and JSON and other payloads. It can deal with asynchronous services – because it can expose the callback interface to which the asynchronous response is to be returned. We will look at SoapUI in our current example.
Create a new SoapUI project – based on the WSDL document exposed by the deployed ThoughtfulGreeter service (at the address shown as Target URL in the console after deployment – with ?WSDL added at the end): http://localhost:7101/AsynchronousJavaWebService-WebServices-context-root/ThoughtfulGreeterSOAP11BindingPort?WSDL).
The project is created – here is what it looks like:
Next, we need a MockService in SoapUI – to implement the callback interface (PortType ThoughtfulGreeterCallback) for the ThoughtfulGreeterService. Right click on the project in SoapUI. Select New SOAP MockService from the context menu.
Set the name of the MockService to ThoughtfulGreeterCallbackService:
And click on OK.
Add a MockOperation – from the context menu on the MockService.
Select the operation helloFromWorld (in the ThoughtfulGreeterCallbackSOAP11Binding in the WSDL for the ThoughtfulGreeterService):
Open the MockService Editor, from the context menu on the Mock Service:
Open the options window for the Mock Service:
Set the Path and Port for the Mock Service to appropriate values – such as /MockThoughfulGreeterCallback and 8081:
Start the Mock Service. Note we do not have to specify a response message for this mock service and operation. The operation is one-way – only to be invoked in order for the asynchronous service to deliver its response.
Using the icon in the Mock Editor window, open the WSDL page for the Mock Service. It is the easiest way to get hold of the end point for the MockService. We need this endpoint, to pass it in the request to the ThoughtfulGreeterService.helloToWorld operationas the ReplyTo address:
The browser opens at the WSDL page for the Mock Service:
Copy the endpoint url (minus ?WSDL) to the clipboard.
Open the Test Request for the helloToWorld operation. Set the endpoint to the endpoint found in the JDeveloper console after deployment. Set a value for the name element in the request message.
Open the tab for Addressing details. Check the checkbox labeled Enable WS-Addressing. Set the ReplyTo property with the endpoint address in the clipboard buffer (copied from the WSDL page for the Mock Service). Check the checkbox labeled Randomly generate MessageId.
This basically means that SoapUI will add several WS-Addressing headers to the request it sends to the ThoughtfulGreeterService – including one for the ReplyTo address (the callback endpoint) and the message id to be used in the callback.
Now make the call from SoapUI.
Check in JDeveloper Console:
Clearly the JAX-WS Web Service was invoked and the request had headers with a callback address and a message id.
Check in SoapUI in the MockService editor. Here you will find a log line for a incoming request. When you inspect the message exchange results, you will find the response message as well as the RelatesTo header property with the same message Id that was sent in the request message:
Resources
Download JDeveloper 12c Application: AsynchronousJavaWebServiceJDeveloper12cApplication
Documentation
SoapUI – Testing Asynchronous Services
SoapUI – Working with MockServices
Blog articles:
Create an Asynchronous JAX-WS Web Service and call it from Oracle BPEL 11g – Bob Webster’s Blog
Invoke a single port async service using JAX-WS and WS-Addressing – Gerard Davison
How to call a webservice directly from Java (without webservice library) – Frank Houweling on the AMIS Technology Blog
Building an asynchronous web service with JAX-WS – Edwin Biemond
SOA Suite 11g Asynchronous Testing with soapUI – A-Team blog
Hello Lucas Jellema,
I have worked on implementing Asynchronous Web Service using JAX-WS in JDeveloper IDE. As per the client requirements, few of the Web Services were of type Polling so I used Thread mechanism of Java.In simple terms or say in layman’s terms below is the explanation.
Syn means :- Guest come and you open the door.
Asyn means :- You close the door and you wait them to press the bell and then open the door
pooling here means :- Every 15 mins you open door and check guest has come or not.
For polling , I have used Thread.sleep of Java. Now as per my client requirements, she wants Async & Polling Together in single war file for single operation.
Could anyone please help me on this as tried every tricks in the box but didn’t succeed.
Thanks, Kailash
I just wanted to make sure about second wsdl file you are using is below one ??
Where can I get the wsdl here. This example requires wsdl to be there. I couldn’t find one which can be used to check