NO MORE CAREER
POLITICIANS!
Get Out Of Our House: Replacing congress with TRUE citizens!
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

best web hosting - top web hosting sites, thetop10bestwebhosting.com

Czech your Page Rank!
Check Page Rank of any web site pages instantly:
This free page rank checking tool is powered by Page Rank Checker service
Surf's Up!
Visit Egosurf.org and massage YOUR web ego!
My Score: 9,001
Doug's Books

Read (and recommend)

  • Men are from Mars, Women are from Venus
  • The Wisdom of Crowds: Why the Many Are Smarter Than the Few and How Collective Wisdom Shapes Business, Economies, Societies and Nations
  • Blink: The Power of Thinking Without Thinking
  • Head First Design Patterns
  • Transact-SQL Programming
  • What's So Amazing About Grace?
  • Just So Stories (Rudyard Kipling collection)

Reading

  • Prayer: Does it Make Any Difference?
  • Data Mining (Practical Machine Learning Tools and Techniques)
<< November, 2008 >>
SMTWTFS
1
2345678
9101112131415
16171819202122
23242526272829
30
Search Blog

Recent Comments
Re: Railo 3.1 on Windows Server 2008 and IIS7 - Part 3 of 3 (by Jon at 8/27 2:04 PM)
Re: Hosts File Changes Not Acknowledged on Vista 64 (by Spacy at 8/24 3:46 PM)
Re: THE DAY CFUNITED DIED (by ComboFusion at 8/23 10:50 AM)
Re: My Grandpa (by Tasha at 8/10 4:29 PM)
Re: Just What IS a 'Service Layer', Anyway? (by dougboude at 8/02 10:10 AM)
Re: Just What IS a 'Service Layer', Anyway? (by Isaac at 8/02 2:25 AM)
Re: PayPal IPN Coldfusion CFC (by Soyestudiambre at 7/25 6:12 PM)
Re: PHP vs COLDFUSION (by Tony Garcia at 7/17 11:24 AM)
Re: PHP vs COLDFUSION (by dougboude at 7/14 8:45 AM)
Re: PHP vs COLDFUSION (by Lola LB at 7/14 5:51 AM)
Categories
Archives
Photo Albums
Funnies (5)
Family (3)
RSS

Powered by
BlogCFM v1.11

26 November 2008
Auto-Synchronizing Your SQL DB Across Multiple Development Machines
how I roll

Building upon my last post regarding the setup of dual development environments and how to keep them in sync, this time I want to focus on keeping the development database in sync and how I have approached it.

In my setup, I have an office PC and a home laptop, both running SQL Express as my database server. The goal: to have all changes performed from either location be reflected on both. Here's a diagram (I love pictures) of my current setup:

In reality, a database is nothing more than a file, so in theory then, if we can manage to keep that file synchronized across different machines, we should then be able to keep our database synchronized as well. With that in mind, here are the steps taken to accomplish my goal:

MACHINE 1
1. Create an account with FolderShare (
www.foldershare.com), or your favorite file syncing service;
2. On machine 1, create a folder to house your database (when you create a database in SQL Express, it wants to know WHERE the actual database file should reside on your hard drive...you'll be pointing it to this directory when the time comes);
3. Create a share on the FolderShare site that points to the directory you created in step 2;
4. Fire up SQL Management Studio, connect to your local database server, and create a new database (again, being sure to make sure the location of the data and log files are the directory you created);

All done on the first machine! Straightforward stuff. Now for the other machine.

MACHINE 2
1. On machine 2, create a folder to house your database, just as you did on machine 1. You can name it anything you like, and it can live on any drive you like.
2. Using FolderShare, direct the share you created earlier to be synchronized with the folder you created on this machine;
3. Go get a cup of coffee and give FolderShare time to synchronize the directories (copy down the MDF and LDF sql database files);
4. IMPORTANT!  Open up your Control Panel -> Services utility and scroll down to the "SQL Server (SQLEXPRESS)" service. Right click it and choose properties. Click on the "Log On" tab, and click the "Local System Account" radio button. Click 'OK', then RESTART THE SQL SERVICE;

changing SQL Server's log on credentials

changing SQL Express log on credentials
5. Fire up your SQL Management Studio and connect to your local database server;
6. Right click 'Databases' and choose 'Attach'. Click the 'Add' button in the resulting dialogue, then navigate your way to the folder you created in step 1;
7. Select the MDF file that should now be there and complete the attach process.

screen shot for attaching the database
attaching a database in SQL Express Management Studio

VOILA! You are now using a synchronized copy of the same MDF that your other dev machine is! This is the exact setup I have running, and it's working pretty doggone good if I do say so myself.

Okay, all that having been said, please note a few caveats I have found when using this arrangement:

1. Only ever have one SQL Management Studio open at a time. If you are doing inserts or modifying tables from both machines at once, funky things happen and FolderShare suddenly becomes suicidal. In theory you should only be working from one machine at a time anyway, so this shouldn't be too much of an annoyance.
2. Remember that synchronizing takes a few minutes to kick off sometimes, so you'll have to allow a little time when going from one machine to the other before your changes will be visible.
3. If you do NOT perform the services step outlined in the tasks for machine 2, your database will attach, but it will be read-only, and that won't be much help to you.

That should be it! If anybody else has any tricks they use for keeping their dev environments in sync, we're all ears!

Posted by dougboude at 7:43 PM | PRINT THIS POST! | Link | 8 comments



23 November 2008
Multi-Worksite Productivity Configuration
how I roll

I am a self-employed individual. It wasn't until just last month, however, that I actually procured an "away from home" office space. It was at that point that I began to ponder the logistics of working at an office AND being able to work from home as well. How would I keep files in sync? How would I be able to do a day's work from home and then do a couple more hours at night without accidentally overwriting something, or needing something from the office computer while working on my laptop in the kitchen? Following is a fairly simple set up that my friend Boyan Kostadinov shared with me, and it has really been quite an efficient configuration.

Let me first show you a diagram of my current setup, a list of the tools I'm using in order to maintain synchronicity, and then I'll delve into more detail for those who are interested.

diagram of how to set up multiple workspaces and keep them in sync

Details
My personal need is to be able to have the following be synchronized wherever I'm working from:

  • browser bookmarks;
  • auto-fill username/password combinations (courtesy of Roboform!);
  • my local web root;
  • project directories connected to SVN repositories

Let me address these one by one.

Bookmarks
Delicious (del.icio.us) is a web-based application whose sole purpose one earth is to maintain your personal bookmarks in a central, universally accessible loation: the web. By relying on Del.icio.us as my primary bookmark storage facility, I don't have to worry about keeping browser bookmarks in sync. Delicious provides lots of add-ins that make using it a relatively easy process. web site:
http://del.icio.us

Usernames/Passwords
Roboform is one of those apps that once you start using it you wonder how you ever got through your day without it. Among other things, Roboform watches your browsing habits and, when it sees you performing what it believes to be some sort of authentication, offers to save your credentials so that you don't have to enter them each time (this info is securable). I don't know about you, but I visit and use a LOT of sites that require authentication. Now when I hit one of them, a little window pops up providing me with the possible logins for that site. I select it, click okay, and I'm in! Roboform stores these username/password combos in a file, so what I did was make sure that this file lives in a directory that I am syncing with my other machine. So if on one machine I add or modify one of these username/password combos, the other machine automatically sees it and vica versa. Roboform has a free version (which I use). You can download it and read all about it at
www.roboform.com. Speaking of synching directories...

Directory/File synchronization
I can't thank my friend Boyan enough for turning me on to THIS web site!
www.foldershare.com . It's a Microsoft hosted application that allows you to share folders on your local machine, but via a web-based proxy. In a nutshell, you browse to the folderShare site and log in. Next you tell it you want to create a new share. It lets you browse your local machine and choose the folder to share, then you give that share an alias. Voila! Now from my OTHER machine I can log in to folderShare, click on the share I had previously created, and tell it i want to synchronize that share with a folder on my current machine. In short order folderShare copies the files down to my local drive and I'm in business. Any changes i make on one machine are automatically copied to every other machine syncing to that folder. FolderShare also allows you to share folders with individuals, so when Boyan has a cool video he wants me to see, he drops it into the folder he shared with me on his machine and I can then lose a few minutes of productivity, just like that!

SVN
Most of what I do involves web development projects that are stored in off-site SVN code repositories, though the actual development takes place locally. Free services such as www.Assembla.com (the one I use) allow one to remove some of the worry out of development by maintaining versioning of your code and the ability to quickly recover in the event of local hardware failure. Using SVN involves connecting one of your local directories to the remote SVN repository (via an "SVN Checkout"), and then manually performing updates and commits as you see fit. When I first started working from two sites, I was having to make sure I remembered to commit whatever changes I had at the end of the day to the SVN repository, then when I got home I would have to remember to do an Update before I started working. Well, forgetting one or the other of these steps a couple of times quickly became a waster of precious hours trying to get things back in sync, so I simply shared the project folder via folderShare. The work process now goes more like this:

I go to the office and make changes and additions to my project folder. All of those changes are automatically sync'd to the project folder on my laptop. (Bear in mind that BOTH of these folders are a "checkout" of my SVN project, meaning they contain all of the versioning metadata files.) I go home and the next morning decide I want to work from the kitchen table. So I make more changes to my project folder and then do an SVN commit to get all of the cumulative changes safe and sound off site. My laptop folder icons indicate that my project folder is all in sync with SVN (little green check marks on all the folders). I go to the office the next day and what do you think my project folder indicates with regard to SVN? Yes, it has all green check marks, meaning my local copy is in sync with my SVN copy, and the commit was done from home on the laptop. Pretty sweet, eh?

If anybody wants more detail on any aspect of what I just shared, feel free to email or IM me. Also, I am positive that many of you have implemented yet more multi-worksite productivity enhancers, so I'd love to hear about them and the tools you've found to make your life easier.

Hope this helps someone.

Doug out.

Posted by dougboude at 4:20 PM | PRINT THIS POST! | Link | 3 comments
22 November 2008
I Have a Dream....

The collective abilities of the many always surpass the few. This is common knowledge, and pervades every aspect of life so much so that we probably don't even take note of it. A pride of lions takes more game than one hunting solo; the most correct answer is the distillation of many people's opinions rather than that of a single individual; the list could go on ad finitum. So why then is it that so many people who catch the entrepreneurial bug tend to want to go it alone? Rather than seek out like-minded individuals to strengthen and further their causes, they segregate and ostrecize themselves, professionally speaking, and attempt to "build the ark" all by their lonesome, dreaming of the day when they alone (and those few souls with whom they select to share their success) will find themselves sitting atop Mount Ararat?

Okay, a somewhat deep intro into the subject of this post, but I do believe the principle is relevant. I have good ideas. I'm sure many, many of you out there have good ideas, too. Ideas that, if we ever find ourselves with all of the needed time, resources, expertise, and perpetual motivation to make the idea tangible, we'd be gazillionaires.The fact is, though, that the solo road from concept to real product is very, very long and most never complete the journey. So then: why not break away from the pack and become part of a very small, very select alliance of like-minded inviduals, pooling your resources, planning together, and executing that plan as a single unit? It's a model that has served nature quite well, with a success rate that has brought mankind himself to his present state.

I myself have caught the entrepreneurial bug, the innate desire to turn my ideas into reality and what were once only dreams into realistic, achievable goals. Having this desire, I often explore different plans of execution, trying to find the best way to invest my resources so that I create a stair step approach to reaching my desired end. But  no matter how I slice it, traversing that road as a solo individual is a lengthy prospect. If I had one, or two other individuals, though, who had the same goals and with whom I could combine allocated resources, I know that we would shorten that road exponentially. We would each bring to the table our own professional and personal networks; or own talents, skillsets, and areas of expertise; our own collection of ideas that we have been mulling over and evolving for the past umpteen years; and our own cache of resources to contribute to the cause. We would form our own elite "brain trust", advancing the causes that would become a legacy to our posterity.

Now, if my treatise has given rise to any hot sparks of interest or a chorus of "hallelujah" whispered under the breath, then perhaps we should begin a dialogue to explore our chemistries, alignment of goals, and how well our ideas complement one another. I for one am READY to make something happen, but would love for it to be the passion of several individuals rather than just myself, for the benefit of all involved.  Any takers?

Posted by dougboude at 12:41 PM | PRINT THIS POST! | Link | 3 comments
18 November 2008
TinyMCE Refusing to Display Icons
or, A Descent into Madness

Okay, this post is as much informative as it is a rant, so bear with me while I vent as I share.

Let's talk TinyMCE. Typically I use FCKEditor, but for my current project I'm going with TinyMCE. How hard can it be, right? An editor is an editor is an editor. I download it, I add the two simple lines needed to transform my textarea into a full blown editor, and voila: it's an editor. But the menu has NO icons to be seen! First impulse is that I obviously have a bad path for the images. But no, TinyMCE uses "embedded sprites" or something like that to display its icons, so it isn't a pathing issue. If I right click where an icon should be, I see it for a moment, but then it's gone again.

The symptoms

tinyMCE not showing its icons

What it should look like

tinymce editor with icons displayed

So I wade through dozens of google results that look like they *might* provide a clue. One is a thread on the TinyMCE forum where the symptoms are the same as mine. I read through the replies looking for that silver bullet, but the only clue I find is that the user eventually solved their problem by removing the div tag from around the textarea. Not a solution for me, because I kinda NEED my divs to provide structure to my layout (I thought we all did), but it does give me reason to believe that perhaps I have implemented some css that TinyMCE doesn't like. So I move my textarea to other parts of the layout and reload until I finally get the icons to show up. Aha! I've narrowed it down to the div area that causes the symptoms, <div id="inner">! So let's see what horrific css i've applied to that div that broke TinyMCE.

#inner {display:block;margin-left:-200px;margin-right:-210px;padding:5px;}

Well, it doesn't LOOk so horrible at first glance. Let me give that div a new ID and add a new line to my css, adding style elements until I see it break again. So now in my layout I have
<div id="innerr">
and in my css I have
#innerr {display:block;}

Reload. Okay, I see my icons. Add another element:
#innerr {display:block;margin-left:-200px;}

Reload. still see my icons. Add another:
#innerr {display:block;margin-left:-200px;margin-right:-210px;}

Reload. Wow, still see my icons. Surely it can't be the padding that's killing it! Let me add it:
#innerr {display:block;margin-left:-200px;margin-right:-210px;padding:5px;}

Reload.
I STILL see all the icons. I have just completely duplicated the style that was applied to div "inner", where my TinyMCE icons would NOT show themselves, and yet I now DO see the icons. Wait, let me try one more thing...

<div id="inner"> (rename the id back to the original value)

I rename my div ID back to "inner". It has the same exact style as "innerr". But my icons disappear again. WHAT THE HECK?

Obviously ID "inner" is reserved for TinyMCE in some way. Perhaps that was actually mentioned somewhere in the docs, but I didn't see it. So anyway, if you are using TinyMCE and experience surreal symptoms such as disappearing icons, step 1: change your div ID's and class names and see if the symptoms go away. It's likely some style or name you've used that stepped on TinyMCE's tiny little toes.

Posted by dougboude at 1:17 PM | PRINT THIS POST! | Link | 2 comments
15 November 2008
My First Excursion into using Ajax with Coldbox
opinions solicited

I had my first successful forray using Ajax in Coldbox today! After reading a LOT, checking out some examples, and then letting my natural developer's instinct take its course, I ended up with a design that left me really wondering if I had taken a wrong turn or had a moment of brilliance . As I said, it works great, but is it an ideal pattern to use or did I cross one of those invisible "development ethics" lines with my approach? I'll let you be the judge. Before I share the details, I am assuming that the reader already has at least a basic working knowledge of Coldbox views, viewlets, handlers, and Ajax. That said, here be the details...

The Scenario

Upon arriving at my Coldbox app, the visitor will be dropped off at my default layout. Here's how it's organized:
basic coldbox layout

We'll be focusing on the "login/logout" area since that is the portion I applied Ajax to. As you can see, in that area of the layout I am rendering by name the view named "login". My login.cfm view is actually a Coldbox "viewlet", meaning that it performs a private Coldbox call whenever it is loaded. Here's the pseudo-code of my login viewlet:

run the 'authentication.login' event;
grab the current user's login status;
if the user is not logged in
     show the login form
else
     show the logout form
end if

and here are the two faces that the viewlet can show:
face 1 of the login view

 

The execution of the private call to "authentication.login" (as seen in the pseudo code) is for the sole purpose of gathering current user status so we can control the flow and output of the login viewlet. Here's the actual handler method being called that accomplishes this:

<cffunction name="login" access="public" returntype="void" output="false">
 <cfargument name="Event" type="any">
 <cfset var oSession = getPlugin("sessionstorage") />

 <cfif not oSession.exists("loggedin")>
  <cfset oSession.setVar("loggedin",false) />
 </cfif>
 <cfset arguments.event.setValue("loggedin",oSession.getVar("loggedin")) />
 <cfif not oSession.getVar("loggedin")>
  <cfset arguments.event.setvalue("xe.frmAction","authentication.doLogin") />
  <cfset arguments.event.setValue("User",oSession.getVar("User")) />
  <cfif oSession.exists("sec_message")>
   <cfset arguments.event.setValue("loginmessage",oSession.getVar("sec_message")) />
   <cfset oSession.deleteVar("sec_message") />
  </cfif>
 <cfelse>
  <cfset arguments.event.setvalue("xe.frmAction","authentication.doLogout") />
  <cfset arguments.event.setValue("User",oSession.getVar("User")) />
 </cfif>
</cffunction>

Now, here's where the Ajax comes in to play. Both the login and logout form have as their submit action a call to a Prototype Ajax.Updater. Here are the actual functions:

// functions for the login view
function logmein(thisURL){
 var loginParams = $('loginform').serialize(true);
 new Ajax.Updater('loginlogout',thisURL ,{parameters: loginParams, method:'post'});
}
function logmeout(thisURL){
 new Ajax.Updater('loginlogout',thisURL,{method:'post'});
}

The nutshell is that the Updater will execute the call to 'thisURL' and place the result, whatever it is, into the target 'loginlogout' div.

 

 

Okay, I have two more relevant methods in my Authentication handler: doLogin and doLogout. Here is the pseudo-code for 'doLogin':

attempt to authenticate using the credentials supplied...
if login failed
   set session.loggedin = false;
   set session.securityMessage = "Login failed. Try again.";
else
   set session.loggedin = true;
end if
//actual code used to perform the following...
<cfset arguments.event.renderData(type="plain",data=getPlugin('renderer').renderView('authentication/login')) />

This last line is taking advantage of two cool things Coldbox allows:

 

1. The ability to render a view (or viewlet) within the handler and create a content variable;
2. The ability to render Data back to the caller rather than a view.

In my case, since "login" is a viewlet (making its own private call to the 'login' method in order to get current state variables), I'm simply rendering it inline. Then, I'm feeding the results of that rendering (a blob of HTML) to the renderData method, which is then passing that blob of HTML back to my Ajax call. Who, in turn, updates my target div with it; in this case, either a login form with a message displayed, or a logout form and a welcome message. Here is my rendition (in pictures) of how it flows:

'doLogout' performs almost identical actions...setting the session variables appropriately and then returning the HTML results of rendering 'authentication/login' inline.

As I said, it works great. But I am very interested in the opinion of others as to how they feel about the appropriateness of this approach. Any thoughts?

Posted by dougboude at 1:22 AM | PRINT THIS POST! | Link | 1 comment
10 November 2008
Using Variables in Coldspring.xml with Coldbox

As you can tell from  my last two posts, I am getting pretty deep into Coldbox used in conjunction with Coldspring. One of the things that Coldbox does for us is pass in our configuration settings to the Coldspring bean factory when it initially loads our beans (from Coldspring.xml), thus allowing us to use configuration variables, like so:

<bean id="transferFactory" class="transfer.TransferFactory" singeleton="true">
 <constructor-arg name="datasourcePath">
  <value>${TransferSettings.datasourcePath}</value>
 </constructor-arg>
  ....

The only shortcoming with this is that because we're using Coldspring's DefaultXmlBeanFactory.cfc, it will only do variable replacements when they are found within <value> tags. Brian Kotek addressed this issue with a CFC found in his Coldspring Utilities collection (http://coldspringutils.riaforge.org/ ) , specifically with a CFC called "DynamicXMLBeanFactory.cfc". Using this instead of Coldspring's default bean factory allows you to place variables in other places within your Coldspring.xml. I've used this CFC before in another project, so now my challenge was to figure out how to implement it in Coldbox so that I could make my Coldspring.xml file more dynamic.

 

After a couple hours of tinkering around, AND having to make a minor modification to DynamicXMLBeanFactory.cfc to account for it being used in the Coldbox environment, here are the steps:

1. Place a copy of the modified version of DynamicXMLBeanFactory.cfc in the Coldbox/System/Extras/Coldspring folder. The Coldspring folder won't exist, so go ahead and create it;

2. Add a setting to your Coldbox.xml.cfm file like so:

<YourSettings>
 <Setting name="ColdspringBeanFactory" value="coldbox.system.extras.coldspring.DynamicXMLBeanFactory" />
  ....

That's it! If you want to make sure it's working, create a Coldbox.xml setting such as this:

<Setting name="modelRoot" value="myapproot.model" />

and then add that variable to your Coldspring.xml as part of a bean's class path, for instance:

<bean id="authenticationService" class="${modelRoot}.services.authenticationservice">

If the app fires up without error, you're in business!

 

 

 

Hope this helps someone.  :0)

 


P.S.
If anybody is interested in the changes I made to DynamicXMLBeanFactory and why, they are as follows:

1. Since DynamicXMLBeanFactory extends Coldspring's DefaultXmlBeanFactory, and since Coldbox is hardwired in its "ioc" plugin to interact with DefaultXmlBeanFactory's interface (specifically calling the method "loadBeansFromXmlFile", which does not exist within DynamicXMLBeanFactory), I had to overload that method in DynamicXMLBeanFactory like so:

<cffunction name="loadBeansFromXmlFile" returntype="void" access="public" hint="I am overloading this super class method">
  <cfargument name="beanDefinitionFile" type="string" required="true" hint="I am the location of the bean definition xml file"/>
  <cfset loadBeansFromDynamicXmlFile(arguments.beanDefinitionFile,getDefaultProperties()) />
</cffunction>

2. DynamicXMLBeanFactory was executing an "expandpath" on an already expanded path (Coldbox is already passing in the fully expanded path to the Coldspring.xml file ), resulting in an error of "file not found". Because of this, I had to comment out line 98 in the "getReplacedColdSpringXML" method.

Perhaps there was a more elegant method for implementing Brian's CFC, but the only two choices I saw was to either modify the framework (NO! BAD MAN! NO!), or the CFC. I opted for the CFC. What I was thinking, though, is that perhaps it would be good if Coldbox allowed not only the path to the IOC's beanfactory class to be a setting, but also the name of the bean loader method that should be called (after init)? Just a thought.

Doug out

Posted by dougboude at 5:00 PM | PRINT THIS POST! | Link | 1 comment
09 November 2008
Basic Security in Coldbox using Transfer and Coldspring - Part II (of II)
wiring and autowiring

In the first post on this subject, I shared my 10,000 foot view of what pieces needed to go where in a Coldbox app in order to implement security. A lot of the code in that post was probably unfamiliar looking to many people (I know it would have been to me a couple of days ago!). So in this post I want to share how I implemented Transfer and Coldspring in the security process, clarify what some of that code was doing, and whatever other details about it I may have also come to know.

I'm assuming that you already know what Coldspring is, what Transfer is, and the basics of an event-driven framework. For example, Coldspring is a framework that allows you to manage the relationships between your CFCs (CFC A needs a configuration bean injected into it, the configuration bean needs to be initialized with parameter X, etc.); Transfer is an ORM framework that stands between you and your database (in a good way) and lets you write your code "sans SQL"; and the basics of event-driven frameworks is that they have core components built into them that allow you (via the methods they expose to you) to reach into their very soul and leverage "core functionality", like retrieving global configuration settings, retrieve system beans, etc. Okay, all that having been said, here's the dialogue I had with my frameworks in order to get them all on the same page of the workbook (Personification to be followed up with real code snippets, don't worry. It just helps me simplify things when I animate the inanimate.  ):

1. "Hey, Coldbox;(via Coldbox.xml.cfm...) I'm using Coldspring to manage my components for me. What's that? You'll make your configuration settings available to Coldspring to use in its XML configuration file? When you fire up Coldspring you'll go through its configuration XML and replace any curly-braced variables with matching values from your own configuration BEFORE you initialize Coldspring? Aw, that's sweet. Thanks!"

2. "Hey Coldspring;(via Coldspring.xml.cfm...) I'm gonna need you to produce a few objects from our host MVC framework's core, Okay? What objects would those be? Oh, well, I'll be needing the Coldbox factory object since that's how you'll need to retrieve the rest of the framework's objects for me. I'll need you to ask the Coldbox Factory for an instance of the Coldbox framework itself since it has all the core methods that many of my model object will need; and I'll want a discrete instance of the Coldbox SessionStorage plugin as well so that my model objects can access my app's persistent scope. Let's see, what else...oh yes, I'll be using an ORM, so i'll need you to produce an instance of Transfer via its own factory. And then I'll just tell you about my model objects as I get them added to the app. Thanks, Coldspring! You're a real bud."

3. "Hey Transfer,(via Transfer.xml.cfm...)  I got a whole BOATLOAD of database objects I need you to make available to me. It's a very, very long list, so just read through it at your leisure."

My frameworks are very good listeners and so once I figured out exactly how to say what I wanted to say, they complied fully with my desires. So let's look at how I made them understand, shall we?

Dialogue 1
Within the Coldbox.xml.cfm file, in the <Settings> section, I made sure the following settings were like so:

<Setting name="IOCFramework" value="Coldspring" />
<!--IOC Definition File Path, relative or absolute -->
<Setting name="IOCDefinitionFile" value="config/coldspring.xml.cfm" />
<!--IOC Object Caching, true/false. For ColdBox to cache your IoC beans-->
<Setting name="IOCObjectCaching" value="false" />

 

As far as the rest of that dialogue, as long as I make sure the setting exists within the Coldbox.xml.cfm file, Coldbox will automatically replace any curly-braced variables in my Coldspring.xml.cfm file for me. For instance, in my Coldbox.xml.cfm file in the <YourSettings> section, I have the following Transfer values:

<YourSettings>
 <Setting name="TransferSettings.datasourcePath" value="/emailmanager/config/datasource.xml.cfm" />
 <Setting name="TransferSettings.configPath" value="/emailmanager/config/transfer.xml.cfm" />
 <Setting name="TransferSettings.definitionPath" value="/emailmanager/model/definitions" />
</YourSettings>

You'll see in the Coldspring snippets below the variable placeholders that correspond to these settings; it'll make more sense there. 

 (Note: presently, only curly-brace variables found within a <value>${myColdboxSetting}</value> tagset will be replaced. Don't put curly-brace vars in your bean's class path, for instance, and expect them to work. There is a way to do this which I'm investigating now, but by default it does not.)

Dialogue 2
We informed Coldspring of several different things, so let's look at them a chunk at a time.
"...produce a few objects from our host MVC framework's core...Coldbox factory object...Coldbox framework itself...a discrete instance of the Coldbox SessionStorage plugin...." Here is the XML to accomplish the previous:

<bean id="ColdboxFactory" class="coldbox.system.extras.ColdboxFactory" />
<bean id="Coldbox" factory-bean="ColdBoxFactory" factory-method="getColdbox" singleton="true" />
<bean id="oSession" factory-bean="ColdBoxFactory" factory-method="getPlugin" singleton="true">
 <constructor-arg name="plugin">
  <value>sessionstorage</value>
 </constructor-arg>
</bean>


If you aren't familiar with Coldspring's ability to produce a bean by executing a method referenced on a previously defined bean, well, you're looking at it in action (note the 'factory-bean/factory-method' attributes). I myself wasn't aware of this ability, so was quite happy to have discovered it. First we're defining Coldbox's object factory; then we're creating an instance of Coldbox by calling the Factory's "getColdbox" method; lastly I'm grabbing an instance of Coldbox's built-in "sessionStorage" plugin the same way, calling the generic "getPlugin" method and passing in the name of the plugin I want.

Next portion of that dialogue...
"...I'll be using an ORM, so i'll need you to produce an instance of Transfer via its own factory...." Here's that code (notice the curly brace vars; each one equates to a setting created in the Coldbox.xml.cfm file): 

<bean id="transferFactory" class="transfer.TransferFactory" singeleton="true">
 <constructor-arg name="datasourcePath">
  <value>${TransferSettings.datasourcePath}</value>
 </constructor-arg>
 <constructor-arg name="configPath">
    <value>${TransferSettings.configPath}</value>
 </constructor-arg>
 <constructor-arg name="definitionPath">
    <value>${TransferSettings.definitionPath}</value>
 </constructor-arg>
</bean>

<bean id="Transfer" factory-bean="TransferFactory" factory-method="getTransfer" singleton="true" />
<bean id="Datasource" factory-bean="TransferFactory" factory-method="getDatasource" singleton="true" />

Defining Transfer's own factory, then defining the other Transfer beans as results of executing Transfer Factory methods. Noice, eh?

 

 As far as the model, so far I have only one bean defined, and that is my "authenticationService" bean. Here's that Coldspring.xml:

<bean id="authenticationService" class="emailmanager.model.services.authenticationservice">
 <constructor-arg name="transfer">
  <ref bean="Transfer" />
 </constructor-arg>
 <constructor-arg name="oSession">
  <ref bean="oSession" />
 </constructor-arg>
</bean>

As you can see, I'm passing in an instance of Transfer and Coldbox's session manager upon instantiation. By doing so, my service object can perform database calls and manage persistent values.

 

 Dialogue 3
Transfer relies on an XML file to get its information about your database entities (tables) and their relationships to one another. I won't share the entire Transfer.xml.cfm file here since I've already got most of my entities defined for my app (long list), but here are the tables relevant to security:

<objectDefinitions>
 <package name="user">
  <object name="user" table="appuser" >
   <id name="id" type="string" generate="false"/>
   <property name="username" type="string" column="username" nullable="false"/>
   <property name="password" type="string" column="password" nullable="false"/>
   <property name="firstname" type="string" column="firstname" nullable="false"/>
   <property name="lastname" type="string" column="lastname" nullable="false"/>
   <property name="email" type="string" column="email" nullable="false"/>
   <property name="isActive" type="boolean" column="isActive" nullable="false"/>
   <property name="timezone" type="string" column="timezone" nullable="true"/>
   <onetomany name="usergroup" lazy="true">
       <link to="usergroup.usergroup" column="userid"/>
       <collection type="array">
         <order  property="id" order="asc"/>
       </collection>
   </onetomany>
  </object>
 </package>
 <package name="usergroup">
  <object name="usergroup" table="usergroup" >
   <id name="id" type="string" generate="false"/>
   <property name="groupid" type="string" column="groupid" nullable="false"/>
  </object>
 </package>
</objectDefinitions>

Now that I have all of that set up, let me share again the code from my authentication handler(controller) and authenticationService cfc (that I shared in my previous post on this topic)  that peform the login function.

 

 authentication handler

<cffunction name="doLogin" access="public" returntype="void" output="false">
 <cfargument name="Event" type="any" />
 <cfset var loggedin = "" />
 <cfset var rc = arguments.Event.getCollection() />
 <!--- attempt to authenticate using the credential supplied... --->
 <cfset loggedin = variables.authenticationService.login(username=rc.username,password=rc.password) />
 <cfif not loggedin><!--- login failed...send them back --->
  <cfset arguments.event.setValue("loginmessage","Login Failed. Please try again.") />
  <cfset arguments.event.setValue("loggedin",false) />
  <cfset arguments.event.overrideEvent("login") />
 <cfelse>
  <cfset arguments.event.setValue("loggedin",true) />
 </cfif>
 <cfset arguments.event.setvalue("xe.frmAction","authentication.doLogout") />
 <cfset arguments.event.setView("login") />
</cffunction>

The line to home in on is the one that begins "<cfset loggedin = ...". It is there that, from within my handler, I am accessing the authenticationService bean we defined in Coldspring.xml.cfm. You'll recall though that I did NOT define a relationship between my handler and authenticationService. How then did my handler get access to it?

In Model-Glue, we would have provided our controller a setter and getter for the authentication service, then Model-Glue itself would have auto-injected that bean for us. Well, Coldbox to the rescue, we have the same type of functionality available to us! Coldbox actually allows two ways to auto-inject Coldspring-defined beans: via setters and getters, as we are probably accustomed to; and via the <cfproperty> tag. Now, typically cfproperty doesn't really do much for us at all; but in a Coldbox handler it's a big ol' flag that says "inject it here! inject it here!. Okay, here's the additional line in our authentication handler that performs this magic:

<cfproperty name="authenticationService" type="ioc" scope="variables" />

I opted NOT to go the setter and getter route because of the fact that if I happened to have created a setter and getter that had the same name as a bean i defined, it would attempt to auto-inject whether I really wanted it to or not. In order to avoid this, I am choosing to explicitly name my auto-injections via the <cfproperty> tag. 

Okay, so our doLogin event is calling the authenticationService's 'login' method, passing in the username and password supplied; Let's look at authenticationService now.

<cffunction name="init" access="public" output="false" returntype="any">
 <cfargument name="transfer" type="any" required="yes" />
 <cfargument name="oSession" type="any" required="yes" />
 <cfset variables._transfer = arguments.transfer />
 <cfset variables._session = arguments.oSession />
 <cfreturn this />
</cffunction>

<cffunction name="login" access="public" returntype="boolean">
 <cfargument name="username" type="string" required="yes" />
 <cfargument name="password" type="string" required="yes" />
 <cfargument name="isActive" type="boolean" required="yes" default="true" />
 <!--- create a transfer user bean, passing in the username and password, then give it back --->
 <cfset var objUser = variables._transfer.readByPropertyMap("user.user",arguments) />
 <cfset retval = false />
 <cfif objUser.getID() IS "0"><!--- login failed... --->
  <cfset variables._session.setVar("loggedin",false) />
 <cfelse>
  <cfset variables._session.setVar("loggedin",true) />
  <cfset variables._session.setVar("user",objUser) />
  <cfset retval = true />
 </cfif>
 <cfreturn retval />
</cffunction>

 We instructed Coldspring to inject Transfer and oSession into this bean upon creation, and made provision for it via the init method. Pretty standard Coldspring stuff. In our login method, we call upon Transfer to create for us the "user.user" bean, giving it our argument collection to use as criteria (my arguments are named exactly as fields in that table). Also, in case you're wondering why we didn't ask Transfer for the "user" bean instead of the "user.user" bean, it's because in our Transfer.xml.cfm file we defined a package called "user" and within that package an object named "user". Hence the path "user.user".

 

 So, Transfer will create the requested bean and, if it matched the criteria passed in, the bean will be populated; otherwise it'll be empty, with a zero value for the primary numeric key ("ID"). After Transfer gives it back, I check the primary key. If it's zero, login obviously failed. If it's not, success! Stuff the user bean into session and return a boolean to the handler (controller).

I do hope you were able to follow this okay. I can't tell you how long I had to bang my head against it for it to sink in and gel, so I hope it saves someone else a few hours of digging through docs.

Doug out.

Posted by dougboude at 1:58 AM | PRINT THIS POST! | Link | 7 comments
Basic Security in Coldbox using Transfer and Coldspring - Part I

There's no denying it: the plethora of documentation and examples that exist for the Coldbox framework is invaluable and undoubtedly covers every possible scenario to one degree or another. As I press on into a project where the use of Coldbox, Coldspring, and Transfer has been mandated to me, I'm finding that, despite the documentation and tutorials, I'm still having to search around and piece together for myself some of the information I seek. So, to complement the existing volumes of Coldbox-centric information and for my own personal reference purposes, I'm going to post some of what I'm learning as it becomes coherent to me.  Tonight's post is focused on an overview of how to implement basic security in Coldbox using Transfer and Coldspring. I won't delve much into Transfer or Coldspring with this one (that post will follow soon) so that we can focus on the 10,000 foot view first.

As I mentioned, the first "block of functionality" I tackled was the implementation of security, so let's use that as our illustration. There is a lot of documentation on the subject and even a few example apps I found. But, the documentation left me with too much gray area as I attempted to relate what I read with my current level of understanding of the framework, and the example apps, though they worked wonderfully, didn't explain to me HOW they were working. I had to dissect the apps using my limited knowledge of Coldbox and painstakingly trace the event flow from one area of the framework and application to the next, referring to the documentation and even examining some of the framework's CFCs internally. The end result for me was the foundation for my own "flavor" of basic security implementation, and it this that I share.

First, my own visualization of the Coldbox event lifecycle. I realize that the true lifecycle in all its detail could consume many a diagram page, but for the purposes of someone simply desiring to add in a bit of functionality, I do believe I've illustrated all that is required.

The Coldbox event lifecycle highly simplified

A request comes in and right away Coldbox executes the interceptors it knows about. Interceptors are very aptly named, as they do just that: intercept the request before it gets too far and executes whatever methods are appropriate. In our case, we're interested in knowing right up front if the user attempting to fulfill an http request is authenticated or not. Intercept them, then, we shall.

Coldbox comes out of the box with a pre-built security interceptor (a CFC that is executed at what we typically know as the "onRequestStart" point), but being at the newbie point I am, I found it a bit too deep to assimilate. In order to understand how things really work, therefore, I created my own. I called it "security.cfc" and dropped it into my app's "interceptor" directory. The next step was to tell Coldbox that I have an interceptor in place. This is done in config/coldbox.xml.cfm, in the <Interceptors> section. Mine looks like this:

<Interceptors>
 <Interceptor class="interceptors.security" />
</Interceptors>

I eluded to it, but now is a good time to talk about one of the things that makes Coldbox unique among the MVC frameworks we CFers have to choose from. If you've not used any framework before that relies on what's typically referred to as "convention" (Ruby on Rails, Fusebox 5.x sans xml), then you are used to defining your events down to every last detail: what messages to broadcast, what methods to execute in what CFC, etc. But Coldbox rather follows the "convention" approach, which is simply naming your CFCs and methods in such a way that the framework knows what to do all by its lonesome. This really isn't a new thing to you at all though, because if you've used Application.cfc in any of your apps, then you have practiced this very thing! Consider this...did you ever have to TELL your app to run application.cfc? Nope, because of the fact that you NAMED it application.cfc, the framework (in this case, CF Server) looked for it and executed it. Inside of your application.cfc you had some methods, right? You had one named "onApplicationStart", one named "onRequestStart", one named "onSessionStart", etc. Why? Because you knew that if you named your method appropriately, the "framework" would execute it at just the right time in the http request lifecycle. This is absolutely no different in Coldbox. Inside our interceptors we create methods that are named according to when we want Coldbox to execute them. Granted, Coldbox uses a few names of its own to indicate a specific point in the event lifecycle (such as 'PreProcess'), but they boil down to the same concept as what we're accustomed to with Application.cfc. So, I told Coldbox "hey, I have an interceptor I want you to execute for me at the beginning of the event lifecycle", then within that interceptor I created methods to run at specific points in time. In the case of my Security.cfc interceptor, I have create a single method called "preProcess" (guess when it's going to be executed). Within this method I am checking to see if the current user is logged in. If yes, do nothing; if no, redirect to my login event. In my simple scenario, "logged in" means i found session.loggedin and it was set to 'true'. Here's my interceptor method:

 

 

<cffunction name="preProcess" access="public" returntype="void" output="false">
 <cfargument name="event" required="true" type="coldbox.system.beans.requestContext" />
 <cfset var loggedin = false />
 <cfset oSession = getPlugin("sessionstorage") />
 <cfif (NOT oSession.exists("loggedIn") OR NOT oSession.getVar("loggedIn")) AND listfind("authentication.doLogin",arguments.Event.getCurrentEvent()) eq 0>
  <cfset arguments.Event.setValue("loginmessage","Please Log In") />
  <cfset arguments.Event.overrideEvent("authentication.login") />
 <cfelse>
  <cfset arguments.Event.setValue("message","we're logged in!") />
 </cfif>
</cffunction>

 

 

 

Let's assume the user is NOT logged in. My interceptor resets the current event to my login event, "authentication.login", and processes it. POP QUIZ: Based on the event name "authentication.login", what CFC and method within that CFC do you suppose Coldbox will be executing? I'm sure you guessed right, so let's go look at the 'Login' method within my 'authentication.cfc'.

Hmmm, where IS my authentication.cfc? It's not an interceptor...where is it? Ah, it's where Coldbox ASSUMES it will be (there's that "convention" thing again!): sitting in the "handlers" directory. We Model-Gluers and other MVC framework people might think of it more commonly as "controllers", but the Coldbox vernacular is "handlers", as in "event handlers". Here is the Login method:

<cffunction name="login" access="public" returntype="void" output="false">
 <cfargument name="Event" type="any">
 <cfset arguments.event.setvalue("loginmessage","You need to log in!") />
 <cfset arguments.event.setValue("loggedin",false) />
 <cfset arguments.event.setvalue("xe.frmAction","authentication.doLogin") />
 <cfset arguments.event.setView("footer") />
 <cfset arguments.event.setView("login") />
</cffunction>

 

 

 

Being the good controller/handler that it is, it's doing next to nothing except setting a few values in the event bucket and tossing some views into the view collection so that we can properly give the user a login form.

Now we see the login form, nothing fancy, just a prompt for a username and password. The user enters it, hits the submit button, and off we go to our form's action: authentication.doLogin .

<cffunction name="doLogin" access="public" returntype="void" output="false">
 <cfargument name="Event" type="any" />
 <cfset var loggedin = "" />
 <cfset var rc = arguments.Event.getCollection() />
 <!--- attempt to authenticate using the credentials supplied... --->
 <cfset loggedin = variables.authenticationService.login(username=rc.username,password=rc.password) />
 <cfif not loggedin><!--- login failed...send them back --->
  <cfset arguments.event.setValue("loginmessage","Login Failed. Please try again.") />
  <cfset arguments.event.setValue("loggedin",false) />
  <cfset arguments.event.overrideEvent("login") />
 <cfelse>
  <cfset arguments.event.setValue("loggedin",true) />
 </cfif>
 <cfset arguments.event.setvalue("xe.frmAction","authentication.doLogout") />
 <cfset arguments.event.setView("login") />
</cffunction>

Ignore the details for a moment, and let it suffice to say that we are grabbing the credentials out of the event bucket, submitting them to our model for authentication, and getting back a boolean value indicating success or failure. Again, our controller/handler method is doing next to nothing (as it should), except setting some values for the view to use.

 

 

Wanna see the "login" method in the model?

<cffunction name="login" access="public" returntype="boolean">
 <cfargument name="username" type="string" required="yes" />
 <cfargument name="password" type="string" required="yes" />
 <cfargument name="isActive" type="boolean" required="yes" default="true" />
 <!--- create a transfer user bean, passing in the username and password, then give it back --->
 <cfset var objUser = variables._transfer.readByPropertyMap("user.user",arguments) />
 <cfset retval = false />
 <cfif objUser.getID() IS "0"><!--- login failed... --->
  <cfset variables._session.setVar("loggedin",false) />
 <cfelse>
  <cfset variables._session.setVar("loggedin",true) />
  <cfset variables._session.setVar("user",objUser) />
  <cfset retval = true />
 </cfif>
 <cfreturn retval />
</cffunction>

We're passing it two parameters and setting a third by default, then passing those parameters to Transfer to see if it can successfully populate a User bean with them. If yes, store the user bean to session so we can utilize it other places and return a boolean 'true'; if not, store the empty user object to session (in case we still want to use it somewhere else...at least we know it will exist) and return a boolean false.

 

 

That's it in a nutshell! If I were me looking at this post two days ago, however, I would be very hungry to know the details of how I set up Coldspring and Transfer to play together, and how it is I am accessing my session scope and Transfer from within my model. In order to encapsulate the purpose of this post (give an overview of basic application flow for the purpose of implementing security), however, I shall end it here. But my next post will be the nitty gritty of how I wired all these pieces together.

Hope this helps someone, and do feel free to contribute your own wisdom to the comments!

Posted by dougboude at 12:30 AM | PRINT THIS POST! | Link | 3 comments
07 November 2008
SQL Forward Engineering with Visio 2003 Professional
made a little simpler

Finding the shortest route from diagram to tangible product can be tricky depending on the tool you use to create your Entity Relationship (database) diagrams. I'm using Visio 2003 Professional for mine, and so I went on the hunt for a way to transform diagrams into SQL 2005 Scripts (Visio Professional doesn't include any export features for ER diagrams). The final solution isn't the absolutely most elegant, but I'd call it live-able at least. The basic steps are:


1. Export your diagram to XML;
2. Apply an XSL stylesheet to the XML that generates SQL 2005-compatible scripts.

Exporting XML from VISIO 2003 Pro

Visio Professional doesn't include the luxury of exporting to XML, so I discovered a very sweet third party tool aptly called "Toolbox" made by a generous company named Orthogonal (the tool is free!). Installing Toolbox creates a floating toolbar in Visio that allows you to export the currently open ER diagram. To install simply download the Orthogonal "Toolbox" product, run the setup, restart Visio (if it was open during install), and open an ER diagram. The toolbox should be floating there in your window. If you don't see it, you can go to View,Toolbars and make sure it is checked as being visible.

Creating the SQL Scripts

In my scenario I opted to just go the route of using Internet Explorer to view the finished XML code since it will automatically apply any referenced stylesheets. Because Toolbox let us choose a stylesheet to apply at the time of export, a reference was added to the XML file so when we view it in IE we see a nicely formed SQL 2005 script to create our tables and their relationships. Here's a snapshot of the Toolbox dialog box:

The finished product:

xml created by appling xslt to Toolbox XML file

On the subject of the XSLT...Orthagonal provides an XSLT file that creats the script, but without any linebreaks or anything to make it readable. I found a modification to this XSLT on this guy's site , and I modified it a little further in order to account for autoincrementing identity fields, table names that might also be reserved words (who ever does that?), and default values for bit type fields. My version is at the end of this post.

Final Notes
The XML exported by Toolbox doesn't seem to capture anything you put into the "default value" for entity columns. Because of this, I hard-code a rule into my XSLT that says if the field type is bit and NULL is NOT allowed, make the default value true. Also, although Visio does allow you to say that an column is an identity column, it does NOT give you a way to specify that it should autoincrement. I added one more rule to my XSLT that says if the column is INT and is IDENTITY, script out the autoincrement functionality as well.

The XSLT file has some HTML embedded in it in order to allow for an eye appealing output when viewed in IE. If you are going to be applying the stylesheet via another mechanism, you'll probably want to go through the XSLT and strip out the generated HTML first.

TIP: If you weren't aware of it, you can have multiple pages within one Visio ERD document (as in the screenshot at the beginning of this post). The Toolbox export will export one xml file for every diagram on every tab, so if you want to get things done in one shot just consolidate your Visio documents into one!

That should be it. Here are the relevant links for you to get started creating SQL 2005 scripts from your Visio 2003 ER diagrams:
my version of the XSLT file

link to get Toolbox
sample of the XML produced by Toolbox (without xslt applied)

sample of the XML produced by Toolbox (WITH xslt applied!)

Posted by dougboude at 6:04 PM | PRINT THIS POST! | Link | 17 comments
04 November 2008
Elegant Approach to Disabling Submit Button on Forms

A while back I had a project that required the submit button of the login form to be disabled unless both the username field AND the password field had values. There are probably several ways to skin that cat, but my good friend Boyan Kostadinov offered a more elegant solution (he's always good for the most elegant approach!), and I thought I'd share it with whoever else may benefit.

This solution uses the Prototype library (you need version 1.6). It also uses a small "login.js" file that Boyan wrote which looks for anything with the class "enableOnEntry" (the key to making this work) and then cycles through the form elements within that class, adding their IDs to an array (actually a delimited list, but it is split into an array later). Boyan then binds event listeners to each of the form fields which, while typing in values, will check to see if the submit button should be enabled or not. Anyway, you can read through the JS file if you like, but here's how to implement it, along with a working demo in this post:

1. acquire and reference the following js files in your template (in this order):
    prototype.js
    login.js
2. ensure that your form tag has the class "enableOnEntry";
3. ensure that your form has exactly one submit button (of type 'submit', not 'button');

That's it!

Working Demo:

For your convenience, here is the code used to create the working sample above:

<script src="/js/prototype.js"></script>
<script src="/js/login.js"></script>
<fieldset style="width:200px;">
<legend>Login Form</legend>
<form class="enableOnEntry" name="login" id="login" onSubmit="alert('form submitting...');return false;">
 Username:<br><input type="text" id="username" name="username" value="" /><br><br>
 Password:<br><input type="password" id="password" name="password" value="" /><br>
 <br>
 <input name="submit" id="submit" type="submit" disabled="true" value="Login" />&nbsp;&nbsp;<input type="reset" value="Clear" onClick="$('submit').disabled = true;" />
</form>
</fieldset> 

 and here are links to the js files:

 

 prototype.js

login.js

Hope it helps.

Posted by dougboude at 5:55 PM | PRINT THIS POST! | Link | 3 comments