You are designing an enterprise application that consumes a service provided by another application. The service defines a contract that all service consumers must conform to in order to access the service. The contract defines such things as the technology, communications protocols, and message definitions needed to communicate with the service. To communicate with the service, your application needs to fulfill its responsibilities as detailed in the contract.
How do you decouple the details of fulfilling the contract responsibilities defined by the service from the rest of your application?
When designing an application that consumes services provided by other applications, you must address the following forces:
Implementing the consumer’s contract responsibilities requires you to implement security and communication mechanisms such as authentication, marshaling, encryption, and message routing. These mechanisms often change at a different rate and for different reasons than the application’s business logic.
The contract may specify data formats that are different from your application’s internal representation. If so, the data must be translated. Sometimes this translation is a simple as renaming a field or converting a data type, but other times this conversion involves complex structural and semantic transformations. For example, most services expose coarse-grained type-based interfaces to optimize their use in distributed environments. Therefore, when an operation is invoked on a service from an object-oriented application, information from several of your applications’ fine-grained objects will often need to be aggregated and transformed into the format specified by the contract. Likewise, the response from the operation will usually need to be broken apart and mapped back to fine-grained objects.
Your organization may not control the contract specified by the service. If the contract changes, you will want to minimize the impact on the application code.
The communications channel that provides connectivity between your application and the services typically exposes a generic, low-level application programming interface (API) to the application. This API may include generic functions such as SendData. In most situations, you want your application to deal with a more semantically rich interface, through methods such as ValidateCreditCard or GetCustomerAddress.
Some contracts may specify asynchronous messaging; that is, they may not return a result immediately. Instead, the service consumer must be prepared to receive a separate result message from the service. The event-driven programming needed to handle such incoming messages from a service can complicate an application significantly.
Encapsulate the code that implements the consumer portion of the contract into its own Service Gateway component. Service gateways play a similar role when accessing services as data access components do for access to the application’s database. They act as proxies to other services, encapsulating the details of connecting to the source and performing any necessary translation.
Service Gateway is a specific type of Martin Fowler’s Gateway pattern [Fowler03] that is adapted for use in service-oriented architectures, and as such, its major concern is encapsulating a consuming application’s access to external systems. Service Gateway often interacts with Remote Facade [Fowler03] instead of interacting with an external system directly. Remote Facade encapsulates complex functionality in provider applications and exposes that functionality as a single simple interface to consumer applications. Service Interface is a specific type of Remote Facade adapted for use in service-oriented architectures. In service-oriented architectures, it is common for a consuming application’s service gateway to collaborate with a service interface exposed by a provider application. The following fiqure illustrates this relationship.
Figure 6.7: Service Gateway consuming the service of a service interface
The Service Gateway component encapsulates the low-level details of communicating with a service. Such details include but are not limited to:
Communications channel. Service Gateway encapsulates all the low-level network communications functionality needed to communicate with the service. For example, Service Gateway hides all the details of using SOAP over HTTP for communicating with a Web service.
Data formats. Service Gateway maps between the internal organization of information in your application and the format mandated by the service’s communication contract. For example, your application may be composed of a collaborating set of fine-grained objects; however a Web service it consumes may require an XML document as input and provide an XML document as a result. The gateway is responsible for translating between the fine-grained object interfaces and XML documents.
Service discovery. For simple to moderately complex scenarios, Service Gateway should encapsulate the process of finding the proper service. This may involve looking up the network address of the service in a configuration file or using a service repository such as UDDI. For complex scenarios, such as those that require dynamic determination of the proper service to call based on changing data, the service discovery functionality may be encapsulated in its own Service Gateway component.
Process adapter. Service Gateway should adapt the application’s business process to work with the service. For example, a single call to the service gateway may result in multiple invocations to one or more service operations. Therefore, the interface that the service gateway presents to the application should be in terms of the application’s processes, rather than in terms of communication and security protocols..
Asynchronous vs. synchronous calling semantics. Service Gateway adapts the consuming application’s calling semantics (asynchronous or synchronous) to the calling semantics specified by the contract. For instance, a consuming application’s design may not support the asynchronous calling semantics specified in the contract. The consuming application’s service gateway would then be required to convert the application’s synchronous calls to the asynchronous protocol specified in the contract.
You do not have to implement Service Gateway as a single object. In fact, it may be advantageous to separate some of the functions into separate objects. For example, using separate objects may make it easier to use code generation to create some portions of the gateway. The code that implements the mapping data between the internal application format and the format expected by the service is an ideal candidate for this mapping, provided that the service provider publishes metadata describing the required data format (for example, in the form of WSDL or an XML schema). This metadata can be used to generate a strongly typed class that encapsulates this mapping.
See Implementing Service Gateway in .NET.
Service Gateway can significantly improve the testability of the system. A service gateway encapsulates all the details of accessing the service into a single component and hides the component behind an interface that has no direct dependencies on the underlying communications channel. This allows you to replace the gateway with a Service Stub [Fowler03] during testing. This stub does not access the external system at all, but returns results that simulate the external system directly to the application logic. Service Stub can also be used to simulate error conditions, such as the external service being unavailable.
Using a Service Gateway component to isolate the application from the details of communicating with the service provides the following benefits and liabilities:
Decoupling the service access logic from the rest of the application makes it easy to change the service the application accesses. For example, you may want to switch to a new version of the same service, or you may want to use a service with better service-level guarantees from another vendor. Switching to another service is much easier if you can automatically generate the code that does the data mapping.
Service Gateway hides the complexities of accessing a service from the application. This improves reuse of both the application components and the service access components. The application has no direct reference to the service, so it is independent of any implementation details and the location of the service. Encapsulating the service access logic in a separate layer also improves the reuse of the access logic because it can now be used across multiple service calls as long as the same transport and authentication mechanism is used.
Service Gateway provides an ideal location for providing common features such as asynchronous invocation, caching, and error handling.
Service Gateway adds an additional level of complexity that may be unnecessary for simple solutions. In particular, the effort and infrastructure needed to support the automatic generation of mapping components may not be needed if your organization will only be accessing a few relatively static services.
A particular service gateway is responsible for interacting with a single service. Coordination among multiple services must he handled by an additional component such as the business process component specified in Three-Layered Services Application.
The service gateway is often contained within a single application. Therefore, code duplication can result: if multiple applications access the same service, both applications may duplicate the gateway functionality. Developing a reusable service gateway component is one alternative. Another solution is to extract the common functionality into its own service that is deployed locally within your organization. Some of distributed computing solutions discussed in the previous chapter, such as Remote Facade, can also be useful in this situation.
For more information, see the following related patterns:
Three-Layered Services Application. The Service Gateway component specified in Three-Layered Services Application is an implementation of the Service Gateway pattern.
Service Interface. Service Interface plays a role in provider applications that is similar to the role Service Gateway plays in consumer applications.
Mapper [Fowler03]. Mapper provides translation between two or more fixed interfaces without either object being aware of the other. Service gateways may incorporate Mapper to translate between application and service data formats.
Remote Facade [Fowler03]. Service Interface is a specific type of Remote Facade adapted for use in service-oriented architectures. A remote facade is similar to a remote proxy but sometimes uses encapsulation to make the remote interface more coarse-grained.
Gateway [Fowler03]. Gateway is an object that encapsulates access to an external system or resource. Service Gateway is a specific instance of Gateway.
Assembler: Similar to Mapper, this pattern assembles an object from many objects. Communication between two interfaces in a mapper is bidirectional, whereas it tends to be unidirectional in assemblers.
[Fowler03] Fowler, Martin. Patterns of Enterprise Application Architecture. Addison-Wesley, 2003.
[Schmidt00] Schmidt, Douglas, Pattern-Oriented Software Architecture Vol.2, Wiley & Sons, 2000.