With the release of ColdFusion MX 7 came the introduction of the Application.cfc ColdFusion component. This component replaced the traditional Application.cfm and OnRequestEnd.cfm ColdFusion application templates. Furthermore, if Application.cfc is present, both of these templates are ignored by the application.

In addition to replacing the Application.cfm, the Application.cfc introduced a number of built in methods that handle specific events. These events, as discussed in detail below, allow for a greater control over events within the application.

Application Variables

The THIS scope in the Application.cfc contains several built-in variables that allow you to set the properties of the application.

The following cfscript briefly outlines the variables that you can set to control the application’s behaviour.

<cfscript>
//the application name (should be unique)
THIS.name = "ApplicationName";
//how long the application variables persist
THIS.applicationTimeout = createTimeSpan(0,2,0,0);
//define whether client variables are enabled
THIS.clientManagement = false;
//where should we store them, if enabled?
THIS.clientStorage = "registry"; //cookie||registry||datasource
//define where cflogin information should persist
THIS.loginStorage = "session"; //cookie||session
//define whether session variables are enabled
THIS.sessionManagement = true;
//how long the session variables persist?
THIS.sessionTimeout = createTimeSpan(0,0,20,0);
//define whether to set cookies on the browser?
THIS.setClientCookies = true;
//should cookies be domain specific
//i.e. *.domain.com or www.domain.com
THIS.setDomainCookies = false;
//should we try to block cross-site scripting?
THIS.scriptProtect = false;
//should we secure our JSON calls?
THIS.secureJSON = false;
//use a prefix in front of JSON strings?
THIS.secureJSONPrefix = "";
//used to help ColdFusion work with missing files
//and directory indexes. tells ColdFusion not to call
//onMissingTemplate method.
THIS.welcomeFileList = "";
//define custom coldfusion mappings.
//Keys are mapping names, values are full paths
THIS.mappings = structNew();
//define a list of custom tag paths.
THIS.customTagPaths = "";
</cfscript>

Method Summary

Below is a brief discussion of the built-in event methods available to the Application.cfc. Since the Application.cfc is a regular ColdFusion component, you can also implement your own methods alongside the built in ones (assuming the names are uniquely different).

The onApplicationStart Method

Runs when the application first starts up: when the first request for a page is processed or the first CFC method is invoked by an event.

<cffunction name="onApplicationStart" returnType="boolean" output="false">
	<cfreturn true />
</cffunction>

This method is typically used to initialise code; for example to to set variables, such as datasource, into the APPLICATION scope, or create Singleton instances of ColdFusion components.

For example:

The following example creates structures in tha application scope to store general configuration settings and Singleton objects that can be later referenced by the application framework.

<cffunction name="onApplicationStart" returnType="boolean" output="false">
	<cfscript>
	// INITIALISE CONFIGURATION VARIABLES AND APPLICATION BUSINESS COMPONENTS
	// **********************************************************************
	// LOAD COMMON SITE VARIABLES INTO APPLICATION SCOPE
	// create structure to hold configuration settings
	APPLICATION.strConfig = structNew();
	//site-wide datasource(s)
	APPLICATION.strConfig.datasource = "DatasourceName";
	// default records per page for pagination
	APPLICATION.strConfig.recordsPerPage = 15;
	// **********************************************************************
	// LOAD PERSISTENT OBJECTS INTO APPLICATION SCOPE
	// data for object instantiation
	strArgs	= structNew(); // flush strArgs
	strArgs.datasource = APPLICATION.strConfig.datasource;
 
	// create structure to hold objects
	APPLICATION.strObjs = structNew();
	APPLICATION.strObjs.objUserManager = createObject("component","com.whatley.user.UserManager").init(argumentCollection=strArgs);
	//etc...
 
	// instantiate utility service objects
	APPLICATION.strObjs.objEmailServices = createObject("component","com.whatley.service.Email");
	APPLICATION.strObjs.objFileServices = createObject("component","com.whatley.service.File");
	APPLICATION.strObjs.objQueryServices = createObject("component","com.whatley.service.Query");
	//etc...
 
	// native coldfusion objects
	APPLICATION.strObjs.objServiceFactory = createObject("java","coldfusion.server.ServiceFactory");
 
	// **********************************************************************
	return true;
	</cfscript>
</cffunction>

Since the objects above are created as Singletons, we do not have to create or destroy objects throughout the application, but simply reference the object held in memory. This is efficient, but of course, would not be suitable for per-session objects, such as shopping carts.

For example:

Referencing and invoking an object from the APPLICATION scope:

<cfinvoke object="APPLICATION.strObjs.objUserManager" method="getUser" returnvariable="qryGetUser">
	<cfargument name="userId" value="#SESSION.strUser.userId#" />
</cfinvoke>

The onApplicationEnd Method

Runs when the application stops: when the application times out or the service is stopped.

<cffunction name="onApplicationEnd" returnType="void" output="false">
	<cfargument name="applicationScope" required="true" />
</cffunction>

This method is typically used to clean-up currently activities, save the current state of the application to a database or log the application’s end to a file. The latter can be useful to help determine when and why an application ended.

Below is a simple example of how you could implement a simple log:

<cffunction name="onApplicationEnd" returnType="void" output="false">
	<cfargument name="applicationScope" required="true" />
        <cflog file="#THIS.Name#" type="Information"
        	text="Application #ARGUMENTS.applicationScope.applicationName# Ended" />
</cffunction>

Notes:

  • The method is not associated with an individual request so you cannot use it to display data to a user.
  • If you call this method explicity, ColdFusion does not end the application, but does execute the code within the method.
  • The method can access the SERVER scope directly, but does not have access to the SESSION and REQUEST scopes.

The onMissingTemplate Method

Triggered when the user requests a ColdFusion template that doesn’t exist.

<cffunction name="onMissingTemplate" returnType="boolean" output="false">
	<cfargument name="targetpage" required="true" type="string" />
	<cfreturn true />
</cffunction>

ColdFusion invokes this method when it encounters a file not found condition, that is, when a URL specifies a CFML page that does not exist. This is an important addition to ColdFusion 8 and allows missing template errors (also known as HTTP 404 errors) to be captured more efficiently by the application framework.

The onRequestStart Method

Runs before the request is processed.

<cffunction name="onRequestStart" returnType="boolean" output="false">
	<cfargument name="thePage" type="string" required="true" />
	<cfreturn true />
</cffunction>

This method is great for user authorisation and login handling and for request specific variable initialisation. For example, you could use this method to log statistics to a database (performance and usage).

As this method runs at the beginning of a request, we can also use it to fire other events. In the example below, I reinitialise the Application which enables me to refresh objects held in memory that may have changed during code development or release.

<cffunction name="onRequestStart" returnType="void" output="false">
	<cfscript>
	//flush the application scope
	if ((CGI.server_name == "localhost") || (structKeyExists(URL,'refresh') && structKeyExists(URL,'password') && URL.password == "p455w0rd"))
	{
		onApplicationStart();
	}
	return true;
	</cfscript>
</cffunction>

The onRequest Method

Runs before the request is processed, but after onRequestStart.

<cffunction name="onRequest" returnType="void">
	<cfargument name="thePage" type="string" required="true" />
	<cfinclude template="#ARGUMENTS.thePage#" />
</cffunction>

This event handler provides an optional request filter mechanism for ColdFusion page requests. Use it to intercept requests to target pages and override the default behavior of running the requested pages. You can use this method to do preprocessing that is required for all requests. Typical uses include filtering and modifying request page contents (such as removing extraneous white space), or creating a switching mechanism that determines the exact page to display based on available parameters.

The onRequestEnd Method

Runs at the end of the request when all pages have been processed.

<!--- Runs at end of request --->
<cffunction name="onRequestEnd" returnType="void" output="false">
	<cfargument name="thePage" type="string" required="true" />
</cffunction>

This method can be useful for gathering performance metrics, or for displaying dynamic footer information (although I wouldn’t generally put display code in an Application.cfc).

For example:

Log the CGI variables to a database table.

<cffunction name="onRequestEnd" returnType="void" output="false">
	<cfset var qryInsertStats = queryNew('tempCol')>
	<cfquery name="qryInsertStats" datasource="#APPLICATION.strConfig.datasource#">
	INSERT INTO tbl_site_stats (template,query_string,referer,user_agent,remote_addr,datetime)
	VALUES
	(
		<cfqueryparam value="#CGI.PATH_INFO#" cfsqltype="cf_sql_varchar" />
		<cfqueryparam value="#CGI.QUERY_STRING#" cfsqltype="cf_sql_varchar" />
		<cfqueryparam value="#CGI.HTTP_REFERER#" cfsqltype="cf_sql_varchar" />
		<cfqueryparam value="#CGI.HTTP_USER_AGENT#" cfsqltype="cf_sql_varchar" />
		<cfqueryparam value="#CGI.REMOTE_ADDR#" cfsqltype="cf_sql_varchar" />
		<cfqueryparam value="#now()#" cfsqltype="cf_sql_datetime" />
	)
	</cfquery>
</cffunction>

The onError Method

Triggered when an error is encountered that is not caught by a try/catch block.

<!--- Runs on error --->
<cffunction name="onError" returnType="void" output="false">
	<cfargument name="exception" required="true" />
	<cfargument name="eventname" type="string" required="true" />
	<cfdump var="#ARGUMENTS#" />
        <cfabort />
</cffunction>

This method is used to handle errors in an application-specific manner. This method overrides any error handlers that you set in the ColdFusion Administrator or in cferror tags. It does not override try/catch blocks.

For example:

The following displays a friendly, static error page to the user if it is not a development server whilst also logging the error. If the error is on development, simply dump the error to screen for debugging.

<cffunction name="onError" returnType="void" output="true">
	<cfargument name="exception" required="true" />
	<cfargument name="eventName" type="string" required="true" />
	<cfif CGI.server_name neq "localhost" and CGI.server_name neq "127.0.0.1">
		<!--- Live application, handle error --->
		<cfinclude template="error/error.htm">
		<!--- Log all errors. --->
	        <cflog file="#THIS.Name#" type="error"
	            text="Event Name: #ARGUMENTS.Eventname#" >
	        <cflog file="#THIS.Name#" type="error"
	            text="Message: #ARGUMENTS.Exception.message#">
	        <cflog file="#THIS.Name#" type="error"
	            text="Root Cause Message: #ARGUMENTS.Exception.rootcause.message#">
	<cfelse>
		<!--- dump error for Staging and Development --->
		<cfif len(ARGUMENTS.eventName)>
			<cfdump var="#ARGUMENTS.eventName#" />
		</cfif>
		<cfdump var="#ARGUMENTS.exception#" />
	</cfif>
</cffunction>

The onSessionStart Method

Runs when your session starts.

<cffunction name="onSessionStart" returnType="void" output="false">
</cffunction>

This method is used for initialising SESSION-scoped data, such as a shopping basket and application form.

For example:

<cffunction name="onSessionStart" returnType="void" output="false">
	<cfscript>
	SESSION.start = now();
	SESSION.strShoppingBasket = structNew();
	SESSION.strShoppingBasket.items = 0;
	</cfscript>
</cffunction>

The onSessionEnd Method

Runs when session ends

<cffunction name="onSessionEnd" returnType="void" output="false">
	<cfargument name="sessionScope" type="struct" required="true" />
	<cfargument name="appScope" type="struct" required="false" />
</cffunction>

Use this method for any clean-up activities when the session ends. A session ends when the session is inactive for the session time-out period. You can, for example, save session-related data, such as shopping basket contents or whether the user has not completed an order, in a database, or do any other required processing based on the user’s status. You might also want to log the end of the session, or other session related information, to a file for diagnostic use.

Adobe Livedocs has a whole section dedicated to the Application.cfc.

I have created an example Application.cfc, which is available for download.

The THIS scope in the Application.cfc contains several built-in variables that allow you to set the properties of the application; the name, session management etc. With the release ColdFusion 8 comes the introduction of application-based pathing in the form of the THIS.mappings and THIS.customTagPaths variables.

The THIS.mappings variable can specify a structure that contains ColdFusion mappings. These settings take precedence over the mappings defined by ColdFusion Administrator Server Settings > Mappings page for the current application. Each structure element consists of the logical path as the key and the absolute path as the value. To use this variable, you must set the Enable Per Application Settings option on the ColdFusion Administrator Server Settings > Settings page.

For example:

<cfset THIS.mappings['/com'] = "C:\Inetpub\com" />

This is syntactically equivalent to using the structInsert() function:

<cfset structInsert(THIS.mappings, '/com', 'C:\Inetpub\com') />

The THIS.customTagPaths variable can specify a list that contains ColdFusion custom tag paths. These settings take precedence over the custom tag paths defined by the ColdFusion Administrator Server Settings > Mappings page for the current application. To use this variable, you must set the Enable Per Application Settings option on the ColdFusion Administrator Server Settings > Settings page.

For example:

<cfset THIS.customTagPaths = "C:\Inetpub\wwwroot\myAppOne\customTags" />

Since we can specify a list, this is also valid:

<cfset THIS.customTagPaths = "C:\Inetpub\wwwroot\myAppOne\customTags,C:\Inetpub\wwwroot\myAppTwo\customTags" />

Alternatively, we could represent the list as:

<cfset THIS.customTagPaths = "C:\Inetpub\wwwroot\myAppOne\customTags" />
<cfset THIS.customTagPaths = listAppend(THIS.customTagPaths, "C:\Inetpub\wwwroot\myAppTwo\customTags" />

For a long time, ColdFusion developers have needed the ability to define application-level settings actually in the application itself. These two new application-based pathing variables bring the ColdFusion developer a step closer to being able to produce out-of-the-box applications that can install in shared environments with little fuss and, more importantly, without the need to access the ColdFusion Adminsitrator to create the necessary mappings and custom tag paths.