© | |
|
|
Service to WorkerContextThe system controls flow of execution and access to business data, from which it creates presentation content. Note The Service to Worker pattern, like the Dispatcher View 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. ProblemThe 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
SolutionCombine 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 delegate content retrieval to helpers, which manage the population of the intermediate model for the view. A dispatcher is responsible for view management and navigation and can be encapsulated either within a controller or a separate component. Service to Worker describes the combination of the Front Controller and View Helper patterns with a dispatcher component. While this pattern and the Dispatcher View pattern describe a similar structure, the two patterns suggest a different division of labor among the components. In Service to Worker, the controller and the dispatcher have more responsibilities. 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 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 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 Service to Worker and Dispatcher View consists of a controller working with a dispatcher, views, and helpers. StructureThe class diagram in Figure 7.20 represents the Service to Worker pattern.
Participants and ResponsibilitiesFigure 7.21 shows the sequence diagram that represents the Service to Worker pattern.
As stated, Service to Worker and Dispatcher View represent a similar structure. The main difference is that Service to Worker describes architectures with more behavior "up front" in the controller and dispatcher, while Dispatcher View describes architectures with more behavior moved back to the time of view processing. Thus, the two patterns suggest a continuum, where behavior is either encapsulated closer to the front or moved farther back in the process flow. ControllerThe controller is typically the initial contact point for handling a request. It works with a dispatcher to complete view management and navigation. The controller manages authentication, authorization, content retrieval, validation, and other aspects of request handling. It delegates to helpers to complete portions of this work. DispatcherA 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 it can be a separate component working in coordination with the controller. The dispatcher can provide static dispatching to the view or it may provide a more sophisticated dynamic dispatching mechanism. The dispatcher uses the RequestDispatcher object (supported in the servlet specification), but it also typically encapsulates some additional processing. The more responsibilities that this component encapsulates, the more it fits into the Service to Worker pattern. Conversely, when the dispatcher plays a more limited role, it fits more closely into the Dispatcher View pattern. ViewA 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. HelperA 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 (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). ValueBeanA 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). BusinessServiceThe 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 the "Business Delegate" on page 248). StrategiesServlet Front StrategySee "Servlet Front Strategy" on page 175. JSP Front StrategySee "JSP Front Strategy" on page 178. JSP View StrategySee "JSP View Strategy" on page 190. Servlet View StrategySee "Servlet View Strategy" on page 191. JavaBean Helper StrategySee "JavaBean Helper Strategy" on page 194. Custom Tag Helper StrategySee "Custom Tag Helper Strategy" on page 194. Dispatcher in Controller StrategySee "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 or moved farther back in the process flow. Figure 7.22 describes a scenario in which the controller is heavily loaded with upfront work, but the dispatcher functionality is minimal.
Transformer Helper StrategySee "Transformer Helper Strategy" on page 200. Consequences
Sample CodeThe following sample code shows an implementation of the Service to Worker pattern, using a controller servlet, a command helper, a dispatcher component, and a view. The implementation includes the Servlet Front Strategy, Command and Controller Strategy, JSP View Strategy, and JavaBean Helper Strategy. A very basic composite view is used as well. A screen shot of the resulting display is shown in Figure 7.23. Example 7.29 shows the controller servlet, which delegates to a Command object (Command and Controller Strategy) to complete the control processing. The Command object is retrieved via a factory invocation, which returns the generic Command type, an interface shown in Example 7.30. The sample code uses a LogManager to log messages. The screen shots in Figure 7.23 and Figure 7.28 show these messages displayed at the bottom of the page, for the purposes of this example. Example 7.29 Controller Servlet with Command and Controller Strategy 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 next; try { // Log pattern info LogManager.recordStrategy(request, "Service To Worker", " ServletFront Strategy;" + " JSPView Strategy; JavaBean 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(), "Getting command object helper"); // Get command object helper Command command = helper.getCommand(); // delegate processing to the command object, // passing request and response objects along next = command.execute(helper); /** If the above command returns a value, we * will dispatch from the controller. In this * example, though, the command will use a * separate dispatcher component to choose a * view and dispatch to that view. The command * object delegates to this dispatcher * component in its execute method, above, and * control should not return to this point **/ } catch (Exception e) { LogManager.logMessage( "EmployeeController(CommandStrategy)", e.getMessage() ); /** ApplicationResources provides a simple API * for retrieving constants and other * preconfigured values**/ next = ApplicationResources.getInstance(). getErrorPage(e); } dispatch(request, response, next); } /** 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(); } /** 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); } public void init(ServletConfig config) throws ServletException { super.init(config); } public void destroy() { } private String getSignature() { return "ServiceToWorker-Controller"; } } public interface Command { public String execute(RequestHelper helper) throws javax.servlet.ServletException, java.io.IOException; } Each Command Object helper implements this generic interface, which is an example of the GoF Command pattern. The Command object is an instance of the ViewAccountDetails class, which is shown in Example 7.31. The command instance delegates to an AccountingAdapter to make an invocation to the business tier via business delegate. The adapter class is shown in Example 7.32. It uses a separate dispatcher component to determine the next view to which control should be dispatched and to actually dispatch to this view. Example 7.30 Command Interface public interface Command { public String execute(RequestHelper helper) throws javax.servlet.ServletException, java.io.IOException; } public class ViewAccountDetailsCommand implements Command { public ViewAccountDetailsCommand() { } // view account details operation public String execute(RequestHelper helper) throws javax.servlet.ServletException, java.io.IOException { /** This will tell the user that a system error * has occured and will typically not be seen. It * should be stored in a resource file **/ String systemerror = "/jspdefaultprocessingerror.jsp"; LogManager.logMessage(helper.getRequest(), "ViewAccountDetailsCommand", "Get Account Details from an adapter object"); /** Use an adapter to retrieve data from business * service, and store it in a request attribute. * Note: Object creation could be avoided via * factory, but for example purposes object * instantiation is shown **/ AccountingAdapter adapter = new AccountingAdapter(); adapter.setAccountInfo(helper); LogManager.logMessage(helper.getRequest(), "ViewAccountDetailsCommand", "processing complete"); /** Note: Object creation could be avoided via * factory, but for example purposes object * instantiation is shown**/ Dispatcher dispatcher = new Dispatcher(); dispatcher.dispatch(helper); /** This return string will not be sent in a * normal execution of this scenario, because * control is forwarded to another resource * before reaching this point. Some commands do * return a String, though, so the return value * is included for correctness. **/ return systemerror; } } public class AccountingAdapter { public void setAccountInfo( RequestHelper requestHelper) { LogManager.logMessage( requestHelper.getRequest(), "Retrieving data from business tier"); // retrieve data from business tier via // delegate. Omit try/catch block for brevity. AccountDelegate delegate = new AccountDelegate(); AccountTO account = delegate.getAccount( requestHelper.getCustomerId(), requestHelper.getAccountKey()); LogManager.logMessage( requestHelper.getRequest(), "Store account Transfer Object in request attribute"); // transport data using request object requestHelper.getRequest().setAttribute( "account", account); } } The invocation on the business service via the delegate yields an Account
Transfer Object, which the adapter stores in a request attribute for use
by the view. Example 7.33 shows Example 7.33 View - accountdetails.jsp <html> <head><title>AccountDetails</title></head> <body> <jsp:useBean id="account" scope="request" class="corepatterns.util.AccountTO" /> <h2><center> Account Detail for <jsp:getProperty name="account" property="owner" /> </h2> <br><br> <table border=3> <tr> <td> Account Number : </td> <td> <jsp:getProperty name "account" property="number" /> </td> </tr> <tr> <td> Account Type: </td> <td> <jsp:getProperty name="account" property="type" /> </td> </tr> <tr> <td> Account Balance: </td> <td> <jsp:getProperty name="account" property="balance" /> </td> </tr> <tr> <td> OverDraft Limit: </td> <td> <jsp:getProperty name="account" property="overdraftLimit" /> </td> </tr> </table> <br> <br> </center> <%@ include file="/jsp/trace.jsp" %> </body> </html> Related Patterns
|
|||||||||||||||||||||||
© 2001, Core J2EE Patterns, All Rights Reserved. |