CF9 ORM TransactionAdvice

As with any new persistence technology, CF9's ORM functionality has necessitated porting my TransactionAdvice for ColdSpring.  The previous "CFML" version was really "CFML/SQL/ORM" and is still the way to go if you're not using ORM functionality.  The new version (cf9ormtransactionadvice.cfc) is specific to ORM applications on CF9.0.  It will not provide transactionality for SQL-based apps as it piggybacks on Hibernate's transaction layer, not the underlying JDBC one.

With CF9, Adobe made a rather fundamental flaw in the transaction implementation around ORM (which they've fixed, by the way) because a transaction (CFTRANSACTION or the new transaction block in CFSCRIPT) would close the current Hibernate session and then open a new one.  This made dealing with transactions hugely problematic because you'd constantly be left with detached persistent instances that you wanted to lazy load a relationship on but couldn't because the session had already been closed.  The solution is either to use entityMerge everywhere or skip the CFML transaction demarcation and use Hibernate's directly.  The latter is how the transaction advice works.

The mechanism is identical to the other versions, though this one is a bit simpler because CF9 finally grew a CFFINALLY tag!  Yay!  It also supports conditional logging of the transaction boundaries which, when combined with this.ormsettings.logSql = true, can assist greatly in debugging transaction problems.  But the gist of it is really simple and uninteresting, excatly the way transaction demarcation should be.

When the new session stuff is released for public consumption by Adobe, using the existing generic CFML/SQL transaction advice will be a better alternative to this.  It is useful for both ORM and plain SQL applications, and can even be used to properly protect hybrid apps where you use a mix of ORM and raw SQL queries.  The CF9 ORM version only does ORM.

And don't forget to disable flushAtRequestEnd.

CF9 ORM and CFGroovy

As I've stated at various times and places, CFGroovy 1 (with Hibernate integration) has been superceded by the ORM functionality now available in ColdFusion 9 and soon to be available in Railo 3.  It has never been my intention to compete with the CFML vendors in the Hibernate space – without access to the engine internals there is simply no way I can do as good a job as the vendors.

As of today I am officially declaring CFGroovy 1 abandonware.

I still use CFGroovy 1 on a couple personal projects and at Mentor (where I work) we run our entire service tier on CFGroovy 1.  So it is by no means unsuitable for production deployment, but no new development should take place on it.  It does not run on CF9 without modifying your CF9 installation, and the same will be true of Railo when it supports Hibernate as well.  So you should assume that if you're upgrading a CFGroovy 1 application from CF7/8 to CF9, part of the upgrade process will be converting to CF9 ORM.  This is not nearly as difficult as you would expect – Groovy beans directly translate to persistent CFCs and your Groovy business logic can be encapsulated with CFGroovy 2 scriptlets.  Existing scriptlets (and non-persistent helper classes) should transfer without any modification.  The only exception is that CFGroovy 2 does not provide the concept of a Groovy classpath, but that's typically only required for entities.

CFGroovy 2 is not affected by this; it is alive and well and will continue to be supported, developed, and widely used for a long time.  As well as being all kinds of useful, it is a crucial part of upgrading CFGroovy 1 applications.

From this point on the term "CFGroovy" will refer specifically to what has until now been called CFGroovy 2.  The Hibernate integration is the only reason anyone should be using CFGroovy 1 as CFGroovy is superior in every way when you're only looking for scriptlet support.  It provides not only a richer environmental binding, it also supports arbitrary JSR-223 languages, will transparently bootstrap Groovy (via JavaLoader) if it's not on your classpath, provides hooks for CFML ORM (CFML, not just CF9) integration, and works in a significantly more streamlined and efficient fashion.

Goodbye ColdFusion, Hello Railo

I've been working towards this for quite some time, and last night I finally replaced ColdFusion with Railo on my personal server.  By and large the switch went flawlessly.  I made a few compatibility changes ahead of time and found and fixed a few issues subsequently, but really smooth overall.  Even better, the memory footprint is significantly reduced with Railo, and I'm always memory constrained.  I'll run through the migration process and the issues I had in a moment, but first a couple memory charts:

Conversion, as you might imagine, happend right about 20:30.  The jaggies you see on the MySQL line are from me manually reducing and then reincreasing it's memory caches.  I wanted to make sure it was mostly out of the way while I was converting, and willing to pay a little performance to get it.  Unfortunately it makes the charts a little dirtier, but oh well.

The actual migration process was really simple.  I spun up a Railo instance on my home computer, configured the server settings, set up my DSNs and mappings, and then shut it down.  Then I stopped Tomcat on my production server, moved the WEB-INF folder out of the way, rsynced up Railo's WEB-INF from my home machine to take it's place, and restarted Tomcat.  Done.

As for the CFML itself, I ran into a very small number of distinct issues, though they manifested in different ways:

  • Railo doesn't support the column-as-array notation for queries that ColdFusion does (e.g. arrayMax(query["column"])), which I had used extensively in building Google Charts.  Fortunately they expose valueArray to compliment valueList, as well as supporting a string (static or dynamic) rather than just the reference (all CF allows).  This change made most of the instances cleaner, though you have to use a temp variable if your query isn't in an implicitly referenceable scope or nested within a complex structure, because the string must two-part.
  • Railo doesn't support escaping keywords in queries of queries.  Fortunately it's not as anal about keywords (e.g., allowing "get"), but if you want to alias a column to "count", you're screwed.  Interestingly, you can happily select from a column named "count", just not alias to it.  It also has some weird issues when combining aggregation and union on timestamp fields (they get truncated to dates).
  • Railo arrays don't support the .subList method from java.util.List.  It's implemented, but is hard coded to throw a RuntimeException.  I beat this via a subList UDF:
    <cffunction name="subList" output="false">
      <cfargument name="a" />
      <cfargument name="s" />
      <cfargument name="e" />
      <cfset var aa = [] />
      <cfset var i = "" />
      <cfloop from="#s + 1#" to="#e#" index="i">
        <cfset arrayAppend(aa, a[i]) />
      </cfloop>
      <cfreturn aa />
    </cffunction>

    It doesn't carry the same semantic as List.subList (which returns a view of the original list, not a new list), but for my purposes it was sufficient.

  • Inline CFMAILPARAM attachments that use a contentId must have the id manually wrapped with angle brackets as Railo doesn't do the wrapping for you like ColdFusion does.  Easily fixed, though this one was actually caught by an end user.  Oops.
  • "url is not a valid unscoped variable name as Railo assumes it means the url scope.  You must either qualify it with a scope, or avoid the name.  "cluster" has the same problem.  As you might imagine, the url-scraping acquisition and cluster-based prioritization of PotD made these two names quite common, so I had to fix a lot of instances.  But it was my fault for being lazy and not scoping to begin with.
  • Railo respects and enforces an "abstract" attribute on CFFUNCTION that requires the body to be empty (just like CFFUNCTION within CFINTERFACE).  I use an "abstract" attribute frequently for metadata inspection, but always implement the method with a single CFTHROW tag (since CF doesn't understand abstractness).  The error message Railo generates is misleading ("cannot nest CFTHROW within CFFUNCTION" rather than "abstract functions cannot have a body"), but once I figured out what the issue was fixing it was simple.
  • imageSetDrawingColor accepts three comma-seperated decimal values (e.g., "128,128,256″ for a blueish hue), but Railo does not.  Easily fixed with formatBaseN.

All in all, a pretty transparent migration.  I'm quite pleased.  And now I'm in a position to get CFML-based ORM without having to fork over the $4,000 to upgrade to CF9, which is a big win for me.  I'm sure little stuff will probably crop up over the next week or two, but all the major pieces (and all the minor bits I checked) seem to have worked flawlessly.

BEWARE: Impending Sporadic Brokenness

Tonight I'm switching from my CFML from ColdFusion 8 to Railo 3.1.2.010 (bleeding edge).  So starting here in a couple hours there is undoubtedly going to be broken stuff.  Pic of the Day, of course, is the primary focus of the upgrade and I've already done extensive testing of that codebase on Railo so it should come across without issue.  Other than that, however, I've tested virtually none of my active CFML on Railo, so it'll be a bit of an adventure.  Fortunately, nothing I run is mission critical, so this sort of ad hoc approach should serve reasonably well.  I wouldn't recommend this technique without careful consideration.

So.  There's your warning.  Hopefully all will go well and within an hour or so I'll have vetted the various microapps to ensure all is well, and fixed any issues that come up, but we shall see.

CF9 Compatibility for FB3Lite

I just made another minor tweak to FB3Lite to fix out-of-the-box ColdFusion 9 compatibility.  CF9 added a 'location' built-in function, which means that the function of the same name that FB3Lite provides now generates a compiler error.  Fortunately, since functions are real data within CFML, a simple realiasing gets around the issue.  This creates a subtle compatibility issue, but better than having to delete the UDF manually.

If your CFML engine does not provide a location function, FB3Lite will ensure one is available for you (simply wrapping CFLOCATION).  This has been the behaviour since the beginning.  Now, if your CFML engine does provide a location function, FB3Lite will still provide one in the variables scope (in case you're doing dynamic evaluation of it), but the engine-provided one will be used for static references (the typical case).

In general, this shouldn't matter to anyone; it's still just download and go.  The issue I alluded to above has to do with the optional parameters that CF9 provides (addToken and statusCode).  Since static invocations will use the built-in function, those optional params will be available on CF9, but will not on platforms that rely on FB3Lite's version.  Eventually I'd expect all CFML engines to provide a location function in which case there will no longer be a discrepancy, but for the meantime, if you're using multiple platforms, you'll need to ensure you're not using the optional parameters with the location function.

And before you say it, adding the parameters to the FB3Lite-provided function isn't an option, because CFLOCATION doesn't support statusCode until ColdFusion 8, which means you'd get compiler errors on CF7.

As always, the source is available, or you can check the project page for the latest info and updates.

FB3Lite appSearchPath Supports Mappings

Piggybacking on the change to allow mappings in do/include, you can now use mapping-relative paths in the appSearchPath initialization variable as well.  Before you had to use a relative path, which got a little hairy when you had a deeply nested structure:

<cfset appSearchPath = "../../../myApp" />
<cfinclude template="../com/barneyb/fb3lite/index.cfm" />

But now with mappings, you can simplify things, even if you're just using the webroot:

<cfset appSearchPath = "/myApp" />
<cfinclude template="/com/barneyb/fb3lite/index.cfm" />

This is exactly the same functionality I added to do/include.  The difference is that the top-level fuseaction is invoked via an internal call to do() which is based on appSearchPath instead of a circuit prefix.  But now both are equivalent again.

As always, source is available, along with the project page with current information and downloads.

Simple CSS Tabs

I use tabs for navigation a lot.  Not for in-page DOM swapping, but for expressing a list of available pages along with indicating which on you're on.  Pretty much every tab "system" is centered around client-side manipulation, rather than just presenting server-generated markup.  And the few counter examples don't do it in an encapsulated way, they use a body selector, tab-id-specific styling, or whatever.  What I really wanted was to simply emit a UL with some LIs inside (one of them with class="active") and be done.  No muss, no fuss.

After faking it with ad hoc CSS in a number of apps I decided it was time to actually make a concerted effort to build a reusable mechanism for doing this.  So I did.

You can get the code as well as a demo and docs at http://www.barneyb.com/r/css_tabs.cfm.  Included is a form for customizing the colors and sizing of the tabs (since some of the values are used in multiple directives), and the CSS is emitted at the bottom (as well as into the document itself for styling the demos).

Note that this is not designed to be the be-all and end-all CSS tab solution.  It is designed to be a really lightweight and easy to use CSS tab solution.  Emphasis on simplicity.  Disemphasis on edge cases, backwards compatibility, and bells and whistles.  Firefox 3+, IE8+, and Chome all do fine.  I didn't test others.  IE7 and less fail spectacularly (though the navigation remains totally usable).  And mind your !DOCTYPE.

Finally, since I'm deliberately only styling the UL and LI, you can put whatever you want inside the LIs.  I'm already using this layout on a number of apps and while most have simple As inside the LIs, some of them are using icons and/or icons and text.

I don't know if that's useful to anyone else, but since it's been so helpful for me, I figured I'd share.

Tag-Based HQL Queries on CF9

I'm sure I wasn't the only one that was sorely disappointed when Adobe released CF9 without the ability to execute HQL queries via the CFQUERY tag.  Using a function (ormExecuteQuery) works, but it's really ungainly if you have complex – or even just long – HQL or need to build your statement conditionally, and you can't get syntax highlighting/code completion.  Being one to solve the Hibernate problem myself (I've been using Hibernate on CF8 for years via CFGroovy), I wrote a couple really simple custom tags to give me the functionality.  Pure CFML, 14 lines total.  Yes, 14 lines.

First, the query tag:

<cfif thisTag.executionMode EQ "start">
  <cfset params = [] />
<cfelse>
  <cfset caller[attributes.name] = ormExecuteQuery(
    thisTag.generatedContent,
    params,
    structKeyExists(attributes, "unique") AND attributes.unique
  ) />
  <cfset thisTag.generatedContent = "" />
</cfif>

And then the queryparam tag:

<cfif thisTag.executionMode EQ "start">
  <cfset arrayAppend(getBaseTagData("cf_query").params, attributes.value) />
  <cfoutput>?</cfoutput>
</cfif>

Wheee!  And here's how you might use them:

<cfimport prefix="h" taglib="/tags/hqlquery" />
<h:query name="policies">
  from FtoPolicy
  order by effectiveDate
</h:query>
<h:query name="emp" unique="true">
  from Employee
  where username = <h:queryparam value="#attributes.username#" />
</h:query>

Note, in particular, that I support a 'unique' attriute on query which behaves exactly like the 'unique' argument to ormExecuteQuery returning a single entity instead of an array of entities.

Pic of the Day Minicards

I always get lots of questions about my Pic of the Day minicards, so I made a page on the PotD site with info about them both in general and the individual runs.  As always, NSFW.

The minicards are the only actual "marketing" I do for PotD aside from occasionally link to it so it can get indexed by search engines.  And it hardly counts as marketing, though after distributing some I do typically see an uptick in subscriptions.  The real objective is to provide a slick and tangible item to start conversation, and the cards shine at that.

What's been very interesting to me is that no one hands them back.  You'd think that if you handed someone a piece of cardstock with a naked picture on it that some people would refuse.  But that's not been my experience at all.  Some people have an obvious aversion to the concept of pornography (though whether it's a facade or not is a different question), but naked or not, the cards always prompt a "what is Pic of the Day?" not a "I don't want this."  And not one person has ever terminated the conversation because of the nudity.

Yes, my sample is not representative of the general population.  My friends and associates are certainly a younger and more liberal (or at least open-eyed) segment.  And I don't mean "liberal" as in political bent, but rather in a broader sense.  Despite this, it's still an interesting outcome.  The project – which is coming up on it's sixth birthday – has proven a nearly unending source of interesting bits and pieces.

Minor FB3Lite Feature

If you've used FB3Lite, you may or may not know that it implicitly supports a Fusebox-like circuit structure.  Both do() and include() allow you to invoke fuseactions/templates from other directories within your application, though without the circuit aliasing abstraction layer that Fusebox provides.  This is a great way to break down large applications into multiple sub sections, or relate multiple separate applications into a single URL space (especially combined with URL rewriting).

The new feature is the ability to dereference directories with webroot/mapping relative paths (e.g., /mapping/dir/file.cfm).  Until now, only relative paths (to the current circuit) were allowed, as they were always prefixed with the current circuit's path.  But now if you start a do/include path with a slash, it'll be assumed a webroot/mapping relative path and be used as-is.

As you'd expect, there is a corresponding 'allowMappedCircuits' settings variable that can be used to disable this behaviour if your application requires the old-style behaviour (of leading slashes being ignored).

The newest version is available here, or look to the project page for links to the demo app, a history of revisions, and any new info that might come up.