The presentation-tier request handling mechanism must control and coordinate processing of each user across multiple requests. Such control mechanisms may be managed in either a centralized or decentralized manner.
The system requires a centralized access point for presentation-tier request handling to support the integration of system services, content retrieval, view management, and navigation. When the user accesses the view directly without going through a centralized mechanism, two problems may occur:
Additionally, distributed control is more difficult to maintain, since changes will often need to be made in numerous places.
Use a controller as the initial point of contact for handling a request. The controller manages the handling of the request, including invoking security services such as authentication and authorization, delegating business processing, managing the choice of an appropriate view, handling errors, and managing the selection of content creation strategies.
The controller provides a centralized entry point that controls and manages Web request handling. By centralizing decision points and controls, the controller also helps reduce the amount of Java code, called scriptlets, embedded in the JavaServer Pages (JSP) page.
Centralizing control in the controller and reducing business logic in the view promotes code reuse across requests. It is a preferable approach to the alternative-embedding code in multiple views-because that approach may lead to a more error-prone, reuse-by-copy- and-paste environment.
Typically, a controller coordinates with a dispatcher component. Dispatchers are responsible for view management and navigation. Thus, a dispatcher chooses the next view for the user and vectors control to the resource. Dispatchers may be encapsulated within the controller directly or can be extracted into a separate component.
While the Front Controller pattern suggests centralizing the handling of all requests, it does not limit the number of handlers in the system, as does a Singleton. An application may use multiple controllers in a system, each mapping to a set of distinct services.
Figure 7.7 represents the Front Controller class diagram pattern.
Participants and Responsibilities
Figure 7.8 shows the sequence diagram representing the Front Controller pattern. It depicts how the controller handles a request.
The controller is the initial contact point for handling all requests in the system. The controller may delegate to a helper to complete authentication and authorization of a user or to initiate contact retrieval.
A dispatcher is responsible for view management and navigation, managing the choice of the next view to present to the user, and providing the mechanism for vectoring control to this resource.
A dispatcher can be encapsulated within a controller or can be a separate component working in coordination. The dispatcher provides either a static dispatching to the view or a more sophisticated dynamic dispatching mechanism.
The dispatcher uses the RequestDispatcher object (supported in the servlet specification) and encapsulates some additional processing.
A helper is responsible for helping a view or controller complete its processing. Thus, helpers have numerous responsibilities, including gathering data required by the view and storing this intermediate model, in which case the helper is sometimes referred to as a value bean. Additionally, helpers may adapt this data model for use by the view. Helpers can service requests for data from the view by simply providing access to the raw data or by formatting the data as Web content.
A view may work with any number of helpers, which are typically implemented as JavaBeans components (JSP 1.0+) and custom tags (JSP 1.1+). Additionally, a helper may represent a Command object, a delegate (see "Business Delegate" on page 248), or an XSL Transformer, which is used in combination with a stylesheet to adapt and convert the model into the appropriate form.
A view represents and displays information to the client. The view retrieves information from a model. Helpers support views by encapsulating and adapting the underlying data model for use in the display.
There are several strategies for implementing a controller.
Servlet Front Strategy
This strategy suggests implementing the controller as a servlet. Though semantically equivalent, it is preferred to the JSP Front Strategy. The controller manages the aspects of request handling that are related to business processing and control flow. These responsibilities are related to, but logically independent of, display formatting, and are more appropriately encapsulated in a servlet rather than in a JSP page.
The Servlet Front Strategy does have some potential drawbacks. In particular, it does not leverage some of the JSP runtime environment utilities, such as automatic population of request parameters into helper properties. Fortunately, this drawback is minimal because it is relatively easy to create or obtain similar utilities for general use. There is also the possibility that the functionality of some of the JSP utilities may be included as standard servlet features in a future version of the servlet specification. Example 7.14 is an example of the Servlet Front Strategy.
Example 7.14 Servlet Front Strategy Sample Code
JSP Front Strategy
This strategy suggests implementing the controller as a JSP page. Though semantically equivalent, the Servlet Front Strategy is preferred to the JSP Front Strategy. Since the controller handles processing that is not specifically related to display formatting, it is a mismatch to implement this component as a JSP page.
Implementing the controller as a JSP page is clearly not preferred for another reason: It requires a software developer to work with a page of markup in order to modify request handling logic. Thus, a software developer will typically find the JSP Front Strategy more cumbersome when completing the cycle of coding, compilation, testing, and debugging. Example 7.15 is an example of the JSP Front Strategy.
Example 7.15 Front Strategy Sample Code
Command and Controller Strategy
Based on the Command pattern [GoF], the Command and Controller Strategy suggests providing a generic interface to the helper components to which the controller may delegate responsibility, minimizing the coupling among these components (see "View Helper" on page 33 for more information on helper components). Adding to or changing the work that needs to be completed by these helpers does not require any changes to the interface between the controller and the helpers, but rather to the type and/or content of the commands. This provides a flexible and easily extensible mechanism for developers to add request handling behaviors.
Finally, because the command processing is not coupled to the command invocation, the command processing mechanism may be reused with various types of clients, not just with Web browsers. This strategy also facilitates the creation of composite commands (see Composite pattern [GoF]). See Example 7.16 for sample code and Figure 7.9 for a sequence diagram.
Example 7.16 Command and Controller Strategy Sample Code
Physical Resource Mapping Strategy
All requests are made to specific physical resource names rather than logical names. An example is the following URL: http://some.server.com/resource1.jsp. In the case of a controller, an example URL might be http://some.server.com/ servlet/Controller. The Logical Resource Mapping Strategy is typically preferred over this strategy because it provides much greater flexibility. The Logical Resource Mapping Strategy lets you modify resource mappings in a declarative manner, via a configuration file. This is much more flexible than the Physical Resource Mapping Strategy, which requires that you make changes to each resource, as is necessary when implementing this strategy.
Logical Resource Mapping Strategy
Requests are made to logical resource names rather than to specific physical names. The physical resources to which these logical names refer may then be modified in a declarative manner.
For example, the URL http://some.server.com/process may be mapped as follows:
Multiplexed Resource Mapping Strategy
This is actually a substrategy of Logical Resource Naming Strategy. This strategy maps not just a single logical name, but an entire set of logical names, to a single physical resource. For example, a wildcard mapping might map all requests that end with .ctrl to a specific handler.
A request and mapping might look as shown in Table 7-1.
In fact, this is the strategy JSP page engines use in order to ensure that requests for JSP page resources (that is, resources whose names end in .jsp) are processed by a specific handler.
Additional information can also be added to a request, providing further details to leverage for this logical mapping. See Table 7-2.
A key benefit of using this strategy is that it provides great flexibility when designing your request handling components. When combined with other strategies, such as the Command and Controller Strategy, you can create a powerful request handling framework.
Consider a controller that handles all requests ending in .ctrl, as described above. Also, consider the left side of this dot-delimited resource name (profile in the above example) to be one part of the name of a use case. Now combine this name with the query parameter value (create in the above example). We are signaling our request handler that we want to process a use case called create profile. Our multiplexed resource mapping sends the request to our servletController, which is part of the mapping shown in Table 7-2 . Our controller creates the appropriate command object, as described in the Command and Controller Strategy. How does the controller know the command object to which it should delegate? Leveraging the additional information in the request URI, the controller delegates to the command object that handles profile creation. This might be a ProfileCommand object that services requests for Profile creation and modification, or it might be a more specific ProfileCreationCommand object.
Dispatcher in Controller Strategy
When the dispatcher functionality is minimal, it can be folded into the controller, as shown in Figure 7.10.
Base Front Strategy
Used in combination with the Servlet Front Strategy, this strategy suggests implementing a controller base class, whose implementation other controllers may extend. The base front may contain common and default implementations, while each subclass can override these implementations. The drawback of this strategy is the fact that any shared superclass, while promoting reuse and sharing, raises the issue of creating a fragile hierarchy, where changes necessary for one subclass affect all subclasses.
Filter Controller Strategy
Filters provide similar support for centralizing request processing control (see Intercepting Filter pattern). Thus, some aspects of a controller can reasonably be implemented as a filter. At the same time, filters primarily focus on request interception and decoration, not request processing and response generation. While there are overlapping responsibilities, such as managing logging or debugging, each component complements the other when used appropriately.