Using JAX-RPC parameter modes with Apache Axis: a look at both the simple and the complex – Focus: tools and tricks
Aravilli Srinivasa Rao
The RPC mechanism enables a remote procedure call from a client to be communicated to a remote server. SOAP RPC supports three types of parameter modes–IN, OUT, and INOUT–for remote method invocation. In this article I’ll explain how JAX-RPC supports SOAP RPC parameter modes and how to use JAX-RPC parameter modes with Apache Axis.
JAX-RPC
JAX-RPC provides a means for performing RPC over SOAP. It provides rules for client code generation, SOAP Binding, mapping from Java to WSDL and WSDL to Java, type mappings between Java and XML data types, and client APIs for constructing Web service invocations.
JAX-RPC defines one static model and two dynamic models for the client side to invoke a remote procedure. In the static model, stubs are used and the code-generation tools generate the stubs. One dynamic model is based on generating a proxy object dynamically using java reflection APIs and another is based on Dynamic Invocation an Interface (DII) using the Call object. The examples shown in this article use DII rather than the static model.
JAX-RPC interfaces
On the client side, JAX-RPC defines the following major interfaces:
* ServiceFactory: Creates the instances of Service interface.
* Service: Defines methods for dynamic proxy invocation and DII. getPort( ) method is used for dynamic proxy invocation.
* Call: createCall( ) method on Service interface returns the Call object which is used for DII.
JAX-RPC supports the following three types of invocation models:
* Synchronous request-response mode: A Client invokes a remote method on a service and receives return values or an exception. Client blocks the thread until it gets a response from the remote service.
* One-way RPC Mode: A Client invokes a remote method on a service endpoint in the one-way mode. The client invocation thread does not block and continues execution without waiting for this remote method invocation to be processed by the service.
* Non-blocking RPC invocation: A service client invokes a remote method on a service endpoint and continues processing in the same thread without waiting for the return of the remote method invocation.
The Synchronous Request-Response Mode and One-Way RPC Mode are achieved by the JAX-RPC DII Call interface.
JAX-RPC Parameter Modes
JAX-RPC uses pass by copy semantics for parameter passing in a remote method invocation. The JAX-RPC specification does not support the object-by-reference mode for remote method invocations. JAX-RPC specifies the following rules for the IN, OUT and INOUT parameter passing modes and return value:
* An IN parameter is passed as copy. The value of the IN parameter is copied before a remote method invocation.
* The return value is created as a copy and returned to the caller from a remote method invocation.
* The OUT and INOUT parameters are passed by copy. JAX-RPC uses the Holder classes to support the INOUT and OUT parameters. A service client provides an instance of a Holder class that is passed by value for either out or inout parameter. The contents of the Holder class are modified in the remote method invocation and the service client uses the changed contents after the method invocation returns.
* JAX-RPC defines ParameterMode class with static instances namely IN, OUT, and INOUT, to specify parameter-passing modes in Web service invocation. ParameterMode class acts as a type safe enumeration for parameter modes.
Holder Classes
Holder classes enable the mapping to preserve the intended operation signature and parameter passing semantics. A holder class is simply a class that contains an instance of its type. According to the JAX-RPC specification, each Holder class provides the following methods and fields
* A public field named value. The type of value is the mapped Java type
* A default constructor that initializes the value fields to a default value
* A constructor that sets the value field to the passed parameter
For example, the holder for the Double class would be:
public final class DoubleHolder implements
Holder {
public double value;
public DoubleHolder() { }
public DoubleHolder(double value) {
this.value = value;
}
}
In this article, I’ve used JAX-RPC Synchronous Request-Response Mode to explain the following parameter modes using Apache Axis.
* IN parameters using simple types
* IN and OUT parameters using simple types
* INOUT parameters using simple types
* OUT parameters using complex types
IN Parameters Using Simple Types
This example deals with developing a currency converter SOAP service (conversion from dollars to rupees). The service takes only one input parameter of simple type and returns a simple type.
Developing the SOAP Service
For example, develop a currency converter SOAP service as:
package com.mydomain.SampleService;
public class SampleService {
public double convertcurrencyin(double
in) {
double res = in * 48;
return res;
}
}
Here I’ve used the default rate; it should be replaced by the actual value.
Deploying the SOAP Service
Create a Web Services Deployment Descriptor file (deploy.wsdd) in order to deploy the Web service (see Listing 1). Deploy the service using the deploy.wsdd file as described in the Axis documentation.
Listing 1: Web ServicesDeployment Descriptor file
<deployment xmlns= "http://xml.apache.org/axis/wsdd/"
xmlns:java
=”http://xml.apache.org/axis/wsdd/providers/java”>
<parameter name="className"
value=”com.mydomain.SampleService”/>
Developing the SOAP Client
Create a service using ServiceFactory in order to create the Call objects.
Service service = new Service();
Call call = (Call)
service.createCall ( );
String endpointURL = http://localhost:
8080/axis/servlet/AxisServlet;
call.setTargetEndpointAddress( new
java.net.URL(endpointURL) );
After creating a Call object, configure the call object with the operation (method) name, parameter types, and parameter modes like IN or OUT or INOUT and return type (see Listing 2).
Listing 2: Configure the call object
Call.setOperationName( new Qname(“SampleService”, “convertcurrencyin”)
);
call.addParameter( “currency”, XMLType.XSD_DOUBLE,
ParameterMode.IN);
call.setReturnType(XMLType. XSD_DOUBLE);
After setting the parameter modes, parameter types, and return types, invoke the target end point by passing the parameters and get the result. The invoke( ) method calls a specified operation using the synchronous requestresponse interaction mode. Use the invoke OneWay( ) method for using the one-way interaction mode. The invoke method blocks until the remote service receives the method call and return either a response or an exception, whereas invokeOneWay( ) doesn’t block and this method is not allowed to propagate a remote exception to the client.
Double db = new Double (4.0);
Object ret = call.invoke( new Object[]
{ db} );
Use the Axis TCP Monitor tool to see the request/response message between the SOAP server and the client on the wire. The SOAP Messages look like Listing 3.
Listing 3: SOAP Message
SOAP Message request
<convertcurrencyin
soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
4.0
SOAP Message response
<convertcurrencyinResponse
soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
<convertcurrencyinReturn
xsi:type=”xsd:double”>192.0
Observe the request and response message and notice that Response is appended to the name of operation i.e. convertcurrencyin. Apache Axis appends operation/ method name for the return element where as some SOAP servers don’t. (See source code for this article, available at www.syscon. com/webservices/sourcec.cfm.)
IN and OUT Parameters Using Simple Types
This example shows how to develop a service and client using in and out parameters. The out parameters are achieved using Holder classes.
Developing the SOAP Service
In this example the client sends the currency to be converted as an input parameter to the service and the client receives the converted currency as output by using the holder classes. The service looks like:
package com.mydomain.SampleService;
public class SampleService {
public int convertcurrencyout(double
in, DoubleHolder dh) {
double res = in * 48;
dh.value = res;
return 1;
}
}
Deploying the SOAP Service
Add the following entries to the deploy. wsdd file as a child element of the service element and deploy the service.
<parameter name="result"
mode=”OUT”/>
A parameter element is used to specify parameter modes and parameter names. This is one of the ways that Axis SOAP server gets the information about the parameters.
Developing the SOAP Client
Create a Call object and configure the objects with the service details (see Listing 4). Parameters of the type OUT need not be passed to the invoke method.
Listing 4: Service details
call.setOperationName( new
QName(“SampleService”, “convertcurrencyout”) );
call.addParameter( “currency”, XMLType.XSD_DOUBLE,
ParameterMode.IN);
call.addParameter(
“result”,XMLType.XSD_DOUBLE,ParameterMode.OUT);
call.setReturnType(
org.apache.axis.encoding.XMLType.XSD_INT);
Double db = new Double(4.0);
Object ret = call.invoke( new Object[] { db} )
In order to get the output parameters from the target end point service, use the method getOutputParams( ) on the Call object as shown in Listing 5.
Listing 5: Use get output Params()
Map outparams = call.getOutputParams();
Setse = outparams.keySet();
Object obj[] = se.toArray(); // iterate this array get
the parameter names
// To get the actual value from the service
Collection se1 = outparams.values();
Object obj1[] = se1.toArray(); // // iterate this array get
the parameter values
The messages in Listing 6 are sent and received from the SOAP server. Observe the SOAP response, it has an additional element “result” after the return element. Each output parameter will have an element in the SOAP response with the output value.
Listing 6: Messages sent and received from SOAP server
SOAP Message request
<convertcurrencyout
soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
4.0
SOAP Message Response
<convertcurrencyoutResponse
soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
<convertcurrencyoutReturn
xsi:type=”xsd:int”>1
192.0
INOUT Parameters Using Simple Types
SOAP INOUT parameters are achieved using Holder classes.
Developing the SOAP Service
In this example the Client sends the currency as an instance of DoubleHolder. The service accesses the currency by using the holder’s value field and setting the converted currency in the same field.
The service looks like:
package com.mydomain;
import javax.xml.rpc.holders.*;
public class SampleService {
public int
convertcurrencyinout(DoubleHolder dh) {
dh.value = dh.value * 48;
return 1;
}
}
Developing the SOAP Client
Create the Call object and configure it with the service details in Listing 7.
Listing 7: Service details
call.setOperationName( new QName(“SampleService”,
“convertcurrencyinout”) );
call.addParameter( “currency”, XMLType.XSD_DOUBLE,
ParameterMode.INOUT);
call.setReturnType(
org.apache.axis.encoding.XMLType.XSD_INT);
Double dbinout = new Double(5.0);
call.invoke( new Object[] {dbinout} );
Observe that code and notice that the parameter mode is ParameterMode.INOUT and the passed parameter is the holder’s wrapper class, i.e., Double. There is no difference in getting the output from the service for output parameters and INOUT parameters. On the wire the SOAP message looks like Listing 8.
Listing 8
SOAP Message request
<convertcurrencyinout
soapenv:encodingStyle =”http://schemas.xmlsoap.org/soap/encoding/” >
4.0
SOAP Message Response
<convertcurrencyinoutResponse
soapenv:encodingStyle =
“http://schemas.xmlsoap.org/soap/encoding/” >.
<convertcurrencyinoutReturn
xsi:type=”xsd:int”>1
192.0
So far I’ve discussed simple data types only. What about complex data types? JAX-RPC specifies the semantics for Java serialization in terms of XML mapping. Axis provides default serialization and deserialization for the JavaBeans. In my next example I’ve used user-defined holders (AddressHolder) for the output parameter and user-defined type (Address) and used axis default bean serialization. Use Apache’s Java to WSDL tool to generate a WSDL file. It generates complex data types for the user-defined types like Address Object. I have not used WSDL to invoke the remote service
OUT Parameters Using Complex Types
In this example the client sends an order ID to the remote SOAP service and the service will return the shipment address as output parameter in the response message. Since Shipment Address is an output parameter, create a holder class to hold the Address and create Address class according to the JavaBeans Specification.
SOAP Service
package com.mydomain;
public class SampleService {{
public String getShipmentDetail(String
orderId, AddressHolder adrh) {
Address adr = new Address();
adr.setstreet(“CunninghamRoad”);
adr.setcountry(“INDIA”);
adrh.value = adr;
return orderId;
}
Add the following entries in the deploy.wsdd file inside the service element and register the bean mappings as shown below.
<parameter name="orderId"
mode=”IN”/>
<parameter name="result"
mode=”OUT”/>
<beanMapping qname="myNS:Address"
xmlns:myNS=”urn:MyService”
languageSpecificType=”java:com.mydomain.
Address”/>
SOAP Client
On the client side, register the serializers and deserializers for the user-defined data types, i.e., for the Address object.
QName qn = new QName(
“urn:SampleService”, “Address” );
call.registerTypeMapping(Address.class,
qn,
new
org.apache.axis.encoding.ser.BeanSeriali
zerFactory(Address.class, qn),
new
org.apache.axis.encoding.ser.BeanDeseria
lizerFactory(Address.class, qn));
Once the type mappings are registered, pass the parameters and invoke the service as shown:
call.setOperationName( new
QName(“SampleService”,
“getShipmentDetail”) );
call.addParameter( “orderId”,
XMLType.XSD_STRING, ParameterMode.IN);
call.addParameter(
“result”,qn,ParameterMode.OUT);
call.setReturnType(
org.apache.axis.encoding.XMLType.XSD_STR
ING );
String orderId = “ORD_001”;
String val = (String)call.invoke( new
Object[] {orderId} );
Retrieving the output parameter is the same as for the simple types. Generating the SOAP message on the wire looks like Listing 9.
Listing 9: SOAP Message request
<getShipmentDetail
soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
ORD_001
SOAP Message response
<ns1:getShipmentDetailResponse
soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”
xmlns:ns1=”SampleService”>
<getShipmentDetailReturn
xsi:type=”xsd:string”>ORD_001
<multiRef id="id0" soapenc:root="0"
soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”
xsi:type=”ns2:Address” xmlns:soapenc=”http://schemas.xmlsoap.
org/soap/encoding/”
xmlns:ns2=”urn:SampleService”>
INDIA
CunninghamRoad
If you want to send a user-defined Holder (AddressHolder) as an INOUT parameter to the remote SOAP service, then pass the user-defined type (Address) as an INOUT parameter and register the type mappings.
References
* Apache Axis: http://xml.apache.org/axis
* JAX-RPC: http://java.sun.com/xml/jaxrpc
* SOAP: www.w3.org/TR/SOAP
Aravilli Srinivasa Rao, a software analyst at Hewlett-Packard, is technical lead for the development of HP’s public UDDI Registry. He is currently involved in a feasibility study of the projects in the mobile space to implement Web services. Aravilli holds a master’s degree in computer applications. SRINIVASA.RAO.ARAVILLI@HP.COM
COPYRIGHT 2003 Sys-Con Publications, Inc.
COPYRIGHT 2003 Gale Group