New Job, New Home, A Lot of Work

It's been a very busy year, up til now. Work ramped up in February, contracting me for additional hours for a month and a half straight, after which I've worked on a sting of side projects. This helped me finance a move to Jacksonville, Florida. My new (daytime) job is full-time telecommute, which allows me to put my desk anywhere. Teresa wanted to get back to sunshine and beaches, being tired of the cold and snow of Tennessee winters, and chose Jacksonville for it's location and proximity to family and friends. Jacksonville is a great area, and we nailed a terrific place in Fleming Island. I like it because there's lots of tech (user groups and such), and it's not far from other tech centers (Orlando, Tampa, Atlanta, etc). It doesn't hurt that I can maintain a year around tan or that the beach is a short drive away.

A lot of work has come my way, often tacking an additional 40 to 60 hours a week on top of my normal day job schedule. Often I'll take a project that takes a week or two, then take a few weeks off to spend with the family (and catch up on my reading). I have a list of posts I need to write, due to exposure to some projects I hadn't previously been exposed to. Part of that already started with some exposure to the DataTables JQuery plugin, but I'm also lining up posts for jqGrid, jsTree, and the cfUniForm project. Evernote is filling up with little tidbits. The most difficult piece is coming up with the time to write examples. I'm particular about writing well formed code and documentation, which is why my posts sometimes get spaced out a bit.

One of the things I have discovered, in my exposure to these other projects, is how much I miss working with Ext JS day-to-day. JQuery UI is a good project, but lacks the maturity of Ext JS, and is missing too many key components for writing web applications (Data Stores, Grid, Tree, Menus, Tooltips, etc). My exposure to those other projects was an attempt to fill needs for which Ext JS would have been better suited, while locked into using JQuery UI. The JQuery UI team is working on closing that gap, but there is a lot of catch up necessary to match the breadth and power of Ext JS.

Speaking of Ext JS, Packt Publishing asked me to write the next Ext JS book on my own. While very flattered, I had to carefully weigh what that commitment would mean. Ultimately, I could not justify committing seven and a half months to writing the book with all of the other responsibilities I have right now. I will write a few articles for Packt (as part of my contract on the last book), but feel like I can continue to create blog content that would be more timely (no six month editorial process) and have a greater reach, and do so as my schedule permits without being a burden on my family. Sencha has already announced What to Expect in Ext JS 4.1, and recently put Ext Designer 1.2 in Beta, so there's a lot to talk about here.

Last, but definitely not least, I'm following all the buzz about the upcoming ColdFusion "Zeus". A quick Google Search already brings up a ton of info that Adobe has put out regarding the next version of the ColdFusion server platform, and it looks to once again be a significant release. Some of the big things already mentioned have been the move from JRun to Tomcat, the retirement of Verity in favor of Solr, the upgrade to Axis 2, and the inclusion of closures in CFML. That's just some of what's coming, as Adobe appears to be giving more and more detail during the various conferences through the year (and you never know the whole story until it's released).

The Next Wave: Ext JS 4 Beta 1

I only have a few minutes, as I am totally buried right now, but I wanted to reach out to everybody to spread the word about Ext JS 4 Beta 1 being released yesterday. Some of you may have been following the Developer Previews on the Sencha Blog, and if you have you already know some of the amazing work coming out of Sencha for this release. If you haven't, well let me give you a really quick recap of some of what you could expect:

There's also an entirely new rendering engine under the hood, new components, and more. You can even run Ext JS 3 & 4 on the same page, if needed. Go to the Sencha site to see some great examples of what you can do. It is still a beta, so the forums are pretty busy with people learning the ropes and filing bugs as they're found, but the foundation has been laid for a truly ground-breaking update to this library.

Java RegEx replaceAll In ColdFusion

In an odd turn, I was given text like below to display on a page.

view plain print about
1Some Title<br />
2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A.&amp;nbsp;&amp;nbsp;Some&amp;nbsp;subheader&amp;nbsp;here<br />
3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;B.&amp;nbsp;&amp;nbsp;Some&amp;nbsp;other&amp;nbsp;subheader&amp;nbsp;here<br />

Two issues here (aside from the fact that it should have been an HTML list): 1) it needed to retain the spacing format, and 2)it needed to wrap within a sized element. A non-breaking space, when viewed, appears as a space ( ), but isn't an actual space, so the browser doesn't know where to break the text when wrapping it in an element. Hmmmm....

[More]

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.

onApplicationStart

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.

onApplicationEnd

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.

Using The DataTables JQuery Plugin

For adminstrative applications, most of my readers know I'm a huge proponent of the Ext JS library. But for front-end, consumer facing sites, I'm often pushed to use JQuery. JQuery is very light weight, and wonderful for DOM manipulation, but it isn't a component library. When you want widgets for advanced data display, you have to use something like JQueryUI. Unfortunately, JQueryUI doesn't yet have a grid component (though they are working on it). So when I recently needed a dynamic, paging data grid, I started looking for something that used server-side data requests and could be skinned using the ThemeRoller. That's when I came upon the DataTables plugin.

It took me some time to figure out the works of how the plugin makes server-side requests. What I found was that, by default the plugin passes an extreme amount of data on a request, and not typically in a format very conducive for our needs. I also had to find a way to pass the method name and data returnFormat needed. That's when I discovered that I could override it's default request. Once I figured that out, I wrote a method to parse the data to create a request object more conducive to a ColdFusion Component request. It passes the following arguments along in a request:

  • iDisplayStart - The number of the first record in the requested set.
  • iDisplayLength - The number of records to return in the requested set.
  • sEcho - A DataTables request identifier, to be echoed back with the return.
  • aoSort - If present, this will be a JSON string representation of sort columns and orders. It's an array of objects:
    • colName - the column name
    • sortDir - the sort direction (asc|desc)

After getting data to my CFC, I had to build my paging query. For my example here I wanted to use the MySQL database I use for my blog, so this was a learning experience for me. The biggest trick for me was getting the TotalCount of records, as this is extremely different from MS SQL, requiring two separate SQL statements for the query and the count. Since DataTables can also sort off of different columns, I needed a way to dynamically set the ORDER BY clause of the query. You can't bind parameters to the ORDER BY clause, but you want to protect your server from SQL injection attack, so you have to validate that part of the request (especially as it's an ajax request, which would be easier to manipulate). Pete Frietag came up with a little regex expression that could be used in this case.

We set up our component to return a structure in the following format:

  • success - A boolean to denote success or failure of the request.
  • message - Only returned if the request fails, a message to state why the failure occurred.
  • totalCount - The total number of records available for the filters applied.
  • result - The paging query.

The last piece of the puzzle was back on the client-side again, where the ColdFusion return had to be put back into a format that can be consumed by the DataTables plugin. This was actually very easy because of the way that ColdFusion returns query data.

Once I had these methods, I wanted to find out how to write a feature plugin for DataTables. One where I could identify additional config arguments in DataTables, and have it automatically work. I contacted Allan Jardine, who wrote DataTables (and has some great web dev tools on his site). He never wrote in that capability, saying that the method override was the only way to make this happen. What I did discover was that I could add options to the standard DataTables config. I created a new option for DataTables, oCFReaderDT, which takes an object of options. Only one argument is required, "method", to define the method to call in the CFC request. I also setup the processor to accept an option, "sForm", as a string selector of a form whose values you may need in the request (i.e.: 'form#myForm'). Then I wrote a custom function that encapsulated the previously written methods into one method, that could then be used as the value of the "fnServerData" option in the DataTables configuration object.

In the download link below is a zip file with all of the files for the example, which has been heavily commented so you know what's going on. Though written for ColdFusion 9, I have included both scripted and non-scripted CFC's. I hope you find this useful, and please leave any comments/questions/suggestions through the Comment Form or Contact links below.

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.

[More]

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.

[More]

I'm an ACP again for 2011

Once again I slid under the radar to become an Adobe Community Professional in 2011. I am, again, extremely humbled and honored to be included in such excellent company. Last year was my first year as an ACP, and events of last year prohibited me from being as involved as I would like (I've already posted more this month than all of last year put together), so I was very happy that I made the list again this year to get it on target. For those unfamiliar with the program:

The Adobe Community Professionals Program is a community based program made up of Adobe customers who share their product expertise with the world-wide Adobe community. The Adobe Community Professionals' mission is to provide high caliber peer-to-peer communication educating and improving the product skills of Adobe customers worldwide.

Adobe has also introduced a new community program, Adobe Community Champions. This is a new program for those who maybe don't have the time to write as much, or possibly the fiscal resources to speak at conferences, but are no less vocal in their support of Adobe products or in helping to educate newer members of the community. Congratulations to this new group. In brief:

Adobe Community Champions are the "megaphone" of the Adobe community, whose objective is to evangelize Adobe products beyond the existing circle of our Adobe ecosystem and helping connect people to the Adobe community.

2011 is going to be a great year, and I can't wait to see what Adobe has in the works. Congratulations to all the new and returning ACP's, and the new ACC's.

Scripted Noob: Queries (and Issues)

OK, I'm not a noob. Not even with cfscript. In fact, I love cfscript, and prefer to script as much as I can. ColdFusion 9 created a much greater degree of parity between cftags and cfscript. Unfortunately, the events of the past year and a half have left me with few opportunities to work on ColdFusion 9, so I'm playing catch-up on some of these great new enhancements. I did script the application.cfc back in October of 2009, but aside from that I was buried in writing a book, new job responsibilities, and more. I'm working to write all future ColdFusion examples in as much script as possible, but I still hit the occassional hurdle and ask for help.

So, while writing my examples for my last post, I kept hitting a snag while scripting a query. After banging my head on the wall for a while, I finally pinged the ColdFusionJedi himself for assistance. Ray probably though I was off my nutter, having never scripted a query, but we did run into something worth talking about.

First, I've gotten into a habit of scoping querynames. Why? If you didn't (in ColdFusion 8 or earlier) they were part of the VARIABLES scope. This can give you unintentional results, if you aren't careful, so I'd gotten into scoping querynames.

view plain print about
1<cffunction name="getSiteId" output="false" access="public" returntype="struct">
2     <cfargument name="cgiScope" required="true" type="struct" />
3 <cfset var LOCAL = StructNew() />
4 <cfset LOCAL.retVal = StructNew() />
5 <cfset LOCAL.retVal['success'] = true />
6 <cftry>
7     <cfquery name="LOCAL.qSiteId" datasource="#VARIABLES.instance.dsn#">
8     SELECT    siteId
9 FROM    sites
10 WHERE    urlAddress = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.cgiScope.server_name#" />
11 </cfquery>
12 <cfif LOCAL.qSiteId.recordCount>
13     <cfset LOCAL.retVal['result'] = LOCAL.qSiteId />
14 <cfelse>
15     <cfthrow type="My_Custom" errorcode="001" message="No siteId was found for this domain." />
16 </cfif>
17 <cfcatch type="any">
18     <cfset LOCAL.retVal['success'] = false />
19 <cfset LOCAL.retVal['message'] = CFCATCH.message />
20 <!--- Any other error handling --->
21 </cfcatch>
22 </cftry>
23 <cfreturn LOCAL.retVal />
24 </cffunction>

We'll come back to that in just a minute. I also like to pass argumentCollections into functions. Maybe it's just me, but it's something I do. So, I created a collection to pass into the constructor of a new Query.

view plain print about
1// THIS DIDN'T WORK!!!
2
3 /**
4 * FUNCTION getSiteIdByUrl
5 * @access public
6 * @returnType struct
7 * @output false
8 */

9 function getSiteIdByUrl(required struct cgiScope) {
10 LOCAL.retVal = {};
11 LOCAL.retVal['success'] = true;
12 LOCAL.qPrms = {};
13 LOCAL.qPrms.name = "LOCAL.qSiteId";
14 LOCAL.qPrms.datasource = VARIABLES.instance.dsn;
15 LOCAL.qPrms.sql = "SELECT siteId
16 FROM sites
17 WHERE UrlAddress = :urlAddress";
18 LOCAL.q = new Query(argumentCollection = LOCAL.qPrms);
19 LOCAL.q.addParam(name = "urlAddress", value = ARGUMENTS.cgiScope.urlAddress,
20 cfsqltype = "cf_sql_varchar");
21         try {
22     LOCAL.retVal['queryResult'] = LOCAL.q.execute();
23 if (!LOCAL.retVal.queryResult.recordCount) {
24     throw (type = "My_Custom",errorcode = "001",message = "No siteId was found for this domain.");
25 }
26 } catch (any excpt) {
27     LOCAL.retVal['success'] = false;
28 LOCAL.retVal['message'] = excpt.message;
29 // other error handling here
30 }
31 return LOCAL.retVal;
32 }

Alright, it seems to look OK, right? So why is it erroring? Well, Ray first told me to break it down some. Make it simple, remove the param, stuff like that. No dice. Then he said use getResult() after the execute statement. Uh huh. Then I decided to take the LOCAL scope out (it's local anyway, right?) Still no dice. Finally Ray said "Don't use argumentCollection." Use the set methods instead. Bam! It worked! I thanked Ray for the assist, and went back to recreating the full function.

Whoops! Not working again. Could not find retVal.qSiteId in LOCAL (or something like that). Now what? But then I saw I had put the LOCAL scope back on the query name. Took it off, and it worked like a charm.

view plain print about
1//    THIS WORKS GREAT!
2
3 /**
4 * FUNCTION getSiteIdByUrl
5 * @access public
6 * @returnType struct
7 * @output false
8 */

9 function getSiteIdByUrl(required struct cgiScope) {
10 var retVal = {};
11 retVal['success'] = true;
12 var sql = "";
13 var q = new Query();
14 q.setName("qSiteId");
15 q.setDatasource(VARIABLES.instance.dsn);
16 sql = "SELECT siteId
17 FROM sites
18 WHERE UrlAddress = :urlAddress";
19 q.setSQL(sql);
20 q.addParam(name = "urlAddress", value = ARGUMENTS.cgiScope.urlAddress,
21 cfsqltype = "cf_sql_varchar");
22         try {
23     retVal['queryResult'] = q.execute().getResult();
24 if (!retVal.queryResult.recordCount) {
25     throw(type = "My_Custom",errorcode = "001",message = "No siteId was found for this domain.");
26 }
27 } catch (any excpt) {
28     retVal['success'] = false;
29 retVal['message'] = excpt.message;
30 // other error handling here
31 }
32 return retVal;
33 }

Now, I should go back and test argumentCollection without the LOCAL scope on the query name, but for now I'm just happy that it works. I really do love scripting, and see where this really brings ColdFusion (once again) to another level as a language choice.

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.

[More]

Previous Entries / More Entries