ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


O'Reilly Book Excerpts: Java and SOAP

Working with Complex Data Types, Part 2

by Robert Englander

Editor's Note: This is the second in a series of excerpts from "Chapter 5: Working with Complex Data Types" of Java and SOAP. This excerpt covers arrays as return values.

In This Series

Working with Complex Data Types, Part 4
This is the last in a series of book excerpts on working with complex data types from Java and SOAP. In this excerpt, learn about returning custom types, using a stock market example.

Working with Complex Data Types, Part 3
The third in a series of excerpts from Java and SOAP, this article excerpt covers passing custom types as parameters.

Working with Complex Data Types, Part 1
In this excerpt on complex data types from Java and SOAP, the authors discuss passing arrays as parameters.

So far we've been passing arrays as parameters. Now let's use an array as the return value of a service method. We'll add a method to our service called getMostActive( ), which returns a String[] that contains the symbols for the most actively traded stocks of the day. Here's the new version of the BasicTradingService class:


package javasoap.book.ch5;
public class BasicTradingService {
   
   public BasicTradingService(  ) {
   }
   public String[] getMostActive(  ) {
   
      // get the most actively traded stocks
      String[] actives = { "ABC", "DEF", "GHI", "JKL" };
      return actives;
   }
   public int getTotalVolume(String[] stocks) {
      
      // get the volumes for each stock from some
      // data feed and return the total
      int total = 345000; 
      return total;
   }
   public String executeTrade(Object[] params) {
      String result;
      try {
         String stock = (String)params[0];
         Integer numShares = (Integer)params[1];
         Boolean buy = (Boolean)params[2];
         String orderType = "Buy";
         if (false == buy.booleanValue(  )) {
            orderType = "Sell";
         }
         result = (orderType + " " + numShares + " of " + stock);
      }
      catch (ClassCastException e) {
         result = "Bad Parameter Type Encountered";
      }
      return result;
   }
}

Since we're not really calling a data feed, we just stuff a few phony stock symbols into an array and return it.

Java and SOAP

Related Reading

Java and SOAP
By Robert Englander

Go ahead and redeploy the service now. Calling this service method from an Apache SOAP client is simple. There are no parameters to the service method, so we just have to set up the call and invoke it:

package javasoap.book.ch5;
import java.net.*;
import org.apache.soap.*;
import org.apache.soap.rpc.*;
public class MostActiveClient
{
  public static void main(String[] args) throws Exception 
  {
    URL url = new   
      URL("http://georgetown:8080/soap/servlet/rpcrouter");
    Call call = new Call(  );
    call.setTargetObjectURI("urn:BasicTradingService");
    call.setMethodName("getMostActive");
    Response resp;
    try {
      resp = call.invoke(url, "");
      Parameter ret = resp.getReturnValue(  );
      String[] value = (String[])ret.getValue(  );
      int cnt = value.length;
      for (int i = 0; i < cnt; i++) {
         System.out.println(value[i]);
      }
    }
    catch (SOAPException e) {
      System.err.println("Caught SOAPException (" +
                         e.getFaultCode(  ) + "): " +
                         e.getMessage(  ));
    }
  }
}

We cast the return value of ret.getValue to a String[], since that's the return type we're expecting. In past examples we were able to leave the value as an Object instance because we relied on the object's toString( ) method to display the value. In this case we need to iterate over the array, so it's necessary to cast the value to the appropriate array type. After that, we just find the array length and then loop over the array values, printing each one as we get to it. If you run this example you should see the following output:

ABC
DEF
GHI
JKL

The SOAP envelope returned by this method invocation is pretty straightforward:

<SOAP-ENV:Envelope 
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"   
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <SOAP-ENV:Body>
     <ns1:getMostActiveResponse 
        xmlns:ns1="urn:BasicTradingService" 
        SOAP-ENV:encodingStyle=
          "http://schemas.xmlsoap.org/soap/encoding/">
  
      <return 
        xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/" 
        xsi:type="ns2:Array" ns2:arrayType="xsd:string[4]">
          <item xsi:type="xsd:string">ABC</item>
          <item xsi:type="xsd:string">DEF</item>
          <item xsi:type="xsd:string">GHI</item>
          <item xsi:type="xsd:string">JKL</item>
      </return>
     </ns1:getMostActiveResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

To deploy this version of the BasicTradingService class in GLUE, we can use our old BasicTradingApp class. We can modify the Java interface, IBasicTradingService, to include the new method:

package javasoap.book.ch5;
public interface IBasicTradingService {
  int getTotalVolume(String[] symbols);
  String executeTrade(Object[] params);
  String[] getMostActive(  );
}

Now we modify the application BasicTradingClient to include a call to the getMostActive( ) method, and then iterate over the values in the array and print them out. When using GLUE we don't have to cast the return value to a String[] because, unlike the Apache SOAP example, the getMostActive( ) method of the interface is defined to return the proper type. Here's the modified code:

package javasoap.book.ch5;
import electric.registry.RegistryException;
import electric.registry.Registry;
public class BasicTradingClient {
   public static void main(String[] args) throws Exception 
   {
      try {
        IBasicTradingService srv = (IBasicTradingService)Registry.bind(
          "http://georgetown:8004/glue/urn:BasicTradingService.wsdl",
          IBasicTradingService.class);
        String[] stocks = { "MINDSTRM", "MSFT", "SUN" };
        int total = srv.getTotalVolume(stocks);
        System.out.println("Total Volume is " + total);
        Object[] multiParams = { "MINDSTRM", new Integer(100), 
                                    new Boolean(true) };
        String desc = srv.executeTrade(multiParams);
        System.out.println("Trade Description: " + desc);
        String[] actives = srv.getMostActive(  );
        int cnt = actives.length;
        for (int i = 0; i < cnt; i++) {
           System.out.println(actives[i]);
        }
    }
    catch (RegistryException e)
    {
       System.out.println(e);
    }
  }
}

If you run this example, you'll get the following output:

Total Volume is 345000
Trade Description: Buy 100 of MINDSTRM
ABC
DEF
GHI
JKL

GLUE uses the same serialization technique for arrays as return values that we saw earlier for array parameters; it uses a reference to a separately serialized array as the actual return value, and it references the actual array data. The SOAP envelope returned when invoking the getMostActive( ) method is:

<soap:Envelope 
  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' 
  xmlns:xsd='http://www.w3.org/2001/XMLSchema' 
  xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'
  xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/' 
  soap:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
    <soap:Body>
      <n:getMostActiveResponse   
        xmlns:n='urn:BasicTradingService'>
         <Result href='#id0'/>
      </n:getMostActiveResponse>
      <id0 id='id0' soapenc:root='0' 
        xmlns:ns2='http://www.themindelectric.com/package/java.lang/' 
        xsi:type='soapenc:Array' soapenc:arrayType='xsd:string[4]'>
         <i xsi:type='xsd:string'>ABC</i>
         <i xsi:type='xsd:string'>DEF</i>
         <i xsi:type='xsd:string'>GHI</i>
         <i xsi:type='xsd:string'>JKL</i>
      </id0>
    </soap:Body>
</soap:Envelope>

In the next installment, learn passing custom types as parameters.

Robert Englander is Principal Engineer and President of MindStream Software, Inc. (www.mindstrm.com). He provides consulting services in software architecture, design, and development, as well as developing frameworks for use on client projects.


View catalog information for Java and SOAP

Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.