A well-designed service will have multiple layers that perform specific functions. A layer is a package of software that has a well-defined interface contract and a few well-known dependencies with other layers. It is a self-contained package of software that can be independently developed, tested, and maintained. The context in which layers are used in a service is similar to the way the pipes and filters architectural pattern is implemented in UNIX. A filter takes input, processes the data, and outputs the data to another filter. These filters are chained to perform a function. Similarly, a well-designed service will be assembled from multiple layers into a working component.
A service consists of four layers: a proxy layer, a network adapter layer, a business logic/integration layer, and a data access layer. Logical layers are mapped onto physical tiers. The most likely scenario for the physical deployment of these logical layers is depicted in the following diagram:
The application and service proxy are deployed onto the client tier. The network adapter is on a separate tier and processes client requests. The business logic and data access layers are deployed into an EJB container together, as a stateless session bean. The resources are databases and systems that are their own tier.
Data, in the form of requests and responses, is transferred from layer to layer through the use of data transfer objects (DTO). DTOs are the only dependency that each layer has with other layers. Some DTOs are generic and use a hash table or reflection for storing and transferring data. Other services may use strongly typed value objects that have specific getters and setters for each attribute.
Software that needs access to the service, such as an application, uses a proxy to access the service. The proxy abstracts all of the details of looking up the service and invoking the remote method. The proxy provides a strongly typed interface for the service client. The client uses native method invocation. For instance, a bank account service proxy will have a method called debit account with a bank account number String and a BigDecimal amount argument. The proxy looks up the URL of the bank account service in a directory, translates the arguments into a SOAP XML message, and posts it to the service. All of the complexities of directory lookup — SOAP, XML, and URL Connections — are handled by the service proxy. The service developer will create proxies for any client that wishes to use the service. For instance, if a Java client, Visual Basic client, and a Perl script all need to access the service, the developer will provide a proxy for each client to make accessing the service as easy as possible.
The network adapter layer is responsible for translating the request format into a format that is understandable by the service logic. It is also responsible for providing access to the service from multiple protocols. For instance, a Java client may want to send Java Objects to the service via RMI. The RMI network adapter provides this function. At the same time, a Visual Basic client can send data to the service using SOAP and HTTP. The Web Services network adapter provides this function. The Web Services network adapter is a Java Servlet that accepts SOAP/XML as input over HTTP and calls the stateless session bean method. It gets the data from the stateless session bean and then sends it back to the client as SOAP/XML over the HTTP connection. The network adapter allows any client, no matter what format and protocol it understands, to use the service.
The business/integration logic layer is the location for the logic of the service. For example, a debit bank account method in the business logic layer will access the account database and the customer database through the data access layer to complete the function. Any data aggregation, calculations, or workflow that is related to the business function is located in the business logic layer. It is called the business logic/integration layer because sometimes the resource is the location for most of the business
logic. An account system may manage bank accounts and the transaction is simply passed on to that resource. In that scenario, it is more of an integration layer than a business logic layer.
The data access layer is responsible for accessing the resource. It encapsulates all of the technical details involved in accessing the resource. Whether the resource is a database, a flat-file, or a complete accounting system, the business logic sees these resources as a simple set of methods in a data access object. The business logic is not aware that the resource is accessed through JDBC, JMS, or file I/O. It only knows about the methods that are available to it from the data access layer.
The service uses entity beans to store shared state. If the service needs to have shared service state, it will use entity beans to provide this function. Shared state is also accessed through the data access layer as just another resource.
Many organizations use the J2EE platform to create services. A service in this environment has multiple layers, each of which handles a specific function. A service is usually created in the J2EE environment as a stateless session bean. A stateless session bean is an EJB component that does not maintain any conversational state with the client. It is a type-based component in which each method call is completely independent from other method calls.
To create a well-designed service, it is necessary to split the various functions of a service into separate layers. By doing this, it is easier to reuse layers in other services. A data access object that is created for one service may be easily reused by another service. The same goes for all layers of the service. Also by creating smaller, encapsulated packages of software, it is easier to test the individual parts of a service. Test harnesses may be created to exercise not only the service interfaces, but also the interfaces of each layer independently. This will result in an overall higher level of service reusability, testability, and maintainability.
|Data Transfer Objects||The Martin Fowler site|
|J2EE Patterns||Sun’s J2EE site|
About the Author
Michael Stevens is an independent consultant specializing in service-oriented architectures for the enterprise. He has over fourteen years of experience in information technology architecting and developing software systems, most recently focusing on J2EE solutions. He founded a software company that developed solutions for the mailing industry. He is a certified Java programmer, a member of the IEEE Computer Society, and of the ACM. He may be reached at firstname.lastname@example.org.