Wednesday, February 9, 2011

Using Metadata To Add Static Variables to ColdFusion Components

Let me start out by saying that everything in this this post I learned from Elliot Sprehn's fantastic CFMeetup presentation "I bet you didn't know you could do that with ColdFusion".  If you haven't already seen this presentation, you should.  Even if you have seen it you should watch it again, and show it to anyone you know who loves to bash ColdFusion.   Anyways, I wanted to play around with this concept on my own to see how I could get it to work for me.  

First, if you are unfamiliar with the concept of metadata in ColdFusion read "Using introspection to get  metadata for components" at adobe.com on for some background.  Also should check out the getMetaData and getComponentMetaData functions over at CFQuickDocs.  The most important thing to know for this post is that these functions return a structure that describes an object.  These properties are generated the first time an object is instantiated and will persists until the object is recompiled by the ColdFusion server.

So what exactly am I talking about when it comes to adding static variables to ColdFusion components?  Well if anybody has worked with a strongly typed language such as .NET or Java you'll be familiar with the static keyword.  Static variables are variables that are variables that exist in only one place and are accessible without having to instantiate a instance of a object.  Basically you can access a property on an object by calling ObjectName.staticVar without having to create a new ObjectName().

Lets take a look at a bare bones component called Employee:

<cfscript>
component name="Employee"
{
 public Employee function Init(){
  var metadata = getComponentMetaData("Employee"); 
  
  if(!structKeyExists(metadata,"myStaticVar")){
   
   lock name="metadata.myStaticVar" timeout="10"{
    metadata.myStaticVar = "Hello Static Variable."; 
   }
  }
  
  return this;
 }
}

As you can see when this component's Init() method is called I get the components metadata and look for a key called "myStaticVar" and if it doesn't exist I create it.  Note: it's important to lock the creation of this key since you are manipulating a shared scope.  Its important to note here that until this component is compiled by ColdFusion this key does not exist.  Dumping the output of getComponentMetaData("Employee")at this point will produce the following output:






















As you can see there is no key for "myStatcVar" which was defined in the init() method of the component.   So let's create an instance of the component and dump its metadata.

<cfscript>
Employee = new Employee();
writeDump(getComponentMetaData("Employee");
</cfscript>
 






















Now you can see that my  the component metadata structure has a key "MYSTATICVAR".  The real beauty of this is that this metadata persists server wide for this component until it is recompiled by the ColdFusion server.   I tested this by creating  a new directory with a new application.cfc and with a new application name and dumped the metadata on the Employee component as shown below:

<cfscript>
writeDump(getComponentMetaData("Employee");
</cfscript>

Sure enough, the MYSTATICVAR key was there.  I even created a completely new website and mapped the component directory to the directory that holds my Employee component and ran the code above again and the metadata was there.

Now anytime I want to access the value of my static variable all I have to do is write code like this to retrieve the value of the static variable:

<cfscript>
 staticVariableValue = getComponentMetaData("Employee").myStaticVar;
 
 writedump(staticVariableValue);
</cfscript>

It's important to note that when the server is restarted this metadata will once again disappear until the component is created for the first time.
Fork me on GitHub