Monthly Archive for June, 2008

Comparators in CF with Groovy

I don't know about anyone else, but wanting to create little ad hoc Java classes in my CF apps in a common occurrence for me.  With my CF Groovy project, it's both possible and very easy.  No Java, no compiling, no classloading hacks.

Here's a simple example.  I'm going to create an array of structs and then sort the array based on a specific field value (the 'date' field) of the structs.  Doing this in CF usually means making a lookup struct, sorting that, and then rebuilding the array (but only if you have unique values), or converting to a query and using QofQ to do it.  Both have serious drawbacks, as well as being very circuitous/obscuring.

First the array construction (six items, each with 'letter' and 'date' fields, holding what you'd expect).  Nothing very interesting here.

<cfscript>
a = [];
month = createDate(year(now()), month(now()), 1);
for (i = 1; i LTE 6; i = i + 1) {
    s = {
        letter = chr(65 + randRange(0, 25)),
        date = dateAdd("d", randRange(0, 30), month)
    };
    arrayAppend(a, s);
}
</cfscript>

Now, using the <g:script> tag from CF Groovy, we'll sort it by date using a java.util.Comparator:

<g:script>
Collections.sort(variables.a, {o1, o2 ->
    o1.date.compareTo(o2.date)
} as Comparator)
</g:script>

If you want to compare based on the letter, just change the two ".date" references to ".letter".  You can, of course, make the comparator as complicated as you'd like, including referencing other Groovy classes through CF Groovy's classloading, or other Java classes on your classpath.

You can see it in action at the demo page, or get the full source from Subversion at https://ssl.barneyb.com/svn/barneyb/cfgroovy/trunk/demo/.

Speaking at CFDevCon

I'm pleased to say that I'll be speaking at CFDevCon this September over in Brighton, England. The conference should be a great one: lots of great speakers, lots of great topics, and what should be a great location. They also announced last Thursday that early bird pricing has been extended to the end of the month, so if you haven't got a ticket, now's a good time.

I'll be presenting on two topics at the conference: AOP for ColdFusion with ColdSpring, and leveraging Java from ColdFusion. Both really ought to be "CFML" instead of "ColdFusion"; I expect I'll be using either Open BlueDragon or Railo for the presos, but time will tell.

In related news, I've since learned that the lighthouse in my blog header is about 20 miles (I'm from the US, what do you want?) from Brighton. We'll see if I can swing a trip over there to get a picture of me with it. It's kind of humorous that I'd been using that photo for well over four years without knowing where it was, and now I'm going to be flying half way around the world and end up 20 miles from it.

CF Groovy

Those of you who remember CF Rhino will recognize the name for my latest little project. I whipped up a small proof-of-concept integration for Groovy into CF apps tonight while playing with some classloading issues within Groovy itself.

Groovy has a number of advantages for this type of integration of JavaScript, the biggest one being that Groovy IS Java, and carries Java's semantics almost perfectly. So unlike with Rhino, no major conversions are needed moving in and out of Groovy, which makes things enormously easier. CF still brings it's special blend of "insane" to the party, but it works quite well overall. Definitely has more real-world potential than CF Rhino ever did.

CF Groovy is not a whole framework like CF Rhino was, it's really just a proof of concept for integrating the two together and sharing resources. You can get the demo (which includes the engine via svn:externals) from Subversion at https://ssl.barneyb.com/svn/barneyb/cfgroovy/trunk/demo/. Just check it out to a directory named 'cfgroovy' in your webroot, drop the groovy JAR from the 'groovyEngine' subdirectory into your /WEB-INF/lib folder, and you should be done.  You can see it in action at the demo page, though without source to browse, it's not very interesting.

Also, unlike CF Rhino, there's no dependencies on the internals of ColdFusion (the Adobe product). To do some of the bridging to JavaScript, I had to invoke internal APIs of ColdFusion, so it wouldn't run on BlueDragon, Railo, etc. I built CF Groovy with Open BlueDragon and Railo 3 on Tomcat simply because I didn't have a CFML runtime on my box, and CF is like 400MB while oBD is 11MB and Railo is 25MB.

Unfortunately, all three runtimes have bugs that prevent them from working as expected.

Railo was the worst: it has some recursion issue with the JEE.include() call. It also doesn't seem to implement java.util.Map with it's struct implementation, and throws on missing keys rather than returning null.

Open BlueDragon initializes ResultSets from manually assembled queries (and possibly "real" queries) with the row pointer pointed at the first row, rather than before the first row as the spec says it should be.

ColdFusion doesn't create java.util.Date objects with the createDate built in, so trying to call ResultSet.getDate() throws a ClassCastException. Using ResultSet.getObject() and letting the ducks work their magic fixes this issue. It's also 15-35 times larger than the others.

Except for the download size issue, I've got conditionals to cover all the cases in the app, so it should be checkout and run on all three platforms. I haven't tested NA BD, CF7-, or Railo 2. I don't know why they wouldn't work, though, since I'm just doing standard Java stuff. I'm not doing any version conditionals, only platform ones, just in case.