Why I Like

With the position I'm in now, I've had the joy of finally being able to write (full time) for ColdFusion 9. There were many great improvements and updates within CF 9, but two of mine were the increased parity to tags, and the ability to write fully scripted components. I was one of the first to post a fully scripted Application.cfc. I've pushed most of my code examples, since then, using cfscript. I wrote a brief primer on extending ColdFusion, by writing custom components for use server wide. I use cfscript constantly in my day to day development, and used to use as much as I could before CF 9. And yet three times, in as many weeks, people have asked me "Why?"

I've gotten this question before. Most, who've mentioned it, don't really mind it one way or another, they just wanted to know why it's my preference. Others were adamantly opposed to it, because it is so different in style from other scripted languages. There have been efforts to improve cfscript, and even calls to deprecate cfscript, in it's current form, and reinvent it (or switch wholly to server side ActionScript). Last month, Adam Tuttle created the CFCommunity, on GitHub, for open source contributions in filling in the few remaining gaps in cfscript through custom component objects. But, why do I like it?

I've been a ColdFusion developer now for over a decade. Like every other programming language I've worked with I was self taught, and came to CF after learning Visual Basic (6), some C++, and InstallScript (which is what Install Shield used to use for custom installers). Aside from progressively improving my knowledge and usage of HTML/XHTML and CSS, I was primarily a 'server side' developer for much of the beginning of my CF career. I'm a programmer, not a designer, so I wrote (hopefully) good logic. The browser wars had soured me on JavaScript, so I avoided it when I could. Luckily libraries like ExtJS and JQuery came on the scene. By this point my grasp of ColdFusion (and programming, in general) was much more advanced, so putting effort into interface development and usability was a good step. This also meant heavily re-aquainting myself with JavaScript, and remembering what a joy scripting was.

After a while, I found that I was writing more JavaScript than ColdFusion, and focusing more time on client-side development than on the server. Complex server-side code had become second nature, and came rather quickly, whereas client-side code was still relatively new and challenging. I was writing two to three lines of client-side code for every line of ColdFusion (at least). In the process, I've also had to adjust how I approach some of my ColdFusion development, to accomodate ajax interface development. It's been a lot of fun.

While I love ColdFusion, writing complex logic in JavaScript again had shown me how much more rapid scripting was. While ColdFusion's tag syntax is fantastic for transitioning html developer's, and great for generating client-side code (cfoutput and cfloop stuff), straight scripting syntax for logic is much faster, trimmer, and concise. I will agree with those who say that cfscript needs an overhaul. Function naming is inconsistent, as is treatment of arguments and argument naming. All of that aside, it's still quick, trim, and powerful, and the Java behind the functions is (sometimes) more current, and better performant, than the Java behind their tag counterparts.

I wish Adam luck with his CFCommunity project on GitHub. I think it will be a great thing for the ColdFusion community, as a whole, if it can gain steam, and hope to make some time to help contribute to it myself. I also hope that, in some future version of ColdFusion, that the Adobe engineering team will do a thorough review of cfscript and work to create a scripted ColdFusion that the community, as a whole, can agree upon as a new standard. In the meantime, I'm happy to use what we have, as it's still very performant, and a lot of fun!

Intro to jqGrid Part 2: Getting the Data

As I mentioned in an Intro to jqGrid, sometimes you have to deal with remote data that isn't in the 'standard' JSON recordset format. I also like to reuse my server-side code, and prefer not to unnecessarily hack native data to meet a client-side need. For this reason, it is often necessary to write client-side methods that parse the server-side native format. Unfortunately, many JQuery plugins only handle the 'standard' JSON recordset format:

[More]

Intro to jqGrid

While there are better choices (ExtJS for instance) for component and architecture libraries, some time ago someone entrenched our current system in JQuery and JQueryUI. But, since JQueryUI is already so prevelent within the system, it would be very time consuming to replace it. JQueryUI isn't bad, by any means, just incomplete, from the standpoint of building "applications". "But, JQueryUI is the bomb! How can you say such things?" Well...

[More]

A Scripted Query Param & Whitespace Gotcha

I discovered this one a while back, but forgot to write a post on it. Did you realize that formatting queries could affect the execution of scripted queries? Consider the following function:

view plain print about
1/**
2 *    FUNCTION login
3 *    A function to validate a user login, and return a struct of user details
4 *
5 *    @access public
6 *    @returnType struct
7 *    @output true
8 */

9function login(required struct formScope) {
10    var retVal = {"success"=true,"message"="","data"=""};
11    var sql = "SELECT     u.userID,
12                        u.username,
13                        u.password,
14                        u.dateCreated,
15                        u.lastUpdated
16                FROM    users u
17                WHERE     u.username = :username
18                AND        u.password = :password
19                AND        u.isActive = 1";
20    var q = new Query(datasource = VARIABLES.instance.dsn,sql = sql);
21    q.addParam(name = "username", value = ARGUMENTS.formScope.username, cfsqltype = "cf_sql_varchar");
22    q.addParam(name = "password", value = ARGUMENTS.formScope.password, cfsqltype = "cf_sql_varchar");
23
24    try {
25        retVal.data = LOCAL.q.execute().getResult();
26        // Check for no recordCount, and throw a 'no records' exception
27        if(!retVal.data.recordCount){
28            throw(type="MH-Custom",errorCode="001",message="The user " & ARGUMENTS.formScope.username & " could not be authenticated. Please check your credentials and try again.");
29        }
30    } catch (any excpt) {
31        retVal.success = false;
32        if(excpt.type eq "MH-Custom"){
33            retVal.message = excpt.message;
34        } else {
35            // TODO: Add admin notification in here somewhere
36            retVal.message = "There was a problem executing this request, and our administrators have been notified";
37            WriteDump(var=VARIABLES.instance,label="instance");
38        }
39        if(StructKeyExists(excpt,"errorCode") AND Len(excpt.errorCode)){
40         retVal["errorCode"] = excpt.errorCode;
41        }
42    }
43    return retVal;
44}

It's a pretty basic function, with a query to check submitted form fields against the database. Right? So, why would it error? "Error? What error?" Yes, it errors. Here's the code for a basic call, along with a dump to output that to the page:

view plain print about
1<cfscript>
2    REQUEST.testObj = CreateObject("component","com.multihome.core.Security").init(DSN='multihome');
3    REQUEST.test = REQUEST.testObj.login({username='admin',password='admin'});
4    WriteDump(var=REQUEST.test);
5
</cfscript>

Dumping that result shows you the error coming through:

CFDump 1

So, to get at the root of this I had to comment out all of my try/catch work:

CFDump 2

Whoops! Forgot my onError handler. OK, I'll comment that out. Here we go! Now we get to the meat of it (the dump was the same, but sometimes you just want to see the raw error):

view plain print about
1Error Executing Database Query
2
3Parameter 'username AND u.password' not found in the list of parameters specified
4
5SQL: SELECT u.userID, u.username, u.password, u.dateCreated, u.lastUpdated FROM users u WHERE u.username = :username AND u.password = :password AND u.isActive = 1
6
7The error occurred in C:\JRun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\cfusion\CustomTags\com\adobe\coldfusion\query.cfc: line 108
8Called from C:\JRun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\cfusion\CustomTags\com\adobe\coldfusion\query.cfc: line 137
9Called from C:\JRun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\cfusion\CustomTags\com\adobe\coldfusion\query.cfc: line 472
10Called from C:\JRun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\cfusion\CustomTags\com\adobe\coldfusion\query.cfc: line 605
11Called from C:\Inetpub\com\multihome\core\Security.cfc: line 68
12Called from C:\Inetpub\wwwroot\multihome\index.cfm: line 21
13Called from C:\Inetpub\wwwroot\multihome\application.cfc: line 228

Did you get anything out of that? Neither did I. The first thing I did was go review the scripted 'new Query()' documentation on the Adobe site. That didn't help. According to the documentation, everything appears to be fine. The next thing I did was look at other examples out there. Yep, still good. Next, I started comparing to other instances of code that I know to work. Wait a minute....Look at this:

SQL code with whitespace characters

See anything odd? Yes, I show whitespace characters in my editor (ColdFusion Builder). Pretty easy to do. Just go to your preferences and change it: go to Window | Preferences | General | Editors | Text Editors, and select Show whitespace characters. What you see in this picture are tabs, spaces, and End of Line markers. "OK, so what?" Well, here's where it gets strange. Let's take our original query, and put it all on a single line:

view plain print about
1var sql = "SELECT u.userID, u.username, u.password, u.dateCreated, u.lastUpdated FROM users u WHERE u.username = :username AND u.password = :password AND u.isActive = 1 ";
2var q = new Query(datasource = VARIABLES.instance.dsn,sql = sql);
3q.addParam(name = "username", value = ARGUMENTS.formScope.username, cfsqltype = "cf_sql_varchar");
4q.addParam(name = "password", value = ARGUMENTS.formScope.password, cfsqltype = "cf_sql_varchar");

If you run this, all is well:

CFDump 3

As you can see, everything works fine now. But, when I format my SQL for readability again, I again get the error. When I went back, and looked at examples that worked (in my editor) I discovered that lines following lines with params were directly preceded with one or more spaces. So, just to test, I added a single space right before those lines that followed lines referencing params:

view plain print about
1var sql = "SELECT     u.userID,
2                    u.username,
3                    u.password,
4                    u.dateCreated,
5                    u.lastUpdated
6            FROM    users u
7            WHERE    u.username = :username
8             AND    u.password = :password
9             AND    u.isActive = 1";
Code with adjust whitespace

This took care of it. My error went away, and my query executed properly, and my query was still formatted for readability. After another round of the great Tabs vs Spaces debate at work I had to change my editor's default preferences back, which is what caused/highlighted this issue. (I told you guys we needed to stick with 4 spaces ;) Maybe it's a bug in the SQL parser, or there's a method to the madness, but adding that single space before those lines is all that's required to get back on track.

MSOC Part 8: onRequest Event Handlers

Some of the most powerful and versatile ColdFusion application event handlers are often the most ignored: the onRequest event handlers. Not sure why these so often seem to get ignored, but I can't name for you how many times, and how many apps, I've started working on that weren't using any of these methods in any capacity, and needed to.

Like the onApplication and onSession before it, the onRequest event handlers include methods that fire immediately before (onRequestStart) and after (onRequestEnd) the page request. Also like the scopes of those handlers, the onRequest handlers allow access to the REQUEST scope variables without having to lock access to those variables. Those are pretty standard, and not much to figure out. But the onRequest handlers also include two additional handlers: onRequest, and onCFCRequest. These two are a bit more confusing to understand "why?", so we'll go a little more in depth.

[More]

ColdFusion 9 Hotfix 2 Released

Adobe has released the ColdFusion 9.0.1 Hotfix 2, available on the update page. This is a cumulative hotfix, containing fixes for security issues, items around ORM, resolution to questions of JSON serialization, integration bits for Exchange, and much more.

Install has some quirks. It's not just a simple 'upload the file' bit, so you'll want to pay careful attention to the instructions, and backup affected files in advance. This will get so much easier with the next version of ColdFusion, but for now it's worthwhile to jump through the hoops. It is a 'cumulative' hotfix, and word from those in the know say that it is safe to skip over the CHF 1 install, if you haven't done it already, as all it's changes are within this hotfix as advertised.

Legacy Code and Some Modern Browsers

Working on some legacy code the other day, and came across one that was driving me nuts. I had a form that was part of a tabbed interface, and the form would not submit in Firefox or Chrome. Finally, after some trial and error, I was on a specific tab when I hit submit, and saw the following:

Unable to display content. Adobe Flash is required.

Did you see that? Some kind of form validation. It was odd though, because I didn't see that popup from any other tab, nor did it shift focus to the tab with that field (though focus was on that field). So, I went searching.

After quite a bit of time I found out something even more odd. There was no form validation on that field. Zilch. Nada. What the...? Now I was really stumped.

So, I started looking at the code of the form itself, specifically at that field. Here's what I found:

view plain print about
1<input type="text" name="somefield" required="No">

Like I said, some legacy code. Have you figured it out yet? Here's the deal. This form used to be a cfform, and the original developer had added the required attribute on a cfinput (unnecessarily). At some point, the form was switched over to a standard form, with it's own validation, and the cfinput was switched quickly to an input, without removing the attribute. No big deal, right?

Well, it wasn't a big deal, for a very long time. But, the browsers are updating. They're slowly implementing changes to support html5. And, guess what. There are changes to the input elements for html5. Now you have a required attribute? It will automatically validate that field, with a default message, and stop form processing if the field is empty. Never mind that you've implemented the required attribute incorrectly for html5, it'll still validate it regardless.

Removing the required attribute, which was no longer necessary in our application, resolved the issue.

How 'bout that gotcha?

How I Do Things: ColdFusion and Ajax Requests

I get a lot of questions about handling Ajax requests. What are some best practices? How do you format your requests? How do you taylor your functions in ColdFusion? Those sort of questions. We (the ColdFusion community) have embraced Ajax. Many of us spent so much time working mostly server side code on top of simple (and often poorly thought out and formatted) forms, but user habits have changed. And so have we. You have to move with the times to keep up in the digital rat race.

Let's start with the stuff most CFers already know; the server side stuff. When we make an Ajax request, most often we will hit a function within a CFC. We need data. You can hit a .cfm page, and return a bunch of preformatted HTML, but often that's a lot of data transfer when your really only need a few bits of data. HTML code can get heavy, what with all the tags and such. Similarly, you could return data in XML form (WDDX is native in ColdFusion). XML is sometimes a required format, for certain requests, but like HTML it can often be overly verbose. When working with server side requests from the client, you want to minimize data transfer as much as possible. That's why Flash performs best using the AMF format, and why most Ajax applications work with JSON.

When constructing your ColdFusion functions for remote requests, you don't have to write functions that can only be used via Ajax. In fact, that would probably be bad practice, as it would really minimize the code reusability of your functions. Basically, the only true requirement, at the server side, is that you set your function's access attribute to remote.

view plain print about
1/*    
2 *    COMPONENT SomeComponent
3 *    Just some example component
4 *
5 *    @name SomeComponent
6 *    @displayName SomeComponent
7 *    @output false
8 */

9component {
10    /*
11     *    FUNCTION SomeFunction
12     *    This is just some function you've written
13     *
14     *    @access remote
15     *    @returnType struct
16     *    @output false
17     */

18    function SomeFunction(required string arg1, required numeric arg2) {
19        var retVal = {"success" = true, "message" = "", "data" = ""};
20        // some function stuff here
21        return retVal
22    }
23}

That's it. Nothing to it. Did you see the required line? The one you need for making a remote request of this function?

view plain print about
1*    @access remote

Ok, we're off and running. Sort of. "Hey, Cutter, what's with returning a struct? I thought we were working with JSON?" Well, let me explain...

Have you ever worked on some Ajax call, loaded the page up in the browser, and nothing happened? You change variables, do this and that, and get nowhere? Finally you open up Firebug, watch the request, and see that you CF code has errored out for some reason. Instead of data coming back, the browser is getting the thousands of lines of HTML and Javascript that is the ColdFusion error display. In the immortal words of Charlie Brown: AAUUGGHH!

What happens if your user sees this behavior? Some variable isn't getting set when you think it is, or some db guy added or removed a column from your database without your knowledge. An error gets thrown, and you never even realize it. Ouch! Users are quick to abandon you. How can you gracefully handle these things?

Well, how do you deal with error handling within your application? If this answer is "I don't", then you might want to explore another career path. No, just kidding (kind of). If you don't use error handling, this is the perfect scenario to start. There is no reason why you're users should see (or, in this case, not see) these types of issues within your application. By carefully thinking things out, you can provide a better user experience.

view plain print about
1/*
2     *    FUNCTION SomeFunction
3     *    This is just some function you've written
4     *
5     *    @access remote
6     *    @returnType struct
7     *    @output false
8     */

9    function SomeFunction (boolean debug = false, required string arg1, required numeric arg2) {
10        var retVal = {"success" = true, "message" = "", "data" = ""};
11        var q = new Query();
12        try {
13            // do your query stuff, setting the result to the "data" key
14            if (!retVal["data"].recordCount) {
15                throw(type = "ourCustom", errorCode = "RC_000", message = "No records were returned matching your criteria.");
16            }
17        } catch (any excpt) {
18            LogTheError(excpt); // Custom error logging for us
19            retVal["success"] = false;
20            if (!ARGUMENTS.debug) {
21                retVal["data"] = ""; // Clear the "data" key, so we don't pass unneeded bits back to the client. Override this by passing 'debug' into the request.
22                if (excpt.type eq "ourCustom") {
23                    retVal["message"] = excpt.message;
24                    retVal["errorCode"] = excpt.errorCode;
25                } else {
26                    retVal["message"] = "There was an error in making your request, and our administrators have been notified.";
27                    retVal["errorCode"] = "UN_001"; // Internal error code for an undefined error
28                }
29            } else {
30                retVal["message"] = excpt.message;
31                // and anything else you might want
32            }
33        }
34        return retVal;
35    }

Now, there are probably better ways to write your catch statements, but I'm just trying to lay some foundation here. The basic idea is, taylor a message to send back to your users in the event of a failure. "ErrorCode?" Many enterprise products have custom error codes they use to denote that a specific error has occurred (like the above 'RC_000' for no returned records).

So, we have a success key, denoting whether the requested ColdFusion function did what we wanted. We have a data key that we use for returning the data generated by the request. And, we have a message key that we may, or may not, use only in the event of an error. We've also used and errorCode in this scenario, only in the event of an error. "Cutter, something doesn't look right?"

view plain print about
1// You use the quotes and this struct access notation to preserve the casing of key names, which is important in JavaScript
2    var retVal = {"success" = true, "message" = "", "data" = ""};
3    ...
4    retVal["message"] = excpt.message;

That should be the basics of the server side stuff. But, then the question comes, "What if our model isn't under the web root? What if the model CFC's aren't web accessible?" OK, fair enough. Then you'll need a proxy CFC. Let's regroup a sec, and show what this might look like.

view plain print about
1/*    
2 *    COMPONENT SomeComponent
3 *    Just some example component
4 *    This example sits outside the webroot, in a 'com' directory that's mapped in the CFIDE
5 *
6 *    @name SomeComponent
7 *    @displayName SomeComponent
8 *    @output false
9 */

10component {
11    /*
12    *    FUNCTION SomeFunction
13    *    This is just some function you've written
14    *
15    *    @access public
16    *    @returnType struct
17    *    @output false
18    */

19    function SomeFunction (boolean debug = false, required string arg1, required numeric arg2) {
20        var retVal = {"success" = true, "message" = "", "data" = ""};
21        var q = new Query();
22        try {
23            // do your query stuff, setting the result to the "data" key
24            
25            if (!retVal["data"].recordCount) {
26                throw(type = "ourCustom", errorCode = "RC_000", message = "No records were returned matching your criteria.");
27            }
28        } catch (any excpt) {
29            LogTheError(excpt); // Custom error logging for us
30            retVal["success"] = false;
31            if (!ARGUMENTS.debug) {
32                retVal["data"] = ""' // Clear the "data" key, so we don't pass unneeded bits back to the client. Override this by passing 'debug' into the request.
33                if (excpt.type eq "ourCustom") {
34                    retVal["message"] = excpt.message;
35                    retVal["errorCode"] = excpt.errorCode;
36                } else {
37                    retVal["message"] = "There was an error in making your request, and our administrators have been notified.";
38                    retVal["errorCode"] = "UN_001"; // Internal error code for an undefined error
39                }
40            } else {
41                retVal["message"] = excpt.message;
42                // and anything else you might want
43            }
44        }
45        return retVal;
46    }
47}

And the remoting proxy...

view plain print about
1/*    
2 *    COMPONENT SomeComponent_Remote
3 *    Just some example proxy component
4 *
5 *    @name SomeComponent_Remote
6 *    @displayName SomeComponent_Remote
7 *    @output false
8 *    @extends "com.cc.Examples.SomeComponent"
9 */

10component {
11    /*
12     *    FUNCTION SomeFunction
13     *    This is just some function you've written
14     *
15     *    @access remote
16     *    @returnType struct
17     *    @output false
18     */

19    function SomeFunction (boolean debug = false, required string arg1, required numeric arg2) {
20        return Super.SomeFunction(argumentCollection = ARGUMENTS);
21    }
22}

"Wait a second! I thought you said this post was about Ajax? Where's the JSON? Where's the Javascript?" Well, Ajax is useless without the data, right? Now that you have your CFC's and functions setup, let's look at the Javascript to make our requests. First we'll look at a basic JQuery Ajax call. First, let's set a global JS variable in the page.

view plain print about
1<cfscript>
2    param type = "boolean" name = "URL.debug" default = false;
3    
4    savecontent variable = "REQUEST.adder" {
5        WriteOutput('<script type="text/javascript">var debug = #URL.debug#;</script>');
6    }
7    REQUEST.addHeaderOutput &= REQUEST.adder;
8
</cfscript>
9...
10<cfhtmlhead text="#REQUEST.addHeaderOutput#" />

Next we'll setup our Ajax call.

view plain print about
1$.ajax({
2    url: '/my/cfc/location/SomeComponentRemote.cfc'
3    dataType: 'json',
4    data: {
5        method: 'SomeFunction', // The method we're calling
6        returnFormat: 'JSON', // Give us the return as JSON
7        debug: debug, // the global default 'debug' set earlier by ColdFusion
8        arg1: 'This is my argument',
9        arg2: 42
10    },
11    success: function (response, status, options) {
12        if (response.data) {
13            // Do something with the data
14        } else {
15            // This means the request failed, and response.data should contain
16            // a 'message' key, to present to the user, and an 'errorCode' key
17            // that you're application might act on
18        }
19    }
20});

Here's the same basic Ajax request, using Sencha's Ext JS.

view plain print about
1Ext.Ajax.request({
2    url: '/my/cfc/location/SomeComponentRemote.cfc',
3    params: {
4        method: 'SomeFunction', // The method we're calling
5        returnFormat: 'JSON', // Give us the return as JSON
6        debug: debug, // the global default 'debug' set earlier by ColdFusion
7        arg1: 'This is my argument',
8        arg2: 42
9    },
10    success: function (response, options) {
11        var response = Ext.util.JSON.decode(response.responseText)
12        if (response.data) {
13            // Do something with the data
14        } else {
15            // This means the request failed, and response.data should contain
16            // a 'message' key, to present to the user, and an 'errorCode' key
17            // that you're application might act on
18        }
19    }
20});

I'm always surprised at how few CFers know this little bit. In case you missed it, the key piece to your request parameters comes down to one important argument.

view plain print about
1returnType: 'JSON'

When this argument is passed in the Ajax request parameters, ColdFusion will automatically serialize your native ColdFusion response objects into JSON. This is what allows you to set your returnType to a struct in your function definitions.

Most of this stuff has been around for quite a while. Some use it a lot more than others. Some are just afraid of client side stuff in general. There's a ton of material out there on how to do these things. This is my way of working with it. That doesn't make it right, or better than anybody else's. It's just what I've developed as a working pattern over the years. How do you handle it?

ColdFusion Hotfix 2 Released

Yesterday, Adobe released their second cumulative hotfix for their popular ColdFusion web application server platform.

Cumulative Hotfix 2 is the result of thousands of hours of review, development, and testing by the ColdFusion engineering team. These guys (and gals) review every bug submission, ask questions and gather feedback from many people within the CF development community, and work hard to address the issues in a timely manner.

Hotfix 2 covers major and minor issues dealing with JSON serialization, ORM relations, Solr indexing, cross-site scripting security, MS Exchange integration, and much much more. See the change list for more information.

A big thanks to the Adobe CF Engineering team for their ongoing, and ever increasing support, or the web's first application server.

Learn Something New

A great man once told me that "A Day Without Learning Is A Day You're Dead From The Neck Up". I strive to learn something new every day, and this week it's really easy.

Starting today (September 12, 2011), Adobe is hosting Adobe ColdFusion Developer Week. Whether you're a long time ColdFusion developer looking to pick up something new, a Flex developer looking to learn about easy integration, or a complete programming noob looking to get started in web development, there is something for everyone in this weeks list of sessions.

Being involved in several different dev communities, I often hear "ColdFusion is still around?" If you're part of that crowd, you really need to check out some of these sessions, covering everything from the basics, to PDF generation and caching and ORM usage, to server monitoring and mobile development. There's a lot to take in here, and it's all free.

Previous Entries / More Entries