Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Clean up your wire protocol with SOAP, Part 2

Use Apache SOAP to create SOAP-based applications

  • Print
  • Feedback

Page 7 of 7

The HelloWorld service

The complete implementation of the new HelloWorld service is shown below:

package hello;
public class HelloServer 
{
   public String sayHelloTo(String name)
   {
      System.out.println("sayHelloTo(String name)");
      return "Hello " + name + ", How are you doing?";       
    }
   public String sayHelloTo(Name theName)
   {
      System.out.println("sayHelloTo(Name theName)");
      return "Hello " + theName.getName() + ", How are you doing?";       
   }
}


The service is still easy and resembles HelloWorld without the JavaBean, which implies that the brunt of the work will fall on the client. In fact, the only difference between this version of the service and the previous one is the presence of an overloaded sayHelloTo method, which is shown in boldface.

This overloaded method takes a reference to a Name JavaBean whose definition is shown below:

package hello;
public class Name
{
   private String name;
   public String getName()
   {
      return name;
   }
   public void setName(String name)
   {
      this.name = name;
   }
}


Listing 2 shows the complete HelloWorld service.

Listing 2: HelloServer.java

package hello;
public class HelloServer 
{
   public String sayHelloTo(String name)
   {
      System.out.println("sayHelloTo(String name)");
      return "Hello " + name + ", How are you doing?";       
   }
   public String sayHelloTo(Name theName)
   {
      System.out.println("sayHelloTo(Name theName)");
      return "Hello " + theName.getName() + ", How are you doing?";       
   }
}


Deploy the service

Because you need to provide some extra information to the Apache SOAP server for it to deploy a service that uses a JavaBean, deploying the service will be slightly more complicated this time.

Use the administration tool
To deploy this version of the HelloWorld service using the administration tool, follow the same instructions that you did before, but don't click the Deploy button. Now set the Number of Mappings field to 1; this indicates that you will give information about one mapping, the Name JavaBean. There should be a table just below the Mappings field; you will use the first row of that table. Keep the Encoding Style as SOAP. Set the NameSpace URI field to the object ID: in your case, urn:Hello. Now set the Local Part and Java Type fields to the fully qualified class name of the Name JavaBean, which is hello.Name. Finally, set the Java to XML Serializer and XML to Java Deserializer fields to org.apache.soap.encoding.soapenc.BeanSerializer, which is the class that implements the Serializer and Deserializer interfaces and will be used to serialize and deserialize the Name JavaBean. If you had more JavaBeans (such as an Address Bean), you would enter information about those beans in this table, and you would update the Number of Mappings field to reflect the number of rows used in the table.

From the command line
From the command line, you need only update the XML deployment descriptor file that is passed in as a command line parameter. The updated XML is shown below:

<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment" id="urn:Hello">
  <isd:provider type="java" scope="Application" methods="sayHelloTo">
    <isd:java class="hello.HelloServer" static="false"/>
  </isd:provider>  
  <isd:mappings>
    <isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
             xmlns:x="urn:Hello" qname="x:hello.Name"
             javaType="hello.Name"
             java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer"
             xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/>
  </isd:mappings>    
</isd:service>


As before, the XML contains the same information that you provided via the Web-based administration tool.

The HelloWorld client

The client program is more interesting and involved, just as it was in the first example. Instead of going through the entire program, I will focus on the differences between the two versions of the client program. Since one of the parameters -- or in this case, the only parameter -- to the method call is a JavaBean, you must manually set up a type-mapping registry. Complete this task by creating a new instance of the class org.apache.soap.encoding.SOAPMappingRegistry and calling the mapTypes() method on it. As the name indicates, that method is used to inform the registry of a previously unknown type, like a custom JavaBean. mapTypes() takes the encoding style to be used, the qualified name, the type's fully qualified class name, and the serializer and deserializer to use, which in your case are standard bean serializers. A qualified name consists of an element's name, including the namespace it belongs to. In your case, the qualified name of the Name JavaBean is formed by combining the namespace URI (urn:Hello) and the local name (hello.Name). The code snippet below shows that:

// Create the type mapping registry
SOAPMappingRegistry smr = new SOAPMappingRegistry();
BeanSerializer beanSer = new BeanSerializer();                     
// Map the types.
smr.mapTypes(Constants.NS_URI_SOAP_ENC,
new QName("urn:Hello", "hello.Name"),hello.Name.class, beanSer, beanSer);


Next, the Call object must be told to use this registry instead of the default one. To do that, call the setSOAPMappingRegistry() method on the Call object, as shown below:

call.setSOAPMappingRegistry(smr);


Once you've manually set up a type-mapping registry, you need to set up the parameters for the Call object. Complete that task just like before; the only difference is that instead of a String name parameter you now have a JavaBean parameter, as shown below:

// Set the Parameters
Vector params = new Vector();         
Name theName = new Name();
theName.setName(name);
params.addElement(new Parameter("name", hello.Name.class, theName, null));
call.setParams(params);


The remainder of the client is the same as before. Listing 3 shows the complete client program:

Listing 3: Client2.java

package hello;
import java.net.URL;
import java.util.Vector;            
import org.apache.soap.SOAPException;
import org.apache.soap.Constants;
import org.apache.soap.Fault;
import org.apache.soap.rpc.Call;
import org.apache.soap.rpc.Parameter;
import org.apache.soap.rpc.Response;
import org.apache.soap.encoding.SOAPMappingRegistry;
import org.apache.soap.encoding.soapenc.BeanSerializer;
import org.apache.soap.util.xml.QName;
                             
public class Client2
{
   public static void main(String[] args) throws Exception 
   {      
      if(args.length == 0)
      {
         System.err.println("Usage: java hello.Client [SOAP-router-URL] <name>");
         System.exit (1);
      }
      try
      {
         URL url = null;
         String name = null;              
         if(args.length == 2)
         {
            url = new URL(args[0]);
            name = args[1];
         }
         else
         {
            url = new URL("http://localhost:8080/apache-soap/servlet/rpcrouter");         
            name = args[0];
         }
         // Build the call.
         Call call = new Call();
         call.setTargetObjectURI("urn:Hello");
         call.setMethodName("sayHelloTo");
         call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);         
         // Create the type mapping registry
         SOAPMappingRegistry smr = new SOAPMappingRegistry();
         BeanSerializer beanSer = new BeanSerializer();                     
         // Map the types.
         smr.mapTypes(Constants.NS_URI_SOAP_ENC,
             new QName("urn:Hello", "hello.Name"),hello.Name.class, beanSer, beanSer);                     
         // and tell the Call object to use it..
         call.setSOAPMappingRegistry(smr);
         // Set the Parameters
         Vector params = new Vector();         
         Name theName = new Name();
         theName.setName(name);
         params.addElement(new Parameter("name", hello.Name.class, theName, null));
         call.setParams(params);
         // Invoke the call.
         Response resp = null;         
         try
         {
            resp = call.invoke(url, "");
         }
         catch( SOAPException e )
         {
            System.err.println("Caught SOAPException (" + e.getFaultCode() + "): " + e.getMessage());
            System.exit(-1);
         }
   
         // Check the response.
         if( !resp.generatedFault() )
         {
            Parameter ret = resp.getReturnValue();
            Object value = ret.getValue();            
            System.out.println(value);
         }
         else
         {
            Fault fault = resp.getFault();            
            System.err.println("Generated fault: ");
            System.out.println ("  Fault Code   = " + fault.getFaultCode());  
            System.out.println ("  Fault String = " + fault.getFaultString());
         }
      }
      catch(Exception e)
      {
         e.printStackTrace();
      }
   }   
}


Compile and run the programs

Now that you've developed the complete example, it's time to see it in action. However, you must first compile the service and client Java code.

Create a hello directory and copy Client1.java, Client2.java, and HelloServer.java into it. I have made my hello directory in the samples directory of the Apache SOAP installation (that is, E:\soap-2_0\samples). To compile the programs, all you need in the classpath is the parent of the hello directory (in my case, E:\soap-2_0\samples), soap.jar, and xerces.jar. I use the following batch file to compile the programs:

set CLASSPATH=E:\soap-2_0\samples\;E:\soap-2_0\lib\soap.jar;E:\xerces-1_2_0\xerces.jar
javac -d .. HelloServer.java Client.java Client2.java


Note: Be sure to execute this batch file from the hello directory.

To use the service, in addition to deploying it, you will need to change the Web server's classpath to ensure that it can find the hello.HelloServer class -- for me, that meant adding E:\soap-2_0\samples to the Web server's classpath. After making the required change to the classpath, restart the Web server. Now you're ready to run the client programs. Here's the batch file that I use to run hello.Client:

set CLASSPATH=E:\soap-2_0\samples\;E:\soap-2_0\lib\soap.jar;E:\xerces-1_2_0\xerces.jar
java hello.Client Tarak


The classpath is the same as the one used for compiling the programs.

Finally, below you will find the batch file that I use to run hello.Client2:

set CLASSPATH=E:\soap-2_0\samples\;E:\soap-2_0\lib\soap.jar;E:\xerces-1_2_0\xerces.jar
java hello.Client2 Tarak


Observe the console window of your Web server and see which methods on the HelloWorld service are being called as a result of running the two different clients.

Summary

In this article, I showed you how to create simple SOAP-based services using the Apache SOAP implementation. The other major contender in terms of SOAP implementation is Microsoft. Unfortunately, pure Java developers would have a tough time using Microsoft, since its implementation consists of COM objects. And besides, Apache's implementation is still very attractive. Read James Snell's article, "MS SOAP SDK vs IBM SOAP4J: Comparison & Review," in Resources for more information.

In Part 3, I will introduce you to another way that Apache SOAP allows you to create and implement services: you can use a scripting language such as JavaScript, as opposed to Java. I'll also introduce you to a cool JavaScript engine called Rhino. So stay tuned!

About the author

A certified Java programmer, Tarak Modi is an architect at North Highland, which specializes in management and technology consulting. He has a master's degree in computer engineering and an MBA concentrating in information systems. He has several years of experience working with C++, Java, and technologies like DCOM, CORBA, RMI, and EJB. He has written articles for leading software magazines, including JavaWorld, and is currently working on a book on Java Message Service with Manning Publications. To find out more about Tarak, his articles, and his upcoming book, please visit his Website at http://tmodi.home.att.net/.

Read more about Enterprise Java in JavaWorld's Enterprise Java section.

  • Print
  • Feedback

Resources