Saturday 3 November 2012

CFML: Application.cfc-set mappings don't work in onApplicationEnd

G'day:
Well this was not what I was intending to be looking at this evening, but I made the mistake of  looking at StackOverflow and didn't understand what I was reading about mappings and onSessionEnd and ColdFusion 8, so looked into it.


I don't really care about quirks of CF8: the boat's pretty much sailed on any problems anyone finds with that.  However I wanted to make sure it wasn't still happening in CF9 or CF10.

The original problem is that ColdFusion mappings that are set in Application.cfc don't seem to exist by the time onSessionEnd() runs (this is on ColdFusion 8).  Here's some test code and the results:

<cfcomponent output="true">
    
    <cfset this.name = "testMappings">
    <cfset this.sessionManagement = true>
    <cfset this.applicationTimeout    = createTimespan(0,0,0,20)>
    <cfset this.sessionTimeout        = createTimespan(0,0,0,10)>
    
    <cfset this.mappings = structNew()>
    <cfset this.mappings["/test"] = "C:\temp">
    
    <cfset testExpandPath("Pseudoconstructor")>
    
    <cffunction name="onApplicationStart" returnType="boolean" output="true">
        <cfset testExpandPath("onApplicationStart")>
        <cfreturn true>
    </cffunction>

    <cffunction name="onApplicationEnd" returnType="void" output="true">
        <cfargument name="applicationScope" required="true">
        <cfset testExpandPath("onApplicationEnd")>
    </cffunction>
    
    <cffunction name="onRequestStart" returnType="boolean" output="true">
        <cfargument name="thePage" type="string" required="true">
        <cfset testExpandPath("onRequestStart")>
        <cfreturn true>
    </cffunction>

    <cffunction name="onRequest" returnType="void">
        <cfargument name="thePage" type="string" required="true">
        <cfset testExpandPath("onRequest")>
        <cfinclude template="#arguments.thePage#">
    </cffunction>

    <cffunction name="onRequestEnd" returnType="void" output="true">
        <cfargument name="thePage" type="string" required="true">
        <cfset testExpandPath("onRequestEnd")>
    </cffunction>

    <cffunction name="onSessionStart" returnType="void" output="true">
        <cfset testExpandPath("onSessionStart")>
    </cffunction>

    <cffunction name="onSessionEnd" returnType="void" output="true">
        <cfargument name="sessionScope" type="struct" required="true">
        <cfargument name="appScope" type="struct" required="false">
        <cfset testExpandPath("onSessionEnd")>
    </cffunction>


    <cffunction name="testExpandPath" returntype="void" access="public" output="true">
        <cfargument name="message" required="true" type="string">

        <cfset var path  = expandPath("/test")>
        <cfset var fullMessage = "#message#: #path#">
        <cfoutput>#fullMessage#<br /></cfoutput>
        <cflog file="testMappings" text="#fullMessage#">
    </cffunction>

</cfcomponent>

Pseudoconstructor: C:\apps\adobe\ColdFusion\8\instances\CF801\cfusion.ear\cfusion.war\test
onApplicationStart: C:\temp
onSessionStart: C:\temp
onRequestStart: C:\temp
onRequest: C:\temp
test.cfm: C:\temp
onRequestEnd: C:\temp
onSessionEnd: C:\apps\adobe\ColdFusion\8\instances\CF801\cfusion.ear\cfusion.war\test
onApplicationEnd: C:\apps\adobe\ColdFusion\8\instances\CF801\cfusion.ear\cfusion.war\test

Firstly, it's completely legit that the mapping doesn't work in the pseudoconstructor.  See my article on how the settings set in the this scope work if you're not sure why.

However to me it's a bug that they aren't still around in onSessionEnd() and onApplicationEnd().  Someone at Adobe clearly thinks so too, as the behaviour has been modified (partially) in CF9:

Pseudoconstructor: C:\webroots\CF902\test
onApplicationStart: C:\temp
onSessionStart: C:\temp
onRequestStart: C:\temp
onRequest: C:\temp
test.cfm: C:\temp
onRequestEnd: C:\temp
onSessionEnd: C:\temp
onApplicationEnd: C:\webroots\CF902\test

onSessionEnd() has been fixed, but not onApplicationEnd().  You'd think that if someone took the time to fix one of these, they might check the other one too eh?  Apparently not.

It's the same behaviour in ColdFusion 10.  But Railo (4.0.013) works fine: the mapping is still available in onApplicationEnd().

I've raised a bug for this: 3358817.

The work around - such as it is - for this is to set the mappings in CFAdmin: then they work fine.  Not much of a work around, but it might help some people.

Righto.

--
Adam