Chapter 41. Using Raw XML Messages

Abstract

The high-level JAX-WS APIs shield the developer from using native XML messages by marshaling the data into JAXB objects. However, there are cases when it is better to have direct access to the raw XML message data that is passing on the wire. The JAX-WS APIs provide two interfaces that provide access to the raw XML: the Dispatch interface is the client-side interface, and the Provider interface is the server-side interface.

41.1. Using XML in a Consumer

Abstract

The Dispatch interface is a low-level JAX-WS API that allows you work directly with raw messages. It accepts and returns messages, or payloads, of a number of types including DOM objects, SOAP messages, and JAXB objects. Because it is a low-level API, the Dispatch interface does not perform any of the message preparation that the higher-level JAX-WS APIs perform. You must ensure that the messages, or payloads, that you pass to the Dispatch object are properly constructed, and make sense for the remote operation being invoked.

41.1.1. Usage Modes

Overview

Dispatch objects have two usage modes:

The usage mode you specify for a Dispatch object determines the amount of detail that is passed to the user level code.

Message mode

In message mode, a Dispatch object works with complete messages. A complete message includes any binding specific headers and wrappers. For example, a consumer interacting with a service that requires SOAP messages must provide the Dispatch object’s invoke() method a fully specified SOAP message. The invoke() method also returns a fully specified SOAP message. The consumer code is responsible for completing and reading the SOAP message’s headers and the SOAP message’s envelope information.

Message mode is not ideal when working with JAXB objects.

To specify that a Dispatch object uses message mode provide the value java.xml.ws.Service.Mode.MESSAGE when creating the Dispatch object. For more information about creating a Dispatch object see the section called “Creating a Dispatch object”.

Payload mode

In payload mode, also called message payload mode, a Dispatch object works with only the payload of a message. For example, a Dispatch object working in payload mode works only with the body of a SOAP message. The binding layer processes any binding level wrappers and headers. When a result is returned from the invoke() method the binding level wrappers and headers are already striped away, and only the body of the message is left.

When working with a binding that does not use special wrappers, such as the Apache CXF XML binding, payload mode and message mode provide the same results.

To specify that a Dispatch object uses payload mode provide the value java.xml.ws.Service.Mode.PAYLOAD when creating the Dispatch object. For more information about creating a Dispatch object see the section called “Creating a Dispatch object”.

41.1.2. Data Types

Overview

Because Dispatch objects are low-level objects, they are not optimized for using the same JAXB generated types as the higher level consumer APIs. Dispatch objects work with the following types of objects:

Using Source objects

A Dispatch object accepts and returns objects that are derived from the javax.xml.transform.Source interface. Source objects are supported by any binding, and in either message mode or payload mode.

Source objects are low level objects that hold XML documents. Each Source implementation provides methods that access the stored XML documents and then manipulate its contents. The following objects implement the Source interface:

DOMSource
Holds XML messages as a Document Object Model(DOM) tree. The XML message is stored as a set of Node objects that are accessed using the getNode() method. Nodes can be either updated or added to the DOM tree using the setNode() method.
SAXSource
Holds XML messages as a Simple API for XML (SAX) object. SAX objects contain an InputSource object that holds the raw data and an XMLReader object that parses the raw data.
StreamSource
Holds XML messages as a data stream. The data stream can be manipulated the same as any other data stream.

If you create your Dispatch object so that it uses generic Source objects, Apache CXF returns the messages as SAXSource objects.

This behavior can be changed using the endpoint’s source-preferred-format property. See Part IV, “Configuring Web Service Endpoints” for information about configuring the Apache CXF runtime.

Using SOAPMessage objects

Dispatch objects can use javax.xml.soap.SOAPMessage objects when the following conditions are true:

  • The Dispatch object is using the SOAP binding
  • The Dispatch object is using message mode

A SOAPMessage object holds a SOAP message. They contain one SOAPPart object and zero or more AttachmentPart objects. The SOAPPart object contains the SOAP specific portions of the SOAP message including the SOAP envelope, any SOAP headers, and the SOAP message body. The AttachmentPart objects contain binary data that is passed as an attachment.

Using DataSource objects

Dispatch objects can use objects that implement the javax.activation.DataSource interface when the following conditions are true:

  • The Dispatch object is using the HTTP binding
  • The Dispatch object is using message mode

DataSource objects provide a mechanism for working with MIME typed data from a variety of sources, including URLs, files, and byte arrays.

Using JAXB objects

While Dispatch objects are intended to be low level APIs that allow you to work with raw messages, they also allow you to work with JAXB objects. To work with JAXB objects a Dispatch object must be passed a JAXBContext that can marshal and unmarshal the JAXB objects in use. The JAXBContext is passed when the Dispatch object is created.

You can pass any JAXB object understood by the JAXBContext object as the parameter to the invoke() method. You can also cast the returned message into any JAXB object understood by the JAXBContext object.

For information on creating a JAXBContext object see Chapter 39, Using A JAXBContext Object.

41.1.3. Working with Dispatch Objects

Procedure

To use a Dispatch object to invoke a remote service the following sequence should be followed:

  1. Create a Dispatch object.
  2. Construct a request message.
  3. Call the proper invoke() method.
  4. Parse the response message.

Creating a Dispatch object

To create a Dispatch object do the following:

  1. Create a Service object to represent the wsdl:service element that defines the service on which the Dispatch object will make invocations. See Section 25.2, “Creating a Service Object”.
  2. Create the Dispatch object using the Service object’s createDispatch() method, shown in Example 41.1, “The createDispatch() Method”.

    Example 41.1. The createDispatch() Method

    publicDispatch<T>createDispatchQNameportNamejava.lang.Class<T>typeService.ModemodeWebServiceException

    Note

    If you are using JAXB objects the method signature for createDispatch() is: publicDispatch<T>createDispatchQNameportNamejavax.xml.bind.JAXBContextcontextService.ModemodeWebServiceException

    Table 41.1, “Parameters for createDispatch() describes the parameters for the createDispatch() method.

    Table 41.1. Parameters for createDispatch()

    ParameterDescription

    portName

    Specifies the QName of the wsdl:port element that represents the service provider where the Dispatch object will make invocations.

    type

    Specifies the data type of the objects used by the Dispatch object. See Section 41.1.2, “Data Types”. When working with JAXB objects, this parameter specifies the JAXBContext object used to marshal and unmarshal the JAXB objects.

    mode

    Specifies the usage mode for the Dispatch object. See Section 41.1.1, “Usage Modes”.

Example 41.2, “Creating a Dispatch Object” shows the code for creating a Dispatch object that works with DOMSource objects in payload mode.

Example 41.2. Creating a Dispatch Object

package com.fusesource.demo;

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

public class Client
{
public static void main(String args[])
  {
    QName serviceName = new QName("http://org.apache.cxf", "stockQuoteReporter");
    Service s = Service.create(serviceName);

    QName portName = new QName("http://org.apache.cxf", "stockQuoteReporterPort");
    Dispatch<DOMSource> dispatch = s.createDispatch(portName,
                                                  DOMSource.class,
                                                  Service.Mode.PAYLOAD);
    ...

Constructing request messages

When working with Dispatch objects, requests must be built from scratch. The developer is responsible for ensuring that the messages passed to a Dispatch object match a request that the targeted service provider can process. This requires precise knowledge about the messages used by the service provider and what, if any, header information it requires.

This information can be provided by a WSDL document or an XML Schema document that defines the messages. While service providers vary greatly there are a few guidelines to be followed:

  • The root element of the request is based in the value of the name attribute of the wsdl:operation element corresponding to the operation being invoked.

    Warning

    If the service being invoked uses doc/literal bare messages, the root element of the request is based on the value of the name attribute of the wsdl:part element referred to by the wsdl:operation element.

  • The root element of the request is namespace qualified.
  • If the service being invoked uses rpc/literal messages, the top-level elements in the request will not be namespace qualified.

    Important

    The children of top-level elements may be namespace qualified. To be certain you must check their schema definitions.

  • If the service being invoked uses rpc/literal messages, none of the top-level elements can be null.
  • If the service being invoked uses doc/literal messages, the schema definition of the message determines if any of the elements are namespace qualified.

For more information about how services use XML messages see, the WS-I Basic Profile.

Synchronous invocation

For consumers that make synchronous invocations that generate a response, use the Dispatch object’s invoke() method shown in Example 41.3, “The Dispatch.invoke() Method”.

Example 41.3. The Dispatch.invoke() Method

TinvokeTmsgWebServiceException

The type of both the response and the request passed to the invoke() method are determined when the Dispatch object is created. For example if you create a Dispatch object using createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE), both the response and the request are SOAPMessage objects.

Note

When using JAXB objects, both the response and the request can be of any type the provided JAXBContext object can marshal and unmarshal. Also, the response and the request can be different JAXB objects.

Example 41.4, “Making a Synchronous Invocation Using a Dispatch Object” shows code for making a synchronous invocation on a remote service using a DOMSource object.

Example 41.4. Making a Synchronous Invocation Using a Dispatch Object

// Creating a DOMSource Object for the request
DocumentBuilder db = DocumentBuilderFactory.newDocumentBuilder();
Document requestDoc = db.newDocument();
Element root = requestDoc.createElementNS("http://org.apache.cxf/stockExample",
                                          "getStockPrice");
root.setNodeValue("DOW");
DOMSource request = new DOMSource(requestDoc);

// Dispatch disp created previously
DOMSource response = disp.invoke(request);

Asynchronous invocation

Dispatch objects also support asynchronous invocations. As with the higher level asynchronous APIs discussed in Chapter 40, Developing Asynchronous Applications, Dispatch objects can use both the polling approach and the callback approach.

When using the polling approach, the invokeAsync() method returns a Response<t> object that can be polled to see if the response has arrived. Example 41.5, “The Dispatch.invokeAsync() Method for Polling” shows the signature of the method used to make an asynchronous invocation using the polling approach.

Example 41.5. The Dispatch.invokeAsync() Method for Polling

Response <T>invokeAsyncTmsgWebServiceException

For detailed information on using the polling approach for asynchronous invocations see Section 40.4, “Implementing an Asynchronous Client with the Polling Approach”.

When using the callback approach, the invokeAsync() method takes an AsyncHandler implementation that processes the response when it is returned. Example 41.6, “The Dispatch.invokeAsync() Method Using a Callback” shows the signature of the method used to make an asynchronous invocation using the callback approach.

Example 41.6. The Dispatch.invokeAsync() Method Using a Callback

Future<?>invokeAsyncTmsgAsyncHandler<T>handlerWebServiceException

For detailed information on using the callback approach for asynchronous invocations see Section 40.5, “Implementing an Asynchronous Client with the Callback Approach”.

Note

As with the synchronous invoke() method, the type of the response and the type of the request are determined when you create the Dispatch object.

Oneway invocation

When a request does not generate a response, make remote invocations using the Dispatch object’s invokeOneWay(). Example 41.7, “The Dispatch.invokeOneWay() Method” shows the signature for this method.

Example 41.7. The Dispatch.invokeOneWay() Method

invokeOneWayTmsgWebServiceException

The type of object used to package the request is determined when the Dispatch object is created. For example if the Dispatch object is created using createDispatch(portName, DOMSource.class, Service.Mode.PAYLOAD), then the request is packaged into a DOMSource object.

Note

When using JAXB objects, the response and the request can be of any type the provided JAXBContext object can marshal and unmarshal.

Example 41.8, “Making a One Way Invocation Using a Dispatch Object” shows code for making a oneway invocation on a remote service using a JAXB object.

Example 41.8. Making a One Way Invocation Using a Dispatch Object

// Creating a JAXBContext and an Unmarshaller for the request
JAXBContext jbc = JAXBContext.newInstance("org.apache.cxf.StockExample");
Unmarshaller u = jbc.createUnmarshaller();

// Read the request from disk
File rf = new File("request.xml");
GetStockPrice request = (GetStockPrice)u.unmarshal(rf);

// Dispatch disp created previously
disp.invokeOneWay(request);

41.2. Using XML in a Service Provider

Abstract

The Provider interface is a low-level JAX-WS API that allows you to implement a service provider that works directly with messages as raw XML. The messages are not packaged into JAXB objects before being passed to an object that implements the Provider interface.

41.2.1. Messaging Modes

Overview

Objects that implement the Provider interface have two messaging modes:

The messaging mode you specify determines the level of messaging detail that is passed to your implementation.

Message mode

When using message mode, a Provider implementation works with complete messages. A complete message includes any binding specific headers and wrappers. For example, a Provider implementation that uses a SOAP binding receives requests as fully specified SOAP message. Any response returned from the implementation must be a fully specified SOAP message.

To specify that a Provider implementation uses message mode by provide the value java.xml.ws.Service.Mode.MESSAGE as the value to the javax.xml.ws.ServiceMode annotation, as shown in Example 41.9, “Specifying that a Provider Implementation Uses Message Mode”.

Example 41.9. Specifying that a Provider Implementation Uses Message Mode

@WebServiceProvider
@ServiceMode(value=Service.Mode.MESSAGE)
public class stockQuoteProvider implements Provider<SOAPMessage>
{
  ...
}

Payload mode

In payload mode a Provider implementation works with only the payload of a message. For example, a Provider implementation working in payload mode works only with the body of a SOAP message. The binding layer processes any binding level wrappers and headers.

When working with a binding that does not use special wrappers, such as the Apache CXF XML binding, payload mode and message mode provide the same results.

To specify that a Provider implementation uses payload mode by provide the value java.xml.ws.Service.Mode.PAYLOAD as the value to the javax.xml.ws.ServiceMode annotation, as shown in Example 41.10, “Specifying that a Provider Implementation Uses Payload Mode”.

Example 41.10. Specifying that a Provider Implementation Uses Payload Mode

@WebServiceProvider
@ServiceMode(value=Service.Mode.PAYLOAD)
public class stockQuoteProvider implements Provider<DOMSource>
{
  ...
}

If you do not provide a value for the @ServiceMode annotation, the Provider implementation uses payload mode.

41.2.2. Data Types

Overview

Because they are low-level objects, Provider implementations cannot use the same JAXB generated types as the higher level consumer APIs. Provider implementations work with the following types of objects:

Using Source objects

A Provider implementation can accept and return objects that are derived from the javax.xml.transform.Source interface. Source objects are low level objects that hold XML documents. Each Source implementation provides methods that access the stored XML documents and manipulate its contents. The following objects implement the Source interface:

DOMSource
Holds XML messages as a Document Object Model(DOM) tree. The XML message is stored as a set of Node objects that are accessed using the getNode() method. Nodes can be either updated or added to the DOM tree using the setNode() method.
SAXSource
Holds XML messages as a Simple API for XML (SAX) object. SAX objects contain an InputSource object that holds the raw data and an XMLReader object that parses the raw data.
StreamSource
Holds XML messages as a data stream. The data stream can be manipulated the same as any other data stream.

If you create your Provider object so that it uses generic Source objects, Apache CXF returns the messages as SAXSource objects.

This behavior can be changed using the endpoint’s source-preferred-format property. See Part IV, “Configuring Web Service Endpoints” for information about configuring the Apache CXF runtime.

Important

When using Source objects the developer is responsible for ensuring that all required binding specific wrappers are added to the message. For example, when interacting with a service expecting SOAP messages, the developer must ensure that the required SOAP envelope is added to the outgoing request and that the SOAP envelope’s contents are correct.

Using SOAPMessage objects

Provider implementations can use javax.xml.soap.SOAPMessage objects when the following conditions are true:

  • The Provider implementation is using the SOAP binding
  • The Provider implementation is using message mode

A SOAPMessage object holds a SOAP message. They contain one SOAPPart object and zero or more AttachmentPart objects. The SOAPPart object contains the SOAP specific portions of the SOAP message including the SOAP envelope, any SOAP headers, and the SOAP message body. The AttachmentPart objects contain binary data that is passed as an attachment.

Using DataSource objects

Provider implementations can use objects that implement the javax.activation.DataSource interface when the following conditions are true:

  • The implementation is using the HTTP binding
  • The implementation is using message mode

DataSource objects provide a mechanism for working with MIME typed data from a variety of sources, including URLs, files, and byte arrays.

41.2.3. Implementing a Provider Object

Overview

The Provider interface is relatively easy to implement. It only has one method, invoke(), that must be implemented. In addition it has three simple requirements:

  • An implementation must have the @WebServiceProvider annotation.
  • An implementation must have a default public constructor.
  • An implementation must implement a typed version of the Provider interface.

    In other words, you cannot implement a Provider<T> interface. You must implement a version of the interface that uses a concrete data type as listed in Section 41.2.2, “Data Types”. For example, you can implement an instance of a Provider<SAXSource>.

The complexity of implementing the Provider interface is in the logic handling the request messages and building the proper responses.

Working with messages

Unlike the higher-level SEI based service implementations, Provider implementations receive requests as raw XML data, and must send responses as raw XML data. This requires that the developer has intimate knowledge of the messages used by the service being implemented. These details can typically be found in the WSDL document describing the service.

WS-I Basic Profile provides guidelines about the messages used by services, including:

  • The root element of a request is based in the value of the name attribute of the wsdl:operation element that corresponds to the operation that is invoked.

    Warning

    If the service uses doc/literal bare messages, the root element of the request is based on the value of name attribute of the wsdl:part element referred to by the wsdl:operation element.

  • The root element of all messages is namespace qualified.
  • If the service uses rpc/literal messages, the top-level elements in the messages are not namespace qualified.

    Important

    The children of top-level elements might be namespace qualified, but to be certain you will must check their schema definitions.

  • If the service uses rpc/literal messages, none of the top-level elements can be null.
  • If the service uses doc/literal messages, then the schema definition of the message determines if any of the elements are namespace qualified.

The @WebServiceProvider annotation

To be recognized by JAX-WS as a service implementation, a Provider implementation must be decorated with the @WebServiceProvider annotation.

Table 41.2, “@WebServiceProvider Properties” describes the properties that can be set for the @WebServiceProvider annotation.

Table 41.2. @WebServiceProvider Properties

PropertyDescription

portName

Specifies the value of the name attribute of the wsdl:port element that defines the service’s endpoint.

serviceName

Specifies the value of the name attribute of the wsdl:service element that contains the service’s endpoint.

targetNamespace

Specifies the targetname space of the service’s WSDL definition.

wsdlLocation

Specifies the URI for the WSDL document defining the service.

All of these properties are optional, and are empty by default. If you leave them empty, Apache CXF creates values using information from the implementation class.

Implementing the invoke() method

The Provider interface has only one method, invoke(), that must be implemented. The invoke() method receives the incoming request packaged into the type of object declared by the type of Provider interface being implemented, and returns the response message packaged into the same type of object. For example, an implementation of a Provider<SOAPMessage> interface receives the request as a SOAPMessage object and returns the response as a SOAPMessage object.

The messaging mode used by the Provider implementation determines the amount of binding specific information the request and the response messages contain. Implementations using message mode receive all of the binding specific wrappers and headers along with the request. They must also add all of the binding specific wrappers and headers to the response message. Implementations using payload mode only receive the body of the request. The XML document returned by an implementation using payload mode is placed into the body of the request message.

Examples

Example 41.11, “Provider<SOAPMessage> Implementation” shows a Provider implementation that works with SOAPMessage objects in message mode.

Example 41.11. Provider<SOAPMessage> Implementation

import javax.xml.ws.Provider;
import javax.xml.ws.Service;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;

@WebServiceProvider(portName="stockQuoteReporterPort"
                    serviceName="stockQuoteReporter")
@ServiceMode(value="Service.Mode.MESSAGE")
public class  stockQuoteReporterProvider implements Provider<SOAPMessage>
{
public stockQuoteReporterProvider()
  {
  }

public SOAPMessage invoke(SOAPMessage request)
  {
  SOAPBody requestBody = request.getSOAPBody();
  if(requestBody.getElementName.getLocalName.equals("getStockPrice"))
    {
    MessageFactory mf = MessageFactory.newInstance();
      SOAPFactory sf = SOAPFactory.newInstance();

    SOAPMessage response = mf.createMessage();
      SOAPBody respBody = response.getSOAPBody();
      Name bodyName = sf.createName("getStockPriceResponse");
      respBody.addBodyElement(bodyName);
      SOAPElement respContent = respBody.addChildElement("price");
      respContent.setValue("123.00");
      response.saveChanges();
    return response;
    }
    ...
  }
}

The code in Example 41.11, “Provider<SOAPMessage> Implementation” does the following:

Specifies that the following class implements a Provider object that implements the service whose wsdl:service element is named stockQuoteReporter, and whose wsdl:port element is named stockQuoteReporterPort.

Specifies that this Provider implementation uses message mode.

Provides the required default public constructor.

Provides an implementation of the invoke() method that takes a SOAPMessage object and returns a SOAPMessage object.

Extracts the request message from the body of the incoming SOAP message.

Checks the root element of the request message to determine how to process the request.

Creates the factories required for building the response.

Builds the SOAP message for the response.

Returns the response as a SOAPMessage object.

Example 41.12, “Provider<DOMSource> Implementation” shows an example of a Provider implementation using DOMSource objects in payload mode.

Example 41.12. Provider<DOMSource> Implementation

import javax.xml.ws.Provider;
import javax.xml.ws.Service;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;

@WebServiceProvider(portName="stockQuoteReporterPort" serviceName="stockQuoteReporter")
@ServiceMode(value="Service.Mode.PAYLOAD")
public class  stockQuoteReporterProvider implements Provider<DOMSource>
public stockQuoteReporterProvider()
  {
  }

public DOMSource invoke(DOMSource request)
  {
    DOMSource response = new DOMSource();
    ...
    return response;
  }
}

The code in Example 41.12, “Provider<DOMSource> Implementation” does the following:

Specifies that the class implements a Provider object that implements the service whose wsdl:service element is named stockQuoteReporter, and whose wsdl:port element is named stockQuoteReporterPort.

Specifies that this Provider implementation uses payload mode.

Provides the required default public constructor.

Provides an implementation of the invoke() method that takes a DOMSource object and returns a DOMSource object.