Orange is my favorite color

Had a user call in – she accidentally deleted half of her attendees in our web app. She thought she was deleting two but instead hit the “toggle all” and ignored the pop-up confirmation dialog which hosed half of her data the afternoon before she needs to deliver it to her team. Awesome.

What does this have to do with jQuery? Well, while I’m waiting for a database dump in the background to finish downloading so I can extract some data, I whipped up a UI enhancements with a few lines of jQuery that might help someone else:

Highlight table rows with checked checkbox in a column

What if we highlighted the selected rows when the confirmation dialog pops up? It would be one more way of pointing out what is about to happen. Here’s what it looks like now:

batch change demonstration

In conjunction with Dan Switzer’s qForms library…

objForm.onSubmit = function() {
	// only ask for confirmation when they change more than 1
	if (objForm.uid.getValue().indexOf(",") != -1)
	{
		$('input[name="uid"]:checked')
			.parents('tr')
			.css('backgroundColor', '#fc0');
		var res = confirm('You are about to make a batch change in registration status.\n\nAre you sure you want to continue?');
		if (!res)
			$('input[name="uid"]:checked')
				.parents('tr')
				.css('backgroundColor', '#fff');

		return res;
	}
	else
		return true;
};

The checkboxes are all named “uid” so when it’s submitted to the server I get a list of IDs to work with. I’m using jQuery to select all of the checked checkboxes named “uid”, then get their parent <tr> tags and then update their backgrounds to be a bright gold color while the confirmation dialog asks them if they’re really, really, seriously sure they want to do this. If they click cancel, we restore the background back to white.

My download is about done, so time to restore!

Dismantled Spec MiataI am finally back in the garage after the holidays and making some progress on the #12 car. All the body panels and doors are off in preparation for paint. I am trying to cut some corners by not completely stripping the engine bay before painting to reduce what I have to reassemble.

I have gotten in the habit of putting screws and bolts back in their holes after removing things so I don’t have to figure out what goes where. While you could almost dismantle an entire Miata with a 10 and 12mm socket, I am hoping this strategy will keep me from wondering exactly which bolt belongs to each hole.

Grabbing lunch now and then going to yank a few more things before dropping it off the jack stands on to four Harbor Freight moving dollies and then it will be pressure wash time. I am pretty sure I will clean about 10lbs of dirt off the shell!

Almost all of the parts are in (and taking up space waiting installation). The tranny is at Mr. Mazda across the street, diff is off to East Street in Memphis and the motor is being built by Haag Performance in Martinez. Once the shell is clean, it will be painted inside and out a light gray and then everything will be cleaned and we will start bolting parts back on.

First official outing target is the SCCA Double National at Thunderhill in March but I am hoping to get it out a couple of times prior to shake it down. I am focused on Regionals this year so the double will be a good chance to see what kind of overall pace we have. As I search for open track days, I finally have a reason to start using the MotorsportReg.com calendar!

Recently I posted a bounty of $800 and Transfer community members matched me with another $1000 to pay ORM creator Mark Mandel to update the caching system in Transfer. Mark has a branch in subversion with the code and I’ll give you here a quick run through on how to configure and use it. Remember, this is beta code, which successfully passes unit tests, but should be tested in your own environment too.

Get the code

First checkout or export the code from the Subversion branch and replace your current version of Transfer. I’m not going to discuss how to get started with Transfer but rather how to migrate from a working, caching Transfer setup to one that uses EHCache behind the scenes. Pull the code from:

http://svn.riaforge.org/transfer/transfer/branches/pluggable_cache/

Change transfer.xml

In transfer.xml, you’re going to replace your existing <objectCache> stanza with something like this:

<objectCache>
	<defaultcache provider="transfer.com.cache.provider.EHCacheProvider">
		<setting name="config" value="transfer/ehcache.xml" />
	</defaultcache>
</objectCache>

The config value is a relative path that gets passed through expandPath() from wherever you instantiate Transfer. In my case, that’s in the root directory so this refers to a file at /transfer/ehcache.xml.

Configure EHCache

Now create a new file ehcache.xml that will define the caching settings. Whereas this used to live in transfer.xml, it now lives in a separate file (specific to the particular caching implementation, of which EHCache is the first and default):

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<defaultCache
        maxElementsInMemory="1000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="900"
        overflowToDisk="false"
        />
</ehcache>

That’s a good starting point. Up to 1,000 objects will go into one bucket with a 2-minute idle timeout and a 15-minute max time to live. Converting from transfer.xml, timeToIdleSeconds replaces accessedminutestimeout and timeToLiveSeconds replaces maxminutespersisted. If you specify eternal=true, then the timeouts are ignored and the only thing that will cause an object to be discarded from the cache is running into the 1,000 object limit.

Delete all of your *.transfer files from your generated folder and restart your application. You should see it come back up, just like it always has. The difference? No more leaky SoftReferences!

Getting Fancy

Ok, you’re memory-leak free, but so what! You’re demanding! You want whiz-bang! Here’s two things you can explore:

Unique per-class cache settings
In transfer.xml, you could define class-specific settings by simply saying:

<cache class="object.class" maxminutespersisted="1440" />

Now, you’ll instead define them in ehcache.xml:

<cache name="event.event" maxElementsInMemory="2000" eternal="true" overflowToDisk="false" />
<cache name="event.venue" maxElementsInMemory="500" eternal="true" overflowToDisk="false" /> 

So long as the name is a case-sensitive match, then the EHCacheProvider will use those specific settings for that specific class.

Use different providers for different caches
In addition to the default cache we created above, we could also stipulate another (as yet unwritten) caching provider or disable caching altogether for a certain class like this example Mark provided in the google group:

<objectCache>
      <defaultcache provider="transfer.com.cache.provider.EHCacheProvider">
        <setting name="config" value="/test/resources/ehcache.xml"/>
      </defaultcache>
      <cache class="none.Basic"
provider="transfer.com.cache.provider.NoCacheProvider"/>
      <cache class="none.Child"
provider="transfer.com.cache.provider.NoCacheProvider"/>
</objectCache> 

You could imagine another provider, maybe one that uses the new virtual file system in ColdFusion 9, to be used for a specific class. Now that caching is pluggable, the limitations are in your hands! I expect to see a Coldbox cache provider straight away. :)

Caveats

There’s one big deal to watch out for with this new approach. The whole idea of SoftReferences is that they will get garbage collected if they need to, like when you’re running out of memory. This default cache has no such provision. So, if you stipulate the cache can hold 10,000 objects but you only have RAM for 5,000 objects, your server is going to grind to a halt as it runs out of memory and either starts going to disk or throws java.lang.OutOfMemory errors. Either way, not good!

Start small and conservative, see how it performs, and grow from there. Mark is putting the finishing touches on the statistics collector so you’ll be able to generate the same graphs for the cache on usage, hit rate and so forth. Plus, this is beta code! Until then, get this into your development environment and test!

Final Word

Even if things are working fine in your current Transfer environment, this is a worthwhile upgrade. It streamlines a LOT of internal code and leverages a very mature caching system with greater flexibility.

And finally, THANK YOU to the people who matched my contribution. Now we’re all better off as a result!

My last floppy disks These are my last four floppy disks. On them are two of the very first web projects I did with Rob back in 1996 including a copy of our first logo (in PageMaker no less). I also pulled out two dozen journal entries from when I started college in 1994. I’m sure they will make for some hilarious reading this week.

As I say goodbye to these disks though, I want to note how incredible it is that they worked at all. I plopped down a circa-1998 VA Linux Server onto our spare desk, powered it up and read all four disks without a single issue. How much media do you have today that you could open up in 15 years and still read successfully? I have a hard time reading a CD-R 10 minutes after I burn it!

Mad props to you, oh Floppy Disk, for your years of stable storage!