- Layering
- Layered Architecture
- Common Layering Schemes
- Layered Architecture Defined
- Other Considerations
- Summary and Preview
Layered Architecture Defined
The primary motivation for layering is to create and to preserve an enterprise-reusable domain model that spans application boundaries. Of course, this can be accomplished with three layers, but introducing two additional layers between the presentation and data source layers further decouples the domain from application presentation and data source requirements (Figure 3.5).
Figure 3.5 Five-Layer Architecture
Let's now take a closer look at the roles and responsibilities of the layers in this proposed five-layer architecture.
Presentation Layer
The presentation layer consists of objects defined to accept user input and to display application outputs. Presentation technologies that can be used with J2EE include
HTML/JSP, with servlets acting as Controllers, as we see in the next section
Applets, using Abstract Windowing Toolkit (AWT) or Swing
Applications, using AWT or Swing
We will focus on the first option, the most common for supporting thin clients and the one that uses the most J2EE technologies, but we will at times bring up issues related to the other two.
Controller/Mediator Layer
Whatever the presentation technology happens to be, requests for domain state and behavior are done through a Controller object defined for the particular presentation requirements. This Controller object implements the Mediator design pattern from [Gamma]. An important design requisite involves making sure that domain-specific logic is not defined in presentation object methods but rather is obtained from a Mediator-referenced domain object. Application navigation topology also is defined within this layer.
Servlets control a client request for dynamic HTML content. Servlets produce HTML by either delegating to a JSP page or simply putting raw HTML tags onto the available PrintWriter. The JSP approach naturally separates the servlet from HTML presentation logic, as JSPs are physical documents, independent of the servlet. However, for producing raw HTML tags, the developer might be tempted to accomplish this with a method defined in a servlet. A better design involves creating a separate HTML-generating class, effectively isolating this functionality (Figure 3.6).
Figure 3.6 A Servlet as a Controller
Servlets don't generate HTML but rather facilitate the production of dynamic HTML content by providing an entry point into a server-side JVM through a Web server. This entry point, known as a servlet, enables the developer to resolve session objects for individual users, access HTML form parameters, and respond with dynamically generated HTML. For a more detailed explanation of the Servlet API, refer to Chapter 4.
Application presentation objects interact with a domain model in generalized ways, regardless of the presentation technology. For instance, a GUI presents a list of choices, a collection of domain model objects; the same collection can be used to populate an HTML list. For that matter, the same collection could be used to provide a list of choices in a voice-response unit interface (Figure 3.7).
Figure 3.7 Mediators Used by Various Presentation Technologies
Mediators capture and decouple application-specific functionality from presentation technology by performing domain model requests for presentation or Controller objects that drive a specific application use case. Mediator classes are defined to satisfy a specific application user interface function or use case; therefore, they are less granular than controllers that usually exist at a component level. Mediators implement behavior that would usually end up in presentation classes as methods/scripts. Moreover, consistently applying mediator objects offers more than just loose coupling a domain model from presentation technologies. Mediators provide a convenient and consistent way to transfer application state between user interfaces, eliminating the typical highly parameterized approach. Additionally, transaction behavior finds an appropriate location in mediator objects, as constraints of navigation and units of work are tied to application-specific functionality.
Mediators also play a role supporting scalability using distributed object technologies, such as EJBs or CORBA. In the case of mediators in a GUI application, making the mediator a distributed object makes for a thin client, and Web-based applications using servlets can keep sessions lightweight by referencing distributed mediator proxies (Figure 3.8).
Figure 3.8 Distributed Mediator Topology
The key to mediators' presentation independence is the enforcement of strict layering, meaning that mediators should not contain any references to presentation objects. However, mediators are free to reference domain object public state and behavior. Care must also be taken not to define domain logic in mediators. This pitfall can be avoided by asking yourself, "Can I still perform or obtain the requested domain operation by using only existing domain objects?" If the answer is, "No, I need a mediator object," the mediator is implementing behavior that belongs in the domain.
Mediators implement the same design intent as controllers. But instead of loosely coupling presentation objects, such as GUI components, mediators help decouple and capture the application presentation requirements of a domain model.
Mediator objects are application specific and possess intimate knowledge of the domain they are mediating on behalf of. So, typically they define methods that quickly delegate requests through to the domain. A common mediator operation involves producing a vector of objects that will be displayed in a drop-down selection list. A developer implementing a JSP page to display this list does not have to write domain-specific code to obtain this list but instead can simply obtain it from a mediator instance. Likewise, a selection will be made from this list and ultimately will result in a "selected" domain instance that an operation will be performed against. Again, instead of defining this application-specific behavior in presentation-specific code, such as a JSP page, the behavior can be captured in methods defined in a mediator class.
It is also worth mentioning that the mediator design is not specific to an HTML/servlet-based application. Mediators are coupled to the domain in an application-specific fashion; however, they do not reference a specific application technology, making them reusable by various presentation technologies. It is realistic to think that a single mediator type can "mediate" for both servlet and GUI-based applications (Figure 3.9).
Figure 3.9 Mediator Servicing Various Presentation Types
In the context of servlet-based applications, mediators provide a convenient and consistent way to store user-specific application session objects. Several servlets are typically defined to support a single Web-based application function. Of course, the Servlet API provides a mechanism to associate domain object state with a user session; however, multiple domain objects could be involved in the function, and having to "get" and "put" multiple objects from the session requires extra bookkeeping. For a detailed discussion on how mediators can be used to help session management, see Chapter 8.
Domain Layer
The domain layer is possibly both the most difficult part of a layered system to understand and the most challenging to implement. To understand what a domain object is, we have to go back to the basic roots of object-oriented programming. When we learn Java programming or OO design, the first examples seen are usually in terms of concrete objects. This might be an example of a control system as in Booch, in which the objects modeled, such as temperature sensors and air conditioners, are physical, or through a simple game in which objects, such as playing cards, are modeled.
Unfortunately, when starting to look at their own day-to-day problems, many programmers instead see more abstract things, such as windows and database tables, not the nice concrete things seen in the books and tutorials. This is unfortunate, as modeling the aspects of a business in software can be one of the most powerful tools that a programmer can bring to bear on solving the most difficult problems in software development. Capturing business abstractions in objects can make a system much more powerful by making it more flexible and can also create a critical distinction between the parts of a system that represent the business problem being solvedits essenceand the "accidents" of implementation resulting from choices in technology that might be transitory.
Domain objects are usually implemented as standard Java classes, which may or may not implement or follow the JavaBeans specification. If domain objects are implemented as JavaBeans, later users of these classes will have more options of how they can be manipulated in visual programming tools, such as VisualAge for Java. Correspondingly, there will be extra features required by the JavaBean specification that must be implemented for these options to be available.
As we have already discussed, J2EE provides another option for implementing domain objects. A programmer can choose to implement domain objects as EJBs, which offers some benefits in distribution, transaction capabilities, and persistence. Even when EJBs are used, a mix of standard Java classes and EJBs can be used, as we will examine in greater detail in the chapters on EJB architecture (Chapters 13 and 22).
Data Mapping Layer
One consequence of building a domain layer as we have described is that if we take a more abstract view of a domain object, it should not be concerned with purely implementation-specific details. For instance, one of the most common questions in enterprise programming is how to extract data from or update data in a database. Rather than making this behavior part of the domain object, a second set of objects is required to perform this function. Separating the behavior out in this way has a number of benefits, including making it possible to change implementation details, such as database vendor or database schema, without changing the domain implementation.
A design like this requires a separate layer, often called a mapping, or persistence, layer, that can move data from domain objects to back-end data sources and vice versa. Several commercial products, such as the VisualAge Persistence Builder, JavaBlend, and TOPLink, can add this behavior. However, for a programmer using J2EE, this behavior will commonly be used through the APIs provided by the EJB container. The EJB container in WebSphere provides a simple and consistent interface for data persistence for entity EJBs. However, we may still need to implement some mapping functions even in designs using EJBs when we need to move data between JavaBeans and EJBs. We cover this topic in depth in a later chapter.
From an architecture design perspective, how mapping operations are engaged from a JavaBean domain should be vendor neutral. Domain models should be implemented as JavaBeans that inherit from a common base class. Methods defined in this class allow an extended class to consistently issue persistent operations for retrieving, saving, and deleting of objects from underlying, "mapped" data sources. A discussion of the Mapper design and implementation details that appear in this book's case study are discussed in Appendix A.
Data Source Access Layer
Relational databases, such as DB2, Oracle, and Informix, are arguably the most common way IT organizations store and query enterprise data. Recognizing this profound market share, Sun delivered the JDBC (Java Database Connectivity) API, which allows the production and execution of vendor-neutral SQL.[1] Developers can use standard ANSI SQL against any JDBC-compliant driver. The specific API and types of available JDBC drivers are beyond the scope of this discussion; refer to the JDBC specification, available on Sun's Java Web site, for more information.
How does this fit into the J2EE architecture? Data source access exists within the EJB portion of the architecture. EJB containers perform mapping and specific persistent operations on behalf of entity objects. Containers accomplish this by using data source access frameworks and such APIs as JDBC. Other objects like servlets and JavaBeans may also use JDBC directly to access enterprise data as well.