Skip to main content

Web services programming tips and tricks: Improve interoperability between J2EE technology and .NET, Part 3

Handling namespaces

Wangming Ye (yme@us.ibm.com), Software Engineer, IBM, Software Group
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 (later merged into IBM), and then as one of the main developers of the WebSphere Content Distribution Framework in the WebSphere Edge Server group. He currently provides technical enablement for WebSphere business partners in the WebSphere Competency Center in the IBM Business Partner Technical Enablement organization. You can reach Wangming at yme@us.ibm.com.

Summary:  Explore the source of the common interoperability challenges facing Web services integration across platforms. This third part in a series describes how the different naming conventions between J2EE technology and .NET can cause difficulty in Web services interoperability.

Date:  10 Feb 2005
Level:  Introductory
Activity:  2846 views

Introduction

Just as a Java package used for qualifying a Java class allows the Java class to reside under a distinct hierachical namespace and to avoid naming conflicts between classes, methods, and so on, an XML namespace serves the same purpose for Web services. It qualifies the name for an XML element or attribute and helps avoid naming conflicts. XML namespaces are based on the need that URLs should be universally unique. However, the way that URLs are interpreted and mapped in the native code differs between platforms. The differences are usually subtle, but if they are not bridged from the beginning, they can turn out to be very difficult to fix in the end.

I will discuss several interoperability issues in relation to namespaces in the following sections, including:

  • The use of relative URI references
  • The use of distinct and unique URIs sharing common domain names
  • The namespace issue in array types

Relative URI reference as a namespace declaration in WSDL

Relative URI references are not strictly banned in namespace declaration, but specifications offer no interpretation for them. This is usually not a problem if a WSDL file is generated from a J2EE Web service, because the target namespace is derived from the Java package names and the tool (for example, Java2WSDL) automatically qualifies them with the schemes. But in Microsoft .NET Web services implementations, if you allow the .NET framework to generate the WSDL file, the target namespace comes directly from what you have defined in the code. You might often see scenarios where the namespace attribute is assigned a relative URI. Listing 1 shows a .NET Web service coded in C# to retrieve a list of products from an inventory.


Listing 1. An inventory Web service with a relative namespace URI
  
[WebService(Namespace="services.inventory")]
  public class GetProductsService: WebService 
  {
	public struct Product {
		public string name;
		public int 	qty;
		public float price;
	}
	[WebMethod]
	[XmlInclude(typeof(Product))]
	public Product[] listProducts()
	{
		Product[] products = 
		getInventory();  // getInventory() is a private method 
to retrieve all products
		return products;
	}
   }


In Listing 1, the attribute Namespace="services.inventory" results in a targetNamespace="services.inventory" in the WSDL file. As a result, all of the locally-defined elements, types and attributes are scoped under a namespace with the relative URI services.inventory. The following shows the schema part of the WSDL document:


Listing 2. The generated WSDL file shows the relative URI reference as the targetNamespace

    xmlns:s0="services.inventory"
    <types>
        <s:schema elementFormDefault="qualified"
            targetNamespace="services.inventory" 
xmlns:s="http://www.w3.org/2001/XMLSchema">
            <s:complexType name="ArrayOfProduct">
                <s:sequence>
                    <s:element maxOccurs="unbounded" minOccurs="0"
                        name="Product" type="s0:Product"/>
                </s:sequence>
            </s:complexType>
            <s:complexType name="Product">
                <s:sequence>
                    <s:element maxOccurs="1" minOccurs="0" name="name" 
type="s:string"/>
                    <s:element maxOccurs="1" minOccurs="1" name="qty" 
type="s:int"/>
                    <s:element maxOccurs="1" minOccurs="1" name="price" 
type="s:float"/>
                </s:sequence>
            </s:complexType>
            <s:element name="ArrayOfProduct" nillable="true" 
type="s0:ArrayOfProduct"/>
        </s:schema>
    </types>


The elementFormDefault="qualified" attribute ensures that the targetNamespace qualifies all of the locally-declared elements, including the complex type Product. Suppose a second organization implements a similar Product type with the same relative namespace. Both schemas are imported into a WSDL document to form a common schema, as is often done using wsdl:import and xsd:import when integrating the Web service into a business process using the IBM® WebSphere® Studio Application Developer Integration Edition (Application Developer) BPEL designer in order to leverage the common complex types from different partner links.

In this scenario, it is highly likely that a naming conflict will occur if both imported schemas have the same target namespace. The tools used to build the integration on another platform must qualify the relative URI based on the base URI in the document tree according to RFC2396. However, in a WSDL document, the base URI is not well-defined; the interpretation of the default base URI hinges upon applications. The best practice is to always make the namespace unique by qualifying it with its own organization domain name.


Unique namespace URIs sharing common domain names

It has been said that namespace pollution is the worst pollution in software engineering. Each organization has a different naming convention, so tools used to generate Web services stub code on another platform might have different interpretations of the namespace declarations in WSDL. Web Services Interoperability Organization (WS-I) specifications have made significant progress in eliminating the ambiguity in namespace declarations and in moving toward a uniform interpretation of the namespace, but there are still some gaps.

Consider two hypothetical .NET Web services in a retail banking branch and an investment branch of a large bank. One creates checking accounts for customers and another creates investment accounts:


Listing 3. A retail AccountService in .NET


namespace Retail
{
  [WebService(Namespace="http://bigbank.com/retail")]
  public class AccountService: WebService 
  {
	public struct Customer {
		public string name;
		public string address;
	}
	[WebMethod]
	public bool createCheckingAccount(Customer customer)
	{
		return true;
	}
   }
}



Listing 4. A investment AccountService in .NET

namespace Investment
{
  [WebService(Namespace="http://bigbank.com/investment")]
  public class AccountService: WebService 
  {
	public struct Customer {
		public string name;
		public string address;
		public int collatoral_amt;
	}
	[WebMethod]
	public bool createInvestmentAccount(Customer customer)
	{
		return true;
	}
   }
}


The above two account services have the same domain, but different branches: http://bigbank.com/retail and http://bigbank.com/investment. Because of different requirements, the retail AccountService has a slightly different Customer complex type than the one in the investment AccountService. Both AccountService class files are named AccountService.asmx. This is fine and, in fact, quite intuitive in .NET, because both account services are qualified by different URLs that accurately reflect their domain name and branch names.

Now, if you are building a client project in Application Developer and trying to integrate the two Web services, the situation changes. In Java code, when creating a Web services client, the package name is based on the domain name of the namespace. Both http://bigbank.com/retail and http://bigbank.com/investment have the same domain name: http://bigbank.com. Therefore the generated complex data types and proxies for both Web services will have the same package name: com.bigbank. Because we named both .NET Web services as AccountService.asmx, and both have the same name for the two different Customer struct types, the result is clear: when Application Developer generates proxy files, the generated stub files for the AccountService client (AccountService.java, AccountServiceLocator.java, AccountServiceSoap.java, AccountServiceSoapProxy.java and AccountServiceSoapStub.java) will overwrite the files of the same name that were generated earlier. And there will be only one Customer complex type instead of two, depending on which was generated later.

This naming conflict is a result of different naming conventions in .NET and Java technology. As you see, a unique URL in the namespace declaration is still not safe from naming conflicts. The solution is to qualify each Web service with a unique domain name. The above two AccountService clients can use http://retail.bigbank.com and http://investment.bigbank.com/ as the namespace qualifier, respectively, to make the domain names unique.

If it is not practical to change the namespace declarations in the existing .NET Web services, the Web services client proxy generation wizard in Application Developer also provides an option to define custom mapping for namespace to package, as shown in Figure 1.


Figure 1. Define custom mapping for namespace to package in Application Developer


Namespaces and sharing XSD schemas

In both J2EE technology and .NET, it is quite common to share XSD schemas among multiple Web services. In fact, it is one of the best practices to share XML schemas for the sake of modular design and reusability. The XML tag: import and include, are used just for this purpose. For example, you can design a schema for a Product type for a merchandise warehouse, as shown in Listing 5:


Listing 5. A Product type
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace=
"http://catalog.warehouse.com" xmlns:Product="http://catalog.warehouse.com">
	<complexType name="Product">
		<sequence>
			<element name="_name" type="string"></element>
			<element name="_int" type="int"></element>
		</sequence>
	</complexType>
</schema>


The Product type is qualified under the namespace http://catalog.warehouse.com. It can be imported into the WSDLs for other Web services managing the inventory. Imagine that the order department has an Order Web service implemented in C#, as shown in Listing 6:


Listing 6. An order Service in .NET

	[WebService(Namespace="http://order.warehouse.com/service")]
	public class OrderProductService: System.Web.Services.WebService
	{
		[WebMethod]
		[XmlInclude(typeof(Product))]
		public string OrderProducts(Product[] products) 
		{
			int len = products.Length;
			//do the order
			return "Total number of orders processed: " + len;
		}
	}


The inventory department has an inventory Web service to restock products to its inventory; it must reuse the same Product type, as shown in Listing 7:


Listing 7. An inventory Service in .NET

	[WebService(Namespace="http://inventory.warehouse.com/service")]
	public class InventoryProductService: System.Web.Services.WebService
	{
		[WebMethod]
		[XmlInclude(typeof(Product))]
		public string RestockProducts(Product[] products) 
		{
			int len = products.Length;
			//add to the inventory
			return "Total number of products added: " + len;
		}
	}


Now that there are three namespaces: http://catalog.warehouse.com for the Product type, the http://order.warehouse.com/service for the Order Web service and the http://inventory.warehouse.com/service for the Inventory Web service. At first look, there doesn't seem to be any potential name conflicts. According to the previous two sections: The three namespace URIs are fully qualified; the domain name for each Web service is unique; even the Web services class names are different.

But still, the problem occurs. The problem occurs when arrays are passed, as in the two Web methods in Listing 6 and Listing 7.

If you build a J2EE project to integrate both the order service and the inventory service, and order a list of products or restock a list of products, only one Web service will be correctly executed; the other one will silently fail because of an empty array of products received, even though the J2EE client indeed sends both with a filled array of products. Why?

You have to investigate the SOAP traffic between the J2EE client and the .NET Web services to look for the answer.


Listing 8. The SOAP request for the .NET order service

<soapenv:Body>
     <OrderProduct xmlns="http://order.warehouse.com/service">
          <products>
                <Product>
                    <_name xmlns="http://catalog.warehouse.com">Computer</_name>
                    <_qty xmlns="http://catalog.warehouse.com">10</_qty>
                </Product>
                <Product>
                    <_name xmlns="http://catalog.warehouse.com">Monitor</_name>
                    <_qty xmlns="http://catalog.warehouse.com">20</_qty>
                </Product>
          </products>
     </OrderProduct>
</soapenv:Body>



Listing 9. The SOAP request for the .NET inventory service

<soapenv:Body>
     <RestockProduct xmlns="http://inventory.warehouse.com/service">
            <products>
                <Product xmlns="http://order.warehouse.com/service">
                    <_name xmlns="http://catalog.warehouse.com">Computer</_name>
                    <_qty xmlns="http://catalog.warehouse.com">10</_qty>
                </Product>
                <Product xmlns="http://order.warehouse.com/service">
                    <_name xmlns="http://catalog.warehouse.com">Monitor</_name>
                    <_qty xmlns="http://catalog.warehouse.com">20</_qty>
                </Product>
            </products>
     </RestockProduct>
</soapenv:Body>


Compare the XML representations of the orders array and the products array in Listing 8 and Listing 9. The array element in the request to the Inventory service is qualified by the namespace URI of the Order service -- http://order.warehouse.com/service -- so the Inventory Web service does not see any product being sent to it.

So, where is the root of the problem? The problem is in the .NET WSDLs and the helper classes that the Application Developer JAX-RPC tools generates. Listing 10 shows the WSDL for the order service in relation to the ArrayOfProduct[]:


Listing 10. Portion of the WSDL for the .NET Order service in relation to the ArrayOfProduct type

xmlns:s1="http://catalog.warehouse.com" 
xmlns:s="http://www.w3.org/2001/XMLSchema" 
xmlns:s0="http://order.warehouse.com/service"
targetNamespace="http://order.warehouse.com/service" 
.......
<types>
  <s:schema elementFormDefault="qualified" targetNamespace=
  "http://order.warehouse.com/service">
     <s:import namespace="http://catalog.warehouse.com" /> 
      .......
     <s:element name="Product" type="s1:Product" /> 
  </s:schema>
  <s:schema elementFormDefault="qualified" targetNamespace=
  "http://catalog.warehouse.com">
     <s:import namespace=
     "http://order.warehouse.com/service" /> 
       <s:complexType name="ArrayOfProduct">
         <s:sequence>
           <s:element minOccurs="0" maxOccurs="unbounded" ref="s0:Product" /> 
         </s:sequence>
       </s:complexType>


The schema ArrayOfProduct is under the targetNamespace http://catalog.warehouse.com, but its element references s0:Product, where s0 is http://order.warehouse.com/service.

Recall how the namespace URI is mapped to the Java package name when the JAX-RPC client stub classes are created; an ArrayOfProduct class is created under the package com.warehouse.catalog, and a helper class ArrayOfProduct_Helper binds its Product field to the namespace s0, which is http://order.warehouse.com/service (see Listing 11 in this sidefile).

This is not good news. Both of the clients for the Inventory and the Order Web services share the same ArrayOfProduct class under the package com.warehouse.catalog, but its class field binds to a particular Web service; in this case it is the Order service. That's precisely what you can see in the SOAP request message in Listing 7, and this is what is causing the problem.

In this scenario, there is no violation of specifications from either side. There are no ideal solutions. You must first identify the problem, and there are two things you can do to solve this namespace binding conflict:

  • When the first client proxy files are created, refactor the com.warehouse.catalog to another package name; when the second client proxy files are generated, both of them will have the correct namespace binding.
  • Use the same techique as shown in Figure 1 when generating the client proxy files; map the http://catalog.warehouse.com to a distinct namespace for each Web service.

It is a good practice to share XSD schemas, but Web service programmers must be aware of the potential namespace problems like this one and know how to fix it when it occurs.


Conclusion

This part of the series discussed some interoperability problems caused by XML namespace conflicts. Still, the namespace conflicts in the interacting Web services do not end here. There are many more scenarios, both subtle and rare, but it happens. Namespace conflicts are difficult to fix when hundreds of Web services are deployed in a large corporation environment. When writing Web services, the best practice is to anticipate and avoid the potential conflicts on a different platform. IBM WebSphere Studio Application Developer Integration Edition also provides a powerful refactoring tool. If naming conflicts indeed occur during the integration, the tool can help you to refactor.

This series of tips discusses a number of important issues that can challenge Web services interoperability across platforms and offers best practices, particularly in the use of XML Schema types, namespaces, and Web services interface bindings. With many years of joint efforts by WS-I members, Web services interoperability is achievable. As vendors' IDE tools mature, the integration will get even better. But it's not realistic to think that some day all of Web services will interact with just a few mouse clicks, even with the help of the most sophisticated and powerful IDE tools. After all, Web services are developed on heterogeneous platforms. Even if everyone is coding to the same WS-I specifications, there will be mismatches, misinterpretations, and different conventions. In the production field, there are many more interoperability issues that need to be considered by human engineers. Some of the important interoperability topics are:

  • Error handling: It is very important to anticipate different error conditions and types of faults that can occur and can be returned by the communicating parties, and to define those wsdl:faults as part of wsdl:operations in the WSDL.
  • Security interoperability: Web services calls need to be signed and encrypted (WS-Security). The capability to perform vendor-neutral and transport-independent security for Web services is the goal of WS-Security and is an important step in Web services integration in a production environment.

I will discuss those other interoperability topics in future tips.


Resources

About the author

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 (later merged into IBM), and then as one of the main developers of the WebSphere Content Distribution Framework in the WebSphere Edge Server group. He currently provides technical enablement for WebSphere business partners in the WebSphere Competency Center in the IBM Business Partner Technical Enablement organization. You can reach Wangming at yme@us.ibm.com.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services, Java technology, XML
ArticleID=40734
ArticleTitle=Web services programming tips and tricks: Improve interoperability between J2EE technology and .NET, Part 3
publish-date=02102005
author1-email=yme@us.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers