Web services in Java SE, Part 4: SOAP with Attachments API for Java

Learn about SAAJ and other advanced Java SE Web service features

1 2 3 4 5 6 Page 2
Page 2 of 6

SOAPPart encapsulates an instance of a class that implements the SOAPEnvelope interface, and the SOAPEnvelope instance encapsulates instances of classes that implement the SOAPHeader and SOAPBody interfaces. Call SOAPMessage's SOAPPart getSOAPPart() method to return the SOAPPart instance. You can then call SOAPPart's SOAPEnvelope getEnvelope() method to return the SOAPEnvelope instance, and call SOAPEnvelope's SOAPBody getBody() and SOAPHeader getHeader() methods to return the SOAPEnvelope instance's SOAPBody and SOAPHeader instances.

The following example shows you how to obtain the SOAPPart, SOAPEnvelope, and SOAPBody instances from the SOAPMessage instance, and also how to detach the SOAPHeader instance:

SOAPPart soapp = soapm.getSOAPPart();
SOAPEnvelope soape = soapp.getEnvelope();
SOAPBody soapb = soape.getBody();
soape.getHeader().detachNode();

SOAPEnvelope and various other interfaces extend SOAPElement, which provides methods that are applicable to different kinds of element implementation instances. For example, the SOAPElement addNamespaceDeclaration(String prefix, String uri) method is useful for adding a namespace declaration with the specified prefix and uri values to a SOAPEnvelope instance. The following example shows how to add declarations for the xsd and xsi namespaces shown in Listing 1 to its Envelope element:

soape.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
soape.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-instance");

The SOAPBody instance contains either content or a fault. Adding content to the body first requires that you create SOAPBodyElement objects (to store this content) and add these objects to the SOAPBody instance. This task is accomplished by calling either of SOAPBody's two addBodyElement() methods, which create the SOAPBodyElement object, add it to the SOAPBody object, and return a reference to the created object so that you can create method call chains.

When a new subelement of the SOAP Body element is created, you must specify a fully qualified name in the form of a javax.xml.soap.Name instance or a javax.xml.namespace.QName instance. Because the Java documentation for the Name interface states that it may be deprecated in favor of QName, you should get into the habit of using QName instead of Name. As a result, you should use SOAPBody's SOAPBodyElement addBodyElement(QName qname) method instead of using this interface's SOAPBodyElement addBodyElement(Name name) method, as demonstrated below:

QName name = new QName("http://tutortutor.ca/library", "getTitle", "lns");
SOAPElement soapel = soapb.addBodyElement(name);

SOAPBodyElement instances store subelement instances. You create these subelements and add them to the SOAPBodyElement instance by calling SOAPElement's various addChildElement() methods, such as SOAPElement addChildElement(String localName), which creates a subelement object having the specified localName, adds this subelement object to the SOAPBodyElement object on which this method is called, and returns a reference to the created SOAPElement object for chaining together method calls.

You can then attach a text node to a body element or a subelement by calling SOAPElement's SOAPElement addTextNode(String text) method. You can also call SOAPElement's void setAttribute(String name, String value) method (inherited from SOAPElement's org.w3c.dom.Element ancestor interface) to add attributes to the subelement as appropriate. The following example demonstrates:

soapel.addChildElement("isbn").addTextNode("9781484219157").setAttribute("xsi:type",
                                                                         "xsd:string");

Attachments are instances of concrete subclasses of the abstract AttachmentPart class. If you need to include an attachment with the SOAP message, call one of SOAPMessage's createAttachmentPart() methods to create and return an AttachmentPart object. After configuring this object, call SOAPMessage's void addAttachmentPart(AttachmentPart attachmentPart) method to add the given attachmentPart-referenced object to this SOAPMessage object.

Sending a SOAP message and receiving a reply

To send the SOAP message and receive a reply, invoke SOAPConnection's SOAPMessage call(SOAPMessage request, Object to) method. The specified request message is sent to the endpoint identified by to, which may be a java.lang.String or java.net.URL instance. This method throws SOAPException when a SOAP problem occurs, and blocks until it receives a SOAP message, which it returns as a SOAPMessage object. The following example provides a demonstration:

String endpoint = "http://tutortutor.ca/library/GetTitle";
// Send the request message identified by soapm to the Web service at the specified 
// endpoint and return the response message.
SOAPMessage response = soapc.call(soapm, endpoint);

Alternatively, you can call SOAPConnection's SOAPMessage get(Object to) method to request a SOAP message. As with call(), get() blocks until there's a reply, and throws SOAPException when a SOAP problem occurs.

Closing a SOAP connection

After finishing your call() and/or get() invocations, call SOAPConnection's void close() method to close the connection to the endpoint. If this method has already been called, a subsequent attempt to close the connection results in a thrown SOAPException instance.

Roman numerals and SAAJ

I've created a RomanNumerals application that demonstrates SAAJ in a more practical context. It uses this API to communicate with a SOAP-based Roman Numerals Conversion Web service, which converts between Roman numerals and base-10 integer values. This Web service's WSDL document is located at http://javajeff.ca/php/rncws.php?wsdl and appears in Listing 2.

Listing 2. WSDL for the Roman numerals/base-10 integer values conversion Web service

<definitions name="IRomanservice" 
             targetNamespace="http://javajeff.ca/"
             xmlns:tns='http://javajeff.ca/'
             xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
             xmlns:xsd='http://www.w3.org/2001/XMLSchema'
             xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
             xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
             xmlns='http://schemas.xmlsoap.org/wsdl/'>
   <message name="IntToRoman0Request">
      <part name="Int" type="xs:int"/>
   </message>
   <message name="IntToRoman0Response">
      <part name="return" type="xs:string"/>
   </message>
   <message name="RomanToInt1Request">
      <part name="Rom" type="xs:string"/>
   </message>
   <message name="RomanToInt1Response">
      <part name="return" type="xs:int"/>
   </message>
   <portType name="IRoman">
      <operation name="IntToRoman">
         <input message="tns:IntToRoman0Request"/>
         <output message="tns:IntToRoman0Response"/>
      </operation>
      <operation name="RomanToInt">
         <input message="tns:RomanToInt1Request"/>
         <output message="tns:RomanToInt1Response"/>
      </operation>
   </portType>
   <binding name="IRomanbinding" type="tns:IRoman">
      <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
      <operation name="IntToRoman">
         <soap:operation soapAction="urn:Roman-IRoman#IntToRoman" style="rpc"/>
         <input message="tns:IntToRoman0Request">
            <soap:body use="encoded"
                       encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                       namespace="urn:Roman-IRoman"/>
         </input>
         <output message="tns:IntToRoman0Response">
            <soap:body use="encoded"
                       encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                       namespace="urn:Roman-IRoman"/>
         </output>
      </operation>
      <operation name="RomanToInt">
         <soap:operation soapAction="urn:Roman-IRoman#RomanToInt" style="rpc"/>
         <input message="tns:RomanToInt1Request">
            <soap:body use="encoded"
                       encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                       namespace="urn:Roman-IRoman"/>
         </input>
         <output message="tns:RomanToInt1Response">
            <soap:body use="encoded"
                       encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                       namespace="urn:Roman-IRoman"/>
         </output>
      </operation>
   </binding>
   <service name="IRomanservice">
      <port name="IRomanPort" binding="tns:IRomanbinding">
         <soap:address
               location="http://javajeff.ca/php/rncws.php"/>
      </port>
   </service>
</definitions>

Listing 2's WSDL document provides important information for constructing SOAP request and response messages -- note the absence of a types element because the service uses only XML Schema builtin simple types; furthermore, the document style is rpc. This information includes the IntToRoman and RomanToInt operation names (which the application calls to perform the conversions) along with parameter and return type information. This listing also presents the service's endpoint address.

Listing 3 reveals RomanNumerals.java, which stores the application's source code.

1 2 3 4 5 6 Page 2
Page 2 of 6