Welcome to another edition of Extending ColdFusion, where we discuss the multitude of ways you can extend your ColdFusion programming with user-defined functions (UDFs), custom tags, CFCs, and other methods. In this edition, we are going to delve into a "gray" area of CF development ? use of hidden/internal methods. These are methods that exist within ColdFusion but are not documented. Be warned ? while all of the following code works just fine in MX 6.1, there is no guarantee that it will continue to work in future versions. That being said, there is some cool functionality if you are willing to take some minor risks!
One of the most requested features for ColdFusion is a simple way to track sessions. As you know, ColdFusion has very simple and easy-to-use session management. What it does not have is a way to grab a list of sessions for an application. This can be useful for many reasons, and as I said, has long been requested. The UDF we will look at will use one of the unsupported methods of the ColdFusion server to get this information:
<cfscript> function getSessions(appName) { var tracker = createObject("java","coldfusion.runtime.SessionTracker"); return tracker.getSessionCollection(appName); } </cfscript>
This UDF, written by Samuel Neff (sam@rewindlife.com), is extremely simple. One line grabs an instance of the Java object, coldfusion.runtime.SessionTracker. The second line calls a method on this object, getSessionCollection(), that returns a structure of sessions based on the application name you pass in. The structure is keyed by a unique session identifier, but if you really want to identify a particular session you'll have to look at the data. Figure 1 shows an example of running the following call:
<cfdump var="#getSessions(application.applicationName)#">
What is application.applicationName? This is one of the default values that will always exist in the application scope. As you can probably guess, it returns the name of the current application. So what are some uses of this code? On CFLib.org, I have a scheduled event that runs once an hour. It records the total number of sessions to the database. In my administrator, I can then display a report of how many sessions were active on an hourly basis. CFLib.org also supports an optional login system. Since this information is stored in the session scope, I cannot only record how many active sessions there are, but how many sessions are from people who are active members of the site. The following code shows the script called by the scheduled task:
<cfscript> function getSessions(appName) { var tracker = createObject("java","coldfusion.runtime.SessionTracker"); return tracker.getSessionCollection(appName); } </cfscript> <cfset nSessions = 0> <cfset nLoggedIn = 0> <cfset sessions = getSessions(application.applicationName)> <cfset nSessions = structCount(sessions)> <cfloop item="s" collection="#sessions#"> <cfif structKeyExists(sessions[s],"username")> <cfset nLoggedIn = nLoggedIn + 1> </cfif> </cfloop> <cfquery name="updStats" datasource="#application.dsn#"> insert into tblStats(numberSessions,numberLoggedIn) values(#nSessions#,#nLoggedIn#) </cfquery>
The first few lines are simply the UDF repeated again. Then we create two variables ? one for the total number of sessions and one for the number of logged-in users. To get the total number of sessions, all we need is the number of keys of the struct, which is returned by structCount(). To get the number of logged-in sessions, we loop over the structure and check for the "username" key. If it exits, it's a session with a logged-in user. Lastly, we insert both values into the database. (The table contains a column with a timestamp that defaults to the current time.) Figure 2 shows a graph report of the last 12 hours of sessions on the site.

As you can probably tell, there are numerous possibilities available with this UDF, but please remember that this is an unsupported function. As I said in the beginning, this feature has been requested for many years. If you would like to see this "hack" added as a real feature of ColdFusion, I strongly urge you to voice your opinion at www.macromedia.com/go/wish. To see more hidden features of ColdFusion sessions and applications, see the blog entry at rewindlife.com: www.rewindlife.com/archives/000069.cfm
Now, what do you do if you don't want to use hidden functions? It is possible to track sessions, but it's just a little bit more difficult. One simple way is to include the following code in your Application.cfm file:
<cfparam name="application.sessions" default="#structNew()#"> <cfset application.sessions[session.urlToken] = now()>
All this code does is define an application structure called sessions and then sets a key equal to session.urlToken, a value that is unique per session, with the value of the current time. Why do we set the time? ColdFusion automatically "clears up" sessions that have expired. For our solution, we have to do it ourselves. So, if you wanted to count the number of sessions online, you could simply loop over each value, check if it's more than your session timeout, and if so, remove the key. If you wanted to store additional information, you could simply use a more advanced structure:
<cfparam name="application.sessions" default="#structNew()#"> <cfset application.sessions[session.urlToken] = structNew()> <cfset application.sessions[session.urlToken].lastHit = now()> <cfset application.sessions[session.urlToken].whatever = whatever>
In this example, I create a substructure for each session and save the time of the last hit, along with a variable called whatever.
In conclusion, I hope you find the methods described above useful for your projects. If you would like to suggest a particular UDF, custom tag, CFC, or some other extension for this series, please e-mail me at jedimaster@mindseye.com. |