Item 22: Consider using Web Services for open integration

Item 22: Consider using Web Services for open integration

Enterprise systems tend to be heterogeneous in nature. They may not start that way, but in the fast-changing dynamic environment of the IT shop, much less the corporate world surrounding it, heterogeneity becomes an eventual reality. Even if your boss is completely sympathetic to the idea of remaining an all-Java environment, his or her boss may not be. Or the company you just acquired wasn't a Java shop, and now it's up to you to integrate the two. Or a new business partner is demanding access to a system you wrote, but the partner uses .NET. The fact is, it's the rare enterprise that is completely platform-aligned.

We can approach a foreign technology in three ways: portability, migration, and integration.

If the technology is portable, we can just take it as is and run it within our environment. In the J2EE case, that means the foreign technology has to be a J2EE-compliant component that can be dropped into our container and simply reused. While possible, such as situations where Python code can be run under the Jython Python-on-Java environment, it definitely doesn't cover the cases of .NET code.

Where we can't port the code, we might migrate it—that is, rewrite it completely in the technology of our current environment. While attractive in some ways, it's pretty impractical to expect business partners to be willing to rewrite their perfectly functioning .NET code in Java; in fact, they might in turn ask you to do the migrating instead of the other way around.

Which means we're left with integration: trying to make the two components work together, as is, with little to no modification in implementation. Hey, how hard can it be? After all, we've managed to get Windows systems to talk HTTP flawlessly to UNIX machines and vice versa for years now, right?

As it turns out, getting interoperability between any two platforms—Java, .NET, COM/DCOM, Perl, Python, Ruby, C/C++, whatever—isn't actually all that difficult. Numerous Java-to-.NET binary RPC interoperability toolkits are on the market. For example, Jython takes care of Java-Python, JRuby handles Java-Ruby, and several open-source toolkits offer Java-COM or Java-C++ integration fairly easily.

It's when we need to interoperate against them all that things get hairy.

To make interoperability across all of these platforms easier, we need a lingua franca, a common language that each one speaks in a (more or less) native way. Web Services step in here, using XML's and HTTP's ubiquity to address that need for a common format that each can understand, so that instead of having to worry about an exponential number of connectors to each platform, we worry about connecting to just one (XML/Web Services), and let each platform itself worry solely about getting data into XML and back out of it.

What's more, the Web Services community, led by standards organizations like the World Wide Web Consortium, OASIS, and the newly-formed WS-Interoperability group, are building a set of protocols and standards on top of XML to make building and consuming Web Services easier. On top of that, J2EE 1.4 has taken steps to make integration with Web Services easier for the Java developer, integrating JAX-RPC as part of EJB, for example, and incorporating the other JAX* specifications as part of the J2EE Collective. In short, from a distance it looks like your interoperability needs are already taken care of.

As with many efforts of this nature, however, things below the surface aren't quite as placid as they seem from up top. For starters, we have the basic problem of the object-hierarchical impedance mismatch between objects and XML Infoset representations, as described more fully in Item 43, that will make it awkward to transform objects into XML documents and back again. To complicate matters, J2EE 1.4 assumes that the Web Services endpoints exported from a J2EE container should be "rpc-encoded"-style services, whereas .NET, the major candidate for Web Service integration, assumes "doc-literal" style out of the box. While not an unassailable obstacle, it still requires more knowledge of the Web Services stack, most importantly WSDL, than most developers probably prefer.

The far greater danger, unfortunately, lies in the basic premise that all of the Web Service vendors are offering, that you can start with your platform-specific code, flip a magic switch, and suddenly have a Web Service all served up, ready to eat. Consider the following session bean interface:

public interface TellerBean extends EJBObject


  public void

    generateBouncedCheckMessages(Set checks, Account acct)

    throws RemoteException


Clearly, from the first parameter, the bean is expecting a collection that contains only unique items—if the same check somehow is inserted twice into the collection, it should generate an exception. Here's the problem: What exactly should the WSDL definition for this method be?

The second parameter we can handle pretty easily, since Account is (hopefully) just a simple wrapper around an account number, but Set creates some problems. .NET has no Set-equivalent type, and even if it does, remember that Set is just an interface whose implementation varies—it could be a java.util.TreeSet, it could be a HashSet, it could be your own custom Set implementation tuned in ways expressed only via behavior, not via interface. The code looking to generate a WSDL document will probably turn that Set parameter into a simple collection, thus losing an important implicit part of the API, that of uniqueness in the collection. .NET clients will have no chance to avoid accidentally passing the bean duplicates, and if the bean is written to assume that no duplicates are present, we could be in for a very long night of debugging.

For best interoperability, Web Services should be context-complete, data-driven communications endpoints (see Items 18 and 19, respectively), yet most EJB Session Bean interfaces aren't designed that way. Even worse, Java programmers looking to pass data in bulk (see Item 23) to a Session Façade [Alur/Crupi/Malks, 341] will chose either a Data Transfer Object [Fowler, 401] or a collection, like a Map or List. The Data Transfer Object will suffer from the limitations of object-hierarchical data mappings, and the Map or List will have no good equivalent in XML, much less the things contained in them.

In short, you can't afford to make platform-centric assumptions about your communications endpoints if you're planning to make your code available via a Web Services endpoint. Instead, you'll need to start from something platform-agnostic—usually XML Schema definitions for data types and WSDL documents for endpoint definitions, both of which should be written before the first line of Java code is generated—just as CORBA objects required you to design the IDL first, or as EJB requires the business/remote interfaces to be defined before the implementation can be written. It also means that once published, those interfaces can never change—even more than in the J2EE environment, Web Services are intended for public consumption, and you can't assume that if you change the URLs or the definitions of the message types expected at those URLs, that clients will be able to keep up with the change.

In many ways, Web Services are the pinnacle of middleware software. Remember, middleware is supposed to be the "glue" that binds systems that were designed independently of one another, and that fits the definition of Web Services. All of the specifications emerging for higher-order Web Service protocols are middleware-focused: WS-ReliableMessaging, WS-Transaction, WS-Security, and WS-Addressing reflect functionality provided by most middleware toolkits over the last twenty years. We're just adding angle brackets (< and >) around them.

Like most other things in the enterprise, Web Services offer some powerful capabilities, in this case the ability to interoperate with foreign platforms, but you don't get those benefits for free. If you're thinking about using Web Services, make sure they're worth the work—they were designed and intended for open interoperability, that is, interoperability against any number of platforms simultaneously. If you're not looking to provide interoperability against any and all platforms, it may turn out to be easier to choose something that's targeted to your specific platform.

     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows