MSOC Part 9: Application Event Handlers, The Rest

So far we've spent a lot of time going over the different Application Event Handlers that relate to specific scope events (application, session, and request). Some ask "How does this relate to MSOC?", to which I have to say "Because it's important to understand application flow and control." We'll be diving into the MSOC specific bits much more in the coming posts. For now, let's wrap this part of our MSOC talk with a brief discussion of our two final Application Event Handlers: onMissingTemplate and onError.

The onMissingTemplate handler kind of does what it says. ALERT: Pay Attention To This Next Statement. This handler will be automatically invoked when a ColdFusion template or component is called but does not exist. Did you catch that? Yes, this only catches requests for templates/files that might be served by the ColdFusion application server. Setup a special mapping for CF to process .inc files? Yes, if the file doesn't exist, then this handler should catch that. A .html page was requested? Unless the server is mapped for CF to handle those requests, then no, your onMissingTemplate method will not catch that error. You get the picture yet?

The basic layout of the onMissingTemplate method is like this:

view plain print about
2 * FUNCTION onMissingTemplate
3 * Runs when a (CF) template is called that does not exist
4 * @access public
5 * @returnType boolean
6 * @output false
7 */

8function onMissingTemplate(required string targetpage) {
9    // something goes here
10    return true;

As you can see, this method is automatically passed one argument, the page being requested. Here's another catch for you, this will only catch requests for ColdFusion processed files in the same directory as your Application.cfc. So a request for will be caught, but a request for will not (This surprised me too, and I had to test it over and over again to make sure I wasn't missing something). Weird, huh? Well, that's ok. To be honest, the onMissingTemplate handler is better served by those who don't have access to change their own webserver. The better option is to setup a 404 handler in their web server configuration. In the Apache Web Server you can look for the ErrorDocument line, in your httpd.conf file, and set it to a specific template that you setup for error handling.

view plain print about
1ErrorDocument 404 /errors/404.cfm

Speaking of error handling... You do do error handling, right? You wouldn't just show end users hard errors, would you? Of course not. You've got try/catch, throw and rethrow all over the place, right?

I've never seen an app that was made to handle every possible scenario for what a user could do. Nope, never. And, I've never seen (or written) a perfect app. It's a mythical creature, like the unicorn, or honest politicians.Fortunately, Coldfusion gives us multiple levels of error handling capability, from the block level of try/catch to the server level error handler applied through the CF Administrator. The onError method allows us to apply an application level error handler, that catches anything not previously coded for (through try/catch). It can display (if desired) any error thrown from onApplicationStart through onRequestEnd, including errors thrown through the process of the request itself, but can not display content for errors thrown in the onSessionEnd or onApplicationEnd.

The onError event handler is formed like this:

view plain print about
2 * FUNCTION onError
3 * This is an application wide error handler. Best practice would be to
4 * write process specific error handling, but this method will help
5 * you trap unexpected errors for custom notification and process
6 * @access public
7 * @returnType void
8 * @output true
9 */

10function onError(required exception, required string eventname) {
11    if(StructKeyExists(APPLICATION.cfc, "errorHandler")){
12        // If the error is thrown in onApplicationEnd or onSessionEnd, the error processor
13        // will still run, but nothing will be displayed to the user
14        WriteOutput(APPLICATION.cfc.errorHandler.process(argumentCollection: ARGUMENTS));
15    } else {
16        WriteDump(var = ARGUMENTS.exception, abort = true);
17    }

The onError method is automatically passed to argments, exception (think CFCATCH) and eventname (the application event that the error was thrown in). In my example, I've used an application wide error handler to process the error, and displayed it's output (if not thrown from onSessionEnd or onApplicationEnd). My handler could do any number of things, from logging to emailing the site admin to generating error code specific text response for output, to all of the above and more.

OK, that's it for the Application Event Handlers. Let's be honest, I really only glossed over them and they still took up a lot of posts. That said, it's time to get back to the core MSOC talk, even as important as understanding all of this might have been. We have things to talk about, like directory structures, shared and specific asset handling, extended application models, and more. Give me your feedback: What are your most pressing questions on running Many Sites with One Codebase?

2011 In Review, and the View for 2012

My, how time flies when you're having fun! It seems like only yesterday that I was welcoming in 2011, and now we're here a year later. So many things have happened in the last year, and rereading that post I see that I missed some things I should've done, but let's take a look in retrospect.

I wrote 27 blog posts in 2011. This is nothing, compared to guys like Ray Camden or Ben Nadel, but for me it was quite a bit, especially when you consider that between March and August I released only one post. Very early in the year, I began a series on creatingmany sites with one codebase. In the process, the series has evolved to contain a fairly detailed primer in ColdFusion application architecture (because of it's importance to this process), has currently spanned 8 separate posts, and was even referenced by Sean Corfield in his great presentations on the same topic. 2012 will see the completion of that CF app discussion, and gradually move it back to the MSOC topic itself, as there is still a ton to talk about there, and a lot of interest in the topic. I also began a series on the jqGrid JQuery plugin. jqGrid is another Data Grid visualization tool (I have now written about three, including Ext JS and DataTables), and is a clear choice for those who must use JQuery. (To be fair, JQueryUI is working on a grid component, but they are still behind the curve, and way behind Sencha.) Finally, one common thread seen in the majority of my posts, is how much I've embraced cfscript. I wrote a lot of things, on a variety of topics, but most of my code examples were pure scripted examples.

Now let's talk about some other departures from the norm for Cutter.

You did not see a lot of content around Ext JS. In fact, I stopped writing Ext JS books. This is not, in any way, a reflection on my feelings for Ext JS. I still believe that Sencha has built one of the best client-side libraries for web application development. In evaluating the overall ROI, I realized that I was writing more for the community than the money, and that my reach was greater through my blog, while giving me flexibility on when and what I deliver from a content standpoint. That said, I didn't have a single project this year that used Ext JS, so had very little time to experiment and write about it. This year, I'm going to expand on a personal project, and get back to some great Ext JS content for my readers.

You, also, did not see me speak at any conferences this past year. Nor at any user group meetings. This wasn't because I didn't want to, but because of some more personal reasons. I'm not going to go in depth here, other than to say that I've had some long standing health issues that required me to have some surgery done on my mouth. (Mark Drew is making a joke right now...) Aside from the fact that this has been very costly (chewing up any conference/travel budget), it also meant that my speech has been affected for a good part of the year. Thankfully this experience is (mostly) over now, and I hope to get back to presenting sometime this year. Any user group looking for a speaker this year, please contact me through the Contact link on this blog.

One group I am hoping to speak to this year is the Northeast Florida CFUG. I have to call Mike back, but he's looking to get things kicked off again, and I want to help it be successful. If you're in or around the Jacksonville area, make sure to keep an eye on the site for upcoming events.

One other thing I'm looking to do is to migrate all of my projects into GitHub. I've been using Git at work, and I am loving it, and I think combining GitHub with RIAForge is a great way to promote the terrific technologies we work with every day. I will make the time, I promise.

This comes to the final discussion of this post, Adobe. I again had the pleasure of being an Adobe Community Professional this past year. Due to my health issues, I didn't get to do everything I would've wanted to this year, but I've tried to be a good supporter. There are some fabulous things coming in ColdFusion Zeus and, by extension, to ColdFusion Builder as well. There has been a lot of hub-bub over Adobe's communications flubs regarding Flash, mobile, and Flex. I've avoided much of the discussion, other than to say "be patient and watch". Flash isn't going away, and neither is Flex. HTML 5 is a beautiful thing, if you aren't developing desktop browser applications (i.e. You're only writing for mobile/tablet development). There, that is my whole contribution to that discussion. Give it a rest.

2012 will be a fantastic year. Set yourself some clear, definable goals. Break them down, step by step, and write the steps down on paper. Each successive step, print out in large letters and place it somewhere where you will see it each and every day. Set yourself up to succeed, and you will. Have a great year, everyone, and I can't wait to hear what you have planned for 2012.

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.


MSOC Part 7: onSession Event Handler

Wow! I just discovered that this post has been sitting since February, waiting to be finished and posted. Time flies! Well, now that I've upgraded to the latest version of BlogCFC, it's a good time to add a new post.

In our last post, in this series, we talked about the onApplication event handlers, which automatically fire when a ColdFusion application starts and ends. This go around we'll discuss the onSession event handlers. As you may have guessed, the onSession handlers (onSessionStart and onSessionEnd) wrap a user session. The onSessionStart method fires when a user first visits an application, allowing you to initialize any SESSION scope variables.


MSOC Part 6: onApplication Event Handlers

In our last MSOC post we gave a brief introduction to the ColdFusion application framework's event handlers. With this post, we'll give a brief explanation of the onApplication handlers.


The CFC constructor is the first thing that processes on a request, but the first request to an application will then run the onApplicationStart() method. This method will run prior to any other code in the request, and is your opportunity to setup variables in the shared APPLICATION scope. Within the onApplication handlers, you are able to manipulate the APPLICATION scope without being required to lock access to the scope, as no other process can access the variables until the method is completed, and preventing race conditions.

The APPLICATION scope is a where you place those variables you will use throughout the entire application. For instance, you may wish to keep a simple variable that holds the phone number for your Customer Support team, so that if the number changes it can instantly update throughout the site. The APPLICATION scope is also where you would store objects that you would use throughout your application, like a user or page manager.


As you might have guessed, this is the last method to fire during the lifetime of your application. In your constructor you would have set THIS.applicationTimeout. This is the length of time that the application will continue to live after it's last request. After this timeout limit is reached is when the onApplicationEnd will fire. This allows you to do some cleanup, or some application level logging. It is important to note that this only occurrs if the application does timeout. It will not fire if the server instance is shutdown/restarted.

Consider This

When you want to write to the APPLICATION scope from one of the other event handlers, you must lock access to prevent race conditions. You may, in your onServerStart method, have created a struct to log each active application (start up, last hit, timeout, number of sessions). When accessing the SERVER scope, you must also lock access.

You also have to heavily consider how much work you're putting into each of these event handlers, especially within the onApplicationStart. The more process you have there, the longer the startup time is for your application. It will be up to you just how much of a trade off that startup time is to the overall performance of your application.

The last thing you must consider (and I'll say this a lot during this series) is what variables and objects belong in what scopes. Remember that everything you place in the APPLICATION scope adds to the overall RAM utilization of that app. Everything you place in the SESSION scope will add to the overall RAM utilization of that session. This is especially important to consider in an MSOC environment. Try to think of it in these terms: the size of the SERVER scope + THE size of every APPLICATION + the size of every SESSION in every application must be less than the amount of RAM allocated to your ColdFusion instance. Careful planning is critical.

In our next piece we'll discuss the onSession event handlers. Hopefully you're finding this series beneficial. As always, any feedback/comments/questions are welcome.

MSOC Part 5: Application Event Handlers, An Intro

Handling the "big picture" application flow in ColdFusion is extremely easy, as a large part of it occurs directly in your application's Application.cfc file. Getting a handle on what's going on, in an MSOC app or any other app, is a matter of managing that application flow effectively. If you have a solid understanding of the event handlers available to you, then you can really begin to see the power behind ColdFusion's application framework.


MSOC Part 4: Application Constructor

OK, we're still working through setting up our Application for a Multi Site One Codebase scenario, and we haven't really gotten into the application yet (aside from dynamically setting the application name). Now is where we really have to take some serious consideration to variable scoping and application workflow. Thing is, there are dozens of ways to skin this cat (no, the view layer stuff comes later). The things we'll talk about in these next several posts aren't MSOC specific either, as they can apply to most any application. The first step is getting a hard handle on what you can do within the Application.cfc, and start to use it as intended.


MSOC Part 3: Setting Up Your Applications

In part two we setup our web server to handle trafficing multiple domains to our single codebase, but now we have to get our applications setup. This is where we have to start thinking about separation. Since each domain is driven off the same set of physical files, we now have to consider how we separate one domain's sessions/actions/resources from another. You don't want one user's session to be cross domain in any way, and it wouldn't be good to have the media assets of one site displaying on another. Where do we begin? With the code.


MSOC Part 2 - Web Server Configuration

When you're writing an application to run on multiple domains, but using a single copy of code, the first thing you have to work out is your Web Server Configuration. Basically there will be a DNS entry for each domain pointed to your server's IP Address. Then your web server will have to be configured to handle those domains. Rarely, in an MSOC environment, will you need a separate site entry for each site you're serving, requiring one entry to serve all sites. If you're working with IIS on Windows you could just use the Default Web Site entry in your IIS manager. Apache is a little different.


Many Sites, One Codebase

The ultimate of reusable code: using one codebase to serve many sites. Not copies of that codebase mind you, but one actual set of code templates. Update a template to fix a bug or add a feature and...? Presto! You've just updated X number of sites at once. Genius! Or is it?