DispatcherView Pattern
Context
System controls flow of execution and access to presentation processing, which is responsible for generating dynamic content.
Note
The Dispatcher View pattern, like the Service to Worker pattern, describes a common combination of other patterns from the catalog. Both of these macro patterns describe the combination of a controller and dispatcher with views and helpers. While describing this common structure, they emphasize related but different usage patterns.
Problem
The problem is a combination of the problems solved by the Front Controller and View Helper patterns in the presentation tier. There is no centralized component for managing access control, content retrieval or view management, and there is duplicate control code scattered throughout various views. Additionally, business logic and presentation formatting logic are intermingled within these views, making the system less flexible, less reusable, and generally less resilient to change.
Intermingling business logic with view processing also reduces modularity and provides a poor separation of roles among Web production and software development teams.
Forces
Solution
Combine a controller and dispatcher with views and helpers (see "Front Controller" on page 172 and "View Helper" on page 186) to handle client requests and prepare a dynamic presentation as the response. Controllers do not delegate content retrieval to helpers, because these activities are deferred to the time of view processing. A dispatcher is responsible for view management and navigation and can be encapsulated either within a controller, a view, or a separate component.
Dispatcher View describes the combination of the Front Controller and View Helper patterns with a dispatcher component. While this pattern and the Service to Worker pattern describe a similar structure, the two patterns suggest a different division of labor among the components. The controller and the dispatcher typically have limited responsibilities, as compared to the Service to Worker pattern, since the upfront processing and view management logic are basic. Furthermore, if centralized control of the underlying resources is considered unnecessary, then the controller is removed and the dispatcher may be moved into a view.
Since the Service to Worker and Dispatcher View patterns represent a common combination of other patterns from the catalog, each warrants its own name to promote efficient communication among developers. Unlike the Service to Worker pattern, the Dispatcher View pattern suggests deferring content retrieval to the time of view processing.
In the Dispatcher View pattern, the dispatcher typically plays a limited to moderate role in view management. In the Service to Worker pattern, the dispatcher typically plays a moderate to large role in view management.
A limited role for the dispatcher occurs when no outside resources are utilized in order to choose the view. The information encapsulated in the request is sufficient to determine the view to dispatch the request. For example:
http://some.server.com/servlet/Controller?next=login.jsp
The sole responsibility of the dispatcher component in this case is to dispatch to the view login.jsp.
An example of the dispatcher playing a moderate role is the case where the client submits a request directly to a controller with a query parameter that describes an action to be completed:
http://some.server.com/servlet/Controller?action=login
The responsibility of the dispatcher component here is to translate the logical name login into the resource name of an appropriate view, such as login.jsp, and dispatch to that view. To accomplish this translation, the dispatcher may access resources such as an XML configuration file that specifies the appropriate view to display.
On the other hand, in the Service to Worker pattern, the dispatcher might be more sophisticated. The dispatcher may invoke a business service to determine the appropriate view to display.
The shared structure of these two patterns, as mentioned above, consists of a controller working with a dispatcher, views, and helpers.
Structure
Figure 7.24 shows the class diagram that represents the Dispatcher View pattern.
Figure 7.24 Dispatcher View class diagram
Participants and Responsibilities
Figure 7.25 shows the Dispatcher View sequence pattern.
Figure 7.25 Dispatcher View sequence diagram
While the controller responsibilities are limited to system services, such as authentication and authorization, it is often still beneficial to centralize these aspects of the system. Notice also that, unlike in Service to Worker, the dispatcher does not make invocations on a business service in order to complete its view management processing.
The dispatcher functionality may be encapsulated in its own component. At the same time, when the responsibilities of the dispatcher are limited, as described by this pattern, the dispatcher functionality is often folded into another component, such as the controller or the view (see "Dispatcher in Controller Strategy" on page 183 and "Dispatcher in View Strategy" on page 32).
In fact, the dispatcher functionality may even be completed by the container, in the case where there is no extra application-level logic necessary. An example is a view called main.jsp that is given the alias name first. The container will process the following request, translate the alias name to the physical resource name, and dispatch directly to that resource:
http://some.server.com/first --> /mywebapp/main.jsp
In this case, we are left with the View Helper pattern, with the request being handled directly by the view. Since the view is the initial contact point for handling a request, custom tag helpers are typically used in these cases to perform business processing or to delegate this processing to other components. See the listing in Example 7.35 in the "Sample Code" section for an implementation sample.
Thus, the Dispatcher View pattern describes a continuum of related scenarios, moving from a scenario that is very structurally similar to Service to Worker to one that is similar to View Helper.
Controller
The controller is typically the initial contact point for handling a request. The controller manages authentication and authorization, and delegates to a dispatcher to do view management.
Dispatcher
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 (see "Front Controller" on page 172) or can be a separate component working in coordination. The dispatcher can provide static dispatching to the view or may provide a more sophisticated dynamic dispatching mechanism.
View
A view represents and displays information to the client. The information that is used in a display is retrieved from a model. Helpers support views by encapsulating and adapting a model for use in a display.
Helper
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 or a Delegate (see "Business Delegate" on page 248).
ValueBean
A value bean is another name for a helper that is responsible for holding intermediate model state for use by a view. A typical case, as shown in the sequence diagram in Figure 7.12, has the business service returning a value bean in response to a request. In this case, ValueBean fulfills the role of a Transfer Object (see "Transfer Object" on page 261).
BusinessService
The business service is a role that is fulfilled by the service the client is seeking to access. Typically, the business service is accessed via a business delegate. The business delegate's role is to provide control and protection for the business service (see "Business Delegate" on page 248).
Strategies
Servlet Front Strategy
See "Servlet Front Strategy" on page 175.
JavaServer Pages Pages Front Strategy
See "JavaServer Pages (JSP) Pages Front Strategy" on page 178.
JSP View Strategy
See "JSP View Strategy" on page 190.
Servlet View Strategy
See "Servlet View Strategy" on page 191.
JavaBean Helper Strategy
See "JavaBean Helper Strategy" on page 194.
Custom Tag Helper Strategy
See "Custom Tag Helper Strategy" on page 194.
Dispatcher in Controller Strategy
See "Dispatcher in Controller Strategy" on page 183.
As stated, the Service to Worker and Dispatcher View patterns suggest a continuum, where behavior is encapsulated closer to the front in Service to Worker or moved farther back in Dispatcher View.
Figure 7.26 shows the interactions for this strategy.
Figure 7.26 Dispatcher in
Controller Strategy
The controller does not create an explicit dispatcher object. Instead, the controller takes care of dispatching to the view. Alternatively, one could implement a dispatcher to which the controller can delegate the dispatching function.
Dispatcher in View Strategy
If the controller is removed due to its limited role, the dispatcher may be moved into a view. This design can be useful in cases where there is typically one view that maps to a specific request, but where a secondary view may be used on an infrequent basis. For example, based on some information in the request or results of some processing in a view, a custom tag helper in the view might vector control to a secondary view. A typical case is when a client request is submitted to a specific view, and will be serviced by that view in almost every case. Consider the case where the user has not been authenticated, but requests access to one of the few protected JSP pages on a site. Since the site has only a few protected pages, and limited dynamic content, authentication can be performed within those JSP pages, instead of using a site-wide centralized controller. Those pages that need authentication include a custom tag helper at the top of the page. This helper performs the authentication check and either displays the page for the user or forwards the user to an authentication page.
Figure 7.27 represents this scenario.
Figure 7.27 Dispatcher in
View Strategy
Transformer Helper Strategy
See "Transformer Helper Strategy" on page 200.
Consequences
Sample Code
The following sample code shows an implementation of the Dispatcher View pattern, using a controller servlet and a view with JavaBean and custom tag helpers. The implementation includes the Servlet Front Strategy, Dispatcher in Controller Strategy, JSP View Strategy, and custom tag and JavaBean helper strategies. A very basic composite view is used as well. A screen shot of the resulting display is shown in Figure 7.28.
Example 7.34 shows the controller servlet, which simply completes an authentication check and passes control to the appropriate view. Notice that the controller does not directly delegate to any helper components in order to make invocations to the business tier via a Delegate. These responsibilities are deferred to the view, which is called accountdetails.jsp and can be seen in Example 7.35. The sample code uses a LogManager to log messages. These messages are displayed at the bottom of the output page, for the purposes of this example, and can be seen in the screen shots in Figure 7.23 and Figure 7.28.
Example 7.34 Dispatcher View Controller Servlet
public class Controller extends HttpServlet {
/** Processes requests for both HTTP * <code>GET</code> and <code>POST</code> methods. * @param request servlet request * @param response servlet response */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { String nextview; try { LogManager.recordStrategy(request, "Dispatcher View", " Servlet Front Strategy; " + "JSP View Strategy; Custom tag helper Strategy"); LogManager.logMessage(request, getSignature(), "Process incoming request. ");
// Use a helper object to gather parameter // specific information. RequestHelper helper = new RequestHelper(request, response); LogManager.logMessage(request, getSignature(), " Authenticate user");
Authenticator auth = new BasicAuthenticator(); auth.authenticate(helper);
//This is an oversimplification for the sake of // simplicity. Typically, there will be a // mapping from logical name to resource name at // this point LogManager.logMessage(request, getSignature(), "Getting nextview"); nextview = request.getParameter("nextview");
LogManager.logMessage(request, getSignature(), "Dispatching to view: " + nextview); } catch (Exception e) { LogManager.logMessage( "Handle exception appropriately", e.getMessage() ); /** ApplicationResources provides a simple API * for retrieving constants and other * preconfigured values**/ nextview = ApplicationResources.getInstance(). getErrorPage(e); } dispatch(request, response, nextview); }
/** Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { processRequest(request, response); }
/** Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { processRequest(request, response); }
/** Returns a short description of the servlet. */ public String getServletInfo(){ return getSignature(); }
public void init(ServletConfig config) throws ServletException { super.init(config); }
public void destroy() { }
/** * dispatcher method */ protected void dispatch(HttpServletRequest request, HttpServletResponse response, String page) throws javax.servlet.ServletException, java.io.IOException { RequestDispatcher dispatcher = getServletContext(). getRequestDispatcher(page); dispatcher.forward(request, response); }
private String getSignature() { return "DispatcherView-Controller"; } } |
Notice that the view uses custom tag helpers to manage content retrieval, since this activity was not completed in the controller. When custom tags are used in this manner, they typically become thin facades for standalone components to which they delegate to complete this processing. This way, the general processing logic is loosely coupled to the tag implementation. If custom tags are not used with Dispatcher View, then too much scriptlet code typically ends up in the JSP page, a situation to be avoided.
Example 7.35 View - accountdetails.jsp
<%@ taglib uri="/web-INF/corepatternstaglibrary.tld" prefix="corepatterns" %>
<html> <head><title>AccountDetails</title></head> <body>
<corepatterns:AccountQuery queryParams="custid,acctkey" scope="request" />
<h2><center> Account Detail for <corepatterns:Account attribute="owner" /></h2> <br><br>
<tr> <td>Account Number :</td> <td><corepatterns:Account attribute="number" /></td> </tr>
<tr> <td>Account Type:</td> <td><corepatterns:Account attribute="type" /></td> </tr>
<tr> <td>Account Balance:</td> <td><corepatterns:Account attribute="balance" /></td> </tr>
<tr> <td>OverDraft Limit:</td> <td><corepatterns:Account attribute="overdraftLimit" /></td> </tr> <table border=3> </table> </corepatterns:AccountQuery>
<br> <br>
</center> <%@ include file="/jsp/trace.jsp" %> </body> </html> |
Figure 7.28 Dispatcher View sample screen shot
Related Patterns
Contact Us© 2001-2002 Sun Microsystems, Inc. All Rights Reserved.