Archive for the 'cfml' Category

CFML Request Parameters

If you've worked with ColdFusion (or CFML) for very long, you've probably noticed that CFML's treatment of request parameters is a little unorthodoxed.  Specifically, it doesn't differentiate between multiple instance of the same parameter being passed.  Consider this url:

page.cfm?a=1&a=2&a=3,4&b=5

As you can see, there are three instances of the 'a' parameter, one of which has a value that contains a comma.  In CFML-land, you're going to get a single value:

url.a == "1,2,3,4"

Uh oh.

Fortunately, the Servlet Specification comes to our rescue.  You can use getParameterValues on the ServletRequest object to get back an array of values:

getPageContext().getRequest().getParameterValues("a") == ["1", "2", "3,4"]

For a more complete series of examples, check out http://barneyb.com/r/params.cfm.  Note that the Servlet spec doesn't differentiate between query string and POST parameters, while CFML does (via the url and form scopes).  If you ask me, however, you shouldn't either.  They're all just parameters - treat them as such.

ColdFusion Struct Literals Are Not Thread Safe (CFML Ones Are)

If you read my blog regularly or follow me on Twitter, you know how much I hate Adobe's quasi-implementation of struct (and array) literals.  I'm really hoping "third time's a charm" and CF9's implementation is sane.  The gripe is that this code:

<cfset s = {
  name = "barney",
  age = 29
} />

is executed as if it were written like this (on Adobe ColdFusion):

<cfset s = structNew() />
<cfset s.name = "barney" />
<cfset s.age = 29 />

The "correct" behaviour is to execute it as if it were written like this (which is how Railo does it):

<cfset temp = structNew() />
<cfset temp.name = "barney" />
<cfset temp.age = 29 />
<cfset s = temp />

This lets you write some really nasty code, causes some weird bugs, and today I realized (through some handy errors on our production cluster) that there are thread safety issues as well.   Consider this code (inside a getCacheForKey() method):

<cfif NOT structKeyExists(key_stats_cache, key)>
<cflock name="getCacheForKey.#key#" type="exclusive" timeout="1">
<cfif NOT structKeyExists(key_stats_cache, key)>
  <cfset key_stats_cache[key] = {
    getCount = 0,
    staleGetCount = 0,
    missCount = 0
  } />
</cfif>
</cflock>
</cfif>

If the struct literal were an expression, this code would be thread safe, because the assignment to 'key_stats_cache[key]' would be atomic.  However, because of the way ColdFusion implements it, it's not thread safe.  It's possible to have the existence checks trigger in a second request while the struct is building in the first request, and therefore some keys will not be present after the outer </cfif> tag of a second request.  Wrapping the outer <cfif> tag with a read-only CFLOCK will address the issue, of course, but if struct literals were implemented as expressions (the second behaviour above), the problem could never manifest itself.  So watch out!  Atomicity of assignment statements is not assured.

Riddle Me This, CFLOOP

Take this simple loop:

<cfloop from="1" to="10" index="i">
  #i#<br />
  <cfif i EQ 3>
    <cfset i += 3 />
  </cfif>
</cfloop>

What is the output?  My answer is the numbers 1-3 followed by 7-10.  But I was dismayed to learn this evening that it doesn't seem to be the case on my server.  There it outputs 1-10 with no breaks.  Can someone please confirm that this is NOT normal behaviour?  I'm running CF 8,0,1,195765 on x64 CentOS 5 (kernel 2.6.18-128.1.6.el5) with 64-bit Java 1.6.0_13.

Update: Clearly I'm just retarded.  It works this way on Windows, on Railo, and everyone else confirms this is known behaviour.  Somehow I've gone 10 years without running into this issue, probably because I always revert to CFSCRIPT when I do "weird" looping.

That syntax above is analogous to collection iteration (in Groovy):

(1..10).each { i ->
  println(i)
  if (i == 3) {
    i += 3
  }
}

It is NOT analogous to this for loop (also in Groovy):

for (i = 1; i <= 10; i += 1) {
  println(i)
  if (i == 3) {
    i += 3
  }
}

Weird.

Shoot the Engineers

About a week ago, Marc Funaro wrote an interesting blog post about CFML and OO.  The prevailing opinion (via Twitter, blogs, etc) is that Marc is incorrect/inaccurate/inexperienced/whatever, and I disagree completely.  He hit the nail on the head.

HTTP is a stateless, request-response environment.  Nearly all web applications interface with a SQL database, which is also a predominantly stateless request-response environment.  Those are orthogonal to the core OO principle of interacting stateful objects.  It's far closer to the FP (functional programming) paradigm, but particularly on the SQL side, still doesn't match completely.

To use OO in a SQL-backed web app, you hide the mismatches with ORM, an object-based Front Controller implementation, and session facades.  As Marc points out, Java works pretty well in this paradigm for two main reasons:  Java is crazy fast, and Java developers have invested ridiculous amounts of effort in tooling to support this model.  CF has neither of these advantages.  I'm not belittling the effort poured into various frameworks (Fusebox, Model-Glue, ColdSpring, Transfer, etc.), just that they are significantly behind what is available to Java developers.

Unlike Marc, I happen to think that a Front Controller framework is essential, but I don't use a OO one for exactly the reasons he outlines.  I build FB3lite for just this purpose: 70 lines of straightforward procedural code that help me enormously with certain common tasks.  I often masquerade my apps as standalone pages with mod_rewrite (converting /viewUser.html into /index.cfm?do=viewUser), but that's a cheat.

I also use CFCs  and ColdSpring for my business tier, but no object (domain) model for me.  The CFCs are really just glorified function libraries that I can use ColdSpring's AOP engine to wrap transactions around without having to manage them explicitly in my code.  In order to get the AOP I have to use CFCs, and I like the namespacing they provide (so I can have a 'doThing' method in multiple namespaces without conflict), but there is no real OO-ness there.

I know what you're saying.

Yes, I often preach the benefits of OO and encourage people to learn about it and use it.  But using a howitzer to hunt mice in your garage is not a clever idea.  If I'm writing Java (or Groovy), I'm going to use OO structures, but that's because of the programming environment.  I am a pragmatic person.  I like to learn about a wide array of tools and then use as few of them as possible, knowing that there are other options available if I need them.

Yes, built CFGroovy with Hibernate support so I could use ORM in my CFML apps via Groovy objects.  It provides the best of both worlds, the speed and tooling of Java in a CFML environment.  That approach works quite well, but if I don't need the complexity, I'm not going to do it.

My First cf.objective()

I know I'm late to the "cf.objective() recap" party, but I've been both crazy busy and rather tired, so I haven't got to it until now.

First, I'd never been to Minneapolis before, and from the little I saw, it's a pretty nice place.  Obviously I missed the "buried under snow" part, and that definitely puts a damper it as a potential home, but I liked it.  Very walkable, clean, and aside from the second-story causeways between the buildings, a nice asthetic overall.  The hotel was in a great spot, with a pretty varied selection of dining an drinking establishments within easy walking distance.

Before I got there, I hadn't quite internalized how small a 200-person conference actually is.  "Social" is a skill I didn't inherit from my father, unfortunately, but with the number of people I knew already, I didn't feel nearly as isolated as I often do at CFUNITED (which is five times the size).

The sessions were pretty good, over all.  I didn't get to go to several that I would have liked to because of scheduling, but c'est la vie.  Here's a rundown of the notable ones I attended:

Adobe's keynote the first day was interesting, and I might be mixing it in with some other Adobe presentations, but quite fascinating to see crowd reaction to certain Centaur features.  CFFINALLY and CFCONTINUE?  Nothing.  It should be noted that I was the only one to applaud them last year at CFUNITED.  Remote diff of server configuration?  Huge applause.  WTF?!?  Script your production environments, people.  If they're ever out of sync, you're doing your job wrong.   ORM stuff got much applause, of course, and rightfully so.  Drag and drop, full-stack scaffolding also did.  Do people actually use that?  Great marketing/sales tool, no question, but for actual applications?!?!  But I digress…

Marc Escher's talk on unit testing was quite interesting, I thought.  I've tried numerous times, with numerous technologies, to really embrace unit testing and failed every time.  Actually had the best luck doing it with Flex, which just drips with irony.  I'm not predicting success next time I attempt it, but I'm confident I'll do better than last time.  On a similar vein, Sean Corfield's talk on cf.spec provided some nice pointers.  I'm not too sure about the "readable" spec document concept, but an interesting technique.  Until you can have exactly one spec document, I'm not sure of the utility, but I think that's really an editor/syntax problem, not a conceptual one.

Mark Mandel's intro to Transfer was quite interesting as well.  That I attended might surprise you if you're familiar with the various Hibernate projects I've worked on, but ORM is still voodoo in my mind.  Coming back to the basics and being "introduced" to ORM from the ground up is always interesting, because the subtleties in interpretation provide a great introspective of ORM as a whole.  The odds of me picking up Transfer and using it on a "real" project are pretty small, but I didn't go to learn about Transfer in particular, more about ORM in general.

Let me be clear on this, Transfer is amazing.  It does things with CFML that I would have sworn were impossible, and does them fast enough to be perfectly servicable.  It's just not the tool that fits my style.  I've been a Hibernate user for many years, and that's a hard framework to supercede.  Honestly, I bet I'll never replace Hibernate with another ORM solution, but instead replace it with an alternate approach (an object database, for example).

As you might expect, I also went to Adobe's talks about the new ORM functionality coming in Centaur.  When I first was exposed to their Hibernate implementation, I was pretty skeptical.  There seemed to be a global misunderstanding of both the technology and the problem it was design to solve, but that has turned around 180 degrees, and Centaur looks to have pretty robust ORM capabilities.  I've got a major bone to pick with how Adobe is marketing the functionality, but the actual implementation looks pretty sound.  It's hard to get a complete picture with the pre-release secrecy, but I'm a lot more excited about it than I was 6 months ago.

Even more exciting is what will hopefully be coming out of Railo/JBoss in the coming months.  There's been no formal talk of what that looks like yet, and it's probably a safe bet that it'll be similar to ColdFusion's implementation (for obvious reasons), but with Railo and Hibernate both under the JBoss umbrella, I think there's some cool stuff on the way.  Obviously any speculation is just that, but with Railo supplanting ColdFusion in a lot of places I use CFML, I'm understandably excited about it.

The last session was Adam Haskell's talk on mentoring and code review.  That is a misnomer of a title, if you ask me, because while he did talk about that stuff, the point was really about team dynamics.  Working on a team is hard.  Working in a "get things done" environment only makes it worse.  Fostering the team, particularly around helping junior developers move up in the world, takes time and effort, but it's worth it.  I think Adam did a good job of emphasising that any sort of formal process is less effective than an equivalent informal process.  Informal is inherently more personal, and with the typically sterile world of technology and computers, the "personal" stuff is really important.

Of course, the big draw of any conference (though the hardest to justify) is the meals/drinks/etc. that happen outside the actual conference.  (It seems like I just said the same thing two sentences in a row, completely by accident.)  With the conference as small as it was, the informal socialization was a lot tighter, I though.  Far less spreading of groups, and so more churn within them.

I also really liked the way they did lunch, with actual table service, rather than a buffet.  With a more formal meal, you end up sitting and talking with fewer people, but for a longer period of time.  Aside from fostering more involved conversation, it also provides a nice break from the chaos to resettle for the afternoon.

Talking with other developers is always fun, and typically the source of the best tidbits of information.  I always like learning about stuff, even if it has no direct applicability, because it gets you mind thinking in ways it otherwise wouldn't.  And it seems to happen pretty often that 6 months down the road one of those random bits of information suddenly because fairly relevant.  Maybe not directly, but at least opens my eyes to some potential approach I wouldn't have otherwise considered.

Great conference, overall.  I gotta hand it to Jared and his team.

Minor FB3lite Update (and a Weird CF Bug)

This evening while adding some reporting to PotD (NSFW, OMM) to help nail down some performance issues that I think are Apache's fault, I noticed a strange issue with FB3lite.  If you've used it, you know the core of the "framework" are the do() and include() UDFs.  Both contain a CFINCLUDE tag, and a weird situation arises with scoping.

CFML has implicit scope traversal, so if you have an unscoped variable, it will automatically traverse across a bunch of scopes until it finds one with the right name.  Further, you get an implicit local scope within UDFs, and you get a magic psuedo-scope within query-based CFOUTPUT and CFLOOP tags.

What I noticed was that looping over a query with a column named "template" always displayed the currently executing template, instead of the value from the query.   No worries, I thought, since prefixing it with the query name solved the issue.  "template" isn't a common query name for me, so while it surprised me I'd never noticed or heard about this magic "template" variable before, I didn't think too much of it.

Then a while later I realized it was my own fault, because of the include() UDF in FB3lite.  The argument to the UDF is named "template", and CFML places the implcit local scope at the top of the heap, including above the magic query-loop scope.  That argument was shadowing my query variable.

I've fixed FB3lite to use a prefix on all it's UDF arguments, so this problem cannot manifest itself anymore.  Well, I suppose it could, but you'd have to have a weird-ass variable name (e.g., "_fb3lite_template").  You can download the latest version, or pull it from Subversion.

CFGroovy And Script Output

One final CFGroovy update for cf.objective() 2009, and then heading to a plane.

In the first version of CFGroovy output generated by your script was discarded.  This fit the original concept behind scriptlets well, but it made debugging kind of a pain, because you had to exit the script in order to dump out any state.  With the CFGroovy2 implementation, output from your script is passed off to the normal page output, just as you'd expect.  The demo (source or output) now showcases this using in-script emission of the list that it builds, rather than CFDUMPing it between scripts.

CFYourFavoriteLanguage (Formerly CFGroovy)

CFGroovy grew some wings this afternoon.  It retains it's core functionality of running Groovy code in a CFML environment, whether you have it installed on your classpath or if it's transparently loaded from the local copy of the JAR.  However, it now supports any JSR 223 scripting language as well (assuming you're on a 1.6 or newer JVM).  Of the various choices, Groovy seems the best fit for CFML developers (hence the focus on this language), but I also tested Python (via Jython) and PHP (via Quercus).

Of the CFML engines, Railo 3.1 was the champ, running all three guest languages flawlessly.  ColdFusion 8.0.1 refused to run the Python example, not really sure why.  Open BlueDragon refused both Python and PHP.  All three run Groovy, of course, even with the conversion to use the JSR 223 interface (for consistency) instead of the "normal" GroovyClassLoader interface.

You can access any installed languages via the new 'lang' (or 'langauge') attribute; Groovy remains the default, of course.  Here's an example for PHP:

<g:script lang="php">
<?php
  $variables["myArray"][] = "it's some PHP";
?>
</g:script>

The empty brackets mean "create a new item at the end", so that line appends a string to the named array.

Latest mods are in Subversion, of course.

More CFGroovy2 Goodness

Last night at dinner I was talking with Mark Mandel and Luis Majano and realized I'd completely misunderstood the way JavaLoader worked based on my initial look see.  So for the price of 21 additional lines (nine of which are purely for misbehaving CFML runtimes), CFGroovy will transparently load an internal copy of Groovy if it can't find one on the classpath.

I've created a branch in Subversion to house the new version at https://ssl.barneyb.com/svn/barneyb/cfgroovy/branches/cfgroovy2/engine/.  It's organized the same way as the trunk, so there is a ../demo/ directory that contains a trivial demo application.  Here's the demo template, so you can get a feel for how easy CFGroovy is to use:

<cfimport prefix="g" taglib="engine" />

<cfset variables.myArray = listToArray("barney is tall,CFML is taggy,Groovy is AWESOME!") />

<cfoutput>
<h1>Inline Groovy</h1>

<p>This demo creates an array of strings, CFDUMPs it, uses some inline
Groovy (via <code>&lt;g:script&gt;</code>) to add a few more, and
then CFDUMPs it again.
</p>

<h1>Only Three</h1>
<cfdump var="#variables.myArray#" />

<g:script>
// better add emery
variables.myArray.add("emery")
// and some other stuff, using some other syntaxes
variables.myArray += "CF Runtime: " + server.coldfusion.productname + " " + server.coldfusion.productversion
variables.myArray << "User Agent: " + cgi.http_user_agent
</g:script>

<h1>There we go!</h1>
<cfdump var="#variables.myArray#" />
</cfoutput>

CFGroovy in Forty Lines

It's been a couple months since I've done anything with CFGroovy.  I've been mulling how to get back to the essence, which is Groovy scriptlets in CFML.  Today at cf.objective() I put my fingers back on the keyboard for the first time.  Here's a full implementation of the <g:script> tag in 40 lines.  There are no bells and whistles, and no Hibernate support, just scriptlets.  But it's production worthy.

<cfsilent>
<cffunction name="getBinding" access="private" output="false" returntype="any"
  hint="I build and return the Binding for the GroovyScriptEngine.">
  <cfargument name="variablesScope" type="struct" default="#structNew()#" />
  <cfset var binding = createObject("java", "groovy.lang.Binding").init() />
  <cfset binding.setVariable("variables", variablesScope) />
  <cfif isDefined("url")>
    <cfset binding.setVariable("url", url) />
  </cfif>
  <cfif isDefined("form")>
    <cfset binding.setVariable("form", form) />
  </cfif>
  <cfset binding.setVariable("request", request) />
  <cfset binding.setVariable("cgi", cgi) />
  <cfset binding.setVariable("pageContext", getPageContext()) />
  <cfif isDefined("session")>
    <cfset binding.setVariable("session", session) />
  </cfif>
  <cfif isDefined("application")>
    <cfset binding.setVariable("application", application) />
  </cfif>
  <cfset binding.setVariable("server", server) />
  <cfreturn binding />
</cffunction>
<cfif thisTag.executionMode EQ "start">
  <cfif NOT structKeyExists(server, "cfgroovy.groovyLoader")>
    <cfset server["cfgroovy.scriptCache"] = createObject("java", "java.util.HashMap").init() />
    <cfset server["cfgroovy.groovyLoader"] = createObject("java", "groovy.lang.GroovyClassLoader").init() />
  </cfif>
<cfelse><!--- executionMode EQ "end" --->
  <cfset body = trim(thisTag.generatedContent) />
  <cfset thisTag.generatedContent = "" />
  <cfif NOT server["cfgroovy.scriptCache"].containsKey(body)>
    <cfset server["cfgroovy.scriptCache"].put(body, server["cfgroovy.groovyLoader"].parseClass(body)) />
  </cfif>
  <cfset script = server["cfgroovy.scriptCache"].get(body).newInstance() />
  <cfset script.setBinding(getBinding(caller)) />
  <cfset script.run() />
</cfif>
</cfsilent>

It does depend on having Groovy already available on your classpath (one of those missing bells and whistles is auto-loading Groovy).  This is the first version of the CFGroovy 2 line, which I've decided will be a ground-up rewrite.  Backwards compatibility is a goal, and I think it's a reasonable one, but where CFGroovy 1.0 was developed with an application focus, CFGroovy 2.0 will be developed with an architecture focus.  I'm willing to sacrifice a little backwards compatibility, particularly with Hibernate integration, to attain that.