Wednesday, August 4, 2010

Creation of Singleton Object with Coldfusion

Note: Coldfusion in and out tag is replaced because of blogging problem)

Singletons are perhaps one of the most simple Design Patterns. For those who don’t know sigletons are a class that can only have one instance. They can be thought of as a glorified global variable - but are a lot more useful.Most ColdFusion classes, or rather instances of CF components, can be turned in a singleton by placing the following code in your Application.cfm:

cfif not structkeyexists(application,instance name)
cfset application.instance name = createobject(”component”,path to component)
/cfifor OnApplicationStart method of your Application.cfc: cfset application.instance name = createobject(”component”,path to component)

The above code places an instance of the component in the application scope and you can then access the properties and methods of the component via the application variable.Singletons can also be placed in other ColdFusion scopes such as the server or session scopes or even the request scope. Which scope you choose depends on what your code does.Another way to create a singleton is to add an getInstance method to your component and use that to return the instance.Like so:

cffunction name=”getInstance” access=”public” output=”false”

cfif not isdefined(”application.instance name”)
cfset application.[instance name] = this
/cfif

cfreturn application.[instance name]
/cffunctionRather than hard coding the instance name we can base it on the displayname of the component.cffunction name=”getInstance” access=”public” output=”false”
cfset var displayname = getMetaData(this).displayname

cfif not isdefined(”application.#displayname#”)
cfset application.[displayname] = this
/cfif

cfreturn application.[displayname]
/cffunction

While this is an improvement on the original code this method would need to be added to all components you wanted to turn into a singleton. A better solution is to create a singleton component and in a component you need to turn into a singleton extend from the singleton component.The singleton component (singleton.cfc):

cfcomponent displayname=”singleton”

cffunction name=”getInstance” access=”public” output=”false”
cfset var displayname = getMetaData(this).displayname

cfif not isdefined(”application.#displayname#”)
cfset application[displayname] = this
/cfif

cfreturn application[displayname]
/cffunction

/cfcomponentThe component we want to use as a singleton (dsn.cfc): cfcomponent displayname=”DSN” extends=”singleton”
cfset variables.DNS = “”

cffunction name=”getDSN” access=”public” returntype=”string” output=”false”
cfreturn variables.DSN
/cffunction

cffunction name=”setDSN” access=”public” output=”false”
cfargument name=”DSN” type=”string” required=”yes”
cfset variables.DSN = arguments.DSN
/cffunction

/cfcomponentUsing the component (in Applicaton.cfm): cfscript
if (not structkeyexists(application,’dsn’)) {
application.dsn = createobject(’component;,’dsn’).getInstance();
application.dsn.setDSN(’mydsn’);
}
/cfscriptor OnApplicationStart method of Application.cfc: cfscript
application.dsn = createobject(’component’,'dsn’).getInstance();
application.dsn.setDSN(’mydsn’);
/cfscriptIn the page: cfquery name=”myquery” datasource=”#applicaton.dsn.getDSN()#”

/cfquery Here the example code : singleton.cfc cfcomponent displayname=”singleton”

cffunction name=”init” access=”public” output=”false”
cfset var displayname = getMetaData(this).displayname

cfif not isdefined(”application._singletons”)
cfset application._singletons = structnew()
/cfif
cfif not isdefined(”application._singletons.#displayname#”)
cfset application._singletons[displayname] = this
/cfif

cfreturn application._singletons[displayname]
/cffunction

cffunction name=”remove” access=”public” output=”false”
cfset var displayname = getMetaData(this).displayname

cfif isdefined(”application._singletons.#displayname#”)
cfset structdelete(application._singletons, displayname)
/cfif
/cffunction

/cfcomponentAnd here hows it’s setup in Application.cfm (or .cfc): cfscript
// function to get an instance of a singleton
function getInstance(name) {
if (not isdefined(”application._singletons.#name#”)) {
instance = createobject(”component”,”com.classsoftware.utils.#name#”).init();
}

return application._singletons[name];
}

// function to remove a singleton
function removeInstance(name) {
if (isdefined(”application._singletons.#name#”)) {
application._singletons[name].remove();
}
}

// remove instance if asked
if (isdefined(”url.init”)) {
removeInstance(’dsn’);
}
/cfscriptAnd how it’s used on the page: cfset dsn = getInstance(”dsn”)

cfquery name=”myquery1″ datasource=”#dsn.getDSN()#”
select ….
/cfquery

cfquery name=”myquery2″ datasource=”#dsn.getDSN()#”
select ….
/cfquery

The functions getInstance and removeInstance could be placed inside a component that creates/removes singletons (a singleton factory?). However that component itself would need to be a singleton or you’d need to create it (via createobject) on every page. I’ll feel it’s best just to leave them as user defined functions for simplicity and performance sake.Anther issue that came up was that you can still use createobject (or cfinvoke) to create other instances of the component and there seems no way of stopping this.Well there’s one way I can think of but I’m not sure if I’d actually use it in a production system, but it may be of interest to someone so here’s how to do it.ColdFusion methods can be set at run time, you can add or replace methods by assigning them to new functions like so: // from this point on when method is called call newmethod instead
cfset instance.method = newmethodMethods can also be removed like so: // remove method “method” from instance
cfset structdelete(instance,”method”)

So you can create a component that has a method that throws an exception (via cfabort) and then have all methods of that component call that method. You can create an instance of the component but if you call any methods you will get an error.Applying this to our singleton component we get:

cfcomponent displayname=”singleton”
cffunction name=”init” access=”public” output=”false”
cfscript
var displayname = getMetaData(this).displayname;

this.invalid();

if (not isdefined(”application._singletons”)) {
application._singletons = structnew();
}
if (not isdefined(”application._singletons.#displayname#”)) {
application._singletons[displayname] = this;
}

return application._singletons[displayname];
/cfscript
/cffunction

cffunction name=”remove” access=”public” output=”false”
cfscript
var displayname = getMetaData(this).displayname;

this.invalid();

if (isdefined(”application._singletons.#displayname#”)) {
structdelete(application._singletons, displayname);
}
/cfscript
/cffunction

cffunction name=”invalid” access=”public” output=”false”
cfabort showerror=”Singletons must be created via helper functions not via create object!”
/cffunction

/cfcomponentThe this.invalid();

would also needed to be added to all methods of classes than extend singleton.cfc. eg dsn.cfc in the last article.If you then remove the method that generates the error (via structdelete) before any methods are called then the methods of the instance can be called.Applying this to our getInstance function we get: // function to get an instance of a singleton
function getInstance(name) {
if (not isdefined(”application._singletons.#name#”)) {
instance = createobject(”component”,”path..#name#”);
structdelete(instance,”invalid”);
instance.init();
}

return application._singletons[name];
}

That way only instances returned from our getInstance function can be used and any other instances created via created object (or other way) will throw an error when a method of that instance is called.

Singletons are perhaps one of the most simple Design Patterns. For those who don’t know sigletons are a class that can only have one instance. They can be thought of as a glorified global variable - but are a lot more useful.Most ColdFusion classes, or rather instances of CF components, can be turned in a singleton by placing the following code in your Application.cfm:

cfif not structkeyexists(application,instance name)
cfset application.instance name = createobject(”component”,path to component)
/cfifor OnApplicationStart method of your Application.cfc: cfset application.instance name = createobject(”component”,path to component)

The above code places an instance of the component in the application scope and you can then access the properties and methods of the component via the application variable.Singletons can also be placed in other ColdFusion scopes such as the server or session scopes or even the request scope. Which scope you choose depends on what your code does.Another way to create a singleton is to add an getInstance method to your component and use that to return the instance.Like so:

cffunction name=”getInstance” access=”public” output=”false”

cfif not isdefined(”application.instance name”)
cfset application.[instance name] = this
/cfif

cfreturn application.[instance name]
/cffunctionRather than hard coding the instance name we can base it on the displayname of the component.cffunction name=”getInstance” access=”public” output=”false”
cfset var displayname = getMetaData(this).displayname

cfif not isdefined(”application.#displayname#”)
cfset application.[displayname] = this
/cfif

cfreturn application.[displayname]
/cffunction

While this is an improvement on the original code this method would need to be added to all components you wanted to turn into a singleton. A better solution is to create a singleton component and in a component you need to turn into a singleton extend from the singleton component.The singleton component (singleton.cfc):

cfcomponent displayname=”singleton”

cffunction name=”getInstance” access=”public” output=”false”
cfset var displayname = getMetaData(this).displayname

cfif not isdefined(”application.#displayname#”)
cfset application[displayname] = this
/cfif

cfreturn application[displayname]
/cffunction

/cfcomponentThe component we want to use as a singleton (dsn.cfc): cfcomponent displayname=”DSN” extends=”singleton”
cfset variables.DNS = “”

cffunction name=”getDSN” access=”public” returntype=”string” output=”false”
cfreturn variables.DSN
/cffunction

cffunction name=”setDSN” access=”public” output=”false”
cfargument name=”DSN” type=”string” required=”yes”
cfset variables.DSN = arguments.DSN
/cffunction

/cfcomponentUsing the component (in Applicaton.cfm): cfscript
if (not structkeyexists(application,’dsn’)) {
application.dsn = createobject(’component;,’dsn’).getInstance();
application.dsn.setDSN(’mydsn’);
}
/cfscriptor OnApplicationStart method of Application.cfc: cfscript
application.dsn = createobject(’component’,'dsn’).getInstance();
application.dsn.setDSN(’mydsn’);
/cfscriptIn the page: cfquery name=”myquery” datasource=”#applicaton.dsn.getDSN()#”

/cfquery Here the example code : singleton.cfc

cfcomponent displayname=”singleton”

cffunction name=”init” access=”public” output=”false”
cfset var displayname = getMetaData(this).displayname

cfif not isdefined(”application._singletons”)
cfset application._singletons = structnew()
/cfif
cfif not isdefined(”application._singletons.#displayname#”)
cfset application._singletons[displayname] = this
/cfif

cfreturn application._singletons[displayname]
/cffunction

cffunction name=”remove” access=”public” output=”false”
cfset var displayname = getMetaData(this).displayname

cfif isdefined(”application._singletons.#displayname#”)
cfset structdelete(application._singletons, displayname)
/cfif
/cffunction

/cfcomponentAnd here hows it’s setup in Application.cfm (or .cfc): cfscript
// function to get an instance of a singleton
function getInstance(name) {
if (not isdefined(”application._singletons.#name#”)) {
instance = createobject(”component”,”com.classsoftware.utils.#name#”).init();
}

return application._singletons[name];
}

// function to remove a singleton
function removeInstance(name) {
if (isdefined(”application._singletons.#name#”)) {
application._singletons[name].remove();
}
}

// remove instance if asked
if (isdefined(”url.init”)) {
removeInstance(’dsn’);
}
/cfscriptAnd how it’s used on the page: cfset dsn = getInstance(”dsn”)

cfquery name=”myquery1″ datasource=”#dsn.getDSN()#”
select ….
/cfquery

cfquery name=”myquery2″ datasource=”#dsn.getDSN()#”
select ….
/cfquery

The functions getInstance and removeInstance could be placed inside a component that creates/removes singletons (a singleton factory?). However that component itself would need to be a singleton or you’d need to create it (via createobject) on every page. I’ll feel it’s best just to leave them as user defined functions for simplicity and performance sake.Anther issue that came up was that you can still use createobject (or cfinvoke) to create other instances of the component and there seems no way of stopping this.Well there’s one way I can think of but I’m not sure if I’d actually use it in a production system, but it may be of interest to someone so here’s how to do it.ColdFusion methods can be set at run time, you can add or replace methods by assigning them to new functions like so: // from this point on when method is called call newmethod instead
cfset instance.method = newmethodMethods can also be removed like so: // remove method “method” from instance
cfset structdelete(instance,”method”)So you can create a component that has a method that throws an exception (via cfabort) and then have all methods of that component call that method. You can create an instance of the component but if you call any methods you will get an error.Applying this to our singleton component we get: cfcomponent displayname=”singleton”
cffunction name=”init” access=”public” output=”false”
cfscript
var displayname = getMetaData(this).displayname;

this.invalid();

if (not isdefined(”application._singletons”)) {
application._singletons = structnew();
}
if (not isdefined(”application._singletons.#displayname#”)) {
application._singletons[displayname] = this;
}

return application._singletons[displayname];
/cfscript
/cffunction

cffunction name=”remove” access=”public” output=”false”
cfscript
var displayname = getMetaData(this).displayname;

this.invalid();

if (isdefined(”application._singletons.#displayname#”)) {
structdelete(application._singletons, displayname);
}
/cfscript
/cffunction

cffunction name=”invalid” access=”public” output=”false”
cfabort showerror=”Singletons must be created via helper functions not via create object!”
/cffunction

/cfcomponent

The this.invalid(); would also needed to be added to all methods of classes than extend singleton.cfc. eg dsn.cfc in the last article.If you then remove the method that generates the error (via structdelete) before any methods are called then the methods of the instance can be called.Applying this to our getInstance function we get:

// function to get an instance of a singleton
function getInstance(name) {
if (not isdefined(”application._singletons.#name#”)) {
instance = createobject(”component”,”path..#name#”);
structdelete(instance,”invalid”);
instance.init();
}

return application._singletons[name];
}

That way only instances returned from our getInstance function can be used and any other instances created via created object (or other way) will throw an error when a method of that instance is called.

How Coldfusion works and it’s Key Features( Compilation and precompile )


Where Does the Compilation Go?
CFMX compiles cfm (and cfc) templates into .class files, which are Java byte code files. The files are written to (and executed from) the cfclasses subdirectory of [cfusionmx]\wwwroot\WEB-INF\ directory where CFMX is installed. This occurs whether you are using another Web server or have located your file outside the default wwwroot location. CFMX compiles and runs the code from this cfclasses directory, regardless of the location of the source file. The file names for these class files may not be at all apparent. A CF template named Setsession.cfm might lead to a class file named cfsetsession2ecfm1011928410.class. All templates from all directories end up in this one cfclasses subdirectory. They’re not stored here in any subdirectories related to their original location. Instead, CF includes a hash of the directory name in that set of numbers after the file name. Keep that in mind when trying to associate a given class file with its original cfm template. The hashing process is a bit convoluted. Perhaps the easiest way to detect which class file goes with which source file is to simply edit the file and then execute (or precompile) it. Look in the cfclasses directory for the most recently created class file. Assuming your server is not too busy with many compilations taking place, it should be pretty easy to associate the classname with the CF source code name.



Saving Java Source Code Produced by CFMX (Earlier coldfusion Versions)
So that’s where the compiled source code goes. But what about seeing the actual uncompiled Java source code that your CF template is converted into? Normally it’s of no concern to CF developers what CFMX is doing under the covers in converting our CFML to Java. For the ardently curious among you, did you know that you can ask CFMX to save the Java code it creates, in source form? You can. It’s an undocumented feature, and while I’ve had no trouble doing it. The setting can only be enabled by someone with administrative control of the server, and the setting is also server-wide. It will add a slight additional time to the compile process, so it’s not something you’d want to turn on in production. It probably ought not be left on in development either. You need to edit the file web.xml in the [cfusionmx]\wwwroot\WEB-INF directory. There, if you’re familiar with XML files, you’ll find a parameter called “coldfusion.compiler.saveJava”. Change its value from false to true. Save the file. Restart the server. Now, whenever a new or recently edited file is compiled (whether automatically by CFMX or by our precompile.bat file), CFMX will also create a “.java” file along with the “.class” file. This “.java” file will be found in that same [cfusionmx]\wwwroot\WEB-INF\cfclasses\ directory as the “.class” files (and will be subject to that same issue of the curious file naming mentioned above).

The Idea of Deleting the Generated Class Files
Some have proposed that instead of precompiling their code they’d just as soon delete the underlying Java class file that was created when it was last compiled. That may seem like overkill, but there are times when it might be worth trying. Just note that, as the previous sections discussed, finding the class file that’s associated with a given source template can be challenging. While some may simply delete all the class files, that’s certainly overkill. There is a -f directive you can pass to the compile process (by modifying the precompile.bat file now cfcompile.bat). That will force a recompile of a file even if CF doesn’t think it’s necessary. Sometimes that solves the same problem that deleting the class file would solve.


Precompiling ColdFusion pages

You can use the cfcompile utility to precompile ColdFusion pages (CFM, CFC, and CFR files). This can enhance initial page loading time at runtime.

Use the following command to compile ColdFusion pages into Java classes:

cfcompile webroot [directory-to-compile]

Sourceless distribution
You can use the cfcompile utility with the -deploy option to create ColdFusion pages (CFM, CFC, and CFR files) that contain Java bytecode. You can then deploy the bytecode versions of the ColdFusion pages instead of the original CFML source code.

Use the following command to compile CFML files into bytecode format that you can deploy instead of CFML source code:

cfcompile -deploy webroot directory-to-compile output-directory

After you run the cfcompile utility, perform the following steps:

Back up your original CFML files
Copy the generated bytecode CFML files to the original directory
Deploy the application.