Parts 1 through 3 of this four-part series on developing Web services in Java SE first presented an overview of Web services and Java SE’s support for developing them. The series then focused on developing SOAP-based and RESTful Web services via this support. Part 4 wraps up this series by focusing on advanced topics.
This article first introduces Java SE’s SAAJ API for working with SOAP-based Web services at a lower level. It then discusses how to create a JAX-WS handler to log the flow of SOAP messages. Next, the article teaches how to create and install a custom lightweight HTTP server to perform authentication.
Moving on, you’re shown how to create a RESTful Web service that returns attachments (e.g., a JPEG image) to its clients. You then dig deeper into JAX-WS by exploring the interplay between providers and dispatch clients, and learn how to create a dispatch client that accesses the
javax.xml.transform.Source instance returned from a Web service provider’s
invoke() method via a different
Source instance in another version of Part 3‘s
Working with SAAJ
Soap with Attachments API for Java (SAAJ) is the Java API for creating, sending, and receiving SOAP messages that may or may not have MIME-typed attachments. SAAJ is a lower-level alternative to JAX-WS for sending and receiving SOAP messages.
This section first presents an overview of SOAP message architecture. It then takes you on a tour of SAAJ. When this tour finishes, I present an application that uses this API to access a SOAP-based Web service (written in PHP) for converting between integer values and Roman numerals. This application reinforces your understanding of SAAJ.
SOAP message architecture
A SOAP message is an XML document sent from an initial SOAP sender node to an ultimate SOAP receiver node, mostly likely passing through intermediate SOAP sender/receiver nodes along its path. A SOAP node is processing logic that operates on a SOAP message.
The SOAP document consists of an
Envelope root element that encapsulates an optional
Header element and a nonoptional
Body element — see Figure 1.
Figure 1. A SOAP message’s architecture consists of an optional
Header element and a mandatory
Body element within an
Header element specifies application-related information (such as authentication details to verify who sent the message) via immediate child elements known as header blocks. A header block represents a logical grouping of data that can target an intermediate SOAP node or the ultimate receiver node.
Although header blocks are defined by the application, their start tags may contain the following SOAP-defined attributes to indicate how SOAP nodes should process them:
encodingStyleidentifies the rules used to serialize parts of a SOAP message
roleidentifies the SOAP node (via a URI) to which the header block is targeted — this SOAP 1.2-introduced attribute replaces the SOAP 1.1 actor attribute, which performs the same function
mustUnderstandindicates whether processing of the header block is mandatory (value
1in SOAP 1.1;
truein SOAP 1.2) or optional (value
0in SOAP 1.1;
falsein SOAP 1.2)
relayindicates whether the header block targeted at a SOAP receiver must be relayed to another node if not processed — this attribute was introduced in SOAP 1.2
Body element contains information that targets the ultimate receiver node. This information is known as the payload, and consists of a SOAP-defined
Fault child element describing a fault (an error being reported by the Web service), or child elements that are specific to the Web service.
Fault element contains error and status information that a Web service returns to a client. SOAP 1.1 specifies the following child elements of
faultcode: This mandatory element provides information about the fault in a form that can be processed by software. SOAP defines a small set of SOAP fault codes that cover basic faults; this set can be extended by applications.
faultstring: This mandatory element provides information about the fault in a human-readable format.
faultactor: This element contains the URI of the SOAP node that generated the fault. A SOAP node that is not the ultimate SOAP receiver must include
faultactorwhen creating a fault; an ultimate SOAP receiver doesn’t have to include this element, but might choose to do so.
detail: This element carries application-specific error information related to the
Bodyelement. It must be present when
Body‘s contents couldn’t be processed successfully. The
detailelement must not be used to carry error information belonging to header blocks; detailed error information belonging to header blocks is carried within these blocks.
SOAP 1.2 specifies the following child elements of
Code: This mandatory element provides information about the fault in a form that can be processed by software. It contains a
Valueelement and an optional
Reason: This mandatory element provides information about the fault in a human-readable format.
Reasoncontains one or more
Textelements, each of which contains information about the fault in a different language.
Node: This element contains the URI of the SOAP node that generated the fault. A SOAP node that’s not the ultimate SOAP receiver must include
Nodewhen creating a fault; an ultimate SOAP receiver doesn’t have to include this element, but might choose to do so.
Role: This element contains a URI that identifies the role the node was operating in when the fault occurred.
Detail: This optional element contains application-specific error information related to the SOAP fault codes describing the fault. Its presence has no significance as to which parts of the faulty SOAP message were processed.
Listing 1 presents an example SOAP message.
Listing 1. A SOAP message for calling a SOAP-based library Web service’s
getTitle() function to retrieve a book’s title when given its ISBN
This SOAP message describes a request to a library Web service to execute its
getTitle() function. Furthermore, it describes the type and value of the ISBN argument passed to this function’s
The message begins with the
tag, which describes the SOAP message’s envelope. The commonly used
SOAP-ENV prefix corresponds to the SOAP 1.1 namespace that provides the schema for SOAP envelopes. The
xsi prefixes correspond to the XML Schema structures and XML Schema Instance namespaces, and are used to denote the XML Schema type that describes the kind of data being passed to
getTitle() (a string) via the
Header element signifies that there is no SOAP header. In contrast, the
Body element identifies a single
getTitle operation request.
getTitle element is namespace-qualified, as recommended by the SOAP 1.1 and 1.2 specifications. In contrast, the
isbn child element of
getTitle isn’t namespace-qualified because it inherits
getTitle‘s namespace — the SOAP 1.1 and 1.2 specifications don’t mandate that such child elements be namespace-qualified.
SAAJ API overview
SAAJ is a small Java SE API that lets you perform the following tasks:
- create an endpoint-to-endpoint connection
- create a SOAP message
- create an XML fragment
- add content to the header of a SOAP message
- add content to the body of a SOAP message
- create attachment parts and add content to them
- access/add/modify parts of a SOAP message
- create/add/modify SOAP fault information
- extract content from a SOAP message
- send a SOAP request-response message
SAAJ is associated with the
javax.xml.soap package, which contains 14 interfaces and 13 classes. Various interfaces and classes extend their counterparts in the
org.w3c.dom package, implying that part of a SOAP message is organized as a tree of nodes.
The following classes and interfaces are used to specify the structure of a SOAP message:
SOAPMessagerepresents the entire SOAP message. It contains a single
SOAPPartinstance and zero or more
SOAPEnvelopeinstance, which represents the actual SOAP
SOAPEnvelopeoptionally contains a
SOAPHeaderinstance and also contains a mandatory
SOAPHeaderrepresents the SOAP message’s header block(s).
SOAPBodycontains either a
SOAPFaultobject or a
SOAPBodyElementobject containing the actual SOAP payload XML content.
SOAPFaultstores a SOAP fault message.
Working with SAAJ involves creating a SOAP connection, creating SOAP messages, populating each message with content and optional attachments, sending the messages to an endpoint and retrieving replies, and closing the connection.
Creating a SOAP connection
You create a connection by working with the
SOAPConnection classes. As its name implies,
SOAPConnectionFactory is a factory class for retrieving
SOAPConnection instances (actually, instances of subclasses of the abstract
SOAPConnection class). A
SOAPConnection instance represents an endpoint-to-endpoint connection to the Web service; the client and Web service exchange messages over this connection. The following example shows you how to instantiate the factory and obtain a SOAP connection:
SOAPConnectionFactory soapcf = SOAPConnectionFactory.newInstance(); SOAPConnection soapc = soapcf.createConnection();
Instantiate the factory by calling
SOAPConnectionFactory newInstance() method. This method throws
SOAPException when a
SOAPConnectionFactory instance cannot be created. If a nonOracle Java implementation doesn’t support the SAAJ communication infrastructure, this method throws an instance of the
SOAPConnectionFactory, call this instance’s
SOAPConnection createConnection() method to create and return a new
SOAPConnection object. This method throws
SOAPException when it’s unable to create this object.
Creating a SOAP message
Create a SOAP message by working with the
MessageFactory provides a pair of methods for returning a
MessageFactory newInstance()creates a
MessageFactoryobject based on the default SOAP 1.1 implementation. This method follows an ordered lookup procedure to locate the
MessageFactoryimplementation class. This procedure first examines the
javax.xml.soap.MessageFactorysystem property, and lastly calls an instance of the
MessageFactory newMessageFactory(String protocol)method to return that factory. This method throws
SOAPExceptionwhen it’s unable to create the factory.
MessageFactory newInstance(String protocol)creates a
MessageFactoryobject that’s based on the SOAP implementation specified by the
protocolargument, which is one of the
SOAP_1_2_PROTOCOLconstants. This method throws
SOAPExceptionwhen it’s unable to create the factory.
MessageFactory, call one of the following methods to create a
SOAPMessage createMessage()creates and returns a new
SOAPMessageobject (actually, an instance of a concrete subclass of this abstract class) with default
SOAPBody(initially empty) and
SOAPHeaderobjects. This method throws
SOAPMessageinstance cannot be created, and
MessageFactoryinstance’s protocol is
SOAPMessage createMessage(MimeHeaders headers, InputStream in)internalizes the contents of the given
java.io.InputStreamobject into a new
SOAPMessageobject and returns this object. The
MimeHeadersinstance specifies transport-specific headers that describe the various attachments to the SOAP message. This method throws
SOAPMessageinstance cannot be created,
java.io.IOExceptionwhen there’s a problem reading data from the input stream, and
MessageFactoryinstance requires one or more MIME headers to be present in the argument passed to headers and these headers are missing.
The following example shows you how to instantiate the factory and create a
SOAPMessage object that’s ready to be populated:
MessageFactory mf = MessageFactory.newInstance(); SOAPMessage soapm = mf.createMessage();
Populating a SOAP message with content and optional attachments
SOAPMessage describes a SOAP message optionally followed by MIME-typed attachments. The SOAP message part of this object is defined by an instance of a concrete subclass of the abstract