Previous Section Next Section

Document-Centric Services

Up to this point, our focus has been on the simple RPC case where the Web service being invoked is a Java method. This is just one way to use SOAP and Axis. As discussed in previous chapters, there is also document-centric SOAP processing. In this scenario, rather than the SOAP processor converting the XML into Java objects and then calling a method, the XML is left untouched and is simply handed to a method for processing. This method is then free to do whatever it wants with the XML. Supporting this approach in Axis is a simple matter of changing the dispatcher that is used. In the RPC case, an RPCDispatcher handler was used; now a MsgDispatcher handler must be used. This handler will locate the appropriate method (as specified by the deployment information) and then call it, passing in the request XML SOAP message as a parameter. The deployment of a document-centric service will look like this:

<service name="POSubmission" pivot="MsgDispatcher">
 <option name="className" value="POSubmission"/>
 <option name="methodName" value="doSubmission"/>
</service>

This code shows the deployment information for a service chain called POSubmission. Notice that it uses MsgDispatcher at the pivot point, and as options it passes in the className and the actual method that should be located and invoked. Unlike the RPC case, where the parameters to the method can be determined by the needs of the service, MsgDipatcher assumes that all document-centric methods have the same method signature, as follows:

public Document doSubmission(MessageContext msgContext, Document xml)
    throws AxisFault;

Notice that the service takes two parameters, a MessageContext and a Document (more on MessageContext later in the "Building Handlers" section; for now, just know that it is Axis-specific data that is made available to the service if it needs it). The service also returns a Document object, which is used as the body of the response SOAP message. Notice that the input and output messages are W3C Document objects, and not SAX events—this is done as a matter of convenience for the handler writer. However, by the time Axis is released, the handler might have the option of processing the SAX events directly. If an error occurs during processing, the service should throw an AxisFault (see the "Faults" section). Listing 4.5 shows a sample service (from Chapter 3).

Listing 4.5 POSubmission.java
package com.skatestown.services; 

import org.w3c.dom.Document;
import org.apache.axis.MessageContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import com.skatestown.data.PO;
import com.skatestown.data.Invoice;
import com.skatestown.backend.ProductDB;
import com.skatestown.backend.POProcessor;
import com.skatestown.xml.Serializer;
import com.skatestown.xml.Deserializer;
import bws.BookUtil;
/**
 * Purchase order submission service
 */
public class POSubmission {
    /**
     * Submit a purchase order and generate an invoice
     */
    public Document doSubmission(MessageContext msgContext, Document inDoc)
        throws Exception
    {
        // Create a PO from the XML document
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        PO po = Deserializer.createPO(inDoc.getDocumentElement());

        // Get the product database
        ProductDB db = BookUtil.getProductDB(msgContext);

        // Create an invoice from the PO
        POProcessor processor = new POProcessor(db);
        Invoice invoice = processor.processPO(po);

        // Serialize the invoice to XML
        Document newDoc = Serializer.writeInvoice(builder, invoice);

        return newDoc;
    }

}

To deploy it, we use the AdminClient:

java org.apache.axis.client.AdminClient po_deploy.xml

The po_deploy.xml file looks like this:

<m:deploy xmlns:m="AdminService">
  <service name="http://www.skatestown.com/ns/po" pivot="MsgDispatcher">
   <option name="className" value="com.skatestown.services.POSubmission"/>
   <option name="methodName" value="doSubmission"/>
  </service>
</m:deploy>

Although invoking an RPC Web service is relative easy, invoking a document-centric Web service requires a little more work, but not much. A corresponding client would look like Listing 4.6.

Listing 4.6 POSubmissionClient.java
package ch3.ex4;

import java.io.InputStream;
import java.io.StringWriter;
import org.apache.axis.encoding.SerializationContext;
import org.apache.axis.message.SOAPEnvelope;
import org.apache.axis.message.SOAPBodyElement;
import org.apache.axis.client.ServiceClient;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;

/**
 * Purchase order submission client
 */
public class POSubmissionClient {
    /**
     * Target service URL
     */
    String url;

    /**
     * Create a client with a target URL
     */
    public POSubmissionClient(String url) {
        this.url = url;
    }

    /**
     * Invoke the PO submission web service
     *
     * @param po Purchase order document
     * @return Invoice document
     * @exception Exception I/O error or Axis error
     */
    public String invoke(InputStream po) throws Exception {
        // Send the message
        ServiceClient client = new ServiceClient(url);
        client.setRequestMessage(new Message(po, true));
        client.getMessageContext().
               setTargetService("http://www.skatestown.com/ns/po");
        client.invoke();

        // Retrieve the response body
        MessageContext ctx = client.getMessageContext();
        Message outMsg = ctx.getResponseMessage();
        SOAPEnvelope envelope = outMsg.getAsSOAPEnvelope();
        SOAPBodyElement body = envelope.getFirstBody();

        // Get the XML from the body
        StringWriter w = new StringWriter();
        SerializationContext sc = new SerializationContext(w, ctx);
        body.output(sc);
        return w.toString();
    }
}

The example starts by creating a ServiceClient object and gives it the location of the SOAP server. Next, it creates an Axis Message object. This object will contain the actual XML of the SOAP message. As input to the constructor, it takes an input stream (the XML for the body of the SOAP envelope) and a boolean indicating whether this XML input stream is the entire SOAP envelope or just the body—true indicates that it is just the body. The ServiceClient object is then told of the request message through the setRequestMessage() method call, and then the Web service itself is invoked. Once the service is invoked, the response message is obtained. This allows for the client to access any part of the response and not just the body. However, in this case, we ask for the first body element to convert it to a String and return it.

    Previous Section Next Section