Categories
Contact Doug!
Learn About Doug!
View Doug Boude's online resume
updated 11/18/2009

View Doug Boude's profile on LinkedIn
Link to me!

Follow Doug Boude on Twitter
Follow me!

Be Doug's friend on Facebook
Befriend me!
(I promise not to follow you home)
OO Lexicon
Chat with Doug!
Recent Entries
You may also be interested in...
Web Hosting

<< June, 2006 >>
SMTWTFS
123
45678910
11121314151617
18192021222324
252627282930
Search Blog

Recent Comments
Re: Disappearing IE Popup Window During Save/Open Dialog (by LZ at 4/20 7:58 AM)
Re: Create Dynamic WHERE Clauses in PHP (by pooja at 3/20 7:29 AM)
Re: Just What IS a 'Service Layer', Anyway? (by EugenK at 3/07 7:56 PM)
Re: Using Google as your CF Mail Server (by 5starwebteam.com at 2/25 1:27 AM)
Re: Why Provide for Service layer objects in CFWheels? (by Steven Benjamin at 1/25 11:43 AM)
Re: What is an 'Advanced' Coldfusion Developer? (by ColdFusion Developer at 12/24 5:14 AM)
Re: Equivalent of SQL "TOP X" in Oracle (by Ashenafi Desalegn at 12/06 5:29 AM)
Re: PHP Export to Excel Snippet (by serene at 12/05 1:44 AM)
Re: Just What Is 'Application Logic', Anyway? (by Arif at 11/13 8:06 AM)
Re: Hosts File Changes Not Acknowledged on Vista 64 (by Aaron at 10/22 2:31 PM)
Re: PHP Export to Excel Snippet (by Jafar Shah at 10/10 4:28 AM)
Re: Viewing Option Text (in IE7) that's Wider than the Select List (by Chenelle S at 10/04 12:53 PM)
Re: PHP Export to Excel Snippet (by Kilo at 9/26 5:20 PM)
Re: Porting Coldfusion Code to Mura (by tariq at 9/03 9:51 AM)
Re: Just What IS a 'Service Layer', Anyway? (by James at 8/27 4:06 PM)
Re: Calculating Business Hours (by helen at 8/14 2:54 AM)
Re: What IS 'Business Logic', Anyway? (by dougboude at 8/06 11:30 AM)
Re: What IS 'Business Logic', Anyway? (by Adrianne at 8/06 10:29 AM)
Re: Family Law: The Weapon of Choice for Woman Scorned (by dougboude at 8/04 4:39 PM)
Re: Family Law: The Weapon of Choice for Woman Scorned (by Lola LB at 8/04 7:43 AM)
Archives
Photo Albums
Funnies (5)
Family (3)
RSS

Powered by
BlogCFM v1.11

30 June 2006
CFUNITED - Coldspring and AOP made simple
If you've been anywhere near a blog or even another CF developer lately, it's quite likely you've at least heard of Coldspring, and you may even be aware that it is a 'framework'. In an informative session entitled 'Inversion of Control and Coldfusion: Using Coldspring', speaker Dave Ross succeeded in conveying a good basic understanding of what Coldspring does and why you should consider it as part of your application's architecture.

CFCs objects have the very useful ability to utilize other CFC objects within themselves. For instance, I may have a USER object that handles all aspects of a user, and an EmailServices object that handles aspects of email for my application. By creating an instance of my EmailServices object inside of my User object, my user object can, internally, utilize whatever methods EmailServices provides. In order to accomplish this from a coding perspective, however, we essentially have to do one of the things that OO says we shouldn't: hard code the relationship. This is the niche Coldspring fills.

Coldspring is a framework that is essentially an object factory. If you're using Coldspring, then whenever your app needs an object it asks Coldspring to instantiate it rather than the code instantiating it itself. In our previous example, rather than have our User object creating an instance of EmailService, Coldspring has already been informed via an XML file that whenever we ask for a User object it should ALSo include an instance of the EmailService object within it. Coldspring has just allowed us to keep our components decoupled, and this is a very good thing. Now, if my EmailService changes the way it is instantiated, I don't need to go into every other component that utilizes it and alter the instantiation code. Since Coldspring will be the one creating the EmailServices object, it will deal with those changes alone. By passing the control of object creation to our Coldspring factory we have implemented the buzzword mentioned in this session's title: Inversion of Control.

Dependency Injection is another buzz phrase associated with this topic, and essentially refers to the scenario where one object is depending on another (our User object depends on our EmailServices object), and the fact that Coldspring is 'injecting' an instance of the EmailServices object into our User object...Dependency Injection. There are two types of dependency injection, each one differing only in the way that the User object internally refers to the EmailServices object. The first type, called "Constructor-Argument injection", means that the EmailServices object will be passed in via the constructor of the User CFC, in the init method. The second type of injection is called "Setter Injection". With this one, rather than passing in the EmailServices object during instantiation, we're simply going to "set" it as a variable within one of the User object's methods. Here's why two methods even bother co-existing: circular dependency.

Circular dependency is another way of saying that object 1 uses an instance of object 2, and object 2 uses an instance of object 1. If you tried to use Constructor-Argument injection, CF would not allow you to have this circular dependency. By using Setter Injection, however, you can.

Lastly, Dave Ross elaborated on another facet of Coldspring called Aspect Oriented Programming, or AOP. In a nutshell, AOP is what allows you to take one method from a given component, let's say the LogIt method from the LOG.CFC, and cause that method to be executed at various times and places throughout your application. As an example, let's say that you wish to log every action executed against a user record, as well as when logging in or logging out of the application. Old-School style, you'd have to go to each of those methods and add a line to perform the logging. Ah, but with the beauty of Coldspring and AOP, you simply set up logging within the XML configuration file that already defines the relationship between CFCs, adding a few more definitions telling Coldspring to execute the logging before, during, or after the execution of other CFC's methods. Niiiice.

Setting up Coldspring is not or the faint of heart or those who are convenience enthusiasts, but if you will take the time to learn and implement it, you'll find yourself a better programmer for it.
Posted by dougboude at 1:29 PM | PRINT THIS POST! | Link | 11 comments



29 June 2006
CFUNITED - Top 10 Security Threats
Adam Lehman works for the State Department, and knows very well the intricacies of hardening a ColdFusion application. In this enlightening and informative session. he walked us all through the top 10 most common security holes found in applications in general, and then expounded upon ways to address these holes for CF applications. Let's count them down together.

Number 10. Insecure Configuration Management. An app can be anally secure, but if you don't remember to actually secure the interface used to manage that security, it's all for nought. Some things to remember for this one are:
  • Do not deploy CF Admin or sample applications to your production environment.
  • Do not deploy RDS to a production environment. RDS is strictly for development, and should have no place in production whatsoever.

Number 9. Denial of Service Attacks. Bots and scripts designed to do nothing more than pound your application with a barrage of legitimate http requests, doing so at such a rate as to consume all available resources on the server. For this one, there really isn't a lot that can be done from an application architecture point of view. It can help if you limit your need to access databases and how much data is stored in session. Ultimately, however, your best bet lies in ensuring that all server patches and service paks are kept up to date, as well as networking hardware designed to sense and deal with DNS(denial of service) attacks.

Number 8. Insecure Storage. The need to access application-centric, sensitive data exists. Information such as datasource names, usernames, passwords, social security or credit card numbers are all types of information that need to be protected. The main tip provided to help address this area of compromise was to either encrypt or hash the information before storing it, if possible. If not, then tuck it away into a most obscure location, preferably not in the path of the webroot.

Number 7. Improper Error Handling
. Error handling is in place to help the developer by showing him or her as much information as possible about the unplanned situation that just took place. When an application doesn't intercept and intelligently redirect errors, information that provides clues as to the database structure, application structure, and server can be revealed to would-be hackers. The answer is to implement an application-wide error handling mechanism that diverts detailed info to email or a log while showing the end user something more generic. This error handling code should preferably in a central location such as application.cfm/cfc. In addition, you  can and perhaps should disable robust error handling and debugging in the CF Administrator.

Number 6. Injection Flaws. Here's one we don't often (if ever) hear about typically. This requires a bit more sophistication on the part of the hacker. What happens is that the hacker hijacks a variable, or finds some other way, to inject malicious script code into your application. Most times this code's target isn't your application at all, but some other underlying system such as the database or the server itself. Some things that can be done to make it more challenging for the hacker:
  • Setup sandboxes in order to limit access to such CF system tags as CF_Execute and CF_Registry.
  • Limit the database access of the user that drives your CF data sources to only what is needed.

Number 5. Buffer Overflow.
Not typically a concern of web apps. For this one, like 9, make sure to keep patches up to date.

Number 4. Cross Site Scripting Flaws (aka, XSS). unlike injection flaws (number 6), XSS injects code that targets other users of the system. This is done in two manners: stored, and reflected. Stored XSS will do things such as write javascript functions to the template, where it will execute whenever that template is requested, performing some action on the client side. Reflected XSS utilizes such things as email to reflect the attack to users on other systems. Here are some things you may want to consider:
  • CF Admin has a "magic checkbox" to enable protection for all scopes. This will perform system regex checks against variable values flowing through CF to ensure no malicious code is present.
  • Within your application.cfc, the line "this.ScriptProtected" enables protection on an application level as well.

Number 3. Broken Authentication and Session Management. Well, not really broken, just weak. Here are some tips for strengthening these items:
Enforce more complex password rules, such as requiring special characters, etc.
Limit failed login attempts. When a user exceeds the count, lock them out for a period of time.
  • Store passwords as a hash rather than human text.
  • Perform the actual authentication process via https/ssl
  • Transmit session IDs via https/ssl
  • Do not put session IDs into the url
  • Use J2EE sessions

Number 2. Broken Access Control. Basically, the code you use to "lock down" certain areas of your application that require a person be authenticated for access. The recommendation here is that, rather than scatter "login checking" throughout the app, move it to a central place that runs on every request, such as application.cfc.

And Number 1: Unvalidated Input.
DO validate submitted data! You can never have too much validation in place. You may use client side javascript to perform validation, but never rely on it as your primary validation. Consider the following:
  • Build in server side validation to ensure that submitted data is of the expected types
  • use cfqueryparam to ensure that values submitted to queries are of the correct types
  • put as much of your functionality into CFCs as possible, as the inherent use of CFARGUMENT will be yet another level of validation.
  • Learn about and USE the CF function IsValid(). Do it. Do it.
Posted by dougboude at 6:45 PM | PRINT THIS POST! | Link | 1 comment
CFUNITED - MVC Unraveled
I spent the first hour of my morning listening (and gladly so) to Joe Reinhart preaching the need for us all to focus on just comprehending exactly what MVC is. Personally I felt like he started the presentation a few feet over most of the audience's head, using terms that were quite comfortable for him but new to many of us. Not his fault, and to his credit he did take the time to define many of the terms for us. Despite the elevated theme, in our short one hour together he accomplished his task in a two-fold manner: by increasing the audience's vocabulary, and by creating a sample app that used the MVC pattern.

That's right, MVC (Model View Controller) IS an application design pattern used across the board with any object oriented language. It also happens to popularly be known as the king of patterns, itself being an efficient symbiotic relationship between three other patterns of lesser scope and with more focused purpose. The Strategy pattern, Observer pattern, and the Composition pattern are what allow MVC to do what it does so well: keep our application segregated (loosely coupled) while allowing each portion of the app to remain highly specialized and autonomous (encapsulated).

The M in MVC is the Model. This is the portion of the application where nearly (if not all) of the business logic and database access will live. Business rules, queries, special validation...basically, if it has nothing to do with the user interface, then more than likely it will live in the Model. Physically the model will be a collection of CFCs that contain the functionality mentioned previously.

The View is that portion of your app responsible for displaying and gathering data. It knows nothing about the Model, the database, the backend system...it only knows that it will display the data given to it, and it will deliver the data it collects. Physically the View will consist of CFM templates containing primarily just layout information, such as forms, tables, and CSS.

lastly we have the Controller. It's job within the MVC design pattern is nothing more than passing data back and forth between the Model and the View; that's it.

The last 10 minutes (that's right, 10 minutes) of the presentation were spent building an entire basic blog application from scratch. Using the Model-Glue Unity framework and some Eclipse Ant scripts, he quickly was able to add in all of the CRUD (Create, Read, Update, Delete) functionality for blog entries and comments. How was this possible? By leveraging the many hours of hard work that have gone into producing and uniting three frameworks that have been all the buzz lately: Coldspring, Reactor, and Model-Glue. By strategically editing XML configuration files and using such shortcuts as "scaffolding", it is possible to auto-generate what would otherwise take a person days to code by hand.

Witnessing the creation of an entire application in just a few minutes is both exciting and disconcerting. On the one hand, Model-Glue Unity provides the developer with shortcuts that are nothing short of amazing, allowing productivity levels that I believe are unachievable otherwise. On the other hand, I could very well empathisize with the framework opposition camp, seeing how it is they could say that the usage of advanced frameworks such as Model-Glue will lead to the de-evolution of the CF community, removing many of the "needs" that often motivate developers to learn and grow. My own opinion, however, is that although frameworks such as this will allow us developers to become more productive, the convenience of it all will never quench the insatiable curiosity that has driven us up to this point, and we will always be "peeking under the hood" regardless of how much automation we adopt.
Posted by dougboude at 5:58 PM | PRINT THIS POST! | Link | 11 comments
CFUNITED - The Frameworks Debate Continues
Most of you may be aware of the debate over frameworks that has been raging off and on since at least CFObjective back in March of this year. In the one corner, representing all that is opposed to the preaching of frameworks to the masses is Simon Horwith. In the other corner, representing framework evangelists and followers from all over the globe is Hal Helms.

I first became aware of this schism at CFObjective when I attended a seminar by Simon Horwith entitled 'Object Think'. It would more appropriately have been entitled 'Friends don't let Friends use Frameworks', as he openly bashed everything else that conference was about and made himself the public prosecutor of the majority of the CF expert community's opinion on frameworks. Last night was no different, as I sat in on a session here at CFUNITED entitled 'Celebrity Death Match'.

It was an open and formal debate between Simon Horwith and Hal Helms, who himself participated remotely via Breeze. The conference room was filled to the hilt as newbie and seasoned alike gathered to be judge and jury for the topic at hand. Let me summarize for you the two opposing arguments, and then tell you what the verdict was.

The Framework Opposition says that frameworks are a crutch that essentially stifle and hinder a developer's professional and technical growth. This camp says that if a developer begins his or her career using an open-source comunity developed framework, they will remain handicapped and incapable of ever being able to truly build an application from the ground up on their own, resulting in a pool of 'talentless talent'.

The Framework Supporters maintain that using a framework, though it is indeed a greater initial investment of time and resources, is a ONE time cost that is greatly offset by the long term benefits afforded at every level. The use of frameworks creates a community-accepted standard that takes an already robust common vocabulary to an exponential level, not only enhancing our ability to transfer and share knowledge on a large scale, but also to easily exchange entire applications and code without the need for significant investments of time to utilize. They also counter that in NO way does the usage of frameworks stifle a developer's technical growth, citing the fact that none of their own growth was stunted when they started using Model-Glue and the like.

Near the end of this mock trial, Simon made a point that set me free of the conflict of the debate. He related an account of a project he had worked on in England some time in the past in which he had 100 developers under him. He shared how it was that this large team had tried using Mach II, tried using Fusebox, and in both instances found those frameworks wanting. Then he showed them his own 'methodology', which they readily adopted and used to successfully complete the project. Simon's point was that he and his team had accomplished a large task, and didn't need to use a framework in the process. But between Simon's words lay the whole truth of this matter, the truth that finally freed me from the points and counterpoints that were tugging my intellect in both directions. This truth, folks, is this: Any application that actually works uses a framework. Simon likes to call his framework his 'methodology', resisting the urge to give it any kind of formal name or documentation, and thus disguising it obscurity and vagueness. Nevertheless, it is indeed a framework. So folks, this whole debate is bogus, the opposition's stance is vapor, and in reality is a one sided debate with the answer to the question of the validity of frameworks already woven into the very fabric of both sides of the argument. The answer, my fellow CF coders, to the question of whether or not using frameworks is a good thing, is an unequivocable "YES". You need frameworks, and whether you roll your own or adopt a community standard, there is no way to avoid them...logic will not permit it.

After being set free by this epiphany, I then had to wonder at what it is that truly motivated Simon Horwith to take such a public stance. What moved him to place himself in the limelight and accept the label of 'framework-hater'? Is he plain and simply a rebel, one who will swim against the current on principle alone despite the direction it takes him? Or, more than likely, is it that he is simply a self-appointed sentinal of the free thinking world, fearing the loss of innovation and open-mindedness and the onset of apathy and weakness in the CF community's skill set? Finding nobody else who could see what he saw, did he then, in our defense, take up the cause to protect what it is he cherishes and believed to be utterly at stake, giving his all to "keep balance in the Force"? We are the jury here....

Back in the conference room the smell of popcorn and cotton candy filled the air as the debate was brought to an end. The judges called for final comments and then a show of hands from the "jury" as to who had won this debate. Almost unanimously, the jury sided with Hal.

Bottom line folks: ignore this debate and give the hard work of your more advanced and experienced peers the attention it is most worthy of. Must you choose a religion (framework)? No. Choose them all, choose one, choose none and roll your own; it doesn't matter. It's all good, it's all good. what IS important is that you keep striving to learn, always push yourself to new levels of understanding, and then you, like ALL those in both corners who are so zealous for their CF causes here, are right.
Posted by dougboude at 12:23 PM | PRINT THIS POST! | Link | 8 comments
28 June 2006
CFUNITED - Recursive Functions presentation
Andrew Schwabe gave an outstanding presentation of a subject that can be somewhat difficult to wrap one's mind around: recursive functions.

Having already traversed the learning curve involved with this subject, I went hoping to learn something new and was not at all disappointed. Andrew approached the subject in a very simple and understandable manner, taking the observer from zero to 60 in one smooth transition. I was quite impressed with Andrew's almost exclusive use of Custom Tags, which nicely complemented my own preference of using CFSCRIPT.

Rather than regurgitate all the details of recursiveness in this post, it's probably simpler to  refer the reader to both Andrew's presentation code and a recent  blog post of my own regarding the subject matter.
Posted by dougboude at 5:35 PM | PRINT THIS POST! | Link | 13 comments
24 June 2006
Charlotte
A Mother's Tale

The desert sun was just dipping behind the mountain when she began to
stir in the darkness of the rocky crevice she called home. While she
waited for the cool of night to finish falling upon her, she checked
the bundle of eggs packaged neatly in the back corner of her web-lined
cave. She pulled it close to herself, wrapping her legs around it and
turning it slightly within her grip, almost as if she were coddling it
like a baby.  A full week ago it was that she had spun the silken sac
and filled it with eggs, and any day now the little ones would be
emerging to take their first glimpse of the world. This was not the
first brood she had tended to; no, she had laid thousands of eggs in
her brief lifetime and sent many youngsters out into the harsh desert
to fend for themselves. But though this was but one of many egg sacs,
it was just as precious to her as any other, and she would protect it
with her life if need be.

The deepening shadows and cooling desert air roused her to the fact
that the web she had spun last evening was in need of repair if she
was to catch any supper. The violent grappling with a large Palmetto
bug the night before had left it quite disheveled and torn.

Cautiously she approached the door of her hideaway, her eight eyes
wide open as they always were, watching for any movement or change in
the dim light that would signal the presence of an enemy. Nothing
moved except for the wind, gently caressing the tiny hairs on her
glistening, black body and inviting her out into the night. With
perfect grace and dexterity she extended a long foreleg out into the
open, gripping the invisible web and pulling her round body forward.

In unison and amazing coordination her eight legs worked as she busily
inspected her web. In a few moments she knew what she had to do, and
began to run long strands of silken rope back and forth from the rocks
to the ground, over and under, until she was satisfied with the
unordered matrix that would ensnare her next meal.

In the moonlight the web glistened, as she made her way to the center
and hung herself upside down. She waited. She would wait all night
long without moving, if she had to, in order to feed. Hours passed.
The bright red hourglass pattern on her abdomen was beautiful in the
light of the traveling moon. She flexed her fangs in anticipation,
gently cleaning her legs one at a time as she awaited a passing
insect.

Another hour passed before she felt a small tug coming from one side
of her web. The tug grew in its intensity and frequency as she hastily
made her way down to where a male cricket had entangled his spiny legs
in her web. As she approached, she turned around and backed herself up
to the cricket, her long back legs working speedily and with
precision. Using first the right leg, then the left, she drew fresh
silk from her spinnerets and pulled it over the cricket like sticky
ropes of steel. In a moment she sensed that all hope of his escape was
gone, and turned to face him. Gripping him with her front legs, she
lowered herself until her fangs found the cricket's soft side, and
then she bit him. Letting the poison work, she turned again and drew
more silk over him, further ensuring that he would not escape. Another
bite, some more silk, and she climbed back up into her web, pulling
the paralyzed cricket behind her like a sack of potatoes. She secured
her supper so that it would not fall, and settled down for a much
needed meal. It was the crickets and Palmetto bugs and moths that
provided her with the nutrients she needed to produce sac after sac of
eggs. So many of her youngsters would not survive their first few days
in the world, and so by design her job in the world was to catch and
eat insects, and to bring young spiderlings into the world.

The sun began to light the landscape from behind the mountains on the
other side of the valley. Her meal complete, she dropped the cricket's
empty skeleton to the ground, and crawled back into the safety and
security of her silk and stone abode. She made her way again to the
corner where her egg sac was safely attached, listening to the faint
stir of spiderlings inside. Resting one motherly leg on the silky egg
case, and with her stomach full, she settled herself down to rest
until the darkness once more signaled her to the hunt.

Posted by dougboude at 2:17 AM | PRINT THIS POST! | Link | 1 comment
Equivalent of SQL "TOP X" in Oracle
A friend asked me a good question, so thought I'd share it and the answer for whomever it may help in the future.

Q:  What is the equivalent of the SQL statement "SELECT TOP 10 * FROM myTable" in Oracle?

A:  SELECT * FROM myTable WHERE ROWNUM < 11
Posted by dougboude at 2:06 AM | PRINT THIS POST! | Link | 7 comments
21 June 2006
Java: The Journey Begins
The 10,000 Foot View
This is the official kickoff of my Java journey, so I thought I'd chronicle the trip for both posterity's sake and those who will be following this trail behind me.

I will be doing Java development primarily with regard to the web (JSP), so right now what I'm in search of is a 10,000 foot view of what the essential pieces and parts are and how they're related. For some strange reason it seems that once a person has this knowledge under their belt and have been at it for a while, they completely forget what Java looks like from a newbie's perspective, and are incapable of creating any kind of analogy or verbalizing the basics...forever geekified. Anywho, i'll keep looking and whether I find the answer outright or am forced to filter feed until I come to my own epiphany of it, I'll share the answer to "The 10,000 Foot View" as soon as I get it.

Doug out.
Posted by dougboude at 5:26 PM | PRINT THIS POST! | Link | 6 comments
17 June 2006
Recursive Functions in ColdFusion
Navigation Methodology
Dr Doug Says:

If you’re churnin’ out a web app cause your sales guy said you would,

And the PM he’s a pushin’ cause he knows you’re just that good;

But the requirements call for nav that stretches to infinity,

Then it may be time to think about recursive hierarchy….


Oh, recursion is a big word to describe a special function

That can chase its tail and catch it if it’s written with some gumption!

You could rightly call it Schizo, as to why, here’s the scoop:

It will call itself AND ANSWER in a never ending loop!


The secret to its mental state that makes it strange, yet stable

Is the special way it uses scope to give its vars a label.

If a variable is private then it’s labeled V-A-R,

While the public ones are public with no label needed thar!


And so, oh best Beloved, this function’s prelude now is ended;

But I must insist that you press on to find it and befriend it!

For no programmer’s app is done, regardless of the version,

Unless it boasts, at least a mite, the power of Recursion!

On THAT note…
Let’s say that you are designing an app and you want to give the user the ability to manage his navigational tree to an infinite level; the ability to add items under items under items under items to his or her heart’s content. From a database point of view, the simplest way to store relational data like this and meet the requirement of infinite relationship levels is a single table with a structure something like the following:
navigation structure

A few quick comments about the fields. ParentID contains the id of the record that the item is a child of. Records with a parentID of zero are top level; they have no parents.

Okay, so storing the hierarchical data is no problem and the way we chose to do it is both elegant and makes perfect sense! The CHALLENGE, however, (there are no problems, only challenges) is how to retrieve and properly display this data while maintaining its hierarchical relationship. For our example, the requirement will be to retrieve the navigational data and output it using html Unordered Lists, maintaining the data’s hierarchy. Here is where the power of the recursive function is a perfect fit.

Recursion can be a difficult thing to visualize in action, so let’s first go through how one could retrieve and display this data if recursion did not exist.

First of all, we must know up front how many levels deep our data goes so that we know how many nestings to use in our code. In this case, none of the data goes more than 4 levels deep. Assuming our data has been retrieved into a query named qryNavigation, the following ColdFusion code will display our information as a properly nested unordered list:

<cfset menustring = "<ul>"><!--- Step 1 - Initial opening UL tag --->
<cfloop query="qrynavigation">
    <cfif parentid eq 0><!--- Step 2 - Loop through all top level nav items --->
        <cfset menustring = menustring & "<li>" & navdescription>
        <!--- Step 3 - see if this item has children --->
        <cfquery name="checkforKids" dbtype="query">
            select * from qrynavigation where parentid = #qrynavigation.id#
        </cfquery>
        <cfif checkforkids.recordcount gt 0><!--- Step 4 - loop through kids --->
            <cfset menustring = menustring & "<ul>">
            <cfloop query="checkforkids">
                <cfset menustring = menustring & "<li>" & navdescription>
                <!--- Step 5 - see if this item has children --->
                <cfquery name="checkforkids2" dbtype="query">
                    select * from qrynavigation where parentid = #checkforkids.id#
                </cfquery>
                <cfif checkforkids2.recordcount gt 0><!--- Step 6 - loop through kids --->
                    <cfset menustring = menustring & "<ul>">
                    <cfloop query="checkforkids2">
                        <cfset menustring = menustring & "<li>" & checkforkids2.navdescription>
                        <!--- Step 7 - see if this item has children --->
                        <cfquery name="checkforkids3" dbtype="query">
                            select * from qrynavigation where parentid = #checkforkids2.id#
                        </cfquery>
                        <cfif checkforkids3.recordcount gt 0><!--- Step 8 - loop through kids --->
                            <cfset menustring = menustring & "<ul>">
                            <cfloop query="checkforkids3">
                                <cfset menustring = menustring & "<li>" & checkforkids3.navdescription & "</li>">
                            </cfloop>
                            <cfset menustring = menustring & "</ul></li>">
                        <cfelse><!--- this level 2 item has no kiddos --->
                            <cfset menustring = menustring & "</li>">
                        </cfif>
                    </cfloop>
                    <cfset menustring = menustring & "</ul></li>">
                <cfelse><!--- this level 1 item has no kiddos --->
                    <cfset menustring = menustring  & "</li>">
                </cfif>
            </cfloop>
            <cfset menustring = menustring & "</ul></li>">
        <cfelse><!--- this level 0 item has no kiddos --->
            <cfset menustring = menustring & "</li>">
        </cfif>
    </cfif>
</cfloop>
<cfset menustring = menustring & "</ul>">
<cfoutput>#menustring#</cfoutput>

Walking through this code, the first thing we have is a query containing all of the nav items. Step 1 is to create the opening UL tag for our unordered list. Next, we retrieve all of our top level (parentID = 0) nav items and loop through them. For each one, we check to see via a Query of Queries if that particular nav item has children. If so, we retrieve that items children and loop through those. For each of the children, we check to see if THEY have children. If so, we loop through them, repeating the process one more time. Opening and closing UL and LI tags are added appropriately to form a string containing a properly formatted html unordered list which is then output to the browser.

That is a lot of code, and as you can tell, it limits the data to 4 levels deep while our requirement called for infinite levels. Not the solution we’re looking for. We need one with a little more imagination, grace, elegance, and usability.

I’m just going to lay it on you; here is the equivalent recursive function that accomplishes the same thing, but without limitations and with less code:

<!--- Initializing our 'variables' scoped variables...public access --->
<cfset variables.menustring = "">
<cfset variables.navigation = "">
<cffunction name="GenerateNav" access="public" returntype="string">
    <CFARGUMENT name="parentID" type="numeric" required="yes" default=0 >
    <CFARGUMENT name="level" type="numeric" required="yes" default=0 >
    <!--- scoping the variables that need to have their values kept private
    to a particular instance of the function call... --->
    <CFSET var checkForKids = ""><!--- used to hold temporary check for children --->
    <CFSET var objNav = ""><!--- used to hold temporary subqueries --->
   
    <!--- On our initial call to this function, we will purge the menustring and grab our navigation source query. --->
        <CFIF arguments.level eq 0>
            <CFSET variables.navigation = qryNavigation>
            <CFSET variables.menustring = "">
        </CFIF>
       
        <!--- Retrieve all nav records from variables.navigation who are the children of our current parent --->
        <CFQUERY name="objNav" dbtype="query">
            select * from variables.navigation where parentid = <CFQUERYPARAM value="#arguments.parentid#" cfsqltype="CF_SQL_INTEGER">
            order by navorder
        </CFQUERY>
        <!--- write our current parent to the menustring... --->
        <CFSET variables.menustring = variables.menustring & "<UL>">
        <!--- loop through this parent's children... --->
        <CFLOOP query="objNav">
            <!--- check for children. If there are any, call this function recursively --->
                <CFQUERY name="checkForKids" dbtype="query">
                    select * from variables.navigation where parentid = <CFQUERYPARAM value="#objNav.id#" cfsqltype="CF_SQL_INTEGER">
                </CFQUERY>
                <CFIF checkForKids.recordcount gt 0><!--- this child has kids too! add it to the menustring, then make the recursive call... --->
                    <CFSET variables.menustring = variables.menustring & "<LI>" & objNav.NavDescription >
                        <CFSET GenerateNav(parentID = objNav.ID, level = arguments.level + 1) >
                <CFELSE><!--- this child is childless...just add it to the menustring... --->
                    <CFSET variables.menustring = variables.menustring & "<LI>" & objNav.NavDescription >
                </CFIF>
                <!--- close the list item --->
                <CFSET variables.menustring = variables.menustring & "</LI>">
        </CFLOOP>
        <!--- close the UL tag --->
        <CFSET variables.menustring = variables.menustring & "</UL>">
        <!--- return final variable to the caller... --->
        <CFIF arguments.level eq 0>
            <CFRETURN variables.menustring>
        </CFIF>
</cffunction>

<!--- THIS is the kickoff point of the whole thing! --->
<cfset recursivenav = GenerateNav(ParentID=0, level=0)>
<cfoutput>#recursivenav#</cfoutput>

Let’s walk through this recursive process. Step 1 really comes last, and that is our initial call to this function that kicks the whole process off like the first domino falling. From here on out, we will cease to use the actual value of the parent ID and simply refer to it as ‘X’; this will make it easier to walk through the code. We call the function passing a value of zero to the level argument (which lets us keep track of where we are in our recursive calls) and a value of X to the parentID argument (used when retrieving navigation subsets via query of queries). Our first call to the function sets up the two private (VAR scoped) variables for use by this instance of the function. Since we are at level zero, it then initializes the values of two public variables: navigation and menustring. Menustring is our cumulative variable, meaning that with every call to GenerateNav, we will be appending more and more items to it.

Our next step is to execute the query objNav which retrieves all items from the complete set of nav items that have a parentID of X. Once retrieved, we have our X level items and begin looping through them. For each item returned, we check to see if there are any children. If there are (drumroll please…), then we make a recursive call to GenerateNav, passing it a parentID equivalent to the current item’s ID, and a level equal to the current level plus one.

The recursive call to GenerateNav sets up its two private instances of checkForKids and objNav, skips the initialization of the public variables, then selects all nav items for the parentID that was just passed in. Those children are retrieved, we step through them, and for each of them that are found to have children themselves, we again call GenerateNav passing in the appropriate values for that particular instance of the function.

When we’ve gotten through every item in our first initial objNav query (which would have been all items with a parentID of zero), we add the closing UL tag to our public variable Menustring and then return it. Notice we enclose the code to add the closing UL tag and to return Menustring within a CFIF that looks at the level. This prevents Menustring from getting returned prematurely by any of our recursive calls.

When a recursive function calls another instance of itself, you can rightly picture that it just managed to perform mitosis and now has an identical brother performing the exact same work, only with its own private variables. Whatever variables were declared public are shared between the first and its brother, and any subsequent brothers that are spawned. As each clone completes its task, it disappears back into the ether until finally there is only the original instance left, and when it has completed its task, it returns the final value and itself disappears, completing the entire process. This is recursiveness in a nutshell. Beautiful, isn’t it?

You may also be wondering how useful it is to output your navigation in an unordered list. Bear in mind that I kept it as simple as possible and did not include fields to hold URLs and other linking information that would normally be present in a navigation table. Those can be added later and included within the information being appended to your Menustring variable, along with CSS class names based on level. Upon output, it is a relatively simple thing to create a Stylesheet to format your unordered list as a flyout menu (no javascript required), such as is shown here:

recursivemenu

I hope you found this information both useful and inspiring, and will be looking for places to leverage it within your own application development. As the late great Buckminster Fuller once said, “…if the solution is not beautiful, then it is wrong.”, so let's keep it beautiful folks.

Posted by dougboude at 1:46 PM | PRINT THIS POST! | Link | 29 comments
16 June 2006
Calculating Business Hours
ColdFusion function
I've had several requests for a copy of a function i wrote that calculates business time between two datetimes, so figured I'd go ahead and make it available via my blog.

It's kind of a long function, but I built it to be thorough and do a lot of validation and such. Also, there are  several supporting function included as well that it uses (not all of which are mine...credit given where applicable).

I couldn't find any documentation ( I thought I had written some, but it was probably just an email I sent to my coworkers), but it's fairly straightforward. Here's a sample call:

<cfset thesebizmins=bizMins(begin_dt,end_dt,8,17,12,"n")>

the function is heavily commented, including a header that explains the parameters and such. Let me know if you have any questions on it and I'll try to answer them.

You may need to edit the function getCompanyHolidays(). It has all the normal ones already, but there may be some you want to add or omit.

If you get any errors because a function is missing, let me know; I may have missed one of the supporting functions.

Oh, and feel absolutely free to share this with anybody you like. I am a true believer in the spirit of the internet, that nobody else should have to go through the same pains I have if me sharing what I learned
can prevent it.

Pay it forward.... :0)

Doug  :0)

P.S.
Oops! I had forgotten to include the supporting function 'validHour' (thanks Cathy Martin!), so added that just now (2/27/07).

************** Download the Code Here ********************
Posted by dougboude at 12:00 AM | PRINT THIS POST! | Link | 14 comments
Managing ColdFusion Mappings through the BACK DOOR
Often when hosting a site somewhere, it can be a slow process to get a mapping created or modified. Then there are also those times when all you really need to be able to do is SEE them so you can verify paths and what not.

Using snippets harvested from google, I wrote myself a simple little MappingUtil.cfm page that I use to perform the tasks previously mentioned, and now i share it here with those who may be interested.

WARNING:
A few things you should think about before using this tool:
  1. This code uses undocumented methods and is not supported by Adobe. It is not guaranteed to work against every version of ColdFusion server.
  2. Most of the time, yours isn't the only site living on a particular host server. This tool will allow you to see and manage ALL mappings, whether yours or not, therefore you must be very careful not to delete someone else's mapping.
  3. Performing your own back door mapping management without the admin's knowledge could get you kicked off of your current host.
  4. Never drink and manage mappings at the same time.

Okay, cautions out of the way, below is the code. It should be saved in a template name that matches the form action. Currently that is "mappingutil.cfm". If you wish to save it as a different name, be sure to edit the form action as well.


********************************  The Code  ***********************************************************
<cfparam name="url.action" default="false">
<cfparam name="form.mapping" default="">
<cfset factory=createObject("java","coldfusion.server.ServiceFactory")>
<cfset mappings = factory.runtimeService.getMappings()>
<cfset actionmessage = "">
<cfif url.action>
    <cfif form.mapping IS NOT "">
        <cfloop index="m" list="#form.mapping#">
            <cfset tmp= structdelete(mappings,m)>
        </cfloop>
        <cfset actionmessage = "<h3>Items Deleted.</h3>">
    </cfif>
    <cfif form.mapname IS NOT "" and form.mappath IS NOT "">
        <cfset mappings[form.mapname] = form.mappath>
        <cfset actionmessage = actionmessage & "<h3>Mapping added.</h3>">
    </cfif>
</cfif>

<cfoutput>
#actionmessage#
<h2>Mapping Admin</h2>
<form action="mappingutil.cfm?action=true" method="post">
<table cellpadding="5" cellspacing="5" bgcolor="##FFFFFF">
<tr><th>Delete</th><th colspan="2" align="center">Mapping</th></tr>
<cfloop collection="#mappings#" item="thismapping">
<tr>
    <td>
        <input type="checkbox" name="mapping" value="#thismapping#">
    </td>
    <td>
         <strong>#thismapping#</strong>
     </td>
     <td>
         (#mappings[thismapping]#)
     </td>
</tr>
</cfloop>
<tr><td colspan="3">Enter new mapping: name<input type="text" value="" name="mapname" size="15">&nbsp;&nbsp;path<input type="text" name="mappath" value="#expandpath(".")#" size="45"></td></tr>
<tr><td colspan="3" align="center"><input type="submit" value="Save Changes"></td></tr>
</table>
</form>
</cfoutput>
Posted by dougboude at 12:00 AM | PRINT THIS POST! | Link | 19 comments
Personal OO Lexicon
Learning OO can be somewhat intimidating at first, especially coming from a procedural CF background.  One of the first things needed in order to be able to take advantage of the different posts, presentations, and articles so graciously shared by your more advanced ColdFusion brethren is to have the OO vocabulary ready at hand. In order to assist with this, I am sharing with you my own personal lexicon of the terms and phrases I find myself most often exposed to in pursuit of mastering OO, especially with regards to the Model-Glue framework.

I'll be updating it periodically as my own understanding grows, so check back every now and then for a fresh copy.


Doug Boude's Lexicon
Posted by dougboude at 12:00 AM | PRINT THIS POST! | Link | 3 comments
Moments of inspiration
Doug Boude's Prose
Just thought I'd share a few of my poetic "works" to keep the mood of my blog dynamic.

My Prose
Posted by dougboude at 12:00 AM | PRINT THIS POST! | Link | 8 comments
Refreshing Cached ColdFusion Webservices Through the Back Door
When developing CF webservices on a server that you don't have admin access to, it can be very frustrating (until you figure out the root cause) when you are making changes to your service and yet when you call it, the change doesn't seem to show up. Well, this is because ColdFusion caches its definition of the webservice, so subsequent changes can only be seen if that cached version is purged first.

This can be done via the CF administrator, but since many of us don't have access to the administrator, I share with you another solution...a backdoor to refresh these cached services.

Deleting a cached service will totally remove it from the cache (it'll be re-cached next time somebody calls it), while refreshing it will delete and then call the webservice again to grab a fresh copy of it. If running this on a shared server, you will see EVERYBODY's cached web services. Deleting or refreshing all services will do no harm, so no need to be concerned about touching someone else's stuff.

The code below should be copied into a single cf template. It's self calling in a generic way (using cgi.script_name), so no need to modify it in any way.


********************** The Code ************************************************************
     <H2>Webservices in cache:</H2>
   
     <cfobject action="CREATE" type="JAVA" class="coldfusion.server.ServiceFactory" name="factory">
     <cfset xmlRpc = factory.getXMLRPCService()>
     <cfset webServices = xmlRpc.mappings>
   
     <cfparam name="url.del" default="false">
     <cfparam name="url.refresh" default="false">
     <cfoutput>
     <cfif url.del>
            <cfloop item="webService" collection="#webServices#">
                    <cfset xmlRpc.unregisterWebService(webService)>
            </cfloop>
            <cflocation url="#cgi.script_name#">
     </cfif>
     <cfif url.refresh>
            <cfloop item="webService" collection="#webServices#">
                    <cfset xmlRpc.refreshWebService(webService)>
            </cfloop>
            <cflocation url="#cgi.script_name#">
     </cfif>
   
     <cfloop item="webService" collection="#webServices#">
            - #webService#<BR>
        <cfflush>
     </cfloop>
    <BR>
     [<A HREF="#cgi.script_name#?del=1">KILL ALL</A>]
     <BR>
     [<A HREF="#cgi.script_name#?refresh=1">REFRESH ALL</A>]
     </cfoutput>
     <HR>
 
Posted by dougboude at 12:00 AM | PRINT THIS POST! | Link | 15 comments
ColdFusion Component Variable Scopes: This, Variables, and Var
Scope within a CFC is incredibly important, and even moreso when you start using Object Oriented Frameworks for your application. It is essential to understand it in order to save yourself a lot of mind numbing troubleshooting, especially when writing recursive functions.

The following information is also contained in my OO Lexicon, but I felt like it was sufficiently encapsulated (that's an OO term ) to go ahead and re-post it here.

THIS, VARIABLES, and VAR Scopes

These are three of the variable scopes that are found within the world of a ColdFusion object or component, and three scopes that can make you pull the rest of your hair out when you don’t know how to think about them. In a nutshell, you’re looking at three increasing levels of variable privacy, from most liberal to most private.

The “THIS” scope holds items that can be directly accessed from anywhere inside OR outside of the object itself. Consider the following example of an instantiation of the myTest.cfc that has a variable called THIS.GLOBALVAL within it’s INIT method:

The component code...

<cfcomponent>
       <cfset this.GLOBALVAL = "Whatchoo lookin at Willis?" >
       <cffunction name="init" output="false" returntype="myTest">
          <cfreturn THIS>
       </cffunction>
    ...
</cfcomponent>

The call from the outside template...

 

 

<cfscript>

            myTestObj = CreateObject(“component”,”myTest”).Init();

            myTestObj.GlobalVal = “I set you from outside of the object!”;

</cfscript>

 

In this example, because the variable GlobalVal was put into the THIS scope within our object, our application could directly access it as a property. Cool, if that’s what you intended to happen. Not cool if it wasn’t.

 

 

 

The VARIABLES scope within a component object is a scope that can be accessed by any method within the object at any time, in real time. In other words, if our component had set up a variable called Variables.LimitedVal, all methods will be sharing that one instance of the variable. If method one sets it to “5”, and later the app calls method two which reads that variable, it will see the value “5”. Any attempt, however, from outside the object itself to manipulate that value will result in an error. The following would FAIL:

The component code...

<cfcomponent>
       <cfset variables.GLOBALVAL = "Whatchoo lookin at Willis?" >
       <cffunction name="init" output="false" returntype="myTest">
          <cfreturn THIS>
       </cffunction>
    ...
</cfcomponent>

The call from the outside template...

 

 

<cfscript>

            myTestObj = CreateObject(“component”,”myTest”).Init();

            myTestObj.GLOBALVAL = “I set you from outside of the object!”;

</cfscript>

 

 

 

 

And finally, the VAR scope. This scope is one which can be seen only from inside of the actual method itself. For example, I can have three methods, each that use a variable with the same name that was initialized within the VAR scope, and no method will ever see the variable used by the other methods. It is a VITAL thing that you initialize your private variables in the VAR scope inside of your methods, because by default they are set up in the VARIABLES scope, and who knows WHAT havoc will occur if you have methods sharing variables that were intended to be private. Consider the following sample of initializing a variable in the VAR scope:

 

<cffunction access="public" name="sampleMethod" output="false" returntype="void">

                        <cfargument name="headlines" type="array" required="yes" >

                        <cfargument name="sourceID" type="numeric" required="yes">

                       

                        <cfset var iterations = 0>

                        <cfset var urlitems = "">

                        <cfset var newInsertItems = arraynew(1)>

</cffunction>

 

Only the ‘sampleMethod’ method will be able to see and manipulate those variables set using the ‘var’ scope. VAR is so private, that every other method within our component could initialize variables with the same name within their own var scope and no overlap would occur.

Posted by dougboude at 12:00 AM | PRINT THIS POST! | Link | 29 comments
03 June 2006
New Member of the Family!
We went yesterday to see the potential new member of the family. There were lots of others there, but she was the one that caught our eye. We spent about an hour getting to know her, talking to the administrators, and just taking it all in, trying to imagine what it would be like to have her as a member of our family. I mean, we already had one, so how much would our lives change if we added one more?  And besides that, she is black, so how much of an adjustment would that be for everybody? We thought about it over night, talked through different scenarios, and finally decided that it was just too right. So this morning we called the administrator to let him know that we wanted her to come home with us. We met with them at 10:30 this morning to go through all of the red tape, and now are just waiting on a phone call to tell us we can come pick her up. I'm so excited! (squealing like a little girl....) More later.

All went well, and Shiniqua is now officially part of the family. She is 12 years old and has had a very good life as far as a Jeep Cherokee is able to. Her previous owners apparently took very good care of her and didn't even put the average number of miles on her. It's been two days, and so far no buyer's remorse, so I think this was a good purchase.

Shiniqua, welcome home!
Posted by dougboude at 12:00 AM | PRINT THIS POST! | Link | 14 comments