Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at CFUNITED 2010 (Landsdown, VA) with:

ColdFusion Application.cfc Properties Get Normalized In Interesting Ways

By Ben Nadel on
Tags: ColdFusion

As I was working on my Scotch on the Rocks (SOTR) presentation this weekend, I noticed something that I don't think I have ever noticed before: the properties that you define in the Application.cfc pseudo-constructor change once they are made available in the application event handlers. When I look back on my blog, I can see that this change was apparent in my post on accessing ColdFusion application settings; but, even at that time, I don't think I was fully aware of what was actually happening.

The change in Application.cfc component properties takes place in two ways: 1) the Application.cfc property set is fleshed out to contain all of the possible application settings, using the default values for any appended properties. And 2) the timeouts defined in terms of days (createTimeSpan()) get translated into the number of seconds. To see this in action, let's take a look at the following Application.cfc:

Application.cfc

  • <cfcomponent
  • output="false"
  • hint="I define application settings and event handlers.">
  •  
  • <!---
  • Define application settings - not that the timeouts are
  • defined using createTimeSpan() which will give us decimal-
  • representations of days.
  • --->
  • <cfset this.name = hash( getCurrentTemplatePath() ) />
  • <cfset this.applicationTimeout = createTimeSpan( 0, 0, 2, 0 ) />
  • <cfset this.sessionManagement = true />
  • <cfset this.sessionTimeout = createTimeSpan( 0, 0, 1, 0 ) />
  •  
  • <!--- Store a copy of the THIS scope for later comparison. --->
  • <cfset this.copy = {
  • name = this.name,
  • applicationTimeout = this.applicationTimeout,
  • sessionManagement = this.sessionManagement,
  • sessionTimeout = this.sessionTimeout
  • } />
  •  
  •  
  • <cffunction
  • name="onRequest"
  • access="public"
  • returntype="void"
  • output="true"
  • hint="I process the requested script.">
  •  
  • <!--- Include the script name. --->
  • <cfinclude template="#arguments[ 1 ]#" />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  • </cfcomponent>

As you can see, I am setting the application settings in the Application.cfc pseudo-constructor. But, after I do that, I create a copy of the settings in a separate property, copy, for later output and comparison. Then, in the onRequest() event handler, I include the requested script so as to make the Application.cfc THIS scope available to the mixin. In my demo, the mixin and requested script was this page:

  • <!---
  • Because this template was included via the onRequest()
  • application event handler, it will have access to the
  • THIS properties as defined in the Application.cfc pseudo
  • constructor.
  • --->
  • <cfdump
  • var="#structCopy( this )#"
  • label="THIS :: Event Handler"
  • showudfs="false"
  • hide="copy"
  • />
  •  
  • <br />
  •  
  • <!---
  • In the psuedo constructor, we copied the values out of the
  • this in a deep-copy way. As such, these should be separate,
  • but same.
  • --->
  • <cfdump
  • var="#this.copy#"
  • label="THIS :: Pseudo-Constructor"
  • />

As you can see, I am simply outputting the THIS-based properties and the "copy" properties to see how they compare. I am using structCopy() here so that I can use CFDump's "hide" attribute (which ColdFusion components appear to ignore). When we run the above test page, we get the following CFDump output:

 
 
 
 
 
 
The ColdFusion Framework Normalizes The Way In Which Settings Appear In The Application.cfc Event Handlers. 
 
 
 

As you can see, the factional-day timeouts defined in the pseudo-constructor get translated to a number-of-seconds by the time our Application.cfc event handlers are executed.

Now, call me crazy, but I am pretty sure that I remember using seconds to define timeouts way back in the day before I discovered the createTimeSpan() function. And, I am pretty sure that I don't ever remember running into this kind of problem (ie. that 3600 seconds wasn't suddenly misunderstood as 3600 days). To re-visit this concept, I tried setting the timeouts using integers rather than the createTimeSpan() function:

Application.cfc (Timeouts as Integers)

  • <cfcomponent
  • output="false"
  • hint="I define application settings and event handlers.">
  •  
  • <!---
  • Define application settings - note that the timeouts are
  • defined using a number of seconds.
  • --->
  • <cfset this.name = hash( getCurrentTemplatePath() ) />
  • <cfset this.applicationTimeout = 120 />
  • <cfset this.sessionManagement = true />
  • <cfset this.sessionTimeout = 60 />
  •  
  • <!--- Store a copy of the THIS scope for later comparison. --->
  • <cfset this.copy = {
  • name = this.name,
  • applicationTimeout = this.applicationTimeout,
  • sessionManagement = this.sessionManagement,
  • sessionTimeout = this.sessionTimeout
  • } />
  •  
  •  
  • <cffunction
  • name="onRequest"
  • access="public"
  • returntype="void"
  • output="true"
  • hint="I process the requested script.">
  •  
  • <!--- Include the script name. --->
  • <cfinclude template="#arguments[ 1 ]#" />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  • </cfcomponent>

As you can see, this time both the application and session timeouts are defined in seconds (supposedly). Running the above request with the new Application.cfc properties, I get the following page output:

 
 
 
 
 
 
The ColdFusion Framework Normalizes The Way In Which Settings Appear In The Application.cfc Event Handlers. 
 
 
 

Ok, this is what I remember from back in the day - using seconds as timeouts work just fine.

But, after I ran this test, I remembered an old post from three years ago where I discovered that createTimeSpan() returns a Double data type. At the time, however, I don't think I really understood what I had stumbled across. I thought I was getting an error; but, what I think now was actually happening was that ColdFusion was using the data type to dictate how it made use the given value. To test this, I am going to create an Application.cfc that uses both the createTimeSpan() method as well as double-casted values:

Application.cfc (Timeouts Using CreateTimeSpan() and JavaCast())

  • <cfcomponent
  • output="false"
  • hint="I define application settings and event handlers.">
  •  
  • <!---
  • Define application settings - note that the timeouts are
  • defined using a both a createTimeSpan() method as well as a
  • javaCast()ed double value.
  • --->
  • <cfset this.name = hash( getCurrentTemplatePath() ) />
  • <cfset this.applicationTimeout = createTimeSpan( 0, 0, 2, 0 ) />
  • <cfset this.sessionManagement = true />
  • <cfset this.sessionTimeout = javaCast( "double", 60 ) />
  •  
  • <!--- Store a copy of the THIS scope for later comparison. --->
  • <cfset this.copy = {
  • name = this.name,
  • applicationTimeout = this.applicationTimeout,
  • sessionManagement = this.sessionManagement,
  • sessionTimeout = this.sessionTimeout
  • } />
  •  
  •  
  • <cffunction
  • name="onRequest"
  • access="public"
  • returntype="void"
  • output="true"
  • hint="I process the requested script.">
  •  
  • <!--- Include the script name. --->
  • <cfinclude template="#arguments[ 1 ]#" />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  • </cfcomponent>

With this new Application.cfc in place, I re-ran the test page and got the following page output:

 
 
 
 
 
 
The ColdFusion Framework Normalizes The Way In Which Settings Appear In The Application.cfc Event Handlers. 
 
 
 

Now, we really see what's going on here. ColdFusion is assuming that any double value is a day-span where as any non-double value is a second-span.

On one hand, I understand why ColdFusion is doing this; but, on the other hand, I think this kind of inference can be very confusing in a typeless language. Of course, as we are in a typeless language, we are only running into this issue when we try to force the language to be explicitly typed (ie. calling JavaCast()). As such, perhaps this is a non-concern. In any case, I think it's important to understand how the ColdFusion framework operates, especially for me as I am giving a presentation on it!




Reader Comments

Interesting... I guess most of us follow methods we saw once in some blog post or book long time ago, never wondering "Why do I put that exactly?!"...

Reply to this Comment

Another interestingly potential argument as to why forcing a "typeless" language to strictly type is potentially a bad idea. I'm all for strong typing, but like you said so well yourself, "...it's important to understand how the ColdFusion framework operates".

Cool post Ben.

Reply to this Comment

Somehow I think this post will come in handy at the most frustrating of times (as in to explain why something behaves oddly). Thanks, Ben!

Reply to this Comment

@Zarko,

I guess in most cases stuff just works :) Only the rare cases when things blow up that it becomes critical to understand.

@Adam,

I feel like this must be a backwards-compatibility issue. Even in the livedocs, it tells you to use createTimeSpan() (even as far back as v7 - previous livedocs links no longer work). Nowhere does it say that you *can* use seconds to set these values.

I think pre-Application.cfc, maybe it was seconds and they are using the datatype to make it more backwards compatible. That is the only thing I can think of.

@Randall,

Ha ha, well then I'll see in the future :)

Reply to this Comment

We're still running on CFMX6.1. The documentation for the 'cfapplication' tag describes the 'applicationTimeout' attribute as follows:

Lifespan of application variables. CreateTimeSpan
function and values in days, hours, minutes, and
seconds, separated by commas.

We would need to have a look at the code of the CF runtime to see whether the interpretation of the value specified is based on the type of the value...

Reply to this Comment

@Wouter,

I was trying to look up the MX6 documentation, but I could only find the MX7 version on Adobe Livedocs. I found a v6 link, but it was dead (silly Adobe). Looks like it has always been best practice to use createTimeSpan(). I wonder where I got all this second-based mumbo-jumbo from. I could swear I used that at some point (although maybe I am thinking of CFSetting/requesttimeout.

Reply to this Comment

Andrew Scott's comment kept getting flagged as spam:

I am not sure what you are trying to promote here, or even point out.

Are you saying that using the timespan is wrong in what it is setting or that when you use it as an integer is wrong?

Curious because the docs clearly spell out that the lifespan is real number of days, so if it is a percentage as what createTimeSpan offers would be correct.

Sorry just looking for a bit more clarification on the actual problem.

Good question - 99% of the time, you won't have to care about this difference. The only time you need to know about this is when you, for some reason, need to compare the current session / application timeout. For example, if you were to use this technique:

http://www.bennadel.com/blog/1686-Accessing-ColdFusion-Application-Settings.htm

... where you re-create the Application.cfc later in the request, you have to be conscious that the timeouts in the local Application.cfc instance are going to be in terms for fractional-days, NOT seconds.

So, let's say you are in the onRequest() event handler, because you are in the Application.cfc, you will have access to the THIS scope. In such a case, the following values will not be equal:

this.applicationTimeout
createObject( "component", "Application" ).applicationTimeout

The former would be in terms of seconds and the latter would be in terms of fractional-days.

That's the only case when you really ever need to care.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.