Interoperability with Other SOAP Implementations

Interoperability was one of the main reasons for creating SOAP in the first place. However, as with any non-trivial specification, the SOAP specification leaves several items up to interpretation. As a result (and also due to simply non-conforming implementations) a SOAP envelope generated by one SOAP implementation may not be properly understood by another implementation.

There is an active effort to improve the interoperability of various SOAP implementations being driven by folks in the "SOAP Builders" mailing list. Some of the issues / solutions described here arose / found by Apache SOAPers active in that effort (including Sam Ruby, Dug Davis and Glen Daniels).

If you would like to read more about interop problems, see the article by Keith Ballinger on MSDN. In that article Keith indentifies 3 types of common interop problems: transport problems, XML problems and SOAP problems. This document explains how you can configure and improve the interoperability of Apache SOAP with other SOAP implementations for each of the 3 types of problems. It is important to note that interoperability testing is an on-going task and that there are bound to be many other issues that come up in the future.

Transport Problems

The difficulty arises primarily with the "SOAPAction" header that SOAP uses. The value of the SOAPAction header is allowed to be null (that is, no value is specified), the empty string ("") - which means that no "intent" is specified, or an arbitrary quoted string. Apache SOAP client-side APIs have no difficulty generating any of these SOAPAction values. As such we do not believe there are any transport level interoperability problems with Apache SOAP.

Another common use of SOAPAction is as the mechanism to route or dispatch the incoming SOAP envelope to the target code that processes it. Apache SOAP does not support that - dispatching is done currently based on the namespace URI of the first child element of the <SOAP:Body> element only. That can potentially cause interop problems as SOAP does not preclude unnamespaced body entries. If an Apache SOAP user wishes to implement a service that must receive and process unnamespaced body entries, then currently there is no built-in mechanism to route those requests. It would require some (relatively small) modifications to the routing infrastructure to enable routing based on SOAPAction.

XML Problems

There are several XML problems that may occur - Keith's article identifies one which causes difficulties for Apache SOAP: the presence of a Byte Order Mark (BOM) for UTF-8 encoded SOAP requests. If using Apache Xerces, we believe that Apache SOAP will fail to read proper SOAP requests encoded in UTF-8 if they also include a BOM. While legal to have the BOM for UTF-8 encoded messages, it is not required to do so. The only known workaround at this time is to not send the BOM. Apache SOAP always sends SOAP envelopes using UTF-8 encoding currently and hence does not generate the BOM. While there are no known solutions for this problem when using Apache Xerces, it is unknown whether using an alternate JAXP enabled parser eliminates this problem.

The second type of XML problems are related to XML Schema support. The problem comes with the fact that there are actually three versions of XML Schema in use today: the version with a 1999 URI which was current when the SOAP v1.1 specification first came out in April 2000, the version with a 2000 URI reflecting a "nearly done" version and the recommended specification with a 2001 URI which became final in May 2001. Apache SOAP currently behaves as follows:

We believe that the current architecture of Apache SOAP offers the best possible compromise between flexibility and rigidity: serialize any given way and deserialize all possible ways.

SOAP Problems

Depending on xsi:type. The most common interop problem that Apache SOAP has had previously is related to the requirement for every SOAP (RPC) envelope read by Apache SOAP to be self-describing in terms of types. That is, Apache SOAP does not (by default) function without every typed value being explicitly typed in the envelope using the xsi:type attribute (see the XML Schema specifications for details). All SOAP envelopes generated by Apache SOAP will always have all the type information, however, other SOAP implementations do not (and are not required to) do so. Hence the interoperability problem.

The correct solution to this problem is for the SOAP runtime to be aware of the service description of the service of which the SOAP envelope is a request, say in WSDL form. Apache SOAP is not WSDL aware and is unlikely to become so.

As of v2.1, Apache SOAP has had a workaround for this problem. The basic problem is that someone has to tell the SOAP engine the type of each parameter of a SOAP RPC call so that the SOAP engine can deserializer the parameter. The workaround allows one to use the element name of the parameter as the schema type and to associate a Java type to map that to. An example will make the solution clear. Consider the following SOAP envelope representing an RPC call:

<SOAP:Envelope xmlns:SOAP="soap-uri">
  <SOAP:Body SOAP:encodingStyle="soap-enc-uri">
    <ns1:foo xmlns:ns1="ns1-uri">
      <arg1>.. value of arg1 ..</arg1>
      <x:arg2 xmlns:x="x-uri">.. value of arg2 ..</arg2>
    </ns1:foo>
  </SOAP:Body>
<SOAP:Envelope>

The problem is that Apache SOAP will not be able to deserialize <arg1>...</arg1> and <x:arg2>...</x:arg2> to appropriate Java objects without help. When an xsi:type attribute indicating the type of <arg1> or <x:arg2> is not found, Apache SOAP uses the name of the parameter (arg1 or x:arg2, in this case) with a namspace URI of "" for unqualified names as the type. Thus, in the above example, it would search for a deserializer to deserialize schema types {""}arg1 and {"x-uri"}arg2 (where the string within the braces represents the namespace URI of the element. All the user needs to do to is tell Apache SOAP what the deserializer is for each of these types.

Serializers for types are specified via the deployment descriptor for the server side and by invoking the appropriate API call. If one wanted to allow an Apache SOAP server to receive the above envelope and decode as discussed above, the deployment descriptor would need to have the following type mappings:

<isd:map encodingStyle="soap-enc-uri"
         xmlns:z="" qname="z:arg1"
         xml2JavaClassName="name-of-deserializer-class"/>
<isd:map encodingStyle="soap-enc-uri"
         xmlns:x="x-uri" qname="x:arg2"
         xml2JavaClassName="name-of-deserializer-class"/>

If one wanted to allow an Apache SOAP client to receive the above envelope (in response to some call) and decode as discussed above, the client-side code would need to do the following:

SOAPMappingRegistry smr = new SOAPMappingRegistry ();
Deserializer sd1 = new appropriate-deserializer ();
smr.mapTypes (Constants.NS_URI_SOAP_ENC,
              new QName ("", "arg1"), null, null, sd1);
Deserializer sd2 = new appropriate-deserializer ();
smr.mapTypes (Constants.NS_URI_SOAP_ENC,
              new QName ("x-uri", "arg2"), null, null, sd2);

The "guidgen" sample shows an instace of the latter.

While the approach in Apache SOAP allows one to work around the lack of WSDL support in most cases, there are cases where it still is not sufficient. Notably, if the name of a parameter coincides with another name within that parameter or elsewhere, one cannot use the name as a key to the type. That is, there is an implicit assumtion tha tthe names will be unique.

Note that the org.apache.soap.encoding.soapenc.BeanSerializer cannot be used in any of the above. The reason is that the bean serializer determines the Java type to produce by querying for the Java type. In the above registrations the Java type is indicated as null to prevent the type mapping registry from registering this deserializer as the default one for Java types. Thus the indicated deserializers must know (intrinsically) the type of Java object it is going to produce. There are deserializers for all the built-in types in the org.apache.soap.encoding.soapenc package to assist users in using this feature.

Not understanding mustUnderstand headers. Apache SOAP currently does not implement the "mustUnderstand" header concept of SOAP. This leads to potential interop difficulties as Apache SOAP may ignore unignorable things. The workaround Apache SOAP offers is the ability to tell the runtime, on a per-service basis, for RPC services only, whether to fault if any mustUnderstand headers are seen. This is available via an attribute in the deployment descriptor. The default value of the "checkMustUnderstands" attribute is false, which means no must understand checks will be done at all. Good citizen SOAP services should set that to true to tell the runtime to check for mustUnderstand attributes on headers.

Accessing headers. The default RPC provider in Apache SOAP does not provide access to any headers in the SOAP envelope to the actual service implementation. If one needs access to this, the workaround is to write your own provider that aceesses the headers and then processes the body (possibly by delegating to other providers).

Return parameters. SOAP RPC also has the notion of return parameters: responses carrying more than one "return" value. Apache SOAP's default RPC service provicer does not support such return parameters as those are beyond the scope of Java (which has only a single return value). Again, the workaround here is to write your own provider that allows the service implementation to not only set a return value, but any number of return "values."

Interoperability Testing

As mentioned earlier, the SOAP Builders forum is leading the charge on interoperability testing. There are several sites that are documenting various parts of the work:

The "bidybuy" sample in the Apache SOAP v2.3 release is an implementation of the "Bid Buy" test developed by the SOAP Builders forum. It provides a fairly comprehensive example of implementing a non-trivial interoperable Web service and service client.

Last updated 6/28/2001 by Bill Nagy <nagy@watson.ibm.com>.