2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

Shale Application Controller

Introduction

Much has been made of the fact that JavaServer Faces promotes a page oriented architecture for applications, typically associating a request scoped "backing bean" with each page to contain event handlers and/or submitted values. Indeed, Shale itself offers extended support for this paradigm by virtue of its View Controller feature. This is in contrast to the action oriented architecture typically found in web application frameworks like Struts 1.x.

A second aspect of action oriented frameworks, however, is also useful. They typically implement an application level controller (in the sense of the Model/View/Controller design pattern) through which all HTTP requests to the application are funneled. Various frameworks offer mechanisms to customize the lifecycle processing that is performed, for example:

  • In Struts 1.1-1.2, you subclass RequestProcessor and override the processXxx() series of methods that perform the actual processing of the request.
  • In Struts 1.3, you customize the Commons Chain command pipeline that implements the standard request processing lifecycle.
  • In JavaServer Faces, you can insert PhaseListener instances that receive control before or after the standard phases of the request processing lifecycle, which can exert control over what happens next.
Shale, being based upon JavaServer Faces, supports the standard PhaseListener approach to customizing the request processing lifecycle. However, it also supports Application Controller functionality that can customize processing before or after the standard JavaServer Faces lifecycle, as described below.

Services Provided

The Application Controller feature of Shale provides application wide services as described below:

(A) Standard Per-Request Processing

As described in Configuring Your Application For Shale, you are requested to configure a Servlet Filter (org.apache.shale.application.faces.ShaleApplicationFilter) and map it to process incoming URLs (typically using the URL pattern /* to process all requests to this application). This filter receives control both before and after the standard JavaServer Faces request processing lifecycle (which is implemented as a servlet).

ShaleApplicationFilter imposes a standard request processing lifecycle using Commons Chain technology, which provides both preprocessing and postprocessing hooks where the application developer can plug in additional behavior at these two points in time. The following processing is performed for each request:

  • Construct an instance of ShaleWebContext (which implements the Commons Chain Context interface) to represent the current request. This instance will be passed in to any Commons Chain commands involved in processing the current request.
  • Store the ShaleWebContext instance as a request scope attribute under the key identified by manifest constant ShaleApplicationFilter.CONTEXT_ATTR so that it is available to later processing stages.
  • Check for a Commons Chain Command instance named preprocess in the shale catalog. If such a command (or chain) exists:
    • Execute the command or chain, rethrowing any exception that might occur.
    • If the executed command or chain returned true (indicating that processing for the entire request should be considered complete), remove the request scope attribute that was added and earlier, and exit.
  • Call doFilter() on the FilterChain argument passed in, which will ultimately trigger the standard JavaServer Faces processing when the incoming URL is mapped to FacesServlet.
  • Check for a Commons Chain Command instance named postprocess in the shale catalog. If such a command (or chain) exists, execute it.
  • Clean up the request scope attribute stored earlier.

(B) Preprocess and Postprocess Basic Implementations

In addition to the standard request processing lifecycle described in the previous section, Shale offers an abstract base class org.apache.shale.application.AbstractReqExpFilter suitable for developing preprocess commands that perform request filtering based on matching incoming request values to regular expressions. See the Javadocs for this class for more information.

Three concrete implementations based on this abstract base class are also provided:

  • ContextRelativePathFilter - Filters requests by matching the context relative portion of the path (i.e. starting with the slash after the context path itself) against one or more regular expressions.
  • RemoteAddrFilter - Filters requests by matching the IP address of the remote client against one or more regular expressions.
  • RemoteHostFilter - Filters requests by matching the hostname of the remote client against one or more regular expressions.

Using Application Controller

The Use Cases example application incorporates the ContextRelativePathFilter described above, using it to disallow direct access to JSP pages by URLs manually typed in to the browser. This is accomplished by the following configuration stored in the WEB-INF/chain-config.xml resource:
  <catalogs>

    <catalog name="shale">

      ...

      <command className="org.apache.shale.application.ContextRelativePathFilter"
       includes="\S*\.xml,\S*\.faces,\S*\.html,\S*\.gif,\S*\.jpg,index\.jsp"
       excludes="\S*\.jsp,\S*\.jspf"/>

      ...

    </catalog>

  </catalogs>

The ContextRelativePathFilter instance is configured to pass through context relative paths that match one of the regular expressions in the includes attribute, while disallowing access for context relative paths that match one of the regular expressions in the excludes list. With these settings, direct access to any URL ending in .jsp or .jspf (other than to a resource named index.jsp) will be prevented.