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
1/**
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;
11}

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 mysite.com/nothere.cfm will be caught, but a request for mysite.com/some/random/path/to/nothere.cfm 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
1/**
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    }
18}

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?