Skin Spider : Moving Application.cfm To ColdFusion MX 7 Application.cfc

Posted October 23, 2006 at 2:24 PM by Ben Nadel

Tags: ColdFusion, Skin Spider

To learn all about Skin Spider, click here.

To view the most updated application, click here.

To view the current code base, click here.

As the first part of Iteration 2, I moved the Application.cfm code over to the newer ColdFusion MX 7 Application.cfc component. The Application.cfc does pretty much the same thing that Application.cfm does, only it gives us more control over the actual system events that can take place:

  • OnApplicationStart()
  • OnSessionStart()
  • OnRequestStart()
  • OnRequest()
  • OnRequestEnd()
  • OnSessionEnd()
  • OnApplicationEnd()
  • OnError()

While I alphabetize most methods in a ColdFusion component, I put these in "execution" order. It helps me think about the page processing is more structured way. And, while ColdFusion offers no true object constructors, anything outside of the method declarations is the component pseudo-constructor and get's called during object instantiation. Notice that in the Application.cfc pseudo constructor, I am defining the application and the general page settings. This replace the CFApplication tag.

Notice that I have left in both the Application.cfm and the Application.cfc templates. This is fine because ColdFusion MX 7 will execute only one. It checks for Application.cfc and executes it if it finds is. If it cannot find it, it then checks for Application.cfm and executes that one. Once we are done, will remove the Application.cfm template, but I am leaving it in for now so that you can see the comparison.

OnApplicationStart() - Application Initialization

I have moved the application initialization code into the OnApplicationStart() method. This method automatically gets called when the ColdFusion application runs for the first time. If all you do is let it run this way, then you never have to worry about race conditions or locking code as this will ONLY be called once. In our application, however, we manually call the OnApplicationStart() method whenever we flag the re-initialization of the application (via URL.reset). When you call the OnApplicationStart() method manually, it runs fine with the exception that it is not thread safe. To handle this, we leave in the double-check locking that we had in place in the Application.cfm file.

OnSessionStart()

Since we are not using any session management in this application, I have commented out this method (but left it in just in case we use it later).

OnRequestStart() - Pre Page Processing

The OnRequestStart() method is our first hook into the pre-page processing of a given page request. This is where I do the file security check and REQUEST scope initialization. As its only argument, this method gets the path of the requested page template. We can use this to determine if there are any security issues and in our case, we are checking for files that start with "_" as being restricted. Notice also that this method returns a boolean. If you choose to return FALSE from this method, it will kill the rest of the page processing for the given page request.

OnRequest() - Executing The Current Page

The OnRequest() method determines which template to actually execute. As its only argument, this method gets the path of the requested page. If you want that template to execute, simply include it. In our case, since we want to the age verification for all index.cfm page requests, we can simply check which template was being requested, and, if it's the index.cfm file then we include the age_verification.cfm instead of index.cfm.

OnRequestEnd() - Post Page Processing

The OnRequestEnd() method gives us a hook into the post-page processing that OnRequestEnd.cfm would have provided. We are not doing anything with it at the moment, but I have left it in for discussion's sake.

OnSessionEnd() - Session Clean Up

The OnSessionEnd() method gets called when a user's session timeouts. This provides us with the ability to clean up a session or perform logging of some sort before we completely lose track of this user. Again, we are not doing any session management so I have commented this code out.

OnApplicationEnd() - Application Shut Down

The OnApplicationEnd() method gets called when the application times out or the server shuts down. It provides us with the ability to clean up data or log any issues. We are not doing anything with it at the moment.

OnError() - Application Error Handling

The OnError() method gets called with any un-caught error that bubbles up through the ColdFusion application. This does not get fired for any errors that are handled via CFTry / CFCatch. It get two arguments passed to it: the error object and the event name. The event name is only available if the error was generated by code in the Application.cfc (to the best of my understanding).

This method is meant to replace the old CFError tag. You will notice that instead of using the CFError tag, I am executing the site_error.cfm template as a custom tag module (via CFModule). I will go more into that in a second, but also take notice that I am not running errors for Abort exceptions. CFLocation fires an Abort error that is not really an error from our stand point (thanks Ray).

Site Error Handling - site_error.cfm

When switching from Application.cfm to Application.cfc the error object that gets generated changes. When using the CFError tag, an object named CFERROR gets created automatically. However, when using the Application.cfc's OnError() method, the error object gets passed in as an argument. To make matters worse, the two error objects do not have the same attributes or the same name. The new one has a bit more information to it.

So, how to cope with the changing specs? I have turned the site_error.cfm template into a custom tag. This way, I can call it from the OnError() method via the CFModule tag and explicitly pass in the values that I want it to use. Then, if you take a look at the site_error.cfm template, you will see that I have defaulted values in the tag's ATTRIBUTES scope. Then, in the page itself, instead of using error values directly, I use only the values passed in as tag attributes. This abstracts out the way the page works and decouples the page from the method of error handling I am using in the system.

I say, decouple, but of course, if I were to move back to using the Application.cfm, I would have to update the code slightly to have an intermediary page get called via CFError which would in turn, call the site_error.cfm custom tag via CFModule.

So now that we have a nice Application.cfc, it's time to start to factor out configuration code. That will be coming soon.



Reader Comments

Oct 23, 2006 at 10:23 PM // reply »
22 Comments

Dude - you rock! Thanks for blogging. I'm learning from you.


Oct 24, 2006 at 7:40 AM // reply »
11,314 Comments

Bruce,

Hey, I love this stuff... just glad you like what I am doing. Thanks!


Ed
Mar 22, 2007 at 2:08 PM // reply »
1 Comments

Good stuff! Clean site design, too. Peace.


Aug 4, 2010 at 4:18 PM // reply »
15 Comments

I have tried and tried with the onApplicationStart() method but it is not clearing the existing application variables. Does anyone know where I might be going wrong?

here is the method i've tried

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

<cfif StructKeyExists(URL,"restartapp")>
<cfset OnApplicationStart()>

</cfif>
<cfreturn true>
</cffunction>


Aug 4, 2010 at 8:17 PM // reply »
1 Comments

Matt, onApplicationStart isn't actually intended to clear the application variables. I thought that at one point too.

TO clear them, at the top of your onApplicationStart function, add:

<cfset structClear(application) />

That will do it for ya. Be aware though, the built in Adobe ColdFusion variable, application.applicationName, will also be cleared. You can fix this by adding the following after the structClear(...):

<cfset application.applicationName = this.name />

That will grab the application name from the Application.cfc component. There is also another way, but it is undocumented so no guarantees it will continue to work:

<cfset application.applicationName = application.getName() />


Aug 5, 2010 at 6:00 AM // reply »
15 Comments

@Greg,

Thank you! it worked! I think I had some other issues also affecting the application but this def. did the job.

Thanks again

Matt


Aug 8, 2010 at 6:36 PM // reply »
11,314 Comments

@Greg,

Thanks for jumping in and helping out @Matt - much appreciated.

@Matt,

Typically, onApplicationStart() can clear out all of your application variables, not by magic, but simply because it resets the value keys. If you are finding that you have code that is not being reset in the onApplicationStart() event handler, you might want to consider configuring that code within the event handler directly.

This actually serves two purposes:

1. We can reset the application more easily (as you are seeing here).

2. It gives you an at-a-glance understanding of how application-level variables are being created and cached. Now, you don't have to scour the rest of your app to see where variables are stored.

Hope some of that helps.


Post A Comment

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.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Jun 20, 2013 at 3:15 AM
A Billion Wicked Thoughts By Ogi Ogas And Sai Gaddam
nice post i love it thanks 4 u :) ... read »
seb
Jun 20, 2013 at 2:32 AM
Working With Inherited Collections In AngularJS
@mike, @ben, The best article about scope and prototypal prototypical inheritance in angularjs is http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical- ... read »
Jun 20, 2013 at 2:17 AM
ColdFusion NumberFormat() Exploration
Nice read thanks Ben, Is there a way to mask a negative number? Long story short in the finance sector when you go 'short' on a stock you want the price to fall this is a good thing because you are ... read »
Jun 20, 2013 at 1:09 AM
The Beauty Of The jQuery Each() Method
my html code : <html> <head> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="nss.js"> ... read »
Jun 19, 2013 at 11:31 PM
Directive Link, $observe, And $watch Functions Execute Inside An AngularJS Context
@Ben, bunch to learn indeed, but thats fun part : ) ... read »
Jun 19, 2013 at 10:41 PM
Referencing ColdFusion Query Columns In A Loop Using Both Array And Dot Notation
Burdock-roots Are you going fat day by day? You need to be good for your family and make some money too. So we bring for you a best product that helps you to be more energetic every day. You will b ... read »
Jun 19, 2013 at 9:52 PM
Working With Inherited Collections In AngularJS
I recognize the applicability of your solution, and how easy it makes to share data across multiple views or even "submodules" of rather simple application. But it seems to me that it creat ... read »
Jun 19, 2013 at 9:38 PM
Directive Link, $observe, And $watch Functions Execute Inside An AngularJS Context
@Alesei, Glad you like it. Even after working with AngularJS for months, I still get a bunch of unexpected, "$digest is already in progress". So hard to debug sometimes! ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools