Archive for the 'coldfusion' Category

The Custom Tag Body-Scope

I was working with FlexChart a little this evening and ran into an interesting situation with a potentially very useful solution. I don't claim to be the first to think of it, but it's the first time I've used/seen it.

I added a date preparation tag a while back, but I thought it'd be nicer to have a UDF that you could use instead, when you're building a descriptor inline. What I realized is that for very little effort, you can easily scope variables (UDFs or otherwise) to the body of a custom tag. Here's how it works:

<cfif thisTag.executionMode EQ "start">
  <cfset injectedPrepChartDate = false />
  <cfif NOT structKeyExists(caller, "prepChartDate")>
    <cfif NOT structKeyExists(variables, "prepChartDate")>
      <cfinclude template="udf_prepchartdate.cfm" />
    </cfif>
    <cfset caller["prepChartDate"] = prepChartDate />
    <cfset injectedPrepChartDate = true />
  </cfif>
<cfelse> <!--- end --->
  <cfif injectedPrepChartDate>
    <cfset structDelete(caller, "prepChartDate") />
  </cfif>
</cfif>

First, in the start tag, I (conditionally) add a prepChartDate UDF to the caller scope, and set a variable for whether I did it or not. Then, in the end tag, I delete the UDF if I'd added it to the caller. The part that I've greyed out is only needed because I'm using a UDF; it's a simple don't-double-define-a-function check. In this case, I'm opting to only expose the UDF if it won't conflict with what is already there in the caller scope. It'd be just as reasonable to shadow the pre-existing variable and restore it after the body. This latter approach is basically how Fusebox implements DO parameters, if you've ever used them, though it's mechanism is both far more elaborate and far more flexible.

I've obviously removed everything else from the tag definition. If you want to see the full implementation of xmlchart.cfm (where I used it), you can see it in Subversion (look near the bottom), and/or see it in action on the demo.

New FlexChart Demo

I've updated the FlexChart demo to include display of the descriptor XML that is loaded into the chart, as well as providing a way to edit the XML inline and load your modified XML into the chart client-side.  In addition to being far easier to experiment with, it also showcases the the client-side redrawing of the chart and gives a hit of how powerful the engine can be within a JS UI.

Doing it this way means I lost the demo of having the chart request a new descriptor from the server-side on it's own, but the client-side descriptor injection is a "neater" capability, I think.   I haven't posted an updated zip of the source (including the demo app), but it's available from Subversion at the URL listed at the bottom of the demo.

A Very Wonky Request/CFTHREAD Bug

Found some really interesting behaviour with CFTHREAD over the past couple days of testing.  Put this code into three browser tabs and run them concurrently (so you get three simultaneous requests which you can view the output of).  And ensure you have the CF Server Monitor open in a different window with monitoring enabled and the Active ColdFusion Threads report showing.

<cfoutput>
<cfapplication name="#createUUID()#" />
<cfset request.threadName = createUUID() />

<h1>Request: #timeFormat(now(), "HH:mm:ss")#</h1>
<cfflush />
<cfdump var="#cfthread#" label="cfthread is empty" />

<cfthread action="run"
  name="#request.threadName#">
  <cfthread action="sleep" duration="10000" />
</cfthread>

<cfdump var="#cfthread#" label="one thread running" />
<h1>Thread: #timeFormat(cfthread[request.threadName].startTime, "HH:mm:ss")#</h1>
<cfflush />

<cfif structKeyExists(url, "join")>
  <cfthread action="join" name="#request.threadName#" />
</cfif>

<h1>Complete: #timeFormat(now(), "HH:mm:ss")#</h1>
<cfdump var="#cfthread#" label="thread shows completed" />
</cfoutput>

What happens?  As expected, all three requests return immediately, each having spawned a thread.  The server monitor shows that the threads all go away after ten seconds.  Most importantly, all three requests started, launched their thread, and completed at the same time (+/- a few tens of milliseconds).

Now go to the first tab and add "?join" to the URL, which will trigger the joining of the thread back to the request thread.  Refresh all three tabs again.  This time, the tabs without the join command behave exactly the same, but the tab with the join waits for the thread to complete before returning, as evidenced by the "Completed" timestamp.  This is all correct behaviour, so lets get down to it.

Add "?join" to the second tab (so now two tabs will join), and refresh all three tabs a third time.  Notice that the second tab that joins doesn't even start until the first joining request completes.  The non-joining request completes immediately, as always, initiating at the same time as the first joining request.

I don't even know how to characterize this issue.  It's certainly a bug, but I'm not sure what.  Even more baffling, I can't even come up with a theoretical scenario that would cause these symptoms.  Anyone?

Clickable FlexCharts

I just updated FlexChart with a 'click' callback.  You can now specify the name of a JavaScript function to be invoked when a data point on the chart is clicked.  The function is passed the ID of the chart, the series label, and the x and y values for the point, in that order.  Check the demo (which just pops an alert) to see it in action.

What is this good for, you ask?  Everything that CFCHART's 'url' attribute was theoretically good for, except it's actually useful.  If you wan CFCHART's behaviour, just have your callback do a window.location.  For those of us that don't, you can use the parameters to AJAX in some related content to another section of the page, compute and inject a new descriptor do do "drill-down" within the same chart instance, or any number of other things.  Lots of possibilities.

CFTHREAD/Server Monitor Issue

I was working with CFTHREAD today, and found an interesting bug in ColdFusion.  I'd wager that it's within the monitoring stuff new in CF8, but I can't say that for sure.  Here's the problem:

Creating threads with CFTHREAD makes them appear in the server monitor, but they aren't removed from the server monitor when the terminate unless the monitoring/profiling options are enabled.

To put that another way, threads give the appearance of sticking around forever unless you launched them with the monitoring/profiling options enabled.  I have no idea why this is the case, but it is.  The inaccurate state persists across reloads of the monitor, so the bug is somewhere inside CF, not the Flex app.  Threads that are listed but are actually dead don't have a value in the "Java Thread Name" column, you can identify (and ignore) them in the datagrid view.  The chart view, however, stays polluted until you restart CF.

Critical Bug: Schema Tool

I discovered a critical bug in my schema tool this evening. During the refactoring I did last week to allow multiple persistence mechanisms (so it doesn't require a DB) I reintroduced a bug that I had fixed in the DB-only version.

If the first minor version of a migration (major version) throws an error, it updates the major version counter in the persistent store without resetting the minor version to zero. As such, when you resolve the error and rerun the script, the tool believes that you've already run N minor versions of the migration, where N is the number of minor versions in the previous migration script.

If you've downloaded the tool since the 18th of November, you've got the buggy code, and need to download a freshly patched copy. Subversion is also updated, if that's your preferred source.

As a freebie, there's a new enhancement in the SQL-based migration script for supplying a custom statement delimiter.  Previously you had to use a semicolon, but now you can specify your own.  Check the comment at the top sqlbasedmigration.cfc for more details.

More Flex Chart Goodness

This evening, I extended my Flex charting widget further.  The demo is still available, and I've posted a new ZIP archive of the source.   Here's a quick rundown of what's changed:

  • The custom tag is now called xmlchart.cfm, instead of just chart.cfm.  That's to make way for a different chart.cfm that provides an XML-less interface (like CFCHART does) that will internally build the XML and then hand it off to xmlchart.cfm.
  • Category and DateTime axes are now supported.  The only gotcha is that you must supply a milliseconds-since-epoch value for your timestamps.  It's XML, not real objects, and the serialization/deserialization doesn't work right with native dates.
  • Pie charts are now available.
  • Legend placement is now customizable (top, bottom, left, right, none).
  • Axes can have a title set for them, and they can be positioned on either edge of the chart (top/bottom for x, left/right for y).
  • The descriptor language has changed significantly:
    • The x- and y-axis now have their own element under the chart element.
    • All series and sets are now contained with a new data element under the chart element.
    • There are only series and set elements now, and both take a type attribute for determining what type of series/set they are.  Series implicitly inherit their type from the containing set, if present, otherwise their type must be specified.

At this point, I'm pretty much done developing, and I'm on to using it.  I did one app as a proof of concept and it works great.  I'll be doing some more shortly.

And Happy Thanksgiving, at least for all you US folks.

My Flex-based Chart Engine

I've been looking for a good charting mechanism for a few personal apps.   CFCHART works in some cases, but I usually opt for SVG, either rendered inline (i.e. SVG and XHTML interleaved in an XML doc) or rasterized into a PNG server-side via Batik.  Both solutions have their merits, but both also have a lot of problems (drawing SVG requires a lot of arcane math, and CFCHART is quite inflexible and has a number of bugs).

At work, I've been doing quite a bit of work with the Flex Charting components, and I got to thinking that a generic chart that could be parameterized with both data and structure wouldn't be too hard to build, but never really did anything about it.  Then today Koen, Joshua, and I were talking about something or other and somehow ended up with me mentioning you could inline your MXML with a JSP taglib and have a Flex movie spit out in your page (much as CFCHART does it).  I threw together a little proof of concept, and digging in a little deeper with flashvar parameterization, realized that you could do some pretty sweet stuff with it.

I kept playing a bit, and started building some generic charting stuff, and this is what I ended up with.  It takes a descriptor XML document either as a literal or a URL, supplied via flashvars or via ExternalInterface callbacks, and will draw a chart based on it.  The descriptor is just that, a complete description of the chart to render, both data and structure.  There's a link to the descriptor on the demo page, so you can see it.  The flexibility is pretty limited (for example, you can't disable the legend), but all that stuff would be pretty simple to add down the road.

The engine only supports Cartesian charts, and only numeric data (linear or logarithmic), but that covers the vast majority of charts, at least for me.  It'd be fairly trivial to extend it to support category and/or datetime axes, I just didn't do it.  The non-Cartesian charts (e.g. pie charts) would be a little more work, as they're pretty fundamentally different, but it should be a backwards compatible change (i.e. strictly additive changes to the descriptor language).

I've made a ZIP of the demo app, including the custom tag wrapper and the MXML source.  For the runtime compilation via the JSP taglib, you have to have Flex on your server.  If you've got CF8 with LCDS, you're set.  I'm not sure about other configurations, but I know the JSP taglib has been around for a while, so I'd expect it to work other places as well (though you might need to tweak).

The runtime compilation is not at all required for the engine to work, it's just an easy way to package it because the taglib takes care of generating all the wrapper HTML/JS.  If you don't mind writing that yourself, you can use the SWF directly.

Also, the SWF is compiled with Flex SDK 2.0.1, because that's what CF's LCDS uses.  Among other things, that means you don't get "grouped" ColumnSets, because those are new in Flex 3.  The MXML will recompile as-is with SDK 3 (e.g. in FlexBuilder), and then you'll be able to use "grouped", but the runtime compilation won't do that unless you upgrade the internal SDK.

Schema Tool Update

I've updated my schema tool again, this time with some pretty significant changes.  Quick recap: the goal of the app is to manage your DB schema via managed code, rather than some external process, so you get transparent database upgrade to all environments as part of deploying a new version of your app.  Very handy in production, essential in development.

Here's a rundown of what's new:

  • Multiple tool types are now supported via a new 'toolfactory' CFC.  The original "database" tool has been joined by a new filesystem tool that stores it's version info in a file, rather than a database.  If you want to use the migration infrastructure for something outside a database (like your CF Admin config via the admin API) you can now do it with no database dependency using the filesystem tool.
  • The 'tool' CFC has been deprecated, in favor of 'databasetool'.  Note that with the new multi-tool arrangement, the order of init parameters has changed (since they're now passed to 'toolfactory' not the tool directly), so watch out when you're upgrading.
  • SQL-based migrations (where you use a SQL file instead of a CFC) are now a lot safer.  The original minor version computations made some assumptions about the scripts that were "mostly" safe, but not completely.  I've improved the parsing significantly (reusing some code from the Rhino project) to do string stripping/replacement, and support both — and /* */ comments.
  • This is entirely internal, but the organization of components has been much improved.  There was a lot of non-encapsulation in there originally, but I've fixed most of that, as well as done some more abstraction to get some additional logic reuse, especially across different tools.

Assuming you haven't gone hacking the core, nor subclassed 'abstractmigration' and overridden 'init', you should be able to migrate simply by replacing the line in Application.cfm that runs the tool.  Instead of creating a tool directly and invoking it, you now use the 'toolfactory' to create your tool implicitly, and then invoke it.  The demo app has an example.  It also has an example of a filesystem tool, with separate migration script directories for each tool to manage.

A ZIP is available here, or you can browse the Subversion repository directly.  As always, comments/questions/bugs are welcome and appreciated.

Regular Expression Backreferences and the Non-Greedy Modifier

Update: James Allen caught a formatting bug. It seems WordPress doesn't like my coloring, and when present, swaps the double quotes for "smart quotes". I've removed the coloring, and it seem to be fine again.

Someone posted a question on CF-Talk about using backreferences in regular expression search strings. Not the replacement string, mind you, but the search string itself. This is, as you'd expect, perfectly legal and can be incredibly powerful. While contriving an example, the one I came up with also required the non-greedy modifier, so I'll illustrate both. Here's the code in question (copy it to a CFM file to run it):

<cfoutput>
<cfset baseString = "some 'text' with ""quotes an' some apostrophes"" in it" />
<h2>Quoted Strings within #baseString#</h2>
<ul>
<cfset start = 1 />
<cfloop condition="true">
  <cfset result = REFind("(['""])(.*?)\1", baseString, start, true) />
  <cfif result.pos[1] LT 1>
    <cfbreak />
  </cfif>
  <cfset string = mid(baseString, result.pos[3], result.len[3]) />
  <cfset quote = mid(baseString, result.pos[2], result.len[2]) />
  <cfset start = result.pos[1] + result.len[1] />
  <li>#string# (quoted with #quote#)</li>
</cfloop>
</ul>
</cfoutput>

The backreference (the "\1" at the end of the regex) behaves exactly the same as when in a replacement string: it represents the "stuff" matched by the first clause wrapped in parentheses (in this case, "['""]"). Ignoring the middle part, the regex says find me either a single or double quote, then some "stuff", and then the same quote character.

In the middle is the non-greedy modifier (the "?", after the asterisk). Without it the ".*" would match as much as possible while still allowing the regex as a whole to succeed. In this specific case, the quote would match the single-quote before "text", the .* would match "text with "quotes an", and then the backreference would match the single-quote after "an". That's clearly not what we want, so we use the non-greedy operator to tell the .* that we only want it to match as much as it needs to, not as much as it can. Then it behaves correctly. Try deleting the non-greedy modifier and run it.