Skip Headers
Oracle® Application Server Advanced Web Services Developer's Guide
10g Release 3 (10.1.3)
B25603-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

1 Ensuring Interoperable Web Services

This chapter contains the following sections.

Why is Interoperability Necessary?

The goal of the Web service architecture is to allow heterogeneous business applications to smoothly work together. The architecture is loosely coupled and based on XML standards. Web services are designed to work with each other by defining Web Service Description Language (WSDL) files as service contracts, regardless of which operating system and development technology are behind them. However, because of the complexity involved in service contracts, standards like WSDL and SOAP leave room for ambiguous interpretations. In addition, vendor-specific enhancements and extensions work against universal interoperability.

Business applications must invoke each other's services. These services are often implemented with different technologies. Interoperability failures tend to increase as Web service complexity increases. If you host a publicly available Web service, you will want to ensure that your clients from all over the world, using vastly different tool kits, can successfully invoke it. Likewise, your business application might need to integrate or interact with another vendor's Web service that was built on top of an existing legacy system and has an unusual interface design.

Interoperability issues can originate from any layer of the protocol stack. On the transport level, both parties involved in exchanging messages must agree on a specific physical transport mechanism. For example, you cannot expect to use JMS transport from a non-Java platform. This is why using basic HTTP protocol increases your chance of interoperability. On the message level, because SOAP allows virtually any type of data encoding to be used, interoperability can become difficult. For example, a standard ArrayList on a Java platform will not be automatically translated into a System.collections.ArrayList on the .NET platform. Also, interoperability issues arise at the basic WSDL and SOAP level: advanced Web service developers will find many more new challenges when they start implementing quality of service (QOS) features such as security, reliability, and transaction services.

Difficulties in interoperability do exist. However, with a few good guidelines, your Oracle Web service should work seamlessly with other J2EE vendor platforms or non-Java platforms like the Microsoft .NET platform.

Web Service Interoperability Organizations

As interoperability gains more and more importance in the Web service community, a number of organizations have been established to achieve this goal.

SOAPBuilders Community

SOAPBuilders is a loosely organized forum of developers working toward a test bed for interoperability testing between SOAP implementations. Interoperability is demonstrated by implementing a canonical set of tests that are collectively defined by the participants in the forum.

The tests developed by the SOAPBuilder community are, by and large, based on vendor practices. However, practices shift over time. Clean and well-defined rules organized in a formal manner are needed for Web service vendors, Web service developers, and Web service consumers.

You can find more information on SOAPBuilder tests at the following Web site.

http://www.whitemesa.net/

WS-Interoperability

The Web Services Interoperability organization (WS-I) is an open industry organization that creates, promotes, and supports generic protocols for the interoperable exchange of messages between Web services. WS-I profiles are guidelines and recommendations for how the standards should be used. These profiles aim to remove ambiguities by adding constraints to the underlying specifications.

WS-I deliverables are profiles, common or best practices, scenarios, testing software, and testing materials.

You should design your Web service so that it adheres to WS-I basic profiles. WS-I compliant services agree to clear contracts and have a greater chance of interoperability.

For example, a WS-I basic profile-compliant Web service should use the following features.

There are many rules defined in the profiles. For more information about WS-I profiles, see the following Web site.

http://www.ws-i.org

Oracle is a member of the WS-I organization and is fully committed to helping our customers to achieve interoperability. The Oracle Application Server Web Services platform allows a high degree of flexibility to help you create interoperable Web services.

General Guidelines for Creating Interoperable Web Services

The first general guideline is to create Web services which are WS-I compliant, if possible.

The WS-I profiles, however, do not solve all interoperability problems. Many Web services were implemented before WS-I profiles existed. Also, the legacy systems that you are enabling as a Web service might have placed restrictions on your designs.

Thus, good practice in designing Web services should always be adopted from the beginning of the development process, whenever possible. The following sections describe these guidelines.

Design your Web service top down

The top down approach enables you to design your Web service from service contracts that are not tied to any platform or language-specific characteristics. Your WSDL is less likely to be affected by existing legacy APIs.

Design data types using XSD first

If possible, use an XSD schema editor to design your data types with schema types. Resist using platform-specific data types such as the .NET DataSet data type, Java collections, and so on.

Keep data types simple

Avoid unnecessarily complex schema data types such as xsd:choice. Simple types provide the best interoperability and have the added benefit of improved performance.

Be careful with null values

Decide what you want to do with null values. For example, should an array be allowed to be null? Should you use a null string or an empty string? If you are sending a null value across the platform, will it cause exceptions on the receiver side?

Avoid sending null values if possible. If you must use null values in your application, design your schema types to clearly indicate that a null value is allowed.

Use a compliance testing tool to validate the WSDL

If your Web service is designed to be WS-I compliant, use the WS-I monitor tool to log messages and the analyzer tool to validate for conformance. WS-I tools can be downloaded for free from the following Web site.

http://www.ws-i.org/deliverables/workinggroup.aspx?wg=testingtools

Understand the differences between platform native types

Some schema types, such as xsd:unsignedshort and xsd:unsignedint, do not always have a direct native type mapping. For example, there are no Java platform equivalent unsigned types. Schema numeric types such as xsd:double, xsd:float, and xsd:decimal might have different precisions once mapped to their platform native types. There are also limitations on the xsd:string type. The strings must not contain illegal XML characters and the \r (carriage return) character will typically be mapped to the \n (line feed) character.

Avoid using RPC-encoded message format

By itself, the RPC-encoded message format does not imply that you will not be able to interoperate with other platform and clients. In many cases, there are RPC-encoded Web services which are working today. The reason to move away from RPC-encoded message formats is to avoid some of the corner cases where different interpretations of the underlying specification and implementation choices break interoperability. Some examples of these corner cases include the treatment of sparse arrays, multi-dimensional arrays, custom fault code QNames, un-typed payloads, and so on.

Common Tips for Diagnosing and Solving Interoperability Issues

Many interoperability problems can be recognized and solved by understanding the relationship between the WSDL, the wire format, and the validity of the data representation. Once you can identify where the issue is, correcting it can be straightforward.

Figure 1-1 illustrates the interaction between the elements in a client stack and a service stack. The WSDL is used to generate the client artifacts. The client application, which could be implemented for either the JAX-RPC or .NET platform, forms an XML SOAP request message. The application serializes the request and passes it to the service over HTTP. The service, which could be implemented for either the JAX-RPC or .NET platform, deserializes the request and processes it.

After processing the client request, the service application forms the XML SOAP response message, serializes it, and passes it to the client over HTTP. The client application deserializes the response and processes the result.

Figure 1-1 Points of Possible Interoperability Failures

Description of Figure 1-1 follows
Description of "Figure 1-1 Points of Possible Interoperability Failures"

The numbers and letters in the illustration identify the points, from the client's perspective, where interoperability failures can occur. On the server side, the failure points are similar. The following list describes these problems.

  1. The utility which generates the client artifacts fails to consume the WSDL (the contract). The WSDL is either invalid, not compliant with a WS-I Profile, or not supported by the client platform. For example, .NET 1.1 does not support RPC-literal style of Web service. "Invalid or Improperly Formatted WSDL" provides more information on this type of failure.

  2. The utility which generates the client artifacts consumes the WSDL successfully, but the artifacts it generates cannot be used or are not very useful. For example, the WSDL might contain proprietary schema extensions that the tool cannot process. "WSDLs Containing Proprietary Data Binding Extensions" provides more information on this type of failure.

  3. At runtime, an exception is thrown to the client application before any payload is actually processed. Usually, the error will be converted into a SOAP fault with a fault code set as Client in SOAP 1.1 or Sender in SOAP 1.2. The reason could be that the service endpoint is unavailable or authentication negotiation is not successful. "Illegal XML Characters" provides more information on this type of failure.

  4. A SOAP fault is thrown from the server side due to one of the following reasons.

    1. The request is not routed to the correct operation. The SOAP fault code would be set as Client in SOAP 1.1 or Sender in SOAP 1.2. "Out of Sync SOAPAction Values" provides more information on this type of failure.

    2. The request is not deserialized successfully. The SOAP fault code would be set as Client in SOAP 1.1 or Sender in SOAP 1.2. "Null Values in SOAP Messages" and "Unsigned Schema Numeric Types" provide more information on this type of failure.

    3. The request is not processed by the application code. The internal exception which is thrown could be an unhandled exception or an application-specific SOAP fault at the business logic level. The SOAP fault code will be set as Server or Receiver unless the server application considers the error to be related to the validation of input parameters.

    4. The response is not serialized. The SOAP fault code will be set as Server or Receiver.

  5. At runtime, an exception is thrown by the client when it tries to deserialize the response to convert the content of the SOAP envelope back into Java instances. "Loss of Precision" provides more information on this failure.

The following sections provide more information and examples of the failures that can occur at each of these points.

Invalid or Improperly Formatted WSDL

Interoperability failures can be caused by errors that arise in processing the WSDL. This is indicated in Point 1 in Figure 1-1. Different tool kits are not consistent in how they process WSDLs. For example, an improperly formatted WSDL might be graciously accepted by one tool kit but rejected by another.

Example

The following code samples illustrate how an improperly formatted WSDL can cause an interoperability failure.

Example 1-1 illustrates a fragment from an improperly formatted WSDL. The fragment contains an improperly named input parameter, getQuote. Notice that the portType operation has defined an input parameter named getQuote, but the corresponding binding operation does not provide input or output names. If you use the default naming pattern (<operationName>Request and <operationName>Response) to create the missing binding operation input and output names, then the WSDL will not be valid because the getQuote operation will have inconsistent input parameters.

Example 1-1 WSDL Fragment with an Improperly Named Input Parameter

<portType name="qotdPortType">
  <operation name="getQuote">
    <input name="getQuote" message="tns:getQuoteRequest"/>
    <output name="getQuoteResponse" message="tns:getQuoteResponse"/>
  </operation>
</portType>
<binding name="qotdBinding" type="tns:qotdPortType">
  <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
  <operation name="getQuote">
    <soap:operation soapAction="urn:xmethods-qotd#getQuote"/>
    <input>
      <soap:body use="encoded"
                 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
                 namespace="urn:xmethods-qotd"/>
    </input>
    <output>
      <soap:body use="encoded"
                 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
                 namespace="urn:xmethods-qotd"/>
    </output>
  </operation>
</binding>

If you attempt to generate client proxy classes from this WSDL, problems will arise regardless of whether you are on the .NET or the Oracle Application Server Web Services platforms. If you attempt to generate client proxy C# classes on the .NET platform, you will get errors rejecting the WSDL as not having a matching binding. On the Oracle Application Server Web Services platform, Java client proxy classes will be generated, however, you will get warnings about the improper input and output names used in the WSDL.

Unfortunately, the WSDL specification does not clearly specify that the default naming pattern for the portType operation should be used for the binding operation when input and output names are missing. It is not clear whether the WSDL should be rejected. The OracleAS Web Services tool kit will graciously accept this WSDL and output warnings.

The potential interoperability problem illustrated in this example can be corrected by specifying the name attribute for the input in the binding operation and in the portType.

WSDLs Containing Proprietary Data Binding Extensions

Point 2 in Figure 1-1 represents a failure point where the tool kit is unable to generate useful artifacts from the given WSDL. This problem can arise if the WSDL contains proprietary data binding extensions.

Example

The following code samples illustrate how working with a WSDL that contains proprietary data binding extensions can cause interoperability failures.


Note:

The following code samples use the ADO.NET System.Data.DataSet data type as an example of a proprietary data binding that can cause interoperability failures. However, because XML is extensible by nature, you will likely face this issue when dealing with other proprietary data bindings as well.

Assume that you are developing a Web service for the .NET platform and you have the following C# method that returns a System.Data.DataSet data type.

public System.Data.DataSet ListBooks (  )

Example 1-2 illustrates an XML schema fragment that represents the response output element when the method is exposed as a .NET Web service.

Example 1-2 XML Schema Fragment for a .NET Web Service

<s:element name="ListBooksResponse">
   <s:complexType>
    <s:sequence>
      <s:element minOccurs="0" maxOccurs="1" name="ListBooksResult">
        <s:complexType>
        <s:sequence>
          <s:element ref="s:schema"/>
          <s:any/>
        </s:sequence>
        </s:complexType>
       </s:element>
      </s:sequence>
    </s:complexType>
</s:element>

Suppose you want to use the WebServicesAssembler tool to generate client proxy code based on this WSDL. WebServicesAssembler will consume the WSDL successfully and will generate a set of proxy classes including the client code that contains the following Java method.

public javax.xml.soap.SOAPElement listBooks(ListBooks parameters) throws java.rmi.RemoteException 

The response is returned as a SOAPElement because OracleAS Web Services cannot infer any more detailed information from the schema definition. Unfortunately, the schema in the .NET WSDL in Example 1-2 does not fully describe the payload you will receive on the wire representing the .NET DataSet data type. The schema describes only that the SOAP message contains two parts: the first part is the schema definition for the payload and the payload follows next.

Example 1-3 illustrates the SOAP message that the client receives. Notice that the first child of the xs:schema element (<xs:element name="NewDataSet"...>) describes the payload of the message. The second child, (<diffgr:diffgram ...>) contains the payload.

Example 1-3 SOAP Message Generated from a .NET DataSet Data Type

<soap:Body>
      <ListBooksResponse xmlns="http://francisshanahan.com/">
         <ListBooksResult>
            <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
               <xs:element name="NewDataSet" msdata:IsDataSet="true">
                  <xs:complexType>
                     <xs:choice maxOccurs="unbounded">
                        <xs:element name="bible_content">
                           <xs:complexType>
                              <xs:sequence>
                                 <xs:element name="Book" type="xs:string" minOccurs="0"/>
                                 <xs:element name="BookTitle" type="xs:string" minOccurs="0"/>
                              </xs:sequence>
                           </xs:complexType>
                        </xs:element>
                     </xs:choice>
                  </xs:complexType>
               </xs:element>
            </xs:schema>
            <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
               <NewDataSet xmlns="">
                  <bible_content diffgr:id="bible_content1" msdata:rowOrder="0">
                     <Book>01</Book>
                     <BookTitle>The First Book of Moses, called Genesis</BookTitle>
                  </bible_content>
                  <bible_content diffgr:id="bible_content2" msdata:rowOrder="1">
                     <Book>02</Book>
                     <BookTitle>The Second Book of Moses, Called Exodus</BookTitle>
                  </bible_content>
                  …
               </NewDataSet>
            </diffgr:diffgram>
         </ListBooksResult>
      </ListBooksResponse>
   </soap:Body>
</soap:Envelope>

Since the WebServicesAssembler tool is unable to provide you with Java type classes that capture the payload schema, how would you write a Java client to process the dataset records appropriately?

The solution is a two step process.

  1. Obtain the schema. The code must parse the incoming SOAPElement, extract the schema child element and save the schema definition.

    <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    
    
  2. Process the actual payload based on the schema you have.

    You can use tools such as JAXB and Oracle TopLink to process the payload. JAXB provides a Java API and command line tools to help you generate Java type-safe classes directly from the schema.

    Oracle TopLink is an advanced object to relational persistence framework that includes support for JAXB. With TopLink, however, you also get a visual mapping editor and many other advanced features. For more information on TopLink, see the following Web site.

    http://www.oracle.com/technology/products/ias/toplink/index.html

    Once you have generated Java types based on the schema with your preferred tools, you can now process the actual SOAP payload and extract the any element that comes after the schema. This element has the tag name diffgr and the actual payload starts as the first child of the <diffgr> element.

    <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
    

Illegal XML Characters

Sometimes, even though you have a perfectly valid WSDL that can successfully generate client artifacts, an application might fail before reaching the server side. This is illustrated in Figure 1-1 as Point 3. Usually, this failure occurs because the service is currently unavailable. There are other, harder to detect, cases as well. For example, the application might have produced invalid XML data in the SOAP message. The application could also be attempting to pass characters which are invalid in XML. In these cases, the server transport layer immediately rejects the message before it reaches the Web service.

If your application must send special characters or data in the SOAP Body that could cause XML parsing errors, then the application should be designed to use a basic encoding scheme such as BASE64Encoding.

Example

The following code samples illustrate how an attempt to pass an invalid XML character in a SOAP message can cause an interoperability failure.

Assume that your C# client application code sends a command string and the service executes the command for the client. Also assume that one of the commands uses the backspace character (\b).

MyCommand request = new MyCommand("\b");
MyCommandResponse response = soapClient.runCommand(request);

If the client application tries to send a command string containing the backspace character (\b), OracleAS Web Services will reject it because the backspace character is an invalid XML character. This can return an HTTP transport error and a HTML reply similar to the following.

<HTML><HEAD><TITLE>Web Service</TITLE></HEAD><BODY><H1>Bad Request</H1><PRE>Error parsing envelope: (2, 237) Invalid char in text.</PRE></BODY></HTML>

Out of Sync SOAPAction Values

In OracleAS Web Services, the value of the soapAction attribute of the WSDL operation element is a URI constructed from the target namespace and the operation name. It has the format (http://<target-namespace>/<operation-name>). This same value should also be used as the value of the SOAPAction HTTP header for this operation in the SOAP request message. If it is not, then unexpected behavior can occur. This type of failure is referred to as Point 4a in Figure 1-1.

Most SOAP processors use the SOAPAction HTTP header as a hint to route the request to the appropriate operation without having to decode the full body. Some implementations support the SOAPAction value of quoted string ("", that is, the empty string). The SOAPAction may even be missing from the HTTP header. You should always use a quoted string to avoid interoperability problems.

This problem indicates that the client is out of sync with the WSDL published by the service. To solve this problem, regenerate your client so that it is consistent with the WSDL for the service.

Example

The following code samples illustrate how a mismatch between the values of the soapAction attribute of the WSDL operation element and the SOAPAction HTTP header for this operation can cause an interoperability failure.

Assume that you have the following add operation defined in WSDL.

<soapbind:operation soapAction= "http://ws.oracle.com/demo/:add"/>

Example 1-4 illustrates a SOAP request that is sent at runtime. Note that the message sets a multiply SOAPAction for an add operation.

Example 1-4 SOAP Request Fragment, Illustrating Value of SOAPAction

POST http://localhost/khub/MathService.asmx HTTP/1.1

Host: localhost
Proxy-Connection: Keep-Alive
Connection: TE
TE: trailers, deflate, gzip, compress
User-Agent: Oracle HTTPClient Version 10h
SOAPAction: "http://ws.oracle.com/demo/:multiply"
Accept-Encoding: gzip, x-gzip, compress, x-compress
Content-type: text/xml; charset="UTF-8"
Content-length: 347

<?xml version = '1.0' encoding = 'UTF-8'?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns0="http://ws.oracle.com/demo/">
   <env:Body>
      <ns0:addElement>
         <ns0:a>3</ns0:a>
         <ns0:b>2</ns0:b>
      </ns0:addElement>
   </env:Body>
</env:Envelope>

OracleAS Web Services will throw an error and quit processing because the server detects that there is a mismatch between the SOAPAction HTTP header value and the first child element of the SOAP body element (<ns0:addElement>). The error will look similar to the following.

unexpected element name: expected={http://ws.oracle.com/demo/}addElement, actual={http://ws.oracle.com/demo/}multiplyElement

In a .NET 1.1 implementation, because the SOAPAction header is used by default for dispatching SOAP messages, the multiply operation will be invoked by mistake instead of the add operation. A fault will not be generated. Example 1-5 illustrates the incorrect response that .NET returns from the multiply service. It should return a fault because the wrong Web service was invoked. Another possible behavior is to ignore the invalid value of the SOAPAction, and route the message to the add operation, based on the payload of the request.

Example 1-5 Incorrect Response Returned by .NET

<multiplyResponseElement xmlns="http://ws.oracle.com/demo/">
         <MultiplyResult>0</MultiplyResult>
      </multiplyResponseElement>

The Apache Axis platform does not rely on the SOAPAction header to route the operation. It will always use the top element of the SOAP Body payload to find a matching operation.

Understanding the soapAction WSDL Attribute

To prevent unexpected behaviors from occurring in Web service interactions, it is useful to understand how the value of the soapAction attribute in the WSDL is set, and its effect on the value of the SOAPAction header in the SOAP message. The following sections describe how this attribute is set and used on the OracleAS Web Services and .NET platforms.

Controlling the Value of soapAction in OracleAS Web Services

When you use the Oracle WebServicesAssembler tool to assemble Web services from Java code, a unique soapAction attribute value is generated for each operation in the WSDL.

You can control the value of this attribute with the Boolean emptySoapAction argument. If you set the argument to true, then the soapAction attribute for each SOAP binding operation in the generated WSDL is set to an empty string and the SOAPAction header in the SOAP message is set to a quoted ("") string. Setting this argument to true increases the chances of interoperability with tools from other vendors.

The default value of the emptySoapAction argument is false. In this case, the value of the soapAction attribute is the concatenation of the targetNamespace and the operation name. This will also be the value of the SOAPAction header in the SOAP message.

Example

The following code samples illustrate how the value of the emptySoapAction argument can be used to control the value of the soapAction attribute in OracleAS Web Services.

Assume that you have the following TimeService Java interface that defines a getDateTime service.

public interface TimeService extends Remote {
    
    public String getDateTime(String name) throws RemoteException;
} 

This interface can be used as input to the WebServicesAssembler assemble command or Ant task without the emptySoapAction argument. Since the emptySoapAction argument will not be used in the command or task, it is assumed that its value is false by default. The resulting WSDL will have the soapAction value soapAction="http://timeService/getDateTime". This will also be the value of the SOAPAction header in the SOAP message.

Controlling the Value of soapAction on the .NET Platform

On the .NET platform, you can specify the RoutingStyle of the XML Web service as SoapAction. Then, depending on whether the Web service is document or RPC style, set the SoapAction by using the Action parameter of the SoapDocumentMethod or SoapRpcMethod attribute. By default, the value for the Action parameter is http://<web service namespace>/MethodName, where MethodName is the name of the XML Web service method.


Note:

Instead of defining the SoapAction parameter to dispatch SOAP messages, you can configure the .NET platform to use the RequestElement parameter to set the request element's name. To do this, set RoutingStyle=SoapServiceRoutingStyle.RequestElement and set [SOAPDocumentMethod(Action="")].

A more detailed discussion of this topic is beyond the scope of this manual. For more information on the RequestElement parameter, see your .NET platform documentation.


Example

The following code sample illustrates how you can use the RoutingStyle parameter to control the value of SoapAction for a .NET Web service.

In Example 1-6, the RoutingStyle of the XML Web service is set to SoapServiceRoutingStyle.SoapAction. The SoapDocumentMethod attribute identifies the service as being of document style, and the Action parameter identifies the URI of the Web services as myAddService and myMultiplyService.

Example 1-6 Setting the Routing Style of a Service on the .NET Platform

<%@ WebService Language="C#" Class="MathService" %>

using System;
using System.Web.Services;
using System.Web.Services.Protocols;

[SoapDocumentService(SoapBindingUse.Literal,
                 SoapParameterStyle.Wrapped,
                 RoutingStyle=SoapServiceRoutingStyle.SoapAction)]

public class MathService : WebService {
   [SoapDocumentMethod(Action="http://localhost/myAddService")]
   [WebMethod]
   public float Add(float a, float b)
   {
       return a + b;
   }

   [SoapDocumentMethod(Action="http://localhost/myMultiplyService")]
   [WebMethod]
   public float multiply(float a, float b)
   {
       return a * b;
   }
}

Null Values in SOAP Messages

Data type mismatch is by far the most common cause of interoperability failures. These failures usually appear when the server or the client tries to deserialize the SOAP message. This is shown in Figure 1-1 as Point 4b and Point 5.

Data type mismatch failure can occur when null values are sent across different platforms. If possible, you should avoid passing null values. If you must send null values from one Web service application to another, you should understand what the data types are mapped to on the other system and whether the data type can handle the null value correctly.

For example, the xsd:dateTime schema type is mapped to System.DateTime on the .NET platform. On the Java platform, it is mapped to java.util.Calendar or java.util.Date. If the Calendar or Date object is initialized with a null value in a Java program, then a null xsd:dateTime is sent in the SOAP message. If a Web service built on the .NET platform receives the SOAP message, then it will not be able to correctly deserialize the message, because the System.DateTime type is not nillable.

Example

The following code samples illustrate how passing a null value between the sending and receiving platform can result in an interoperability failure.

An XML element is a null element when its nil attribute is set to true. The WSDL must account for this by setting the nillable attribute of the corresponding element to true (the default value of nillable is false).

In the WSDL in Example 1-7, the source element has omitted the nillable attribute. Thus, by default, it has a nillable=false attribute.

Example 1-7 WSDL Fragment, Where the Source Element is Not Nillable

<s:element name="Src2html">
    <s:complexType>
    <s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="login" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="passe" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="lan" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="source" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>

Suppose the client application assigns a null value to the Java object representing the source element. Assuming that the Apache Axis platform generates the client proxy code from this WSDL, Example 1-8 illustrates the resulting request SOAP message on the wire. Note that the source element has the xsi:nil attribute set to true.

Example 1-8 Request Message, With xsi:nil Set to true

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
  <Src2html xmlns="http://www.dotnetisp.com/webservices/dotnetisp/src2html.asmx">
   <login>Gigi</login>
   <passe>oracle</passe>
   <lan>C#</lan>
   <source xsi:nil="true"/>
  </Src2html>
 </soapenv:Body>
</soapenv:Envelope>

Because the WSDL definition does not allow the source element to contain a nil value, the Web service built on the OracleAS Web Services platform will fail to deserialize the incoming SOAP message. Example 1-9 illustrates a sample SOAP fault response that OracleAS Web Services generates for the preceding request.

Example 1-9 Sample SOAP Fault Response from OracleAS Web Services

<env:Body>
<env:Fault>
    <faultcode>env:Client</faultcode>
    <faultstring>caught exception while handling request: unexpected null</faultstring></env:Fault>
</env:Body>
</env:Envelope>

On the other hand, if the same client application assigning a null source element is developed with OracleAS Web Services, it will omit the source element completely, because the schema defines it to be optional. Example 1-10 illustrates a request SOAP message on the wire sent by a client developed with OracleAS Web Services.

Example 1-10 Request Message, Omitting Optional Elements

<env:Envelope xmlns:env=http://schemas.xmlsoap.org/soap/envelope/ 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
    xmlns:ns0="http://www.dotnetisp.com/webservices/dotnetisp/src2html.asmx">
<env:Body>
<ns0:Src2html>
    <ns0:login>Gigi</login>
    <ns0:passe>oracle</passe>
    <ns0:lan>C#</lan>
</ns0:Src2html>
</env:Body>
</env:Envelope>

Because the request in Example 1-10 does not contain an invalid null element, the server returns a response without error. Example 1-11 illustrates a sample response to the request.

Example 1-11 Sample SOAP Message

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:ns0="http://www.dotnetisp.com/webservices/dotnetisp/src2html.asmx">
<env:Body>
<ns0:Src2htmlResponse/>
</env:Body>
</env:Envelope>

Unsigned Schema Numeric Types

Another type of deserialization failure that occurs at Point 4b or Point 5 in Figure 1-1 involves using unsigned schema types. On the .NET platform, unsigned types are directly mapped to unsigned native types, while on the Java platform, unsigned types are not defined. As a result, using unsigned schema types in your WSDL can cause unexpected interoperability failures.

If possible, avoid using unsigned numeric data types, such as unsignedShort, unsignedInt, double, or float in your client applications. If you do use these data types, you must check their range and precision limit on each system.

Example

The following code samples illustrate how using unsigned data types in a client application can cause unexpected interoperability failures.

The following C# Web method takes an unsigned input argument, ui, and returns the same value back to the caller.

[WebMethod]
Public uint getUint(uint ui) {
    Return ui
}

Example 1-12 illustrates the WSDL fragment containing the input and output parameters for the getUnit Web method. These parameters are directly mapped to the xsd:unsignedInt type.

Example 1-12 WSDL Fragment, with Mappings for Input and Output Parameters

...
<s:element name="getUint">
    <s:complexType>
<s:sequence>
         <s:element minOccurs="1" maxOccurs="1" name="ui" type="s:unsignedInt" /> 
       </s:sequence>
    </s:complexType>
 </s:element> <s:element name="getUintResponse">
    <s:complexType>
        <s:sequence>
         <s:element minOccurs="1" maxOccurs="1" name="getUintResult" type="s:unsignedInt" /> 
        </s:sequence>
    </s:complexType>
  </s:element>
...

Using the WebServicesAssembler tool, you can generate JAX-RPC-compliant client code that consumes the getUnit service. The generated client code maps the request input type to the Java native type long.

Now, assume that your Java client application, similar to the code fragment illustrated in Example 1-13, passes in a very large long value without knowing the type expected on the other end of the Web service.

Example 1-13 Client Application Fragment that Passes a Large long Value

...
stubs.Service1SoapClient myPort = new stubs.Service1SoapClient();
System.out.println("calling " + myPort.getEndpoint());
long l1 = 9223372036854775807L;
GetUint request = new GetUint(l1);
GetUintResponse response = myPort.getUint(request);
long l2 = response.getGetUintResult();
...

When the message is sent across the wire, the .NET platform will reject the value and return a SOAP fault similar to the one illustrated in Example 1-14.

Example 1-14 Sample SOAP Fault Sent by the .NET Platform

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  <soap:Body>
    <soap:Fault>
      <faultcode>soap:Client</faultcode>
      <faultstring>Server was unable to read request. --&gt; There is an error in XML document (2, 261). --&gt; Value was either too large or too small for a UInt32.</faultstring>
      <detail />
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

Loss of Precision

Loss of precision can occur at the point where messages are deserialized. This is depicted as Point 4b and Point 5 in Figure 1-1. Failures of this kind are not always obvious, because SOAP faults are not always thrown.

Loss of precision can occur when translating values of XML data types to different platforms. For example, the value of an XML dateTime simple type might be different on the Java and .NET platforms. This is because these platforms use different precisions when interpreting the value this XML type.

Example

The following code samples illustrate how passing the xsd:dateTime XML simple type between Java and .NET Web services can cause a loss of precision, which translates into a potential interoperability issue.

The following C# Web method returns a System MAX_VALUE of the DateTime data type.

[WebMethod]
Pubic DateTime getDateTime() {
    Return DateTime.MaxValue;
}

Example 1-15 illustrates a Java client code fragment that accesses the getDateTime .NET Web service.

Example 1-15 Java Code Fragment to Access a .NET Web Service

...
GetDateTime request = new GetDateTime();
GetDateTimeResponse response = myPort.getDateTime(request);
Calendar cal = response.getGetDateTimeResult();
...

Example 1-16 illustrates the SOAP response that the Java client receives on the wire. Note the values given for the date (highlighted in bold).

Example 1-16 SOAP Response Message from a .NET Web Service that Returns a Date

<?xml version="1.0" encoding="utf-8" ?> 
  <dateTime xmlns="http://tempuri.org/">9999-12-31T23:59:59.9999999-08:00</dateTime>

The Java client deserializes the response into the java.util.Calendar class. Example 1-17 illustrates the printout of the contents of the Calendar object. Notice that the dateTime value is slightly later than the value passed over the wire. This is because the two native dateTime types have different precisions. On the .NET platform, four digits are used for the year value and seven digits are used for the milliseconds. On the Java platform, five digits are used for the year value and three digits are for milliseconds. Moreover, the Java Web service maintains only three digits of milliseconds and rounds up the date. The new value, on the receiving side is January 1, 10000.

Example 1-17 Printout of a Java Calendar Object

[java] ERA: 1
[java] YEAR: 10000
[java] MONTH: 0
[java] WEEK_OF_YEAR: 1
[java] WEEK_OF_MONTH: 1
[java] DATE: 1
[java] DAY_OF_MONTH: 1
[java] DAY_OF_YEAR: 1
[java] DAY_OF_WEEK: 7
[java] DAY_OF_WEEK_IN_MONTH: 1
[java] AM_PM: 0
[java] HOUR: 0
[java] HOUR_OF_DAY: 0
[java] MINUTE: 0
[java] SECOND: 0
[java] MILLISECOND: 0
[java] ZONE_OFFSET: -8
[java] DST_OFFSET: 0

Tool Support for Interoperability

The previous sections suggest that there are distinct steps which you can follow to investigate Web services interoperability. These steps can be summarized as the Capture, Replay, Analyze process:

Oracle provides tools that can assist you in each step. Which tools you use will depend on the environment where you are developing the Web service endpoints and proxies. The following sections describe the tools which can assist you in each step.

Capturing the Web Service Contract

The Web service contract consists of the WSDL file, the SOAP message payload, and the HTTP headers.

To capture the WSDL and the XSD files, you can use the following tools:

  • Oracle JDeveloper wizards provide an option that will make a local copy of the WSDL file in your project. Figure 1-2 illustrates the JDeveloper Copy WSDL Into Project option.

  • The WebServicesAssembler tool provides a command, fetchWsdl, that will copy the base (or top-level) WSDL file and all of its imported and included WSDLs and schemas into a specified output directory. You can run this command on the command line or as an Ant task. See "fetchwsdl" in the Oracle Application Server Web Services Developer's Guide for more information on this command.

  • The generic Ant task get can be used to return a WSDL. If you use this Ant task, you must make a local copy of all the remote resources that have been referenced using wsdl:import or xsd:import.

Figure 1-2 Oracle JDeveloper Option to Make a Local WSDL Copy

Description of Figure 1-2 follows
Description of "Figure 1-2 Oracle JDeveloper Option to Make a Local WSDL Copy"

Capturing the SOAP Payload and HTTP Headers

To capture the SOAP payload and HTTP headers, you can use the following tools:

  • The HTTP Analyzer tool which is included with Oracle JDeveloper 10g offers a convenient way to capture the HTTP traffic between the service consumer and the service provider. This technique assumes that you can easily introduce an HTTP proxy between the two nodes. To change the behavior of the client, you must use the http.proxyHost and http.proxyPort system properties, while running the client.

  • If inserting an HTTP proxy is not practical, you can use an intermediary node, which will redirect the incoming traffic to the final destination. The WS-I monitor is an example of a tool that can do this. Unlike an HTTP proxy, using an intermediary node requires you to change the URL of the endpoint on the client side.

  • If you cannot change the client code or route the HTTP traffic through a proxy, set up an TCP sniffer. Ethereal is an example of a network protocol analyzer for Unix and Windows that can be used in this context.

Replaying the Message Payload

Once you have captured the payload, you must be able to either re-send the same payload, or to edit the payload and send it to see the effects of your changes.

  • JUnit can help you with the process of re-sending the same payload. You can take advantage of the test classes generated by the WebServicesAssembler genProxy command. You can also generate these test classes with Oracle JDeveloper 10g. Figure 1-3 illustrates the option to generate JUnit classes, as it appears in JDeveloper wizards.

  • The HTTP Analyzer tool, included with Oracle JDeveloper 10g, offers a convenient way to re-send either the same payload, or the edited payload. Figure 1-4 illustrates the Resend Request command in the HTTP Analyzer tool included with JDeveloper.

Figure 1-3 Oracle JDeveloper Option to Generate JUnit Classes

Description of Figure 1-3 follows
Description of "Figure 1-3 Oracle JDeveloper Option to Generate JUnit Classes"

Figure 1-4 HTTP Analyzer Tool's Resend Request Command, Included with JDeveloper

Description of Figure 1-4 follows
Description of "Figure 1-4 HTTP Analyzer Tool's Resend Request Command, Included with JDeveloper "

Analyzing the Interaction

Analyze the interaction between the service consumer and the provider. To help you analyze the interaction, you can use the following tools.

  • Oracle JDeveloper 10g HTTP Analyzer lets you use the WS-I Analyzer directly from the IDE. To use the Analyzer from the IDE, you must first download the Java version of the WS-I tools. The WS-I Analyzer generates the XML configuration files for you, and displays the progress as the reports are generated. Figure 1-5 illustrates the JDeveloper HTTP Analyzer with the focus on the integrated WS-I Analyzer command.

  • The WebServicesAssembler tool provides analyze command which performs a full scan of the WSDL and confirms whether the WSDL can be processed by this version of the WebServicesAssembler. The genProxy and genInterface commands perform the same task, but unlike these commands, analyze does not generate any code. See "analyze" in the Oracle Application Server Web Services Developer's Guide for more information about this command.

    The WSDL validation command is also integrated into the JDeveloper IDE. It is available from the Context menu, based on the type of resource selected. Figure 1-6 illustrates the JDeveloper command to compare files. In this case, the command compares two WSDL files.

Figure 1-5 Oracle JDeveloper with the Integrated WS-I Analyzer Command

Description of Figure 1-5 follows
Description of "Figure 1-5 Oracle JDeveloper with the Integrated WS-I Analyzer Command"

Figure 1-6 Oracle JDeveloper Compare Files Command

Description of Figure 1-6 follows
Description of "Figure 1-6 Oracle JDeveloper Compare Files Command"

Obtaining WS-I Tools

For more information on the tools mentioned in this section, see the following Web addresses.

Using WS-I Test Tools:

http://www.oracle.com/technology/products/jdev/howtos/10g/WS_WSI/WSI_HowTo.html

WS-I Basic Profile 1.0 Compliance Analyzer demo:

http://www.oracle.com/technology/products/jdev/viewlets/905p_j2ee_wsi/wsi_webservices_10g_viewlet_swf.html

Downloading the WS-I tool:

http://www.ws-i.org/deliverables/workinggroup.aspx?wg=testingtools

Limitations

See "Ensuring Interoperable Web Services".

Additional Information

For more information on: