The Apache SOAP Routing Service

Before moving on to the rest of the examples, we need to make a quick note about Apache SOAP’s routing and service capability. It’s a concept that is likely to be applicable to other SOAP infrastructures you may use in the future. If you have poked around with Apache (or you looked ahead at the rest of the chapter), you may have noticed that many samples use a common URL, which either looks like http://localhost:8080/soap/servlet/messagerouter or http://localhost:8080/soap/servlet/rpcrouter. These special URLs point to Apache’s routing and dispatching mechanism. This mechanism looks at the content of the SOAP envelope and decides which class to load and which method to call within that class. Apache refers to this destination as a service . The service is registered with the servlet engine in a two-step process. First, an XML deployment descriptor is created, specifying details about the class name of the service, its associated method call, and the target URI. Then a special org.apache.soap.server.ServiceManagerClient class is invoked to register the service with Apache SOAP.

Using the RPC router, any Java class and method can be registered as a service; the Apache SOAP infrastructure will call the method with the appropriate parameters. An example of SOAP-RPC can be found in Chapter 4. Using the message router, the method name is the tag name of the body entry in the SOAP envelope, and the method always conforms to the following signature:

public void anyMessageMethod(Envelope requestEnvelope, 
   SOAPContext requestContext, SOAPContext responseContext)

for which anyMessageMethod is specified in the deployment descriptor for the service and is also the tag name of the body entry in the SOAP envelope.

The Apache TunnelGui Application

Sending SOAP messages to the SimpleHTTPReceive servlet is an excellent way of dumping raw output to the screen. A more convenient way to see the raw output from the sender and the receiver is to use the TunnelGui included with Apache SOAP. TunnelGui is a simple utility that intercepts the HTTP request, displays it in a window on the screen, and forwards the request to the ultimate destination. It’s a great tool for analyzing and debugging problems that have to do with unexpected output. To launch the Apache TunnelGui utility, issue the following command:

java org.apache.soap.util.net.TcpTunnelGui 5555 localhost 8080

5555 is the port on which TunnelGui listens; 8080 is the port to which it forwards requests (8080 also happens to be the default port for Tomcat). To send a SOAP request through TunnelGui, specify port 5555 instead of 8080 in the destination URL. For example, issue the following command:

java GenericHTTPSoapClient -df ./PO.xml -url 
    http://localhost:5555/examples/servlet/SimpleHTTPReceive

This command displays the expected output in the Tomcat server window and shows the request and response in the TunnelGui window (Figure 3-2).

The Apache TunnelGui utility

Figure 3-2. The Apache TunnelGui utility

The SOAP-Aware Servlet Becomes a Message Router

In the previous example, we promised to show another way to set up a servlet that passes the SOAP envelope directly to the receiver. To do this, we’ll use Apache’s message router service. For this example, we can use the GenericHTTPClient without any modifications; simply override the destination URL on the command line:

java GenericHTTPSoapClient -url http://localhost:8080/soap/servlet/messagerouter

Here’s what you should see in the command window for the sender:

_________________________________________________________
Starting GenericHTTPSoapClient:
    host url        = http://localhost:8080/soap/servlet/messagerouter
    data file       = ./PO.xml
_________________________________________________________

Sent SOAP Message with Apache HTTP SOAP Client.
Waiting for response....
<PurchaseOrderResponse>Accepted</PurchaseOrderResponse>

In the Tomcat console window, you should see:

Received a PurchaseOrder!!

Header==>
<jaws:MessageHeader xmlns:jaws="urn:oreilly:jaws:samples"><From>Me</From><To>You
</To><MessageId>9999</MessageId></jaws:MessageHeader>
Body====>
<PurchaseOrder xmlns="urn:oreilly-jaws-samples">
        <shipTo country="US">
                <name>Joe Smith</name>
                <street>14 Oak Park</street>
                <city>Bedford</city>
                <state>MA</state>
                <zip>01730</zip>
        </shipTo>
        <items>
                <item partNum="872-AA">
                        <productName>Candy Canes</productName>
                        <quantity>444</quantity>
                        <price>1.68</price>
                        <comment>I want candy!</comment>
                </item>
        </items>
</PurchaseOrder>

This example works partly because of the information in the deployment descriptor for this service. The class name of the receiver is PurchaseOrderAcceptor. The method name is PurchaseOrder, which is also the name of the main tag in the SOAP body. Here’s the deployment descriptor:

<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"
             id="urn:oreilly-jaws-samples" type="message">
  <isd:provider type="java" scope="Application" 
            methods="PurchaseOrder PurchaseOrderWithAttachment">
    <isd:java class="PurchaseOrderAcceptor"/>
  </isd:provider>
  <isd:faultListener>org.apache.soap.server.DOMFaultListener</isd:faultListener>
</isd:service>

If you are going to experiment with creating your own Apache services, remember that the URI represented by the id attribute of the service tag in the deployment descriptor must match the target URI used in the Message.send( ) call—something that’s not obvious from reading the Apache documentation.

Here’s a listing of the PurchaseOrderAcceptor class and its PurchaseOrder( ) method. It uses the Envelope, Header, and Body APIs to pick apart the header and body of the message:

import org.apache.soap.Envelope;
import org.apache.soap.Constants;
import org.apache.soap.SOAPException;

import org.apache.soap.rpc.SOAPContext;

public class PurchaseOrderAcceptor
{

  public void PurchaseOrder(Envelope requestEnvelope, SOAPContext requestContext,
                            SOAPContext responseContext)
    throws SOAPException
  {
    System.out.println("Received a PurchaseOrder!!");

    java.io.StringWriter writer = new java.io.StringWriter(  );

    org.apache.soap.Header header = requestEnvelope.getHeader(  );
    java.util.Vector headerEntries = header.getHeaderEntries(  );
    
    writer.write("
Header==>
");
    for (java.util.Enumeration e = headerEntries.elements(); e.hasMoreElements(  );)
    {
        org.w3c.dom.Element el = (org.w3c.dom.Element)e.nextElement(  );
        org.apache.soap.util.xml.DOM2Writer.serializeAsXML(
            (org.w3c.dom.Node)el, writer);
    }
    
    org.apache.soap.Body body = requestEnvelope.getBody(  );
    java.util.Vector bodyEntries = body.getBodyEntries(  );
    
    writer.write("
Body====>
");
    for (java.util.Enumeration e = bodyEntries.elements(); e.hasMoreElements(  );)
    {
        org.w3c.dom.Element el = (org.w3c.dom.Element)e.nextElement(  );
        org.apache.soap.util.xml.DOM2Writer.serializeAsXML(
            (org.w3c.dom.Node)el, writer);
    }
    System.out.println(writer.toString(  ));
    try
    {
      //should really be better XML with declaration and namespaces
      responseContext.setRootPart(
         "<PurchaseOrderResponse>Accepted</PurchaseOrderResponse>", "text/xml");
    }
    catch(Exception e)
    {
      throw new SOAPException(Constants.FAULT_CODE_SERVER, 
         "Error writing response", e);
    }
  }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset