The WSDL to Java Remote Interface (RMI) Compiler

The Novell exteNd Web Services SDK wsdl2java compiler transforms WSDL documents into Java RMI interfaces. This provides Java programmers with a familiar and typed programming model for invoking and implementing Web Services. The client simply uses a stub to invoke the Web Service as if it was a regular Java object in the same address space, and the server implements a servlet base class.

The wsdl2java compiler is typically used when developing Java client programs that need to access an existing Web Service. As WSDL becomes more wide-spread it is expected that standard Internet services will be formalized with a WSDL document. The wsdl2java compiler can also be used when a developer want to provide a Java based implementation of some service defined using WSDL.

This guide to the Novell exteNd Web Services SDK wsdl2java compiler consists of the following sections:

  1. Introduction - a brief primer to WSDL and how it relates to RMI.

  2. Data Types - the data types supported by the wsdl2java compiler.

  3. Faults - how fault messages map to Java exceptions.

  4. In/Out and Result Parameters - support for in/out and out parameters.

  5. Custom Types - how to add new types to the wsdl2java compiler using type mapper.

You can also refer to the wsdl2java man page for a detailed description of the compiler's command line options.

Introduction

A WSDL document consists of the following major sections:

Most of the concepts in WSDL map to familiar Java concepts:

WSDL Java
Types Types
Message Parameters, return values and exceptions
Operation Method
Port type Interface
Binding The transport and protocol used by a Web Service object instance.
Service A set of addresses available to a Web Service object instance.

Table 1: Equivalence of WSDL and Java concepts.

Below is a very simple WSDL document without binding and service information. It defines a simple currency service, which returns the exchange rate between two countries.

<?xml version="1.0"?>
<definitions name="CurrencyService"
    targetNamespace="http://example.com/currency.wsdl"
    xmlns:tns="http://example.com/currency.wsdl"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns="http://schemas.xmlsoap.org/wsdl/">
  <message name="GetRateInput">
    <part name="country1" element="xsd:string"/>
    <part name="country2" element="xsd:string"/>
  </message>
  <message name="GetRateOutput">
    <part name="result" type="xsd:float"/>
  </message>
  <portType name="Currency">
    <operation name="getRate">
      <input message="tns:GetRateInput"/>
      <output message="tns:GetRateOutput"/>
    </operation>
  </portType>
</definitions>

Example 1: WSDL for a simple currency exchange service.

The currency WSDL maps into a simple Java RMI with a single method, as shown below.

import java.rmi.Remote;
import java.rmi.RemoteException;
 
public interface Currency extends Remote
{
    float getRate(String country1, String country2) throws RemoteException;
}

Example 2: Java interface for the simple currency exchange service.

Data Types

The table below lists the XML data types supported by the wsdl2java compiler and how they map into Java types. These types are defined in the http://www.w3.org/2001/XMLSchema namespace. For details about XML data types, please refer to the specification at the W3C website.

XML Data Type Java Data Type
anyType java.lang.Object
boolean boolean
byte byte
base64Binary byte[]
hexBinary byte[]
dateTime java.util.Calendar
integer java.math.BigInteger
double double
float float
int int
long long
decimal java.math.BigDecimal
short short
string java.lang.String
QName javax.xml.rpc.namespace.QName

Table 2: Mapping between XML and Java data types.

The remaining XML Schema simple data types are mapped to Novell exteNd Web Services SDK classes as summarized in Table 3 below:

XML Data Type Java Data Type
anyType java.lang.Object
anyURI com.sssw.jbroker.web.xsd.AnyURI
date com.sssw.jbroker.web.xsd.Date
duration com.sssw.jbroker.web.xsd.Duration
ENTITIES com.sssw.jbroker.web.xsd.ENTITIES
ENTITY com.sssw.jbroker.web.xsd.ENTITY
gDay com.sssw.jbroker.web.xsd.GDay
gMonth com.sssw.jbroker.web.xsd.GMonth
gMonthDay com.sssw.jbroker.web.xsd.GMonthDay
gYearDay com.sssw.jbroker.web.xsd.GYearDay
ID com.sssw.jbroker.web.xsd.ID
IDREF com.sssw.jbroker.web.xsd.IDREF
IDREFS com.sssw.jbroker.web.xsd.IDREFS
language com.sssw.jbroker.web.xsd.Language
Name com.sssw.jbroker.web.xsd.Name
NCName com.sssw.jbroker.web.xsd.NCName
NegativeInteger com.sssw.jbroker.web.xsd.NegativeInteger
NMTOKEN com.sssw.jbroker.web.xsd.NMTOKEN
NMTOKENS com.sssw.jbroker.web.xsd.NMTOKENS
NonNegativeInteger com.sssw.jbroker.web.xsd.NonNegativeInteger
NonPositiveInteger com.sssw.jbroker.web.xsd.NonPositiveInteger
NormalizedString com.sssw.jbroker.web.xsd.NormalizedString
PositiveInteger com.sssw.jbroker.web.xsd.PositiveInteger
Time com.sssw.jbroker.web.xsd.Time
Token com.sssw.jbroker.web.xsd.Token
UnsignedByte com.sssw.jbroker.web.xsd.UnsignedByte
UnsignedInt com.sssw.jbroker.web.xsd.UnsignedInt
UnsignedLong com.sssw.jbroker.web.xsd.UnsignedLong
UnsignedLong com.sssw.jbroker.web.xsd.UnsignedLong

Table 3: Mapping between other XML simple types and Java data types.

If the nillable attribute is set to "true" when declaring a simple XML type, the wsdl2java compiler generated Java box types, as summarized in Table 4 below:

XML Nillable Data Type Java Data Type
boolean java.lang.Boolean
byte java.lang.Byte
double java.lang.Double
float java.lang.Float
int java.lang.Integer
long java.lang.Long
short java.lang.Short

Table 4: Mapping between XML nillable types and Java data types.

The data types defined in the SOAP 1.1. specification are always nillable, which means they get mapped as specified in the table below:

SOAP Encoded Type Java Data Type
boolean java.lang.Boolean
byte java.lang.Byte
double java.lang.Double
float java.lang.Float
int java.lang.Integer
long java.lang.Long
short java.lang.Short
decimal java.util.BigDecimal
base64 byte[]

Table 5: Mapping between XML nillable types and Java data types.

Furthermore, the Novell exteNd WSSDK compilers support a number of other XML types, which have been declared in the http://schemas.silverstream.com/jBroker namespace. These types are listed in Table 6 below. Note that interoperability is not guaranteed when using Novell exteNd WSSDK data types, and these can only be used safely when both client and server was developed using Novell exteNd WSSDK.

Novell exteNd WSSDK XML Data Type Java Data Type
Class java.lang.Class
List java.util.List
Long java.lang.Long
Map java.util.Map
Set java.util.Set

Table 6: Mapping between Novell exteNd WSSDK XML types and Java data types.

Also, the wsdl2java compiler supports the SOAP array syntax defined in the WSDL specification. Any built-in or custom types can be used to create an array. Below is an example for string:

<complexType name="ArrayOfString">
  <complexContent>
    <restriction base="soapenc:Array">
      <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
    </restriction>
  </complexContent>
</complexType>

Example 3: Definition of an array type in WSDL.

Although Novell exteNd WSSDK prefers the above definition for arrays, it also supports a number of alternative definitions to provide more flexible parsing of WSDL documents. The four alternative array definitions shown below are also recognized by the wsdl2java compiler:

<complexType name='ArrayOfString'>
  <sequence>
    <element name='name' type='xsd:string' maxOccurs='unbounded'/>
  </sequence>
</complexType>

Example 3a: Alternative definition of an array type in WSDL.

<complexType name='ArrayOfString'>
  <complexContent>
    <restriction base='SOAP-ENC:Array'>
      <sequence>
        <element name='name' type='xsd:String' maxOccurs='unbounded'/>
       </sequence>
    </restriction>
  </complexContent>
</complexType>

Example 3b: Second alternative definition of an array type in WSDL.

<element name='ArrayOfString'>
  <complexType>
    <element name='name' type='xsd:String' maxOccurs='unbounded'/>
  </complexType>
</element>

Example 3c: Third alternative definition of an array type in WSDL.

<element name='ArrayOfString'>
  <complexType>
    <sequence>
      <element name='name' type='xsd:String' maxOccurs='unbounded'/>
    </sequence>
  </complexType>
</element>

Example 3d: Fourth alternative definition of an array type in WSDL.

Faults

WSDL allows operations to produce fault messages. A fault message maps to a Java exception by converting the fault message parts into properties of an exception Java Bean. A marshaler to serialize and de-serialize the exception Java Bean is also generated.

<?xml version="1.0"?>
<definitions name="NameService"
    targetNamespace="http://example.com/name.wsdl"
    xmlns:tns="    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://schemas.xmlsoap.org/wsdl/">
  <message name="GetNameInput">
    <part name="id" element="xsd:int"/>
  </message>
  <message name="GetNameOutput">
    <part name="result" type="xsd:string"/>
  </message>
  <message name="NameNotFound">
    <part name="id" type="xsd:int"/>
  </message>
  <portType name="NameService">
    <operation name="getRate">
      <input message="tns:GetNameInput"/>
      <output message="tns:GetNameOutput"/>
      <fault name="NoName" message="tns:NameNotFound"/>
    </operation>
  </portType>
</definitions>

Example 4: WSDL for a name service, which has a fault message.

The above WSDL document gets mapped into the following RMI.

import java.rmi.Remote;
import java.rmi.RemoteException;
 
public interface NameService extends Remote
{
    String getName(int id) throws NameNotFound, RemoteException;
}

Example 5: Java interface for the name service.

The NameNotFound exception is a Java Bean with one bean property for each part of the message. In addition to generating the exception class, the wsdl2java compiler also generates a NameNotFoundMarshaler Java class to support serialization and de-serialization of exceptions of this type.

public class NameNotFound extends Exception
{
    private int_id;
 
    public NameNotFound()
    {
    }
 
    public NameNotFound(int id)
    {
        _id = id;
    }
 
    public int getId()
    {
        return _id;
    }
 
    public setId(int_id)
    {
        _id = id;
    }
}

Example 6: Generated Java exception for the fault message.

Inout Parameters and Return Values

WSDL supports both in/out parameters and parameters with return values. An output message with a single part is normally mapped to a regular return value unless it is also an input parameter or it is specified in the parameterOrder attribute. Output messages with multiple parts are mapped to out parameters. Note that if a part has the name "result" or "return", the wsdl2java compiler will map it into a return value unless the input message also has a corresponding "result" or "return" part.

<?xml version="1.0"?>
<definitions name="InOutService"
    targetNamespace="http://example.com/inout.wsdl"
    xmlns:tns="http://example.com/inout.wsdl"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://schemas.xmlsoap.org/wsdl/">
  <message name="Input">
    <part name="A" element="xsd:int"/>
    <part name="B" element="xsd:long"/>
  </message>
  <message name="Output">
    <part name="A" type="xsd:int"/>
  </message>
  <portType name="Service">
    <operation name="foo" parameterOrder="B A">
      <input message="tns:Input"/>
      <output message="tns:Output"/>
    </operation>
  </portType>
</definitions>

Example 7: WSDL with parameter order and in/out and return parameters.

Since both the input and output messages have an "A" part, this maps into an in/out parameter. Since Java always uses pass-by-value semantics, this concepts is supported by using special holder classes that wrap a Java object or primitive type. There are holders for all types supported natively by Novell exteNd WSSDK, and the wsdl2java compiler automatically generates holders for any other out or in/out types. This example also illustrates the use of the parameterOrder attribute.

import java.rmi.Remote;
import java.rmi.RemoteException;
 
public interface Service extends Remote
{
    void foo(long B, IntHolder A) throws RemoteException;
}

Example 8: Java interface with Holder parameters.

Custom Types

The wsdl2java compiler is fully integrated with the type mapper component of Novell exteNd WSSDK. In order to make a custom type available to the wsdl2java compiler, you must provide a resource called xmlrpc.type.mappings. This resource should be available in the CLASSPATH in order for the compiler to pick it up. The format of this resource is the same as described in the address book example:

#
# Address Book Type Library Descriptor
#
address=addressbook.Address addressbook.AddressMarshaler addressbook.AddressMarshaler urn:AddressBook Address http://www.acme.com/schemas
exception=addressbook.NoAddressFound com.sssw.jbroker.web.encoding.BeanMarshaler com.sssw.jbroker.web.encoding.BeanMarshaler urn:AddressBook NoAddressFound http://www.acme.com/schemas

If you run the wsdl2java compiler with the -verbose flag, it will print out all type mapping resources it loads. An easy way to ensure that the compiler picks up the xmlrpc.type.mappings file is to place it in the lib directory where wssdk.jar is also located. The compilers will always include this directory into the CLASSPATH before running.



Copyright © 2003, 2004 Novell, Inc. All rights reserved. Copyright © 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved.