Skip to main content
Ben Nadel at cf.Objective() 2012 (Minneapolis, MN) with: Alec Irwin
Ben Nadel at cf.Objective() 2012 (Minneapolis, MN) with: Alec Irwin

Using AttributeCollection To Manage Locking In ColdFusion

By
Published in

The other day, when I was demonstrating how to use an ordered struct as a fixed-size cache in ColdFusion, I had to synchronize access to the cache in order to limit the number of cache keys. Whenever I make a new demo, it gives me a chance to reconsider and experiment with different approaches. And, in the aforementioned demo, I used ColdFusion's attributeCollection functionality to define my CFLock tags. This felt like a rather elegant and easily consumable approach; and I wanted to showcase it more directly.

ColdFusion has so many subtle developer ergonomic luxuries, it can be hard to known which mechanic makes the most sense in any given situation. That's part of what makes CFML such a joy to write—you're always mixing and matching different techniques in an ongoing effort to strike the right balance between elegance, readability, and maintainability.

For example, in my previous demo (regarding the fixed-size cache), I defined my CFLock attributes in the ColdFusion component's constructor function, init(). In today's demo, I want to mix it up a little and use private methods to define the read and write lock attributes. By using methods, I gain a little more wiggle room in how things are implemented.

In the following ColdFusion component, I have two public methods: one for reading data and one for writing data. I don't actually read or write anything in this code; but, I do define the CFLock tags that would synchronize access to an underlying data store.

You'll note that each CFlock tag is defined using attributeCollection, which is, itself, defined by a private method call, either synchronizedRead() or synchronizedWrite():

component
	output = false
	hint = "I manage synchronized access to some sort of internal data store."
	{

	/**
	* I read some data from the underlying synchronized data collection.
	*/
	public any function getSomeData() {

		lock attributeCollection = synchronizedRead() {

			// ... READ some data within the READ-ONLY lock.

		}

	}

	/**
	* I change some data in the underlying synchronized data collection.
	*/
	public void function mutateSomeData() {

		lock attributeCollection = synchronizedWrite() {

			// ... MUTATE some data within the EXCLUSIVE lock.

		}

	}

	// ---
	// PRIVATE METHODS.
	// ---

	/**
	* I build the attributes for a read-only lock with the given timeout.
	*/
	private struct function synchronizedRead( numeric timeoutInSeconds = 1 ) {

		return {
			name: "ManagerLockForGreatGood",
			type: "readonly",
			timeout: timeoutInSeconds
		};

	}

	/**
	* I build the attributes for an exclusive lock with the given timeout.
	*/
	private struct function synchronizedWrite( numeric timeoutInSeconds = 1 ) {

		// The only difference between the READ and the WRITE lock is the [type]. As such,
		// we're going to use the read lock to define the base attributes and then simply
		// override the type. This way, the lock name is only defined in one place.
		return synchronizedRead( timeoutInSeconds ).append({
			type: "exclusive"
		});

	}

}

What I love about this code is that it minimizes the "noise" added by the locking mechanics. If we're going to synchronize access to data, we need to have locking. But, the locking itself is just a distraction from what's actually taking place. By moving the lock attributes into method calls, each CFLock is reduced to a single line of code; which allows the more important logic of the data access to be more prominent.

Also, by using private methods to define the CFLock attributes, I'm able to have one method piggy-back off the other. In this case, the only difference between the readonly lock and the exclusive lock is the type. As such, I'm able to define the exclusive lock by gathering the readonly lock and then overriding the type attribute.

The attributeCollection feature is such a boon to CFML developers. Whether it's used to define tag attributes whole-hog; or, it's merely the base collection upon which other attributes are cascaded; it's just a wonderful developer ergonomic of the language.

Want to use code from this post? Check out the license.

Reader Comments

Post A Comment — I'd Love To Hear From You!

Post a Comment

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel