Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
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
Page 7 of 7
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?";
}
}
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 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();
}
}
}
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.
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!
Read more about Enterprise Java in JavaWorld's Enterprise Java section.