J2EE Design Patterns

The term J2EE is tossed around a lot because it is a generic term that covers many areas of enterprise and distributed development. The J2EE modules and environment continue to grow as a rapid pace, and as many of you have come to learn, in recent years J2EE development has had its trials and tribulations.

For exactly this reason, it is important to take advantage of the most efficient and effective strategies for new development or the refactoring of existing projects. To keep up with the new developments, it is imperative that you aren't wasting time maintaining designs that have poor architecture or code that was poorly written.

This article covers how to use and identify design patterns, specifically for the presentation tier, in J2EE applications. The interest in design patterns has been around for a number of years in the software industry. However, interest among mainstream software developers is a fairly recent development -- and one that's long overdue, in my opinion. There are a number of reasons for this: it takes a highly experienced engineer to recognize a pattern; it requires collaboration; and it requires ongoing refinements. It also requires a sense of fluidity. Design patterns are not absolutes -- they are more expressions of proven solutions. It is up to you, the engineer or architect, to apply a pattern appropriately to your given scenario. This, of course, is easier said than done.

Patterns are not a magic pill. Just because a problem is observed and a pattern applied does not mean that you will have a perfect application -- or solution, for that matter. Patterns are a way of bringing clarity to a system architecture and they allow for the possibility of better systems being built. Building a system that meets the intended business requirements, performs well, is maintainable, and is delivered on time, is what keeps us engineers in business. Patterns have the distinct advantage of helping us do it all quicker.

So, What is a Design Pattern Anyway?

First of all, let's define what a design pattern is. There are a number of formal definitions, but I prefer a simple approach:
a design pattern is simply a description of a recurring solution to a problem, given a context.

Simple enough. The context is the environment, surroundings, situation, or interrelated conditions within which the problem exists. Design patterns have a number of advantages, among which are:

They capture engineering experience.

Once described, any level engineer can use the pattern.

They allow for reuse without having to reinvent the wheel on a project-by-project basis.

They allow for us, as engineers, to better define system structure.

They provide a design vocabulary.

They also provide reusable artifacts.

It is a rare instance (although not an impossible one), that a design pattern is used in an isolated fashion. Typically, patterns have relationships and work together to form a weave, in that a pattern can be composed of, or rely on, other patterns. That is why you will see that the more familiar you are with different patterns, the better equipped you are to determine their interactions. Patterns can also form frameworks that can then be used for implementations.

Enterprise systems are built crossing many tiers; this should not be news to anyone reading this article. This discussion is focused on the presentation tier, and primarily covers patterns that can be used with JSP and Servlet technology.

Show Me Your Pattern

There are a number of patterns that have been identified by the Sun Java Center for the presentation tier. These are certainly not the only patterns that can be applied, but they are a good starting point. The presentation patterns take into consideration the logic required to service clients that access the system. This includes client requests, single sign-on, session management, access to business services, as well as the creation, formatting, and delivery of responses to the client. These patterns include:

Intercepting Filter: facilitates preprocessing and post-processing of a request.

Front Controller: provides a centralized controller for managing the handling of requests.

View Helper: encapsulates logic that is not related to presentation formatting into Helper components.

Composite View: creates an aggregate View from atomic subcomponents.

Service To Worker: combines a Dispatcher component with the Front Controller and View Helper patterns.

Dispatch View: combines a Dispatcher component with the Front Controller and View Helper patterns, deferring many activities to View processing.

While the patterns listed above might not mean anything to you now, by the time you finish this article, you will understand how using patterns to describe solutions will give you a clear understanding of the problem being discussed, just by the use of the pattern name. Think of the time that will be saved in meetings by just saying, "I think the View Helper can be applied here," instead of droning on about a complete problem description that we've all faced many times.

Helpful Hints

A couple of words of advice if you are just starting on your pattern odyssey.

If you haven't boned up on UML yet, the time is now. UML is quite commonly used to describe patterns in pattern catalogs, including class diagrams, sequence or interaction diagrams, and stereotypes. I'm not going to go into UML in this article, but I highly recommend getting up to speed on it.

When using patterns, it is important to define a naming convention. It will be much easier to manage a project as it grows and identify exactly what role an object plays by using such naming conventions. For example, if you are using the View Helper or Composite View patterns, you might want to define the naming convention to be [action]Helper.java or [action].jsp, respectively; for instance, CreatePageHelper.java or CreatePage.jsp.

Make a list of requirement statements that you will be addressing and then try to identify relevant patterns (once you are familiar with them) that might be applicable. By doing this, you will be amazed at how quickly you will start to recognize appropriate solutions to problems. For example:

Requirement: I need one place of control for handling all requests.Possible pattern: Front Controller Intercepting Filter.

Requirement: I need a generic command interface for delegating processing from a controller to various helper components.Possible pattern: Front Controller.

And the Winner is…

In this section, we will briefly describe the presentation patterns mentioned so far. Most of these descriptions should invoke an "oh, yeah" response, as you identify situations you have faced during development. For a full pattern description, I highly recommend taking a look at Core J2EE Patterns (Alur, et al, Sun Microsystems Press, ISBN 0-13-064884-1) or "J2EE Blueprints."

Intercepting Filter

The Intercepting Filter intercepts incoming requests and outgoing responses, and applies a filter. Filters may be added and removed in a declarative manner, allowing them to be applied in a variety of combinations. After pre- or post-processing is finished, the final filter in the group passes control to the original target object, typically a Front Controller.

Front Controller

A Front Controller is a container that holds common processing logic that occurs within the presentation tier and that may otherwise be misplaced in a View. A controller handles requests and manages content retrieval, security, view management, navigation, and delegation to a Dispatcher component, which further dispatches to a View.

View Helper

View Helper encourages the separation of formatting-related code from other business logic. It suggests using Helper components to encapsulate logic relating to initiating content retrieval and validation, as well as adapting and formatting the model. The View component is then left to encapsulate the presentation formatting. Helper components typically delegate to Business Services (a business-tier pattern which we won't be discussing further).

Composite View

The Composite View composes a View from numerous pieces. Multiple smaller views, which could be either static or dynamic, are pieced together to create a single template.

Service to Worker and Dispatcher View

The Service to Worker and Dispatcher View patterns are a combination of other patterns. They share a common structure with common components, consisting of a controller working with a Dispatcher, Views, and Helpers, but the division of labor is different. The Dispatcher View defers content retrieval and error handling to the time of View processing. This pattern also suggests that the Dispatcher plays a more limited role in the View management, as the choice of the View is typically already included in the request.

You may already be using pattern-like strategies in your development process without even being aware of it. By identifying and becoming familiar with particular patterns, you will see that what might first appear as a problem that requires a roll-your-own solution might be better served by using a defined pattern. Let's explore a sample development scenario using the View Helper pattern and see how this might work.

Sample Scenario

Our scenario is a system that creates presentation content that requires processing of dynamic business data. This is a fairly common scenario to anyone doing J2EE development. The problem is that it is not uncommon for changes to occur in the presentation tier during the course of development. When business data logic and presentation-formatting logic are mingled together, the system becomes less flexible, harder to maintain, and provides a poor separation of tiers. Most of us -- even me -- are guilty at one point or another of coding Java into our JSPs. We want to avoid this situation.

Enter the View Helper pattern. The solution is to enforce this pattern so that the View contains formatting code, delegating its processing responsibilities to its helper classes. These classes might be implemented in a number of ways, including JavaBeans or custom tags. Helpers also store the View's intermediate data model and serve as business data adapters. It is important not to confuse a solution with its implementation strategy. For example, it's possible to implement this type of solution using a JSP View strategy, which uses a JSP as the View component. While this is a common strategy, it's also possible to take a Servlet View strategy, which uses a Servlet as a view instead. While we all know that a JSP actually becomes a Servlet, the strategy chosen becomes a matter of preference among the teams involved, as well as of the requirements of your project.

We have identified that we will use the View Helper pattern in our project. The class diagram for this pattern is shown in Figure 1.

Figure 1.

The class diagram tells us what components we will need to create in order to realize this pattern. Remember the naming conventions we spoke about earlier! (As a side note, if you are working with Rational Rose, there are a number of patterns included in v2002 that allow for the actual classes that need to be realized for a pattern to be generated for you. Depending on the pattern you select, the appropriate classes are created. It's quite convenient.) By using a sequence diagram that represents the View Helper pattern, we are quickly able to see the logic flow.

Figure 2.

The View represents and displays information to the client. Dynamic data is required, and the display is retrieved from a model. The helpers are used to support the View by encapsulating and adapting the model for displaying. A Helper is called a ValueBean if it is storing intermediate data from the model needed by the View. How the helper is implemented doesn't really matter; it could be a JavaBean or a custom tag, as we previously discussed. It could also be an XSL transformer, if XSL is being used for converting the model into the appropriate output for a specific client device. The Business Service is the service the client is trying to access -- the Business Service would typically branch off into another pattern specific to handling control and protection of the business service.

By using this pattern, we improve the tier partitioning and maintainability of our application by using helpers, as well as providing JavaBeans, custom tags, or XSL files that could very well be reused on other projects. The View Helper is also a good example of when a pattern is commonly used in conjunction with other patterns.

Take note: this is just the beginning. While this simple sequence diagram is a starting point, you will have to learn how to adapt your system modelling to your own development. Transforming patterns and strategies into an implementation is non-trivial. The more familiar you become with patterns, their strategies, and their implementation, the quicker you will be able to determine what you need for a specific project.

Summary

I hope this article has whet your appetite for using patterns in your development process. While this article only touched on presentation-tier patterns, there is a whole slew of patterns for the business and resource tiers that you should also become aware of (if you aren't already). By becoming familiar with patterns, as well as when and how to use them, you will ultimately become a better engineer. You will also find that your development process will improve, because you will more than likely be using tools that help create artifacts of your projects, including use-cases, sequence and class diagrams, and complete UML models of your systems.