Sun GlassFish Message Queue 4.4 Developer's Guide for Java Clients

Writing a SOAP Service

A SOAP service represents the final recipient of a SOAP message and should currently be implemented as a servlet. You can write your own servlet or you can extend the JAXMServlet class, which is furnished in the soap.messaging package for your convenience. This section describes the task of writing a SOAP service based on the JAXMServlet class.

Your servlet must implement either the ReqRespListener or OneWayListener interfaces. The difference between these two is that ReqRespListener requires that you return a reply.

Using either of these interfaces, you must implement a method called onMessage(SOAPMsg). JAXMServlet will call onMessage after receiving a message using the HTTP POST method, which saves you the work of implementing your own doPost() method to convert the incoming message into a SOAP message.

Example 5–2 shows the basic structure of a SOAP service that uses the JAXMServlet utility class.


Example 5–2 Skeleton Message Consumer


public class MyServlet extends JAXMServlet implements
                                 ReqRespListener
{
    public SOAPMessage onMessage(SOAP Message msg)
    { //Process message here
    }
}

Example 5–3 shows a simple ping message service:


Example 5–3 A Simple Ping Message Service


public class SOAPEchoServlet extends JAXMServlet
                                         implements ReqRespListener{

    public SOAPMessage onMessage(SOAPMessage mySoapMessage) {
        return mySoapMessage
    }
}

Table 5–2 describes the methods that the JAXM servlet uses. If you were to write your own servlet, you would need to provide methods that performed similar work. In extending JAXMServlet , you may need to override the Init method and the SetMessageFactory method; you must implement the onMessage method.

Table 5–2 JAXMServlet Methods

Method 

Description 

void init (ServletConfig)

Passes the ServletConfig object to its parent’s constructor and creates a default messageFactory object.

If you want incoming messages to be constructed according to a certain profile, you must call the SetMessageFactory method and specify the profile it should use in constructing SOAP messages.


void doPost (HTTPRequest,
HTTPResponse

Gets the body of the HTTP request and creates a SOAP message according to the default or specified MessageFactory profile. 

Calls the onMessage() method of an appropriate listener, passing the SOAP message as a parameter.

It is recommended that you do not override this method. 


void setMessageFactory
  (MessageFactory)

Sets the MessageFactory object. This is the object used to create the SOAP message that is passed to the onMessage method.


MimeHeaders getHeaders
 (HTTPRequest)

Returns a MimeHeaders object that contains the headers in the given HTTPRequest object.


void putHeaders (mimeHeaders,
 HTTPresponse) 

Sets the given HTTPResponse object with the headers in the given MimeHeaders object.


onMessage
(SOAPMesssage)

User-defined method that is called by the servlet when the SOAP message is received. Normally this method needs to disassemble the SOAP message passed to it and to send a reply back to the client (if the servlet implements the ReqRespListener interface.)

Disassembling Messages

The onMessage method needs to disassemble the SOAP message that is passed to it by the servlet and process its contents in an appropriate manner. If there are problems in the processing of the message, the service needs to create a SOAP fault object and send it back to the client as described in Handling SOAP Faults.

Processing the SOAP message may involve working with the headers as well as locating the body elements and dealing with their contents. The following code sample shows how you might disassemble a SOAP message in the body of your onMessage method. Basically, you need to use a Document Object Model (DOM) API to parse through the SOAP message.

See http://xml.coverpages.org/dom.html for more information about the DOM API.


Example 5–4 Processing a SOAP Message


{http://xml.coverpages.org/dom.html
    SOAPEnvelope env = reply.getSOAPPart().getEnvelope();
    SOAPBody sb = env.getBody();
    // create Name object for XElement that we are searching for
    Name ElName = env.createName("XElement");

    //Get child elements with the name XElement
    Iterator it = sb.getChildElements(ElName);

    //Get the first matched child element.
    //We know there is only one.
    SOAPBodyElement sbe = (SOAPBodyElement) it.next();

    //Get the value for XElement
    MyValue =   sbe.getValue();
}               

Handling Attachments

A SOAP message may have attachments. For sample code that shows you how to create and add an attachment, see Code Samples. For sample code that shows you how to receive and process an attachment, see Code Samples.

In handling attachments, you will need to use the Java Activation Framework API. See http://java.sun.com/products/javabeans/glasgow/jaf.html for more information.

Replying to Messages

In replying to messages, you are simply taking on the client role, now from the server side.

Handling SOAP Faults

Server-side code must use a SOAP fault object to handle errors that occur on the server side when unmarshalling the request, processing the message, or marshalling the response. The SOAPFault interface extends the SOAPBodyElement interface.

SOAP messages have a specific element and format for error reporting on the server side: a SOAP message body can include a SOAP fault element to report errors that happen during the processing of a request. Created on the server side and sent from the server back to the client, the SOAP message containing the SOAPFault object reports any unexpected behavior to the originator of the message.

Within a SOAP message object, the SOAP fault object is a child of the SOAP body, as shown in the figure below. Detail and detail entry objects are only needed if one needs to report that the body of the received message was malformed or contained inappropriate data. In such a case, the detail entry object is used to describe the malformed data.

Figure 5–8 SOAP Fault Element

Diagram showing hierarchy from top to bottom for a message
containing fault information: SOAP part, envelope, body, fault, detail, and
detail entry.

The SOAP Fault element defines the following four sub-elements:

Predefined Fault Codes

The SOAP specification lists four predefined faultcode values. The namespace identifier for these is http://schemas.xmlsoap.org/soap/envelope/.

Table 5–3 SOAP Faultcode Values

Faultcode Name 

Meaning 


VersionMismatch 

The processing party found an invalid namespace for the SOAP envelope element; that is, the namespace of the SOAP envelope element was not http://schemas.xmlsoap.org/soap/envelope/ .


MustUnderstand 

An immediate child element of the SOAP Header element was either not understood or not appropriately processed by the recipient. This element’s mustUnderstand attribute was set to 1 (true).


Client

The message was incorrectly formed or did not contain the appropriate information. For example, the message did not have the proper authentication or payment information. The client should interpret this code to mean that the message must be changed before it is sent again. 

If this is the code returned, the SOAPFault object should probably include a detailEntry object that provides additional information about the malformed message.


Server 

The message could not be processed for reasons that are not connected with its content. For example, one of the message handlers could not communicate with another message handler that was upstream and did not respond. Or, the database that the server needed to access is down. The client should interpret this error to mean that the transmission could succeed at a later point in time. 

These standard fault codes represent classes of faults. You can extend these by appending a period to the code and adding an additional name. For example, you could define a Server.OutOfMemory code, a Server.Down code, and so forth.

Defining a SOAP Fault

Using SAAJ you can specify the value for faultcode, faultstring, and faultactor using methods of the SOAPFault object. The following code creates a SOAP fault object and sets the faultcode, faultstring, and faultactor attributes:


SOAPFault fault;
reply = factory.createMessage();
envp = reply.getSOAPPart().getEnvelope(true);
someBody = envp.getBody();
fault = someBody.addFault():
fault.setFaultCode("Server");
fault.setFaultString("Some Server Error");
fault.setFaultActor(http://xxx.me.com/list/endpoint.esp/)
reply.saveChanges();
               

The server can return this object in its reply to an incoming SOAP message in case of a server error.

The next code sample shows how to define a detail and detail entry object. Note that you must create a name for the detail entry object.


SOAPFault fault = someBody.addFault();
fault.setFaultCode("Server");
fault.setFaultActor("http://foo.com/uri");
fault.setFaultString ("Unkown error");
Detail myDetail = fault.addDetail();
detail.addDetailEntry(envelope.createName("125detail", "m",
        "Someuri")).addTextNode("the message cannot contain
         the string //");
reply.saveChanges();