Java and Soap: JAX-WS Security

Java API for XML Web Services (JAX-WS) is an Application Programming Interface (API) for developing web services and clients. It is one of the Java XML programming APIs. JAX-WS web services and clients use SOAP messages for communication and HTTP for message transport.

The web service developer specifies the operations by defining methods in a Java interface and also provides implementation of those methods. A client creates a proxy (a local object representing the service) and then simply calls methods on the proxy. JAX-WS runtime system converts the calls and responses to and from SOAP messages. The developer need not generate or parse SOAP messages. The JAX-WS runtime hides the internal complexity from the application developer.

Though, JAX-WS is a part of the Java EE, it can also be used in Java SE version 6 and onwards. The reason of including JAX-WS in Java SE is that it does not require any servlet of EJB container. This also makes HTTP a competitor of RMI as a distributed computing technology. We shall start with some examples to demonstrate how to develop, deploy and use simple web services using the Java SE 7.0 environment. We shall then show how to use tomcat to work with web service. An overview of the JAX-WS packages can be found in Table 18.1:

Note that JAX-WS programming model extends the foundation provided by the Java API for XML-based RPC (JAX-RPC) programming model. It was introduced to simplify developing web services and clients and provides greater platform independence for Java applications by the use of dynamic proxies and Java annotations. The tools included in this model support JAX-WS 2.0, 2.1, and 2.2.

The JAX-WS strategically aligns itself with the current industry trend. It extensively uses a document-centric messaging model which essentially replaces the remote procedure call programming model as specified by JAX-RPC. However, it still supports the JAX-RPC programming model and applications. It introduced some new features that were absent in JAX-RPC some of which are mentioned below:

  • Better platform independence for Java applications
  • Annotations
  • Invoking Web services asynchronously
  • Data binding with JAXB 2.2
  • Dynamic and static clients
  • Message Transmission Optimization Mechanism (MTOM)
  • Multiple payload structures
  • SOAP 1.2 support
  • Support for method parameters and return types

1. Developing Web Service

We shall develop a web service for our calculator application. In this web service, we shall not explore the sophisticated features of JAX-WS. Instead, we shall concentrate on how to write and invoke a web service. The discussion about the extended features may be found later in this chapter.

Our web service will have a single operation add(). We first write an interface Calculator as follows:

package calc.ws;

import javax.jws.WebMethod;

import javax.jws.WebService;

import javax.jws.soap.SOAPBinding;

import javax.jws.soap.SOAPBinding.Style;

 

//Service Endpoint Interface @WebService

@SOAPBinding(style = Style.RPC) public interface Calculator

{

@WebMethod public int add(int a, int b);

}

Writing an endpoint interface is not always required. However, it makes testing and using the web service from other Java clients far easier. This is an ordinary Java interface except that it uses some annotations. JAX-WS uses annotations extensively, to simplify the development and deployment of web service.

An interface, to be a web service interface, must be annotated by @WebService. The @S0APBinding annotation maps this web service to SOAP. The element style instructs to use RPC encoding style for messages sent to and from the web service. Note that SOAP supports two kinds of encoding: RPC style and document style. The default is document.

The @WebMethodtells that the method add() has to be exposed as a web service operation. Although the specification says that the annotation is mandatory, often the code runs without it. The exposed method must be public. The interface is ready and acts as a contract between the web service and the client. The next step is to write an implementation of this interface.

package calc.ws;

import javax.jws.WebService;

//Service Implementation

@WebService(endpointInterface = “calc.ws.Calculator”)

public class SimpleCalculator implements Calculator

{

@Override

public int add(int a, int b) {

System.out.println(”Received: ” + a + ” and ” + b);

int result = a + b;

System.out.println(”Sent: ” + result);

return result;

}

}

This class defines the method add() declared in Calculator interface. When a class implements an endpoint interface, it is mandatory to use a @WebService annotation with a endpointInteface element specifying the fully qualified name of the interface. In the above implementation class, endpointInterface element tells that the name of the service endpoint interface defining the service’s contract is calc.ws.Calculator.

2. Deploying Web Service

JAX-WS includes a class javax.xml.ws.Endpoint to easily publish and configure a web service. We do not need a container to deploy a web service. Instead, we can end up with a bootstrap class that calls one of the publish() method of Endpoint class. This bootstrap class may be the same service implementation or a different class. We shall use a separate class for publishing web service. Here is the essential line of code in the bootstrap class:

Endpoint.publish(“http://172.16.5.81:6789/ws/calc”, new SimpleCalculator());

This essentially publishes an endpoint for SimpleCalculator object with the URL http://172.16.5.81:678 9/ws/calc. The necessary server infrastructure is created by the JAX-WS implementation and configured using some default configuration. For custom configuration, we can use other overloaded methods of Endpoint class. We assume that the IP address of the machine publishing this web service is 172.16.5.81. If you have a different address, change it.

The following is a complete source code (CalculatorPublisher.java) of the web service publisher:

import calc.ws.*;

import javax.xml.ws.Endpoint;

public class CalculatorPublisher {

public static void main(String[] args) {

Endpoint.publish(“http://172.16.5.81:6789/ws/calc”, new SimpleCalculator());

}

}

To compile and run the programs, create the following directory structure.

Go to the directory pub and use the following command to compile all classes:

javac calc\ws\*.java *.java

To publish the web service, run the publisher using the following command

java CalculatorPublisher

You can check if the web service is published successfully or not by typing the following URL in a web browser:

http://172.16.5.81:6789/ws/calc

If everything goes well, the browser’s screen looks as shown in Figure. 18.2:

Note that in practice, we hardly use Endpoint class to publish a web service; instead application server is used for publishing the web services based on your web service SEI and other classes. We shall see how to publish a web service using Apache’s tomcat servlet container later in this chapter.

3. Invoking Web Service

To invoke a web service, a client first creates a Service object that encapsulates a web service, which is a set of related ports. A port, in turn, includes a port type, bound to a particular protocol, and a particular endpoint address. A Service object is usually created from WSDL contract which is available via WSDL URL.

In this section, we shall create the Service object manually using its static create() method and the next section describes how to create it from WSDL using wsimport command. The create() method has many overloaded versions. The commonly used one takes a URL and a QName as follows:

URL url = new URL(“http://172.16.5.81:6789/ws/calc”);

QName qname = new QName(“http://ws.calc/”, “SimpleCalculatorService”);

Service service = Service.create(url, qname);

The first argument specifies the location of the web service’s WSDL file and the second gives the qualified name of the web service. Since this Service is created from a WSDL file, the port(s) binding ID, QName, and endpoint address are known to the Service. Anyway, this Service object is then used to create a local proxy to the web service:

Calculator cal = service.getPort(Calculator.class);

The parameter specifies the service endpoint interface that is supported by the returned proxy. Since, endpoint interface for the simpleCalculator web service is Calculator, we have specified it. Note that JAX-WS runtime system selects protocol binding (and a port) and configures the proxy accordingly. The returned proxy should not be reconfigured by the client further. Note that to run the client, service endpoint interface Calculator is needed. However, it is not difficult to obtain/create this endpoint interface. There are also ways to write a client program without using the endpoint interface. We shall discuss this method in the next section.

Invoking an operation on the web service is now as simple as invoking a method on a local object:

int x = 4, y = 3;

int result = cal.add(x,y);

The complete source code of the client (CalculatorClient.java) is shown below:

import java.net.URL;

import javax.xml.namespace.QName;

import javax.xml.ws.Service;

import calc.ws.*;

public class CalculatorClient {

public static void main(String[] args) throws Exception {

URL url = new URL(“http://172.16.5.81:6789/ws/calc”);

QName qname = new QName(”http://ws.calc/”, “SimpleCalculatorService”);

Service service = Service.create(url, qname);

Calculator cal = service.getPort(Calculator.class);

int x = 4, y = 3;

int result = cal.add(x,y);

System.out.println(“Sent: ” + x +” and “+y);

System.out.print(“Received(“+x+”+”+y+”=): ” + result);

}

}

Create the following directory structure in a machine for the web service client.

Note that the service endpoint interface Calculator.java is needed by this client. Had there been a provision, you may download it or may write one such interface manually. Open a terminal, go to the client directory and use thje following command to compile client files:

javac calc\ws\*.java *.java

Now, execute the client to invoke the web service as follows:

java CalculatorClient

A sample result is shown in Figure 18.3:

4. Tracking SOAP messages

If you want to see the underlying SOAP messages at the publisher side, insert the following line of code in CalculatorPublisher.java:

System.setProperty(“com.sun.xml.internal.ws.transport.http.HttpAdapter.dump”,“true”);

Similarly, insert the following line of code to see SOAP messages at the client side:

System.setProperty(“com.sun.xml.internal.ws.transport.http.client.HttpTransport Pipe.dump”, “true”);

You will see that the client sends a SOAP message which looks like this:

<?xml version=”1.0″ ?>

<S:Envelope xmlns:S=”http://schemas.xmlsoap.org/soap/envelope/”>

<S:Body>

<ns2:add xmlns:ns2=”http://ws.calc/”>

<arg0>4</arg0>

<arg1>3</arg1><

/ns2:add>

</S:Body>

</S:Envelope>

The web service responds with the following SOAP message:

<?xml version=”1.0″ ?>

<S:Envelope xmlns:S=”http://schemas.xmlsoap.org/soap/envelope/”>

<S:Body>

<ns2:addResponse xmlns:ns2=”http://ws.calc/”>

<return>7</return>

</ns2:addResponse>

</S:Body>

</S:Envelope>

To check that the communication really takes place using SOAP messages, we may write a simple Java socket program. The following is a sample socket program that sends a SOAP request message directly to the web service:

import java.io.*; import java.net.*; class SoapClient {

public static void main(String args[]) throws Exception { int c;

Socket socket = new Socket(”172.16.5.81”, 6789);

InputStream in = socket.getInputStream();

OutputStream out = socket.getOutputStream();

InputStream fin = new FileInputStream(args[0]);

while(((c = fin.read()) != -1)) out.write((char)c);

while(((c = in.read()) != -1))

System.out.print((char)c);

in.close();

}

}

To run this program, create a file (say request.txt) containing a HTTP SOAP request message as follows:

POST /ws/calc HTTP/1.1 Content-Type: text/xml; charset=utf-8 Content-Length: 215

<?xml version=”1.0” ?>

<S:Envelope xmlns:S=”http://schemas.xmlsoap.org/soap/envelope/”>

<S:Body>

<ns2:add xmlns:ns2=”http://ws.calc/”>

<arg0>4</arg0>

<arg1>3</arg1>

</ns2:add>

</S:Body>

</S:Envelope>

We can now invoke the web service from this socket program using the following command:

java SoapClient request.txt

You will see an output similar to as shown below:

HTTP/1.1 200 OK Transfer-encoding: chunked Content-type: text/xml; charset=utf-8 Date: Sun, 25 May 2014 06:40:35 GMT

c5

<?xml version=”1.0” ?>

<S:Envelopexmlns:S=”http://schemas.xmlsoap.org/soap/envelope/”>

<S:Body>

<ns2:addResponse xmlns:ns2=”http://ws.calc/”>

<return>7</return>

</ns2:addResponse>

</S:Body>

</S:Envelope>

Note that we hardly create SOAP messages explicitly in our program. Instead, we use JAX-WS API to invoke web service. JAX-WS runtime system converts the calls and responses to and from SOAP messages. The example given above will help you understanding how the JAX-WS runtime internally works.

5. Using WSDL

WSDL is used to develop XML files that specify rules for communication between different systems such as:

  • How one system can talk to another system
  • Which specific data are needed in the request
  • What would be the structure of the XML file containing data
  • What error messages to display when a certain rule for communication is not observed, to make troubleshooting easier

Web service publisher generates WSDL document for the clients, who can inspect this document to gather knowledge about the syntax of calling the web service. When we published our web service using pubiish() method of Endpoint class, a WSDL document was also generated which can be accessed using the URL http://i72.i6.5.8i:67 8 9/ws/caic?wsdi. In general, for a web service endpoint URL u, the location of the WSDL file will be u?wsdl. The WSDL file looks like this:

<!–

Published by JAX-WS RI at http://jax-ws.dev.java.net. RI’s version is JAX-WS RI 2.2.4-b01.

–>

<!–

Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI’s version is JAX-WS RI 2.2.4-b01.

–>

<definitions xmlns:wsu=”http://docs.oasis-open.org/wss/2004/01/oasis-200401- wss-wssecurity-

utility-1.0.xsd” xmlns:wsp=”http://www.w3.org/ns/ws-

policy”xmlns:wsp1_2=”http://schemas.xmlsoap.org/ws/2004/09/policy” xmlns: wsam=”http://www.w3.o

rg/2007/05/addressing/metadata”xmlns:soap=”http://schemas.xmlsoap.org/wsdl

/soap/” xmlns:tns=”h

ttp://ws.calc/” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns=”http: //schemas.xmlsoap.org

/wsdl/”targetNamespace=”http://ws.calc/” name=”SimpleCalculatorService”>

<types/>

<message name=”add”>

<part name=”arg0” type=”xsd:int”/>

<part name=”arg1” type=”xsd:int”/>

</message>

<message name=”addResponse”>

<part name=”return” type=”xsd:int”/>

</message>

<portType name=”Calculator”>

<operation name=”add” parameterOrder=”arg0 arg1”>

<input wsam:Action=”http://ws.calc/Calculator/addRequest” message=”tns: add”/>

<output wsam:Action=”http://ws.calc/Calculator/addResponse” message=”tns: addResponse”/>

</operation>

</portType>

<binding name=”SimpleCalculatorPortBinding” type=”tns:Calculator”>

<soap:binding transport=”http://schemas.xmlsoap.org/soap/http” style=”rpc”/> <operation name=”add”>

<soap:operation soapAction=””/>

<input>

<soap:body use=”literal” namespace=”http://ws.calc/”/>

</input>

<output>

<soap:body use=”literal” namespace=”http://ws.calc/”/>

</output>

</operation>

</binding>

<service name=”SimpleCalculatorService”>

<port name=”SimpleCalculatorPort” binding=”tns:SimpleCalculatorPortBinding”> <soap:address location=”http://172.16.5.81:6789/ws/calc”/>

</port>

</service>

</definitions>

In a nutshell it defines one operation add() which takes two int arguments and returns the sum of them. This WSDL file can be used to generate helper classes such as Service Endpoint Interface (SEI), Service and Exception classes etc. using the application wsimport. These classes are popularly known as portable artifacts (or simply artifacts). The wsimport takes URL of WSDL file as a parameter, and generates a set of files, structured in a directory tree. In order to create these artifacts, create a directory (say client1), open a terminal, go to this directory and use the following command to generate JAX-WS artifacts:

wsimport -keep http://172.16.5.81:6789/ws/calc?wsdl

This will generate the Java artifacts and compile them by importing the http://172.16.5.81:6789/ ws/calc?wsdl. A sample output of this command is shown below:

parsing WSDL…

Generating code…

Compiling code…

A sample directory after creating artifacts is shown here:

The -keep option tells not to delete (keep) the source artifacts. You may use this option to inspect the generated files. The SEI is Caicuiator.java and Service class is simpieCaicuiatorService. java. The name of the source file representing a service is generally named as <ciassname>Service. java. The generated service class has many public constructors including a no-argument constructor. This no-argument constructor is used most often which uses WSDL location and service name from the WSDL file.

Developing the client using these artifacts is very easy. We first create a service as follows:

SimpieCaicuiatorService calcService = new SimpleCalculatorService();

The service class also has methods each of which returns a local proxy, called dynamic proxy, of service implementation. We get a reference to this proxy as follows:

Calculator cal = calcService.getSimpleCalculatorPort();

The complete source code of the client is shown below:

import calc.ws.*;

public class CalculatorClient {

public static void main(String[] args) {

SimpieCaicuiatorService calcService = new SimpleCalculatorService();

Calculator cal = calcService.getSimpleCalculatorPort();

int x = 4, y = 3;

int result = cal.add(x,y);

System.out.println(”Sent: ” + x +” and ”+y);

System.out.print(”Received(”+x+”+”+y+”=): ” + result);

}

}

You can now run this client exactly as before.

Since, in the above example, a client generates artifacts from WSDL document, the web service need not implement an interface and may be coded as:

package calc.ws;

import javax.jws.*;

import javax.jws.soap.SOAPBinding;

import javax.jws.soap.SOAPBinding.Style;

@WebService

@SOAPBinding(style = Style.RPC) public class SimpleCalculator {

@WebMethod public int add(int a, int b) {

System.out.println(”Received: ” + a + ” and ” + b);

int result = a + b;

System.out.println(”Sent: ” + result);

return result;

}

}

Deploy it using Endpoint class as before. If you now generate the client artifacts in a directory ciient2, using wsimport, the following files are generated:

With these artifacts, the client code in the ciient2 directory will look like this:

import calc.ws.*;

public class CalculatorClient {

public static void main(String[] args) {

SimpleCalculatorService calcService = new SimpleCalculatorService();

SimpleCalculator cal = calcService.getSimpleCalculatorPort();

int x = 4, y = 3;

int result = cal.add(x,y);

System.out.println(”Sent: ” + x +” and ”+y);

System.out.print(”Received(”+x+”+”+y+”=): ” + result);

}

}

In the subsequent sections, we shall use the above implementation of our SimpleCalculator class.

6. Document Style

In the previous examples, we used RPC Style for our SOAP Binding. Actually, there are two different ways to encode and construct SOAP messages: RPC style and Document style. In short, RPC style SOAP messages contain an XML representation of the method’s call in their body. This XML representation uses the name of the method and its parameters.

The WSDL document for RPC style merely tells us how to construct a SOAP message. Consider the WSDL document fragment or our previous web service:

<message name=”add”>

<part name=”arg0″ type=”xsd:int”/>

<part name=”arg1″ type=”xsd:int”/>

</message>

<message name=”addResponse”>

<part name=”return” type=”xsd:int”/>

</message>

<binding name=”SimpleCalculatorPortBinding” type=”tns:Calculator”>

<soap:binding transport=”http://schemas.xmlsoap.org/soap/http” style=”rpc”/>

It tells us that to call a method add, SOAP body should contain an XML document fragment as follows:

<add>

<arg0>4</arg0>

<arg1>3</arg1>

</add>

However, there is no provision to verify this XML representation.

In Document style, the SOAP body contains an XML document that can be validated against a defined XML schema. Since, this style relies on the pre-defined schema to determine the structure of the SOAP message, it is a more customizable and flexible approach than RPC style. In this section, we shall rewrite our SimpleCalculator web service using document style. Using document style web service is very easy. Simply include @S0APBinding annotation as follows:

@S0APBinding(style = Style.DOCUMENT)

Actually, @SOAPBinding annotation is optional and the default style is document. So, if the annotation is absent, the style is assumed to document.

The WSDL document fragment for this web service looks like this:

<xsd:schema>

<xsd:import namespace= “http://ws.calc/”

schemaLocation=”http://172.16.5.81:6789/ws/calc?xsd=1″/>

</xsd:schema>

<message name=”add”>

<part name=”parameters” element=”tns:add”/>

</message>

<message name=”addResponse”>

<part name=”parameters” element=”tns:add”/>

</message>

<message name=”addResponse”>

<part name=”parameters” element=”tns:addResponse”/>

</message>

<soap:binding transport=”http://schemas.xmlsoap.org/soap/http” style=”document”/>

It tells that XML document in the SOAP request and response can be validated against the XML schema which can be downloaded from http://i72.i6.5.8i:6789/ws/caic?xsd=i. We downloaded it and it looks like:

<xs:schema xmlns:tns=”http://ws.calc/”

xmlns:xs=”http://www.w3.org/2001/XMLSchema” version=”1.0″ targetNamespace=”http://ws.calc/”>

<xs:element name=”add” type=”tns:add”/>

<xs:element name=”addResponse” type=”tns:addResponse”/>

<xs:complexType name=”add”>

<xs:sequence>

<xs:element name=”arg0″ type=”xs:int”/>

<xs:element name=”arg1″ type=”xs:int”/>

</xs:sequence>

</xs:complexType>

<xs:complexType name=”addResponse”>

<xs:sequence>

<xs:element name=”return” type=”xs:int”/>

</xs:sequence>

</xs:complexType>

</xs:schema>

This schema helps us to create XML document in the SOAP message on the fly. You can also generate WSDL and schema from implementation class using the following command:

wsgen -keep -wsdl -cp . calc.ws.SimpleCalculator

It generates SimpleCalculatorService.wsdl (WSDL file) and SimpleCalculatorService_ schema1.xsd (schema) files.

7. Using tomcat to deploy web service

Usually, a web service runs under the supervision of a servlet container such as Tomcat, JBoss etc. We need to perform the following steps, at a minimum:

  • Create the web application deployment descriptor (web.xml) and a proprietary web service deployment descriptor (for example, sun-jaxws.xml).
  • Package generated artifacts, service implementation class and those descriptors into a web archive (.war file).
  • Deploy the .war archive into the servlet container.

To deploy a JAX-WS Web Service using tomcat, we need JAX-WS API that can be downloaded from https://jax-ws.java.net/. We downloaded jaxws-ri-2.2.8.zip and when unzipped, the following directory structure was created. The API jars can be found in jaxws-ri/lib. Create a web application directory (say caicws) in tomcat’s webapps directory. The API jars may be copied in the application’s lib (i.e. calcWS/WEB-INF/lib) directory. In that case, the jars will be only available to the including web application. If you want them available from all applications, place those jar files in tomcat’s lib directory. We placed them in the application’s lib directory.

Now we create a standard web deployment descriptor web.xml for the deployment. It specifies WSServletContextListener as listener class and WSServlet as servlet class. A sample web.xml is shown below:

<?xml version=”1.0” encoding=”ISO-8859-1”?>

<web-app xmlns=”http://xmlns.jcp.org/xml/ns/javaee”

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation=”http://xmlns.jcp.org/xml/ns/javaee

http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd”

version=”3.1”

metadata-complete=”true”>

<listener>

<listener-class>

com.sun.xml.ws.transport.http.servlet.WSServletContextListener

</listener-class>

</listener>

<servlet>

<servlet-name>ws</servlet-name>

<servlet-class>

com.sun.xml.ws.transport.http.servlet.WSServlet

</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>ws</servlet-name>

<url-pattern>/ws</url-pattern>

</servlet-mapping>

</web-app>

Note that in the current tomcat version 8.0, the use of web deployment descriptor web.xml is not mandatory. It works fine without web.xml file. Since, older versions needs this file, we have used it for illustration.

We then create a web service deployment descriptor. The name of this file for JAX-WS is sun- jaxws.xml. A sample file is shown below:

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

<endpoints xmlns=”http://java.sun.com/xml/ns/jax-ws/ri/runtime” version=”2.0”>

<endpoint name=”Calculator” implementation=”calc.ws.SimpleCalculator”

url-pattern=”/ws/calc”/>

</endpoints>

This essentially tells that for URL pattern ws/calc, the corresponding implementation class is

calc.ws.SimpleCalculator.

Now, start the tomcat . If everything goes fine, our web service will be deployed successfully and the following message appears:

INFO: Deploying web application directory D:\apache-tomcat-8.0.0- RC1\webapps\calcWS

Apr 08, 2014 10:10:7 AM com.sun.xml.ws.transport.http.servlet.WSServletDelegate

<init>

INFO: WSSERVLET14: JAX-WS servlet initializing Apr 08, 2014 10:10:7 AM

com.sun.xml.ws.transport.http.servlet.WSServletContextListener

coEtextlEitialized

INFO: WSSERVLET12: JAX-WS context listener initializing Apr 08, 2014 10:10:7 AM

com.sun.xml.ws.transport.http.servlet.WSServletContextListener

contextInitialized

INFO: WSSERVLET12: JAX-WS context listener initializing

This can be verified by typing the following URL at the address bar of a web browser:

http://172.16.5.81:9090/calcWS/ws/calc

You can now create a consumer of this web service as discussed earlier.

8. Using Ant to build war file

If you want to build a web archive (WAR) file, create the following directory structure. Place all JAR files from jaxws-ri/lib in calcWS/WebContent/WEB-INF/lib directory. calcWS

There are various tools to build a web archive. We shall use the well needs a build file (build.xml). The following is a sample ant build.xml

<project name=”calcWS” default=”war” basedir=”.”>

<description>Web Services build file</description>

<!– set global properties for this build –>

<property name=”src” location=”src”/>

<property name=”build” location=”build”/>

<property name=”dist” location=”dist”/>

<property name=”webcontent” location=”WebContent”/>

<target name=”compile” description=”compile the source ” >

<mkdir dir=”${build}”/>

<!– Compile the java code from ${src} into ${build} –>

<javac srcdir=”${src}” destdir=”${build}”/>

</target>

<target name=”war” depends=”compile” description=”generate war” >

<!– Create the war distribution directory –>

<mkdir dir=”${dist}/war”/>

<!– Follow standard WAR structure –>

<copy todir=”${dist}/war/build/”><fileset dir=”${webcontent}”/></copy>

<copy todir=”${dist}/war/build/WEB-INF/classes/”><fileset dir=’ = ${build}”/></copy>

<jar jarfile=”${dist}/war/calcWS.war” basedir=”${dist}/war/build/”/>

</target>

</project>

Open a terminal, go the directory calcWS and use the following command to build the WAR file:

ant

Make sure that the ant application is in our PATH environment variable. If everything goes fine, the following message appears:

Buildfile: E:\ajp\soap\calcWS\build.xml

compile:

[mkdir] Created dir: E:\ajp\soap\calcWS\build

[javac] Compiling 2 source files to E:\ajp\soap\calcWS\build

war:

[mkdir] Created dir: E:\ajp\soap\calcWS\dist\war [copy] Copying 31 files to

E:\ajp\soap\calcWS\dist\war\build [copy] Copying 2 files to

E:\ajp\soap\calcWS\dist\war\build\WEB-

INF\classes

[jar] Building jar: E:\ajp\soap\calcWS\dist\war\calcWS.war

BUILD SUCCESSFUL

Total time: 2 seconds

The war file caicws.war is stored in caicws/dist/war/ directory. Place this file in tomcat’s webapps directory and restart the server. The SimpleCalculator web service will be deployed.

9. Asynchronous Client

The clients that we have written so far are called synchronous clients as they wait for the response to return. If processing of request takes a very long time, a synchronous client cannot continue its work. Fortunately, JAX-WS provides a feature called asynchronous request-response that allows a client application to continue its work and handle the response later on. This section describes how to create a client that asynchronously invokes an add() operation in a calculator web service.

When using asynchronous request-response, a client, instead of invoking the operation directly, invokes an asynchronous flavor of the same operation. The SEI, we generated so far, does not have asynchronous methods included in the interface. We use JAX-WS bindings to add the asynchronous callback or polling methods on the interface. To generate a service endpoint interface having such asynchronous methods, we use enabieAsyncMapping binding declaration. There are two ways to specify binding declarations. In the first approach, all binding declarations are written in a separate document, called an external binding file. In the second approach, the binding declarations are embedded directly inside a WSDL document.

Using external binding file

A sample external binding file (bind.xml) at minimum, is shown below:

<!–bind.xml–>

<bindings xmlns=”http://java.sun.com/xml/ns/jaxws”>

<enableAsyncMapping>true</enableAsyncMapping>

</bindings>

The <bindings> element is used as a container for JAX-WS binding declaration. The elements must belong to the http://java.sun.com/xml/ns/jaxws namespace. The only child element <enableAsyncMapping> indicates that asynchronous methods should be generated. We then use the following command to create artifacts:

wsimport -b bind.xml -keep http://172.16.5.81:6789/ws/calc?wsdl

The file containing JAX-WS binding information is specified using -b option of wsimport tool.

Using embedded binding

The binding declaration may be written inside the WSDL file directly on any of the following nodes.

  • <definitions>—Applies to all operations of all portType attributes.
  • <portType>—Applies to all operations in the portType.
  • <operation>—Applies to the operation only.

Download the WSDL file from http://i72.i6.5.8i:67 8 9/ws/caic?wsdi and save it in a file caic.xmi (say). Now, modify this file as follows:

<portType name=”SimpleCalculator”>

<bindings xmlns=”http://java.sun.com/xml/ns/jaxws”>

<enableAsyncMapping>true</enableAsyncMapping>

</bindings>

</portType>

The inserted code is shown using bold face. Use the following command to generate the artifacts:

wsimport -keep caic.xmi

Either case, it generates the following asynchronous methods along with the normal synchronous methods in the resultant service endpoint interface simpieCaicuiator. public int add(int arg0, int argl);

public Response<Integer>

addAsync(int arg0, int argl);

public Future<?> addAsync(int arg0, int arg1, AsyncHandler<Integer>

asyncHandler);

For clarity the annotations have been removed from the actual declaration. JAX-W S supports two models to invoke methods asynchronously: polling and callback. The first is for ordinary synchronous method and the last two are asynchronous polling and callback methods respectively. We have omitted the annotations for better clarity. Asynchronous invocations require special consideration. For example, instead of invoking the method add() directly, we invoke addAsync() method.

9.1. Polling

Consider the second method generated by wsimport application:

pubiic Response<Integer> addAsync(int arg0, int argl);

In the polling method, a client typically invokes this asynchronous method as follows.

SimpieCaicuiator cal = …

int x = 4, y = 3;

Response<Integer> response = cal.addAsync(x,y);

This method addAsync() does not block the client and lets client to continue its own work. The client periodically checks for a response by polling the returned Response object. The response is available when isDone() method of this object returns true. The following code segment illustrates this:

while (!response.isDone()) {

// do something here

}

When this loop exits (i.e. response is available), the client gets the result using get() method of

Response as follows:

int resuit = response.get();

The complete source code of the client that used polling is shown below:

import javax.xml.ws.*;

import async.client.*;

public class CalculatorClientPoll {

public static void main(String[] args) {

SimpleCalculatorService calcService = new SimpleCalculatorService();

SimpleCalculator cal = calcService.getSimpleCalculatorPort(); int x = 4, y = 3;

Response<Integer> response = cal.addAsync(x,y);

System.out.println(”Sent: ” + x +” and ”+y);

try {

while (!response.isDone()) {

Thread.sleep(10);

System.out.println(”Printing a message”);

}

int result = response.get();

System.out.print(”Received(”+x+”+”+y+”=): ” + result);

}catch(Exception e) {e.printStackTrace();}

}

}

The sieep() method is merely used to avoid printing too many messages on the screen. When executed, this client produced the following result:

Sent: 4 and 3

Printing a message

Printing a message

Printing a message

Received(4+3=): 7

This implies that the client was printing a message after requesting the service. After some time, the client receives the result from the service, prints and exits.

9.2. Callback

In this model of method invocation, the client does not continuously poll for response; it instead sets up a handler and continues its normal work. The handler gets notified when the response is available. The asynchronous operation takes an additional parameter, an AsyncHandier object that refers to the handler.

public Future<?> addAsync(int arg0, int argl, AsyncHandler<Integer> asyncHandler);

The client provides an AsynchHandier instance as a callback handler to accept and process the inbound response object. This handler implements javax.xmi.ws.AsynchHandier interface which has single method handieResponse(). The handler defines this method which gets called when an asynchronous response is received from the server. The response is delivered to the callback handler in the form of a javax.xmi.ws.Response object. Here is a sample callback handler:

class MyHandler implements AsyncHandler<Integer> {

private int result;

public void handleResponse(Response<Integer> response) { try {

result = response.get();

} catch (Exception e) { e.printStackTrace(); }

}

int get(){ return result; }

}

This handler, upon receiving a response, extracts the result from Response object and stores it in a variable result, which can be retrieved later using get() method. The client code looks similar to polling method except that it passes a AsyncHandler object as follows:

SimpleCalculator cal = … int x = 4, y = 3;

MyHandler mh = new MyHandler();

Future<?> response = cal.addAsync(x,y, mh);

while (!response.isDone()) {

// do something here

}

When this loop exits (i.e. response is available), the client gets the result using get() method of MyHandier as follows:

int result = mh.get();

The complete source code of callback asynchronous client is shown below:

import javax.xml.ws.*; import async.client.*;

import java.util.concurrent.Future;

public class CalculatorClientCallBack { public static void main(String[] args) {

SimpleCalculatorService calcService = new SimpleCalculatorService();

SimpleCalculator cal = calcService.getSimpleCalculatorPort();

int x = 4, y = 3;

MyHandler mh = new MyHandler();

Future<?> response = cal.addAsync(x,y, mh);

System.out.println(”Sent: ” + x + ” and ”+y); try {

while (!response.isDone()) {

Thread.sleep(10);

System.out.println(”Printing a message”);

}

int result = mh.get();

System.out.print(”Received(”+x+”+”+y+”=): ” + result);

}catch(Exception e) {e.printStackTrace();}

}

}

When executed, this client produced the following result:

Sent: 4 and 3

Printing a message

Printing a message

Printing a message

Printing a message

Received(4+3=): 7

Source: Uttam Kumar Roy (2015), Advanced Java programming, Oxford University Press.

Leave a Reply

Your email address will not be published. Required fields are marked *