Entries Tagged as 'ColdFusion'

Creating a Reload Event-Handler for Model-Glue

ColdFusion , Model-Glue No Comments »

The Model-Glue framework has a number of configuration settings that modify its behavior. Perhaps the most important of these settings is the "reload" setting. When the reload setting is set to "true", the framework itself will be reload on each request, and any changes you made to the Model-Glue, ColdSpring, or ORM settings of your application since the last reload will be implemented. When reload is set to "false," those framework files will not be reloaded, and any changes you might have made to them are ignored.

So the idea is that you would have the reload setting set to "true" during development so that any changes you make are processed in the next request. The drawback to being in this constant-reload mode is that it takes time to reload the framework, an amount of time that increases as you add event handlers, message broadcasts, and such to the ModelGlue.xml file and add more bean definitions to your ColdSpring file. It's for this very reason that the Model-Glue team state that it is "imperative" that you set reload to "false" when you put your application into production.

As the development of your application progresses, you'll reach a point where you don't want to reload the framework for every single request because you're spending too much time waiting between requests. At that point, you would set reload to "false", and manually force a reload of the framework when necessary by adding the reloadKey and reloadPassword to the URL of one of your page requests, like so:

http://www.myModelGlueApp.org/index.cfm?init=true

...where "init" is the reloadKey and "true" is the reloadPassword.

Many Model-Glue developers open a separate tab in their web browsers pointing a URL for their application that contains the reloadKey and reloadPassword and simply reload that page whenever they need the framework reloaded, rather than navigating away from the current page they're working on. I decided to go a slightly different route and create a reload event-handler that I could trigger from any page in my Model-Glue application and execute the reload event in a new browser tab or window.

The page layouts of my applications always include some sort of header area at the top of the page. In the header area, I added a hyperlink labeled "Reload MG" with a URL pointing at my reload event-handler:

<cfif viewState.getValue("appEnvironment") EQ "local">
    <cfset reloadURL= viewState.getValue("myself") & "performReload&init=true">
    <p align="right"><a href="#reloadURL#" target="_blank">Reload MG</a></p>
</cfif>

In my last blog post, I explained how my applications determine whether they're running in my local development environment or my remote production environment. The <cfif> statement ensures that the reload link only appears in the header when I'm running the application on my local box. Having the "target" of the hyperlink set to "_blank" ensures that the reloader page opens in a new tab or window.

The performReload event-handler is defined in the ModelGlue.xml file like so:

<event-handler name="performReload">
    <broadcasts />
    <results />
    <views>
        <include name="body" template="util/dspReload.cfm" />
    </views>
</event-handler>

The reload action is initiated by the presence of the reloadKey and reloadPassword in the URL, so there isn't a need to execute any additional controller or model code. The event-handler simply loads the dspReload.cfm page in my "util" directory. This is what the dspReload.cfm page looks like:

<h2>Page Should Close Automatically</h2>

<script type="text/javascript">
    window.close();
</script>

The single Javascript statement is pretty self-explanatory: close the current window.

So when I click on the "Reload MG" link at the top of any of my Model-Glue application pages, a new browser tab opens and the focus of the browser is on that new tab. I can return to my previous tab (where I'm working) and simply wait for the reload event to complete over in the new tab. Once it does complete, the Javascript executes and the new tab is closed: I don't have to close it myself.

So instead of keeping an open browser tab that I'd have click on, click the reload button for, and the click back to my previous tab, I can just click a link in my current page to spawn a reload tab and simply navigate back to my original tab. While it's not a huge improvement, I prefer it over maintaining a reload tab.

Managing Environment-Specific Application Settings Via A ColdSpring Bean

ColdFusion , ColdSpring , Model-Glue 1 Comment »

When I develop my ColdFusion applications, I work in two different environments. I develop the applications on my local machine, then deploy them to the server when I reach particular milestones or when it's ready for limited user testing. Even though I mimic the server environment as best as I can on my local machine, there are still certain aspects of the application that are different when it executes on the server. For example, my local machine isn't configured to send and receive e-mail, but I want my application (when it's running in production) to send out an e-mail when certain functions are executed.

What I used to do to solve this problem was to run a series of functions via the onApplicationStart() function in Application.cfc that would determine where the application was running (development or production), record that fact in an application-scoped variable called "locale", and then set a series of additional application-scoped variables based on what the current environment was. I would then code certain aspects of my applications, such as those responsible for sending e-mail, to examine the value of the application.locale variable to determine if certain function should execute and then use any other application-level settings necessary for the actual execution (like the e-mail address associated with the application).

I recently started using Model-Glue as my application framework, and since Model-Glue uses ColdSpring to manage some of its internal settings, I decided to revise my technique to take advantage of ColdSpring as well.

Here is the code of the appConfig.cfc I created for managing the application settings:

<cfcomponent displayname="appConfig" hint="I provide the configuration settings for the application dependent on where the application is running.">

<cffunction name="init" access="public" returntype="any" hint="I accept all of the possible setting configurations">
<cfargument name="universalSettings" type="struct" required="true" hint="A struct of all of the configuration settings that are true regardless of environment" />
<cfargument name="localSettings" type="struct" required="true" hint="A struct of all of the configuration settings for the local environment" />
<cfargument name="remoteSettings" type="struct" required="true" hint="A struct of all of the configuration settings for the remote environment" />
<cfset var loc= StructNew()>
<cfset variables.config= StructNew()>
<cfloop collection="#arguments.universalSettings#" item="loc.ukey">
<cfset variables.config[loc.ukey]= arguments.universalSettings[loc.ukey]>
</cfloop>

<cfset loc.env= determineEnvironment()>

<cfloop collection="#arguments[loc.env]#" item="loc.ekey">
<cfset variables.config[loc.ekey]= arguments[loc.env][loc.ekey]>
</cfloop>

<cfreturn this />
</cffunction>

<cffunction name="determineEnvironment" access="private" output="false" returntype="string" hint="I determine the application environment">
<cfif Left(cgi.cf_template_path,6) EQ "/Users">
<cfreturn "localSettings" />
<cfelse>
<cfreturn "remoteSettings" />
</cfif>
</cffunction>

<cffunction name="getConfig" access="public" output="false" returntype="any" hint="I return a config setting">
<cfargument name="configName" type="string" required="true" hint="The name of the configuration setting">
<cfreturn variables.config[arguments.configName]>
</cffunction>

<cffunction name="setConfig" access="public" output="false" returntype="void" hint="I set a config setting">
<cfargument name="configName" type="string" required="true" hint="The name of the configuration setting">
<cfargument name="configValue" type="any" required="true" hint="The value/data to store in the configuration setting">
<cfset variables.config[arguments.configName]= arguments.configValue>
</cffunction>

</cfcomponent>

The init() constructor function takes three structs as arguments: one that contains the universal application settings that are the same regardless of environment, one that contains the application configuration settings for my local/development environment, and one that contains the configuration settings specific to my remote/production environment. The universal settings are copied into the "config" struct in the variables scope, and then a call is made out to the determineEnvironment() function to determine the current application environment. The determineEnvironment() function uses the cgi.cf_template_path to determine if the current ColdFusion template is running on a Macintosh system (my work laptop is a Mac) and returns the name of the constructor argument that should be used to populate the rest of the "config" struct. The getConfig() function provides a means of retrieving the value of a configuration setting, while the setConfig() function allows you to change a configuration setting.

So populating this appConfig object with the correct application configuration settings is simply a matter of providing the three different configuration structs into the init() constructor argument. That's where ColdSpring comes into play: ColdSpring is ideal for managing and documenting the data and objects that need to be injected into singleton objects. Here is an example ColdSpring bean definition (within a ColdSpring.xml file) for the appConfig object:

<bean id="appConfig" class="myApp.model.csBeans.appConfig">
<constructor-arg name="universalSettings">
<map>
<entry key="ds"><value>myDatasource</value></entry>
<entry key="appName"><value>myApp</value></entry>
<entry key="approot"><value>/myApp</value></entry>
</map>
</constructor-arg>
<constructor-arg name="localSettings">
<map>
<entry key="locale"><value>local</value></entry>
<entry key="emailNotification"><value>false</value></entry>
<entry key="uploadDirectory"><value>/Users/Brian/Websites/myApp/fileRepo/</value></entry>
</map>
</constructor-arg>
<constructor-arg name="remoteSettings">
<map>
<entry key="locale"><value>remote</value></entry>
<entry key="emailNotification"><value>true</value></entry>
<entry key="errorSenderName"><value>myApp System</value></entry>
<entry key="errorSenderEmail"><value>myApp@domain.org</value></entry>
<entry key="errorDefaultSubject"><value>An error has occurred in the myApp system</value></entry>
<entry key="uploadDirectory"><value>/wwwroot/myApp/uploadedFiles/</value></entry>
</map>
</constructor-arg>
</bean>

As you can see, the ColdSpring bean definition contains three <constructor-arg> XML blocks, one for each argument to be passed into the appConfig.cfc during instantiation, and each constructor argument contains a <map> XML block that defines the struct variable for that argument.

What's the advantage of defining these settings in ColdSpring? Once the appConfig object is defined as a ColdSpring bean, I can inject an appConfig bean into any other singleton bean object I define in ColdSpring or retrieve appConfig from the ColdSpring beanFactory object (which is usually instantiated during application startup). Plus, Model-Glue makes it very easy to inject ColdSpring beans into any of your controller objects simply by passing a list of ColdSpring bean names into a "beans" attribute in either the controller's &lt;cfcontroller&gt; tag or the starting &lt;controller&gt; tag of the controller's XML block in the ModelGlue.xml file of the application (see the "How to Use Bean Injection" page on Model-Glue documentation site for more details on that).  And it makes sense to put my application configuration settings alongside the Model-Glue configuration settings in ColdSpring so there's only one file I need to refer to for my configuration data.

The end result? I end up with an appConfig object containing the correct application settings for the current environment that my code can retrieve variable settings from whenever a function's behavior is dependent upon the application environment.

This technique I've just outlined works for me because I'm a solo developer with only two application environments, a simple way of determining which environment an application is running in, and usually only a small number of environment-specific app settings to deal with. If you're working in a team or with multiple application environments, you made need a more robust approach.  One option you might want to consider is the Environment Config project on RIAForge.org. The project also lets you leverage ColdSpring to define environment-specific variables, but it provides more options for distinguishing between different application environments and more flexibility in how you structure and retrieve your application configuration information. It's still in beta at the moment, but it looks promising.

Looking for Support For My CF Builder Enhancement Request: WebDAV Support

CFML , ColdFusion , ColdFusion Builder , Miscellaneous 6 Comments »

As a whole, I like the new ColdFusion Builder IDE. I've run into a few quirks and roadblocks while trying to install it and set it up the way I want it on my machines, but I suspect that's more a result of how my machines are set up than a failing of the product, and hopefully I'll get it all straight soon.

But CF Builder is missing one feature that I need to make it my sole, do-it-all IDE: support for the WebDAV file transfer protocol. At the university where I work, WebDAV is THE protocol used to allow developers to upload, download, update, and delete files on the web server because it makes it easy for the web hosting unit to delegate a certain amount of control to departmental representatives in what is essentially a shared webhosting environment.

This isn't exactly a new problem for me: CFEclipse didn't provide any WebDAV support of its own either. While there is an Eclipse plugin in existence that provides both FTP and WebDAV support, it's old, doesn't support the secure WebDAV implementation that we use, and is no longer being worked on/developed further. So while I've been doing my coding and testing locally using CFEclipse, I've had to rely on Dreamweaver or a stand-alone WebDAV desktop client to actually upload my files to the server. It's not the worst process in the world, but it would be nice to be able to handle it all in one program/IDE.

At CFUnited, I asked Adam Lehman (Product Manager for ColdFusion at Adobe) if there were any plans in the works for adding WebDAV support to Builder (seeing as how Dreamweaver supports WebDAV). He indicated that he didn't think so, but suggested that I submit a feature enhancement through the CF Builder bug database.

So I did: it's request #79437.

If you have any interest in seeing WebDAV support added to ColdFusion Builder (whether because you also have a need to upload files via WebDAV, or because you simply feel Builder should be capable of handling any file management protocol), please visit the CF Builder bug database, log in with your Adobe ID and password (if you don't already have an Adobe account, it's easy to sign up for one), go to the request record, and use the "Bug Votes" option to vote for the request and/or the "Comments" option to weigh in on the topic.

News and Impressions from CFUnited 2009

ColdFusion , Web development , CFML , Adobe No Comments »

If you've been following my updates on Twitter, you know that I was at the CFUnited conference last week. I didn't post anything during the conference because, quite frankly, I didn't set aside any time to do so, and there was lot going on most of the time.

I'm not going to try and sum up everything that was presented at the conference: I'm not sure any one person can. But there were a number of news items and developments that came about either just before the conference or during the conference that I thought were worth pointing out:

  • ColdFusion 9 in the Cloud: In the opening CFUnited keynote, Ben Forta and the Adobe team announced that ColdFusion 9 would include licensing options for running ColdFusion in cloud environments, and that they would specifically support the use of ColdFusion 9 on Amazon's EC2 cloud environment. Details (sparse though they are) can be found on Ben's blog post on the subject. Though I'm not a fan boy of cloud computing, having this option is important for ColdFusion developers who have an idea for a high-traffic web application but don't have the money to invest in their own server farm.

  • 4CFF: 4CFF is the acronym for the For ColdFusion Foundation, a new non-profit foundations founded by several member of the CF community with the goal of providing assistance and resources to ColdFusion open-source projects and establishing a "professional membership society for the ColdFusion Community at large." I missed their unofficial announcement/presentation, so I can't provide any information about how they plan to move forward with their goals, but I think the idea of having a resource where CF programmers can get help with the non-programming challenges involved in starting and maintaining an open-source project is a good one.

  • Framework updates/changes: The final, production version of Model-Glue 3.0 (Gesture) was released just prior to the conference, while the beta release of ColdBox 3.0 was announced on the first day of the conference. But perhaps the most dramatic framework announcement was that Adam Haskell, previously the lead developer for the Fusebox framework, was going to resign from that role and lead the development of a new and separate version of Fusebox called FuseNG (Fusebox Next Generation), citing irreconcilable difference between himself and TeraTech, the Maryland-based CF development/training shop that currently controls the domain name and source code behind Fusebox. As a developer who uses Fusebox, I'm curious to see how this decision will play out. The current version of Fusebox is a very effective, usable, and mature framework, but Adam's a smart guy and it'll be interesting to see what he and the other developers involved in FuseNG will come up with.

  • The Merlin Manager beta: The final event on Friday at the conference was the Demo Derby, where developers got several minutes to show off a project of theirs. While all of the presentations were noteworthy (and in two instances quite humorous), the one I thought really needed to be brought to the attention of the CF community as a whole was John Mason's Merlin Manager. One of the announcements regarding ColdFusion 9 was that it would provide an AIR-powered desktop application that would let ColdFusion server administrators manage and compare multiple ColdFusion server instances from one dashboard. John's Merlin Manager is also an AIR-powered CF server manager, but it's built to work with ColdFusion 7 and 8 servers. He demonstrated how his app provided real-time status information for a server, how it let you store current server settings as a snapshot prior to making a settings change, and that it could compare the settings between two different servers, highlighting where the settings differed. Even though the project is still in beta, it looked very feature-complete and could be of real benefit to those CF shops that won't be upgrading to CF 9 anytime soon. John is looking for volunteers to participate in evaluating the beta: if you're interested, visit http://www.merlinmanager.com/ to sign up.

As for the conference as a whole, I have to echo everyone who's already commented about it on their blogs and via Twitter: it was an excellent, informative, and fun conference, the best I've ever attended. And that statement is coming from someone who, for various personal and professional reasons, wasn't all that worked up about attending. Everyone involved in the planning and execution of the conferences, especially the folks from Stellr and those presenters who stepped up to fill in for last-minute speaker cancellations (all the presenters deserve credit, but those folks especially) should be proud of the work they did.

For those folks who weren't able to attend, be aware that a number of the presenters will be posting their presentations online, either on their own blogs, SlideSix, or both, so keep an eye out for announcements about those (and note that some of those posting and announcements were made last week during the conference itself).

ColdFusion Builder Extension for Looking Up CFML Tags/Functions in CFQuickDocs

Adobe , CFML , ColdFusion 1 Comment »

Sometimes when you're working on an idea, the things you learn inspire another idea. It's not something you planned on doing, but it seems like a cool idea and it wouldn't take much time to do, so you jump into it without much thought.

That's pretty much how my CFQuickDocs Lookup Extension for ColdFusion Builder came about. For anyone who doesn't already know about CFQuickDocs (hopefully very few of you), it's a website created by Jake Munson that lets you quickly look up the documentation for any ColdFusion tag or function.  I knew from previous experience that it was possible to pull up the CFQuickDocs page about a particular tag or function by adding the tag/function name as an anchor parameter to the CFQuickDocs URL, so when I realized that I could design a ColdFusion Builder extension that pulls in content from an external web page, creating a simple extension to do a CFQuickDocs lookup seemed like a no-brainer.

But in my enthusiasm to follow through with the idea, it didn't occur to me to look more closely at ColdFusion Builder to see what kind of documentation might actually be incorporated into the IDE itself:  that thought didn't occur to me until after I'd finished the extension and submitted it to RIAForge. Turns out that all of the tags and functions for ColdFusion 9 can be found in the general Help menu under ColdFusion:  it's not front and center, but it's not hard to find either.  And the style and functionality of the documentation is fairly similar to how CFQuickDocs looks and works. That fact, plus the fact that you can have the Help window open and still interact with the IDE (something you cannot do with the dialog windows used in Builder extensions, which is one of the biggest limitations of extensions IMHO), diminishes the usefulness of my extension (comparatively).

Still, my extension can serve as a simple example of how to pull an external web page into an extension dialog box. And folks who are still using ColdFusion 7 and 8 in production (such as myself) may prefer to rely on the CFQuickDocs documentation rather than the CF9-centric docs in the IDE.