Fusebox 5.5's NoXML Option - First Impressions

I have worked with Fusebox for several years, primarily version 3 and version 5.1. At work we have a large (I'm talking 8K+ files) application written in Fusebox 3, along with a few apps written in Fusebox 2 that pop up every now and then on the maintenance radar. It is time to start thinking of a large-scale rearchitecture and refactoring of the FB3 app, so I decided to take a look at the noxml option for Fusebox 5.5.

I really like the use of CFCs over a big switch file, whether it is the FB3 fbx_switch.cfm or FB5 circuit.xml. I am a little unclear on how it all works. I decided to add a new view circuit and found that I could not nest them and have the implicit pickup work. This worked:

views
 + myview

But this did not:

views
 + new
  + myview

This definitely needs more exploration since I might want to have the option of grouping circuits together to help code organization.

Listing Zip File Contents Before CF8

ColdFusion 8 brought us the cfzip tag family, which greatly simplified working with zip files in ColdFusion. But, what about those of us who are not yet, for whatever reason, upgraded to CF8? Since ColdFusion has access to the Java API, we can use the classes in the java.util.Zip package to give us a hand.

[More]

Under the CF Hood: Peeking at Object Inheritance

I was chatting with a coworker today about random ColdFusion topics, and we ended up talking about the Java that underlies CF. He pointed me towards a few good resources for "peeking under the hood" that really stood out.

Simon Whatley's blog entry about finding out what makes up CF arrays and structures makes use of Java reflection to follow the inheritance path for those two object types. After reading it, I decided to write up a quick function for dumping the full class hierarchy of any Java object.

Note: Other UDFs do exist that do this, including the rather complete getJavaMetaData() function on CFLib.

view plain print about
1function getClassHierarchy( obj ) {
2    var local = structNew();
3    local.hierarchy = arrayNew(1);
4    
5    local.currentClass = arguments.obj.getClass();
6    arrayAppend(local.hierarchy, local.currentClass.getName());
7
8    /* All java objects ultimately extend java.lang.Object, so stop once we reach it. */
9    while (local.currentClass.getName() NEQ "java.lang.Object") {
10        local.currentClass = local.currentClass.getSuperClass();
11        arrayAppend(local.hierarchy, local.currentClass.getName());
12    }
13    
14    return local.hierarchy;
15}

The getClass() and getSuperClass() methods are the heavy lifters of the Java reflection API. The getSuperClass() method allows us to traverse up the inheritance chain until we reach java.lang.Object, the base class for all Java objects.

The results of this function are very informative. For example, the class hierarchy for a ColdFusion struct (using ColdFusion 7.0.2) is:

  • coldfusion.runtime.Struct
  • coldfusion.util.FastHashtable
  • java.util.Hashtable
  • java.util.Dictionary
  • java.lang.Object

Just a little peek into what makes CF tick.

Friendly UDFs - Validating Function Arguments

I use UDFs (user defined functions) frequently in my coding. One recent function I wrote got me thinking about the importance of validating the data that is passed to the function as an argument.

[More]

Getting the Intersection of Two Lists

In my last post about combining two lists, Geoffrey asked:

Is there an easy way in CF to find an intersection between two lists? It seems like listFind and listContains can find an element in a list, but what if you wanted to find if any element from list A were in list B?

Like most things in ColdFusion, there is not a single method for finding the intersection, or shared values, between two lists. Geoffrey already mentioned two built-in functions that are useful for comparing list values.

First, let's set up two lists of values:

view plain print about
1<cfset variables.aList = "1,2,3,5,8,13">
2<cfset variables.bList = "1,3,4,7,11,18">

By using a loop and the listFind function, we can generate a list of values shared between the two lists:

view plain print about
1<cfset variables.finalList = "">
2
3<!--- Examine each element in the first list and see if it exists in the second. --->
4<cfloop list="#variables.aList#" index="itm">
5    <cfif listFind(variables.bList, itm)>
6        <cfset variables.finalList = listAppend(variables.finalList, itm)>
7    </cfif>
8</cfloop>

The resulting list is:

view plain print about
11,3

Simple and effective, but there is another way.

Since ColdFusion is, ultimately, a Java application, we can use the underlying Java API to manipulate many CF variables, as demonstrated by Rupesh Kumar.

Again, let's start with our two lists:

view plain print about
1<cfset variables.aList = "1,2,3,5,8,13">
2<cfset variables.bList = "1,3,4,7,11,18">

Since ColdFusion lists are just strings (java.lang.String) our options are very limited. But we can easily covert them to arrays, which are implemented as Java lists (java.util.List), which gives us access to a rich API:

view plain print about
1<cfset variables.aList = listToArray("1,2,3,5,8,13")>
2<cfset variables.bList = listToArray("1,3,4,7,11,18")>

One of the methods available to Java lists is retainAll which "Retains only the elements in this list that are contained in the specified collection." In other words, we can remove any items from the first list that do not exist in the second:

view plain print about
1<!--- Create a deep copy of the first list to keep it intact. --->
2<cfset variables.finalList = duplicate(variables.aList)>
3<!--- Remove any elements from the first list that do not exist in the second. --->
4<cfset variables.finalList.retainAll(variables.bList)>
5<cfset variables.finalList = arrayToList(variables.finalList)>

The result is the intersection between the two original lists:

view plain print about
11,3

Combining Two Lists

Lists are a simple way to organize information in a web application. ColdFusion lists are comma-delimited by default. But what if you want to combine two lists using a comma, yet retain the same number of elements as the original list? I'm thinking about names in the format lastname, firstname.

Let's start with these two lists, which we want to combine into a single list of names in the format lastname, firstname:

view plain print about
1<cfset variables.lastNames = "Washington,Adams,Jefferson,Madison,Monroe">
2<cfset variables.firstNames = "George,John,Thomas,James,James">

I hope you will recognize the first five presidents of the United States.

The Long Way

In reality, the long way is not terribly long, but it is repetitive. First we need to combine the list elements together:

view plain print about
1<cfloop from="1" to="#listLen(variables.lastNames)#" index="idx">
2    <cfset variables.names = listAppend(variables.names, "#listGetAt(variables.lastNames, idx)#, #listGetAt(variables.firstNames, idx)#")>
3</cfloop>

A warning on the use of listGetAt: If the target list does not have an element at the referenced position, you will get an error. This loop works because both the lastNames list and the firstNames list have the same number of elements.

Next, we can use two ColdFusion functions, replaceNoCase and listChangeDelims, to manipulate the list delimiters to reach our final format, a semi-colon delimited list of names in the format lastname, firstname:

view plain print about
1<cfset variables.names = replaceNoCase(variables.names, ", ", ";", "ALL")>
2<cfset variables.names = listChangeDelims(variables.names, "~", ",")>
3<cfset variables.names = replaceNoCase(variables.names, ";", ", ", "ALL")>
4<cfset variables.names = listChangeDelims(variables.names, ";", "~")>

The result is:

view plain print about
1Washington, George;Adams, John;Jefferson, Thomas;Madison, James;Monroe, James

That sure was a lot of list manipulation for something that should be easy. Is there an easier way? Of course!

The Short Way

The listAppend function has an optional parameter to specify the delimiter for the newly appended item. Using this parameter results in the elimination of the last four lines of code in the above example:

view plain print about
1<cfloop from="1" to="#listLen(variables.lastNames)#" index="idx">
2    <cfset variables.names = listAppend(variables.names, "#listGetAt(variables.lastNames, idx)#, #listGetAt(variables.firstNames, idx)#", ";")>
3</cfloop>

The result, I believe, is simpler and easier to read code.

ColdFusion has many well designed wheels. As developers, we often do not venture deep enough into the language to see what is available to us and what it can do for us.

Coding Standards

I admit, I am a code diva. I want to see and write clean, clear, prettified code. I firmly believe that all programmers (and teams) should have, and more importantly follow, a set of coding standards. A few of my personal CF quirks are:

  • Tabs not spaces for code indentation.
  • Functions are camel-cased, e.g., querySetCell and arrayToList.
  • Variables are camel-cased and descriptive, e.g., currentRecord and dateOfBirth.
  • Component names are capitalized, e.g., User and UserService.
  • SQL keywords are upper case, e.g., SELECT username FROM users.
  • Use implicit boolean function results, e.g., .
  • Use structKeyExists over isDefined whenever possible.
  • And so on.

The important concept behind coding standards is not necessarily the nitty-gritty details of what is good and what is bad, but the discipline it provides your coding efforts. Consistency in coding is more important than the (endless) debates about which code formatting template is more readable or which function is better. If you cannot read your own code because you never structure it the same way twice then you have only yourself to blame.

CFUnited 2008

This was my third CFUnited and once again I found it was worth every penny to be there. I focused most of my attention on sessions in the frameworks and advanced CF tracks, but also managed to go to a few Flex-related sessions.

ColdSpring

I recently started to use ColdSpring for its dependency-injection engine, so I attended Mark Drew's ColdSpring session on Wednesday and Chris Scott's ColdSpring 1337 session on Thursday. Both sessions gave me plenty to think about and explore. I need to find an application to experiment with the AOP capabilities of the framework.

I18N

I may soon get the chance to help design an internationalized application, so I attended Oguz Demirkapi's session on creating multi-lingual CF applications. I really learned a lot about the built-in localization abilities of CF and tips for truly working in Unicode.

Flex

The Flex-related sessions I went to really got me excited about using Flex for a project. Matt Woodward's Real World Flex and ColdFusion session made building a Flex front end for a CF app really look easy. Mike Nimer's session, Flex 3 for ColdFusion Developers, went into more technical details about integrating the latest Flex release with a CF backend. The key detail I took away from his talk was the 'properties in, events out' model of Flex. Thinking in events will take a bit getting used to.

Inside CF

The last session I attended, Elliott Sprehn's Internals of the Adobe ColdFusion Server, just blew my mind. Wow... I had to stop my notes and just let the information flow over me. He obviously is not satisfied with just accepting that things work, but wants to know the details of how. I left feeling a bit overwhelmed, but inspired to pay more attention to stack traces as well as a lot more curious about the underlying Java APIs that make up CF.

Why Scope? Variable Scoping in ColdFusion

Variable scoping, or lack of scoping, is a topic that comes up nearly every day on the various ColdFusion discussion lists and blogs I follow. An unscoped variable, in my opinion, is an immediate red flag during a code review and requires immediate correction or a detailed (and convincing) explaination on why it should remain unscoped.

Aside from readability issues, unscoped variables may cause interesting, and sometimes difficult to trace, bugs in your code. When CF processes a code template and reaches an unscoped variable, it looks in the following scopes in order:

  1. Function local (UDFs and CFCs)
  2. Thread local (new in CF 8)
  3. Arguments
  4. Variables (local scope)
  5. Thread (new in CF 8)
  6. CGI
  7. CFFile
  8. URL
  9. Form
  10. Cookie
  11. Client

The following example illustrates one of the many problems that unscoped variables can bring about.

view plain print about
1<cfparam name="customerID" value="100">
2
3<cfquery name="customer" datasource="example">
4    SELECT customerid, customername
5    FROM customers
6    WHERE customerid = <cfqueryparam value="#customerID#" cfsqltype="cf_sql_numeric">
7</cfquery>

We have a simple page that retrieves a database record for a customer based on their customerid. The cfparam makes sure a default value exists.

So, where is the customerID value coming from - a form post, a url parameter, a cookie? In this respect, the code is not self-documenting. It is also not a performant as it could be. ColdFusion will check each scope in order, starting with the function local scope, to find the customerID variable.

The code is also not as controlled as it could be. If, for example, the code is meant to be reached via a form post, someone could bypass the form entirely by adding customerid to the URL (&customerid=123). Since the URL scope is evaluated before the form scope, the URL value will take precedence over the form field value.

All variables, even local variables, should be scoped. No exceptions without a very good reason. It increases code readability and decreases inadvertant value changes due to scope precedence rules.

Retrieving Text from an ODT File

ODT files are an archive of XML files that describe and contain the content for a text document in the OpenDocument format. As I wrote earlier, you can use ColdFusion 8 and the CFZip tag to browse the contents of these files. Extracting the actual content of an ODT file, however, is more useful than simply looking.

[More]

Previous Entries / More Entries