YOUR FEEDBACK
sahil wrote: help
AJAXWorld RIA Conference
October 20-22 San Jose, CA
Register Today and SAVE !..


2008 East
DIAMOND SPONSOR:
Data Direct
Frontiers in Data Access: The Coming Wave in Data Services
PLATINUM SPONSORS:
Red Hat
The Opening of Virtualization
Intel
Virtualization – Path to Predictive Enterprise
Green Hills
IT Security in a Hostile World
JBoss / freedom oss
Practical SOA Approach
GOLD SPONSORS:
Software AG
The Art & Science of SOA: How Governance Enables Adoption
PlateSpin
Effective Planning for Virtual Infrastructure Growth
Fujitsu
Automated Business Process Discovery & Virtualization Service
Ceedo
Workspace Virtualization
Click For 2007 West
Event Webcasts

2008 East
PLATINUM SPONSORS:
Appcelerator
Think Fast: Accelerate AJAX Development with Appcelerator
GOLD SPONSORS:
DreamFace Interactive
The Ultimate Framework for Creating Personalized Web 2.0 Mashups
ICEsoft
AJAX and Social Computing for the Enterprise
Kaazing
Enterprise Comet: Real–Time, Real–Time, or Real–Time Web 2.0?
Nexaweb
Now Playing: Desktop Apps in the Browser!
Sun
jMaki as an AJAX Mashup Framework
POWER PANELS:
The Business Value
of RIAs
What Lies Beyond AJAX?
KEYNOTES:
Douglas Crockford
Can We Fix the Web?
Anthony Franco
2008: The Year of the RIA
Click For 2007 Event Webcasts
SYS-CON.TV
TOP COLDFUSION LINKS


Caching Redundant Dynamic Content With Custom Tags
Caching Redundant Dynamic Content With Custom Tags

What do you do when you want to get even better performance out of your most efficient application code?

It can be difficult to keep total page execution time low when processing a complex page. Developers are tasked with finding ways to make apps perform better everyday. By statically storing redundant results of a dynamic page, you can get a CF site to run exponentially faster.

CFHTTP, CFCACHE, and custom tags allow you to create static versions of an entire page, but only custom tags give you the flexibility to cache the results of portions of code, unleashing some awesome possibilities.

A Common Challenge
If you're like me, you do all your SQL queries with <CFQUERY> when developing a new page. Any CF developer knows this is not the preferred way to do things. We know we should use stored procedures because they're precompiled, so we create stored procedures out of each working <CFQUERY>. Some developers time their code and rewrite it in an effort to shave off milliseconds from their total execution time. Maybe you've tried everything, and you want to go even faster.

This is a situation I've been in. I wanted to make sure that each piece of my project was working at maximum capacity. My site was template-based and it became clear that each time a page was built, ColdFusion Server was doing a whole bunch of unnecessary work.

The Web application had three classic features: a navigation bar that the site administrator could change by logging in; the ability to modify content on the main page of the site; and a rotating ad management system - changes that were all stored in the database (see Figure 1).

The problem was that each time a visitor requested the main page, my application would query for the elements of the navigation bar, query for the main page content, and query for the banner advertising. If my site gets a million requests per day, that's 3 million queries right there. And for what? If the only thing that's changing between page re-quests is the advertising, why query for the navigation bar and the main page content over and over again? The application is running 2 million redundant queries per day.

This is the point at which many CF developers would mention cached queries. However, what if you have a cluster of machines and need to run 400 hefty queries? ColdFusion can only cache 100 queries. If you're an ASP, that's not enough.

Creating Static Pages
One way you can maximize your resources is to create static pages based on dynamic ones. Then, you just serve off the static version of your page and ColdFusion Server doesn't need to do any work for each page request. You can use CFHTTP to grab the HTML being served from a dynamic page, and then use CFFILE to write it off as a regular .html file. CFCACHE does the same thing in a single step, as does the procedure of saving the output of a ColdFusion scheduled task, described in Chapter 5 of Allaire ColdFusion Web Applic-ation Server 4.5, "Administrating Cold- Fusion Server".

The main problem I had with the CFHTTP method was that by creating a static version of the entire page, the resulting static page could no longer rotate banners or count banner impressions because it was no longer a .cfm file. Even if you end the resulting file with ".cfm", CFHTTP will return the same HTML content that you get when you view the source code of a page in your browser - HTML with all CFML removed.

I needed to find a way to generate partially static main pages. I say "partially" because I needed to maintain my ability to manage dynamic banner ads in ColdFusion, but at the same time, reduce the load on my CF boxes. It didn't make any sense to query for the navigation bar and the main page content for each page request because that rarely changed - that was the part I wanted to be static. Also, I didn't want to deal with CFHTTP because it was a bit slow, and I would need to reconfigure my production firewall in order to get CFHTTP requests from my production servers that are directed at my load balancer to work right. The solution was in a special variable called thisTag.generatedContent, available in any closing custom tag.

thisTag.generatedContent
In case you're not familiar with this custom tag feature, you must first understand that custom tags have execution modes. Most developers call only the START mode without even knowing it. That's because you're in START mode when you call a given custom tag like this:

<cf_exampleTag>
In exampleTag.cfm, you can check what mode you're in by using a special variable called thisTag.-executionMode. You're in END mode only in closing custom tags, which are called when you pass a slash in the tag, like this:
</cf_exampleTag>
This allows you to use a CFSWITCH statement or a CFIF conditional statement in your custom tags to do certain things depending on which mode you're in. You could use the following code construct in the exampleTag.cfm:
<CFIF thisTag.executionMode IS "START">
<!--- Execute your code for start mode here --->
<CFELSEIF thisTag.executionMode IS "END">
<!--- Execute code for end mode here --->
</CFIF>
Using these modes in conjunction with thisTag.generatedContent, you can grab the results of everything that happens between an opening custom tag and the corresponding closing custom tag. In the next example, I'll create a navigation bar based on a query:
<cf_grabTheNavBar>

<cfoutput query="navBarInfo"> <a href="#anchor#">#navText#</a><br>
</cfoutput>
</cf_grabTheNavBar>
There would be a variable available in </cf_grabTheNavBar>'s END execution mode called thisTag.-generatedContent, which contains the result of everything that happened between the <cf_grabThe-NavBar> and </cf_grabTheNavBar>. In this case, thisTag.generated-Content contains the resulting HTML content for the simple navigation bar:
<a href="main.cfm">Main</a><br>
<a href="company.cfm">Company</a><br>
<a href="contact.cfm">Contact Us</a><br>
While you're in <cf_grabThe-NavBar>'s END execution mode, you can do some cool things like change what the generated content is. In the next example, I'll take the generated content and CFFILE WRITE it to a .txt file, then clear the variable so nothing appears on the Web page. This is what my custom tag named grabTheNavBar.cfm would look like:
<CFIF thisTag.executionMode IS "START">
<!--- I won't do anything here. --->
<CFELSEIF thisTag.executionMode IS "END">
<!--- Write the content to a file. --->
<CFFILE ACTION="WRITE"
ACTION="C:\myCFcache\sam ple.txt"
OUTPUT="#thisTag.generatedContent #">
<!--- Hide from browser display. --->
<cfset thisTag.generatedContent = "">
</CFIF>
In this example, I've created a text file out of thisTag.generatedContent using CFFILE. Later, I can CFINCLUDE that .txt file on the main page of my site without having to query for it every time the page is requested.

I used this technique to solve my problem. I set up my application to write off the results of the navigation bar and of the main page content when they changed. On my main page, I had two simple CFINCLUDEs that bring in the preprocessed results. This way, I no longer have to waste my resources querying to get the same information for each page build. I have to query for it only once and write it off when the site administrator makes changes. With this simple technique, I got my application to perform five times faster because the database access on my main page was reduced to banner advertisement activity only.

Some other benefits of using thisTag.generatedContent instead of CFHTTP are:

  • The data is prepared much faster.
  • Your server will not count the static page generation as a page view or banner impression.
  • You free up CFHTTP threads for other things.
  • CF server doesn't need to be able to access itself. This could be troublesome depending on firewall settings.
Security
Maybe you realize that by using the method described above, I make my main page vulnerable to a form of cross-site scripting. This means that the user responsible for editing site content could write ColdFusion code in the navigation bar or main page content that would be executed. For example, say the user wrote the following sentence in his or her main page content:
"ColdFusion is great. My favorite tag is the <CFABORT> tag."
thisTag.generatedContent would write that string to a .txt file via CFFILE, and then it would be included via CFINCLUDE when users browse the site. CFINCLUDE not only includes a file, but executes the included code as well. The <CFABORT> would be evaluated by ColdFusion Server and page processing would subsequently halt.

Using CFINCLUDE can mean big problems if you CFINCLUDE any random user's saved file. Somebody could write very nasty code that could do just about anything to your file system or database. Therefore, only use CFINCLUDE when you trust the author, or you want to be able to create executable CF code from within your application.

If you're concerned about unexpected ColdFusion code, one alternative that seems to work quite nicely is CFFILE READ instead of CFINCLUDE.

<CFFILE
ACTION="READ"
FILE="C:\myCFcache\sample.txt"
VARIABLE="staticContent">
This way, the contents of your .txt file are stored in a ColdFusion variable that you simply CFOUTPUT.
<CFOUTPUT>
#staticContent#
</CFOUTPUT>
When ColdFusion code is stored inside the text content of a Cold-Fusion variable, it's not evaluated. Therefore, the <CFABORT> will never be executed by ColdFusion Server. Instead, it flows into the HTML source and is sent to the browser.

Conclusion
There are lots of ways to optimize your code. It may be worth your while to figure out which parts of your code don't need to be dynamic for every page build. You may not have the need to keep some parts of a page dynamic, so you use the CFHTTP method. However, in ColdFusion 4.x, custom tags provide a faster way to render the complete page, or just certain parts of it. Let's see how Macromedia can make this technique less complex with the upcoming release of ColdFusion Server 5.

About Jon Block
Jon Block is the lead ColdFusion developer at Members Connect, Inc., in Boston. He is one of the cofounders of the firm's proprietary content management system.

CFDJ LATEST STORIES . . .
Kevin Lynch, who will be keynoting on October 21, 2008, helped originally coin the term "Rich Internet Application" in 2002. He has been at the center of innovation in Flash and Adobe AIR since their inception, and currently drives Adobe’s technology platform for designers and develo...
Rich Internet Applications offer the potential to fundamentally change the user experience and in doing so, yield significant business benefits. The theme of this October's AJAX World Conference & Expo 2008 West is 'Beyond AJAX to the RIA Era' and the Call for Papers, which is still op...
Join Scott Guthrie as he discusses Microsoft’s commitment to web standards development, Rich Internet Applications and how Microsoft is contributing to help move the web forward. Join Adobe’s Kevin Lynch as he demonstrates how Flash and HTML come together to make the most engaging,...
Virtualization has become a critical part of Enterprise IT strategy. Why and how has it become one of the most important change agents in our industry? To answer these questions I had the good fortune recently to be able to speak to a select group of top IT industry executives who join...
SQL Injection attacks are one of the easiest ways to hack into a website. One recent hack, using a script from verynx.cn, involves injecting sql into a web form that then appends some JavaScript code into fields in a database that then gets executed on the client side when a user views...
Recursion Software released a private beta version of their Voyager mobile platform, with powerful interoperability for Android, Microsoft .NET and Compact Framework (CF), all Java editions (JME CDC, JSE and JEE), and more than 15 embedded operating systems. The Voyager platform is a p...
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS
SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021


SYS-CON FEATURED WHITEPAPERS

MOST READ THIS WEEK
ADS BY GOOGLE