13.4.2. Develop a JAX-WS Client Application

This topic discusses JAX-WS Web Service clients in general. The client communicates with, and requests work from, the JAX-WS endpoint, which is deployed in the Java Enterprise Edition 6 container. For detailed information about the classes, methods, and other implementation details mentioned below, refer to Section 13.5.2, “JAX-WS Common API Reference” and the relevant sections of the Javadocs bundle included with JBoss EAP 6.

Service

Overview
A Service is an abstraction which represents a WSDL service. A WSDL service is a collection of related ports, each of which includes a port type bound to a particular protocol and a particular endpoint address.
Usually, the Service is generated when the rest of the component stubs are generated from an existing WSDL contract. The WSDL contract is available via the WSDL URL of the deployed endpoint, or can be created from the endpoint source using the wsprovide.sh command in the EAP_HOME/bin/ directory.
This type of usage is referred to as the static use case. In this case, you create instances of the Service class which is created as one of the component stubs.
You can also create the service manually, using the Service.create method. This is referred to as the dynamic use case.
Usage
Static Use Case
The static use case for a JAX-WS client assumes that you already have a WSDL contract. This may be generated by an external tool or generated by using the correct JAX-WS annotations when you create your JAX-WS endpoint.
To generate your component stubs, you use the wsconsume.sh or wsconsume.bat script which is included in EAP_HOME/bin/. The script takes the WSDL URL or file as a parameter, and generates multiple of files, structured in a directory tree. The source and class files representing your Service are named CLASSNAME_Service.java and CLASSNAME_Service.class, respectively.
The generated implementation class has two public constructors, one with no arguments and one with two arguments. The two arguments represent the WSDL location (a java.net.URL) and the service name (a javax.xml.namespace.QName) respectively.
The no-argument constructor is the one used most often. In this case the WSDL location and service name are those found in the WSDL. These are set implicitly from the @WebServiceClient annotation that decorates the generated class.

Example 13.19. Example Generated Service Class

@WebServiceClient(name="StockQuoteService", targetNamespace="http://example.com/stocks", wsdlLocation="http://example.com/stocks.wsdl")
public class StockQuoteService extends javax.xml.ws.Service
{
   public StockQuoteService()
   {
      super(new URL("http://example.com/stocks.wsdl"), new QName("http://example.com/stocks", "StockQuoteService"));
   }

   public StockQuoteService(String wsdlLocation, QName serviceName)
   {
      super(wsdlLocation, serviceName);
   }

   ...
}
Dynamic Use Case
In the dynamic case, no stubs are generated automatically. Instead, a web service client uses the Service.create method to create Service instances. The following code fragment illustrates this process.

Example 13.20. Creating Services Manually

URL wsdlLocation = new URL("http://example.org/my.wsdl");
QName serviceName = new QName("http://example.org/sample", "MyService");
Service service = Service.create(wsdlLocation, serviceName);

Handler Resolver
JAX-WS provides a flexible plug-in framework for message processing modules, known as handlers. These handlers extend the capabilities of a JAX-WS runtime system. A Service instance provides access to a HandlerResolver via a pair of getHandlerResolver and setHandlerResolver methods that can configure a set of handlers on a per-service, per-port or per-protocol binding basis.
When a Service instance creates a proxy or a Dispatch instance, the handler resolver currently registered with the service creates the required handler chain. Subsequent changes to the handler resolver configured for a Service instance do not affect the handlers on previously created proxies or Dispatch instances.
Executor
Service instances can be configured with a java.util.concurrent.Executor. The Executor invokes any asynchronous callbacks requested by the application. The setExecutor and getExecutor methods of Service can modify and retrieve the Executor configured for a service.
Dynamic Proxy

A dynamic proxy is an instance of a client proxy using one of the getPort methods provided in the Service. The portName specifies the name of the WSDL port the service uses. The serviceEndpointInterface specifies the service endpoint interface supported by the created dynamic proxy instance.

Example 13.21. getPort Methods

public <T> T getPort(QName portName, Class<T> serviceEndpointInterface)
public <T> T getPort(Class<T> serviceEndpointInterface)
The Service Endpoint Interface is usually generated using the wsconsume.sh command, which parses the WSDL and creates Java classes from it.
A typed method which returns a port is also provided. These methods also return dynamic proxies that implement the SEI. See the following example.

Example 13.22. Returning the Port of a Service

@WebServiceClient(name = "TestEndpointService", targetNamespace = "http://org.jboss.ws/wsref",
   wsdlLocation = "http://localhost.localdomain:8080/jaxws-samples-webserviceref?wsdl")

public class TestEndpointService extends Service
{
    ...

    public TestEndpointService(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }

    @WebEndpoint(name = "TestEndpointPort")
    public TestEndpoint getTestEndpointPort()
    {
        return (TestEndpoint)super.getPort(TESTENDPOINTPORT, TestEndpoint.class);
    }
}

@WebServiceRef

The @WebServiceRef annotation declares a reference to a Web Service. It follows the resource pattern shown by the javax.annotation.Resource annotation defined in http://www.jcp.org/en/jsr/summary?id=250.

Use Cases for @WebServiceRef

  • You can use it to define a reference whose type is a generated Service class. In this case, the type and value element each refer to the generated Service class type. Moreover, if the reference type can be inferred by the field or method declaration the annotation is applied to, the type and value elements may (but are not required to) have the default value of Object.class. If the type cannot be inferred, then at least the type element must be present with a non-default value.
  • You can use it to define a reference whose type is an SEI. In this case, the type element may (but is not required to) be present with its default value if the type of the reference can be inferred from the annotated field or method declaration. However, the value element must always be present and refer to a generated service class type, which is a subtype of javax.xml.ws.Service. The wsdlLocation element, if present, overrides the WSDL location information specified in the @WebService annotation of the referenced generated service class.

    Example 13.23. @WebServiceRef Examples

    public class EJB3Client implements EJB3Remote
    {
       @WebServiceRef
       public TestEndpointService service4;
    
       @WebServiceRef
       public TestEndpoint port3;
    
Dispatch

XML Web Services use XML messages for communication between the endpoint, which is deployed in the Java EE container, and any clients. The XML messages use an XML language called Simple Object Access Protocol (SOAP). The JAX-WS API provides the mechanisms for the endpoint and clients to each be able to send and receive SOAP messages and convert SOAP messages into Java, and vice versa. This is called marshalling and unmarshalling.

In some cases, you need access to the raw SOAP messages themselves, rather than the result of the conversion. The Dispatch class provides this functionality. Dispatch operates in one of two usage modes, which are identified by one of the following constants.
  • javax.xml.ws.Service.Mode.MESSAGE - This mode directs client applications to work directly with protocol-specific message structures. When used with a SOAP protocol binding, a client application works directly with a SOAP message.
  • javax.xml.ws.Service.Mode.PAYLOAD - This mode causes the client to work with the payload itself. For instance, if it is used with a SOAP protocol binding, a client application would work with the contents of the SOAP body rather than the entire SOAP message.
Dispatch is a low-level API which requires clients to structure messages or payloads as XML, with strict adherence to the standards of the individual protocol and a detailed knowledge of message or payload structure. Dispatch is a generic class which supports input and output of messages or message payloads of any type.

Example 13.24. Dispatch Usage

Service service = Service.create(wsdlURL, serviceName);
Dispatch dispatch = service.createDispatch(portName, StreamSource.class, Mode.PAYLOAD);

String payload = "<ns1:ping xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>";
dispatch.invokeOneWay(new StreamSource(new StringReader(payload)));

payload = "<ns1:feedback xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>";
Source retObj = (Source)dispatch.invoke(new StreamSource(new StringReader(payload)));	

Asynchronous Invocations

The BindingProvider interface represents a component that provides a protocol binding which clients can use. It is implemented by proxies and is extended by the Dispatch interface.

BindingProvider instances may provide asynchronous operation capabilities.Asynchronous operation invocations are decoupled from the BindingProvider instance at invocation time. The response context is not updated when the operation completes. Instead, a separate response context is made available using the Response interface.

Example 13.25. Example Asynchronous Invocation

public void testInvokeAsync() throws Exception
{
   URL wsdlURL = new URL("http://" + getServerHost() + ":8080/jaxws-samples-asynchronous?wsdl");
   QName serviceName = new QName(targetNS, "TestEndpointService");
   Service service = Service.create(wsdlURL, serviceName);
   TestEndpoint port = service.getPort(TestEndpoint.class);
   Response response = port.echoAsync("Async");
   // access future
   String retStr = (String) response.get();
   assertEquals("Async", retStr);
}
@Oneway Invocations

The @Oneway annotation indicates that the given web method takes an input message but returns no output message. Usually, a @Oneway method returns the thread of control to the calling application before the business method is executed.

Example 13.26. Example @Oneway Invocation

@WebService (name="PingEndpoint")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class PingEndpointImpl
{
   private static String feedback;
  
   @WebMethod
   @Oneway
   public void ping()
   {
      log.info("ping");
      feedback = "ok";
   }
  
   @WebMethod
   public String feedback()
   {
      log.info("feedback");
      return feedback;
   }
}
Timeout Configuration

Two different properties control the timeout behavior of the HTTP connection and the timeout of a client which is waiting to receive a message. The first is javax.xml.ws.client.connectionTimeout and the second is javax.xml.ws.client.receiveTimeout. Each is expressed in milliseconds, and the correct syntax is shown below.

Example 13.27. JAX-WS Timeout Configuration

public void testConfigureTimeout() throws Exception
{
   //Set timeout until a connection is established
   ((BindingProvider)port).getRequestContext().put("javax.xml.ws.client.connectionTimeout", "6000");

   //Set timeout until the response is received
   ((BindingProvider) port).getRequestContext().put("javax.xml.ws.client.receiveTimeout", "1000");

   port.echo("testTimeout");
}