This morning, as I was starting to learn more about ColdFusion 9's new Object-Relational Mapping (ORM) functionality, I came across a new system function: ApplicationStop(). In the context of ORM, you can call ApplicationStop() to reset the application such that all of the ORM configuration files and settings will be rebuilt. Since these files are only built when the application starts up, ApplicationStop() gives you the ability to "force quit" an application such that the next page request will restart the application and therefore rebuild all of the ORM configuration files. While this makes less sense in production, I can see that having the ability to flush ORM settings as you make changes to your database and your model during development (much like the RefreshWSDL attribute in the CFInvoke tag), will be quite awesome.
This same functionality - the rebuild of the ORM / Hibernate configuration and mappings - can also be accomplished using the ORMReload() method. So this got me thinking: if this can be done in two different ways, then maybe ApplicationStop() has a wider benefit? I wanted to get a better sense of what was going on when this method, ApplicationStop(), was called, so I set up a really simple application to test application and session persistence.
To me, sessions are very tightly coupled to the application under which they exist. As such, the test application needed to have session management turned on:
<cfcomponent output="false" hint="I define the application settings and event handlers."> <!--- Define the application settings. ---> <cfset this.name = hash( getCurrentTemplatePath() ) /> <cfset this.applicationTimeout = createTimeSpan( 0, 0, 5, 0 ) /> <cfset this.sessionManagement = true /> <cfset this.sessionTimeout = createTimeSpan( 0, 0, 3, 0 ) /> <!--- Define the request settings. ---> <cfsetting showdebugoutput="false" /> <cffunction name="onApplicationStart" access="public" returntype="boolean" output="false" hint="I initialize the application."> <!--- Initialize the application settings. ---> <cfset application.dateInitialized = now() /> <!--- Return true so that the page can load. ---> <cfreturn true /> </cffunction> <cffunction name="onSessionStart" access="public" returntype="void" output="false" hint="I initialize the session."> <!--- Initialize the session settings. ---> <cfset session.dateInitialized = now() /> <!--- Return out. ---> <cfreturn /> </cffunction> </cfcomponent>
As you can see in this code, our Application.cfc only has two methods, OnApplicationStart() and OnSessionStart(). Each of these methods creates one scoped variable to mark the time at which the scope was initialized. We will be using these time stamps in the next page, index.cfm, to output the relative age of each scope (Application and Session):
<!--- Param a variable in the application. We are doing this outside of the OnApplicationStart() method to test whether or not the application was truly killed of if the above method was simply called. ---> <cfparam name="application.hitCount" type="numeric" default="0" /> <!--- Increment the hit count. ---> <cfset application.hitCount++ /> <cfoutput> <h1> Application And Session Overview </h1> <p> Application hit count: #application.hitCount# </p> <p> Application initialized: #dateDiff( "s", application.dateInitialized, now() )# seconds ago. </p> <p> Session initialized: #dateDiff( "s", session.dateInitialized, now() )# seconds ago. </p> <p> <a href="reset.cfm">Reset application</a> » </p> </cfoutput>
As you can see in this code, we are outputting the age of both the Application and the Session scopes based on their DateInitialized time stamp. We are also defining and incrementing a new Application variable to record the hit count to this page. I am using this hitCount variable to see if the Application is truly reset, or if the OnApplicationStart() method is simply called again. If the application was not truly reset, then this extra-method variable assignment would not be reset.
At the bottom of the page we are providing a link to reset the application. Normally, this kind of link would end up triggering code within the Application.cfc that might look like this:
<!--- Check to see if reset flag exists in URL. ---> <cfif structKeyExists( url, "reset" )> <cfset this.onApplicationStart() /> </cfif>
Here, we are manually calling the application initialization function from within the Application.cfc itself (usually from within the OnRequestStart() event handler). But, using this new ColdFusion 9 method, ApplicationStop(), we are doing this implicitly:
<!--- Stop the application. After calling this method, the next page request to the application should start it up again (resetting it). ---> <cfset applicationStop() /> <!--- Redirect back to overview. ---> <cflocation url="index.cfm" addtoken="false" />
As you can see, this code just stops the application and then redirects the user back to the overview page. At this point, the application has stopped and the next page request (precipitated by the CFLocation tag) should restart the application.
When I refresh the overview page a few times, I get this output:
Application And Session Overview
Application hit count: 5
Application initialized: 41 seconds ago.
Session initialized: 41 seconds ago.
Then, when I click on the "Reset application" link, I end up back on the overview page with the following output:
Application And Session Overview
Application hit count: 1
Application initialized: 3 seconds ago.
Session initialized: 91 seconds ago.
As you can see, the entire Application scope was wiped out and the OnApplicationStart() method in the Application.cfc must have executed to reset the DateInitialized property. But, the Session scope was not changed at all! Whether or not this was done on purpose, I think that this is a bug in the ColdFusion 9 application architecture. I strongly believe that when an application stops, all of the sessions within it should stop as well. Remember, these are not two completely independent entities - the Application might contain references or aggregates of the Session data. If the Application resets and the Sessions continue to live on, unaltered, then potentially troublesome discrepancies could form between the two memory pools.
When I saw that ColdFusion 9 provided two ways to flush the ORM / Hibernate configuration and mappings, I thought that maybe one of these methods - using ApplicationStop() - might have additional benefits in terms of allowing us to restart applications (something that has before only been available via hacks). After some testing, it seems that ApplicationStop() allows us to reset an Application, but only partially, leaving the Session scopes untouched.
Want to use code from this post? Check out the license.