I was just reading on Terrence Ryan's blog about introspecting the Application.cfc data. The method he uses is so simple, so obvious that it blows my mind that I haven't seen this before. I don't want to jump on his coat tails, but when I saw this, I was so excited that I felt I had to share it. So, what is the goal here? Usually the question of application introspection comes up when someone whats to do something like:
- Check to see what the application name is.
- Check to see if session management is enabled.
- Check to see what the session timeout is.
The information sought out by these questions is defined in our Application.cfc ColdFusion component:
<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, 20, 0 ) /> <cfset this.sessionManagement = true /> <cfset this.sessionTimeout = createTimeSpan( 0, 0, 5, 0 ) /> <cffunction name="onRequest" access="public" returntype="void" output="true" hint="I execute the requested template."> <!--- Define arguments. ---> <cfargument name="template" type="string" required="true" hint="I am the user-requested template." /> <!--- Include the requested template. ---> <cfinclude template="#arguments.template#" /> <!--- Return out. ---> <cfreturn /> </cffunction> </cfcomponent>
It's easy enough to see in the code, but when questions like this come up, how do we access this information programmatically? To start experimenting, we will often try to do something like access the Application scope:
<!--- Duump out the application scope. ---> <cfdump var="#application#" label="Application Scope" />
But, checking the Application scope is not very fruitful. When we run the above code, we get the following CFDump output:
As you can see, we only get the application name.
Next, we might look at the Application.cfc and realize that the OnRequest() event handler turns the user-requested template into a large mixin (see Application.cfc above). What this does is essentially execute the requested template in the context of the Application.cfc object, giving it access to all the Application.cfc scopes. In situations like this, you can access the THIS scope directly:
<!--- Because we are using the OnRequest() event handler, our target template becomes a mixin - essentially becoming PART OF the Application.cfc execution. As such, it lives in the context of the application instance and has access to Application.cfc scopes. ---> <cfdump var="#this#" label="Template As Mixin" />
When we run this code, we get the entire Application.cfc object:
This gives us all the information we need, but it only works in situations where the template we are executing is included directly into the OnRequest() event method. This excludes any custom tag execution or ColdFusion component calls (not to mention AMF style execution).
At this point, we might get kinky and examine the underlying Java objects available to us. After a lot of introspection of various scopes, we might find out that the Application scope itself has some very useful, undocumented methods like GetApplicationSettings():
<!--- Dump out application settings. This is a hacky way that leverages undocumented features of the language. ---> <cfdump var="#application.getApplicationSettings()#" label="Undocumented Application Settings" />
As you can see, here, we are accessing GetApplicationSettings(), an undocumented method on the Application scope. When we run this, we get the following CFDump output:
This gives us exactly the information that we need; but, in order to get at it, we need to use undocumented features of the ColdFusion language. This leaves a bad taste in our mouth and opens our applications up to future bugs. Furthermore, it gives us timeout values in Seconds, not franctions of a day (as defined by CreateTimeSpan()).
So far, we've explored three different attempts at introspecting our ColdFusion application information and none of them has been fully satisfactory. That is why I was so excited when I saw Terry's blog post. His idea can be used anywhere in the application with any type of request and does not use any voodoo magic. So, what did Terry suggest? Creating a new instance of the Application.cfc ColdFusion component:
<!--- Create a new instance of the application object. ---> <cfset applicationInstance = createObject( "component", "Application" ) /> <!--- Dump out the application instance. ---> <cfdump var="#applicationInstance#" label="Application Instance" />
As you can see, from within the current page request, we are creating a new instance of the Application.cfc. And, when we create this instance and dump it out, we get the following output:
Here, we get all the information that is defined in the Application.cfc. At first, you might be nervous that we'll accidentally invoke some of the event handlers; but, that won't happen. Remember, there is nothing special about the Application.cfc ColdFusion component other than the fact that the ColdFusion server looks for it when first executing a page request. Once you are in the middle of a page execution, however, attempts to create an Application.cfc instance will be treated the same as any other ordinary CFC invocation. Essentially, all that runs is the Application.cfc pseudo constructor. As such, you won't incur any boot-up costs associated with the OnApplicationStart() event method.
A huge thanks to Terry for pointing out such a simple but awesome tip!
Want to use code from this post? Check out the license.