Web Services Asynchronous

Perhaps something very different and weird to see around is an asynchronous web services, but yes! This beast really exists, at least it’s possible to generate an asynchronous Web Services Client with some binding customization. The JAX-WS provides support for invoking a Web Services through an asynchronous client. This asynchronous calling support is provided in two models: Callback and Polling. In the Callback approach we (as the client) just have to wait for a call arrives with our response, and in the Polling approach we have to check once in a while whether our response is already available and Β then get it.

Asynchronous communication is a feature controlled by WSDL binding customization in JAX-WS. The binding process is instrumented by a tag enableAsyncMapping for asynchrony when generating web service client artifacts. One option is to use an external standalone XML file for the WSDL binding customization. In addition to the external binding file approach, another option would be embed binding declarations directly into a WSDL document, and use this approach to customize the client. In our example, we are going to use the first option, an external XML binding file. Let’s dive into our sample.

Thinking and drawing…

Well, nothing better than a clean blank paper sheet to help you think before execute something. It’s always a good idea have, at least, some sketches of what we are going to implement.

Synchronous Calling

Actually, I was in doubt about add this sketch regarding the synchronous calling of a Web Services, of course, this is so obvious for everybody (I think), but just not to be unfair with the synchronous calling and for the sake of comparison between all the the calling techniques, let’s add its drawing as well.

As mentioned before, there’s nothing new in Picture 1 below, the Consumer fires the request and waits for around fifteen seconds for the response, getting completely blocked at this period of waiting. There’s one big advantage in this case! You have a good excuse to grab a hot cup of coffee. πŸ™‚

Picture 1. The synchronous calling scenario

Picture 1. The synchronous calling scenario

Now let’s start drawing the not so common scenarios, starting with the Asynchronous Web Services Calling using the pooling technique. We fires a request once in a while to check if the response is ready to be sent back. When it does, we call the method that provides the response. While the response is not ready, the client could be doing any other tasks. We will see the coding of this scenario soon in this article. Below, at Picture 2, we have the behaviour of this scenario.

Picture 2. The asynchronous polling calling scenario

Picture 2. The asynchronous polling calling scenario

At last, but probably the most interesting option, we have the web services asynchronous calling using a callback handler. Again, here the client have the opportunity to work on other tasks while waiting for the response to arrive. As the response comes through a callback, the client doesn’t have to do anything to trigger the receiving, only have to have an interface implemented, called AsyncHandler (JAX-WS 2.0), in order to the server have a point to deliver its response. The Picture 3 below show how this scenario works.

Picture 3. The asynchronous callback scenario

Picture 3. The asynchronous callback scenario

Now, the Proof!

First, On the server side…
The Web Service Implementation and “Deployment”

On the server side there’s nothing new regarding the implementation, as we stated at the beginning of this article, the asynchronous communication is a feature of the JAX-WS web services clients. Here we are going to implement the server side, that is, the Web Services itself. This Web Service is a simple Accounting processing service that calculates the total of expenses in a specific period. The average time of response for this service is (purposely) 15 seconds. Yes, I know, maybe 15 seconds is not enough to grab a cup of coffee, but bear in mind that this is all the time that Israelis living near Gaza has to run for shelter during a rocket alert :-(.Β So, it’s a matter of life or death for some people :-(.

We will use the contract-first approach, hence the first thing to do is to create the Service Contract through a WSDL file.

These are the steps we’ll perform:

1. Create the service contract;
2. Generate the Java Web Service artifacts
3. Implement/Coding the Web Service

1. Create the Service Contract:
Let’s create a file called accounting-service.wsdl with the following content:

<types>
		<xsd:schema xmlns:tns="http://async.ws.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://async.ws.com/">
			<xsd:element name="getPeriodTotalExpenses" type="tns:getPeriodTotalExpenses"></xsd:element>
			<xsd:element name="getPeriodTotalExpensesResponse" type="tns:getPeriodTotalExpensesResponse"></xsd:element>
			<xsd:element name="faultAccountingService" type="tns:faultAccountingService"></xsd:element>
			<xsd:complexType name="getPeriodTotalExpenses">
				<xsd:sequence>
					<xsd:element name="startDate" type="xsd:date" minOccurs="0"></xsd:element>
					<xsd:element name="endDate" type="xsd:date" minOccurs="0"></xsd:element>
				</xsd:sequence>
			</xsd:complexType>
			<xsd:complexType name="getPeriodTotalExpensesResponse">
				<xsd:sequence>
					<xsd:element name="totalExpensesPeriod" type="xsd:double"></xsd:element>
				</xsd:sequence>
			</xsd:complexType>
			<xsd:complexType name="faultAccountingService">
			    <xsd:sequence>
                    <xsd:element name="code" type="xsd:int" minOccurs="0"></xsd:element>
                    <xsd:element name="description" type="xsd:string" minOccurs="0"></xsd:element>
                </xsd:sequence>
			</xsd:complexType>
		</xsd:schema>
	</types>

	<message name="getPeriodTotalExpenses">
		<part name="parameters" element="tns:getPeriodTotalExpenses"></part>
	</message>
	<message name="getPeriodTotalExpensesResponse">
		<part name="parameters" element="tns:getPeriodTotalExpensesResponse"></part>
	</message>
	<message name="faultAccountingService">
	   <part name="parameters" element="tns:faultAccountingService"></part>
	</message>

	<portType name="AccountingService">
		<operation name="getPeriodTotalExpenses">
			<input wsam:Action="http://async.ws.com/ExchangeRate/getPeriodTotalExpensesRequest" message="tns:getPeriodTotalExpenses"></input>
			<output wsam:Action="http://async.ws.com/ExchangeRate/getPeriodTotalExpensesResponse" message="tns:getPeriodTotalExpensesResponse"></output>
			<fault name="fault" message="tns:faultAccountingService"></fault>
		</operation>
	</portType>

At the Listing 1, through the line 17 to 27, we have the elements defined to build our message request and message response. The request is composed of two parameters, the beginning and the end date of the period. The response is only a double value, representing the total expenses of the period requested. Β Through the line 48 to 52 is defined the unique operation of service called getPeriodoTotalExpenses.

2. Generate the Java Web Service Arctifacts:
With the JAX-WS maven plugin we will generate the Java code for the service interface and all the others artifacts needed to implement this contract.

           <plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>jaxws-maven-plugin</artifactId>
				<executions>
					<execution>
						<goals>
							<goal>wsimport</goal>
						</goals>
						<configuration>
						    <target>2.2</target>
							<wsdlDirectory>${basedir}/src/main/resources/wsdl</wsdlDirectory>
							<keep>true</keep>
							<packageName>com.ws.async.generated</packageName>
							<sourceDestDir>${basedir}/src/main/java</sourceDestDir>
						</configuration>
					</execution>
				</executions>
			</plugin>

At Listing 2, through the line 21 to 24, we configure the wsimport goal of the JAX-WS maven plugin with: the WSDL directory, asking to keep the source code, informing the package to be generated and the localization of the source destination folder.

3. Implementing/Coding the Web Service:
Among all the Java source code generated at the com.ws.async.generated package, we are mainly interested in one specific class, actually a Java interface, called AccountingService.java shown at Listing 3, that’s our Service Endpoint Interface (SEI). There, at the line 40, Β we have the unique operation defined earlier in the WSDL.

@WebService(name = "AccountingService", targetNamespace = "http://async.ws.com/")
@XmlSeeAlso({
    ObjectFactory.class
})
public interface AccountingService {

    /**
     *
     * @param endDate
     * @param startDate
     * @return
     *     returns double
     * @throws FaultAccountingService_Exception
     */
    @WebMethod
    @WebResult(name = "totalExpensesPeriod", targetNamespace = "")
    @RequestWrapper(localName = "getPeriodTotalExpenses", targetNamespace = "http://async.ws.com/", className = "com.ws.async.generated.GetPeriodTotalExpenses")
    @ResponseWrapper(localName = "getPeriodTotalExpensesResponse", targetNamespace = "http://async.ws.com/", className = "com.ws.async.generated.GetPeriodTotalExpensesResponse")
    @Action(input = "http://async.ws.com/ExchangeRate/getPeriodTotalExpensesRequest", output = "http://async.ws.com/ExchangeRate/getPeriodTotalExpensesResponse")
    public double getPeriodTotalExpenses(
        @WebParam(name = "startDate", targetNamespace = "")
        XMLGregorianCalendar startDate,
        @WebParam(name = "endDate", targetNamespace = "")
        XMLGregorianCalendar endDate)
        throws FaultAccountingService_Exception
    ;
}

Now what is left is build the Web Service based on this interface, we’re going to call it AccountingServiceEndpoint.java. This implementation is shown at the Listing 4. In this class we implement the interface and so the business method. Purposely we wait 15 seconds before answer the request to simulate a high latency due to the hard processing or… Β whatever. (line 50).

@WebService(serviceName = "AccountingService", portName = "AccountingServicePort", endpointInterface = "com.ws.async.generated.AccountingService")
public class AccountingServiceEndpoint implements AccountingService {
	public static void main(String[] args) {
		if (args.length != 1) {
			System.out.println("Usage: java -cp <jarFile> com.ws.async.AccountingServiceEndpoint http://localhost:8282/accountingService");
			System.exit(-1);
		}
		AccountingServiceEndpoint wsInstance = new AccountingServiceEndpoint();
		Endpoint.publish(args[0], wsInstance);
		System.out.println("β–‘β–’β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“");
		System.out.println("β–‘β–’β–“β–“β–“β–“β–“β–“ »»»» Published Endpoint at URL " + args[0]);
		System.out.println("β–‘β–’β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“\n\n");
	}

	@WebMethod
	@Override
	public double getPeriodTotalExpenses(XMLGregorianCalendar startDate, XMLGregorianCalendar endDate) throws FaultAccountingService_Exception {
		double result = 0;
		System.out.println("β–‘β–’β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–’β–‘");
		System.out.println("β–‘β–’β–“ »»» Start transaction            β–“β–’β–‘");
		System.out.println("β–‘β–’β–“ Wait 15 seconds, calculating...  β–“β–’β–‘");
		try {
			LocalDate localDateStartDate = LocalDate.of(startDate.getYear(), startDate.getMonth(), startDate.getDay());
			LocalDate localDateEndDate = LocalDate.of(endDate.getYear(), endDate.getMonth(), endDate.getDay());

			if (localDateEndDate.isBefore(localDateStartDate)) {
				FaultAccountingService faultInfo = new FaultAccountingService();
				faultInfo.setCode(1);
				faultInfo.setDescription("The End Date is not after Start Date");
				System.out.println("β–‘β–’β–“ Exception thrown!!!              β–“β–’β–‘");
				throw new FaultAccountingService_Exception("Problems with Period information", faultInfo);
			} else {
				long days = ChronoUnit.DAYS.between(localDateStartDate, localDateEndDate);
				result = 2.85 * days;
				// Simulates 15 seconds of processing
				Thread.sleep(15000);
			}
		} catch (InterruptedException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
		System.out.println("β–‘β–’β–“ Answering now...                 β–“β–’β–‘");
		System.out.println("β–‘β–’β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–’β–‘");
		System.out.println("\n");

		return result;
	}
}

Perhaps the different thing in here I would like to point is the fact that: we are using only the Java SE to provide a fully running Web Service Endpoint. At the line 23 we simply publish our Web Service at the URL informed (http://localhost:8282/accountingService) using the Endpoint.pusblish method. We start our Web Service program with the following command:

uaza@mac:~$
uaza@mac:~$ java -cp target/AccountingServiceWebService.jar com.ws.async.AccountingServiceEndpoint http://localhost:8282/accountingService
uaza@mac:~$

After this, we check the Web service accessing the address http://localhost:8282/accountingService?wsdl at any browser. If everything went well we now can see our WSDL exposed. With this we finish the implementation and deployment of our Web Service, so far we haven’t seen anything related to asynchronous calls, again… Β this is because the asynchronous communication is a feature available to the client of web service, that’s what we’re going to do next. Β Now, the real fun begins.

Second, On the client side…
The Web Service Client (Asynchronous) Implementation

Part of the process to create the client Web Service is similar to what we have done to create the implementation. But now, we have to create the artifacts to perform the invocation of the service, and besides the synchronous option, we also want that be available the options of asynchronous call for this web service.

For the Client Web Service, there will be only two steps to perform:

1. Create the artifacts to call the Web Services (asking for the asynchronous feature options);
2. Building the Web Services call of the Client.

Β 1. Create the artifacts to call the Web Services

We are going to generate all the artifacts necessary to consume this Web Service almost the same way we did for the creation of the implementation of the Web Service, but the subtle difference is very important to produce the results that we want. At the Listing 4 we have the JAX-WS maven plugin configuration to generate our artifacts for the client.


			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>jaxws-maven-plugin</artifactId>
				<executions>
					<execution>
						<goals>
							<goal>wsimport</goal>
						</goals>
						<configuration>
							<wsdlUrls>
								<wsdlUrl>http://localhost:8282/accountingService?wsdl</wsdlUrl>
							</wsdlUrls>
							<bindingDirectory>${basedir}/src/main/resources/jaxws</bindingDirectory>
							<keep>true</keep>
							<packageName>com.ws.async.generated</packageName>
							<sourceDestDir>${basedir}/src/main/java</sourceDestDir>
						</configuration>
					</execution>
				</executions>
			</plugin>

The highlights here: at the line 43 we are pointing to the public already published (and running) Web Service WSDL to generate the artifacts. At the line 45 we are informing the binding directory, where is localized a XML file to customize the bindings for this Web Services client. Doing so… the customization bindings, we have the chance to configure our service interface to provide the asynchronous method (polling and callback). At the Listing 5 is shown the binding customization file content.

<?xml version="1.0" encoding="UTF-8"?>

<bindings       	xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"       	wsdlLocation="http://localhost:8282/accountingService?wsdl"       	xmlns="http://java.sun.com/xml/ns/jaxws">

	<!-- applies to wsdl:definitions node, that would mean the entire wsdl -->
	<enableAsyncMapping>false</enableAsyncMapping>

	<!-- wsdl:portType operation customization -->
	<bindings node="wsdl:definitions/wsdl:portType [@name='AccountingService']/wsdl:operation[@name='getPeriodTotalExpenses']">
		<enableAsyncMapping>true</enableAsyncMapping>
	</bindings>
</bindings>

In the Listing 5, at the line 9 we are turning off the asynchronous feature for the whole Web Services, i.e., all operations that exists in this Web Service won’t have provided the asynchronous call feature. We are doing this to assure the only operation that will have this feature provided will be the one explicit that we inform through the line 12 through 14. It’s being filtered through the portType (AccountingService) and the operation name (getPeriodTotalExpenses) the exactly function we want to realize asynchronous calls. Then, the result interface service that the client has is different from the one generated for the server at the Listing 3. Below at the Listing 6 is shown the service interface generated, the outcome of the JAX-WS maven plugin executed with the binding customization.

/**
     *
     * @param endDate
     * @param startDate
     * @return
     *     returns javax.xml.ws.Response<com.ws.async.generated.GetPeriodTotalExpensesResponse>
     */
    @WebMethod(operationName = "getPeriodTotalExpenses")
    @RequestWrapper(localName = "getPeriodTotalExpenses", targetNamespace = "http://async.ws.com/", className = "com.ws.async.generated.GetPeriodTotalExpenses")
    @ResponseWrapper(localName = "getPeriodTotalExpensesResponse", targetNamespace = "http://async.ws.com/", className = "com.ws.async.generated.GetPeriodTotalExpensesResponse")
    public Response<GetPeriodTotalExpensesResponse> getPeriodTotalExpensesAsync(
        @WebParam(name = "startDate", targetNamespace = "")
        XMLGregorianCalendar startDate,
        @WebParam(name = "endDate", targetNamespace = "")
        XMLGregorianCalendar endDate);

    /**
     *
     * @param endDate
     * @param asyncHandler
     * @param startDate
     * @return
     *     returns java.util.concurrent.Future<? extends java.lang.Object>
     */
    @WebMethod(operationName = "getPeriodTotalExpenses")
    @RequestWrapper(localName = "getPeriodTotalExpenses", targetNamespace = "http://async.ws.com/", className = "com.ws.async.generated.GetPeriodTotalExpenses")
    @ResponseWrapper(localName = "getPeriodTotalExpensesResponse", targetNamespace = "http://async.ws.com/", className = "com.ws.async.generated.GetPeriodTotalExpensesResponse")
    public Future<?> getPeriodTotalExpensesAsync(
        @WebParam(name = "startDate", targetNamespace = "")
        XMLGregorianCalendar startDate,
        @WebParam(name = "endDate", targetNamespace = "")
        XMLGregorianCalendar endDate,
        @WebParam(name = "asyncHandler", targetNamespace = "")
        AsyncHandler<GetPeriodTotalExpensesResponse> asyncHandler);

    /**
     *
     * @param endDate
     * @param startDate
     * @return
     *     returns double
     * @throws FaultAccountingServiceException
     */
    @WebMethod
    @WebResult(name = "totalExpensesPeriod", targetNamespace = "")
    @RequestWrapper(localName = "getPeriodTotalExpenses", targetNamespace = "http://async.ws.com/", className = "com.ws.async.generated.GetPeriodTotalExpenses")
    @ResponseWrapper(localName = "getPeriodTotalExpensesResponse", targetNamespace = "http://async.ws.com/", className = "com.ws.async.generated.GetPeriodTotalExpensesResponse")
    @Action(input = "http://async.ws.com/ExchangeRate/getPeriodTotalExpensesRequest", output = "http://async.ws.com/ExchangeRate/getPeriodTotalExpensesResponse", fault = {
        @FaultAction(className = FaultAccountingServiceException.class, value = "http://async.ws.com/AccountingService/getPeriodTotalExpenses/Fault/FaultAccountingService_Exception")
    })
    public double getPeriodTotalExpenses(
        @WebParam(name = "startDate", targetNamespace = "")
        XMLGregorianCalendar startDate,
        @WebParam(name = "endDate", targetNamespace = "")
        XMLGregorianCalendar endDate)
        throws FaultAccountingServiceException
    ;

In the Listing 6, starting from bottom-up, the line 81 we have the same method available to perform synchronous calls, we can confirm comparing with the line 34 at the Listing 3. Now, let’s look for the new things happening at this interface…

1.1. The Asynchronous POLLING Method:
At the line 41 we have the signature of the asynchronous polling method. The name of the method has a suffix Async and the return object is a ResponseΒ interface with a generic declaration of the type GetPeriodTotalExpesesResponse. That’s the type of the payload, that is, the type of object the Response interface will deliver when asked for the response. We will see how to handle the Response object later building the Client of the Web Services.

1.2. The Asynchronous CALLBACK Method:
At the line 58 we have the signature of the asynchronous callback method. The name of the method also has a suffix Async, but the return object is an interface of the type Future, and one thing very different is the presence of a new parameter of the type AsyncHandler (line 64) with a generic declaration of the type GetPeriodTotalExpensesResponse. This extra parameter represents the instance of the handler that will receive the callback when the responses is available. This method gets a Response object, the same as we’ve seen above, and then this object deliver the payload with our response.

2. Building the Web Services call of the Client

In our client we will call the web services using the three available options: first the synchronous method, then the asynchronous polling method and then the asynchronous callback method. We will implement the exactly same behaviour illustrated in the Picture 1, Picture 2 and Picture 3 shown in this article. The client is simple, it’s a class with a unique method that perform the three mentioned operations one after another. We run this class passing the URL location of our Web Services. Just like this way:

uaza@mac:~$
uaza@mac:~$ java -cp target/AsyncServiceClient.jar:target/* com.ws.async.AccountingServiceClient http://localhost:8282/accountingServices
uaza@mac:~$

2.1. Synchronous Call:
As told before, this is the one that might be obvious for everyone, but anyway letΒ΄s insert it here for the sake of the whole comparison. We will execute the Web Services requesting the total expenses of a period of a whole year of 2016. These parameters will be the same for the following calling techniques (Polling and Callback) that we will execute in sequence of each other. At the Listing 7 is shown part of the code of the AccountingServiceClient class. At the lines 47 and 48 we set the date of the period, and at the line 61, we call the service synchronously getting blocked for about 15 seconds.

		DatatypeFactory dataTypeFactory;
		try {
			dataTypeFactory = DatatypeFactory.newInstance();
		} catch (DatatypeConfigurationException e1) {
			throw new RuntimeException(e1.getMessage(), e1);
		}
		XMLGregorianCalendar startDate = dataTypeFactory.newXMLGregorianCalendarDate(2016, 1, 1, DatatypeConstants.FIELD_UNDEFINED);
		XMLGregorianCalendar endDate = dataTypeFactory.newXMLGregorianCalendarDate(2016, 12, 1, DatatypeConstants.FIELD_UNDEFINED);

		theClient = this;
		wsdlUrl = urlStr;
		URL url = new URL(wsdlUrl);
		QName qname = new QName("http://async.ws.com/", "AccountingService");
		AccountingService_Service accountingService_service = new AccountingService_Service(url, qname);
		accountingService = accountingService_service.getAccountingServicePort();

		try {
			// synchronous:
			System.out.println("β–‘β–’β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–’β–‘");
			System.out.println("β–‘β–’β–“ »»» Synchronous Call                 β–“β–’β–‘");
			System.out.println("β–‘β–’β–“ Retrieved synchronously, is: " + formatNumber(accountingService.getPeriodTotalExpenses(startDate, endDate)) + " β–“β–“β–“");
			System.out.println("β–‘β–’β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–’β–‘");
			System.out.println("\n\n");
		} catch (FaultAccountingServiceException fault) {
			System.out.println("Dear user, please check the error: " + fault.getFaultInfo().getCode() + "-" + fault.getFaultInfo().getDescription());
			throw new RuntimeException(fault.getMessage());
		}

2.2. Polling Asynchronous Call:
Now let’s see the first option of asynchronous call following the sequence in the AccountingServiceClient class. Check Listing 8, at the line 71, we execute the method with the Async suffix without to have to pass any other parameters that we had to with the synchronous method. This is the polling asynchronous call option, because the lack of the Handler in the parameters and the Async suffix. As response of this call, we have an object Response with a defined generic type of GetPeriodTotalExpensesResponse returned. So… how do we know if the response is ready to be read? We have to ask for this, realizing the polling. Hence, we go through a loop requesting the status of the response, (with the chance to do anything else – in this case just a simple System.out.print information) check if it’s ready, waiting 2 seconds – Thread.sleep(2000) – between each check. When it is ready, we exit from the loop and finally grab our response using the Response.get() method, check from the line 75 through 82.

		// asynchronous with polling:
		try {
			Response<GetPeriodTotalExpensesResponse> response = accountingService.getPeriodTotalExpensesAsync(startDate, endDate);
			System.out.println("β–‘β–’β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–’β–‘");
			System.out.println("β–‘β–’β–“ »»» Polling Call                                                                           β–“β–’β–‘");
			int count = 0;
			while (!response.isDone()) {
				Thread.sleep(2000L);
				System.out.println("β–‘β–’β–“ --> Waiting 2 secs then ask if the response is ready. I could be doing something else.  " + (++count) + "  β–“β–’β–‘");
			}
			GetPeriodTotalExpensesResponse output = response.get();
			System.out.println(
					"β–‘β–’β–“ --> retrieved via polling: " + output.getTotalExpensesPeriod() + "                                                          β–“β–’β–‘");
			System.out.println("β–‘β–’β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–’β–‘");
			System.out.println("\n\n");
		} catch (Exception exc) {
			System.out.println(exc.getClass().getName() + " polling for response: " + exc.getMessage());
		}

2.3. Callback Asynchronous Call
This is the other option for asynchronous call, perhaps the most interesting for the majority of the scenarios. At the Listing 9 we can see the part of the code relevant to the callback implementation. In this implementation I have decided to let both implementation options, one with Lambda and the another without it. The reason is that the Lambda is so conveniently useful that hides all the method representing the callback, so in our case of study we miss the chance to know exactly how is the signature of the callback method, that’s why we have commented the implementation in the old style (earlier than the Java 8), from line 92 through 101. Well… checking the same implementation, from line 104 to 110, there… we are calling the Web Services implementing our AsyncHandler using Lambda (very concise) in order to be able to receive the response when it’s ready at the server side. Again, while the response doesn’t arrive we can perform any other things, like printing a message every 3 seconds – Thread.sleep (3000), line 113.

		// asynchronous with callback:
		System.out.println("β–‘β–’β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–’β–‘");
		System.out.println("β–‘β–’β–“ »»» CallBack Call                                                  β–“β–’β–‘");
		/*
		// Using the Old style (no Lambda)
		Future<?> future = accountingService.getPeriodTotalExpensesAsync(startDate, endDate, new AsyncHandler<GetPeriodTotalExpensesResponse>() {
			public void handleResponse(Response<GetPeriodTotalExpensesResponse> response) {
				try {
					theClient.setTotalExpensesPeriod(response.get().getTotalExpensesPeriod());
				} catch (Exception exc) {
					System.out.println(exc.getClass().getName() + " using callback for response:" + exc.getMessage());
				}
			}
		});
		*/
		// Using Lambda
		Future<?> future = accountingService.getPeriodTotalExpensesAsync(startDate, endDate, (response) -> {
			try {
				theClient.setTotalExpensesPeriod(response.get().getTotalExpensesPeriod());
			} catch (Exception exc) {
				System.out.println(exc.getClass().getName() + " using callback for response:" + exc.getMessage());
			}
		});
		try {
			System.out.println("β–‘β–’β–“ While no answer...  I will do something else in meantime...    1   β–“β–’β–‘");
			Thread.sleep(3000);
			System.out.println("β–‘β–’β–“ While no answer...  I will do something else in meantime...    2   β–“β–’β–‘");
			Thread.sleep(3000);
			System.out.println("β–‘β–’β–“ While no answer...  I will do something else in meantime...    3   β–“β–’β–‘");
			Thread.sleep(3000);
			System.out.println("β–‘β–’β–“ While no answer...  I will do something else in meantime...    4   β–“β–’β–‘");
			Thread.sleep(3000);
			// Although I am waiting the callback, I can still ask if the response is ready,
			//     if ( future.isDone() ) ...
			// Or even cancel transaction
			//     future.cancel(true);
			System.out.println("β–‘β–’β–“ While no answer...  I will do something else in meantime...    5   β–“β–’β–‘");
		} catch (InterruptedException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
	}

The Evidence!

Let’s now see the outcome of our proof application. We have already seen the commands to start the Web Services App, as well the Client App of the service. Of course, let’s start the server side first, and we are going to have the following output (Picture 4). We have printed the URL address of the publication of the Web Services.

Picture 4. The output of the Web Services when started.

Picture 4. The output of the Web Services when started.

Right away after we’ve started the Web Services Client App, it’s launched the first call. As you might recall, it’s a synchronous call, so it will take 15 seconds to have any other animation in our output screen. Be patient, wait for a quarter of a minute and see the following result (Picture 5):

Picture 5. The output of the Web Services Client synchronous.

Picture 5. The output of the Web Services Client synchronous.

Next, it will happen the first asynchronous call using the polling technique. At the Picture 6 we can check the result, the difference now is that we can see some outputs while the response doesn’t arrive.

Picture 6. The output of the Web Services Client asynchronous call, using polling technique.

Picture 6. The output of the Web Services Client asynchronous call, using polling technique.

At third call, we have the other technique of an asynchronous call, the callback. The same way we did at the polling technique, here with the callback we can do something else but with the difference that (in between) we do not have “to ping” the server to check the readiness of the response, we just wait for the callback with the response.

Picture 7. The output of the Web Services Client asynchronous call, using callback technique.

Picture 7. The output of the Web Services Client asynchronous call, using callback technique.

Conclusion: As we already know: “the truth is out there” ( I hope you have watched X-Files πŸ™‚ ), we have to know that the asynchronous Web Services call is also there. If that feature of the JAX-WS is useful or not is up to you analyze according to the business and technical scenario you might be dealing with. The point here is to be aware of which options are available, perhaps sooner or later this could be useful in your case. For the good or bad, the beast (Asynchronous Web Services) is out there! πŸ˜‰


Source Code:
https://github.com/ualter/AsyncWebService/archive/master.zip