JAX-WS Callback Example
1. Introduction
Java Architecture for XML Web Services (JAX-WS) is a Java programming language for creating web services, particularly SOAP services.
JAX-WS provides both Callback and Polling mechanisms to invoke web services asynchronously. In Callback mode, the client provides a callback handler to accept and process the inbound response object.
In this example, I will demonstrate how to invoke a JAX-WS service asynchronously via the callback mechanism.
2. Business Use Case
A HelloService
takes exactly 1 minute to complete the sayHello
operation. The client of HelloService
wants to continue with other tasks while waiting for the response from sayHello
for performance purposes.
3. Technologies used
The example code in this article was built and run using:
- Java 1.8.101 (1.8.x will do fine)
- Maven 3.3.9 (3.3.x will do fine)
- Eclipse Mars (Any Java IDE would work)
4. JAX-WS Service
Create a project named jax-ws-server-jdk
which creates HelloService
with one operation: sayHello
.
4.1. HelloService Interface
Create a HelloService
interface and annotate it with @WebService
.
HelloService.java
package jcg.demo.jaxws.service; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; @WebService(name = "HelloService", targetNamespace = "http://jcg.demo.async.ws") @SOAPBinding(style = Style.DOCUMENT) public interface HelloService { @WebMethod String sayHello(String msg); }
4.2. HelloServiceImpl Class
Create a HelloServiceImpl
to implement the HelloService
Interface.
HelloService.java
package jcg.demo.jaxws.service.impl; import javax.jws.WebService; import jcg.demo.jaxws.service.HelloService; @WebService(endpointInterface = "jcg.demo.jaxws.service.HelloService") public class HelloServiceImpl implements HelloService { private static final int ONE_MINUTES = 60000; @Override public String sayHello(String message) { try { Thread.sleep(ONE_MINUTES); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Server sayHello to " + message); return "Hello " + message; } }
4.3. HelloServerApp
Publish the HelloServiceImpl
at http://localhost:9980/hello?wsdl
.
HelloServerApp.java
package jcg.demo.jaxws; import javax.xml.ws.Endpoint; import jcg.demo.jaxws.service.impl.HelloServiceImpl; public class HelloServerApp { public static void main(String[] args) { Endpoint ep = Endpoint.create(new HelloServiceImpl()); ep.publish("http://localhost:9980/hello"); } }
5. Generate Client with AyncMapping Enabled
Create a project named jax-ws-client-static
which generates a JAX-WS client from http://localhost:9980/hello?wsdl
with enableAsyncMapping
enabled.
5.1. POM.XML
Configure Maven POM.xml to generate the JAX-WS client with enableAsyncMapping
enabled.
async-bindings.xml
<?xml version="1.0" encoding="UTF-8"?> <bindings xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="http://localhost:9980/hello?wsdl" xmlns="http://java.sun.com/xml/ns/jaxws"> <!-- applies to wsdl:definitions node, that would mean the entire wsdl --> <enableAsyncMapping>true</enableAsyncMapping> </bindings>
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jax-ws-client</groupId> <artifactId>jax-ws-client-static</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> <profiles> <profile> <id>codegen</id> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxws-maven-plugin</artifactId> <version>1.12</version> <executions> <execution> <id>hello_wsdl</id> <goals> <goal>wsimport</goal> </goals> <configuration> <wsdlUrls> <wsdlUrl>http://localhost:9980/hello?wsdl</wsdlUrl> </wsdlUrls> <bindingDirectory>${basedir}/src/main/resources/jaxws</bindingDirectory> <keep>true</keep> <packageName>jcg.demo.jaxws.client.hello</packageName> <sourceDestDir>src/generated/java</sourceDestDir> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> </project>
5.2. HelloService Generated Code
Execute mv install -P codegen
to generate the source code and verify that HelloService
has three operations:
sayHello
for synchronous callResponse sayHelloAsync
for asynchronous call with pollingFuture sayHelloAsync
for asynchronous call with callback
HelloService.java
package jcg.demo.jaxws.client.hello; import java.util.concurrent.Future; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.ws.AsyncHandler; import javax.xml.ws.RequestWrapper; import javax.xml.ws.Response; import javax.xml.ws.ResponseWrapper; /** * This class was generated by the JAX-WS RI. * JAX-WS RI 2.1.7-b01- * Generated source version: 2.1 * */ @WebService(name = "HelloService", targetNamespace = "http://jcg.demo.async.ws") @XmlSeeAlso({ ObjectFactory.class }) public interface HelloService { /** * * @param arg0 * @return * returns javax.xml.ws.Response<jcg.demo.jaxws.client.hello.SayHelloResponse> */ @WebMethod(operationName = "sayHello") @RequestWrapper(localName = "sayHello", targetNamespace = "http://jcg.demo.async.ws", className = "jcg.demo.jaxws.client.hello.SayHello") @ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://jcg.demo.async.ws", className = "jcg.demo.jaxws.client.hello.SayHelloResponse") public Response<SayHelloResponse> sayHelloAsync( @WebParam(name = "arg0", targetNamespace = "") String arg0); /** * * @param arg0 * @param asyncHandler * @return * returns java.util.concurrent.Future<? extends java.lang.Object> */ @WebMethod(operationName = "sayHello") @RequestWrapper(localName = "sayHello", targetNamespace = "http://jcg.demo.async.ws", className = "jcg.demo.jaxws.client.hello.SayHello") @ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://jcg.demo.async.ws", className = "jcg.demo.jaxws.client.hello.SayHelloResponse") public Future<?> sayHelloAsync( @WebParam(name = "arg0", targetNamespace = "") String arg0, @WebParam(name = "asyncHandler", targetNamespace = "") AsyncHandler<SayHelloResponse> asyncHandler); /** * * @param arg0 * @return * returns java.lang.String */ @WebMethod @WebResult(targetNamespace = "") @RequestWrapper(localName = "sayHello", targetNamespace = "http://jcg.demo.async.ws", className = "jcg.demo.jaxws.client.hello.SayHello") @ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://jcg.demo.async.ws", className = "jcg.demo.jaxws.client.hello.SayHelloResponse") public String sayHello( @WebParam(name = "arg0", targetNamespace = "") String arg0); }
5.3. ClientApp
Create a client application which invokes the service asynchronously.
ClientApp.java
package jcg.demo.callback; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import javax.xml.ws.Response; import jcg.demo.jaxws.client.hello.HelloService; import jcg.demo.jaxws.client.hello.HelloServiceImplService; import jcg.demo.jaxws.client.hello.SayHelloResponse; public class ClientApp { private static final int TEN_SECONDS = 10000; private static final String MESSAGE_DEMO = "Mary Zheng"; public static void main(String args[]) { HelloServiceImplService client = new HelloServiceImplService(); HelloService helloService = client.getHelloServiceImplPort(); try { invokeSync(helloService); invokeAsyncWithCallBack(helloService); invokeAsyncWithPolling(helloService); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } private static void invokeSync(HelloService helloService) { String retFromServer = helloService.sayHello(MESSAGE_DEMO); System.out.println("Program waits till service returns. " + retFromServer); } private static void invokeAsyncWithPolling(HelloService helloService) throws InterruptedException, ExecutionException { Response response = helloService.sayHelloAsync(MESSAGE_DEMO); while (!response.isDone()) { Thread.sleep(TEN_SECONDS); System.out.println("Program can do something while waiting and checking if the response is done. "); } SayHelloResponse output = response.get(); System.out.println("Retrieved via polling: " + output.getReturn()); } private static void invokeAsyncWithCallBack(HelloService helloService) throws InterruptedException { Future future = helloService.sayHelloAsync(MESSAGE_DEMO, (response) -> { try { System.out.println("Retrieved via callback response: " + response.get().getReturn()); } catch (Exception exc) { System.out.println(exc.getClass().getName() + " using callback for response:" + exc.getMessage()); } }); for (int i = 0; i < 9; i++) { System.out.println("Program can do something while waiting for the callback response!!!"); Thread.sleep(TEN_SECONDS); } } }
6. Demo Time
Start HelloServerApp
and ClientApp
.
ClientApp output
Program waits till service returns. Hello Mary Zheng Program can do something while waiting for the callback response!!! Program can do something while waiting for the callback response!!! Program can do something while waiting for the callback response!!! Program can do something while waiting for the callback response!!! Program can do something while waiting for the callback response!!! Program can do something while waiting for the callback response!!! Program can do something while waiting for the callback response!!! Retrieved via callback response: Hello Mary Zheng Program can do something while waiting for the callback response!!! Program can do something while waiting for the callback response!!! Program can do something while waiting and checking if the response is done. Program can do something while waiting and checking if the response is done. Program can do something while waiting and checking if the response is done. Program can do something while waiting and checking if the response is done. Program can do something while waiting and checking if the response is done. Program can do something while waiting and checking if the response is done. Program can do something while waiting and checking if the response is done. Retrieved via polling: Hello Mary Zheng
Note: Both invokeAsyncWithCallBack
and invokeAsyncWithPolling
allow the client to continue on other task while waiting for the service response.
7. Summary
In this example, I first built a JAX-WS service: HelloService
. Then I built a JAX-WS client from the server WSDL with asyncMapping
enabled. Lastly I built a clientApp
to demonstrate how to invoke the service asynchronously.
8. Download the Source Code
This example consists of a JAX-WS service and JAX-WS client which invokes the service asynchronously with callback.
You can download the full source code of this example here: JAX-WS Callback Example
Good work. Was able to use it almost seamlessly and exactly what I was looking for. Very basic example to get started along with right level of explanation.