November 10, 2005

CFEclipse and Flex Builder 2: Happy Together

I now do all my Flash development in Flex Builder 2. No exceptions. But I still use another installation of Eclipse for other types of development (ColdFusion, Java, HTML, JavaScript, etc.). Yesterday, I ran into a situation where I needed to embed a small Flex application in a custom HTML page, so tried installing CFEclipse into Flex Builder 2, and it seems to work perfectly. It's not guaranteed to work, and I supposed it could break in the future, but for now, I'm a very happy developer.

Update: I should qualify that I'm talking about the standalone version of Flex Builder 2. The plugin version will definitely work with CFEclipse.

Posted by cantrell at 09:56 AM. Link | Comments (5) | References

July 30, 2005

Making Your ColdFusion and Java Applications More Platform Independent (Part III)

Making Your ColdFusion and Java Applications More Platform Independent (Part III)

Two years ago (has it really been that long?!), I made a couple of posts about how to make your ColdFusion and Java applications more platform independent. The first post covered the importance of case consistency, and the second talked about not hard-coding path separators since they are different on different platforms. Well, all this time later, I actually have a third piece of advice: don't hard-code new line characters.

I'm switching my development environment over from OS X to Windows (I haven't used Windows consistently in many years, so I figured it was time to give it a try again), and while trying to get MXNA running locally, I came across a bug that I'd never seen in development (on OS X) or on production (Linux). The problem was this line of code:

<cfset blArray = listToArray(blacklist, chr(10))/>

The code is trying to convert a line-separated list into an array. On OS X and Linux, it works fine since the new line character is "line feed", or chr(10), or \n, but on Windows, the code didn't work because a new line is "line feed" and "carriage return", or chr(10) & chr(13), or \n and \r. So rather than ever having to worry about this again, I used a little Java trick to make the code run in any environment. Now it looks like this:

<cfset blArray = listToArray(blacklist, createObject("java", "java.lang.System").getProperty("line.separator"))/>

Even with a language like Java (and hence, ColdFusion), if you want your code to be truly platform independent, it takes a little work. The good news is that once that was fixed, MXNA was up and running in my development environment perfectly.

Posted by cantrell at 10:50 AM. Link | Comments (8) | References

May 18, 2005

Why Distinguish Between GETs and POSTs?

It's nice that ColdFusion gives you the option of distinguishing between GET and POST requests by putting variables in two different scopes (the "url" and "form" scopes, or structs), but with the framework I've put together for ColdFusion applications, I don't really need to know. In fact, I don't want my code distinguishing between the two because it makes it less generic (meaning I'm forced to make requests in way or the other). The answer has been to include this little piece of code from my Application.cfc file:

<!--- Combine gets and posts into the request scope --->
<cfif isDefined("form")>
    <cfset structAppend(request, form, true)/>
</cfif>
<cfif isDefined("url")>
    <cfset structAppend(request, url, true)/>
</cfif>

Now I reference everything in the "request" scope or struct, regardless of whether it was submitted through a form or a URL parameter which makes my code more generic and reusable.

Posted by cantrell at 10:48 AM. Link | Comments (14) | References

April 24, 2005

Don't Forget to Scope CFHTTP

I ran into a nasty MXNA 2.0 bug last week. As many of you noticed, we had a case where one person's posts were attributed to someone else. I was stumped for about an hour as I went through lots of lines of code, and long spells of staring into space and contemplating. Then it hit me that since this has only happened one time in all the thousands of posts MXNA 2.0 has aggregated, it must be a concurrency issue.

And it was. MXNA 2.0 uses cached instances of parser components, and in one of those components was a CFHTTP tag that wasn't scoped, or "VARed". Just the right sequence of events caused the variable cfhttp.fileContent to be overwritten with a string from someone else's feed. It's a one in a million shot, but it happened once, and it would have happened again given enough time.

If you're using CFHTTP in a component, and you're using CF 7.0, your code should look like this:

<cfset var foo = 0/>
<cfhttp result="foo".../>

If you're using CF 6.x, it should look like this:

<cfset var cfhttp.fileContent = 0/>
<cfhttp .../>

Note: I owe Sean Corfield a big thanks for helping me track this down.

Posted by cantrell at 11:27 PM. Link | Comments (2) | References

February 22, 2005

xmlSearch is Always Case Sensitive

The ColdFusion function xmlSearch is always case sensitive, it seems, even if you specified case insensitive in the xmlParse function to create the XML object in the first place. So if you're parsing an XML document that you don't have complete control over (like an RSS feed), be careful. If there's a chance the case could be different than what you're expecting, make sure you search for both upper and lower case.

Posted by cantrell at 05:33 PM. Link | Comments (2) | References

February 18, 2005

UTF8, MySQL 4.1, and CFMX 7.0

I spent a good portion of my day trying to get unicode to work with MySQL 4.1 and CFMX 7.0. As it turns out, it's actually pretty easy. I had the database tables created correctly. That I learned from earlier versions of MySQL. Just add this to the end of your CREATE TABLE command:

CHARACTER SET utf8;

I even had the connection string right in the data source form in the CFMX administrator:

useUnicode=true&characterEncoding=UTF8

The problem is that the connection string apparently doesn't go in the "connection string" field. Since I'm using a newer MySQL driver than the one that shipped with CFMX 7 (that supports MySQL 4.x), I discovered that you actually have to append the connection string to the JDBC URL, like this:

jdbc:mysql://localhost:3306/dataBaseName?useUnicode=true&characterEncoding=UTF8

Once I made the change, instant Japanese! I hope this saves someone out there several hours of head scratching.

Posted by cantrell at 05:30 PM. Link | Comments (10) | References

February 15, 2005

Partial Page Caching with ColdFusion

ColdFusion Jedi Master Ray Camden will be giving a Macrochat on partial page caching with ColdFusion tomorrow (Wednesday) from 1:00 to 2:00 Eastern. Here's the official stuff:

Learn how to write a custom tag that allows for simple caching in ColdFusion MX. Ray Camden will lead this discussion on creating a CF tag for partial page caching of information. Ray is the Director of Development for Mindseye, Inc., a Team Macromedia member, and Macromedia User Group manager.

What You Will Learn

If you're interested, you must register!

Posted by cantrell at 10:20 AM. Link | Comments (0) | References

February 09, 2005

CFMX 7 in the News

Here are all the mentions of the CFMX 7 launch in the news that I'm aware of:

Props to Macromedia PR for digging up all these articles.

Posted by cantrell at 11:47 AM. Link | Comments (4) | References

February 07, 2005

Macromedia ColdFusion 7.0 Resources

Everyone knows by now that Macromedia announced ColdFusion 7.0 today, so rather than making an announcement that everyone has already heard, I thought I'd post a few links to some good ColdFusion 7 resources that I've come across today:

Posted by cantrell at 03:02 PM. Link | Comments (1) | References

January 12, 2005

Eliminate ColdFusion Whitespace Once and For All

Since I'm at Macworld this week, and consequently don't have a lot of time to put into my weblog, I'm going to be lazy, and reprint a comment that was sent to me by Jon Alsbury. It was submitted in response to a post entitled Controlling Whitespace in ColdFusion. John writes:

The most effective (and easy to implement) technique for reducing whitespace in CFMX generated pages I have discovered so far is to set up a simple servlet filter to intercept the response in order to strip out whitespace before it is returned to the client. The filer I've been using for this is called Trim Filter and can be downloaded here:

http://www.servletsuite.com/servlets/trimflt.htm

Setup is easy: simply download trimflt.jar from the above URL, drop it into your 'cfusionmx/lib' directory. Add the following to 'cfusionmx/wwwroot/WEB-INF/web.xml':

<filter>
<filter-name>trimFilter</filter-name>
<filter-class>com.cj.trim.trimFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>trimFilter</filter-name>
<url-pattern>*.cfm</url-pattern>
</filter-mapping>

Posted by cantrell at 12:39 PM. Link | Comments (20) | References

December 21, 2004

Who Would Use a CFCONTINUE Tag?

This isn't an official survey (or even unofficial one, for that matter), but I'm wondering how many people out there would use a CFCONTINUE tag if there were one available. Personally, I find the ability to continue (to jump to the next item in a loop) very useful, and occasionally my ColdFusion code suffers without it. 90% of the time I easily get by with CFIF tags inside loops, but when there is a great deal of processing going on, and a lot of decisions being made, I've found myself having to nest a lot of CFIF tags when a CFCONTINUE tag could have simplified my code. What are your thoughts?

Posted by cantrell at 11:35 AM. Link | Comments (23) | References

December 07, 2004

Submitting Flash Forms Without Refreshing

I've been working on a way to submit Blackstone Flash forms without refreshing the page, and I have it working quite well. The code lets you either submit data to the server without re-rendering the Flash, or submit the data to a different window (the CFFORM tag supports targets, but the target attribute doesn't give you a way to submit to a different window).

I've only tested it with Firefox, but I'm pretty sure it will work on all modern browsers. It's a bit too early to release the code just yet, but once Blackstone is live, I'll release the code along with a tutorial.

What do you guys think of what you've seen of Flash forms so far?

Posted by cantrell at 12:01 PM. Link | Comments (5) | References

November 23, 2004

Reinitializing an Application Using Blackstone Events

One of the most useful tags I've ever written is the init tag. Typically, it goes in your Application.cfm file, and the body of the tag gets executed only the first time it's encountered, which means it's the perfect place to put initialization code. You can also force the body to execute again by passing a certain query string parameter in with any request. This is very useful during development when you need to flush cached components or other data.

As I started thinking more in Blackstone terms, however, I wondered what the Blackstone equivalent on the init tag would be. Of course, the init tag still works in Blackstone as does all the CFMX 6.1 code I've run so far, but I wanted to take advantage of the new event handling mechanisms available in Blackstone. So here's what I've come up with so far.

Now, I handle application initialization using the onApplicationStart event. That takes care of running the code only once (usually when the application receives its first request since the server was last started). I then added the following inside my onRequestStart event handler:

<!--- Re-initialize the application, if necessary --->
<cfif structKeyExists(url, "restart") and url.restart>
	<!--- Invoke onApplicationStart event --->
</cfif>

Now, when I want to invoke the onApplicationStart event, I just append a restart=true parameter to any request, and my application is reinitialized without me having to restart the server.

Posted by cantrell at 01:46 PM. Link | Comments (1) | References

November 16, 2004

Chopping Off the End of a List

I'm sure there are tons of these functions around, but I decided to write my own. The listChop function chops a list down to the specified size. Use it like this:

<cfset myList = "a,b,c,d,e"/>
<!--- Chop this list down to 3 elements. --->
<cfset myList = listChop(myList, 3[, delimiter])/>

Here's the function:

<cffunction name="listChop" returnType="string" output="no" >
  <cfargument name="targetList" type="string" required="true"/>
  <cfargument name="amountToKeep" type="numeric" required="true"/>
  <cfargument name="delimiter" type="string" required="false" default=","/>
  <cfset var listSize = listLen(arguments.targetList, arguments.delimiter)/>
  <cfset var i = 0/>
  <cfif arguments.amountToKeep lt 0 or listSize - arguments.amountToKeep le 0>
    <cfreturn arguments.targetList/>
  </cfif>
  <cfloop from="#arguments.amountToKeep+1#" to="#listSize#" index="i">
    <cfset arguments.targetList = listDeleteAt(arguments.targetList,
                                               arguments.amountToKeep+1,
                                               arguments.delimiter)/>
  </cfloop>
  <cfreturn arguments.targetList/>
</cffunction>

I'm using it in a pretty big application I'm writing, so let me know if you see any bugs.

Posted by cantrell at 03:50 PM. Link | Comments (7) | References

November 10, 2004

Safely Selecting the Last Inserted ID, Part II

Well, as it turns out, this isn't an issue at all. I ran two tests. The first followed these steps:

  1. Using a CFQUERY tag, I executed an insert statement.
  2. Used Thread.sleep() to make the page hang for 10 seconds.
  3. Inserted ten additional rows from the command line (using the MySQL command line tool).
  4. After the Thread.sleep(), used LAST_INSERT_ID() to get the last inserted ID, and displaed it.

I expected the result to be 11, but it was actually 1.  The 10 rows I inserted between the initial insert and when I selected the last inserted ID had no effect.  I figured this was because ColdFusion was considered one client, and the command line administrator was considered a different client, and since the scope of the last inserted ID is the client/connection, I was protected.  So I ran this test, instead:

  1. Executed an insert statement in ColdFusion.
  2. Slept for 10 seconds.
  3. Ran a second CFM page that inserted 10 rows while the first page was hung.
  4. After the thread in the original page woke up, selected the last inserted id and displayed it.

Keep in mind I was using no transactions or locks since I was trying to get a wrong result before trying to figure out how to get the correct one, however the result was once again 1.  As it turns out, no transactions or locks are needed.  Why?  Apparently because each request gets its own database connection, and that one connection gets reused for the duration for the request, regardless of how many database operations you perform.  Other requests can happen simultanously, of course, but they all get their own connections, and hense do not affect the first connection's last inserted ID value.  In other words, it seems to work exactly how you would want it to!  ColdFusion does it again!

Disclaimer: This test was run using JRun, CFMX 6.1 (with the latest updater) and MySQL version 4.0.18.  Before you rely on this data, you might want to run some tests yourself, though I will try to get confirmation from the ColdFusion team that this technique should work across all databases and future versions of ColdFusion.

Posted by cantrell at 03:28 PM. Link | Comments (5) | References

Safely Selecting the Last Inserted ID

I run into this issue occasionally, and always find some kind of work-around, but I've finally decided to address it head-on. The scenario is this:

  1. You insert a record into the database.
  2. You need the ID of the row you just inserted so you can insert additional rows in other tables referencing the first row you inserted.
  3. You're worried about your code being thread-safe, so you consider using locks, transactions, UUIDs, etc. But what is the best way?

The easiest and most database-independent way of doing this is to generate a UUID and use it for the primary key for the first insert, and the foreign key for any subsequent inserts. That's fine for certain apps, but for the app I'm working on now, I need to use sequential, auto incremented integers as keys. I'm using the MySQL function LAST_INSERT_ID() to get the last inserted ID, however the ID's scope is the current connection, so if I use two CFQUERY tags (one to insert the row, and one to get the last inserted ID), I believe it's possible I could get the wrong ID if another row is inserted between the time I do my insert and the time I select the last inserted ID. So I'm going to try:

  1. Sending two queries to MySQL at the same time. One to do the insert, and one to do the select. Both statements will use the same connection, and problem solved. I haven't had any luck with this so far, though. I'm not sure MySQL supports this as I keep getting SQL syntax errors.
  2. Putting both CFQUERY tags in a transaction (they actually already are in a transaction), and using the isolation level of serializable. I'm potentially sacrificing some performance, but it should be miniscule. This is a very good solution if it works, but I'm not 100% positive that it will work, though I am hopeful.
  3. Using an exclusive lock. If all else fails, this will definitely work, although the disadvantage is that I will only be taking database operations that originate from one CF server into account. In other words, another server that is unaffected by the lock can slip a new row into the database at just the right moment and trip me up. I would much rather the lock occur at a lower level -- actually in the database, if possible.

I'll post my results. In the meantime, anyone have any additional insight?

Posted by cantrell at 01:22 PM. Link | Comments (9) | References

October 29, 2004

What If You Want To Round Down?

ColdFusion's round() function rounds up. What if you want to round down? Use this:

<cffunction name="roundDown" output="no">
    <cfargument name="target" type="numeric" required="true"/>
    <cfreturn abs(round((arguments.target * -1)))/>
</cffunction>

Example:

round(1.1) = 1
roundDown(1.1) = 1

round(1.5) = 2
roundDown(1.5) = 1

round(1.6) = 2
roundDown(1.6) = 2

Addition:

Bill pointed out that the function above doesn't work with negative numbers. This one does. Thanks, Bill!

<cffunction name="roundDown" output="no">
    <cfargument name="target" type="numeric" required="true"/>
    <cfreturn (round((arguments.target * -1))) * -1/>
</cffunction>

Example:

roundDown(-1.5) = -2

Posted by cantrell at 10:18 AM. Link | Comments (11) | References

August 31, 2004

How to Log Out of an Application that Uses HTTP Authentication

I'm working on an application right now that uses the simple 401 (unauthorized) response code and "WWW-Authenticate" HTTP header to prompt the user for a username and password. This mostly works as expected, however I want the user to be able to log out of the application, which is not so easily done. The CFLOGOUT tag does not tell the browser to stop sending the Authentication header containing your credentials to protected pages, so the only way to be sure you are logged out is to end your session from the browser's perspective, which means closing it. I'm experimenting with another technique, though, and I'd like to get some feedback.

The only people who log into this application I'm working on are system administrators, so the solution doesn't have to look pretty as long as it works. The idea is to make the browser forget the user's credentials by giving it new, false credentials to send, instead. The "logout" code I came up with looks like this:

<cffunction name="logout" ...>
    <cflogout/>
    <cfheader statuscode="401"/>
    <cfheader name="WWW-Authenticate" value="Basic realm=""admin"""/>
    <html>
        <script language="javascript">
            document.location = '../index.cfm';
        </script>
    </html>
    <cfabort/>
</cffunction>

When the user clicks on the "Log Out" link, the function above is executed, and the user is prompted by the browser to enter a username and a password at which point he clicks on cancel, the browser forgets the previous (presumably correct) authentication information, and the user is redirected to an unprotected, public index page. All subsequent requests to the protected admin section of the application will send the wrong credentials, and cause the browser to prompt for new ones.

This seems to work well in the few browsers I've tested with, though, as I said, it's not that pretty, and wouldn't be a good solution for end users. For admins, though, it seems reasonable.

Does anyone else have a different way of tackling this problem?

Posted by cantrell at 12:25 PM. Link | Comments (1) | References

August 26, 2004

ColdFusion 6.1 Updater Now Available

Well, you finally convinced us that there were too many hot fixes out there for you to keep track of, and we needed to roll them all into a 6.1 updater, so here you go. Now back to Blackstone.

Posted by cantrell at 11:08 AM. Link | Comments (0) | References

July 28, 2004

Introduction to Flash (for ColdFusion Developers)

I delivered a presentation today to ColdFusion User Group managers via Breeze. It's basically an introduction to Flash and RIAs for ColdFusion developers. I go through some slides discussing RIAs in general, then dissect a Flash and ColdFusion application line by line. It's about an hour long, so if you have some time, and you're curious about Flash and RIAs, check it out.

Posted by cantrell at 04:48 PM. Link | Comments (2) | References

July 26, 2004

ColdFusion Makes the World a Safer Place

About three weeks ago, America's Most Wanted launch a new site with very comprehensive crime-solving and fugitive-finding functionality. And it's all powered by ColdFusion and Flash (man, I'd love to know how much traffic they are supporting). Macromedia isn't just changing the web -- we're helping to change the world!

Posted by cantrell at 01:28 PM. Link | Comments (0) | References

July 13, 2004

Renaming Files As They Are Uploaded (how CFFILE actually works)

When receiving a file uploaded from a client, you can actually save it and rename it all in one step rather than two steps as the documentation implies.

The documentation states that the "destination" attribute of the CFFILE tag specifies the "pathname of the directory in which to upload the file." This is misleading for two reasons:

  1. The file has actually already been uploaded by the time your CFFILE tag is encountered. The file has automatically been saved in ColdFusion's temporary directory. Using the CFFILE tag with the action attribute set to "upload" is really just moving the file from one place to another. If no CFFILE tag is encountered, the file is simply deleted.
  2. You can actually specify a file name in addition to a directory in the destination attribute. Rather than this...

    <cffile action="upload" destination="/path/to/some/directory" ... />
    <cffile action="rename" ... />

    ... you can just do this...

    <cffile action="upload" destination="/path/to/some/directory/#createUUID()#.gif" ... />

This moves the uploaded file from ColdFuson's temporary directory into the specified directory, and renames it using a unique ID generated by ColdFusion, all in one step.

Posted by cantrell at 11:23 AM. Link | Comments (14) | References

July 08, 2004

The Definitive Guide to the ColdFusion Classpath

Before you can load and use third-party Java classes from ColdFusion, you have to add them to the ColdFusion class path. Unfortunately, class paths are not much fun (learning to get your class path right is probably just as hard as learning to write Java in the first place), and on top of that, adding classes to ColdFusion's class path is confusing because there are so many different ways of doing it. I finally decided to sit down and create the definitive guide to how it's done to try to clarify the process.

First of all, there are different ways of doing it depending on how ColdFusion is deployed. The techniques below are broken down by deployment preference. Also note that there is a difference between adding class files to your class path, and adding jar files. I would recommend jarring up your class files to simplify the installation process, but you can deploy either jar files or class files. If you deploy the class files outside of a jar file, make sure you grab the entire directory structure representing your packages. In other words, if you have a class file called VeryCoolUtil.class in the package "com.macromedia.util", make sure you deploy the entire directory structure (ie com/macromedia/util/VeryCoolUtil.class). If you decide to jar you class files up instead, you also need to make sure you jar up the entire directory structure representing your packages as opposed to just the class files.

ColdFuison Standalone

  1. The easiest way to add class or jar files to your class path is to simply drop them in the lib directory where they are automatically picked up. The directory is located at {cf_installation}/lib.
  2. You can also drop them in any of the Java extension directories. To find a list of the Java extension directories, open the ColdFusion administrator and click on "System Information". Toward the bottom, you will see a system property called "Java Ext Dirs". You can put jar and class files in any of those directories to have them picked up by the ColdFusion server.
  3. If you want more control over the order in which class files are loaded, you can add them to the ColdFusion server's class path manually. In the ColdFusion administrator, click on "Java and JVM", then add the absolute paths to your jar or class files in the "Class Path" field.
  4. Finally, you can manually add class and jar files to the server's class path located in the jvm.config file. I'm not going to go into much detail about that since I recommend you use the admin interface rather than tweaking config files by hand.

J2EE Deployment

  1. The easiest way to add class or jar files to your class path is to simply drop them in the lib directory where they are automatically picked up. The directory is located at {cf_installation}/servers/lib. These class files will be available to all servers.
  2. You can also make your class files available only to the ColdFusion server by dropping them in "{cf_installation}/servers/default/cfmx/WEB-INF/lib". (Note that putting them in {cf_installation}/servers/default/cfmx/WEB-INF/cfusion/lib will NOT work.)
  3. You can drop them in any of the Java extension directories. To find a list of the Java extension directories, open the ColdFusion administrator and click on "System Information". Toward the bottom, you will see a system property called "Java Ext Dirs". You can put jar and class files in any of those directories to have them picked up by the ColdFusion server.
  4. Another way to do it is to add classes through the JRun Management Console. Open up the console, and under the default server, click on settings, then add your classes to the class path list. (Note you can also click on "ColdFusion MX application" under the default server, then click on settings to make the same changes.)
  5. And finally, once again, you can edit the jvm.config file yourself, however again, I recommend you stick to using one of the methods above.

There are also ways to load your class files programatically in ColdFusion, or even to load them remotely, which you can find instructions on here. And finally, keep in mind that changes to you class path always require you to restart ColdFusion and/or JRun for them to be picked up.

Posted by cantrell at 01:54 PM. Link | Comments (5) | References

June 23, 2004

Free ColdFusion Applications

Need an application, and need it fast? There is no more efficient technology for developing web applications than ColdFusion, so of course, you can build just about anything you need quickly enough, but now you can also just download a complete application for free from Free ColdFusion Applications (by the folks at EasyCFM). There are only about 12 applications at this point to choose from, but it looks like a lot of the basics are covered (weblog, calendars, forums, etc.) I have no idea how good any of these applications are, but it seems like they have a lot of potential. I can think of several uses:

  1. Download and use as-is.
  2. Download and customize.
  3. Download and cannibalize.
  4. At the very least, get some ideas for the fully customized version you are writing yourself.

Anyone have any experiences with any of these apps? What do you think?

Posted by cantrell at 11:57 AM. Link | Comments (2) | References

June 22, 2004

Know Your List Functions

If you use ColdFusion list functions, make sure you know the difference between listContains and listFind. Using listContains where you should be using listFind might appear to work at first, but can introduce hard-to-find bugs in your applications down the road.

listContains returns the index of the first item in the list which contains a substring of the string you are searching for. For instance, consider the following code:

<cfset myList = "abc,def,ghi"/>
<cfoutput>#listContains(myList, "e")#</cfoutput>

The substring "e" is contained in the second item in the list, so listContains returns 2 rather than 0. Now consider the code below which uses listFind:

<cfset myList = "abc,def,ghi"/>
<cfoutput>#listFind(myList, "e")#</cfoutput>

listFind looks for an exact match rather than just a substring, so 0 is returned since there is no item in the list which matches "e" exactly. (The search is case-sensitive -- for a case-insensitive search, use listFindNoCase.)

Most of the time, you are probably going to want to use listFind. Either way, just make sure you are aware of the difference.

Posted by cantrell at 10:09 AM. Link | Comments (0) | References

June 08, 2004

Loading Class File Remotely in ColdFusion

Spike Milligan of Spike-fu made a very cool post recently entitled "Loading java class files from a relative path" which demonstrates a technique for loading class files through a local file URL so that you don't have put them in your classpath. I thought that was very innovative, and decided to take it a step further.

The point of Spike's post was to make server configuration easier. To make configuration easier still, why not store all your class files on one central server, and use a similar technique to load them remotely? I wrote a component called RemoteClassLoader that does it for you:

<cfcomponent displayName="RemoteClassLoader" output="no">

  <cfset my = structNew()/>

  <cffunction name="setRemoteClassPaths" returnType="void" output="no">
      <cfargument name="classPaths" type="array" required="true"/>
      <cfset var urls = arrayNew(1)/>
      <cfset var arrayFactory =
          createObject("java", "java.lang.reflect.Array")/>
      <cfset var urlClass =
          createObject("java", "java.net.URL").init("http://macromedia.com")/>
      <cfset var urlArray = arrayFactory.newInstance(urlClass.class, 0)/>
      <cfloop from="1" to="#arrayLen(arguments.classPaths)#" index="i">
          <cfset urls[i] =
              createObject("java", "java.net.URL").init(arguments.classPaths[i])/>
      </cfloop>
      <cfset my.loader =
          createObject("java",
                       "java.net.URLClassLoader").init(urls.toArray(urlArray))/>
  </cffunction>

  <cffunction name="getRemoteClass">
      <cfargument name="class" type="string" required="true"/>
      <cfreturn my.loader.loadClass(class)/>
  </cffunction>
</cfcomponent>

Using the component above, I was able to load Spike's HelloWorld class right from his server, instantiate it, and call functions on it. The code looks like this:

<cfscript>
  remoteClassLoader =
      createObject("component",
                   "com.macromedia.net.RemoteClassLoader");
  urlArray = arrayNew(1);
  urlArray[1] = "http://www.spike.org.uk/downloads/";
  remoteClassLoader.setRemoteClassPaths(urlArray);
  helloWorld = remoteClassLoader.getRemoteClass("HelloWorld");
</cfscript>

<html>
  <cfoutput>#helloWorld.newInstance().sayHello()#</cfoutput>
</html>

A couple of notes:

  1. The code above assumes that the RemoteClassLoader component is in the package "com.macromedia.net" (which is where I put it after I wrote it before checking it into CVS).
  2. I haven't tested this with jar files, but it should work fine.
  3. I wrote this in about 5 minutes, so you might want to bulletproof it before using it in a production environment.

Thanks for the inspiration, Spike!

Posted by cantrell at 02:49 PM. Link | Comments (10) | References

June 07, 2004

Logging Classes Loaded by the JVM

Good ol' Debbie has just published an interesting TechNote entitled "Determining which class files are loaded by ColdFusion MX" which explains how to get ColdFusion (actually, Java) to log all the classes loaded by the JVM. This can be handy for resolving classpath conflicts, and for some types of optimization. Be warned, however, that the log file will get very big, very quickly, and that this should not be used in a production environment due to performance degradation unless that is the only way to debug your specific issue.

Posted by cantrell at 11:09 AM. Link | Comments (0) | References

June 01, 2004

CFMX, OS X, and Java 1.4.2

Back in February, I posted some information on how to get ColdFusion to run on OS using Java 1.4.2. I made that post before realizing that, although CFMX does start up with the right version of Java, there is no way that I know of to add libraries to Java's (and therefore, ColdFusion's) classpath. Adding paths to the -cp or -classpath flags doesn't work because ColdFusion gets its classpath from the admin application. I thought that starting both CFMX and the admin application was fixing the problem until Sean Corfield pointed out that starting the admin application with CFMX forced CFMX to use Java 1.3 rather than 1.4.2. Oops.

Well, now I have a complete solution. The instructions I posted back in February are still valid, but now we also have a way to add libraries, as well. Rather than using the classpath to make additional libraries available to Java, put jar files in a directory specified by the java.ext.dirs system property. With my configuration, the directory "/Library/Java/Extensions" works well. For a list of valid directories, log into the ColdFusion administrator, click on the "System Information" link at the top, and scroll down to "Java Ext Dirs". Pick a directory in that list, and copy all your third-party jar files there. If you don't like to jar up your classes, you should also be able to put your classes (in their appropriate packages) right into an extension directory, as well.

The java.ext.dirs and java.class.path system properties cannot be changed dynamically after Java has started up, so don't bother going that route (I tried it just to be sure). At this point, I think using one of the Java extension directories is your best bet. There are still advantages to using a classpath on other platforms when you can since the classpath gives you the added advantage of sequencing your jars files (so that classes appearing earlier in your classpath take precedence over classes appearing later), but if that's all I have to give up in order to be able to fully run CFMX on OS X using the latest and greatest version of Java, that's perfectly fine with me.

Posted by cantrell at 02:32 PM. Link | Comments (1) | References

May 26, 2004

Macromedia ColdFusion Forums RSSified

Roger Benningfield of Big Damn Heroes has rssified all the ColdFusion forums except, mysteriously enough, the security forum. You can get the feed URLs from his post entitled "Minimalist RSS for the Macromedia CF Forums". Be responsible, however. Roger warns, "Abuse them by pounding my server every few minutes and I'll just drop the service entirely... the feeds only update every few hours, so don't bother polling them more than that."

This is a very cool service. Thanks, Roger.

Posted by cantrell at 05:11 PM. Link | Comments (0) | References

May 20, 2004

ColdFusion MacroChat Today

I think this is likely to be the coolest MacroChat yet. At 12:00 PM Pacific (3:00 PM Eastern), Ben Forta, Tim Buntel and Dave Gruber talk ColdFusion and answer community questions. To participate, go to:

http://macromedia.breezecentral.com/r36158305/

Other MacroChats for today (Thursday):

CSS for Dreamweaver
A free presentation by Macromedia Dreamweaver Product Evangelist, Greg Rewis
Thursday, May 20, 2004
9:00 AM PT/12:00 PM ET
http://macromedia.breezecentral.com/r82016586/

Delegating Web Content Updates with Macromedia Contribute
A free presentation by Macromedia Product Manager, Lawson Hancock
Thursday, May 20, 2004
10:00 AM PT/1:00 PM ET
http://macromedia.breezecentral.com/r84286274/

Director MX 2004 New Features, Putting It All Together
A free presentation by Macromedia Product Engineer, Thomas Higgins
Thursday, May 20, 2004
3:00 PM PT/6:00 PM ET
http://macromedia.breezecentral.com/r81881694/

Customizing and Extending Dreamweaver MX 2004
A free presentation by Team Macromedia member, Danilo Celic
Thursday, May 20, 2004
4:00 PM PT/7:00 PM ET
http://macromedia.breezecentral.com/r17184370/

Posted by cantrell at 08:41 AM. Link | Comments (0) | References

May 05, 2004

New ColdFusion IDE On The Way

Gestaltech, Inc. and R337 Consulting (Matt Liotta's new company) have formed a joint venture called RichPallet, Inc. in order to build new tools for the ColdFusion market. Their first project is a new dedicated ColdFusion IDE called He3 based on the open-source editor Eclipse. A beta version is planned for release at CFUN-04 on June 26th. I look forward to taking it for a spin!

Posted by cantrell at 02:03 PM. Link | Comments (0) | References

March 23, 2004

Eclipse and ColdFusion

Who out there is using Eclipse for ColdFusion coding? Which plugins (if any) are you using, and how do you like them? The two I know of are cfeclipse by (I think) Oliver Tupman and Rob Rohan, and cfplugin by Matt Liotta. I haven't used Eclipse yet, but I think it's time I give it (and these CF plugins) a try. I'll report my findings here.

Posted by cantrell at 05:01 PM. Link | Comments (9) | References

March 18, 2004

getAuthUser needs CFLOGIN

I discovered during some DRK research that the getAuthUser and isUserInRole functions will only work if the CFLOGIN tag was encountered previously within the scope of the same request. In other words, if your CFLOGIN tag is not in your Application.cfm file, and you try to call getAuthUser or isUserInRole during the scope of a request where no CFLOGIN tag was encountered, you get an empty string and false respectively. I never noticed this before because I always have my CFLOGIN tag in my Application.cfm file, where it was clearly intended to go. Fortunately, a quick <cflogin/> tag before you call getAuthUser or isUserInRole fixes the issue by making the necessary variable scope available.

Posted by cantrell at 03:15 PM. Link | Comments (8) | References

March 17, 2004

ColdFusion Security Bulletins

For those of you who don't keep up with ColdFusion security bulletins, one was issue recently that you might want to look into, especially if you expose web services.

MPSB04-04 Security Patch available for ColdFusion MX and JRun 4.0 Web Services DoS

ColdFusion MX and JRun 4.0 Web Services may be vulnerable to a Denial-of-Service attack from maliciously constructed SOAP requests. ColdFusion Version 5 and earlier versions and JRun 3.1 and earlier versions do not support Web Services and are not vulnerable.

If you're behind in your security patches, while you're at it, you might want to install this one, as well:

MPSB04-02 Security Patch available for ColdFusion MX 6.1 form fields Denial of service

ColdFusion MX 6.1 is vulnerable to a denial of service attack if a malicious user creates a ficticious request containing a large number of form fields.

Find all the most recent Macromedia security bulletins at the Macromedia Security Zone. And if either of this bulletins were news to you, I recommend that you sign up for the Macromedia Security Notification Service.

Posted by cantrell at 10:38 AM. Link | Comments (0) | References

February 17, 2004

Running JRun and ColdFusion with Java 1.4.2 on OS X

NOTE: The solution below is neither supported nor endorsed by Macromedia. Use at your own risk!

Most of you running JRun/CF on OS X are aware of the fact that we have been stuck with Java 1.3.1 while everyone else has gotten the benefit of newer versions of Java. For reasons unknown (at least to me), editing your jvm.config file and changing java.home to point to a newer version of Java did not work. Fortunately, there is another way. CD into JRun's lib directory, and type the following command:

java -jar ./jrun.jar -start default

I have the process scripted. Below is the meat of my "start.sh" script:


#!/bin/bash

JRUN_HOME="/home/cantrell/Unix/JRun4"
LOG_HOME="${JRUN_HOME}/logs"
java -jar ${JRUN_HOME}/lib/jrun.jar -start default admin \
     1>$LOG_HOME/default-out.log 2>$LOG_HOME/default-err.log

Unfortunately I have found that I have to start the admin server along with the default server in order to affect the JVM's classpath (I need to add drivers for PostgreSQL). For some reason, using the -cp flag hasn't worked. Still looking into that.

Anyway, once again, this is not a supported configuration, and if you choose to try it, you are doing so at your own risk.

Posted by cantrell at 12:36 PM. Link | Comments (2) | References

February 11, 2004

Preserving Star Wars History with ColdFusion

originaltrilogy.com could prove to be one of the most important websites of our time, and I'm proud to say it's powered by ColdFusion. The purpose of the site, in their own words:

"George Lucas doesn't plan on releasing the original theatrical cuts of the first Star Wars trilogy on DVD -- or any other home video format for that matter. They're gone forever. The point of the petition is to try and change his mind."

ColdFusion and Star Wars: an unbeatable combination, and a noble cause.

Posted by cantrell at 12:14 AM. Link | Comments (6) | References

February 04, 2004

Hidden String Functionality

You can do more with ColdFusion strings than you might realize by using the java.lang.String methods. Most of the functionality provided by java.lang.String is already available in some form or another as ColdFusion string functions, and of course, there's a way to do just about anything you want with ColdFusion string functions, but there a few of nice java.lang.String methods which I really like being able to use in ColdFusion:

Just use them as though they were native (which I guess technically they are), like so:

<cfscript>
    str = "This is my string.";
    myCharArray = str.toCharArray();
    thisIsTrue = str.startsWith("T");
    thisIsFalse = str.endsWith("!");
    myByteArray = str.getBytes();
    fourteen = str.lastIndexOf("i");
</cfscript>

Posted by cantrell at 12:00 PM. Link | Comments (6) | References

January 26, 2004

Generating Random Numbers in ColdFusion

There was a post last week on cf-talk about random number generation with ColdFusion, and in particular, the use of the randomize() function. The ColdFusion documentation indicates that you should call randomize() before calling rand() in order to ensure highly random numbers (though the same applies to randRange()). The problems are:

  1. The randomize() function only takes in an int. The best way to generate a unique number is by calling getTickCount() which returns a long. The two functions cannot be used together.
  2. If you don't use a unique number to seed the random number generator, then your results are anything but random. Each time you call rand() or randRange() without reseeding the random number generator, you will get predictable results. In other words, the algorithm for generating random numbers is, ironically enough, predictable, so the only way to get (pseudo) random numbers is by using a unique, dynamic seed. The current time in milliseconds is a perfect choice (and is what gets used by default).

As Sam Neff pointed out on cf-talk, it seems better not to call randomize() in order to allow the ColdFusion server to seed the random number generator with the current time in milliseconds -- a long value that cannot otherwise be passed in -- and I tend to agree. The problem with this, however, is synchronization since two requests made at the exact same time will cause the same "random" number to be generated. Fortunately, there's a good solution.

Sam also suggested creating an instance of java.util.Random, storing it in the application scope, and using it to generate your random numbers. It automatically gets seeded with the current time in milliseconds, and will keep returning highly random numbers each time you call it. If you create a new instance of it on each request, you will get fairly random numbers since it will get re-seeded with the current time in milliseconds, however by storing it in your application scope, you can seed it once, then get highly random numbers by calling one of its next methods to get the next pseudorandom, uniformly distributed value from its internal sequence. This sounds like a pretty good solution to me. It also eliminates the possibility of creating two random number generators at the exact same time. If two random number generators using the current time in milliseconds as seeds are instantiated simultaneous, the "random" numbers they generate will be identical. Oops.

In order to make the solution described above a little easier, I threw together a Randomize component which does the following:

  1. Creates a single instance of java.util.Random at the time it's instantiated and continues to use it for generating additional random numbers. By putting the Random component in some persistent scope, you can ensure that the same instance of Random is being used, and hence your numbers will be highly random.
  2. Allows you to seed the random number generator, and happily accepts ints or longs, which means you can pass in the result of calling getTickCount(). (Just don't try to pass in a decimal of any kind -- it won't like that.)
  3. Allows you to easily set bounds for your random numbers using the setBounds() and setMax() functions. These can be changed without having to create a new instance of the Randomize component.
  4. Provides a nextBoolean() function for getting back random booleans.

If none of this made much sense to you, the bottom line is that if you need to generate a lot of highly random numbers, create an instance of this component, store it in a persistent scope, and call next() on it whenever you need a random number.

The code is here:


<cfcomponent output="no">

    <cfset my = structNew()/>
    <cfset my.rnd = createObject("java", "java.util.Random").init()/>
    <cfset my.min = 0/>
    <cfset my.max = 0/>
    <cfset my.cnt = 0/>

    <!-- Set the minimum and maximum. --->
    <cffunction name="setBounds" access="public" returnType="void" output="no">
        <cfargument name="min" type="numeric" required="true"/>
        <cfargument name="max" type="numeric" required="true"/>
        <cfset my.min = arguments.min/>
        <cfset my.max = arguments.max/>
    </cffunction>

    <!--- Set the maximum.  The minimum is automatically 0. --->
    <cffunction name="setMax" access="public" returnType="void" output="no">
        <cfargument name="max" type="numeric" required="true"/>
        <cfset my.max = arguments.max/>
    </cffunction>

    <!--- Sets the seed.  Accepts ints and longs (but no decimals). --->
    <cffunction name="setSeed" access="public" returnType="void" output="no">
        <cfargument name="seed" type="string" required="true"/>
        <cfset var l = createObject("java", "java.lang.Long").init(arguments.seed)/>
        <cfset my.rnd.setSeed(l.longValue())/>
    </cffunction>

    <!--- Returns the next highly random number. --->
    <cffunction name="next" access="public" returnType="numeric" output="no">
        <cfif my.min + my.max eq 0>
            <cfreturn my.rnd.nextInt()/>
        <cfelse>
            <cfreturn (my.rnd.nextInt(javaCast("int",((my.max+1) - my.min))) + my.min)/>
        </cfif>
    </cffunction>

    <!--- Returns a random boolean. --->
    <cffunction name="nextBoolean" access="public" returnType="boolean" output="no">
        <cfreturn my.rnd.nextBoolean()/>
    </cffunction>

</cfcomponent>

Posted by cantrell at 11:07 AM. Link | Comments (3) | References

January 22, 2004

PATH Variable in ColdFusion

I just stumbled across the fact that the ColdFusion variable #path# refers to my system path, which I think is strange. I wonder if the purpose is to assist CFEXECUTE in finding executables. Anyone know? Any other variables like that which are not commonly known? I tried other environment variables, but #path# was the only one defined.

Update:
I should have mentioned that I'm running CFMX 6.1 on OS X with Apache. Anyone seeing this with any other configurations?

Posted by cantrell at 07:03 PM. Link | Comments (7) | References

January 16, 2004

Byte Arrays and ColdFusion (Part II)

The function below creates an empty byte array of a specified length in ColdFusion. Why is this useful? You usually need byte arrays for reading from Java InputStreams, so if you are working with Java streams in ColdFusion (trying to embed all your Java code in CFScript so as to not require a jar file installation) the function below will come in very handy:


<cffunction name="getByteArray" access="private" returnType="binary" output="no">
    <cfargument name="size" type="numeric" required="true"/>
    <cfset var emptyByteArray = 
    createObject("java", "java.io.ByteArrayOutputStream").init().toByteArray()/>
    <cfset var byteClass = emptyByteArray.getClass().getComponentType()/>
    <cfset var byteArray = 
    createObject("java","java.lang.reflect.Array").newInstance(byteClass, arguments.size)/>
    <cfreturn byteArray/>
</cffunction>

Posted by cantrell at 12:14 PM. Link | Comments (16) | References

January 15, 2004

Byte Arrays and ColdFusion

I'm looking for ways to dynamically create byte arrays of indeterminate length in ColdFusion. I have tried this:


sb = createObject("java", "java.lang.StringBuffer");
sb.init(someLength);
byteArray = sb.toString().getBytes();

// and this:

baos = createObject("java", "java.io.ByteArrayOutputStream");
baos.init(someLength);
byteArray = boas.toByteArray();

... but both return byte arrays of 0 length rather than someLength. The only technique I have found that works is this:


function getByteArray(someLength)
{
    sb = createObject("java", "java.lang.StringBuffer");
    for (i = 0; i lt someLength; i = i + 1)
    {
        sb.append("_");
    }
    return sb.toString().getBytes();
}

This works, but as you might expect, it's not the most efficient technique. Any other ideas?

Posted by cantrell at 12:03 AM. Link | Comments (4) | References

January 07, 2004

ColdFusion and Types

I saw an interesting thread on CFCDev about overloading, which lead to a few posts on types in ColdFusion, which lead to this post, which lead to the new survey off to the right. Basically, I'm curious about what people think about types in ColdFusion. Should ColdFusion be a more strongly typed language? Should typing be optional? What do you think the advantages would be? How far should it go (in other words, should there be a predefined set of types, or should developers be able to define their own types).

This is a tricky topic, and I'm not sure where I stand on it. I clearly see the advantages of ColdFusion being a loosely typed language, and I appreciate the flexibility and simplicity it allows. On the other hand, there are a lot of advantages to more strongly typed languages, mostly relating to compile type optimizations and validation (anyone who has gone from ActionScript 1 to ActionScript 2 knows what I'm talking about).

So what are your thoughts? Post here and take the survey!

Posted by cantrell at 12:04 PM. Link | Comments (11) | References

November 13, 2003

ColdFusion vs Flash (Part III)

I haven't had time to focus on this for the last few days because I've been working on MAXBloggers.com, and on finishing up the ColdFusion portion of the Community Resource Directory application. The CF side is completely done now, which includes both the CF server-side code (the web services and everything "below" the web services), and the client-side code (that which interacts with the web services, and everything "above" it).

The architecture is such that the ColdFusion front-end can be installed on another server, and still work seamlessly with the rest of the application through web services. I wrote it that way because I wanted to be able to install the front-end of the application on multiple servers throughout the company, not so much for performance reasons (although this architecture does allow for a form of scalability), but for convenience.

While I was developing the CF front-end of the application, I was very impressed by how well it performed considering the fact that it was using web services and several layers of components. In fact, there was no perceptible delay beyond what you would expect from any web application (time to make the request, render the results in the browser, etc). Once I installed it on an internal production server, however, and imported over 200 records from an Excel spreadsheet, I started getting the type of performance I had been expecting. The reason it was so fast during development is that I was only sending a few test records over the wire at any given time.

How slow is slow? Well, using only components to retrieve a query object with 206 rows takes between 61 and 110 milliseconds (pretty darn fast, I think). Retrieving an identical query object through web services takes anywhere from 877 milliseconds to 1400 (pretty darn not fast, I would say). Considering that using web services can be up to about 20 times slower, one might jump to the conclusion that this was not the smartest way to design my application. Allow me to explain.

Web services are amazingly convenient and useful. One of the reason they are so convenient and useful is that they work across so many different technologies. The reason they work across so many different technologies is because they are so abstract, and typically with abstraction comes overhead. One could say, therefore, that with convenience often comes overhead. To a certain extent, that's ok. For instance, people don't write web applications in C or assembly because although they might execute faster on the server, they would take too long to develop and maintain. Developers are generally willing to give up speed for convenience in most circumstance, at least up to a certain threshold, and although using web services for the application makes it around 20 times slower than if I were just using local components, it's worth the convenience of my application being more easily distributed.

The absolute best way to write an application like this would be to make it configurable enough that you could have it use either web services or local components. I should have thought of that from the beginning. Oops. Oh, well. It won't be hard to re-factor. Before I do that, though, the next step is to write the Flash front-end and compare developing the front end with CFML, HTML, JavaScript and CSS to building it in Flash. My Flash skills are a little rusty, so there will be a little learning curve, but I should have something to report back soon after MAX.

Posted by cantrell at 03:43 PM. Link | Comments (8) | References

October 31, 2003

ColdFusion vs Flash (Part II)

(For background on this project, see yesterday's post.)

The application I'm experimenting with is called Community Resource Directory (CRD). It's a simple application which other community managers and myself will use to keep track of various online community resources such as weblogs, mailing lists, forums, news groups, etc. Resources will have one or more categories (relating to the particular technology they address) and one medium (mailing list, forum, weblog, etc.). The application will support all the operations you would expect: adding, updating and deleting resources, categories and mediums.

I'm well on my way to having the HTML version of this application functional. As of this moment, I can add, update and delete categories. So far, I'm very happy with the way the architecture is turning out. It's much more complex than if I had just decided to hack together a quick ColdFusion/HTML version of the application, but even though the application is not particularly extensive, I am treating it as though it could grow into something much larger. In my opinion, the key to a successful and effective architecture is that it should never grow in complexity (beyond an initial level of complexity) no matter what type of functionality you add to your application and how big it gets. The application should scale in size, not in complexity. In other words, it's ok if the application seems a little complicated at 5 pages as long as it is no more complicated at 500.

I have designed the ColdFusion/HTML version of the application to use web services, and much to my delight, although I am invoking as many as 4 remote functions during the course of a single request, the application is still very fast. Of course, the web services happen to be located on the computer the client is running on, so this isn't a fair test yet, but I'm glad to see that using web services is not noticeably slower than invoking the components they wrap directly.

One thing I am being very careful not ever do is put any remote function invocations in loops. For instance, if I want to delete ten categories, the wrong way to accomplish this would be to call the remote deleteCategory function ten times in a loop. Instead, I build an array of category IDs that are meant to be deleted, and send that over the wire instead. This is much more efficient, and should have a dramatic impact on how well the application performs.

Posted by cantrell at 03:58 PM. Link | Comments (1) | References

October 30, 2003

ColdFusion MX 6.1 Verses Flash MX 2004

I'm working on a relatively simple application that I have decided I am going to build both a ColdFusion/HTML and a Flash interface for. Neither interface will provide any more or less functionality than the other, and both will be written on top of the same components, but I think it will be an interesting experience. I will document the pros and cons of both approaches as I go along.

I'm considering a slightly unique architecture for this project, as well. The Flash front-end will use web services to communicate with the server, and I'm actually considering having the ColdFusion/HTML interface communicate via the same web services. Unconventional, I know. The the obvious approach would be to have the web services that the Flash front-end uses wrap the components that the ColdFusion/HTML interface uses, but if they both use the same web service interface, that would allow me to run the ColdFusion interface on a different server than the rest of the back-end, which I think is interesting. I haven't decided yet, but I'm leaning in that direction. If nothing else, it would be an interesting experiment, and I am interested in seeing how the ColdFusion application would perform.

Posted by cantrell at 05:24 PM. Link | Comments (8) | References

October 28, 2003

Interesting Article on Community MX

How many of you visit Community MX on a regular basis? There are some good paid articles over there, but also some good free content, as well. An interesting article called "Getting Into Good Coding Habits" just went live today. Here is an excerpt:

In this article, we will look at how we can customise the default ColdFusion template that Dreamweaver generates to aid our workflow. Further aiding our local development, we will also look at how we can help ColdFusion process our templates in a more efficient manner. This will aid the processing speed and therefore improve the rendering time in the browser window which, of course, delivers a faster site to our end user.

Posted by cantrell at 02:46 PM. Link | Comments (1) | References

October 27, 2003

US Government Powered By ColdFusion

I'm sure many of you already caught this on Ben Forta's weblog, but in case you missed it, it seems that ColdFusion is, by far, the preferred technology for government websites. Second is ASP, third is PHP, and last is JSP. You can get more specific numbers on forta.com.

Posted by cantrell at 04:13 PM. Link | Comments (0) | References

October 16, 2003

ColdFusion MX 6.1 CFFORM Hot Fix

From the Macromedia TechNote Index:

Macromedia has created a hot fix to address issues with the cfform controls in Macromedia ColdFusion MX 6.1. The updated JAR file resolves the following issues with the cfform applets:

  1. Required fields in cfform / cfinput are not processed in the order they are defined within the form.
  2. When more than one image is specified for cftreeitem, the first specified image is displayed for all levels.
  3. Using cftree and cftreeitem throws Java ClassCastException error.

Posted by cantrell at 04:00 PM. Link | Comments (1) | References

October 09, 2003

Where Do You Put Your Components?

The Macromedia Web Technology Group, in their most recent ColdFusion MX Coding Guidelines, recommends that you put components which are to be accessed directly either through Flash Remoting or web services in {cfmxroot}/wwwroot/{applicationname}/ and any other components should be stored under {cfmxroot}/extensions/components/{applicationname}/. I sometimes do something similar, although I generally use {cfmxroot}/com/macromedia/apps/{applicationname}/ instead. This works well for applications that you write, install and configure yourself, however I found that when I wanted to distribute an application, I preferred having all the application's files in a single directory. Therefore, I have started putting all application-specific components -- whether or not they are accessed directly through the browser, Flash Remoting or web services -- in {cfmxroot}/wwwroot/{applicationname}/components/{subdirectory}. At first, this may not appear to be the most elegant relationship, however I like the idea of having people unzip a single directory in their web root, set up a data source, tweak a few configuration parameters in the Application.cfm file or an external XML file, and be up and running. Now there's really no reason you can't do the same thing with your components outside your application directory, however I have found both packaging and unpacking to be more straightforward when everything is contained in a single directory.

So my current thinking is that I try to consider the type of application that I am writing and what it is intended for before deciding where to place my components. Where do you put yours?

Also, one circumstance that the WTG coding guidelines does not address is the location of generic, reusable components. For instance, I have a calc.cfc which performs certain mathematical functions in {cfmxroot}/wwwroot/com/macromedia/util, which has worked out well.

Posted by cantrell at 04:02 PM. Link | Comments (24) | References

October 08, 2003

Ben Forta Holds Forth on ASP.NET and ColdFusion

Macromedia recently published an article by Ben Forta entitled Life After ASP. The basic premise is that ASP developers are going to have to think about migrating pretty soon since ASP is n