Developing a ConsumerPage edited by Daniel KulpChanges (1)
Full ContentDeveloping a Consumer with CXFGenerating the Stub CodeThe 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.
Basic HelloWorld WSDL contractExample1 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. Example 1:HelloWorld WSDL Contract <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions name="HelloWorld" targetNamespace="http://apache.org/hello_world_soap_http" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://apache.org/hello_world_soap_http" xmlns:x1="http://apache.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://apache.org/hello_world_soap_http/types" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://apache.org/hello_world_soap_http/types" elementFormDefault="qualified"> <simpleType name="MyStringType"> <restriction base="string"> <maxLength value="30" /> </restriction> </simpleType>
<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="tns:MyStringType"/>
</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">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="sayHi">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="sayHiRequest">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="sayHiResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="greetMe">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="greetMeRequest">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="greetMeResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="greetMeOneWay">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="greetMeOneWayRequest">
<soap:body use="literal"/>
</wsdl:input>
</wsdl:operation>
<wsdl:operation name="pingMe">
<soap:operation style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
<wsdl:fault name="pingMeFault">
<soap:fault name="pingMeFault" use="literal"/>
</wsdl:fault>
</wsdl:operation>
</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>
The Greeter port type from Example1 defines the following WSDL operations:
Example1 also defines a binding, Greeter_SOAPBinding, for the SOAP protocol. In practice, the binding is normally generated Generating the stub codeAfter defining the WSDL contract, you can generate client code using the CXF wsdl2java utility. Enter the following command at a command-line prompt: wsdl2java -ant -client -d ClientDir hello_world.wsdl Where ClientDir is the location of a directory where you would like to put the generated files and The preceding wsdl2java command generates the following Java packages:
The stub files generated by the wsdl2java command fall into the following categories:
Implementing a CXF ClientThis section describes how to write the code for a simple Java client, based on the WSDL contract from Example1. To implement the client, you need to use the following stub classes:
Generated service classExample2 shows the typical outline a generated service class, ServiceName, which extends the javax.xml.ws.Service base class. Example 2:Outline of a Generated Service Class public class ServiceName extends javax.xml.ws.Service { ... public ServiceName(URL wsdlLocation, QName serviceName) { } public ServiceName() { } public Greeter getPortName() { } . . . } The ServiceName class in Example2 defines the following methods:
Service endpoint interfaceFor 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:
For example, Example3 shows the Greeter service endpoint interface, which is generated from the Greeter port type defined in Example1. For simplicity, Example3 omits the standard JAXB and JAX-WS annotations. Example 3:The Greeter Service Endpoint Interface /* 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; } Client main functionExample4 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. Example 4:Client Implementation Code package demo.hw.client; import java.io.File; import java.net.URL; import javax.xml.namespace.QName; import org.apache.hello_world_soap_http.Greeter; import org.apache.hello_world_soap_http.PingMeFault; import org.apche.hello_world_soap_http.SOAPService; public final class Client { private static final QName SERVICE_NAME = new QName("http://apache.org/hello_world_soap_http", "SOAPService"); private Client() { } public static void main(String args[]) throws Exception { if (args.length == 0) { System.out.println("please specify wsdl"); System.exit(1); } URL wsdlURL; File wsdlFile = new File(args[0]); if (wsdlFile.exists()) { wsdlURL = wsdlFile.toURL(); } else { 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 { System.out.println("Invoking pingMe, expecting exception..."); port.pingMe(); } catch (PingMeFault ex) { System.out.println("Expected exception: PingMeFault has occurred."); System.out.println(ex.toString()); } System.exit(0); } } The Client.main() function from Example4 proceeds as follows:</para>
Setting Connection Properties with ContextsYou 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:
Setting a request contextTo set a particular request context property, ContextPropertyName, to the value, PropertyValue, use the code shown in Example4. Example 4:Setting a Request Context Property on the Client Side // 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(); You have to cast the port object to javax.xml.ws.BindingProvider in order to access the request context. The request context itself is of type, java.util.Map<String, Object>, which is a hash map that has keys of String and values of arbitrary type. Use java.util.Map.put() to create a new entry in the hash map. Reading a response contextTo retrieve a particular response context property, ContextPropertyName, use the code shown in Example5. Example 5:Reading a Response Context Property on the Client Side // 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); The response context is of type, java.util.Map<String, Object>, which is a hash map that has keys of type String and values of an arbitrary type. Use java.util.Map.get() to access an entry in the hash map of response context properties. Supported contextsCXF supports the following context properties:
Asynchronous Invocation ModelIn addition to the usual synchronous mode of invocation, CXF also supports two forms of asynchronous invocation, as follows:
Both of these asynchronous invocation approaches are described here and illustrated by code examples. Contract for asynchronous exampleExample6 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. Example 6:HelloWorld WSDL Contract for Asynchronous Example <wsdl:definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://apache.org/hello_world_async_soap_http" xmlns:x1="http://apache.org/hello_world_async_soap_http/types" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://apache.org/hello_world_async_soap_http" name="HelloWorld"> <wsdl:types> <schema targetNamespace="http://apache.org/hello_world_async_soap_http/types" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:x1="http://apache.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"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="greetMeSometime"> <soap:operation style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </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> Generating the asynchronous stub codeThe 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. 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 jaxws:bindings tag (where the jaxws prefix is tied to the http://java.sun.com/xml/ns/jaxws namespace). There are two alternative ways of specifying a binding declaration:
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 Example7. Example 7:Template for an Asynchronous Binding Declaration <bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="@WSDL_LOCATION@/hello_world_async.wsdl" xmlns="http://java.sun.com/xml/ns/jaxws"> <bindings node="wsdl:definitions"> <enableAsyncMapping>true</enableAsyncMapping> </bindings> </bindings> <para>Where AffectedWSDLContract specifies the URL of the WSDL contract that is affected by this binding declaration. The AffectedNode is an XPath value that specifies which node (or nodes) from the WSDL contract are affected by this binding declaration. You can set AffectedNode to wsdl:definitions, if you want the entire WSDL contract to be affected. The {jaxws:enableAsyncMapping}} element is set to true to enable the asynchronous invocation feature. For example, if you want to generate asynchronous methods only for the GreeterAsync port type, you could specify <bindings node="wsdl:definitions/wsdl:portType[@name='GreeterAsync']"> in the preceding binding declaration. Assuming that the binding declaration is stored in a file, async_binding.xml, you can generate the requisite stub files with asynchronous support by entering the following wsdl2java command: wsdl2java -ant -client -d ClientDir -b async_binding.xml hello_world.wsdl 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 GreeterAsync.java) is defined as shown in Example8. Example 8:Service Endpoint Interface with Methods for Asynchronous Invocations /* Generated by WSDLToJava Compiler. */ package org.apache.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.apache.hello_world_async_soap_http.types.GreetMeSometimeResponse> asyncHandler ); public Response<org.pache.hello_world_async_soap_http.types.GreetMeSometimeResponse> greetMeSometimeAsync( java.lang.String requestType ); public java.lang.String greetMeSometime( java.lang.String requestType ); } In addition to the usual synchronous method, greetMeSometime(), two asynchronous methods are also generated for the greetMeSometime operation, as follows:
The details of the callback approach and the polling approach are discussed in the following subsections. Implementing an asynchronous client with the polling approachExample9 illustrates the polling approach to making an asynchronous operation call. Using this approach, the client invokes the Example 9:Polling Approach for an Asynchronous Operation Call 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.apache.hello_world_async_soap_http.GreeterAsync; import org.apache.hello_world_async_soap_http.SOAPService; import org.apche.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()) { Thread.sleep(100); } GreetMeSometimeResponse reply = greetMeSomeTimeResp.get(); ... System.exit(0); } } The greetMeSometimeAsync() method invokes the greetMeSometimes operation, transmitting the input parameters to the remote service and returning a reference to a javax.xml.ws.Response<GreetMeSometimeResponse> object. The Response class is defined by extending the standard java.util.concurrency.Future<T> 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 Response object:
Implementing an asynchronous client with the callback approachAn alternative approach to making an asynchronous operation invocation is to implement a callback class, by deriving from the Example10: The javax.xml.ws.AsyncHandler Interface package javax.xml.ws; public interface AsyncHandler<T> { void handleResponse(Response<T> res); } In this example, a callback class, TestAsyncHandler, is defined as shown in Example11. Example 11: The TestAsyncHandler Callback Class package demo.hw.client; import javax.xml.ws.AsyncHandler; import javax.xml.ws.Response; import org.apache.hello_world_async_soap_http.types.GreetMeSometimeResponse; public class TestAsyncHandler implements AsyncHandler<GreetMeSometimeResponse> { private GreetMeSometimeResponse reply; public void handleResponse(Response<GreetMeSometimeResponse> response) { try { reply = response.get(); } catch (Exception ex) { ex.printStackTrace(); } } public String getResponse() { return reply.getResponseType(); } } The implementation of handleResponse() shown in Example11 simply gets the response data and stores it in a member variable, reply. The extra getResponse() method is just a convenience method that extracts the sole output parameter (that is, responseType) from the response. Example12 illustrates the callback approach to making an asynchronous operation call. Using this approach, the client invokes the operation by calling the special Java method, _OperationName_Async(), that returns a java.util.concurrency.Future<?> object and takes an extra parameter of AsyncHandler<T>. Callback Approach for an Asynchronous Operation Call 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.apache.hello_world_async_soap_http.GreeterAsync; import org.apache.hello_world_async_soap_http.SOAPService; import org.apache.hello_world_async_soap_http.types.GreetMeSometimeResponse; public final class Client { private static final QName SERVICE_NAME = new QName("http://apache.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()) { Thread.sleep(100); } resp = testAsyncHandler.getResponse(); ... System.exit(0); } } The Future<?> object returned by greetMeSometimeAsync() can be used only to test whether or not a response has arrived yet - for example, by calling response.isDone(). The value of the response is only made available to the callback object, testAsyncHandler.
Change Notification Preferences
View Online
|
View Changes
|
Add Comment
|
- [CONF] Apache CXF Documentation > Developing a Consumer confluence
