Last month in CFDJ (Vol. 4, issue 1) we began building a Fusebox 3 application - a game played at a social club run by Vinny.
The game is simple: registered users log in, pick a number, and then place a bet...
Vinny: Make a donation Me: Huh? Vinny: You said, "Place a bet." There's no betting going on. People choose numbers and make donations. Me: But Vinny, people are picking numbers and then putting money down. Surely, that's a bet. Vinny: Let me reiterate: the donations people place are not related to the numbers they pick in order to bet... Me: Ha! You said it: "bet"! Vinny: ...to better enjoy the game. Me: I gotta tell you, Vinny. I think somebody's pulling a fast one on you. I know you would never countenance such a thing, but it appears quite clear to me that what we're building here is a betting apparatus, an illegal betting apparatus. Vinny: That kind of talk is...dangerous. I think you better stick to building the application. Me: I don't know, Vinny. Well, for now, let's continue. Between last month and this month I wrote all the fuses. Vinny: Don't these people need to know how to write these fuses? Me: Well, it's just normal ColdFusion code. The only thing slightly different is that all action returns to the main index.cfm page, or whatever your default page is. Here's some sample code to make this clear:
Using a form:
<form action="#self#?fuseaction= #XFA.home#" method="post">
<input type="submit" value="Go
home">
</form>
Using <cflocation>:
<cflocation url="#self#?fuseaction="#XFA.makeDonation#" addtoken= "yes">
Using an href link:
<a href="#self#?fuseaction="#XFA. buyProbableWinners#>
Look at numbers that are "due" to win!</a>
Vinny: Yeah, that's clear, clear as mud. What's with this "self" and "XFA." stuff? Me: Self is a variable that's set to the home circuit's default page. Vinny: So, why don't you just say that: "index.cfm"? Me: What happens if your code is deployed on a server that uses "default.cfm"? By using a variable, the code is more portable. Vinny: What about these XFA things? Me: XFAs stand for eXit FuseActions. They're also variables. Vinny: Why do we need those? Me: Well, two of the design goals of Fusebox 3.0 are to make code more reusable and more maintainable. Imagine that you wrote some code that performs a user login and validation. Vinny: Yeah, we're gonna need that. Me: Sure. But lots of applications need the same basic functionality. However, where you head to after validation differs for each application. In some applications, after the user is validated, we want them to go to a catalog. Other applications might send them to a personalized home page, or maybe to an admin page. Vinny: Okay. But what's that got to do with XFAs? Me: Well, look at this code that validates a user. I wrote it for another application several months ago. I'll take out the XFAs:
Vinny: If the "UserInfo"...what do you call it? Me: Recordset? Vinny: Yeah, recordset has any rows, then we'll go to the..., help me out here. Me: To the home circuit's default page. Vinny: Right. And we send a fuseaction called "catalog.personalized". By the way, what's with the dot stuff in the fuseaction name? Me: We'll get to that in a minute. I figure I can reuse this code and save you some money. Sound good? Vinny: Yeah, but... Me: But what? Vinny: But, we ain't got a catalog to send people to. Me: That's just where XFAs come in handy! Take a look at the same code but with XFAs:
Vinny: But I ain't going to "XFA.success". I'm going to the player's main page. Me: Right, and the project I wrote that code for was headed off to "catalog.personalized". But by using a variable, we can use the same code for both. Vinny: How? Me: By setting the value of "XFA.success" and "XFA.failure" before the fuse is called. That way, it can be specific to each application. Vinny: Oh...okay. That does kind of make sense. Where would we set this variable? Me: In a file called "FBX_Switch. cfm". Vinny: Oh, now you're losing me, and you never answered my question about the dots in the fuseaction name. Me: All right. Let's back up. Last month, I used a tool called Visual Mind to create a Fusebox "schematic." It looked like Figure 1. Vinny: Yeah, I remember. Me: Now, let's build a Fusebox application around it. I think you'll see how it fits together. The first thing is to create a directory structure that mirrors the schematic, like Figure 2. Me: There are Fusebox core files - files that should appear in each circuit. Vinny: What's a circuit again? Me: We call each directory in Fusebox that handles fuseactions a "circuit." Vinny: Okay. Me: You can get the core Fusebox files at www.fusebox.org. They are:
FBX_Fusebox30_CF50.cfm
FBX_Fusebox30_CF50_nix.cfm
FBX_Fusebox30_CF45.cfm
FBX_Fusebox30_CF45_nix.cfm
FBX_Fusebox30_CF40.cfm
Vinny: Wait, those all seem like pretty much the same file, no? Me: Yes, they are. This is the true core Fusebox file and it comes in different flavors, depending on the version of ColdFusion server you're running. Vinny: But you said that this "self" thing is where everything goes back to, so isn't that really the true core file? Me: No, all that does is call the core Fusebox file. In fact, "self" can be as simple as this:
<cfinclude template="FBX_Fusebox30_CF50.cfm">
Vinny: Okay, go on with the other core files. Me: There's a file called FBX_ Circuits.cfm. This lets you define aliases for directory names (or circuits). Vinny: Why would you want to do that? Me: Because you may have more than one circuit with the same name. Look at the directory structure in Figure 3.
Here you have two circuits with the same name, "Users." How will the core FBX_Fusebox file know which one you mean? Vinny: That FBX_Circuits file? Me: Right. You provide aliases for the directories. Here's the FBX_ Circuits.cfm file for the "sample-app" application:
The FBX_Circuits.cfm file is needed only in the home circuit, by the way.
On the left side of each definition is an entry into a structure called "fusebox.Circuits". That structure is automatically created by the core file.
Vinny: FBX_Fusebox_thingamajig. Me: Right. The alias to be used is really a key in this circuit. On the right side of the equals sign is the path to the appropriate circuit beginning with the home circuit.
Now when you make a call back to the default page - remember I showed you several examples? - you provide the circuit alias name, followed by a dot separator, and then the name of the fuseaction you want performed, like this:
Vinny: That answers my question about the dot stuff. But I thought you said we don't use the fuseaction name itself, that we use an XFA? Me: That's right. It would really look more like:
Vinny: Two questions: Where did you get that name "XFA.addUser"? There's no "addUser" in the schematic you did. Me: That's easy: I made it up. I make up XFAs to describe as best I can the condition under which an XFA would be called. They don't have to correspond with the actual fuseaction name. Remember, that's just a variable name. Vinny: Okay, but it looks like a circuit alias - dot - fuseaction thing, and you don't have a circuit called "XFA". Me: No, "XFA" is a structure that's set in the FBX_Fusebox file. I'm just using a key to that structure. Vinny: I got it. But where does the value of that key get set? Me: Good question. For that we have to go to the FBX_Switch.cfm file. First, you need to know a little about what the FBX_Fusebox file is doing. Vinny: Okay. Me: When the core file gets a request for a compound fuseaction, something like "Users.newUser" (and for now, just trust that XFA.addUser gets resolved to that), it uses the FBX_Circuits file.
The core file says in effect, "You said 'Users.newUser', but you really mean 'sampleApp/Admin/Users'." Vinny: This it gets from FBX_ Circuits? Me: Right! With that knowledge it calls the file FBX_Switch.cfm that's found in the target directory. Vinny: The target directory being "sampleApp/Admin/Users"? Me: Right again. It also strips off the circuit alias and the dot separator and presents what's left as the variable "fusebox.fuseaction". Vinny: When it gets to the FBX_Switch file in sample/App/Admin/Users, that file sees a variable called "fusebox.fuseaction"? Me: Yes. Let's look at that file. Here's a portion of it:
What's happening here? First, notice that our "<cfcase>" statement is looking for a simple fuseaction. The circuit alias and dot separator have been stripped away. Also, notice that we're setting the values of two keys in the XFA structure, "submitForm" and "cancelForm".
Vinny: Yeah, so that's where they get set. Me: Yes. You can look at XFAs as "candidate fuseactions." When the fuse returns to self, it does so with only one fuseaction, right? Vinny: Yeah. That's the <cflocation url="#self#?fuseaction=#XFA.something#">. Me: Right, and the value of the fuseaction depends on the exit path chosen. If the user clicks the submit button on the form, we'll use the value of "XFA.submitForm" as the fuseaction's value. Vinny: What would that look like? The code, I mean. Me: Like this:
Vinny: This time you created a hidden field called "fuseaction". Me: Yes, the core file will sort it out whether a fuseaction is sent as a URL or a form variable. I did this so that if the user clicks on a "Cancel" button, I can use a little JavaScript to reset the value of that form field. Make sense? Vinny: I think so... Me: If we wanted to reuse the fuse "dsp_NewUserForm.cfm" in another application, we'd never have to touch that code. We would just set the values of "XFA.submitForm" and "XFA.cancelForm" to whatever would be appropriate for that application. Vinny: That ain't so hard! Me: I tell you, Vinny, you should get out of this betting stuff and get an honest job, like programming. Vinny: Watch what you're saying. I specifically said there wasn't no betting going on. Me: I know, Vinny, but you have to admit... Vinny: I ain't admittin' nuthin'! You got any more to say about this Fusebox stuff? Me: Okay, Vinny...have it your way.
After we set the values of the XFAs, we include whatever fuses are needed to perform the task at hand. Here, we just call "dsp_NewUserForm.cfm". Vinny: Where would you ever need more than one? Me: Well, you might need to include a query file prior to calling another display file, that's one example. Vinny: Yeah, okay. Me: Now we have to deal with the question of where we set common variables. Vinny: Like what? Me: Like "self," for example. Or maybe the data source for a database used throughout the application. We've got another core file for that, FBX_Settings.cfm. Vinny: Is that just in the home circuit? Me: No, it goes in every circuit. This enables Fusebox to implement a simple inheritance mechanism, while allowing children to override their parents' settings. Vinny: It just has "self" and the data source? Me: No, it can have anything you want. For example, you could put the "<cfapplication>" tag in the home circuit's FBX_Settings.cfm file. If you had common XFAs across an application, you could put those in FBX_Settings. Vinny: When do I call them - the FBX_Settings files? Me: They're called automatically by the core Fusebox file. In fact, the core file uses the directory path for the target circuit... Vinny: Wait, what's that mean again? Me: The directory path is the part on the right side of the equal sign in FBX Circuits. This code in FBX_ Circuits
is used by the core file to create a list of circuits whose FBX_Settings.cfm files it will include.
Vinny: It will first include the FBX_Settings file in "sampleApp", then in "Admin", and then in "Users"? Me: Right, and it does it in that order. That lets the coder set variables higher "up" the tree if he or she wants them to be inherited by children circuits. Those variables can always be overridden by one of the children, if needed. Vinny: Huh, that makes sense. Me: There's just one other thing you would need to know. Fusebox 3 has the concept of nested layouts. Vinny: How does that work? Me: Well, it lets you "wrap" the content generated by your fuses in a layout file. Figure 4 shows an example of one I did for teaching purposes. See how many layouts you can spot.
I'll give you a couple of hints. Figure 5 provides the circuit structure for the application. I'll also tell you that the fuseaction being called was "grandson.sayHi". Vinny: Hmmm...well, I'm thinking that "Hi there!" is what the fuse in the grandson circuit did. Is that right? Me: So far, so good. Vinny: Then I'm thinking that each box is a layout applied to that content. That right? Me: Right again. Vinny: There would be four levels of layout applied: grandson, son, father, and home. But we don't have a "home" circuit. Me: Well, those are the alias names, and if you looked at that application's FBX_Circuit's file, you'd see that I aliased the grandparent circuit as "home". Vinny: Hey, I like that! Me: Me, too. Nested layouts are immensely powerful stuff. Vinny: You just gotta remember to call them in the right order. Me: No, the core Fusebox file takes care of that for you. It uses that same "fuseaction path", sample-app/Admin/Users in our example, and reverses it to Users/Admin/ sampleApp. Then it walks "up" that tree, including FBX_Layouts.cfm for each circuit. Vinny: Yeah, that's cool. Me: See, Vinny? Face it, you were born to be a programmer. Ditch this gangster stuff and... Vinny: Yeah, I wanna discuss that very shortly. For now, though, is there anything else I need to know to get my application completed? Me: Well, the FBX_Layouts.cfm file sets two variables: "fusebox.layoutfile" and "fusebox.layoutdir". Unless you want to have a separate directory for layout files, you can set "fusebox.layoutdir" to an empty string:
<cfset fusebox.layoutdir = "">
Vinny: What about "fusebox.layoutfile"? Me: That points to a file that, well, take a look at the one I used for that sample application I just showed you:
<cfoutput>
<style>
.#Fusebox.thisCircuit# {
border : double Silver;
}
</style>
<table class="#Fusebox.thisCircuit#">
<tr>
<td>
<font size="-2">Don't mind me, I'm just the #Fusebox.thisCircuit#</font>
</td>
</tr>
<tr>
<td>
#Fusebox.layout#
</td>
</tr>
</table>
</cfoutput>
Vinny: Hmmm...you lost me a little. Me: All right. The first part of the file is just declaring a style; it's an HTML thing. I'm using a variable name to declare it. Vinny: Yeah, I see that, "fusebox.-thisCircuit". Where did that get set? Me: That's part of the API (application programming interface) of Fusebox. There are several variables you can access - things like "fusebox.thisCircuit", "fusebox.rootpath", "fusebox.targetCircuit" - a bunch of others. Vinny: Okay, and I can find that info where? Me: Look in the Fusedoc of the core file and you'll see the info on it. But don't worry, Vinny, I'm not going to leave you stranded until we finish your app. Vinny: Yeah, I was just thinkin' if anything was to happen... Me: Well, contingency plans are always a good idea! Okay, let's continue with the layout file. I create a table that applies the style I just created, then it outputs the variable "fusebox.layout". Vinny: What is that? Me: That's another part of the API. Essentially, whatever is done in each circuit is wrapped into a variable called "fusebox.layout". Then the programmer can decide what to do with it. Here, I'm wrapping the results of what went before in a table. Vinny: Wait, if "fusebox.layout" wraps "whatever is done in each circuit," then won't that code you just wrote be wrapped into this "fusebox.layout" variable? Me: Exactly! You're really getting it now. It's the programmer's job to do whatever he or she wishes with that variable. Eventually, though, it's the core file's job to output "fusebox.-layout". Vinny: In that example, what you did was just keep wrapping it in layout files? Me: Yes, the layout files were identical, with the exception of the actual definition of the style. Vinny: Well, I think I understand a lot more now. Me: I think you're making fantastic progress! Hey, maybe you should come to one of my classes as a student, instead of as the client! Vinny: Yeah, well, all this talk of yours about how you're convinced I'm runnin' an illegal bettin' operation has made me...reexamine things. Say, I know a nice little place down by the East River where we could talk about this in greater privacy. Me: That sounds great, Vinny. Let me post this last bit to my editor and, hey, is that your car? Nice car! Wow, look at those guys. Are those your customer service reps? Vinny: Yeah. Let me introduce you to them...
* * *
Editor's Note: The last section planned for this article, "Final Thoughts," had to be omitted since, at this point, we stopped receiving updates from the author. More information may be found at www.halhelms.com.
About Hal Helms Hal Helms is a well-known speaker/writer/strategist on software development issues. His monthly column in CFDJ contains his Musings on Software Development and he has written and contributed to several books. Hal holds training sessions on Java, ColdFusion, and software development processes. He authors a popular monthly newsletter series. For more information, contact him at hal@halhelms.com or see his website, www.halhelms.com.
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...
Mike Neil is general manager for virtualization strategy in the Windows Server Division at Microsoft. Mike is focused on the delivery of the Windows virtualization technology, including Windows Server 2008 Hyper-V, Microsoft Hyper-V Server and Virtual PC 2007. Mike also directs the tec...
Two of the biggest launches in Rich Internet Application history took place in 2007/2008 when Adobe launched AIR 1.0 in February '08 and Microsoft launched Silverlight (September '07). At the 6th International AJAXWorld RIA Conference & Expo in October SYS-CON Events is delighted to be...
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...
2008 is going to be an important year for Rich Internet Applications. Most organizations are delivering or planning to deliver Rich Internet Applications; however, at the same time, most IT managers are facing a dilemma: which Rich Internet Application technology and platform to use? T...
CFDynamics, a ColdFusion web host, has renewed an agreement with SmarterTools that will allow them to pass on immediate value to their customers. When a customers signs up for a dedicated hosting account they will now receive $750 worth of features including SmarterMail, SmarterStats a...
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: