Web Services Interoperability between J2EE and .NET - Part 1

Still RPC/encoded?

WS-I Basic Profile 1.0 promotes the use of literal XML for interoperability. It prohibits the use of soap:encodingStyle attributes to soap:Envelope or descendents of the soap:Body elements. Therefore, RPC/literal and Document/literal are the only two formats supported by the WS-I standards. But not many Web services toolkits support RPC/literal , so it leaves the Document/literal as the only actual interoperability standard.

However, the RPC/encoded way of doing things existed long before XML Schema or WSDL came into existence; even then, some encoding rules still can not be expressed in XSD. Even though SOAP encoding is recognized as one of the major sources of the Web services interoperability problems and, combined with the fact that the ASP.NET WebMethod infrastructure defaults to Document/literal , most of the J2EE Web services tools defaulted to RPC/encoded , until recently.

The RPC/encoded style is popular mainly because of its simple programming model for developers who are accustomed to the remote procedure calling convention. The RPC binding style uses the names of the method and its parameters to generate structures that represent a method's call stack, so it makes the Web services look like a single logical component with encapsulated objects, all handled in the SOAP RPC stack. This is in contrast with the Document/literal style in which developers have to assume everything, including the serialization and de-serialization of the XML-based SOAP messages.

Moreover, the SOAP encoding rules define standards to conveniently map the programmatic types to XML. The encoding rules are very flexible and support the representation of data graphs and polymorphism. This is no doubt more capable than the Document/literal model, which relies on the natural tree structures to represent data objects.

To get an idea of what the RPC/encoded model can and can't do, let's start with an example. Consider a Serializable Person class that defines a friend of its own, as shown in Listing 1 .

Listing 1. A Person class with self-reference

public class Person implements java.io.Serializable {
    private Person friend;
    private String name;
   
    public Person getFriend() {
        return this.friend;
    }
    public void setFriend(Person friend) {
        this.friend = friend;
    }
<!-- Other setter and getter methods -->
}

If you instantiate two Persons: A and B, and make Person A a friend of Person B and Person B a friend of Person A, you are creating a cyclical object graph:

Listing 2. The makeFriend method

public Person makeFriend(Person A, Person B) {
    A.setFriend(B);
    B.setFriend(A);
    return A;
}

If you were to expose the public method in Listing 2 as a Document/literal Web service, how would the cyclic graph be represented in XML?

It turns out there is no easy way to do this with the Document/literal approach. The reason: the Document/literal approach defines the message types as concrete types based on the XML Schema; the XML Schema represents natural tree structures with the XSD primitive types as leaf nodes. A cyclic object graph cannot be transformed into a tree structure. In this case, because of the circular references between the object instances A and B of the Person class, the serialization of object A and B falls into a recursive loop. With WebSphere Studio, for example, you see a stack overflow exception in the end. That doesn't mean that the Document/literal approach offers no way of doing this, but it would require considerable effort on the developers' side.

If you use the SOAP encoding as the message bindings, the circular reference can be easily represented by applying SOAP encoding rules on the cyclic graph by using the multireference accessors. Take a look at the serialized XML payload by the Web service running on a WebSphere platform in response to a SOAP request to make John and Jason friends of each other. Listing 3 shows how easy the cyclic graph is represented.

Listing 3. SOAP encoded response message from WebSphere

<soapenv:Body soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<makeFriendResponse xmlns="http://cyclic.test">
<makeFriendReturn href="#id0" xmlns=""/>
</makeFriendResponse>
<multiRef  id="id0" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns-
520570027:Person" xmlns:ns-520570027="http://cyclic.test" xmlns="">
<name xsi:type="xsd:string">John</name>
<friend href="#id1"/>
</multiRef>
<multiRef  id="id1" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns-
520570027:Person" xmlns:ns-520570027="http://cyclic.test" xmlns="">
<name xsi:type="xsd:string">Jason</name>
<friend href="#id0"/>
</multiRef>
</soapenv:Body >

Notice how SOAP uses the local unqualified attributes id0 and id1 of type ID to specify the unique identifiers for the encoded elements Person A (John) and Person B (Jason) and another local unqualified attribute href is used to specify references to those two ID values. The circular references between Object A and Object B are handily represented by the flexible SOAP encoding rules.

The power of the RPC/encoded model has enormous appeal to traditional object-oriented programmers who are accustomed to programming within a single organizational domain, such as J2EE technology or .NET. While it provides great ease for the Web services designers and implementers when the scope is limited to a single platform where both the SOAP message writers and readers have a synchronized stub to understand the encoded SOAP messages, it comes at a big price as Web services go global. Its powerful strength turns out to be its weakness in the face of the demand for interoperability across platforms. To illustrate the interoperability problem, examine the WSDL file that Application Developer generated from the previous Web service (see Listing 4 ).

Listing 4: The WSDL document defining the rpc/encoded MakeFriend Web service

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://cyclic.test" xmlns:impl="http://cyclic.test"
xmlns:intf="http://cyclic.test"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
  <schema targetNamespace="http://cyclic.test"
xmlns="http://www.w3.org/2001/XMLSchema" xmlns:impl="http://cyclic.test"
xmlns:intf="http://cyclic.test"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
  <complexType name="Person">
    <sequence>
    <element name="name" nillable="true" type="xsd:string"/>
    <element name="friend" nillable="true" type="impl:Person"/>
    </sequence>
  </complexType>
  <element name="Person" nillable="true" type="impl:Person"/>
  </schema>
</wsdl:types>
<wsdl:message name="makeFriendResponse">
      <wsdl:part name="makeFriendReturn" type="intf:Person"/>
</wsdl:message>
<wsdl:message name="makeFriendRequest">
      <wsdl:part name="A" type="intf:Person"/>
      <wsdl:part name="B" type="intf:Person"/>
</wsdl:message>
<wsdl:portType name="MakeFriends">
      <wsdl:operation name="makeFriend" parameterOrder="A B">
          <wsdl:input message="intf:makeFriendRequest" name="makeFriendRequest"/>
          <wsdl:output message="intf:makeFriendResponse"
name="makeFriendResponse"/>
      </wsdl:operation>
</wsdl:portType>
      <wsdl:binding name="MakeFriendsSoapBinding" type="intf:MakeFriends">
          <wsdlsoap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
          <wsdl:operation name="makeFriend">
          <wsdlsoap:operation soapAction=""/>
            <wsdl:input name="makeFriendRequest">
                <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://cyclic.test" use="encoded"/>
            </wsdl:input>
            <wsdl:output name="makeFriendResponse">
                <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://cyclic.test" use="encoded"/>
            </wsdl:output>
          </wsdl:operation>
    </wsdl:binding>
<wsdl:service name="MakeFriendsService">
    <wsdl:port binding="intf:MakeFriendsSoapBinding" name="MakeFriends">
        <wsdlsoap:address
location="http://localhost:9080/CyclicTestEJBClient/services/MakeFriends"/>
    </wsdl:port>
</wsdl:service>
</wsdl:definitions>

In the WSDL document, the operation makeFriend 's output message makeFriendResponse has a message part makeFriendReturn of Person type. According to the schema, the Person complex type must have the direct child elements name of xsd:string type and friend of Person type, and should not have any other types and attributes. However, the serialized SOAP response message ( Listing 3 ) certainly does not match this rule. The href attribute in the response message is not present in the definitions. Given this discrepancy, how do you tell the message receiver that the elements A and B are instances of the Person class?

In fact, if you code a .NET client to talk to this Web service, the .NET client fails to de-serialize the WebSphere response, as in Listing 3 . What the .NET client expects is the following response message to describe that John and Jason are friends:

Listing 5: SOAP encoded response message from .NET

<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<tns:makeFriendsResponse>
    <makeFriendsResult href="#id1" />
</tns:makeFriendsResponse>
<types:Person id="id1" xsi:type="types:Person">
    <name xsi:type="xsd:string">John</name>
    <friend href="#id2" />
</types:Person>
<types:Person id="id2" xsi:type="types:Person">
    <name xsi:type="xsd:string">Jason</name>
    <friend href="#id1" />
</types:Person></soap:Body>

As you see, the multireference accessor encoding is powerful, but it is difficult to express in XSD. As a result, the implementations can have some subtle differences between different platforms, as in Listing 3 and Listing 5. This example illustrates the gap between SOAP encoding and XML Schema validation. Unlike the Document/literal approach, which passes through the literal documents and relies on the XML Schema to validate and de-serialize the XML representation of objects, the RPC/encoded model uses the SOAP encoding rules to represent the abstract SOAP data model and relies on the vendors' SOAP library to provide the concrete implementation of the abstract SOAP data model. It is thus highly platform-dependent. There is no intermediary specification to fill the gap and, as a result, this approach is open to different implementations by vendors. Although SOAP is a standard, the SOAP implementations (such as the DOM-based Apache SOAP library and the SAX-based Apache AXIS library for Application Developer V4 and V5, MS SOAP toolkit for MS .NET Framework 1.1) have subtle differences because of the lack of XML Schema support.

You might also like...

Comments

About the author

Wangming Ye United States

Wangming Ye is an IBM Certified Enterprise Developer and a Sun Certified Enterprise Architect for J2EE Technology. He began as a developer in the DCE/DFS department at Transarc Corporation (late...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Debuggers don't remove bugs. They only show them in slow motion.”