Adam Tuttle

Entries Tagged as ColdFusion

Save Elvis! er, I mean ?:

Today was an interesting day.

I got an alert from the Adobe Bug Tracker, as I often do, to let me know that there was a change to one of the bugs I created / voted for / commented on. I clicked through to see what bug it was and what was new. It was a new comment on this beauty (CF11u3 broke the ?: operator) from everyone's favorite CFML curmudgeon (I think?), Adam Cameron. He asked what the status was for releasing the fix.

"A valid question!" I thought to myself, considering the bug was marked fixed on December 22nd, 2014. What gives, Adobe? Where's the fix? So I tweeted it, too. I believe strongly that the prescribed methods of communication should be used, until you start getting ignored or otherwise let down. Then, if the cause is just, it's time for a small dose of public shaming:

A few tweets were had back and forth between myself, Elishia, and Anit, with the end result being that the fix is scheduled for the next regularly scheduled update. Sounds great, right? Except updates are quarterly. Who wants to wait 3 months for a regression to be fixed? Is that even reasonable for a commercial platform? I don't think so, personally. Here's what I wrote in a comment on the bug, following that conversation:

I've already stated this elsewhere but just to put it on the record: I think that waiting for a quarterly update to fix a regression Adobe caused is terrible.

You say, "If you need a fix sooner, please contact our support team to request a private fix for this."

This implies that you have or can fairly easily create an update that fixes the issue. Why not just release that as update 4 and push all of the other non-update3-regressions back to update 5 on its normal schedule?

Further, "If you need a fix" can be rewritten as, "If you're using this feature" and I can assure you that either people have rolled back to update 2 or removed the feature from their code, because having syntax errors in your code is not just something you can leave be while you wait 3 months for a fix.

Either one is a losing proposition: There were things that are very nice to have included in Update 3 (many, many things, if my memory is correct. And if so, good and thank you for the update!) so rolling back to Update 2 denies us of useful features and bug fixes JUST like staying on Update 3 would deny us of this feature.

And lest you think I'm just being a jerk-nose for the sake of jerk-nosing...

Alas, that was the last they seem to have to say on the matter. Unacceptable, in my opinion. They did, however, offer to provide a "private fix" (their words) for anyone that asked.

For my part, while I do want it fixed, I don't consider myself special. I don't have a support contract — aside, you know, from the fact that CF11 was just released and is still in core support. So I'm not requesting a "private fix." But that doesn't mean you shouldn't.

In fact, I had the idea that we should more or less flood them with (legitimate) requests for the "private fix" in hopes that, if we can get enough, it will be easier for them just to go ahead and release an out-of-band patch. Also known as "doing the right thing."

So I made a form for you. Just click on over here, enter your name and email address, and submit the form. They'll be emailed, and you and I will be copied. (I keep a copy for posterity. Don't want any funny business with fudged numbers...)

Please feel free to share the link, and please only use the form once. It does not make any attempt to prevent duplicate submissions, and in my estimation they'll do more harm than good, so let's just keep things on the up and up, ok?

Published 2015-01-21 @ 04:34 in ColdFusion

In Response to CFHour #226

The latest episode of the CFHour podcast mentioned me in two consecutive segments, and in the latter they said that they fully expected me to respond... And who am I to let down a podcast to which I regularly listen?

First, they very kindly mention that I wrote a book! Thanks for that mention, guys. If you had reached out to let me know you were going to mention it, I would have been more than happy to offer a discount code for your listeners. Alas, I'll have to give that out here instead. CFHour listeners can save 10% by using this link.

The second segment was about my previous blog post, detailing the reasons that we gave up attempting to switch to Railo.

ORM Mapped Superclass entities named the same

As I mentioned in my previous post:

using MappedSuperClass with ORM entities that have the same name (e.g. User and base/User) — for reasons I don't feel like elaborating on but I assure you are completely legitimate — causes a Stack Overflow error

I guess Scott didn't accept my assurances of legitimacy. Not that I blame him, I'm always a skeptic, myself...

Scott: I guess I kind of understood, but I would never think to do that. Like, I would probably name the base user cfc, baseUser.cfc
Dave: Mmmhmm
Scott: I've used MappedSuperClasses a lot in the stuff that I do. As a matter of fact, all of my ORM entities extend a BaseEntity that has common methods that I want available to each one of the entities.
Dave: Yeah, most of mine do too.
Scott: I would just never think to name them the same name. Or more to the point, I wouldn't think to not name them base{Blah}, as part of the actual name itself—
Dave: Yeah
Scott: —rather than—
Dave: Uh-huh
Scott: —using a path to delineate them.

Ok guys, here goes. We've got lots of entities, and this system is only fractionally complete. We're sitting on around 50 entities right now and can easily see that expanding to be several hundred. In addition to that, this is for a resellable product, not a one-install bespoke system. So we're writing with customer-customizations in mind. Our customers are universities and colleges across the country (and maybe eventually the world?) and I'm sure you realize that they all have their own favorite way of storing data and their own favorite custom fields; so we're planning ahead to support that sort of thing.

Maybe User was a poor example. Universities tend to refer to their students, alumni, and sometimes even faculty and staff, as Constituents, so let's go with that. Uni A wants an isFaculty flag, an isAlumni flag, an isParent flag, and so-on (not a terrible idea, considering it's possible to be all 3 of those, and more)... Meanwhile Uni B might prefer to just have a type_code column with coded values to represent every possible case. Neither is objectively wrong, and it would be a crappy reason to lose a potential customer if we couldn't support their desired data formats.

So how did this drive the naming decision? Well, with potentially several hundred entities on our hands, our first goal was to set things up so that customizing the entities for one customer didn't make it difficult to maintain the source code (remember, this is all going into git) for other customers. So the strategy we decided on was to put the system properties in the MappedSuperClass orm/base/Constituent.cfc, and the custom properties into the child class orm/Constituent.cfc. Each customer will have their own branch of the repo, so the child class will stay empty in the master branch and the customer modifications to it will be done only in the customer's branch. This should (in theory!) practically eliminate merge conflicts (at least in the case of ORM entities), and keep each branch pretty clean.

We wanted to make maintenance as easy as possible, too. I suppose baseConstituent.cfc is just as easy to remember as base/Constituent.cfc — no argument there. But what happens when an entity legitimately needs to start with the word "Base?" Sure, we can have BaseBaseSalary.cfc (Yes, that's completely contrived: Why would you need a Base Salary entity? I've no idea!) but that just has a certain smell to it that I'm not fond of... like milk that hasn't quite expired yet, but still makes you think twice before drinking it. So instead we stuffed them in a base/ folder and called it a day.

As you've probably figured out, this was something that we were able to deal with relatively quickly: It wasn't "the last straw," so it had already been resolved by the time that last straw was reached. I do have to say, though, that I was very happy to revert the commit that made this work on Railo and go back to my base/Constituent.cfc strategy.

CFImport vs. App-Specific Mappings

I think we're mostly of the same mind on this, so just one quick note here: I think that the only way I'll consider this functionality "fixed" is when mappings are respected in all cases on all platforms. Anything short of that is a cop-out for what amounts to "academic" reasons. (If you're asking yourself what constitutes "academic" reasoning, think about your ipod playing the same song 5 times in a row in shuffle mode even though you'd hate that, because that's how random numbers work sometimes... Academic reasoning is not always the best.) And I don't think CF11 has, as you mentioned Scott, "fixed" (removed) the include-based workaround. I'm pretty sure it still works fine for me on CF11, though I did not revert the code changes I made to get this functionality running on Railo.


Scott: This is the one that really had me kind of scratching my head

No worries, I'll explain!

Your description of the problem is dead-on: We've got functions with a definition like this:

function remove( rc ) iq:role="users:delete" {}

In fact, nearly every Controller method looks like that. It's the configuration necessary for our role-based security implementation. We combine this metadata with FW/1's before() lifecycle event to authorize (nearly) every pageview / form submission / etc a user makes in the application. This makes the code very terse, which is a particular passion of mine, but does come with its own challenges. For one, getting that metadata is on the "expensive" (in computational time) side. Again, we have to make use of a base class, but in this case it's just a generic baseController that all controllers extend:

component {

    function init(){
        var md = getMetadata( this );

        for ( var fn in md.functions ){
            if ( structKeyExists( fn, "IQ:ROLE" ) ){
                variables.permissions[ ] = fn['IQ:ROLE'];

    function before( rc ){
        //if the requested action requires user to be logged in, verify that they are
        verifyLoggedIn( rc.action );

        //if user is logged in, check role-based security for the requested action
        verifyPermissions( framework.getItem() );

    function verifyPermissions( 
        ,failMessage = 'You do not have access to the requested functionality'
        ,jailEvent = 'main:jail/home'
        //action doesn't have role requirement
        if ( !structKeyExists( variables.permissions, methodName ) ){
            return true;

        var requiredRole = variables.permissions[ arguments.methodName ];
        if ( session.user.isAssignedRole( trim(requiredRole) ) ){
            return true;

        request.context.requiredRole = requiredRole;

        framework.redirect( arguments.jailEvent, "requiredRole" );


When each controller is initialized (infrequently) it grabs a copy of its own metadata (see init()) and stores a copy of the iq:role metadata in the component instance (variables scope) for later reference. Then, during the before() lifecycle event, it is referenced to make sure the logged in user has access to the requested action, before the action happens.

Apologies, that was a rather long-winded way of getting to this next part: Why is the metadata named iq:role? Why not iq_role? The short answer is: Because when you can, it makes sense to... And you can on Adobe CF10+... So I did.

In a few more words: Namespacing. You never know what crazy feature the platform vendor will come out with next, right? I mean... CFClient, anyone? So by appending custom metadata to your functions, you run the risk that one day they will release a new version that you really want to use, but now they have revitalized <cflogin> to actually be relevant, and oh by the way, it uses a role metadata attribute on your functions. So you have to go change every function that uses your custom role metadata attribute if you're not lucky enough to have been using it "their way" before they were. By prepending some characters that are unique to your application, you reduce the risk of a collision later down the line. Just to be clear, the extra characters don't change the functionality in any way, they just reduce that risk of collision. That's what namespacing is for, but it still doesn't fully explain why ours uses a colon instead of an underscore or something else.

And the answer to that question is: because I said so! When you're in charge of decisions like that (and I am, right now), you sometimes get to pick things because you like the way they look. On Adobe ColdFusion, iq_role and iq:role are functionally identical, so I picked the one that I found more visually appealing. I can't really explain why I find the colon more pleasing to the eye, but I do. I probably saw it somewhere else (Java? Python? Who knows...) and it stuck with me. And it continues to serve us well on the ACF platform.

Taffy users are also probably familiar with it, as Taffy supports both taffy_uri and taffy:uri metadata attributes for specifying a resource's uri mapping (for both Railo and ACF8-9 support reasons).

So why doesn't Railo support it? Because they also support this: role:"foo". At some point in the past they chose to accept a colon as the delineator between the LHS and RHS of attributes, and as a consequence they can not support colons in the LHS. For them, it is like trying to write: iq=role="foo" — and I accept that. That is a particularly hard problem to solve, and I don't blame them for not considering it a high priority. I find it unfortunate that they dug that hole for themselves, but there's no use dwelling on the past: This is the world we live in, so this is what we have to deal with. Doing otherwise would be like fighting gravity.

Scott: You know, when people run into these problems and I don't, I can't help but think, "Are they doing something really weird, or am I doing something really weird?" Are they doing it wrong, or am I doing it wrong? And you know, when you're talking about me and Adam Tuttle, I would err on the side of me doing it wrong.

That's very kind of you to say so, Scott, but I think that this time it's very clearly my fault that it doesn't work on Railo... I didn't originally make the choice with platform agnosticism in mind. But would I go so far as to say it is "wrong"? I think not.

One last thing about that previous post ("We Tried (and Failed) to Switch to Railo")... While it was not meant to be putting down Railo in any way, I think it would be easy to see it in that light. I actually really think Railo is a great option; even more so if you get to start with a clean slate. But I just wanted to put out some information that showed a first-hand account that switching from one platform to the other is not all unicorns and rainbows. There is significant work involved. So when the fanboys spout off on mailing lists that you should just switch, you can rightfully start ignoring them. It's not that simple.

Scott had mentioned toward the end of that segment that he was impressed that these were the only issues that we ran into, and there is some truth to that statement, but probably not the kind he intended. It's more like the truth that your keys are always in the last place you look for them because you stop looking when you find them. We gave up once we ran into the metadata issue. It's possible that could have been the last thing; but it's equally possible that there could have been 30 other differences to deal with once the metadata problem was resolved.

In truth, we were working at a running pace. Steve was about to leave for a road trip and I was head-down on something unrelated, and while we were switching to a new AWS EC2 instance, we thought it would be a good opportunity to give Railo a try. We didn't really have the time to deal with a lot of issues that needed sorting out, so our threshold for conversion pain was pretty low. It ended up being about a 2 hour experiment that proved it wasn't going to be quick and painless to switch. Would we make these changes down the road and try again? We might... When we have time available to deal with it.

Published 2015-01-19 @ 09:40 in ColdFusion

We Tried (and Failed) to Switch to Railo

One of the things we wanted to do with our new product was to try running it on Railo. We've been developing it against Adobe ColdFusion 11 for a while now, but have wanted to try our code on Railo for a while. It would be nice if we could eliminate the license cost. We figured there would be a few things we would have to deal with, but we'd just fix those and move on. "How bad can it be?" we asked ourselves...

Pretty bad, apparently.

ORM Inconsistency

The first issue we ran into was that using MappedSuperClass with ORM entities that have the same name (e.g. User and base/User) — for reasons I don't feel like elaborating on but I assure you are completely legitimate — causes a Stack Overflow error.

So I renamed the base entities to xUser/etc, for what felt like ~200 entities (oh and all of the extends= referring to those base classes), but in reality was probably more like 50.

Class vs JAR

The next thing we found out was that Railo won't load .class files out of the classpath (as Adobe ColdFusion will), only .jar files. Fine, zip them up, rename to jar. A nuisance, but not the end of the world...

CFImport vs. App-specific Mappings

Having cleared those issues, we next found that Railo doesn't respect application-specific mappings in the taglib argument of the cfimport tag (don't believe the status=resolved, it's not)...

Ok, fine, we got lucky and were only using this in a few places. I fixed those, on to the next speed bump.

The Last Straw

We use a neat, custom, home-made solution to do role-based security throughout our application applying restrictions in the global FW/1 before() event shared by all of our controllers. Essentially, each FW/1 controller action method can optionally have a bit of metadata like iq:role="users:delete" and if the logged in user doesn't have this role, then they are redirected away from the action.

Unfortunately Railo handles metadata differently, and rewriting this portion of our code would be pretty drastic and take time that we don't have to invest right now.

That was the straw that broke the camel's back. We're going back to Adobe ColdFusion... for now.

I'm really disappointed. Certain people have been espousing Railo as their go-to CFML server for so long that I figured it would be pretty smooth sailing. (No ill will directed at you chaps... You're not to blame!) While Railo certainly does have a track record of responding to (some?) bugs much more rapidly than Adobe, their track record for feature parity is apparently pretty low.

In fairness to Railo, if we had spent equal time developing against Railo as our base and then tried our code on Adobe ColdFusion, it's equally likely we would be having similar problems. I just wish there was better parity and that old bugs weren't simply written off and ignored the way they sometimes seem to be.

Guess we'll keep using ACF until we're ready to switch to Node. ;)

Published 2015-01-06 @ 08:00 in ColdFusion Railo

Upgrading to OSX Yosemite with CF10 Already Installed

Yesterday morning I decided to take the plunge and upgrade my daily-driver laptop to OSX Yosemite. This is the story of what I did, what I could have done better, and how I dug myself out of that hole.

Before I made the decision I snooped around to see if anyone else had any trouble. By that I mean that I had already seen a relevant bug report and I asked on twitter:

I didn't put much stock into the bug report: It looks like it was written by someone that doesn't really know their way around a CF installer, and I like to think that I do (know my way around a CF installer). And the tweets were generally positive: You'll probably have to reinstall MySQL, and the built-in Apache install will probably get un-configured. Not that big of a deal, all in all.

So I dove in! Knowing that apache config would be mucked with, I was (1) very happy that I had checked it into a git repo a long time ago, and (2) made a backup copy in my home directory just in case. I also backed up all of my mysql databases. That should cover everything that wasn't backed up overnight with Backblaze.

The download went faster than when I upgraded my Mac Mini HTPC the other day (irony: the mac mini is on a wired connection and my laptop is on wifi...), but the installer took for-freaking-ever. When it got down to "2 minutes remaining" it was just about noon so I left it alone and went out for lunch. When I returned an hour later, it still said, "2 minutes remaining."

... Crap.

Not to worry, though, as this appears to be a pretty common problem, especially for people that have a lot of stuff in /usr/local/bin (homebrew, global node.js modules, etc) -- which includes me. So wait it out I did (I did hit Cmd+L to watch the log and confirmed it was actually working that whole time, so at least it wasn't just the dreaded beachball of death). At about 1:40 it finally finished installing, and I was able to use my laptop again.

The first thing I did was install updates for things I was prompted for; probably stuff that required Yosemite: a new version of 1Password, an iTerm update, and Keynote, iMovie, and iPhoto; as well as the updated Command Line Tools. Then it was down to business.

The first thing I wanted to do was verify that I could start CF and Apache and get to the CF Administrator. No complaints when I started them, but as expected, I was not able to get to the CF Administrator: 404.

I went through the diff of changes made to my httpd.conf file (thanks, git!) and adjusted things that made sense to me: re-establishing my preferred default document root, re-enabling my vhosts, adding the Include line for mod_jk that was removed, etc. But still, Apache never seemed to finish starting: there were no errors printed to stdout or stderr when I started it, but I never found httpd in the process list either. Then I found reference to apachectl configtest on Stack Overflow (you may or may not need to use sudo; I did), which does exactly what you should expect: it verifies that your apache configuration is at valid, syntactically and otherwise. I had a few problems. Firstly:

httpd: Syntax error on line 531 of /private/etc/apache2/httpd.conf: Syntax error on line 2 of /private/etc/apache2/modjk.conf: Cannot load /Applications/ColdFusion10/config/wsconfig/1/ into server: dlopen(/Applications/ColdFusion10/config/wsconfig/1/, 10): Symbol not found: _aplogerror\n Referenced from: /Applications/ColdFusion10/config/wsconfig/1/\n Expected in: flat namespace\n in /Applications/ColdFusion10/config/wsconfig/1/

My assumption here was that there's some problem with the webserver connector as built on OSX 10.9, so I commented that out. After doing that, of course, my JkMountFile lines in each vhost were the next problems:

AH00526: Syntax error on line 116 of /private/etc/apache2/extra/httpd-vhosts.conf:
Invalid command 'JkMountFile', perhaps misspelled or defined by a module not included in the server configuration

Commenting each of those out has made Apache successfully start, and I can now browse around my various vhosts, but obviously ColdFusion isn't running. I had run wsconfig at some point previously and it was crashing. I was hopeful that the problem had something to do with my mucked up Apache config, but alas, even once the config was cleaned up the web server connector continued crashing on startup.

Saddened, I downloaded a fresh copy of the CF10 installer and tried to uninstall my existing copy. The uninstaller crashed too. "Oh well," I thought, and figured I would rename the CF10 folder and install anew. The freshly downloaded installer crashes, too. Delightful!

Not that I particularly want it, but ColdFusion11 might work, since it's been released more recently. Since CF10 is still supported (*ahem*) you'd expect its installer to be able to run, but whatever. I downloaded CF11, hoping it would save me from having to reformat my laptop and stay up all night reinstalling stuff from scratch and... hallelujah, it runs!

Let's not get too excited just yet, though. The installer completes (with a very ugly dead give-away "this app was written with Java" dialog box for selecting the path of my existing CF10 installation for settings migration), and the CF Administrator loads! Hooray! I get to sleep tonight!

Mappings copied over and look right. Still don't have a mail server configured (this is how I want it, so check!). My MySQL datasources check out. MSSQL TBD: I need to run windows update in that VM and make sure it's still forwarding ports correctly, but it's not mission critical at the moment.

I did have to figure out where to drop in my Bcrypt.class file so that BCrypt will work (hint: /Applications/ColdFusion11/cfusion/wwwroot/WEB-INF/classes/), but all in all everything appears to be in working order. I'd still prefer to have CF10 installed to match my production servers, but I suppose this will have to do.

... That was not how I wanted to spend my Wednesday.

Published 2014-11-06 @ 09:00 in Apple ColdFusion