XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

Web Services Integration Patterns, Part 1

June 16, 2004

A few months ago I was working on a Java application for the banking industry. There were a bunch of hosted services that we had to integrate in our software. We had to use web services, since the SOAP protocol was the bank's standard way to access legacy data, throughout CICS transactions.

The bank's middleware department, in fact, has a cluster of WebSphere application servers running the integration layer which allows the applications to communicate with the mainframe using SOAP. This layer is a home-grown integration software using a variety of proprietary protocols to exchange data with COBOL transactions; the raw data is then converted to SOAP messages. This common) approach allows the applications to deal with CICS transactions as if they were web services.

On our side some work was already done: the first services were in place and working. But the first developers didn't bother with the clarity or the extensibility of the host integration layer. So we started reworking the code, creating a little integration framework and, not suprisingly, we started using Design Patterns.

The interesting thing was that I started thinking that some solutions could be considered to be "Domain Patterns", a specialized form of the original Gang of Four (and other) patterns, placed into the context of web services and integration. In this and in my next article you'll find a catalog of such patterns, plus some others that seem to be common sense and which I found useful organizing in a pattern template. These ideas came from our own case study; perhaps they will be useful in your work.

Here is a quick list of what follows in this first installment:

  1. Service Proxy
  2. Proxy with Channel
  3. Service Coordinator
  4. Service Simulator

The second installment will cover five more patterns.

The implementation of those patterns in our software allowed us to gain some advantages: first, we had a common language to describe the components of the systems and the interactions; second, our integration layer had a more polished aspect, that is, it was more readable. Third, following these structures we were able to reuse common base classes and build a simple framework.

Service Proxy

Each service is represented by a Service Proxy

When you need to integrate an external service, you can link directly to the service in your client code, using some specific API. For example, to create a Java client for a SOAP web service you can use the JAXM (Java API for XML Processing) APIs:


public float getRate( String currency1, String currency2 ) {
 MessageFactory mf = MessageFactory.newInstance();
 SOAPMessage msg = mf.createMessage();
 SOAPPart sp = msg.getSOAPPart();
 SOAPEnvelope env = sp.getEnvelope();
 SOAPHeader hdr = env.getHeader();
 SOAPBody bdy = env.getBody();

 String xsi = "http://www.w3.org/2001/XMLSchema-instance";
 env.addNamespaceDeclaration("xsi", xsi); 
 env.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
 env.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");

javax.xml.soap.Name xsiTypeString = env.createName("type", "xsi", xsi);

 SOAPBodyElement gltp = bdy.addBodyElement(
  env.createName("getRate","ns1", "urn:xmethods-CurrencyExchange")
 );

 SOAPElement e1 = gltp.addChildElement(
  env.createName("country1")
 ).addTextNode( country1 );
 e1.addAttribute( xsiTypeString, "xsd:string" );
...
more JAXM code
...
 return rate;
}

This approach has some problems. First, you're creating a hard coupling between your program and the service. Second, it becames more difficult to reuse the same service in other parts of the application: in such case you have to reimplement this specific call. Sure, you can reuse the code at the method level, but it is still awkward.

Using a service proxy instead, you can decouple the service from the main program, and you're able to leverage this extra layer to clear the interface and to implement some useful features, such as logging and coordination.

The proxy implements an interface that separates in three steps the operation required for performing the call:

  1. parameter passing
  2. web service calling
  3. reading the results

The first step is implemented by a series of setXXX() methods, one for each parameter involved in the call. The Service Proxy contains a setter for each parameter requested by the service.

Then the service is called by the call() method. After the method returns, the client code can get the returned data calling the getter methods getXXX():

We chose to organize the parameters and return values as properties of the service object rather than parameters, and we return values of a single method because we encountered several complex services, with many parameters (around 300) and equally numbered return values.

You typically use the Service Proxy when you start realizing that your integration code is getting bigger and bigger, multiplicating boilerplate code and replicating calls to the same service in different program locations. As a result, the code is more organized, as you have one service for one class. You decouple the techical layer and API used to access the service from the client code thus reducing the cost of a possibile API changeover.

Also, the Service Proxy

  • can be grouped using packages, obtaining a hiearchy of services used by the application;
  • could subclass from an abstract class that could provide some additional services and boilerplate code;
  • could be coordinated by a third class organizing your services in an operation flow.

The Service Proxy class represents your single service, so you can use it in a UML diagram to show relationships, collaborations and more. It should not, however, become a kind of orchestraction, i.e. calling multiple services. This functionality is covered by the Service Coordinator pattern which builds on the Service Proxy pattern.

Sample code

The figure shown below illustrates a Service Proxy that represent the Currency Exchange Service:

The two parameters, country1 and country2, are implemented by the setCountry1() and setCountry2() methods:


Service service = new ExchangeService();
service.setCountry1( currency1 );
service.setCountry2( currency2 );

After setting the parameters, the client should call the service and read the response:


service.call();
System.out.println( service.getRate() );

Derived from

[gof] Proxy

Proxy with Channel

Each service decouples communication using a channel object

As an evolution of the Service Proxy pattern, it is possibile to decouple the protocol layer from the service aspect. This allows you to change the physical protocol used; for example, replacing SOAP with JMS or vice versa. Decoupling makes the single service and channel class simpler.

When you start implementing your own integration framework using Service Proxy classes, you'll end up with a common abstract class that hosts the boilerplate code used to costruct and decode the SOAP messages. This way, you keep the single Service Proxy classes simpler, but you hardcode in the class hierarchy the wire protocol you're using. Even using JAX-RPC technology you're tying your code to SOAP. It is, despite the API designer's intentions, the only protocol implemented. Even if future implementations will provide different protocols, JAX-RPC architecture requires that you have to regenerate the stub and skeletons for each protocol used.

Decoupling the service from the Channel means that you separate the service-specific computations (data formatting, mathematical operations, descriptions/codes lookup) from the wire protocol used.

This could be useful if the service you're calling will change the protocol, maybe passing from SOAP 1.1 to 1.2 or XML-RPC or REST. Having a Channel object that encapsulates the wire protocol makes the change more easy.

This approach comes at a cost. If your framework or application is lightweight and calls few services, and those services aren't expected to change in the short term, maybe the Proxy with Channel is overkill for you.

Pages: 1, 2

Next Pagearrow