What's New in Mach-II 1.5

A Quick Start for Current Mach-II Developers

by Matt Woodward (matt@mach-ii.com)

Mach-II 1.5 introduces numerous powerful new features to the Mach-II framework, and each of these features was added to help make your Mach-II applications more powerful, flexible, and easy to maintain. The new architectural features in Mach-II 1.5 make it the most significant release of the framework since its original introduction in 2003.

Mach-II 1.5 Goals

In addition to the introduction of new features that Mach-II developers have requested, we had several other goals during the development of Mach-II 1.5.


Mach-II 1.5 Feature Overview

At a high level there are seven new features in Mach-II 1.5, along with numerous other bug fixes and performance enhancements.

Mach-II 1.5 Features In Depth

Now let's look at each of the new features in Mach-II 1.5 in more detail.

XML Includes

The Problem
As with many other frameworks, Mach-II relies on XML as its configuration language. This declarative configuration methodology is powerful and also creates an easy-to-read, single roadmap for the entire applciation. As Mach-II applications grow, however, the mach-ii.xml configuration file grows as well, which makes maintenance of the application more difficult. Even with good XML tools and IDEs maintaining large XML configuration files was more difficult than it needed to be, and having everything in a single XML file also reduces the reusability of the XML code.

The Solution
Mach-II 1.5 now supports the use of XML includes through the new <include> command, which allows developers to divide the Mach-II XML configuration file into multiple files. Not only does this make maintenance easier, it also allows for core application configuration to be separated from configuration that is specific to a particular instance of an application or sub-application. This also makes dealing with version control in a team environment more flexible.

The XML <include> command allows for overriding of the base configuration file through the inclusion of the override attribute. When override is set to true, anything in the included XML configuration file will override the contents of the base XML configuration file.

How It's Used
XML includes are easy to implement in legacy applications. The single mach-ii.xml configuration file can simply be divided into multiple configuration files and these files can then be included in the main configuration file.
<includes>
    <include file="/someother.xml" />
</includes>
Additional Information and Considerations

Modules

The Problem
With large-scale Mach-II applications there is often the desire to divide the application into logical sub-applications for easier maintenance and greater reusability of functionality across independent application. Prior to Mach-II 1.5 this was handled by creating multiple, independent Mach-II applications that all shared the same application scope through the declaration of a common application name in the related applications. While this did place all the sub-applications under a single application scope, this also lead to a great deal of redundancy in XML and other code between the related applications. For example, if a sub-application needed to share plugins, filters, or even event-handlers, it was necessary to include all the related XML code in every sub-application because the sub-applications had no true awareness of one another.

The Solution
Mach-II 1.5 modules allow developers to break large applications into peer and sub-applications without the shortfalls associated with the application key method described above. In Mach-II 1.5, a module is declared by name in the base XML configuration file, and the sub-application is controlled by an independent, complete XML configuration file. Sub-applications do, however, have access to the XML configuration file of the base application, which removes the redundancy in the XML configuration files. In addition, events in modules can be announced directly from the base application, and sub-applications can announce events in the base application, all without duplicating any XML configuration code.

How It's Used
Modules are simple to include in Mach-II 1.5 applications through the declaration of the module with a name and the location of its configuration file. For example, to include MachBlog inside an existing Mach-II application, the following syntax is used:
<modules>
    <module name="blog" file="/machblog/config.xml" />
</modules>
If the base application needs to announce an event in the subapplication, this is accomplished through the new module attribute of the announce command:
<announce module="blog" event="showBlogEntry" copyEventArgs="true" />
Event announcement in modules can also be performed from within CFML code in your application:
<cfset announceEventInModule("blog", "showBlogEntry", args) />
The modules attribute has also been added to the <event-mapping> (called mappingModule which is akin to the mapping attribute used to specify the event name) and <redirect> commands. Module events may also be announced via the URL through the use of the module name and event name separated by a colon:
index.cfm?event=blog:showLogin
A colon is used as the default delimiter, but this is configurable by setting a property called "moduleDelimiter" in your base application config file.

Additional Information and Considerations

Subroutines

The Problem
Prior to Mach-II 1.5 it was not possible to perform inline execution of XML "snippets" or XML code that did not constitute a complete Mach-II construct such as an event-handler. This necessitated redundancy in the XML configuration file and made things such as pod layouts more cumbersome than they needed to be. In addition, it was necessary in some cases to use something such as a continuation filter to perform "event chaining" in order to create dynamic layouts.

The Solution
Mach-II 1.5 subroutines enable the inline execution of XML snippets through use of the new <execute> command. This does not announce a new event that is put into the event queue, but rather the subroutine code is executed immediately in the context of the current event handler. This solution reduces redundancy and increases reusability of the XML code.

How It's Used
In versions of Mach-II prior to 1.5 it was commonplace to announce a new event for layout:
<event-handler event="displaySomething">
    <notify listener="myListener" method="myMethod" resultArg="myData" />
    <view-page name="myContentPage" contentArg="content" />
    <announce event="myLayout" copyEventArgs="true" />
</event-handler>
If the event "myLayout" is something like a pod-style layout that has numerous sub-components, this process becomes cumbersome rather quickly.

With Mach-II 1.5 the new event announcement is replaced by the execution of a subroutine, which executes the XML of the subroutine inline as opposed to announcing a new event:
<event-handler event="displaySomething">
    <notify listener="myListener" method="myMethod" resultArg="myData" />
    <view-page name="myContentPage" contentArg="content" />
    <execute subroutine="myLayout" />
</event-handler>
The subroutines are declared in the new <subroutines> section of the XML configuration file which follows the <event-handlers> section. The code for this sample subroutine might look something like this:
<subroutines>
    <subroutine name="myLayout">
        <view-page name="header" contentArg="header" />
        <view-page name="footer" contentArg="footer" />
        <view-page name="mainTemplate" />
    </subroutine>
</subroutines>
Because no new event is announced, the subroutine shares the same event context as the event in which the subroutine is executed. This eliminates the need for event chaining through the use of a continuation filter, and makes complex layouts far easier and less redundant.

Additional Information and Considerations

<redirect> Command Enhancements

The Problem
The <redirect> command was introduced in Mach-II 1.1.0 and allowed the ability to perform a client-side redirect when announcing a new event. This solved the issue of the URL not changing when a new event is announced, which caused issues in certain situations. For example, in an e-commerce application, if after a checkout operation is completed the URL does not change, the user could hit refresh and cause the order to be executed again.

The use of <redirect> solves this problem by announcing a new event that causes the URL to change, but because this is a client-side redirect, the ability to persist anything other than simple name/value pairs across the redirect did not exist. This issue was typically solved through the use of a filter/plugin combination.

The Solution
Mach-II 1.5 introduces enhancements to the <redirect> command, both to support persistence of complex objects across redirects, and also to allow for redirects to events within other modules. The redirect command actually uses the BuildUrlToModule() method behind the scenes, and if a module is not defined, it assumes the current module. In addition, the ability to specify an HTTP status code has been added, giving you precise control over the specific type of redirect you wish to perform.

How It's Used
To persist complex arguments across a redirect, simply add persist="true" to the redirect command:
<redirect event="myRedirectEvent" persist="true" />
By default if "persist" is set to true, the entire event object will be persisted across the redirect. Otherwise, you may optionally specify a list of the event arguments to persist across the redirect:
<redirect event="myRedirectEvent" persist="true" persistArgs="list,of,event,args,to,persist" />
With Mach-II 1.5 you may also specify a statusType attribute in the redirect command for explicit control over the type of redirect that is performed. This can assist with things such as search engine spidering, because in some cases search engines will not index things such as temporary redirects (HTTP status code 302), which is the default behavior of cflocation.

For example, the following would perform a redirect and specify the redirect status as permanent (301):
<redirect event="myRedirectEvent" statusType="permanent" />
The three status types supported are "permanent" (HTTP status 301), "temporary" (HTTP status 302, which is the default behavior), and "PRG" for a post-redirect-get (HTTP status 303).

Additional Information and Considerations

New Property Datatypes

The Problem
The use of Mach-II properties is a powerful way to make properties available throughout Mach-II applications. Simple name/value pairs can be declared in the <properties> section of the XML configuration file. Setting complex data types such as arrays, structs, and CFCs as properties, however, required the use of the configure() method of a plugin in order to instantiate these complex data types as properties when the application loads. While this worked, it was unnecessary cumbersome and was clearly less than ideal.

The Solution
Mach-II 1.5 introduces the ability to declare arrays and structs as properties in the XML configuration file. In addition, a new Property.cfc has been added to the Mach-II framework to allow declaration of custom CFCs as Mach-II properties that will automatically be loaded when the application initializes. This eliminates the need to use the configure() method of a plugin to load complex data types as properties in Mach-II applications.

How It's Used
Declaring structs and arrays in the XML configuration file is simple and flexible:
<property name="myStruct">
    <struct>
        <key name="key1" value="value1" />
        <key name="key2"><value>value2</value></key>
    </struct>
</property>

<property name="myArray">
    <array>
        <element value="value1" />
        <element><value>value2</value></element>
    </array>
</property>
You may also create composition objects using this notation, such as arrays of structs or structs of arrays. For example:
<property name="myArray">
    <array>
        <element>
            <struct>
                <key name="key1" value="value1" />
            </struct>
        </element>
    </array>
</property>
The new Property.cfc is extended by the developer in similar fashion as Listeners, Plugins, and Filters, and allows for easy declaration of CFC properties in the XML configuration file. A Property.cfc must contain a configure() method that is automatically called by Mach-II once when the application initializes which is similar to how listeners, filters and plugins are designed. Declaration of custom CFCs as properties in the XML configuration file is performed as follows:
<property name="myCustomCFCProperty" type="path.to.myCFC" />
Similar to filters and plugins, Property.cfc also supports runtime parameters:
<property name="myCustomCFCProperty" type="path.to.myCFC">
    <parameters>
        <parameter name="param1" value="value1" />
        <parameter name="param2">
            <struct>
                <key name="blue" value="is a cool color"/>
                <key name="red" value="is not a cool color"/>
            </struct>
        </parameter>
    </parameters>
</property>
Additional Information and Considerations

URL Management

The Problem
Prior to version 1.5, Mach-II did not provide a means for interacting with URL management and URL building, which limited the ability for developers to control URL formatting, made the URL syntax more verbose than it needed to be, and did not support things such as search engine safe (SES) or friendly URLs. If developers do not have control over URL building at the web server level using something such as Apache's mod_rewrite, in some cases this limited the ability for developers to use Mach-II when SES URLs were mandatory.

The Solution
After much deliberation, we decided that because Mach-II acts as the controller in an HTML-based MVC application, it should know how to build URLs. It was necessary to add URL building functionality to the framework in order to support features such as modules within the framework itself, so we decided to expose this functionality to developers for use on the front-end as well.

To support this new functionality, the new methods BuildUrl() and BuildUrlToModule() were added to Mach-II 1.5. These methods are configurable so the developer can create URLs in virtually any desired format.

How It's Used
Use of the new BuildUrl() and BuildUrlToModule() methods is very simple, and uses new configurable properties in building the URL. For example, to create a URL to the showLogin event, this is all that is required:
BuildUrl("showLogin")
If the default URL building parameters are used, this generates the URL index.cfm?event=showLogin.

To pass arguments to the event announcement, the arguments are added as the second argument to the BuildUrl() method:
BuildUrl("showLogin", "usr=#event.getArg('usr')#") or
BuildUrl("showLogin", structOfArgs)
This becomes the URL index.cfm?event=showLogin&usr=bob (or additional name/value pairs as defined in the struct).

If the event is in another module, the BuildUrlToModule() method is used:
BuildUrlToModule("myModule", "myEvent")
This becomes the URL:
index.cfm?event=myModule:myEvent
As mentioned above, all of the URL building parameters are customizable. These are set by properties in you configuration file.  These new properties are as follows:
<property name="urlBase" value="index.cfm" />
<property name="urlDelimiters" value="?|&|=" />
<property name="moduleDelimiter" value=":" />

SES/friendly URL parsing is now available in Mach-II 1.5. This is enabled through the new Mach-II property UrlParseSES, which defaults to false. As an example, the URL http://myserver/index.cfm?event=showLogin could easily become http://myserver/index.cfm/event/showLogin through the use of SES URL parsing in Mach-II 1.5.

If you wanted to create SES urls like the example in the previous paragraph, just set these properties and use buildUrl():
<property name="urlParseSES" value="true" />
<property name="urlDelimiters" value="/|/|/" />
Additional Information and Considerations

Bindable Property Placeholder

The Problem
By using parameters in Mach-II objects such as plugins, filters, and listeners, it's easy to set variables to specific values inside these objects. By nature, however, this means that the value of these parameters is hard-coded, so when these parameters need to be changed for deployment to different servers, for example, it's often necessary to change the value of these parameters in multiple places.

The Solution
The introduction of bindable property placeholders in Mach-II 1.5 allows developers to set the value of a parameter once and refer to that value using the common data binding notation used in other frameworks such as ColdSpring. This may seem like a small enhancement, but it makes life as a developer much easier as applications are moved from development to staging to production.

How It's Used
Use of the bindable property placeholder is simple:
<parameter name="someParameter" value="${somePropertyName}" />
This would reference a property that is set in the Mach-II XML configuration file in the properties section:
<properties>
    <property name="somePropertyName" value="someValue" />
</properties>
This syntax can be used wherever parameters are supported.

Additional Information and Considerations

Other Fixes and New Features

In addition to the new architectural features outlined above, we incorporated numerous other fixes and new features in the Mach-II 1.5 release.

What You Can Do To Help

We hope that you're happy with all the new features in Mach-II 1.5. How you can help us ensure that this is the most functional, solid release of Mach-II is by doing the following:

The Road Ahead

Never resting on our laurels, we're already looking ahead to new incremental releases, more and better documentation, and new full releases of Mach-II.

Resources