You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Developing a Consumer with CeltiXfire

Generating the Stub Code

The starting point for developing a service consumer (or client) in CXF is a WSDL contract, complete with port type, binding, and service definitions. You can then use the wsdl2java utility to generate the Java stub code from the WSDL contract. The stub code provides the supporting code that is required to invoke operations on the remote service.
For CXF clients, the wsdl2java utility can generate the following kinds of code:

  • Stub code — supporting files for implementing a CXF client.
  • Client starting point code — sample client code that connects to the remote service and invokes every operation on the remote service.
  • Ant build file — a build.xml file intended for use with the ant build utility. It has targets for building and for running the sample client application.

    Basic HelloWorld WSDL contract

[#Table3] shows the HelloWorld WSDL contract. This contract defines a single port type, Greeter, with a SOAP binding, Greeter_SOAPBinding, and a service, SOAPService, which has a single port, SoapPort.

HelloWorld WSDL Contract

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="HelloWorld" targetNamespace="http://objectweb.org/hello_world_soap_http"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://objectweb.org/hello_world_soap_http"
xmlns:x1="http://objectweb.org/hello_world_soap_http/types"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<schema targetNamespace="http://objectweb.org/hello_world_soap_http/types"
xmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<element name="sayHi">
<complexType/>
</element>
<element name="sayHiResponse">
<complexType>
<sequence>
<element name="responseType" type="string"/>
</sequence>
</complexType>
</element>
<element name="greetMe">
<complexType>
<sequence>
<element name="requestType" type="string"/>
</sequence>
</complexType>
</element>
<element name="greetMeResponse">
<complexType>
<sequence>
<element name="responseType" type="string"/>
</sequence>
</complexType>
</element>
<element name="greetMeOneWay">
<complexType>
<sequence>
<element name="requestType" type="string"/>
</sequence>
</complexType>
</element>
<element name="pingMe">
<complexType/>
</element>
<element name="pingMeResponse">
<complexType/>
</element>
<element name="faultDetail">
<complexType>
<sequence>
<element name="minor" type="short"/>
<element name="major" type="short"/>
</sequence>
</complexType>
</element>
</schema>
</wsdl:types>

<wsdl:message name="sayHiRequest">
<wsdl:part element="x1:sayHi" name="in"/>
</wsdl:message>
<wsdl:message name="sayHiResponse">
<wsdl:part element="x1:sayHiResponse" name="out"/>
</wsdl:message>
<wsdl:message name="greetMeRequest">
<wsdl:part element="x1:greetMe" name="in"/>
</wsdl:message>
<wsdl:message name="greetMeResponse">
<wsdl:part element="x1:greetMeResponse" name="out"/>
</wsdl:message>
<wsdl:message name="greetMeOneWayRequest">
<wsdl:part element="x1:greetMeOneWay" name="in"/>
</wsdl:message>
<wsdl:message name="pingMeRequest">
<wsdl:part name="in" element="x1:pingMe"/>
</wsdl:message>
<wsdl:message name="pingMeResponse">
<wsdl:part name="out" element="x1:pingMeResponse"/>
</wsdl:message>
<wsdl:message name="pingMeFault">
<wsdl:part name="faultDetail" element="x1:faultDetail"/>
</wsdl:message>

<wsdl:portType name="Greeter">
<wsdl:operation name="sayHi">
<wsdl:input message="tns:sayHiRequest" name="sayHiRequest"/>
<wsdl:output message="tns:sayHiResponse" name="sayHiResponse"/>
</wsdl:operation>

<wsdl:operation name="greetMe">
<wsdl:input message="tns:greetMeRequest" name="greetMeRequest"/>
<wsdl:output message="tns:greetMeResponse" name="greetMeResponse"/>
</wsdl:operation>

<wsdl:operation name="greetMeOneWay">
<wsdl:input message="tns:greetMeOneWayRequest" name="greetMeOneWayRequest"/>
</wsdl:operation>

<wsdl:operation name="pingMe">
<wsdl:input name="pingMeRequest" message="tns:pingMeRequest"/>
<wsdl:output name="pingMeResponse" message="tns:pingMeResponse"/>
<wsdl:fault name="pingMeFault" message="tns:pingMeFault"/>
</wsdl:operation>
</wsdl:portType>

<wsdl:binding name="Greeter_SOAPBinding" type="tns:Greeter">
...
</wsdl:binding>

<wsdl:service name="SOAPService">
<wsdl:port binding="tns:Greeter_SOAPBinding" name="SoapPort">
<soap:address location="http://localhost:9000/SoapContext/SoapPort"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

<para>The Greeter port type from <xref linkend="Table3" /> defines the
following WSDL operations:</para>

<itemizedlist>
<listitem>
<para>sayHi — has a single output parameter, of
<type>xsd:string</type>.</para>
</listitem>

<listitem>
<para>greetMe — has an input parameter, of <type>xsd:string</type>, and an
output parameter, of <type>xsd:string</type>.</para>
</listitem>

<listitem>
<para>greetMeOneWay — has a single input parameter, of
<type>xsd:string</type>. Because this operation has no output parameters,
CeltiXfire can optimize this call to be a oneway invocation (that is, the
client does not wait for a response from the server).</para>
</listitem>

<listitem>
<para>pingMe — has no input parameters and no output parameters, but it can
raise a fault exception.</para>
</listitem>
</itemizedlist>

<para><xref linkend="Table3" /> also defines a binding, Greeter_SOAPBinding,
for the SOAP protocol. In practice, the binding is normally generated
automatically — for example, by running either of the CeltiXfire wsdl2soap or
wsdl2xml utilities. Likewise, the SOAPService service can be generated
automatically by running the CeltiXfire wsdl2service utility.</para>
</simplesect>

<simplesect>
<title>Generating the stub code</title>

<para>After defining the WSDL contract, you can generate client code using the
CeltiXfire wsdl2java utility. Enter the following command at a command-line
prompt:</para>

<screen><userinput>wsdl2java -ant -client -d <replaceable>ClientDir</replaceable> hello_world.wsdl</userinput></screen>

<para>Where <replaceable>ClientDir</replaceable> is the location of a
directory where you would like to put the generated files and
<filename>hello_world.wsdl</filename> is a file containing the contract shown
in <xref linkend="Table3" />. The -ant option generates an ant
<filename>build.xml</filename> file, for use with the ant build utility. The
-client option generates starting point code for a client
<methodname>main()</methodname> method.</para>

<para>The preceding wsdl2java command generates the following Java
packages:</para>

<itemizedlist>
<listitem>
<para><classname>org.objectweb.hello_world_soap_http</classname></para>

<para>This package name is generated from the
<literal>http://objectweb.org/hello_world_soap_http</literal> target
namespace. All of the WSDL entities defined in this target namespace (for
example, the Greeter port type and the SOAPService service) map to Java
classes in the corresponding Java package.</para>
</listitem>

<listitem>
<para><classname>org.objectweb.hello_world_soap_http.types</classname></para>

<para>This package name is generated from the
<literal>http://objectweb.org/hello_world_soap_http/types</literal> target
namespace. All of the XML types defined in this target namespace (that is,
everything defined in the <sgmltag class="element">wsdl:types</sgmltag>
element of the HelloWorld contract) map to Java classes in the corresponding
Java package.</para>
</listitem>
</itemizedlist>

<para>The stub files generated by the wsdl2java command fall into the
following categories:</para>

<itemizedlist>
<listitem>
<para>Classes representing WSDL entities (in <classname>the
org.objectweb.hello_world_soap_http</classname> package) — the following
classes are generated to represent WSDL entities:</para>

<itemizedlist>
<listitem>
<para><interfacename>Greeter</interfacename> is a Java interface that
represents the Greeter WSDL port type. In JAX-WS terminology, this Java
interface is a service endpoint interface.</para>
</listitem>

<listitem>
<para><classname>SOAPService</classname> is a Java class that represents the
SOAPService WSDL <sgmltag class="element">service</sgmltag> element.</para>
</listitem>

<listitem>
<para><exceptionname>PingMeFault</exceptionname> is a Java exception class
(extending <classname>java.lang.Exception</classname>) that represents the
pingMeFault WSDL <sgmltag class="element">fault</sgmltag> element.</para>
</listitem>
</itemizedlist>
</listitem>

<listitem>
<para>Classes representing XML types (in the
<classname>org.objectweb.hello_world_soap_http.types</classname> package) — in
the HelloWorld example, the only generated types are the various wrappers for
the request and reply messages. Some of these data types are useful for the
asynchronous invocation model.</para>
</listitem>
</itemizedlist>
</simplesect>
</section>

<section>
<title>Implementing a CeltiXfire Client</title>

<para>This section describes how to write the code for a simple Java client,
based on the WSDL contract from <xref linkend="Table3" />. To implement the
client, you need to use the following stub classes:</para>

<itemizedlist>
<listitem>
<para>Service class (that is, <classname>SOAPService</classname>).</para>
</listitem>

<listitem>
<para>Service endpoint interface (that is,
<interfacename>Greeter</interfacename>).</para>
</listitem>
</itemizedlist>

<simplesect>
<title>Generated service class</title>

<para><xref linkend="Table2" /> shows the typical outline a generated service
class, <classname>ServiceName</classname>, which extends the
<classname>javax.xml.ws.Service</classname> base class.</para>

<example id="Table2">
<title>Outline of a Generated Service Class</title>

<programlisting>public class ServiceName extends javax.xml.ws.Service
{
...
public ServiceName(URL wsdlLocation, QName serviceName) { }

public ServiceName() { }

public Greeter getPortName() { }
.
.
.
}</programlisting>
</example>

<para>The ServiceName class in <xref linkend="Table2" /> defines the following
methods:</para>

<itemizedlist>
<listitem>
<para>Constructor methods — the following forms of constructor are
defined:</para>

<itemizedlist>
<listitem>
<para><methodname><replaceable>ServiceName</replaceable>(URL wsdlLocation,
QName serviceName)</methodname> constructs a service object based on the data
in the <varname>serviceName</varname> service in the WSDL contract that is
obtainable from <varname>wsdlLocation</varname>.</para>
</listitem>

<listitem>
<para><methodname><replaceable>ServiceName</replaceable>()</methodname> is the
default constructor, which constructs a service object based on the service
name and WSDL contract that were provided at the time the stub code was
generated (for example, when running the CeltiXfire wsdl2java command). Using
this constructor presupposes that the WSDL contract remains available at its
original location.</para>
</listitem>
</itemizedlist>
</listitem>

<listitem>
<para><methodname>get<replaceable>PortName</replaceable>()</methodname>
methods — for every <replaceable>PortName</replaceable> port defined on the
<replaceable>ServiceName</replaceable> service, CeltiXfire generates a
corresponding
<methodname>get<replaceable>PortName</replaceable>()</methodname> method in
Java. Therefore, a <sgmltag class="element">wsdl:service</sgmltag> element
that defines multiple ports will generate a service class with multiple
<methodname>get<replaceable>PortName</replaceable>()</methodname>
methods.</para>
</listitem>
</itemizedlist>
</simplesect>

<simplesect>
<title>Service endpoint interface</title>

<para>For every port type defined in the original WSDL contract, you can
generate a corresponding service endpoint interface in Java. A service
endpoint interface is the Java mapping of a WSDL port type. Each operation
defined in the original WSDL port type maps to a corresponding method in the
service endpoint interface. The operation's parameters are mapped as
follows:</para>

<orderedlist>
<listitem>
<para>The input parameters are mapped to method arguments.</para>
</listitem>

<listitem>
<para>The first output parameter is mapped to a return value.</para>
</listitem>

<listitem>
<para>If there is more than one output parameter, the second and subsequent
output parameters map to method arguments (moreover, the values of these
arguments must be passed using Holder types).</para>
</listitem>
</orderedlist>

<para>For example, <xref linkend="Table4" /> shows the Greeter service
endpoint interface, which is generated from the Greeter port type defined in
<xref linkend="Table3" />. For simplicity, <xref linkend="Table4" /> omits the
standard JAXB and JAX-WS annotations.</para>

<example id="Table4">
<title>The Greeter Service Endpoint Interface</title>

<programlisting>/* Generated by WSDLToJava Compiler. */

package org.objectweb.hello_world_soap_http;
...
public interface Greeter
{
public java.lang.String sayHi();

public java.lang.String greetMe(java.lang.String requestType);

public void greetMeOneWay(java.lang.String requestType);

public void pingMe() throws PingMeFault;
}</programlisting>
</example>
</simplesect>

<simplesect>
<title>Client main function</title>

<para><xref linkend="Table1" /> shows the Java code that implements the
HelloWorld client. In summary, the client connects to the SoapPort port on the
SOAPService service and then proceeds to invoke each of the operations
supported by the Greeter port type.</para>

<example id="Table1">
<title>Client Implementation Code</title>

<programlisting>package demo.hw.client;

import java.io.File;
import java.net.URL;
import javax.xml.namespace.QName;
import org.objectweb.hello_world_soap_http.Greeter;
import org.objectweb.hello_world_soap_http.PingMeFault;
import org.objectweb.hello_world_soap_http.SOAPService;

public final class Client {

private static final QName SERVICE_NAME =
new QName("http://objectweb.org/hello_world_soap_http", "SOAPService");

private Client()
{
}

public static void main(String args[]) throws Exception
{
if (args.length == 0)

Unknown macro: { System.out.println("please specify wsdl"); System.exit(1); }

URL wsdlURL;
File wsdlFile = new File(args[0]);
if (wsdlFile.exists())

Unknown macro: { wsdlURL = wsdlFile.toURL(); }

else

Unknown macro: { wsdlURL = new URL(args[0]); }

System.out.println(wsdlURL);
SOAPService ss = new SOAPService(wsdlURL, SERVICE_NAME);
Greeter port = ss.getSoapPort();
String resp;

System.out.println("Invoking sayHi...");
resp = port.sayHi();
System.out.println("Server responded with: " + resp);
System.out.println();

System.out.println("Invoking greetMe...");
resp = port.greetMe(System.getProperty("user.name"));
System.out.println("Server responded with: " + resp);
System.out.println();

System.out.println("Invoking greetMeOneWay...");
port.greetMeOneWay(System.getProperty("user.name"));
System.out.println("No response from server as method is OneWay");
System.out.println();

try

Unknown macro: { System.out.println("Invoking pingMe, expecting exception..."); port.pingMe(); }

catch (PingMeFault ex)

Unknown macro: { System.out.println("Expected exception}

System.exit(0);
}
}</programlisting>
</example>

<para>The <methodname>Client.main()</methodname> function from <xref
linkend="Table1" /> proceeds as follows:</para>

<orderedlist>
<listitem>
<para>The CeltiXfire runtime is implicitly initialized — that is, provided the
CeltiXfire runtime classes are loaded. Hence, there is no need to call a
special function in order to initialize CeltiXfire.</para>
</listitem>

<listitem>
<para>The client expects a single string argument that gives the location of
the WSDL contract for HelloWorld. The WSDL location is stored in
<varname>wsdlURL</varname>.</para>
</listitem>

<listitem>
<para>A new port object (which enables you to access the remote server
endpoint) is created in two steps, as shown in the following code
fragment:</para>

<programlisting>SOAPService ss = new SOAPService(wsdlURL, SERVICE_NAME);
Greeter port = ss.getSoapPort();</programlisting>

<para>To create a new port object, you first create a service object (passing
in the WSDL location and service name) and then call the appropriate
<methodname>get<replaceable>PortName</replaceable>()</methodname> method to
obtain an instance of the particular port you need. In this case, the
SOAPService service supports only the SoapPort port, which is of Greeter
type.</para>
</listitem>

<listitem>
<para>The client proceeds to call each of the methods supported by the Greeter
service endpoint interface.</para>
</listitem>

<listitem>
<para>In the case of the <methodname>pingMe()</methodname> operation, the
example code shows how to catch the <classname>PingMeFault</classname> fault
exception.</para>
</listitem>
</orderedlist>
</simplesect>
</section>

<section>
<title>Setting Connection Properties with Contexts</title>

<para>You can use JAX-WS contexts to customize the properties of a client
proxy. In particular, contexts can be used to modify connection properties and
to send data in protocol headers. For example, you could use contexts to add a
SOAP header, either to a request message or to a response message. The
following types of context are supported on the client side:</para>

<itemizedlist>
<listitem>
<para>Request context — on the client side, the request context enables you to
set properties that affect outbound messages. Request context properties are
applied to a specific port instance and, once set, the properties affect every
subsequent operation invocation made on the port, until such time as a
property is explicitly cleared. For example, you might use a request context
property to set a connection timeout or to initialize data for sending in a
header.</para>
</listitem>

<listitem>
<para>Response context — on the client side, you can access the response
context to read the property values set by the inbound message from the last
operation invocation. Response context properties are reset after every
operation invocation. For example, you might access a response context
property to read header information received from the last inbound
message.</para>
</listitem>
</itemizedlist>

<simplesect>
<title>Setting a request context</title>

<para>To set a particular request context property,
<replaceable>ContextPropertyName</replaceable>, to the value,
<replaceable>PropertyValue</replaceable>, use the code shown in <xref
linkend="Table6" />.</para>

<example id="Table6">
<title>Setting a Request Context Property on the Client Side</title>

<programlisting>// Set request context property.
java.util.Map<String, Object> requestContext =
((javax.xml.ws.BindingProvider)port).getRequestContext();
requestContext.put(ContextPropertyName, PropertyValue);

// Invoke an operation.
port.SomeOperation();</programlisting>
</example>

<para>You have to cast the port object to
<classname>javax.xml.ws.BindingProvider</classname> in order to access the
request context. The request context itself is of type,
<classname>java.util.Map<String, Object></classname>, which is a hash
map that has keys of <type>String</type> and values of arbitrary type. Use
<methodname>java.util.Map.put()</methodname> to create a new entry in the hash
map.</para>
</simplesect>

<simplesect>
<title>Reading a response context</title>

<para>To retrieve a particular response context property,
<replaceable>ContextPropertyName</replaceable>, use the code shown in <xref
linkend="Table7" />.</para>

<example id="Table7">
<title>Reading a Response Context Property on the Client Side</title>

<programlisting>// Invoke an operation.
port.SomeOperation();

// Read response context property.
java.util.Map<String, Object> responseContext =
((javax.xml.ws.BindingProvider)port).getResponseContext();
PropertyType propValue = (PropertyType) responseContext.get(ContextPropertyName);</programlisting>
</example>

<para>The response context is of type, <classname>java.util.Map<String,
Object></classname>, which is a hash map that has keys <type>String</type>
and values of arbitrary type. Use <methodname>java.util.Map.get()</methodname>
to access an entry in the hash map of response context properties.</para>
</simplesect>

<simplesect>
<title>Supported contexts</title>

<para>CeltiXfire supports the following context properties:</para>

<table frame="all" id="Table8">
<title>CeltiXfire Context Properties</title>

<tgroup cols="2">
<thead>
<row>
<entry>Context Property Name</entry>

<entry>Context Property Type</entry>
</row>
</thead>

<tbody>
<row>
<entry><constant>org.objectweb.celtix.ws.addressing.JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES</constant></entry>

<entry><classname>org.objectweb.celtix.ws.addressing.AddressingProperties</classname></entry>
</row>
</tbody>
</tgroup>
</table>
</simplesect>
</section>

<section>
<title>Asynchronous Invocation Model</title>

<para>In addition to the usual synchronous mode of invocation, CeltiXfire also
supports two forms of asynchronous invocation, as follows:</para>

<itemizedlist>
<listitem>
<para>Polling approach — in this case, to invoke the remote operation, you
call a special method that has no output parameters, but returns a
<classname>javax.xml.ws.Response</classname> instance. The
<classname>Response</classname> object (which inherits from the
<interfacename>javax.util.concurrency.Future</interfacename> interface) can be
polled to check whether or not a response message has arrived.</para>
</listitem>

<listitem>
<para>Callback approach — in this case, to invoke the remote operation, you
call another special method that takes a reference to a callback object (of
<classname>javax.xml.ws.AsyncHandler</classname> type) as one of its
parameters. Whenever the response message arrives at the client, the
CeltiXfire runtime calls back on the <classname>AsyncHandler</classname>
object to give it the contents of the response message.</para>
</listitem>
</itemizedlist>

<para>Both of these asynchronous invocation approaches are described here and
illustrated by code examples.</para>

<simplesect>
<title>Contract for asynchronous example</title>

<para><xref linkend="async1" /> shows the WSDL contract that is used for the
asynchronous example. The contract defines a single port type, GreeterAsync,
which contains a single operation, greetMeSometime.</para>

<example id="async1">
<title>HelloWorld WSDL Contract for Asynchronous Example</title>

<programlisting><?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://objectweb.org/hello_world_async_soap_http"
xmlns:x1="http://objectweb.org/hello_world_async_soap_http/types"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://objectweb.org/hello_world_async_soap_http"
name="HelloWorld">
<wsdl:types>
<schema targetNamespace="http://objectweb.org/hello_world_async_soap_http/types"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:x1="http://objectweb.org/hello_world_async_soap_http/types"
elementFormDefault="qualified">
<element name="greetMeSometime">
<complexType>
<sequence>
<element name="requestType" type="xsd:string"/>
</sequence>
</complexType>
</element>
<element name="greetMeSometimeResponse">
<complexType>
<sequence>
<element name="responseType" type="xsd:string"/>
</sequence>
</complexType>
</element>
</schema>
</wsdl:types>

<wsdl:message name="greetMeSometimeRequest">
<wsdl:part name="in" element="x1:greetMeSometime"/>
</wsdl:message>
<wsdl:message name="greetMeSometimeResponse">
<wsdl:part name="out" element="x1:greetMeSometimeResponse"/>
</wsdl:message>

<wsdl:portType name="GreeterAsync">
<wsdl:operation name="greetMeSometime">
<wsdl:input name="greetMeSometimeRequest" message="tns:greetMeSometimeRequest"/>
<wsdl:output name="greetMeSometimeResponse" message="tns:greetMeSometimeResponse"/>
</wsdl:operation>
</wsdl:portType>

<wsdl:binding name="GreeterAsync_SOAPBinding" type="tns:GreeterAsync">
...
</wsdl:binding>

<wsdl:service name="SOAPService">
<wsdl:port name="SoapPort" binding="tns:GreeterAsync_SOAPBinding">
<soap:address location="http://localhost:9000/SoapContext/SoapPort"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions></programlisting>
</example>
</simplesect>

<simplesect>
<title>Generating the asynchronous stub code</title>

<para>The asynchronous style of invocation requires extra stub code (for
example, dedicated asychronous methods defined on the service endpoint
interface). This special stub code is not generated by default, however. To
switch on the asynchronous feature and generate the requisite stub code, you
must use the mapping customization feature from the WSDL 2.0
specification.</para>

<para>Customization enables you to modify the way the wsdl2java utility
generates stub code. In particular, it enables you to modify the WSDL-to-Java
mapping and to switch on certain features. Here, customization is used to
switch on the asynchronous invocation feature. Customizations are specified
using a binding declaration, which you define using a <sgmltag
class="element">jaxws:bindings</sgmltag> tag (where the jaxws prefix is tied
to the <literal>http://java.sun.com/xml/ns/jaxws</literal> namespace). There
are two alternative ways of specifying a binding declaration:</para>

<itemizedlist>
<listitem>
<para>External binding declaration — the <sgmltag
class="element">jaxws:bindings</sgmltag> element is defined in a file
separately from the WSDL contract. You specify the location of the binding
declaration file to the wsdl2java utility when you generate the stub
code.</para>
</listitem>

<listitem>
<para>Embedded binding declaration — you can also embed the <sgmltag
class="element">jaxws:bindings</sgmltag> element directly in a WSDL contract,
treating it as a WSDL extension. In this case, the settings in <sgmltag
class="element">jaxws:bindings</sgmltag> apply only to the immediate parent
element.</para>
</listitem>
</itemizedlist>

<para>This section considers only the first approach, the external binding
declaration. The template for a binding declaration file that switches on
asynchronous invocations is shown in <xref linkend="async2" />.</para>

<example id="async2">
<title>Template for an Asynchronous Binding Declaration</title>

<programlisting><bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
wsdlLocation="<replaceable>AffectedWSDLContract</replaceable>"
xmlns="http://java.sun.com/xml/ns/jaxws">
<bindings node="<replaceable>AffectedNode</replaceable>">
<enableAsyncMapping>true</enableAsyncMapping>
</bindings>
</bindings></programlisting>
</example>

<para>Where <replaceable>AffectedWSDLContract</replaceable> specifies the URL
of the WSDL contract that is affected by this binding declaration. The
<replaceable>AffectedNode</replaceable> is an XPath value that specifies which
node (or nodes) from the WSDL contract are affected by this binding
declaration. You can set <replaceable>AffectedNode</replaceable> to <sgmltag
class="element">wsdl:definitions</sgmltag>, if you want the entire WSDL
contract to be affected. The <sgmltag
class="element">jaxws:enableAsyncMapping</sgmltag> element is set to
<constant>true</constant> to enable the asynchronous invocation
feature.</para>

<para>For example, if you want to generate asynchronous methods only for the
GreeterAsync port type, you could specify <markup><bindings
node="wsdl:definitions/wsdl:portType[@name='GreeterAsync']"></markup> in
the preceding binding declaration.</para>

<para>Assuming that the binding declaration is stored in a file,
<filename>async_binding.xml</filename>, you can generate the requisite stub
files with asynchronous support by entering the following wsdl2java
command:</para>

<screen><userinput>wsdl2java -ant -client -d ClientDir -b async_binding.xml hello_world.wsdl</userinput>
</screen>

<para>When you run the wsdl2java command, you specify the location of the
binding declaration file using the -b option. After generating the stub code
in this way, the GreeterAsync service endpoint interface (in the file
<filename>GreeterAsync.java</filename>) is defined as shown in <xref
linkend="async3" />.</para>

<example id="async3">
<title>Service Endpoint Interface with Methods for Asynchronous
Invocations</title>

<programlisting>/* Generated by WSDLToJava Compiler. */
package org.objectweb.hello_world_async_soap_http;
...
import java.util.concurrent.Future;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;
...
public interface GreeterAsync {

public Future<?> greetMeSometimeAsync(
java.lang.String requestType,
AsyncHandler<org.objectweb.hello_world_async_soap_http.types.GreetMeSometimeResponse> asyncHandler
);

public Response<org.objectweb.hello_world_async_soap_http.types.GreetMeSometimeResponse> greetMeSometimeAsync(
java.lang.String requestType
);

public java.lang.String greetMeSometime(
java.lang.String requestType
);
}</programlisting>
</example>

<para>In addition to the usual synchronous method,
<methodname>greetMeSometime()</methodname>, two asynchronous methods are also
generated for the greetMeSometime operation, as follows:</para>

<itemizedlist>
<listitem>
<para><methodname>greetMeSometimeAsync()</methodname> method with
<classname>Future<?></classname> return type and an extra
<classname>javax.xml.ws.AsyncHandler</classname> parameter — call this method
for the callback approach to asynchronous invocation.</para>
</listitem>

<listitem>
<para><methodname>greetMeSometimeAsync()</methodname> method with
<classname>Response<GreetMeSometimeResponse></classname> return type —
call this method for the polling approach to asynchronous invocation</para>
</listitem>
</itemizedlist>

<para>The details of the callback approach and the polling approach are
discussed in the following subsections.</para>
</simplesect>

<simplesect>
<title>Implementing an asynchronous client with the polling approach</title>

<para><xref linkend="async4" /> illustrates the polling approach to making an
asynchronous operation call. Using this approach, the client invokes the
operation by calling the special Java method,
<methodname><replaceable>OperationName</replaceable>Async()</methodname>, that
returns a <classname>javax.xml.ws.Response<T></classname> object, where
T is the type of the operation's response message. The
<classname>Response<T></classname> object can be polled at a later stage
to check whether the operation's response message has arrived.</para>

<example id="async4">
<title>Polling Approach for an Asynchronous Operation Call</title>

<programlisting>package demo.hw.client;

import java.io.File;
import java.util.concurrent.Future;

import javax.xml.namespace.QName;
import javax.xml.ws.Response;

import org.objectweb.hello_world_async_soap_http.GreeterAsync;
import org.objectweb.hello_world_async_soap_http.SOAPService;
import org.objectweb.hello_world_async_soap_http.types.GreetMeSometimeResponse;

public final class Client {
private static final QName SERVICE_NAME
= new QName("http://objectweb.org/hello_world_async_soap_http", "SOAPService");

private Client() {}

public static void main(String args[]) throws Exception {
...
// Polling approach:
Response<GreetMeSometimeResponse> greetMeSomeTimeResp =
port.greetMeSometimeAsync(System.getProperty("user.name"));
while (!greetMeSomeTimeResp.isDone())

Unknown macro: { Thread.sleep(100); }

GreetMeSometimeResponse reply = greetMeSomeTimeResp.get();
...
System.exit(0);
}
}</programlisting>
</example>

<para>The <methodname>greetMeSometimeAsync()</methodname> method invokes the
<methodname>greetMeSometimes</methodname> operation, transmitting the input
parameters to the remote service and returning a reference to a
<classname>javax.xml.ws.Response<GreetMeSometimeResponse></classname>
object. The <classname>Response</classname> class is defined by extending the
standard <interfacename>java.util.concurrency.Future<T></interfacename>
interface, which is specifically designed for polling the outcome of work
performed by a concurrent thread. There are essentially two basic approaches
to polling using the <classname>Response</classname> object:</para>

<itemizedlist>
<listitem>
<para>Non-blocking polling — before attempting to get the result, check
whether the response has arrived by calling the non-blocking
<methodname>Response<T>.isDone()</methodname> method. For
example:</para>

<programlisting>Response<GreetMeSometimeResponse> greetMeSomeTimeResp = ...;

if (greetMeSomeTimeResp.isDone()) {
GreetMeSometimeResponse reply = greetMeSomeTimeResp.get();
}</programlisting>
</listitem>

<listitem>
<para>Blocking polling — call <methodname>Response<T>.get()</methodname>
right away and block until the response arrives (optionally specifying a
timeout). For example, to poll for a response, with a 60 second
timeout:</para>

<programlisting>Response<GreetMeSometimeResponse> greetMeSomeTimeResp = ...;

GreetMeSometimeResponse reply = greetMeSomeTimeResp.get(
60L,
java.util.concurrent.TimeUnit.SECONDS
);</programlisting>
</listitem>
</itemizedlist>
</simplesect>

<simplesect>
<title>Implementing an asynchronous client with the callback approach</title>

<para>An alternative approach to making an asynchronous operation invocation
is to implement a callback class, by deriving from the
<interfacename>javax.xml.ws.AsyncHandler</interfacename> interface. This
callback class must implement a <methodname>handleResponse()</methodname>
method, which is called by the CeltiXfire runtime to notify the client that
the response has arrived. <xref linkend="async5" /> shows an outline of the
<interfacename>AsyncHandler</interfacename> interface that you need to
implement.</para>

<example id="async5">
<title>The javax.xml.ws.AsyncHandler Interface</title>

<programlisting>package javax.xml.ws;

public interface AsyncHandler<T>
{
void handleResponse(Response<T> res);
}</programlisting>
</example>

<para>In this example, a callback class,
<classname>TestAsyncHandler</classname>, is defined as shown in <xref
linkend="async6" />.</para>

<example id="async6">
<title>The TestAsyncHandler Callback Class</title>

<programlisting>package demo.hw.client;

import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;

import org.objectweb.hello_world_async_soap_http.types.GreetMeSometimeResponse;

public class TestAsyncHandler implements AsyncHandler<GreetMeSometimeResponse> {
private GreetMeSometimeResponse reply;

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

Unknown macro: { reply = response.get(); }

catch (Exception ex)

Unknown macro: { ex.printStackTrace(); }

}

public String getResponse()

Unknown macro: { return reply.getResponseType(); }

}</programlisting>
</example>

<para>The implementation of <methodname>handleResponse()</methodname> shown in
<xref linkend="async6" /> simply gets the response data and stores it in a
member variable, <varname>reply</varname>. The extra
<methodname>getResponse()</methodname> method is just a convenience method
that extracts the sole output parameter (that is, responseType) from the
response.</para>

<para><xref linkend="async7" /> illustrates the callback approach to making an
asynchronous operation call. Using this approach, the client invokes the
operation by calling the special Java method,
<methodname><replaceable>OperationName</replaceable>Async()</methodname>, that
returns a <classname>java.util.concurrency.Future<?></classname> object
and takes an extra parameter of
<classname>AsyncHandler<T></classname>.</para>

<example id="async7">
<title>Callback Approach for an Asynchronous Operation Call</title>

<programlisting>package demo.hw.client;

import java.io.File;
import java.util.concurrent.Future;

import javax.xml.namespace.QName;
import javax.xml.ws.Response;

import org.objectweb.hello_world_async_soap_http.GreeterAsync;
import org.objectweb.hello_world_async_soap_http.SOAPService;
import org.objectweb.hello_world_async_soap_http.types.GreetMeSometimeResponse;

public final class Client {
private static final QName SERVICE_NAME
= new QName("http://objectweb.org/hello_world_async_soap_http", "SOAPService");

private Client() {}

public static void main(String args[]) throws Exception {
...
// Callback approach
TestAsyncHandler testAsyncHandler = new TestAsyncHandler();
System.out.println("Invoking greetMeSometimeAsync using callback object...");
Future<?> response = port.greetMeSometimeAsync(System.getProperty("user.name"), testAsyncHandler);
while (!response.isDone())

Unknown macro: { Thread.sleep(100); }

resp = testAsyncHandler.getResponse();
...
System.exit(0);
}
}</programlisting>
</example>

<para>The <classname>Future<?></classname> object returned by
<methodname>greetMeSometimeAsync()</methodname> can be used only to test
whether or not a response has arrived yet — for example, by calling
<methodname>response.isDone()</methodname>. The value of the response is only
made available to the callback object,
<classname>testAsyncHandler</classname>.</para>
</simplesect>

  • No labels