What's New in 2.6.0

This is a great new update for the ColdBox Framework & Toolkit. It includes several optimizations, bug fixes and some great new features and additions. For the entire list of tickets for this release, please visit the Release Notes.

Per-App Conventions

As you know, ColdBox works on conventions in order to work. However, in previous versions, you had to abide by the framework wide conventions. You could change them, but that meant ALL applications where the same. With per-app conventions you can declare the conventions YOU want for your app right on the configuration file. This increases the portabilities of the ColdBox applications, as now you can override any setting a framework-wide installation might have implemented and you are guaranteed that they will work. All you need to do is add the following to the coldbox.xml file:

<Conventions>
        <handlersLocation>_handlers</handlersLocation>
        <pluginsLocation>_myplugins</pluginsLocation>
        <layoutsLocation>_layouts</layoutsLocation>
        <viewsLocation>_views</viewsLocation>
        <eventAction>index</eventAction>                
</Conventions>
Important All conventions that are locations require a relative location to the Root of the running application. They cannot be set outside the root.

New Convention: Default Event Action

The framework now declares a default event action that will be executed on an event handler if not passed via URL/FORM/REMOTE. The default framework-wide convention is index. This means that you can create a new event called index in your event handler and the framework will call it implicitly. Example, create a new event handler called default then create a method on it called index. When you go to the URL: index.cfm?event=default or index.cfm/default, if the default event handler has the method index on it, it will execute it. How cool is that, your URL's can even become shorter now.

This update also applies to the SES interceptor.

New Convention: onMissingAction()

Again, the power of conventions. With this new convention you can now create virtual events that do not even need to be created in a handler. Every time an event requests an action from an event handler and that action does not exists in the handler, the framework will check if an onMissingAction() event action has been declared. If it has, it will execute it. This is very similar to ColdFusion's onMissingMethod but on an event-driven framework.

Below is the skeleton for such an event action:

<!--- onMissingAction --->
<cffunction name="onMissingAction" access="public" returntype="void" output="false" hint="on missing action">
    <cfargument name="Event" type="coldbox.system.beans.requestContext" required="yes">
    <cfargument name="missingAction" required="true" type="string" hint="">
    <cfset var rc = event.getCollection()>
        <cfscript>
                
        </cfscript> 
</cffunction>

This event has an extra argument: missingAction which is the missing action that was requested. You can then do any kind of logic against this missing action and decide to do internal processing, error handling or anything you like. The power of this convention method is extraordinary, you have tons of possibilities as you can create virtual events on specific event handlers.

Note: This convention will only fire if the missing action is on a specified event handler and the onMissingAction method exists on the handler. If not, the normal error handling routines will fire.

Debugger Settings

The ColdBox Debugger has been updated and it is in great transition to become an open API for further ColdBox versions. Versions 2.6.0 introduces the configuration of the debugger via the framework wide settings file or your application configuration file. Below is a snippet of what you can do:

<DebuggerSettings>
        <PersistentRequestProfiler>true</PersistentRequestProfiler>
        <maxPersistentRequestProfilers>10</maxPersistentRequestProfilers>
        <maxRCPanelQueryRows>50</maxRCPanelQueryRows>
        
        <TracerPanel    show="true" expanded="true" />
        <InfoPanel      show="true" expanded="true" />
        <CachePanel     show="true" expanded="false" />
        <RCPanel        show="true" expanded="false" />
</DebuggerSettings>

The panel sections are pretty self-explanatory, you choose which panels you want to display and which ones you want expanded by default. The first three settings are new and here are their explanation table:

Setting Type Framework Default Description
PersistentRequestProfiler boolean false If set to true, the framework will store request profiler information so you can view it via the new execution profiler panel
maxPersistentRequestProfilers numeric 10 The number of requests to store in the persistent profiler.
maxRCPanelQueryRows numeric 50 The number of rows to display on the RC panel when dumping queries.

Execution Profiler Monitor

A brand new monitor has been built that will keep a stack of the latest X requests and their execution profiles. This monitor can be kept side by side with your flex/AJAX or any frontend and give you execution profiles about your event model. By default the request profiler is turned off, so you will have to turn it on via the new Debugger Settings in your configuration file. You can also choose the max number of requests to persist execution profiles for.

Reinit Button on Info Panel

The info panel now has a button that you can use to reinitialize the framework. The panel even detects if you are using a reinit password or not. If you are it will ask you for the password and be off reinitializing your application with ease and comfort.

New setting ViewsExternalLocation

This completes the circle for having external locations for handlers, plugins and now views. This is a great missing addition that enables the possibilities of creating an external location for drop-and-play functionality for the framework. You can create an external location to be a modules section and then you can build standalone modules with their views/handlers and plugins. How cool is that.

Example:

<Setting name="ViewsExternalLocation" value="modules" />
<Setting name="HandlersExternalLocation" value="modules" />
<Setting name="MyPluginsLocation" value="modules" />

Then you can create different modules like a blog, forum, etc.

Event-RenderData()

This new method will change the way you do AJAX and REMOTE integration in all of your applications. This method in the event object will provide you with the ability to render data back to the caller, either in MVC mode or in Remote mode via the ColdBox Proxy. The following is the method signature:

  • renderData(type=[JSON|WDDX|Plain], data, contentType)

You can use this function from your event handler to set some data and in what type it should be rendered and what content type to use. No setting of views or layouts or nothing. Let the framework marshall the data for you into either JSON, wddx, or plain types. So easy to return a JSON object, or maybe an rss feed, or a boolean response, or anything you can imagine. Simply by using one simple method.

Examples:

//Render a json query
<cfset event.renderData(type="JSON", data=myQuery)>

//Render a boolean value
<cfset event.renderData(type="plain", data=true)>

//Render Some words
<cfset event.renderData(type="plain",data="Received">

//Render a structure into wddx
<cfset event.renderData(type="wddx", data=myStruct)>

As you can see, it is really really easy to interact with this new method. Take advantage of it and simply your AJAX and REMOTE interactions.

Resource Bundle Ehancement

You can now declare a new setting under the i18n settings called UnknownTranslation. You will use this setting to set a key to display when a translation is not found in the resource bundle.

<UknownTranslation>NONE</UknownTranslation>

Interceptors Enhancements

Interceptors are a great way to add functionality at certain executions points to the framework or even create a broadcast-listener patterns. 2.6 solidifies the usage of this great functionality and now you can do the following:

  • Un-Register interceptors from specific states programmatically: unregister() from an interceptor cfc.
  • Register interceptors programmatically by using the registerInterceptor() method. You can register ANY component as an interceptor now, they no longer need to have an interceptor signature if they are registered programmatically. You can register a handler as an observer, a plugin or even any kind of object. As long as the conventions on the interception point is implemented as a method, you are ready to go. This means, that you can register anything on the fly, and they don't even have to be interceptors, they become interceptors when you register them.
  • Append custom interception points programmatically. You can now tell the interceptor to register new interception points without touching the configuration file
  • Stop Execution chain via interceptor method return type
//Add new interception points
getController().getInterceptorService().appendInterceptionPoints('onLog,onError,flexcalls');

//Add the current handler as an observer for the interception point of "flexcalls"
getController().getInterceptorService().registerInterceptor(interceptorObject=this,customPoints='flexcalls');

//Add a non-instantiated interceptor as an observer for the interception point of 'wikiTranslate':
getController().getInterceptorService().registerInterceptor(interceptorClass='model.wikiparser.feedparser',interceptorProperties=myProps,customPoints='wikiTranslate');


//Unregister yourself from the preProcess point, this is from within an interceptor
unregister('preProcess');

//get the entire state container for preProcess For metadata or reporting
getController().getInterceptorService().getStateContainer('preProcess');

//Get all the interception state containers for metadata or reportin
getController().getInterceptorService().getInterceptionStates();

//Get all the interception points registered in the application
getController().getInterceptorService().getInterceptionPoints();

Even when you register an interceptor programmatically, the system can even AUTOWIRE it if you have defined the autowire metadata attribute in its cfcomponent tag. So you can create a new interceptor and the system will autowire it for you automagically. As you can see, interceptors have been solidified and expanding on their great contributions to building applications.

Interceptors Return Type

In pre-2.6 ColdBox applications, the interceptor methods had a return type of void. On 2.6 applications, this has changed to boolean. The default return value is false. Why? Well, this boolean variable can determine if the processing service should continue to execute interceptors in the chain. If you return a true, this means that the interceptor service should STOP executing the other interceptors in the chain. In summary, the return value acts as a stop command for the chain. You do not need to change anything in order for your previous interceptors to work. However, the knowledge of this feature is now useful. Below you can see two samples, one return false and another return true. The second one will cause the executing chain of afterConfigurationLoad interception points to stop.

<cffunction name="afterConfigurationLoad" output="false" access="public" returntype="boolean" hint="ENVIRONMENT control the settings">
        <!--- *********************************************************************** --->
        <cfargument name="event"        required="true" type="coldbox.system.beans.requestContext" hint="The event object.">
        <cfargument name="interceptData" required="true" type="struct" hint="A structure containing intercepted information. NONE BY DEFAULT HERE">
        <!--- *********************************************************************** --->
        <cfscript>
                if( getProperty('interceptorCompleted') eq false){
                        parseAndSet();  
                        setProperty('interceptorCompleted',true);
                }
                //continue with chain, or don't return anything, leave it as void.
                return false;
        </cfscript>
</cffunction>

<cffunction name="afterConfigurationLoad" output="false" access="public" returntype="boolean" hint="ENVIRONMENT control the settings">
        <!--- *********************************************************************** --->
        <cfargument name="event"        required="true" type="coldbox.system.beans.requestContext" hint="The event object.">
        <cfargument name="interceptData" required="true" type="struct" hint="A structure containing intercepted information. NONE BY DEFAULT HERE">
        <!--- *********************************************************************** --->
        <cfscript>
                if( getProperty('interceptorCompleted') eq false){
                        parseAndSet();  
                        setProperty('interceptorCompleted',true);
                        
                        //Stop Chain
                        return true;
                }
        </cfscript>
</cffunction>

Autowire Interceptor Enhancements

The autowire interceptor has been enhanced to read an object's cfproperties and setter methods. You can now simply annotate or describe your dependencies via the cfproperty tag and the interceptor will inject them as you describe them. You can even choose the scope and from where to inject, either the IoC container or the ColdBox Cache.

<cfproperty name="UserService"   type="ioc" scope="instance" />
<cfproperty name="LookupService" type="ioc" scope="instance" />
<cfproperty name="PublicService" type="ocm" scope="this" />

As you can see from the sample above, you annotate using three properties:

property value description
name string The name of the bean to inject
type ioc or ocm This indicates that the dependency exists in the ColdBox Cache or the IoC Container
scope string This is the scope to which to inject the dependency to. This can be anything you like, but it defaults to variables scope.

This enhancement is a more descriptive approach to your object dependencies than mere setter injections. Properties are read first and then setter methods will be discovered. So you can still use setter injection or a combination of both. The autowire interceptor will also work with any the object's inheritance tree. Not only will you be able to autowire anything from an IoC container, but also from the ColdBox Cache.

New Plugins: Feed Reader, Feed Generator

These plugins where already in the code depot but they have been moved to the core in order to provide feed capabilities to non-Adobe cfml engines. Also, it is an enhanced type of cffeed in that it will parse any type of feed from any source: web,file,ram. It also makes use of the ColdBox caching engine or a new File Engine Cache Provider. So you can determine to cache the feeds in a serialized form in the coldbox cache or a file cache. All of the plugins parse ISO8601 and RFC822 dates correctly and uses their timezone information and calculates the epoch offsets correctly.

  • parse Atom or RSS feeds
  • cache the parsed feeds in RAM or file cache
  • tweakable cache settings
  • parse all ISO8601 and RFC822 dates
  • configurable from your application configuration file
  • generate RSS 2.0 feeds
  • generate feeds using a data mapper, so it can tranlsate from query columns to feed columns
  • much more...

Utilities Plugin Enhancements

  • Ability to upload a file to a location: uploadFile()
  • New date parsing methods:
    • parseISO8601()
    • parseRFC822()

Bean Factory Plugin Enhancements

The bean factory plugin has been enhanced with some new methods:

  • populateFromStruct : Populate a bean from a structure of key-value pairs
  • populateFromJSON : Populate a bean from a JSON packet
  • populateFromQuery : Populate a bean using a query
  • autowire : The ability to autowire a bean using the IoC container, it follows the same conventions as autowiring with the autowire interceptor.

Please look at the API to see all the available arguments.

Messagebox Plugin Enhancements

The messagebox plugin has been revamped and has improvements in the following areas:

  • You can now override the storage scope without affecting all framework applications by setting a Custom Setting. Pre 2.6 you had the storage scope set in the framework wide settings.
Your Setting Values
messagebox_storage_scope session or client
<YourSettings>
  <Setting name="messagebox_storage_scope" value="session" />
</YourSettings>
  • You can now send an array of messages to the setMessage() method, the plugin will create a message string and they will be rendered with a <br/> Separator.
<cfset ErrorsArray = ArrayNew(1)>
<cfset ErrorsArray[1] = "The username is invalid">
<cfset ErrorsArray[2] = "The password is invalid">

<cfset getPlugin("messagebox").setMessage(type="info",messageArray=ErrorsArray)>
  • You can append messages to a currently set or unset message box. If you append to an empty messagebox the default type of information will be used.
<cfset getPlugin("messagebox").append('<br/> My Appended message')>
  • You can append an array of messages to a currently set or unset message box. If you append to an empty messagebox the default type of information will be used.
<cfset getPlugin("messagebox").appendArray(myMessageArray)>

Environment Interceptor

  • Added the ability to override ALL settings found in the configuration settings structure. If you would like to see the entire structure graph, you can dump the actual configuration structure and see the path of all the variables. For example, to override a particular nested setting, I can just say:
<Setting name="CacheSettings.ObjectDefaultTimeout"  value="0" />
<Setting name="Datasources.myAlias.password"  value="" />

Pretty handy! Please also see the Configuration Guide for a full list of the nested structures.

  • Refactored to create a separate function for environment detection, detectEnvironment. You can now extend the interceptor an just override this method and you can have your own detection schemas at your disposal. Below is the method included:
<cffunction name="detectEnvironment" access="private" returntype="string" hint="Detect the running environment and return the name" output="false" >
<!--- *********************************************************************** --->
<cfargument name="environmentsArray" required="true" type="array" hint="The environment array">
<!--- *********************************************************************** --->
<cfscript>
for(i=1; i lte ArrayLen(arguments.environmentsArray); i=i+1){
        if ( listFindNoCase(trim(arguments.environmentsArray[i].XMLAttributes.urls),cgi.http_host) ){
                //Place the ENVIRONMENT on the settings structure.
                setSetting("ENVIRONMENT", trim(arguments.environmentsArray[i].XMLAttributes.name));
                return trim(arguments.environmentsArray[i].XMLAttributes.name);
                break;
        }
}
return "";
</cfscript>
</cffunction>

New Plugin: JSON

A new plugin has been adapted for this release by Ernst Van der Linden and Sana Ullah. This plugin can encode/decode JSON syntax back and from coldfusion variables. It is super speedy and super awesome.

JSON notation for dynamic complex settings

The configuration file allowed for simple notation to create structures: {name:'luis',active:'true'} and arrays: [1,2,3]. However, with the inclusion of the new json plugin, you can now declare full JSON syntax notations on ALL complex variables in the configuration file. So you can inflate queries, nested arrays, structures and so much more. For a full syntax, see http://www.json.org/

*single quotes will be converted to double quotes by the processor, so it validates

<Setting name="myNestedSetting" value="{name:'luis', values:[1,2,3,4]}" />

<Setting name="myQuery" value="{'COLUMNS':['ID','CREATEDATE','ACTIVE'],'DATA':[['E9B6F2D1-B3D6-CB68-BBB327AFEF140A9B','March, 25 2008 23:12:03',0],['E9B6F2E1-E423-5409-C4146A3AA9AE0AF8','March, 25 2008 23:12:03',1],['E9B6F2F1-D076-074D-2292172D696107BA','March, 25 2008 23:12:03',1],['E9B6F300-A28E-0176-6B68C0B63CE65F4B','March, 25 2008 23:12:03',0]]}" />

New Plugin: MethodInjector

This is an advanced plugin to help you inject/remove UDF's and properties from coldfusion components. It also lets you invoke private methods on components. The applications for such a component are for dependency injection, runtime UDF additions or removals, unit testing, ability to call private methods from other contexts, etc. The plugin is available because it is internally used for internal core coldbox operations.

The utility methods that this plugin injects to a CFC are the following:

  • injectMixin(UDF) : To inject a method
  • removeMixin(UDF) : To remove a method
  • invokerMixin( method, [argCollection:struct],[argList:string]) : To invoke a method, no matter what scope it is.
  • injectPropertyMixin(propertyName,propertyValue,scope) : Inject properties to the variables or any scope you want.
  • removePropertyMixin(propertyName,scope) : Remove a property from the specifed scope and name.
//I have a cfc called UserService that I would like to do some injections/removals and call a private method

//Inject our utility methods
getPlugin("methodInjector").start(UserService);

//Let's inject the setController method
UserService.injectMixin( variables.setController );

//Let's set the Coldbox controller on it
UserService.setController( getController() );

//let's remove it now that its injected
UserService.removeMixin( "setController" );

//Now let's call a private method on the service called getTypes()
userTypes = UserService.invokerMixin("getTypes");

//Now another call with some arguments
userRole = UserService.invokerMixin("getDefaultRole",arglist="id='23423'");

//We are done, remove our utility methods
getPlugin("methodInjector").stop( UserService );

New SuperType Methods: htmlhead(), getInterceptor()

  • You can now easily use the cfhtmlhead tag from cfscript by just calling htmlhead(content). This method is available in all plugins, handlers, and interceptors.
htmlhead( myVar );

//or

htmlhead("<script src='includes/myScripts.js'></script>");
  • You can now interact with any loaded interceptors by executing the method: getInterceptor(interceptorclass). This is super useful if you would like to manually fire stages, interact with the interceptors or get data from them.
<cfset var myValidator = getPlugin("ioc").getBean("myValidator")>

<!--- Register a security validator --->
<cfset getInterceptor('colbox.system.interceptors.security').registerValidator( myValidator )>

IOC Plugin Updates

There are several updates to the ioc plugin that are shown below:

  • You can now override the ColdSpring or LightWire factory bean to use by setting the following in your Custom Settings in your configuration file.
    • ColdspringBeanFactory : Instantiation path to the ColdSpring factory.
    • LightWireBeanFactory : Instantiation path to the LightWire factory.
<Setting name="ColdspringBeanFactory" value="frameworks.coldspring1_2.beans.DefaultXMLBeanFactory" />
  • LightWire can be used with only a valid configuration file. Before, you had to declare the location of your base config object in the IOCDefinitionFile setting. This was the instantiation path of your lightwire configuration object. On 2.6 you can let go of that configuration object if you already have a valid coldspring xml file with all your bean declarations. The ioc plugin will detect that you want to use a coldspring xml file and it will create a base config object for you and make it parse this configuration file for you. So interchanging between colspring and lightwire in coldbox becomes even simpler.
<Setting name="IOCFramework" value="lightwire" />
<Setting name="IOCDefinitionFile" value="config/services.xml.cfm" />

This feature really makes life easier for the developer who is used to working with bean configuration files and doesn't want to create a configuration object. ColdBox will create one for you and configure it.

Applicationstorage and sessionstorage plugins updated

These two plugins have been updated in that each of them create a storage bin in their appropriate scopes. This permits the developer to now clear all variables or even get the entire storage scope. This in effect also protects other variables that might be on the scopes that are not in the ColdBox lifecycle. Finally, the code was optimized and they are actually faster!! New methods:

  • clearAll() : Clears the entire storage in the appropriate scope
  • getStorage() : Gets a structure with all the variables you have set in it.

SES: Numeric & Alphanumeric Routes

The SES interceptor has been updated to distinguish between numeric and alphanumeric routes. As of version 2.5.2 the interceptor only searched for alphanumeric routes, now you can do both. To do this, you simply add the following: -numeric to the variable place holder.

/:varname/ sets the varname as an alphanumeric placeholder
/:varname-numeric/ sets the varname as a numeric placeholder

Examples:

//Course 1
addCourse(pattern="blog/entry/:month-numeric/:year-numeric", handler="blog", action="displayEntry");

//Course 2
addCourse(pattern="wiki/:name/page/:page-numeric", handler="wiki",action="show");

The first course will look for a course that starts with blog/entry and then a numeric part and then another numeric part to create two variables: month & year.

The second course will look for a course that starts with wiki/ then a part that is alphanumeric and assign it to name, then page then another part that is a number an assign it to the variable page.

As you can see, with this feature, you can increase your custom routing system.

SES: Optional Variables

The SES interceptor also introduces optional variables for your applications. With this feature, you can declare 1 route and the different permutations will be created for you in the correct ordering. In order to determine that a variable is an optional variable you only need to append a ? at the end of the variable name:

Example:

/blog/:year-numeric/:month?/:day-numeric?

This route tells the interceptor that the month and day place holders are optional. This will then create the following routes in the ses interceptor:

/blog/:year-numeric/:month/:day-numeric
/blog/:year-numeric/:month
/blog/:year-numeric/

What an improvement and great feature. ColdBox now only includes the following route:

/:handler/:action?/:id?

Which will be translated into three distinct routes:

/:handler/:action/:id
/:handler/:action
/:handler

So welcome to SES optional variables.

SES: Loose Matching Directive

You can now configure the interceptor to do loose matching from the incoming url by using the LooseMatching? property.

<Property name="LooseMatching" value="true" />

The default value is false. What this directive does, is that it will try to find the routes ANYWHERE in the incoming url instead of starting from the beginning of the url. This can be useful, when you can have loose matching and your URL ROUTE might be in the middle or the end of an incoming url.

For example, I have a route defined as /test/:id-numeric. If I have loose matching turned OFF and I receive the following url:

/index.cfm/test/1233

The route would match. If the incoming url would be

/index.cfm/blog/test/12333

The route would NOT match. However, if I turn on Loose Matching, then the last url would match, because the route /test/:id-numeric can be found with no specific ordering.

SES: Convention name-value pairs

ColdBox introduces name-value pairs by convention via SES. This means that after a route has been matched and there are still values in the request string, the interceptor will try to create name-value pairs out of them. Example, if we have the following route:

addRoute(':handler/:action')

Then if we have the following url: index.cfm/users/list/page/2/issues/5 Then the interceptor would route it to the event = users.list and nothing more. With convention name-value pairs, the interceptor will try to create name-value pairs from the remaining string, in our case: page/2/issues/5. So the interceptor will create the following variables in the request collection for you, without YOU doing anything:

  • page = 2
  • issues = 5

Is this cool or what, you can easily create more custom routes and even have convention routing, all provided for free.

New Interceptor: Security

This feature can still change its implementation.

You can now add roles, permissions or any criteria based security easily to your applications. The premise of the interceptor is that it will protect incoming events and as it fires on every preProcess execution point. The interceptor validates the incoming event against a set of rules that you define and then if a rule is matched will try to see if the user is authenticated and in a specific criteria. The two available authentication criterias are:

  1. (default) By using cflogin, cfloginuser, cflogout
  2. Security Validation Object that you create and implement.

Features

  • It secures all events in the system as incoming requests try to access them by wrapping the preProcess execution point.
  • Security rules are created and can be stored in the following mediums, where the interceptor can retrieve them from
    • xml (ColdBox standard)
    • database
    • IoC bean
    • ColdBox Cache (You will place the rules here)
  • A rule engine has been built to provide security for multiple events
  • The rules can be configured to use regular expressions
  • Use CF authentication security
  • Use your own Security Validation by creating a security validation object.

Default Security

This interceptor will try to use ColdFusion's cflogin + cfloginuser authentication by default. However, if you are using your own authentication mechanisms you can still use this interceptor by implementing a Security Validator Object (See Below).

Ex:

<cflogin>
        Your login logic here
        <cfloginuser name="name" password="password" roles="ROLES HERE">
</cflogin>

Security Validator Object

A security validator object is a simple cfc that implements the following function:

userValidator(rule:struct,messagebox:coldbox.system.plugins.messagebox) : boolean

This function must return a boolean variable and it must validate a user according to the rule that just ran by testing the fields that get sent in as a rule. Where this method exists is up to you. The method also receives a reference to the messagebox plugin so you can set messages or anything you like for display purposes if the security fails. Below is a real life example:

<!--- User Validator for security --->
<cffunction name="userValidator" access="public" returntype="boolean" output="false" hint="Verifies that the user is in any permission">
        <!--- ************************************************************* --->
        <cfargument name="rule"         required="true" type="struct"   hint="The rule to verify">
        <cfargument name="messagebox" type="coldbox.system.plugins.messagebox" required="true" hint="The ColdBox messagebox plugin. You can use to set a redirection message"/>
        <!--- ************************************************************* --->
        <!--- Local call to get the user object --->
        <cfset var oUser = getUserSession()>
        <cfset var results = false>
        <cfset var thisPermission = "">
                        
        <!--- Authorized Check, if true, then see if user is valid. --->
        <cfif arguments.rule['authorize_check'] and oUser.getisAuthorized()>
                <cfset results = true>
        </cfif>
        
        <!--- Loop Over Permissions --->
        <cfloop list="#arguments.rule['permissions']#" index="thisPermission">
                <cfif oUser.checkPermission( thisPermission ) >
                        <cfset results = true>
                        <cfbreak>
                </cfif>
        </cfloop>
        
        <!--- Messagebox --->
        <cfif not results>
                <cfset arguments.messagebox.setMessage("warning","You are not authorized to view this page.")>
        </cfif> 
        
        <cfreturn results>
</cffunction>

Declaring the Validator

You have three ways to declare the security validator:

1) This validator object can be set as a property in the interceptor declaration (validator=) as an instantiation path. The interceptor will create it, cache it in itself and try to execute it every time.

<Property name="validator">mypath.model.myvalidator</Property>

2) You can register the validator via the registerValidator() method on this interceptor. This must be called from the application start handler or other interceptors as long as it executes before any preProcess execution occurs, else it will fail validation:

<!--- The following is in my application start handler --->
<cfset getInterceptor('coldbox.system.interceptors.security').registerValidator(myValidator)>

That validator object can exists and come from anywhere you want using the mentioned technique above.

3) Use the validatorIOC property, in which the interceptor grabs the validator from the ioc plugin, whether you are using coldspring or lightwire. It is the bean name

<Property name="validatorIOC">myValidator</Property>

Interceptor Properties

  • useRegex So you can decide to use or not regular expressions on pattern matching
  • useRoutes So you can redirect using the SES routes or normal events
  • rulesSource Where to look for the rules as described above, either (xml,db,ioc or ocm)
  • debugMode Logs all activities as events are checked.
  • validator If set, it must be a valid instantiation path to a security validator object.
  • rulesFile The file location of the rules xml
  • rulesDSN The dsn to use if the rules should be taken off the db.
  • rulesTable The table to query for the rules.
  • rulesBean The bean name that will be used to get the rules. This bean name is declared in your ioc container.
  • rulesBeanMethod The method in the bean object to call to get the rules.
  • rulesOCMKey The cache key to use to retrieve the rules from.
Note: If you want to register your own validator instead of the interceptor creating it, please use the registerValidator() method and do not declare the validator property.

Rules

All the security rules follows the following format (However, you can append as much as you like for your own custom validations and the interceptor will register all the columns you pass to it, except from the xml file.):

whitelist varchar A comma delimited list of events or patterns to whitelist or to bypass security on
securelist varchar A comma delimited list of events or patterns to secure
roles varchar A comma delimited list of roles that can access these secure events
permissions varchar A comma delimited list of permissions that can access these secure events
redirect varchar A event or route to redirect if user is not in a role

Sample XML Rules

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- 
Declare as many rule elements as you want, order is important 
Remember that the securelist can contain a list of regular
expression if you want

ex: All events in the user handler
 user\..*
ex: All events
 .*
ex: All events that start with admin
 ^admin

If you are not using regular expression, just write the text
that can be found in an event.
-->
<rules>
    <rule>
        <whitelist>user\.login,user\.logout,^main.*</whitelist>
        <securelist>^user\..*, ^admin</securelist>
        <roles>admin</roles>
        <permissions>read,write</permissions>
        <redirect>user.login</redirect>
    </rule>

    <rule>
        <whitelist></whitelist>
        <securelist>^moderator</securelist>
        <roles>admin,moderator</roles>
        <permissions>read</permissions>
        <redirect>user.login</redirect>
    </rule>
</rules>

Usage

So what can you do with this, really? Well, let's look at some rules using regex, because they are meaner!!

whitelist = ^admin\.(do|dsp)login, ^admin\.logout
securelist = ^admin
roles = admin
redirect = admin.dspLogin

How cool is that, I just secured every single handler that starts with admin, whitelisted any dspLogin,doLogin,logout events. The cool thing is that you can create as many rules as you like.

Unit Testing: MX Unit Integration

A new testing base class has been created to support the MX Unit testing framework. You will find it under coldbox.system.extras.testing.baseMXUnitTest.cfc.

Important: The baseTest.cfc based on CFCUnit has been moved to its own package to allow for the development of more testing classes. You can now find the baseTest.cfc under coldbox.system.extras.testing.baseTest. Please make sure you update your unit tests to reflect this change of location

Cookiestorage Encryption

The cookiestorage plugin has been updated to support encryption on its values. The default is no encryption, but you can activate it by using the following custom settings:

Setting Type Default Value Description
cookiestorage_encryption boolean false Whether to encrypt the values or not
cookiestorage_encryption_seed string (Look in Plugin) The encryption seed to use. Else, use a default one (Not Recommened)
cookiestorage_encryption_algorithm string CFMX_COMPAT & BD_DEFAULT The encryption algorithm to use (According to CFML Engine)

That's it. If you activate encryption, the plugin will take care of encrypting and decrypting values for you.

Renderer Plugin: Render & Cache

Thanks to view caching introduced in 2.5.0 we can now render and cache at the same time. This is the missing piece on rendering and caching views, since before you could only cache views that where set by the event handlers. Now, you can render and cache at the same time.

  • renderView( view, [cache], [cacheTimeout], [cacheLastAccessTimeout] )
  • renderExternalView( view, [cache], [cacheTimeout], [cacheLastAccessTimeout] )
<!--- The following snippet is of a layout file --->
<body>
  <!--- Render the header and cache it for 10 minutes --->
  <div id="header">#renderView(view="tags/header",cache=true,cacheTimeout=10)#</div>

  <div id="body">#renderView()#</div>

  <!--- Render the footer and cache it for 10 minutes --->
  <div id="footer">#renderView(view="tags/footer",cache=true,cacheTimeout=10)#</div>
</body>
Important If view is cached (ex: Footer), then anywhere the footer view will be renderer it will rendered from cache until it expires or you programmatically purge it. So you can share cached views anywhere in your layouts or views.

Also, the render external view method has been updated to automatically append a .cfm extension to the view name.

Flash Persistence Scope: Session or Client

You can now decide where the flash persistence of variables across redirections occurs in. You can choose between:

  • session
  • client

The framework will then switch where it saves it persistence variables. You have a framework-wide setting in the framework's setting.xml but also a setting: FlashURLPersistScope that you can set in your coldbox.xml file to override the framework wide settings.

<Setting name="FlashURLPersistScope" value="session" />

<Setting name="FlashURLPersistScope" value="client" />

This takes effect when you pass in a persistence list form the request collection to the setNextEvent() or setNextRoute() methods. However, there is also a method by itself called persistVariables()

Flash Persistance : on demand

You can now on demand flash variables that are not even in the request collection into the flash RAM. How? well look for an extra parameter called varStruct in the following methods:

  • setNextEvent()
  • setNextRoute()
  • persistVariables()

This argument: varStruct hast to be a structure that contains name-value pairs. You can send that in and the framework will persist the content's for you. You can even use this structure alongside the persist list argument.

Run Private Events

You can now run private events from anywhere inside your framework life cycle! If you want to create private events, just set their access to private. Then use the runEvent method to execute private events by passing the private argument to true. That's it. Let's say I have a handler named users and have a private action called processRoles, then I would do the following to execute it:

<cfset RunEvent(event="users.processRoles",private=true)>

That is all folks. The advantage of using runEvent is that it goes through the full execution life cycle (Executes interceptors, pre/post process events, and times your execution.). The debugger will even tell you when a private event was executed.

Caching Updates

The ColdBox cache has been really optimized and some great new features have been added to it. The cache has been the foundation of the framework and it is even more solid than ever. It was based on fixed limits, but now it has morphed into the memory sensitive space. Below are the major improvements to the current ColdBox cache, more features will be posted at a later date.

JVM Memory Sensitive

The cache now supports java soft references as their basis for non-eternal objects apart from the fixed limits and algorithms of the cache. The best results can now be achieved with a mixed mode cache, where fixed limits are mixed with memory sensitive algorithms. You can cache without worrying that out of memory errors will occur (Again, theoritically!)

JDK 1.5 > Concurrency Classes

If you are using ColdFusion 8, Bluedragon 7 or Railo 2.X, you will get the benefits of using the JDK 1.5 concurrency collections. The cache object pool has been updated to support concurrent hash maps for atomical operations that will provide even more stability under heavy load and faster access times under heavy load.

Create your own Eviction Policies

A basic interface has been created for you to create and implement your own eviction policies if you so desired. ColdBox comes bundled with LFU and LRU eviction policies.

Cache Panel Updates

The cache panel has been udpated with better charting and more descriptive statistics including how much the JVM has garbage collected your cache references. This is a great way for you to know how the cache is performing and how to tweak it under load.

Discard Mechanism Updates

The clearing and expiring of keys has been updated to take advantage of regular expressions and asynchronous operations of CFML engines that support threading. You can now take advantage of the snippet mechanism to clear or expire objects by just using cache key snippets with or without regular expressions.

cfcViewer plugin updated

The cfcviewer plugin has been totally revamped. It is now even easier to document components. All you do is use the plugin and render it. You can override the styles, links, js links, and even the rendering template and create your own. All the tools necessary to document your applications. The API is really easy to use and direct.

A new method has been created in the request context to help you build links whether you are using the routing system or the event system. The context knows if you are running in SES mode, you can also use event.isSES() to help you deal with routing. The method takes in one arguments, the event or route you want to construct the link to.

Arguments

argument type required default description
linkTo string true --- the event + query string combination
translate boolean false true If set to true it will translate any . to / if in SES mode. If false, it will not translate
<cfform action="#event.buildLink('users.create')#">

</cfform>

Request Context Decorator Updates

The request context decorator got a very nice update, it now receives a reference to the ColdBox Controller. You can now call it by using the getController() method. What does this mean to you? Well, you can now call plugins, settings, and everything the controller can call right from your own request context decorator. So now you have even more tools to help you build your very own custom request context objects.

  • instance.controller : New property
  • getController() : New method