After Mark Mandel kindly pointed out the ApplicationStop() function that’s available in CF9, I thought my previous post, on flagging an application to fire onApplicationStart, needed a follow up.
This is a new addition to CF9. The documentation for it isn’t very clear as it states it will:
Stops or resets the current application. The application is restarted on the next request to the application.
Is that supposed to be “Stops and resets”? I’m guessing so as it’s a little confusing otherwise.
The function appears to destroy the application scope completely, as soon as the request has finished being processed. The next request that hits that application will start a completely new application scope, firing the “onApplicationStart()” event in the process.
If you continue reading, you’ll see it in action below.
What about CF7 and CF8?
Well they don’t have that function, it was new to CF9. But, why don’t we make our own? Doing my usual dig around I uncovered a function called “cleanUp” that belongs to the “ApplicationScopeTracker” which appears to manage all the application scopes that are active.
Here’s a dump of the “ApplicationScopeTracker”:
<cfdump var="#CreateObject('java', 'coldfusion.runtime.ApplicationScopeTracker')#" />
As you can see, we need to pass it the current application scope so it can work it’s magic.
<cfset CreateObject('java', 'coldfusion.runtime.ApplicationScopeTracker').cleanUp(application) />
It’s as simple as that. All you need to do is wrap it up in a function and you’ve backported “applicationStop()” to CF7 and CF8.
<cffunction name="ApplicationStop" returntype="boolean" output="false"> <cfif IsDefined('application')> <cftry> <!--- This is just in case there's no app scope but variables.application ---> <cfset CreateObject('java', 'coldfusion.runtime.ApplicationScopeTracker').cleanUp(application) /> <cfreturn true /> <cfcatch type="any"></cfcatch> </cftry> </cfif> <cfreturn false /> </cffunction>
ApplicationRestart() for CF7 – CF9
With stopping an application taken care of, what about restarting one. Well we covered that in part 1 of this post, we have a way of not destroying the application scope and firing onApplicationStart again. This is very useful if you have a large set of application variables that you don’t really want to repopulate, but still have some tasks in the “onApplicationStart” that you want executed. A good idea for this approach is, within the onApplicationStart, add an if that checks for an application variable. If it’s present, you know the application has been restarted and all the data is currently there, if not then it’s a fresh start.
Let’s wrap up the code from part 1 of this post into a function called ApplicationRestart().
<cffunction name="ApplicationRestart" returntype="boolean" output="false"> <cfif IsDefined('application')> <cftry> <!--- This is just in case there's no app scope but variables.application ---> <cfset application.setIsInited(false) /> <cfreturn true /> <cfcatch type="any"></cfcatch> </cftry> </cfif> <cfthrow message="No application scope found." /> </cffunction>
Putting them together
Now we can construct a little application that has a simple onApplicationStart which counts how many times the application has been restarted (not stopped). Then add a template with three links: Restart Application, Stop Application and a normal request.
<cfcomponent output="false"> <cfscript> this.name = 'TestApp'; this.applicationTimeout = createTimeSpan(0, 1, 0, 0); </cfscript> <!--- Run when application starts up ---> <cffunction name="onApplicationStart" returnType="boolean" output="false"> <cfset application.stamp = Now() /> <cfif Not StructKeyExists(application, 'inits')> <cfset application.inits = 0 /> </cfif> <cfset application.inits = application.inits + 1 /> <cfreturn true> </cffunction> </cfcomponent>
<cfif ListFind('7,8', ListFirst(server.coldfusion.productVersion))> <cfinclude template="applicationStop.cfm" /> </cfif> <cfinclude template="applicationRestart.cfm" /> <cfif StructKeyExists(url, 'restart')> <cfset applicationRestart() /> <cfelseif StructKeyExists(url, 'stop')> <cfset applicationStop() /> </cfif> <cfoutput>Application IsInited? #application.isInited()#</cfoutput> <cfdump var="#application#" /> <ul> <li><a href="index.cfm?restart=true">ApplicationRestart()</a></li> <li><a href="index.cfm?stop=true">ApplicationStop()</a></li> <li><a href="index.cfm">Normal refresh.</a></li> </ul>
One quick note. CF doesn’t like you overwriting existing functions, even if you wrap an if statement around it’s creation. Hence the reason for the CFIncludes, otherwise if you’re on CF7/8 you can bring those functions in or store them in the same template.
Now, when you click the restart link followed by a normal request, you’ll see the application.inits value increase and the application.stamp value refresh. Clicking the stop link, followed by the normal request link, will clear the application completely. This will reset the init count and the date stamp.
Video exampleVodpod videos no longer available.
Currently I haven’t found a way to replicate this in Railo and the ApplicationStop function has been requested already. I can’t find any obvious way of replicating ApplicationRestart either but you could easily call onApplicationStart manually if needed.