A Good Example Of Multiple Outs And In Out

In/out and Multiple Out Parameters

WSDL

In certain RPC situations, WSDL can specify message parts that appear on both the input message and output message; these translate to in/out parameters. Further, WSDL can specify an output message with more than one part. In/out and multipart output messages pose an interesting problem for translating WSDL to Java.

Consider the following example WSDL:

<wsdl:message name="inmsg">
  <wsdl:part name="in1" type="in"/>
  <wsdl:part name="inout1" type="inout"/>
</wsdl:message>
<wsdl:message name="outmsg">
  <wsdl:part name="inout1" type="inout"/>
  <wsdl:part name="out1" type="out"/>
  <wsdl:part name="out2" type="out"/>
</wsdl:message>
 
<wsdl:portType name="pt1">
  <wsdl:operation name="op1">
    <wsdl:input message="inmsg"/>
    <wsdl:output message="outmsg"/>
  </wsdl:operation>
</wsdl:portType>

The operation named op1 has a message part named inout1 appearing in both the input message and output message. Further, you will notice that the output message of the operation has three output parts: the inout1 part, and two parts that appear only in the output message, out1 and out2.

How is it possible in Java to have a parameter that is both on the input and the output,or to have multiple output values? This is where the holder classes come in.
As we have seen, Axis WSDL tooling generates holder classes for each of the input,output, and in/out parameters. The classes generated when this WSDL file was processed included InHolder.Java, InOutHolder.Java, and OutHolder.Java. These holder classes are simple: They contain a value of the given underlying type and provide a simple constructor.

Skeleton

Now, the skeleton generated for the following binding

<wsdl:binding name="pt1SOAPBinding1" type="pt1">
  <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
  <wsdl:operation name="op1">
        <soap:operation soapAction="op1"/>
           <wsdl:input>
               <soap:body use="encoded"   namespace="someNamespace"  encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
           </wsdl:input>
           <wsdl:output>
               <soap:body use="encoded"  namespace="someNamespace"   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
           </wsdl:output>
  </wsdl:operation>
</wsdl:binding>

looks like this:

public Object op1(org.apache.axis.MessageContext ctx, In in1, Inout inout1)  throws java.rmi.RemoteException
{
   InoutHolder inout1Holder = new InoutHolder(inout1);
   OutHolder out2Holder = new OutHolder();
 
   Object ret = impl.op1(ctx, in1, inout1Holder, out2Holder);
   org.apache.axis.server.ParamList list =  new org.apache.axis.server.ParamList();
   list.add(new org.apache.axis.message.RPCParam("out1", ret));
   list.add(new org.apache.axis.message.RPCParam("inout1", inout1Holder._value));
   list.add(new org.apache.axis.message.RPCParam("out2", out2Holder._value));
   return list;
}

Note the way the target Web service is dispatched. Holder objects are created for the in/out and the second out parameter and passed to the implementation. The implementation then puts a value in the Out2Holder object passed and potentially modifies the value in the InoutHolder that is passed. All three values are passed back to the requestor as RPCParams.

Client Test

Consider the test program shown in Listing 6.8.

Listing 6.8 The In/Out and Out Parameter Test Program

package ch6.ex5;
public class Test {
    public static void main(String[] args){
        if(args.length != 2){
             System.err.println("Usage: Test int1 int2");
             System.err.println("Multiplies int1 by int2 and returns that as out parm,");
             System.err.println("Adds value of int1 to int2 (as inout parm)");
             System.err.println("Adds new value of inout parm with the result of the  multiplication" + "to produce return value.");
             System.exit(1);
        }
        try{
             int int1 = Integer.valueOf(args[0]).intValue();
             int int2 = Integer.valueOf(args[1]).intValue();
             pt1 stub = new In_Out_Parm().getIn_Out_Test_Port();
             In in1 = new In(int1);
             InoutHolder inout1 = new InoutHolder(new Inout(int2));
             OutHolder out2 = new OutHolder();
             Out res = stub.op1 (in1, inout1, out2);
             System.out.println(int1 + "*" + int2 + " = " + out2._value.getE3());
             System.out.println(int1 + "+" + int2 + " = " + inout1._value.getE2());
             System.out.println(int1 + "*" + int2 + " + " + int1 + "+" + int2 + " = " + res.getE3());
        }catch (Exception e){
             System.err.println("Something wrong with the Test service");
             e.printStackTrace();
        }
    }
}

When this is run with the command: java ch6.ex5.Test 2 3

The following SOAP message is generated:

POST /axis/servlet/AxisServlet/In_Out_Test_Port HTTP/1.0

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 
    <SOAP-ENV:Body>
         <ns3:op1 xmlns:ns3="someNamespace">
             <in1 href="#id0"/>
             <inout1 href="#id1"/>
         </ns3:op1>
 
         <multiRef id="id1" xsi:type="ns6:Inout" xmlns:ns6="anotherNamespace">
             <e2 xsi:type="xsd:int">3</e2>
         </multiRef>
 
         <multiRef id="id0" xsi:type="ns10:In" xmlns:ns10="anotherNamespace">
             <e1 xsi:type="xsd:int">2</e1>
         </multiRef>
     </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Service(skeleton) implementation

A sample Web service implementation of this service looks like Listing 6.9.

Listing 6.9 Example In/Out and Out Parameter Web Service Implementation

package ch6.ex5;
import java.rmi.RemoteException;
import org.apache.axis.MessageContext;
public class pt1SOAPBinding1Impl implements pt1Axis {
/**
* @see pt1Axis#op1(MessageContext, In, InoutHolder, OutHolder)
* multiply the value of inout by in and toss it into out2 
* add in to inout and toss that into inout
* return the total of inout and out2
*/
public Out op1(MessageContext ctx, In in1, InoutHolder inout1, OutHolder out2) throws RemoteException {
         out2._value = new Out();
         out2._value.setE3(in1.getE1()*inout1._value.getE2());
         inout1._value.setE2(inout1._value.getE2() + in1.getE1());
         return new Out(inout1._value.getE2() + out2._value.getE3());
}
/**
* in case the messageContext parm was not used
*/
public Out op1(In in1, InoutHolder inout1, OutHolder out2) throws RemoteException {
         out2._value = new Out();
         out2._value.setE3(in1.getE1()*inout1._value.getE2());
         inout1._value.setE2(inout1._value.getE2() + in1.getE1());
         return new Out(inout1._value.getE2() + out2._value.getE3());
}
}

This is a simple program that takes the input value and increments the in/out value by that amount. Further, it returns in one output parameter the product of the in and the original in/out value, and in the "real" output of the message, returns the sum of the newly incremented in/out value and the other output parameter. It is a useless function, but it illustrates the in/out and multiple out situations in a simple fashion.

This program produces the following output SOAP response:
HTTP/1.0 200 OK…

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=http://schemas.xmlsoap.org/soap/encoding/
                xmlns:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/
                xmlns:xsd=http://www.w3.org/2001/XMLSchema
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
 
    <ns3:op1Response xmlns:ns3="someNamespace">
         <out1 href="#id0"/>
         <inout1 href="#id1"/>
         <out2 href="#id2"/>
    </ns3:op1Response>
 
    <multiRef id="id2" xsi:type="ns7:Out"  xmlns:ns7="anotherNamespace">
         <e3 xsi:type="xsd:int">6         </e3>
    </multiRef>
 
    <multiRef id="id1" xsi:type="ns11:Inout"  xmlns:ns11="anotherNamespace">
         <e2 xsi:type="xsd:int">5 </e2>
    </multiRef>
 
    <multiRef id="id0" xsi:type="ns15:Out"  xmlns:ns15="anotherNamespace">
         <e3 xsi:type="xsd:int">11</e3>
    </multiRef>
 
  </SOAP-ENV:Body>
 
</SOAP-ENV:Envelope>

Note the way the multiref element is used to contain the holder values back to the requestor. The test program shown in Listing 6.8 then takes these values from the returned holder classes and prints the following out on the screen:

2*3 = 6
2+3 = 5
2*3 + 2+3 = 11

This would have been extremely tricky to do manually, but it was nothing for the Axis WSDL tooling.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License