ColdFusion 10 - An Augmented Virtual File System (VFS)

Last week, I explored ColdFusion 10's new ability to load custom Java Classes and JAR files on a per-application basis. In that exploration, I ended up creating a number of Java classes and a ColdFusion component (CFC) that needed to work together. This got me thinking about code deployment - if I created a Java class that depended on a ColdFusion component, could I deploy them together in the same JAR file? With ColdFusion 10's enhanced virtual file system (VFS), the answer is surprisingly, Yes. In fact, a ColdFusion component can now be loaded directly from a JAR file.

NOTE: At the time of this writing, ColdFusion 10 was in public beta.

To recap what I did last week, I came up with a way to enable Java to invoke ColdFusion closures and ColdFusion component methods. I did this by storing a dynamic Java proxy to the ColdFusionProxy.cfc component as a static Java class property. This, obviously, created a strong coupling between the Java class files to the ColdFusionProxy.cfc component. As such, I wanted to deploy them together in a single JAR file.

The result of this thinking was the cf10.jar file which created an archive with the following, embedded files:

cf10.jar !/ com / bennadel / cf10 / Core.class

cf10.jar !/ com / bennadel / cf10 / CFArray.class

cf10.jar !/ com / bennadel / cf10 / ColdFusionProxy.cfc

As you can see, this JAR file contains two Java classes and my ColdFusion component.

The augmented virtual file system in ColdFusion 10 provides us with read-access to JAR files. So, in order to create a dynamic Java proxy for this archived ColdFusion component, I simply had to map the JAR file path to a custom ColdFusion mapping:

Application.cfc - Our ColdFusion Application Framework Component

<cfscript>

// NOTE: CFScript tags add purely for Gist color-coding. Remove.

component

output="false"

hint="I define the application settings and event handlers."

{

// Define our standard Application settings.

this.name = hash( getCurrentTemplatePath() );

this.applicationTimeout = createTimeSpan( 0, 0, 0, 5 );

// Map aspects of the Virtial File System (VFS). Notice that the

// mapped file here ends with "!". This separates the JAR file

// path from the embedded, archived files.

this.mappings[ "/cf10jar" ] = (

"jar://" &

getDirectoryFromPath( getCurrentTemplatePath() ) &

"lib/cf10.jar!"

);

// Define our per-application Java library settings. Here, we

// are telling it to load our CF10.jar file.

this.javaSettings = {

loadPaths: [

"./lib/cf10.jar"

],

loadColdFusionClassPath: true

};

// I initialize the application.

function onApplicationStart(){

// Create a dynamic proxy using a ColdFusion Component that

// is loacated in our CF10 JAR file. Since we mapped the

// location of the JAR file itself, now all we need to

// supply is the dot-file-path to the embedded component.

var coldfusionProxy = createDynamicProxy(

"/cf10jar.com.bennadel.cf10.ColdFusionProxy",

[ "com.bennadel.cf10.ColdFusionProxy" ]

);

// Now that we have our proxy, let's initialize our custom

// JAVA library with our ColdFusion invocation "tunnel."

// This will enable our Java classes to be able to invoke

// ColdFusion closures and component methods.

createObject( "java", "com.bennadel.cf10.Core" )

.setColdFusionProxy( coldfusionProxy )

;

// Return true so the application can load.

return( true );

}

}

// NOTE: CFScript tags add purely for Gist color-coding. Remove.

</cfscript>

As you can see, I am creating a ColdFusion application mapping of the virtual file path:

jar://[app directory]/lib/cf10.jar!

... to the mapping:

/cf10jar

Notice that the virtual file path contains a trailing "!". This character separates the physical file path (JAR) from the embedded file paths (archived files). Everything after the "!" will be considered an in-JAR file path.

Once this mapping has been set up, I can then create a ColdFusion component using the fully qualified component path:

/cf10jar.com.bennadel.cf10.ColdFusionProxy

As you can see, this component class path starts off with "/cf10jar", our custom ColdFusion mapping. But then, we use the standard dot-notation to define the in-JAR file path to the ColdFusionProxy.cfc component. We're using the virtual file system to load a ColdFusion component out of a JAR file archive.

The ColdFusion 10 virtual file system (VFS) is pretty darn cool. It provides file-based access to the following protocols:

BZIP2

File

FTP

FTPS

GZIP

HTTP

HTTPS

JAR

RAM

RES

SFTP

TAR

TEMP

WebDAV

ZIP

Not all of these protocols provide read, write, and list access. Many provide only read-access to virtual files. The list of functionality and limitations can be seen on the Apache Commons website.

NOTE: ColdFusion 9.01 and ColdFusion 10 also support Amazon's Simple Storage Service (S3) through the protocol, "s3://". This integration is much more robust and requires application settings to be defined in the Application.cfc ColdFusion framework component.

Wile not all protocols in the ColdFusion virtual file system (VFS) support both read and write access, I think the unified access notation is going to be a very useful feature.

I recently found the VFS in both ColdFusion 9 and 10 has some weird performance curves when writing a lot of in-memory files.( I tried this because I wanted to create a high performance log entry write-cache)

Creating a few files in RAM:// is much faster than the physical disk.

When you create about 500 files the physical and the ram disk have about the same performance.But expanding this example creating 10.000 files, the physical disk is ten times faster!

I believe problem is related to the number of files created in a single directory. If I create 10.000 files in 20 different directories RAM maintains its performance curve in comparison to the physical disk.

So even if you have the ram to create a lot of in-memory files, the VCF should be avoided when you want to write many different entries.

I am the co-founder and lead engineer at InVision App, Inc — the world's leading prototyping,
collaboration & workflow platform. I also rock out in JavaScript and ColdFusion 24x7 and I dream about
promise resolving asynchronously.