-
Notifications
You must be signed in to change notification settings - Fork 24
What's New in Mach II 1.5
A Quick Start for Current Mach-II Developers
- What's New in Mach-II 1.5
- Mach-II 1.5 Goals
- Mach-II 1.5 Feature Overview
- Mach-II 1.5 Features In Depth
- What You Can Do To Help
- The Road Ahead
- Resources
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.
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.
- Maintain backwards compatibility. Mach-II 1.5 is 100% compatible with existing Mach-II applications currently running on earlier versions of Mach-II.
- Make large applications easier to develop and maintain. Mach-II has always run large applications extremely well, but its use of a single XML configuration file meant development and maintenance were not as easy as they could be. The introduction of XML includes, subroutines, and modules addresses this concern and allows for a great deal of flexibility in Mach-II application configuration and architecture.
- Introduce official support for peer and sub-applications. Although the creation of sub-applications was possible in previous versions of Mach-II by using the same application name across applications, the new module feature in Mach-II 1.5 allows for official, flexible support for peer and sub-applications, complete with granular overrides. Module support also allows Mach-II developers to build and share reusable functionality such as authentication, shopping carts, or even complete stand-alone applications that can easily be integrated as modules into existing Mach-II applications.
- Introduce official support for common tasks that required workarounds. The new Property.cfc and support for the declaration of arrays and structs as properties eliminates the need to use the configure() method in a plugin to add complex datatypes to the Mach-II property manager. The <redirect> command now supports persistence of complex objects across the redirect, without the need for the plugin/filter combination that was previously used to support this functionality.
- Keep the framework true to its mission. The mission of Mach-II is to provide ColdFusion developers with a powerful, easy-to-use MVC framework that is extensible through its plugin and filter architecture. We are always extremely cautious when we add new features to Mach-II, and we weighed the inclusion of each of the new Mach-II 1.5 features very carefully. We feel that the features introduced in Mach-II 1.5 represent a logical evolution without diluting the framework through the addition of ancillary features directly into the framework.
- Set the stage for Mach-II 2.0. We made several behind-the-scenes changes that will enable functionality we have planned for Mach-II 2.0, which we are currently targeting for early 2009.
At a high level there are seven new features in Mach-II 1.5, along with numerous other bug fixes and performance enhancements.
-
XML Includes Mach-II 1.5 now allows the inclusion of additional XML files in the main mach-ii.xml configuration file. This is accomplished through a simple
<include>
directive in the XML file. -
Modules Modules can be used to create sub- and peer-applications, or to easily integrate third-party functionality within Mach-II applications.
-
Subroutines Subroutines allow for inline, immediate execution of "snippets" of XML. This allows for more granular reuse of and reduces redundancy in the XML, and is extremely handy for things such as executing layouts that previously required a new event announcement.
-
<redirect>
Command Enhancements The<redirect>
command now supports the persistence of complex objects across redirects, which previously required the use of a filter/plugin combination. -
New Mach-II Property Datatype Support
- Mach-II 1.5 introduces the ability to declare structs and arrays as properties in the mach-ii.xml configuration file.
- Mach-II 1.5 introduces support for using CFCs as Mach-II properties through the new Property.cfc framework object, which previously required the use of the configure() method in a plugin to ensure the CFCs were placed in the Mach-II property manager when the application initialized.
-
New URL Management Features Mach-II 1.5 introduces two new methods, BuildUrl() and BuildUrlToModule(), that allow for highly configurable control over URL formatting. These methods make the syntax for URLs within Mach-II applications much more compact, and also enable the creation of SES/friendly URLs
-
Bindable Property Placeholder Support with Parameters Dynamic properties can be bound to specific values in the XML configuration file through the use of common data binding syntax, e.g.
{$property}
. One example of the use of bindable properties is in the deployment of an application to different servers that require server-specific parameters, such as when running an application on development, staging, and production servers.
Now let's look at each of the new features in Mach-II 1.5 in more detail.
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.
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.
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>
- XML includes are run in the order in which they are declared.
- You cannot declare two Mach-II elements with the same name. For example, your base config file has a "home" event-handler and your include also has a "home" event-handler. Mach-II will throw an error saying you cannot have two elements with the same name. If you want your include elements to override elements in the base config file, add the override="true" attribute to the <include> tag. Any conflicts between the base and include config files will be overridden with the elements from the include file.
- Mach-II reloads all includes when the framework is reloaded, or if the framework is being run in dynamic reload mode.
- XML includes can be used to create modular applications to a certain extent, but for truly modular applications the new module feature of Mach-II 1.5 should be used.
- The file attribute of the
<include>
tag supports relative paths. We use the../
(move up a directory) and./
(same directory) syntax from HTML and *nix. All relative paths must start with./
or../
All relative paths are relative from the configuration file that defines the path to the other configuration file - not relative to your webroot or application root. - XML includes must be fully formed Mach-II XML files, and as such must have a root node of <mach-ii>. Includes must also contain a node for the Mach-II XML configuration element type to which they apply. For example, if you wanted to include a file called properties.xml containing application-specific properties, the contents of this include file would be as follows:
<mach-ii>
<properties>
<property name="myAppSpecificProperty" value="myValue" />
</properties>
</mach-ii>
- XML includes are not limited to a single Mach-II element type. For example, if you wanted to include both properties and event handlers in an include, the contents of the include could be as follows:
<mach-ii>
<properties>
<property name="myAppSpecificProperty" value="myValue" />
</properties>
<event-handlers>
<event-handler name="myEventHandler" access="public">
<!-- event-handler actions here ... -->
</event-handler>
</event-handlers>
</mach-ii>
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.
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.
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 use 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.
- Modules can be used to divide large applications into smaller logical sections.
- Modules can provide drop-in functionality from third-party sources.
- Modules are simple to use in newly created Mach-II applications, and legacy applications can be easily refactored to be used as Mach-II 1.5 modules.
- Mach-II reloads modules independently when the framework is in dynamic reload mode, meaning that if a module hasn't changed, it won't be reloaded.
- XML includes can be used inside modules.
- Additional modules cannot be declared inside a module. In other words, you cannot nested modules inside a module.
- Modules extend the base application modules, which allows filters, listeners, properties, event-handlers, and anything else declared in the base XML configuration file to be used directly within the module.
- Module elements may be overridden by the base module. For example, if a module has its own login process but you want to use the base module's authentication mechanism in the module, the module's login method could be overridden by the base module. Note that this may require some refactoring of the module.
- By design, all modules use the URL syntax properties (which are used by
BuildUrl()
) set by the base config file. As long as the module uses BuildURL() throughout its' implementation, any properties that affect how URLs are built will be used by the module. Modules cannot override the URL syntax properties set by the base config file. - The file attribute of the
<module>
tag supports relative paths. We use the../
(move up a directory) and./
(same directory) syntax from HTML and *nix. All relative paths must start with./
or../
All relative paths are relative from the configuration file that defines the path to the other configuration file - not relative to your webroot or application root.
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.
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.
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.
- Subroutines share the same event context and event object as the event in which they are executed.
- There are no preSubroutine or postSubroutine plugin points.
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.
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.
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).
- Use redirect when you don't want the user to be able to resubmit things such as form data by clicking refresh in their browser.
- Use the new "persist" attribute to persist complex arguments across the redirect.
- If necessary, specify the statusType to explicitly set the type of redirect that will be performed.
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.
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
type 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.
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>
- Custom CFCs used as properties must extend
MachII.framework.Property.cfc
. - Don't use the new Property.cfc to instantiate your model as properties in Mach-II. The intended use of Property.cfc is to instantiate things such as utility objects, UDF libraries, etc. as properties within Mach-II.
- Structs and arrays of Property.cfc data types is not supported.
- New
ColdSpringProperty.cfc
is available in the bleeding edge release of the ColdSpring CVS repository. This will eliminate the need to use a plugin to interact with ColdSpring. - Parameters for listeners, filters, plugins and properties now supports structs and arrays just like they are defined in properties.
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.
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.
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')#")
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:
-
UrlBase
: defaults to index.cfm -
UrlDelimiters
: defaluts to ?|&|= (We use the pipe | as the list delimiter)- First position is the query string delimiter (?)
- Second position is the URL parameter delimiter (&)
- Third position is the name/value pair delimiter (=)
-
ModuleDelimiter
: defaults to:<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://www.example.com/index.cfm?event=showLogin
could easily become http://www.example.com/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="/|/|/" />
- URL parsing does have some limiting behavior due to the nature of web servers and URL parsing unless you have full control over your web server
- Mach-II will parse the
cgi.PATH_INFO
for the SES URL data and will add this to the event object - If you need total control over URL rewriting, we recommend the use of a web server tool such as mod_rewrite for Apache or IIS Rewrite
- You may need to specify base href tag in the head of your layout when using SES.
- If you pass a struct of parameters to
BuildUrl()
, ColdFusion will automatically uppercase the keys in your url.
Take this example:
<cfset urlParams = StructNew() />
<cfset urlParams.username = "dude" />
<cfset urlParams.lastName = "Bob" />
#BuildUrl("someEvent", urlParams)#
will do this http://www.example.com/index.cfm?event=somEvent&USERNAME=dude&LASTNAME=Bob
This is probably undesirable, however this is how ColdFusion converts key names when creating structs with a dot notation. You can keep your case by using array notation:
<cfset urlParams = StructNew() />
<cfset urlParams["username"] = "dude" />
<cfset urlParams["lastName"] = "Bob" />
BuildUrl("someEvent", urlParams)#
will do this http://www.example.com/index.cfm?event=somEvent&username=dude&lastName=Bob
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 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 (i.e. ${propertyName}) 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.
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, but cannto be used for values of command attributes. For example:
<redirect event="${anotherEvent}"/>
Is not valid and will not work.
- Small enhancement that provides big flexibility gains in application configuration
- Use wherever run-time parameters are available (listeners, filters, plugins)
- Future versions of Mach-II may add a scope for bindable properties, e.g.
${property.somePropertyName}
, and this may break some backwards compatibility. - You could easily write an Property.cfc that defines property values depending on the server that the application is deployed (could use the
cgi.SERVER_NAME
for example).
In addition to the new architectural features outlined above, we incorporated numerous other fixes and new features in the Mach-II 1.5 release.
-
TracePlugin has better granular display support
-
The event-bean command has a new optional
reinit
attribute that can be used to control the reinitialization of the event bean within events -
New required event-handler check; if there is no
defaultEvent
specified Mach-II will throw an exception- Mach-II will skip required event-handler checks in modules if you do not define a "defaultEvent" or "exceptionEvent" property in the module's property section. The framework will default to the default event and exception from the base config file
-
Performance improvements in framework loading (10-20%)
-
The
EventContext
andRequestHandler
objects have been completely rewritten to support new functionality -
Numerous miscellaneous bug fixes
- The "white screen of death" was still being thrown when the maximum number of events was exceeded (thanks to Dave Shuck for pointing this out)
- Metadata bug in the PluginManager (thanks to Mark Mandel for pointing this out)
- The framework loaded itself twice when running in dynamic reload mode
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:
- Test your existing applications for backwards compatibility
- Use the new features and give us your feedback. Do they work? Do you like the way they work?
- Go bug hunting and let us know ASAP if you have any issues. If you do find bugs, please write a test case for our test harness to demonstrate the bug.
- Post all your findings on our Google Group (http://groups.google.com/group/mach-ii-for-coldfusion)
- Write documentation! FAQs, Quick Starts, Tutorials, Sample Applications, etc.--the more the better.
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.
- Developer exchange on mach-ii.com coming soon - this will allow developers to exchange modules, filters, plugins, etc.
- Team Mach-II blog to help everyone keep up on the latest Mach-II development information
- 1.6.0 release, scheduled for Q3 2008
- 2.0 alpha release, scheduled for Q1 2009
- big features planned!
- The Official Mach-II Web Site
- Mach-II on Google Groups
- Working Specifications for Mach-II 1.5 Features
- Modules and Includes: http://docs.google.com/Doc?id=dhjcwfn4_8hsz9kh
- Complex Property Datatypes: http://docs.google.com/Doc?id=dhjcwfn4_9g592s9
- Subroutines: http://docs.google.com/Doc?id=dhjcwfn4_10hhrb8s
- URL Management Enhancements: http://docs.google.com/Doc?id=dhjcwfn4_20fszzw3
Contact Team Mach-II (info [at] mach-ii.com)