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.
Tip
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> { ... }
Tip
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 thegetNode()
method. Nodes can be either updated or added to the DOM tree using thesetNode()
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 anXMLReader
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 aProvider<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 aProvider<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 thewsdl:operation
element that corresponds to the operation that is invoked.WarningIf the service uses doc/literal bare messages, the root element of the request is based on the value ofname
attribute of thewsdl:part
element referred to by thewsdl: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.ImportantThe 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.
Property | Description |
---|---|
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; 1@WebServiceProvider(portName="stockQuoteReporterPort" serviceName="stockQuoteReporter") 2@ServiceMode(value="Service.Mode.MESSAGE") public class stockQuoteReporterProvider implements Provider<SOAPMessage> { 3public stockQuoteReporterProvider() { } 4public SOAPMessage invoke(SOAPMessage request) { 5 SOAPBody requestBody = request.getSOAPBody(); 6 if(requestBody.getElementName.getLocalName.equals("getStockPrice")) { 7 MessageFactory mf = MessageFactory.newInstance(); SOAPFactory sf = SOAPFactory.newInstance(); 8 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(); 9 return response; } ... } }
The code in Example 41.11, “Provider<SOAPMessage> Implementation” does the following:
- 1
- Specifies that the following class implements a
Provider
object that implements the service whosewsdl:service
element is namedstockQuoteReporter
, and whosewsdl:port
element is namedstockQuoteReporterPort
. - 2
- Specifies that this
Provider
implementation uses message mode. - 3
- Provides the required default public constructor.
- 4
- Provides an implementation of the
invoke()
method that takes aSOAPMessage
object and returns aSOAPMessage
object. - 5
- Extracts the request message from the body of the incoming SOAP message.
- 6
- Checks the root element of the request message to determine how to process the request.
- 7
- Creates the factories required for building the response.
- 8
- Builds the SOAP message for the response.
- 9
- 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; 1@WebServiceProvider(portName="stockQuoteReporterPort" serviceName="stockQuoteReporter") 2@ServiceMode(value="Service.Mode.PAYLOAD") public class stockQuoteReporterProvider implements Provider<DOMSource> 3public stockQuoteReporterProvider() { } 4public DOMSource invoke(DOMSource request) { DOMSource response = new DOMSource(); ... return response; } }
The code in Example 41.12, “Provider<DOMSource> Implementation” does the following:
- 1
- Specifies that the class implements a
Provider
object that implements the service whosewsdl:service
element is namedstockQuoteReporter
, and whosewsdl:port
element is namedstockQuoteReporterPort
. - 2
- Specifies that this
Provider
implementation uses payload mode. - 3
- Provides the required default public constructor.
- 4
- Provides an implementation of the
invoke()
method that takes aDOMSource
object and returns aDOMSource
object.