Mach II : Concepts

There's some important concepts to understand when building applications with Mach II. I'll cover a few of them very briefly here but you should always check the official site for more up-to-date documentation. I won't cover the XML configuration file itself because I can't do it justice in a few paragraphs - you can read the official documentation for that!

MVC : Model-View-Controller

The first concept is MVC - Model-View-Controller - where the presentation (View) is completely separated from your business logic (Model) and interactions between the two are handled by Mach II itself (Controller). The Views are simply .cfm files that render HTML - presentation code - and can make use of the event object and request scope variables (set by Mach II - more below). The Model is a set of ColdFusion Components that represent all the logic of your application, from the database interaction to the business rules and decisions. The Controller is, essentially, Mach II itself and the parameters of the Controller are defined by the mach-ii.xml file.

Implicit Invocation Architecture

The second concept is the Implicit Invocation Architecture on which Mach II is based. You can read more about this on the Mach II website (Ben Edwards has a great paper on this). The basic premise is that events are generated (by the user or by the application) and they are handled by, well, event handlers. The event handlers respond to the events by performing business logic and sometimes generating more events. Mach II keeps track of the active events and processes them, invoking listeners as necessary and rendering views until each each request is fully processed.

Passing Data in Mach II

The next thing to understand is how to use resultKey and contentKey to pass data out of the model (resultKey) and out of the views (contentKey) so that it is available for the controller to pass to other parts of the model or other views. When Mach II invokes a listener, or more precisely a method on a listener component, in response to an event, it can store the result of the method call in a resultKey variable. This is typically a request scope variable that is then available to views (or subsequent listener invocations for this request using the <event-arg> command to move the request variable into the event object). When Mach II renders a view, it can store the rendered HTML in a contentKey variable. Again, this is typically a request scope variable that is then available to subsequent views. These two mechanisms allow events to set up an environment of data that influences how subsequent events are handled and what the final view contains. For example, a calendar model could return a struct (via a resultKey) that defines: the title of the calendar (month, year), the number of days in a month and the day of the week on which the month starts; a calendar view could then take that struct and render a monthly calendar (e.g., as a table, like the calendar on my blog) as a contentKey and the final view could place that calendar anywhere on the page.

The Mach II Lifecycle

There are two key parts to understanding the lifecycle of requests and objects in Mach II: framework initialization and event handling. You can read about request and event handling in more detail on the official Mach II Documentation page.

All requests come through the root index.cfm file which simply includes the core /MachII/mach-ii.cfm. On the very first request (after the server has been started), the framework is initialized and all of the associated CFCs are cached in the application scope. The important thing to bear in mind here is that Listener CFC instances are created at this point and cached in application scope. That means that if your listeners are stateful, i.e., they store instance data in variables or this scope, then that data will be shared across all sessions and requests because it will be stored in application scope. The upside of this is that Mach II provides an easy way to perform centralized caching of data: you simply save it as instance data in your listeners. The downside is that if you need per-session data, e.g., a shopping cart, then you need to write a listener that acts as a Session Façade, i.e., it delegates its actions to a CFC that is stored in session scope. The ShoppingCart example application shows how this works: model/ShoppingCart.cfc acts as a Session Façade for model/Cart.cfc - the ShoppingCart component manages an instance of Cart in each user's session (session.cart).

When a request comes in, Mach II gathers up all the URL and form scope variables and creates an Event component instance in request scope containing all that data as event arguments. You can retrieve data from an event via the getArg("argName") method - and you can test for existence and set arguments using other methods on the event. Mach II then processes the event handler for the event specified in the request and either passes the event object to the method as a single argument (called event) or passes all of the event arguments as separate arguments to the method (depending on the invoker type). The event handler may generate additional events (using the announceEvent() method of Listener or the <announce ...> tag in the XML file) which are queued up for later processing. Mach II continues to process events until the queue is empty. This is the primary way that control flow is handled. Event handlers may or may not generate output, depending on whether they render a view or not. The very simplest control flow is that an event comes in (with no associated data) and the event handler specifies a view which is rendered to HTML. More complex flows might have an event handler invoke a listener method that then generates one or more events which determine how the request be processed.

More Information...

Read more about...