MDCFUG Presentation on Zip Files

Last night I had the opportunity to speak at the Maryland CFUG about working with zip files in ColdFusion. Since this was my first time speaking outside of the office environment, I admit I was a little apprehensive. I spent some time worrying about everything that could go wrong: getting stuck in traffic (not a problem, it was a federal holiday so traffic was light around the DC metro area), my presentation and code getting corrupted (MDCFUG asked for a copy of the presentation ahead of time), Connect not working (OK, there were some lag issues there, something about Macs and Adobe Connect, but nothing major for me).

When it came time for me to start, however, all of those worries were gone. The folks a TeraTech run a good meeting, even small CFUGs. The turn out was light, most likely due to the holiday, but I wasn't talking to an empty room. Thanks to everyone who came and asked questions. Overall, the experience was positive and I will be looking for opportunities to speak again.

Reading Binary Files in a Zip File Before CF8

In my last post about working with zip files, I examined how to list the contents of an archive without using CF8's cfzip tag. Now that we have a list of files, let's look at how to read one of the entries.


Finding a Random Row

Every now and then I get a requirement to do something to a random table record. The most common is to retrieve a random record for display. Other times it is part of a data scrambling routine. So how is this done?

Most database platforms have a function that generates a unique identifier. SQL Server has NEWID(), which generates a GUID:

view plain print about
3Example Output: 0B7869E5-1428-4CA9-9D5A-CDA0E9756DC2

MySQL has RAND(), which generates a random floating-point value:

view plain print about
3Example Output: 0.93845168309142

Using these functions, retrieving a random row from a table becomes as simple as:

SQL Server

view plain print about
2FROM mytable


view plain print about
2FROM mytable

So what is really going on behind the scenes? The key to the randomness is the ORDER BY clause. As each row in the table is evaluated, it is assigned a unique value via the NEWID() or RAND() function. The value changes for each row and each time the query is executed.

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:

 + myview

But this did not:

 + 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.


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);
5    local.currentClass = arguments.obj.getClass();
6    arrayAppend(local.hierarchy, local.currentClass.getName());
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    }
14    return local.hierarchy;

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.

A New Look

The title says it all. I recently started a new job so why not celebrate with a new look-and-feel. I should have more time and brain cells to write in the coming weeks too.

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.


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 = "">
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>

The resulting list is:

view plain print about

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

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)#")>

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)#", ";")>

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.

Previous Entries / More Entries