Adam Tuttle

ColdFusion 11 Sometimes Chokes on /api

Here's a weird issue I've seen repeatedly, which took far too long to track down: When I have a ColdFusion application running at —usually a Taffy API, but I've tried simple hello-world scripts, too— CF throws a 500 error, claiming "Application could not be found". Sometimes. And by "sometimes" I don't mean sporadically, but rather, only on certain computers.

I've got several different AWS EC2 instances running CF11 where this happens (the source of the above screen shot), and yet on a non-cloud server setup nearly identically (to the point that it would be tedious to discover the things that are different: all on the same version of windows and IIS, etc, so differences will be microscopic), and with the same code repository cloned, there are no errors.

In addition, if your application lives in a sub-folder under /api, it shows a similar 500 error, even if the requested folder doesn't exist:

Normally you would expect a 404 in this case, because I just made up that boston-terriers-rock folder name and it definitely does not exist.

But get this: Access the same code through another URL and it works fine. Notice I didn't say rename the folder. You could rename the folder and that would work too, but on operating systems that support it you can also just create a symbolic link (e.g. ln -s api splat). So it must be something to do with URL handling, right?

Having spoken to several of my friends in the community about this frustrating issue over the last few months, it seems like several people have been sporadically affected: If they've seen it at all, it's not been on every server. Whatever the problem is, it's inconsistent. Some people have seen it with Apache on CentOS, I mostly see it with IIS on Windows; and it's never affected me with Apache on OSX. It's also been reported in the adobe forums.

It took me a while to track this down because it was only happening on production servers, never on my local development machine, and I don't always have immediate access to the log files in production. Ultimately it was the exception log contents that identified the problem, though.

"Error","ajp-bio-8014-exec-7","04/06/15","16:53:13",,"Application boston-terriers-rock could not be found. The specific sequence of files included or processed is: '''' "
javax.servlet.ServletException: Application boston-terriers-rock could not be found.

Do you see the give-away there? CFRestServlet

If you'll recall, when Adobe introduced their oddball REST components implementation, you had to use what appears to be a mapping (/rest) but which isn't really a mapping, to access your rest services. You could alter this in web.xml to be something other than /rest but whatever you wanted to use had to be hard-coded in that file and would be true for all domains using that CF instance.

My gut was right: This is more oddball URL handling. If we look in web.xml, we'll now find this:

<servlet-mapping id="coldfusion_mapping_16">

Why this affects some installations and not others I can't begin to explain. Sorry. But I can tell you that if you're affected, and assuming you're not interested in the native REST functionality (and why would you be?), you can comment out the above block in web.xml and —after a quick service restart— go on about your business with your now-functioning api.

I have half a mind to file a bug for this, because as far as I know this change from /rest to /api is undocumented, and even if it were documented, it's a pretty crappy thing to do out of the box, even without any REST components configured. But I've got deadlines to hit and a head cold to contend with, so I'm not filing anything just yet.

Have you seen this happen? Can you explain why it doesn't happen for every server? I'd love to find out why...

Published 2015-04-06 @ 03:15 in ColdFusion

The Case For UCASE

I think it's time we address the elephant in the room: We need to convert all text for situations when case is insignificant to UPPER CASE. Because it's smaller.

Not visually, obviously. But if you look at the facts I think you'll agree with me. The upper-case letters A through Z have ASCII codes 65 through 90 respectively; while lower case a through z use codes 97 through 122 respectively. That's 32 wasted picobits for every lower case character you use. If you write 100,000,000 lower case characters in a day, you're practically responsible for global warming.

For years I have selfishly hoarded hard disk space, and the extra energy necessary to read and write it, because my eyes subjectively preferred lower case HTML tags and tag attributes. Never again! And my selfishness is even more apparent in my JSON APIs where I chose to use lower case structure key names even though it was only another computer that would ever read it!

I'm so embarrassed.

And to think... ColdFusion has been hinting at this for years by defaulting object keys to UCASE... but it has fallen on the deaf ears of the community. We should all be ashamed of ourselves!

That's why I'm starting the #SAVINGNOTSHOUTING campaign today. Please make sure you UCASE all of your source code; and while you're at it you should UCASE your Tweets and use the #SAVINGNOTSHOUTING hashtag so people know you're being green, not yelling at them.

Published 2015-04-01 @ 09:00 in Meta

Introducing Moment.cfc

Today I'm releasing a new open source project, moment.cfc.

If you've ever used moment.js calm down, because I promise you this isn't quite as awesome as that. If you haven't used moment.js —first of all, get on that!— it's a great little library for dealing with and manipulating dates and times in JavaScript. They also have a newer companion library for dealing with time zones in JavaScript.

While moment.cfc isn't as awesome as moment.js, it's still pretty rad.

The original motivation was having to deal with time zones in ColdFusion. CF has some limited functionality for converting between local time zones and UTC, but it assumes your server is running in the desired local time and there are no functions for converting between arbitrary time zones. We're working on a big app to be used by nation- and globe-spanning organizations, so time zones are a pretty big deal.

Let me share with you what was on my mind just hours before this project was undertaken:

Assume your DB server and App server are configured to run in UTC. (So dateConvert() with utc2local and local2utc are non-starters right away...). Now imagine this scenario: Your organization's headquarters is on the east coast of the us (America/New_York time zone). You're creating an "event" for people to register to attend, which will be held on the west coast (America/Pacific). And although while you're creating this event it is currently Standard Time, between now and when the event starts, Daylight Saving Time will begin. Pop quiz, hot shot! What do you do? What. Do. You. Do?

If you guessed, "consider quitting your job and opening a lemonade stand" then I was right there with you (with 2nd place going to, "seek out and destroy every computer in the world"). Fortunately I had my friends in the ColdFusion IRC channel to talk me down from that ledge.

The answer, of course, is that DST "doesn't matter" (in that it's an entirely human concept) and if you schedule an event for 5pm Pacific time on Thursday, it should display as 5pm Pacific time on Thursday, regardless of DST coming and going. If you store all date/times in UTC and use smart conversion functions, they'll take care of the rest themselves.

If only there were a way to make that time zone math easier in ColdFusion. There isn't. Yet. But all is not lost. As much as I like to bemoan Java for its complexity and verboseness, it saved my bacon this time. java.util.TimeZone to the rescue.

After a few hours spent reading the documentation, and some blog posts, and fiddling with trying to find the right syntax to get it to instantiate and run from within CF, I had a super basic proof of concept that I could specify a time in an arbitrary time zone and convert it to UTC or any other time zone of my choosing.

I was pretty thrilled with this, but then I had a light bulb moment...

Light Bulb!

I could turn this into a moment.js-like tool for CFML. And thus was born moment.cfc. It's not a port of moment.js (there are many features I've skipped for now, or because I think they just aren't necessary), but it is heavily inspired by its namesake.

Allow me to give you a taste of some of the syntactic goodness:

Adobe CF moment.cfc
x = now(); x = new moment();
y = createDateTime( 2008, 11, 27, 13, 47, 0 ); y = new moment( '2008-11-27 13:47:00' );
x = dateAdd( 'ww', 1, x ); x.add( 1, 'week' );
y = dateAdd( 'n', -30, y ); y.subtract( 30, 'minutes' );
diff = dateDiff( 's', x, y ); diff = x.diff( y, 'seconds' );
before = dateCompare( now(), x, 'h' ) == -1; before = x.isBefore( y, 'hours' );

And as promised, it makes time zone conversion, including UTC, a breeze:

  • event = new moment( '2015-03-26 17:00', 'America/Pacific' );
  • utc = event.utc();

There are around a dozen methods available, with more coming soon, so if you really want the nitty gritty, you should read its documentation. And there is (almost) 300% more code lines in the tests (829) than in the component itself (305): it's pretty well tested.

As for me, when I signed off on Friday with these time zone thoughts swirling around my head I was dreading coming to work on Monday morning. Now I'm excited to get in there and kick some butt!

Published 2015-03-23 @ 08:00 in ColdFusion My projects Open Source

ColdFusion and ORMReload()

If you use ColdFusion's ORM (layer on top of Hibernate), then chances are pretty good you've needed to run an ormReload() now and then to pick up changes to your entity definitions. In our application, I've been having a minor nuisance getting this to work as intended, and I think I've finally figured out why.

Let's consider my ORM settings:

this.ormenabled = true;
this.ormsettings = {
    , logsql=false
    , cfclocation= ["/orm"]
    , flushAtRequestEnd=false
    , useDBForMapping=false
    , dialect="MySQL"
if (getEnvironment() eq "dev"){
    this.ormsettings.dbcreate = "update";

The intention is, on all environments other than my local machine, to block ormReload() from doing its job. In those scenarios, we're willing to jump through a few extra hoops to deploy our changes for the sake of safety; but during DEV you just want to be able to make changes and have them quickly picked up.

The only problem was that getting ORM to detect changes and actually do the ormReload() seemed to always require a CF service restart. It happens so infrequently that it was hard to remember if it requires a service restart every time, or just seemingly every time — but just often enough to be annoying.

As it turns out (I think), this bit of cleverness seems to have been too clever for Adobe ColdFusion. (I've not tested on Lucee.) It appears as though the very first time the value for this.ormsettings.dbcreate is set is the only value that is ever used. So, in the above case, where we default it to "none" but then overwrite it to "update" on development machines, ACF never noticed — or never cared that it changed. It would also seem that it wasn't the service restart + ormReload() that caused my changes to be picked up, but just the service restart itself.

It took explaining this frustration to our new developer, with the code in front of my face, to have my lightbulb moment.

I've since changed the code to the following:

this.ormenabled = true;
this.ormsettings = {
    dbcreate=(getEnvironment() eq "dev" ? "update" : "none")
    , logsql=false
    , cfclocation= ["/orm"]
    , flushAtRequestEnd=false
    , useDBForMapping=false
    , dialect="MySQL"

And now everything is peachy. Does this account mirror your own experiences, or am I losing my marbles?

Published 2015-03-16 @ 02:30 in ColdFusion