ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Working with Complex Data Types, Part 3
Pages: 1, 2, 3, 4, 5

Most of the deployment descriptor should look familiar; it's similar to the ones shown in Chapter 4. The difference is that we now have an entry in the isd:mappings section. There is one entry, isd:map, that describes the mapping of the stock trade type to the StockTrade_ServerSide class. The isd:map element has no data; all the information is supplied as attributes. The first attribute, encodingStyle, specifies the encoding style associated with the serialization of the type. Next, a namespace identifier, x, is assigned the value urn:BasicTradingService. I'm using the name of the service as the namespace qualifier for the custom type; however, you don't have to do this, and in fact may not want to in many instances. For example, if you have custom types that are used by multiple services, or if you're using custom types whose definitions are specified by a third party, then you'd certainly want to qualify the custom type using the appropriate namespace. The next attribute, qname, specifies the fully qualified name of the type being mapped. The value assigned is x:StockTrade, which is the same StockTrade namespace qualified using the service name. The javaType attribute specifies the server-local Java class used to implement the type; on the server side we're using javasoap.book.ch5.StockTrade_ServerSide. The last two attributes, java2XMLClassName and xml2JavaClassName, tell Apache SOAP which local Java classes to use to perform the serialization and deserialization, respectively. Apache SOAP comes with a custom serializer/deserializer class that can convert between custom XML types and Java classes that conform to the JavaBeans property accessor pattern. It can handle both serialization and deserialization, which is why we use it for both attributes. In the next chapter we'll look at creating custom type serializers.

Now that we have a deployment descriptor, we can go ahead and redeploy the urn:BasicTradingService. Once we do that, our service is ready to accept executeStockTrade method invocations. However, we need to do some setup work in the client application as well. Let's take a look at the client application:

package javasoap.book.ch5;
import java.net.*;
import java.util.*;
import org.apache.soap.*;
import org.apache.soap.rpc.*;
import org.apache.soap.encoding.*;
import org.apache.soap.encoding.soapenc.*;
import org.apache.soap.util.xml.*;
public class StockTradeClient
  public static void main(String[] args) throws Exception 
    URL url = new  
    Call call = new Call(  );
    SOAPMappingRegistry smr = new SOAPMappingRegistry(  );
    BeanSerializer beanSer = new BeanSerializer(  );
    // Map the Stock Trade type
       new QName("urn:BasicTradingService", "StockTrade"),
       StockTrade_ClientSide.class, beanSer, beanSer);
    // create an instance of the stock trade
    StockTrade_ClientSide trade = 
           new StockTrade_ClientSide("XYZ", false, 350);
    Vector params = new Vector(  );
    params.addElement(new Parameter("trade", 
                           StockTrade_ClientSide.class, trade, null));
    Response resp;
    try {
      resp = call.invoke(url, "");
      Parameter ret = resp.getReturnValue(  );
      Object desc = ret.getValue(  );
      System.out.println("Trade Description: " + desc);
    catch (SOAPException e) {
      System.err.println("Caught SOAPException (" +
                         e.getFaultCode(  ) + "): " +
                         e.getMessage(  ));

After the Call object is created, we create an instance of org.apache.soap.encoding.SOAPMappingRegistry called smr. This class holds the mappings of custom types to Java classes, and gets passed to the Call object using the setSOAPMappingRegistry( ) method of our Call object. We haven't had to do this in previous examples because the Call object creates a mapping registry for itself if one isn't passed to it. The SOAPMappingRegistry( ) contains all of the predefined mappings, such as those we took advantage of for arrays. We'll add our mapping to it shortly.

Next we call the call.setEncodingStyleURI( ) method. This method specifies the overall encoding style to be used for the custom type parameters. The constant NS_URI_SOAP_ENC, from the org.apache.soap.Constants class, represents the http://schemas.xmlsoap.org/soap/encoding/ namespace that we've been using thus far. This should be the same encoding style namespace that we specified in the deployment descriptor for the StockTrade type. The setTargetObjectURI( ) and setMethodName( ) methods are used in the same way as in previous examples. The next step is to create an instance of org.apache.soap.encoding.soapenc.BeanSerializer; we can use this standard serializer because our custom type conforms to the JavaBeans property accessor pattern. Now we can establish the mapping by calling smr.mapTypes( ). The first parameter is Constants.NS_URI_SOAP_ENC, which specifies that the encoding style used for this mapping is the standard SOAP encoding. You may be wondering why we need to do this if we've already specified the encoding style for the entire call earlier. The reason is simple: this parameter gives you the opportunity to override the encoding style used for this particular mapping. However, if you use null as the parameter value, you'll end up with a mapping that attempts to use the null namespace for the encoding style, which is not correct. When we look at the SOAP envelope for this message, you'll see that since the encoding style is the same as that of the overall call, the encodingStyle attribute will not be repeated for this serialized parameter. If the encoding style were not the same as that of the Call, it would appear as an attribute of the parameter.

The next parameter of smr.mapTypes( ) is an instance of org.apache.soap.util.xml.Qname, which represents a fully qualified name (one that includes a namespace qualifier followed by a name). We use urn:BasicTradingService as the namespace and StockTrade as the name. The third parameter is StockTrade_ClientSide.class, the Java class that implements the custom type. The next two parameters are instances of the serializer and deserializer that will be used for this type. We use the beanSer object that we created earlier for both, as the org.apache.soap.encoding.soapenc.BeanSerializer class implements both serialization and deserialization.

Pages: 1, 2, 3, 4, 5

Next Pagearrow