/!\ Outline - work in progress

ReDesign of request handling

In DesignPaper some problems of the current architecture of MoinMoin were outlined. To overcome those, core functions and interfaces have to be redesigned, breaking some compatibility in the process. FlorianFesti instructed me to write a proposal on a better architecture for dealing with the request-response cycle in MoinMoin, especially in regards to the output of templated/themed HTML.

An approach for Moin

To reduce tight coupling of components like in current MoinMoin, a new approach would have to promote a clean separation of responsibilities. The responsibilities of typical current MoinMoin artefacts, regarded from what they should be instead of what they are, can be described as follows:

To support the connection between the described artefacts some additional artefacts can be put to use:

Regardless of how those concepts are put together and implemented, the following directive should be followed at all times: /!\ Only Request itself, Actions and the Dispatcher write to the output stream /!\

Approach Patterns

In the following two design approaches with their respective advantages and disadvantages are discussed. The mentioned artefacts are put into relation to the specific design. Also examples for the processing of requests are given.

MVC

ModelViewController is a well understand and often used principle in object oriented design. While the current implementation of MoinMoin follows this pattern in some way, the intended decoupling is neglected in a way that produces the problems described in DesignPaper.

Pro & Contra:

Dataflow (a.k.a Pipes & Filters)

This describes a somewhat different approach. Instead of revolving around the dispatcher and the controlling actions, which act on data, processing is centered around the data itself. The basic image of the process is that of "Pipes and Filters". The incoming request is passed through several handlers that registered themselves centrally for a specific processing task (for example determining the template and additional context data or in the higher levels parsing a wiki page). The handlers themselves hold no state that is data-specific but instead simply augment the data, pass to a bunch of other registered handlers for further processing and return data to the calling handlers accordingly.

To get an idea of how this pattern is implemented and put to use, following bits of source can be consulted. The code from Trac serves as an example for low level request processing and the code from Pocoo shows how this pattern can be continued into the last corner of a wiki web application.

trac/core.py - Trac's implementation of a component model, the basis for the different handlers. Communication and locatability between components is achieved via defined interfaces.

trac/web/api.py - Some interfaces used at the low levels, especially the RequestHandler interface

trac/web/main.py- Trac's entry-point for the handling of an incoming request. Note how the RequestDispatcher actually tries the different registered handlers in turn and lets them decide if they are responsible.

tekisuto/lexer.py - tekisuto is an experiment in parser building for markup based systems like wikis. The Lexer (central registry) passes the data to parse line by line to the Directives (registered handlers), together with a dictionary from the current stacklevel. Matching directives can use the dictionary to carry state between their respective start and end in the nesting of markups, or simply handle the whole markup in the start directive.

tekisuto/../tests/moinlexer.py - This is a simple example for the use of the basic classes. It parses a subset of MoinMoin wiki markup.

Examples for MoinMoin

The examples are simplified here and there (Caching components are left out for example).

Request to show a wikipage:

  1. Request (abstracted into an object) enters the system

  2. a Dispatcher (perhaps local to a wiki in a farm) augments it with data from the config

  3. the Request is passed to every registered RequestHandler

  4. the ViewHandler (corresponding to the 'view'-Action in current implementation) claims that he can satisfy the Request

  5. Dispatcher passes the Request to the ViewHandler

  6. ViewHandler determines the requested Page and fetches it from the storage (not detailed here)

  7. ViewHandler determines the requested representation of the page => 'text/html'

  8. the Page and desired format is passed to every registered FormatHandler

  9. the HTMLFormatter claims that he can satisfy the Request

  10. ViewHandler passes the Page to the HTMLFormatter

  11. [ ... the dataflow continues in the same way to the ParserHandlers ... ]

  12. ViewHandler receives a formatted version of the Page-content from the HTMLFormatter

  13. ViewHandler prepares a content dictionary for the rendering (the page content, perhaps user data, etc.), adds some information to the Chrome (css-stylesheet to include, some javascript) and sets some response headers (content type, cache control, etc.)

  14. Dispatcher receives the content dictionary, the content type and the name of the template to use ('view.html') from the ViewHandler.

  15. It interprets this as a prompt to use the Chrome-HTML-renderer for generation of final output (opposed to receiving raw content from the RequestHandler) and therefore passes on the request, the content dictionary and the template name to the Chrome-component.

  16. Chrome-HTML-renderer uses the config and user-data in the request to determine the theme to use.

  17. Chrome finds and loads 'view.html' and theme-specific templates (a more specialized 'view.html' from the theme directory for example)

  18. Chrome generates HTML from the templates, the content dictionary, the Requests chrome-object and then passes the result back to the Dispatcher

  19. Dispatcher get's control for the last time. The complete response is send to the user agent, final cleanups are carried out.

Dataflow.png

Where to reduce tight coupling

Misc. Notes

MoinMoin: FlorianKrupicka/SOC2007/ReDesign (last edited 2008-05-03 13:59:56 by FlorianKrupicka)