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

advertisement

Web Services Integration Patterns, Part 2

June 30, 2004

In the first installment of this article, I introduced some design patterns applied to the problem area of web services integration. This article presents more patterns:

  1. Configuration Driven Service
  2. Data Logger
  3. Flow Logger
  4. State Logger
  5. Input/Output Validator

Configuration Driven Service

Input to the service isn't hardcoded, but driven by external configuration data

Sometimes you can't hardcode the parameters used to call a service because they can quickly change based on business rules. The input could then be dynamically constructed, using a configuration table. These parameters could be stored in a database schema, an XML file, a properties file, or in other storage.

With the simple services you encounter in the tutorials, demos, or web services technologies documentation, the interface appears immediately clear, is usually made up of few methods, and embeds a fair simple logic. However, in the real world web services may be very complex.

For example, we had to integrate a service for customer registry census, which required many input parameters, as it needs all the personal information about the customer, like name and surname, addresses, social security number, and other data collected by the application. We also integrated external data banks, which provide financial information about the customers; again, we had to pass a few hundred parameters.

Consider, too, that most web services are stateless: if they relate to some specific data, each time they require even more parameters to identify the primary key of the data being processed.

In such cases we found it useful to externalize the name of the parameters to pass and the logic used to obtain the values of that parameters.

Take for example an e-commerce application that should store the information about the order; maybe the customer is new, so the user had to introduce some personal information. In the case that the store operation is done by a web service, the configuration for that service could be present in a database table like this:

SOAP parameter EL like expression
Name session.currentOrder.requestingCustomer.name
Surname session.currentOrder.requestingCustomer.surname
Street session.currentOrder.requestingCustomer.address.street
City session.currentOrder.requestingCustomer.address.city
Country session.currentOrder.requestingCustomer.address.country
ssn session.currentOrder.requestingCustomer.ssn

The first column is the name of the SOAP element (the Service Parameter); the second one contains an EL-like expression that navigates the domain tree until it finds the getter that returns the required value.

The service proxy relies then on the Configuration Manager to load this table and to evaluate each EL expression against the domain entities to obtain the actual values of such data.

The Dynamic Service Proxy represents the service, but its interface doesn't contain all the setters that would be required to replicate the service interface as in the Service Proxy pattern. Instead, the Dynamic Service Proxy has a generic interface. The Configuration Manager manages the configuration data, maybe delegating data access to a DAO. The Configuration stores all the information needed to perform the parameter-value mapping.

When the client requires a call() to the Dynamic Service Proxy, it calls the Service Manager, requesting the loading of the configuration for such service; this data, often cached in memory, is used by the Manager to create the parameter and values lists and passes them to the proxy.

Looking at the Dynamic Service Proxy, you don't see clearly the service interface, so it gives no immediate feedback of the business rules that drive that particular service. The client code is decoupled from the service proxy, allowing the two to evolve in an independent way.

Sample code

The CustomerStoreService is used to store the customer data in the Customer Management Software; it is a subclass of AbstractDynamicService, a common base class for dynamic services. The implementation of the call() method should invoke the Configuration Manager to load the configuration of the specific services; the Configuration Manager in turns obtains from the domain entities the data required by the configuration and passes it to the service, calling the generic setParameter() method:

public class CustomerStoreService extends AbstractDynamicService {
  
  public void call() {
    ConfigurationManager manager = 
      new ConfigurationManager( "CustomerStoreService" );
      
    //add parameters and values
    manager.prepare( this, session );
    
    //calls the channel
    super.call();
  }
}

public class ConfigurationManager {

  String serviceName;
  Map cache;
  
  public ConfigurationManager( String serviceName ) {
    this.serviceName = serviceName;
    
    initDAO();
  }
  
  public void prepare( DynamicService service, ApplicationSession session ) {
    //loads the service configuration
    ConfigurationData conf = loadConfiguration();
    
    //obtain the values of the parameters, based on data session
    Map values = loadValues( session );
    
    //values the service parameters
    prepareService( service, conf, values );
  }
  
  //load cache-enabled configuration data
  ConfigurationData loadConfiguration() {
    ...
  }
  

  //obtains data from the domain entities
  Map loadValues( ApplicationSession session ) {
    ...
  }
  
  //sets the parameter calling the setParameter() method on the service
  prepareService( DynamicService, ConfigurationData conf, Map values ) {
    ...
  }
}

Pages: 1, 2, 3, 4, 5

Next Pagearrow