Chrysalis Architecture

The document describes the architecture and design philosophy behind the Chrysalis Web Framework.

Motivating Design Patterns

Chrysalis is based on one simple idea: that servlet invocations resemble Remote Procedures Calls (RPC). Form values can be considered parameters of a procedure call with the servlet as the procedure being invoked.

Servlet Invoked with the parameters id, name and stock

The above operation could be mapped to a method like the following:

void saveItem(long id, String name, int stock) ...

Once we perform this mapping successfully, we can follow the standard object-oriented pattern of putting related methods into a single class, with instance variables for the data values manipulated by those methods. This makes the servlet controllers less like RPC and more like Distributed Objects.

public class CatalogController extends Controller {
  private Item currentItem;

  void saveItem(long id, String name, int stock) ...

  void removeItem(long id) ...

  // Other methods ...
}

Chrysalis combines this idea with the Model-View-Controller (MVC) pattern used by many web frameworks:

  • The Model: Components that store business data. In Chrysalis, these are JavaBeans. The Model should not know anything about the web environment.
  • The View: Components that display information to the user. In Chrysalis, these are JSP pages and custom tags. The JSP display information from the JavaBeans.
  • The Controller: Components that react to user input. In a sense, controllers mediate between the model and the view, because they take data entered by the user in the view and insert those values into the model. In Chrysalis these controllers are called "controllers" (subclasses of the Controller class).

Chrysalis also uses the Front Controller pattern to limit entry points into the system.

Basic Architecture

The following diagram illustrates the basic Chrysalis architecture.

All invocations go through one of two Front Controllers:

  • CommandFilter: For command invocations (URLs ending with *.cmd).
  • ViewFilter: For view invocations (*.jsp and URLs ending with *.view).

The CommandFilter invokes the appropriate controller method of a controller class. The ViewFilter displays a JSP. Both controllers and JSP invoke JavaBeans to manipulate application data.

Command Invocations

The flow for command invocations is as follows:

  1. The browser invokes the command with its URL: Cart.placeOrder.cmd .
  2. The command extension (*.cmd) is mapped to the CommandFilter.
  3. The command filter invokes the ControllerMapper.
  4. The ControllerMapper parses the URL to determine the correct controller and controller method.
  5. The ControllerMapper retrieves the controller from the servlet session. If no controller exists, a new one is created.
  6. The ControllerMapper invokes the correct controller method, converting request parameters to method parameters.

View Invocations

The flow for command invocations is as follows:

  1. The browser invokes the view with its URL: showOrder.jsp .
  2. The invocation passes through the ViewFilter to initialize the Chrysalis environment.
  3. The servlet engine executes the appropriate JSP.
  4. The JSP may use a tag to load object data from controllers: <jutil:use var=" order " controller=" Cart " /> .
  5. This tag retrieves the controller from the session and invokes the appropriate initializer method to load object data.
  6. The object data is stored in the JSP pageContext, so its information can be displayed in the page.

If the page has a template, things are a bit more complicated:

  1. The ViewFilter first calls the template page.
  2. The template page uses the <ji18n:includeBody /> tag to invoke the original target JSP.
  3. The message tags in the template use the same configuration data as the target page, allowing template contents like page title to be customized for a particular page through the page configuration.
  4. The target JSP is invoked, and its output is inserted (included) into the template page.

Application Flow

Chrysalis uses two kinds of links between commands:

  • Command Invocations (*.cmd): Invokes the appropriate controller method.
  • View Invocations (*.jsp/*.view): Display the appropriate page.

Unlike many frameworks, object data is not pre-loaded and forwarded to the JSP. The JSP can invoke controllers directly to load data (via the <jutil:use> tag). This means that it is possible to link directly to a view page and test them as self-contained components.

Links between components should be as follows:

  • JSP to JSP : Simple hyperlinks to the next view component.
  • JSP to Controller : Command invocations in hyperlinks or form actions.
  • Controller to JSP : Redirection to the appropriate view after the command invocation is complete.
  • Controller to Controller: Direct Java invocation using the Controller.getController() method (possible, but not recommended).

The flow diagram of the sample application illustrates these principles.

Note: Since the template.jsp is embedded in every page, its links are available globally.

Servlet 2.2 Filter Support

The key components in Chrysalis are javax.servlet.Filter classes. For backwards compatibility with the Servlet 2.2 standard, Chrysalis has a Filter Micro-Container to add partial filter support to older web containers. The implementation classes for the Filter Micro-Container are in the org.chwf.servlet.filter package.

The heart of the Filter Micro-Container is the FilterServlet, which invokes filters based on the configuration information in the /WEB-INF/filter.xml file. The FilterServlet must be assigned the full set of URL patterns handled by all of its filters; individual filters may be assigned more specific filter patterns.

The Filter Micro-Container is independent of much of the rest of the Chrysalis framework, and can be used as a generic mechanism for adding filter support to older web applications.

Resource Mapper

The filter specifications state that when the end of a filter chain is reached, the original target resource should be invoked. The component that fulfills this function in the Filter Micro-Container is the ResourceMapper class. When the filter chain is finished, the ResourceMapper invokes the target resource using the RequestDispatcher.include() method.

Unfortunately, the ResourceMapper (and filters) cannot directly filter the target resource on Servlet 2.2 containers. Suppose, for example, a filter was mapped to the URL pattern "*.jsp". This means that the FilterServlet must also be mapped to the URL pattern "*.jsp". When the ResourceMapper tries to invoke the JSP page, the servlet engine will invoke the FilterServlet instead, which will re-start the filter chain and trapped the system in an endless loop.

To circumvent this problem, the ResourceMapper matches "mapped" extensions to "resource" extensions. The mapped extension acts as an alias for the file extension of the actual resource. For example, the ".view" extension is mapped to the ".jsp" extension in the standard Chrysalis configuration. To invoke the filters in front of a JSP, the browser's URL must replace ".jsp" with the ".view" extension. The ResourceMapper converts ".view" back to ".jsp" before invoking the resource.

This means that on older web containers, Chrysalis view URLs must use a different extension (.view) from the file extension (.jsp). This is annoying, but this is the best that can be done on older web containers without rebuilding the entire servlet engine from scratch.

Also note that the same issue prevents the FilterServlet from being mapped to the "/*" pattern; the FilterServlet cannot filter everything, because it becomes impossible for the ResourceMapper to invoke the target resources.

The exact resource mappings can be controlled in the /WEB-INF/filter.xml configuration file.

<web-app>
  
  <!-- Other configuration ... -->
  
  <resource-mapping>
    <mapped-extension>*.view</mapped-extension>
    <resource-extension>*.jsp</resource-extension>
  </resource-mapping>
</web-app>

Composite Filters

To simplify configuration for common filter chains, the Filter Micro-Container has a CompositeFilter that can be used to group other filters together. When a CompositeFilter (or one of its subclasses) is invoked, all of the composed filters are invoked in turn, then the filter chain continues. All of the composed filters effectively match the same URL pattern as the composite filter.

Both the CommandFilter and ViewFilter at the heart of the Chrysalis engine are composite filters, to facilitate future expansion.

Filters on Servlet 2.3+ Containers

On Servlet 2.3+ containers, the Chrysalis filters can be specified in the standard /WEB-INF/web.xml configuration file. This allows the filters to have URL patterns matching file resource extensions, such as ".jsp". This makes the web application much easier to understand, since file extensions and URL extensions will be the same for view pages.

If backwards compatibility with Servlet 2.2 containers is necessary, you can add the ResourceMapper filter to the end of the filter chain to perform the necessary extension mappings. The necessary steps are discussed in the Chrysalis configuration guidelines for the web.xml and filter.xml files.