Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
titleHelloWorld 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>

...

This WSDL 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 CXF wsdl2soap or wsdl2xml utilities. Likewise, the SOAPService service can be generated automatically by running the CXF wsdl2service utility.

...

Where ClientDir is the location of a directory where you would like to put the generated files and
hello_world.wsdl is a file containing the contract shown in the WSDL above. The -ant option generates an ant build.xml file, for use with the ant build utility. The -client option generates starting point code for a client main() method.

...

  • org.apache.hello_world_soap_http
    This package name is generated from the http://apache.org/hello_world_soap_httpImage Removed 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.
  • org.apache.hello_world_soap_http.types
    This package name is generated from the http://apache.org/hello_world_soap_http/typesImage Removed target namespace. All of the XML types defined in this target namespace (that is, everything defined in the wsdl:types element of the HelloWorld contract) map to Java classes in the corresponding Java package.

...

  • Classes representing WSDL entities (in the org.apache.hello_world_soap_http package) - the following classes are generated to represent WSDL entities:
    • Greeter is a Java interface that represents the Greeter WSDL port type. In JAX-WS terminology, this Java interface is a service endpoint interface.
    • SOAPService is a Java class that represents the SOAPService WSDL service element.
    • PingMeFault is a Java exception class (extending java.lang.Exception) that represents the pingMeFault WSDL fault element.
  • Classes representing XML types (in the org.apache.hello_world_soap_http.types 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.

...

This section describes how to write the code for a simple Java client, based on the WSDL contract above. To implement the client, you need to use the following stub classes:

...

Code Block
titleOutline of a Generated Service Class

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

  public Greeter getPortName() { }
  .
  .
  .
}

...

For example, the below 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.

...

Code Block
titleThe 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;
}

...

Code Block
titleClient 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);
  }
}

...

  1. The CXF runtime is implicitly initialized - that is, provided the CXF runtime classes are loaded. Hence, there is no need to call a special function in order to initialize CXF.
  2. The client expects a single string argument that gives the location of the WSDL contract for HelloWorld. The WSDL location is stored in wsdlURL.
  3. 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:

    Code Block
    SOAPService ss = new SOAPService(wsdlURL, SERVICE_NAME);
    Greeter port = ss.getSoapPort();

    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 get PortName () 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.

  4. The client proceeds to call each of the methods supported by the Greeter service endpoint interface.
  5. In the case of the pingMe() operation, the example code shows how to catch the PingMeFault fault exception.

...

Code Block
titleSetting 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();

...

Code Block
titleReading 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);

...

CXF supports the following context properties:

Context Property Name

Context Property Type

org.apache.cxf.ws.addressing.JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES

org.apache.cxf.ws.addressing.AddressingProperties

Asynchronous Invocation Model

...

Code Block
titleHelloWorld 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>

...

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/jaxwsImage Removed namespace). There are two alternative ways of specifying a binding declaration:

...

Code Block
titleTemplate for an Asynchronous Binding Declaration

<bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
          xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
          wsdlLocation="<at:var at:name="WSDL_LOCATION" />/hello_world_async.wsdl"
          xmlns="http://java.sun.com/xml/ns/jaxws">
  <bindings node="wsdl:definitions">
    <enableAsyncMapping>true</enableAsyncMapping>
  </bindings>
</bindings>

...

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.

...

Code Block
titleService 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(
    String requestType,
    AsyncHandler<org.myorg.types.GreetMeSometimeResponse> asyncHandler
  );

  public Response<org.myorg.types.GreetMeSometimeResponse> greetMeSometimeAsync(
     String requestType);

  public java.lang.String greetMeSometime(
     String requestType
  );
}

...

The below sample illustrates the polling 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 javax.xml.ws.Response<T> object, where T is the type of the operation's response message. The Response<T> object can be polled at a later stage to check whether the operation's response message has arrived.

...

Code Block
titlePolling 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:

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

    Code Block
    Response<GreetMeSometimeResponse> greetMeSomeTimeResp = ...;
    
    if (greetMeSomeTimeResp.isDone()) {
      GreetMeSometimeResponse reply = greetMeSomeTimeResp.get();
    }
    


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

    Code Block
    
    Response<GreetMeSometimeResponse> greetMeSomeTimeResp = ...;
    
    GreetMeSometimeResponse reply = greetMeSomeTimeResp.get(
      60L,
      java.util.concurrent.TimeUnit.SECONDS
      );
    


Implementing an asynchronous client with the callback approach

An alternative approach to making an asynchronous operation invocation is to implement a callback class, by deriving from the
javax.xml.ws.AsyncHandler interface. This callback class must implement a handleResponse() method, which is called by the CXF runtime to notify the client that the response has arrived. The following shows an outline of the AsyncHandler interface that you need to implement.

...

Code Block
titleThe javax.xml.ws.AsyncHandler Interface

package javax.xml.ws;

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

...

Code Block
titleThe 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>.

...

Code Block
titleCallback 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.

Warning

Please be careful when using asynchronous consumers along with reactive / non-blocking libraries. There is certain amount of intialization code (usually, on the first asynchronous invocation) which may cause unnecessary blocking.