ServiceToWorker Pattern

Context

The 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.

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

  • Authentication and authorization checks are completed per request.
  • Scriptlet code within views should be minimized.
  • Business logic should be encapsulated in components other than the view.
  • Control flow is relatively complex and based on values from dynamic content.
  • View management logic is relatively sophisticated, with multiple views potentially mapping to the same request.

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 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 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 Service to Worker and Dispatcher View consists of a controller working with a dispatcher, views, and helpers.

Structure

The class diagram in Figure 7.20 represents the Service to Worker pattern.


Figure 7.20 Service to Worker class diagram

Participants and Responsibilities

Figure 7.21 shows the sequence diagram that represents the Service to Worker pattern.


Figure 7.21 Service to Worker sequence diagram

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.

Controller

The 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.

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 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.

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 (JSP 1.0+) components 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 the "Business Delegate" on page 248).

Strategies

Servlet Front Strategy

See "Servlet Front Strategy" on page 175.

JavaServer Pages Front Strategy

See "JSP 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 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.


Figure 7.22 Folding the dispatcher into the controller

Transformer Helper Strategy

See "Transformer Helper Strategy" on page 200.

Consequences

  • Centralizes Control and Improves Modularity and Reuse
    This pattern suggests providing a central place to handle system services and business logic across multiple requests. The controller manages business logic processing and request handling. Keep in mind, though, that as control centralizes, it is possible to introduce a single point of failure.

The pattern also promotes cleaner application partitioning and encourages reuse. Common code is moved into a controller and reused per request and moved into helper components, to which controllers and views delegate. The improved modularity and reuse means less duplication, which typically means a more bug-free environment.

  • Improves Application Partitioning
    Using helpers results in a cleaner separation of the view from the business processing in an application. Helpers, in the form of JavaBeans (JSP 1.0+) and Custom tags (JSP 1.1+), provide a place for business logic to be factored out of the JSP page. If the business logic is left in a JSP page, large projects result in cumbersome and unwieldy scriptlet code.
  • Improves Role Separation
    Separating the formatting logic from the application business logic also reduces dependencies on the same resources among individuals fulfilling different roles. Without this separation, for example, a software developer would own code that is embedded within HTML markup, while a Web production team member would need to modify page layout and design components that are intermingled with business logic. Because neither individual fulfilling these roles is familiar with the implementation specifics of the other individual's work, it raises the likelihood of modifications accidentally introducing bugs into the system.

Sample Code

The 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";

  }

}



 


Example 7.30 Command Interface

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;

}


Example 7.31 ViewAccountDetailsCommand

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;

  }

}



 


Example 7.32 AccountingAdapter

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 accountdetails.jsp, the JSP page to which the request is dispatched. The Transfer Object is imported via the standard <jsp:useBean> tag and its properties accessed with the standard <jsp:getProperty> tag. Also, the view uses a very simple composite strategy, doing a translation-time inclusion of the trace.jsp subview, which is responsible for displaying log information on the display solely for example purposes.

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>



 



Figure 7.23 Service to Worker sample screen shot

Related Patterns

  • Front Controller and View Helper
    The Service to Worker pattern is the result of combining the View Helper pattern with a dispatcher, in coordination with the Front Controller pattern.
  • Dispatcher View
    The Dispatcher View pattern is another name for the combination of the Front Controller pattern with a dispatcher, and the View Helper pattern. The Service to Worker and the Dispatcher View patterns are identical with respect to the components involved, but differ in the division of labor among those components. The Dispatcher View pattern suggests deferring content retrieval to the time of view processing. Also, the dispatcher plays a more limited role in view management, as the choice of view is typically already included in the request.

 

Contact Us© 2001-2002 Sun Microsystems, Inc. All Rights Reserved.