Whatterz


Anatomy of the Application.cfc in ColdFusion 8

by Simon. Average Reading Time: about 6 minutes.

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.

This article has been tagged

, , , , , , , , , , , , , , , , , , , , , , , , ,

Other articles I recommend

Application-Based Paths in ColdFusion

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 Law of Demeter

The Law of Demeter (LoD), or Principle of Least Knowledge, is a design guideline for developing software applications, particularly object-oriented programs. The guideline can be succinctly summarised as “Only talk to your immediate friends.” The fundamental notion is that a given object should assume as little as possible about the structure or properties of anything else, including its sub-components.

The Inner Workings of a ColdFusion Array and Structure

Array and Structures are considered to be complex data types in ColdFusion. In contrast, simple data types are ones that contain a single piece of data, such as an Integer, String, or Boolean value. A complex data type can contain multiple pieces of data, which, in the case of arrays, are usually related. All the data are referenced under a single variable name. You can think of a complex variable as a variable that contains a collection of other variables inside it. An array maps Integers to arbitrarily typed objects (Integers, Strings, Booleans and Objects) while a structure, or associative array, maps arbitrarily typed objects to arbitrarily typed objects.

  • Excellent overview! Thank you!

  • Pretty amazing and simple-to-understand article. I’m finding all your articles to be great, Simon, thank you!

  • Sasa

    I dont know why but every time i have variables declared in onApplicationStart i get error for example: “Element STRCONFIG.DATASOURCE is undefined in APPLICATION”.

  • @Sasa – you need to make sure you restart your application for the variables to be correctly loaded into the application scope. You can do this programmatically (look at the onRequestStart method detailed above) or by restarting the ColdFusion service.

  • For more information, check out Application.CFC reference on ColdFusion 8 livedocs:
    http://livedocs.adobe.com/coldfusion/8/htmldocs/AppEvents_01.html

    …and the Method Summary:
    http://livedocs.adobe.com/coldfusion/8/htmldocs/AppEvents_03.html#1190269

  • Larry Buta

    Good explanation of the properties and methods available in Application.cfc and how to use them…am studying for the cf8 certification and this is a good resource…

  • Wow Simon, thanks!
    Q: Should your onError function have a ?

  • <cfabort>?

  • @phillip it really depends upon what you want the onError function to do. If you want it to stop page processing when an error occurs, then a cfabort is fine, otherwise it is perfectly OK to remove it.

  • Jack

    @Simon: I am in a shared hosting environment, probably with sandbox security on, using CF 8 (not 8.0.1 though) and onError method just doesn’t work. Any error generated by the application shows standard CF error page with the following text:

    ” java method security exception.
    A security exception occurred while invoking java method on a “java.lang.Class” object. MethodName is getName. Possible cause: createobject function and cfobject tag are disabled in the security sandbox or you are trying to create a class in the coldfusion package and that is disabled. ”

    It has nothing to do with createObject or cfobject, any error generated even by a simple cfm page shows the same info.

    Trying to dump Arguments scope of the onError function I receive 2-element struct with “exception” key filled with strange “[undefined struct element]”.

    I’d appreciate your opinion, is it some sandbox strange behavior, or just have to change my hosting provider?

  • Frank

    Simon,

    What are the implications of forcing a onApplicationStart() on current threads/processing that may be occurring at the sametime? Will the processing/data be dumped midway?

  • A note about your second OnRequestStart method (with the call to OnApplicationStart) – I get an error when I set a returntype=”void” and then attempt to return true. The error says:

    “Void functions must not return any values. ”

    Not a big deal. Just seems to be a little typo.

  • Lewis Billingsley

    Is AppScope a reserved word? I’m confused. I’ve read about creating a <cfarguement name="appScope" variable for both onSessionEnd and onApplicationEnd (or maybe it was onApplicationStart ). In another place, I saw applicationScope used. And, somewhere I saw my question answered, with something like "it's about positioning." What's up with this?

    Thanks Much,
    Lewis Billingsley

  • Pingback: Migrating from application.cfm to Application.cfc « Bollox and Bytes()