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 9: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: [code] [/code] 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 5: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 5: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 | References

February 9, 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 7, 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 3: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 7, 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 1: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 3: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 3: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 1: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 | 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 4: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 1:28 PM. Link | 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 8, 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 1: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 | References

June 8, 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 2:49 PM. Link | Comments (10) | References

June 7, 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 | References

June 1, 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 2: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 5:11 PM. Link | 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 8:41 AM. Link | References

May 5, 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 2:03 PM. Link | 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 5: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 3: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 | 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 4, 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 7: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 7, 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 3: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 3: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 5: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 2: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 4:13 PM. Link | 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 4:00 PM. Link | Comments (1) | References

October 9, 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 4:02 PM. Link | Comments (24) | References

October 8, 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 no longer being developed and Microsoft is obviously trying to get developers to start adopting ASP.NET. Ben points out, however, that going from ASP to ASP.NET may not be as easy as it sounds. And if you are already going to make a significant investment in what is essentially a new technology, why not take a look at other options like ColdFusion MX 6.1 for the reasons that all of us already know:

Ben says it much more eloquently than I just did, so go have a look, and make sure you forward it to any friends you have who are using ASP.

Posted by cantrell at 6:10 PM. Link | Comments (2) | References

October 6, 2003

Does This ColdFusion Tag Make Sense?

I had a debate the other day over whether this tag makes sense or not. I say it doesn't, but the ColdFusion server says otherwise. What do you think, and why?

<cfargument name="foo" required="true" default="bar"/>

Posted by cantrell at 6:27 PM. Link | Comments (8) | References

October 3, 2003

New Whitepaper Available on ColdFusion Security

There's a new whitepaper available on the ColdFusion Data Sheet and White Paper section of Macromedia's website entitle "Building Secure Internet Applications with ColdFusion MX 6.1". The description reads:

"This whitepaper examines some of the security risks associated with Internet applications and describes how ColdFusion MX 6.1 provides powerful, yet easy to implement features that address them."

Posted by cantrell at 5:02 PM. Link | Comments (2) | References

October 1, 2003

CFFORM - An Informal Poll

Yesterday I wrote about server-side validation and error handling versus client-side validation using JavaScript. I got some awesome comments, many of which contained some pretty valuable insight. Now on to a related topic: CFFORM.

From what I've been able to gather, you either love CFFORM or hate it. If you love it, you love it because it saves you time, and because you might not know JavaScript very well and would rather build applications and make money than take the time to learn a new language. If you hate it, you probably know JavaScript pretty well, and prefer your own way doing validation. What are your thoughts on CFFORM? If you like it, what do you like about it? If you don't like it, is it the implementation or the concept? In other words, if it were completely re-factored, would you consider using it, or will you always prefer to use your own code?

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

September 30, 2003

Validation - Client or Server-side?

I used to be pretty fanatical about implementing both client and server-side validation, however recently, I have stopped bothering with client side error messages almost entirely. The conventional wisdom is that client-side validation is necessary because it:

  1. Gives your users instant feedback.
  2. Saves CPU cycles.
  3. Lowers bandwidth use.

While all of these things are true, it is also true that:

  1. Client-side validation adds coding and QA time to the development process.
  2. Large amounts of JavaScript (which are often required for validation frameworks) also use bandwidth.
  3. Thanks to CSS-P, pages can be small enough that reloading them doesn't have to take as long as loading Amazon.com.
  4. You have to do server-side validation in addition to client-side validation anyway since client-side validation can always be bypassed.
  5. JavaScript alerts can be alloying and less intuitive than well positioned, verbose server-side error messages.

In my experience, the amount of additional CPU cycles and bandwidth required to process requests with data that does not validate is really quite negligible (if it weren't, I would say your app is not as user-friendly and intuitive as it should be). Additionally, I would personally rather reload a page and get clear instructions on exactly which fields need attention rather than instantly get something less helpful. DHTML solutions (which I have not experimented with extensively) may be a good compromise, but I think you would need to come up with a very solid framework to make the additional development costs such that they are practical since data must still also be validated on the server.

What are your thoughts on validation?

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

September 29, 2003

Simplifying Component Inheritance

When you want one component to extend another, if the parent component is in the same package (directory) as the child component, you don't have to specify a fully-qualified name. For instance, if both components were in the directory "/myApp/components/handlers" rather than doing this...

<cfcomponent name="myComponent" extends="myApp.components.somePackage.Parent">

...you can do this...

<cfcomponent name="myComponent" extends="Parent">

This is particularly useful when you want your component path to be dynamic or configurable since if you hard-code the entire path, and you want to move your components or your entire application to a different directly, all your component inheritance would be broken.

Posted by cantrell at 1:17 PM. Link | Comments (2) | References

September 25, 2003

Multiple Threads in ColdFusion

I have gotten a lot of great feedback and suggestions from yesterday's post about new ColdFusion features. One that really interests me is the idea of a CFFORK or a CFTHREAD tag. I agree that certain operations would benefit from the ability to happen concurrently (in fact, keep your eye out for DRK 5!), but I'm wondering what specifically people envision spawning new threads for. And what would the programming model be? When you spawn a new thread, execution obviously continues in the original thread, so how do you know when the new thread is finished, or get back the results of whatever operation it performed, or know if an error occurred. One way to do it is with callback functions, which may be something that can be built into components. I have an interesting idea of how this can be done (again, keep an eye out for DRK 5), but I want to get some other suggestions, as well.

Posted by cantrell at 1:40 PM. Link | References

September 24, 2003

What's Your Dream ColdFusion Feature?

Let's say the entire ColdFusion engineering team were at your disposal for the purposes of adding any single feature you wanted. What would it be? Don't just think in terms of tags or functions, either. Think big. It can essentially be any change you want to the language or server. The person who comes up with the coolest, most interesting and innovative new feature request will win tons of respect from everyone who reads this weblog, guaranteed.

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

September 18, 2003

Builder.com Reviews ColdFusion MX 6.1

Builder.com has an extremely positive review of ColdFusion MX 6.1 entitled "Take another leap forward with ColdFusion MX 6.1". The article discusses installation, J2EE deployment, expanded OS support, performance, CFCs, CFMAIL, CFHTTP, and even mentions the Mach-II framework. If you are already using CFMX 6.1 and you are aware of the differences between it and CFMX, you may not get much out of the article, however if you haven't upgraded yet, or still aren't sure of everything CFMX 6.1 can do, you might find it useful.

Posted by cantrell at 1:37 PM. Link | Comments (13) | References

September 15, 2003

Tabs or Spaces?

Which do you use when coding, and why? I've always considered spaces to be "correct", but I can't really say why. Tabs certainly seem simpler: one character rather than four, even if you have your IDE configured to insert spaces for tabs. File size is another issue. Files are obviously smaller when you use tabs rather than spaces. In fact, I found they are significantly smaller. I took a ColdFusion page of what I consider to be average size (10,038 bytes), and when I replaced every occurrence of four consecutive spaces with a single tab, the file was only 6,855 bytes (it still had some unnecessary spaces in it, too, so I could probably have even gotten rid of another 100 bytes if I wanted to screw around with some regular expressions). But why does file size really matter? Although it could have a minuscule affect on the amount of time it takes to compile a CFML page, it wouldn't affect runtime speed. Perhaps having smaller files would help your IDE to perform better, or at the very least, use less RAM. And reducing the size of source files by 1/3 might also make checking large amounts of code out from a remote CVS server much faster. What are your thoughts on the matter?

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

September 9, 2003

Binary Deployment of ColdFusion Applications

I saw some talk on the BACFUG list today about binary deployment of ColdFusion applications. I know this has been discussed at length in the past, but I would like to get some fresh feedback about what people are looking for. Specifically:

  1. Are you just looking for a convenient way to deploy your ColdFusion applications?
  2. Are you looking for a secure way to distribute your applications (which implies encryption or obfuscation in addition to compilation)?
  3. Would it be enough to just deploy Java byte code, even though Java byte code can easily be decompiled (in other words, is it just the CFML that you want to protect, or the CFML and the Java source code)?
  4. In what circumstances would you find this feature useful, and do you think your clients would go for it?

Thanks for the input!

Posted by cantrell at 1:27 PM. Link | Comments (14) | References

September 8, 2003

Leveraging Java in Your ColdFusion Applications

There are four basic ways to use Java with ColdFusion:

  1. CFX tags
  2. JSP tags
  3. Using CFOBJECT or createObject() to accesses custom classes in your classpath
  4. Direct embedding (usually using CFScript)

CFX tags have a very straightforward interface. You simply implement a function called processRequest contained in the interface com.allaire.cfx.CustomTag, and work with the Request and Response objects that get passed in. CFX tags are the easiest way to implement ColdFusion tags in Java. The JSP custom tag interface is much more complex and flexible, allowing you to respond to very specific tag parsing events, nest tags, and work with body content. Using the CFOBJECT tag or createObject function is as easy or difficult or as the APIs you are accessing, while the simplest way to work with Java in ColdFusion is probably to embed it directly, typically using CFScript.

How often do you find yourself using Java in your ColdFusion applications? What do you typically use it for, or what have you used it for in the past? Finally, which of the techniques above do you typically use, and why?

Posted by cantrell at 11:22 AM. Link | Comments (13) | References

September 2, 2003

Using expandPath with Virtual Directories and IIS

Thanks to Nathan Strutz for submitting his findings on using expandPath with virtual directories:

Nathan found that the following code...

expandPath("../myDirectory/mySharedDirectory/")

...will return...

c:\inetpub\wwwroot\myDirectory\mySharedDirectory\

However, if he adds a slash to the beginning, like this...

expandPath("/../myDirectory/mySharedDirectory/")

...he gets...

\\sharedComputer\ShareName\shareLocation\mySharedDirectory\

Anyone care to confirm or deny this behavior? (I'm running on OS X right now, so I can't.)

If you have tips or tricks that you would like to blog vicariously through me (you get the credit, of course), send them to cantrell@macromedia.com. Don't worry about including a self-addressed stamped envelope.

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

August 27, 2003

Dreamweaver MX 2004 for ColdFusion Developers

I've seen some comments out there about Dreamweaver MX 2004 not offering ColdFusion developers any new features. It's true that a great deal of emphasis for this release was placed on CSS support and designer tools, but aren't these features just as important to ColdFusion developers as they are to anyone else? Anyone who uses ColdFusion should be looking very seriously at CSS, if not already using it full time. As far as I'm concerned, features that are good for web development in general are good for ColdFusion developers.

There are several other features that I think are huge wins for ColdFusion developers. Although I haven't had time to really familiarize myself with Dreamweaver MX 2004 yet, as I read through the list of new features, the following really caught my attention:

And finally, if you try Dreamweaver MX 2004 and still think it just isn't for you, it comes with a new version of Homesite+!

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

August 26, 2003

Application Configuration: How Do You Do It?

There are lots of ways you can configuration an application. You can define server, application, or request variables in your Application.cfm file; you can load an external XML file; you can use an INI, or initialization, style file; you can store you application's configuration parameters in a database (although often, configuration data contains data source information, so that's a bit like locking your keys in your car). You can even try to dynamically determine your configuration based on your environment.

I find myself using a little of everything. Primarily, I use the init custom tag from DRK 3 and put configuration in my Application.cfm file. I actually like using code to express my application's configuration as opposed to text formats like INI or XML because code is more flexible and often less verbose. If it gets out of control and I want to externalize huge lists of things like products or countries or something, I will use an XML file or store them in a database table, depending on how dynamic I need them to be, and whether I have time to build an interface for editing the information in the database, which I usually don't.

What techniques to you use in different circumstances, and why?

Posted by cantrell at 12:42 PM. Link | Comments (7) | References

August 22, 2003

Customer Research: How Do You Use CFHTTP?

I'd like to find out the primary ways in which ColdFusion customers use the CFHTTP tag. Specifically, I'm interested in the following:

  1. How often do you use it?
  2. What types of things do you use it for?
  3. Do you primarily use it for GET or POST operations?
  4. Do you use its more advanced capabilities like proxy and query support?

Please posts responses here, or send them to me directly at cantrell@macromedia.com. Thanks for your time!

Posted by cantrell at 1:23 PM. Link | Comments (13) | References

August 21, 2003

Debate: The Best Way to Invoke Custom Tags

How do you invoke custom tags? Do you use the CF_MYTAG approach, or do you use CFIMPORT? I started out using the CF_ technique, but now I find I prefer to use CFIMPORT for the following reasons:

  1. I like the flexibility it gives me in terms of where I can put my custom tags (without having to create mappings).
  2. I like the ability to create "packages" or groups of related tags, which allows me to reuse tag names.

The Jimg project from DRK 4 comes with a set of custom tags for image manipulation: border, crop, draw, fill, height, load, pattern, rotate, save, scale, scaleToAtLeast, sequence, size, text, tint and width. I certainly wouldn't want to copy all those tags in my CustomTag directory and take the chance of overwriting existing custom tags. Rather, I copy create a directory called "jimg" in my /cf_tags directory, and import them like this:

<cfimport taglib="/cf_tags/jimg" prefix="img"/>

Then, I can use the tags like this:

<img:sequence>
    <img:load .../>
    <img:scale .../>
    <img:save .../>
</img:sequence>

What's your preference, and why?

Posted by cantrell at 10:34 AM. Link | Comments (17) | References

August 20, 2003

Separating Sessions From Cookies

Cookies are a great way to pass around session identifies (CFID, CFTOKEN, and jsession values), especially when they are managed seamlessly by the server, saving developers a great deal of time and hassle. So if the process works so well and makes developers' lives so much easier, why would anyone choose to manually encode session identifiers into all URLs and form action values? There are two reasons:

  1. People who have cookies disabled can still use your application just like people with cookies enabled.
  2. Users can use multiple browser instances to log into multiple application accounts simultaneously.

#1 is pretty straightforward, but #2 requires some additional explanation.

If you use cookies to automatically manage sessions, when a user opens a new browser instance and goes to your application, all the domain's cookies get sent, and you automatically join the same session that is active in the other browser instance (unless you use an entirely different browser as opposed to just a second instance of the same browser). If you have setClientCookies set to "no" in your Application.cfm file, however, and you use the urlSessionFormat function to encode the session identifier into links and form action values, when a user goes to your application in a different browser instance, they will receive an entirely new session, and can easily maintain both session simultaneously.

If you decide to go this route, I would actually recommend not using urlSessionFormat, at least not directly. A better solution is to write you own version, and use your UDF everywhere instead. That way, just by changing one function, you can add or remove arbitrary parameters that get passed around your entire application. For instance, maybe you have a concept of a role or an affiliate, or something that you decide you want every page in your application to be aware of outside of the context of users' sessions.

This may seem like a lot of trouble just to allow the occasional user the luxury of maintaining two sessions at the same time, but it's actually a nice hook to have and can sometime get you out of corners you have inadvertently backed yourself into.

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

August 19, 2003

eWEEK Reviews ColdFusion MX 6.1

Yesterday, eWEEK published a review ColdFusion MX 6.1. Some highlights:

... although the server and the development engine moved to Java, site developers were still able to take advantage of ColdFusion's excellent CFML (ColdFusion Markup Language), which remains the easiest-to-use Web scripting language that eWEEK Labs has seen.

In eWEEK Labs' tests, Version 6.1 outperformed the previous version at all load levels.

These prices are higher than those of previous versions, but they are very low when compared with most enterprise application servers...

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

August 18, 2003

Using ColdFusion with Java 1.4.1 on OS X

JRun and ColdFusion MX 6.1 work just fine with JRun on OS X using Java 1.3.1, which is good, since, as far as I can tell, there's no way to get it to work with the newest installation of Java, which is Java 1.4.1 (if you know of a way, please let me know). If you are not intermingling Java and ColdFusion too much, it's a great setup, but what do you do when you need the combination of ColdFusion MX 6.1 and Java 1.4.1 and OS X? According to Sean Corfield, the answer is Jakarta Tomcat. I installed Tomcat this morning, and so far, so good. If you need access to 1.4.1 and you are working with ColdFusion MX 6.1 on OS X, Tomcat currently appears to be your best option. Macromedia even provides a set of ColdFusion installation instructions for Tomcat.

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

August 15, 2003

Tags vs. CFScript

Now that you can write functions in both tag form and as CFScript, which way are people leaning and why? I like that tags allow a level of validation in terms of data types and requirements, however I must admit that I prefer the more streamlined syntax of CFScript. What are your thoughts? Should the same advantages that one gets from writing UDFs as tags be added to CFScript? Should CFScript become ECMAScript? Server-side ActionScript? Java? What?

Posted by cantrell at 12:42 PM. Link | Comments (18) | References

August 14, 2003

Macromedia Releases ColdFusion MX 6.1 Performance Briefs

Check out the new performance briefs Macromedia recently released comparing CFMX 6.1 to previous versions of ColdFusion on various platforms. Some quick numbers:

Posted by cantrell at 12:57 PM. Link | Comments (7) | References

August 13, 2003

Using CFHTTP to Build a Query

Sorry I have been lazy about posts recently. I've been in Boston, meeting with various product teams. All I can say is that there is some cool stuff on the horizon.

Anyway, did you know that CFHTTP can automatically turn a comma-delimited file into a query object for you? Let's say you have a file called data.txt that looks like this:

firstName, lastName, emailAddress
Christian, Cantrell, cantrell@macromedia.com
Mike, Chambers, mesh@macromedia.com
Baby, Blue, bluebaby@macromedia.com

The following use of CFHTTP will parse the data above into a query stored in the variable "myQuery":

<cfhttp method="GET" url="http://localhost/tests/cfhttp/data.txt" name="myQuery">

You can use the columns attribute of the CFHTTP tag to specify a different set of column headers, and you can use the firstrowasheaders attribute to include the first row as data rather than column headers. And, of course, your comma-delimited file doesn't have to be static; the delimited values can be dynamically generated by any means.

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

August 7, 2003

Improved Email Functionality in CFMX 6.1

In case you haven't heard, one of the coolest new features of Macromedia ColdFusion MX 6.1 is the new email functionality. First and foremost, performance has been greatly improved through the use of multithreading and connection pooling. Using multiple threads to send email means that ColdFusion can send multiple messages simultaneously rather than one at a time, and connection pooling means that ColdFusion will reuse connections between it and the mail server rather than making new connections each time it wants to send an email. Creating connections is a relatively time consuming process, so the more you can reuse existing connections, the more efficient the server is being. These two improvements mean that ColdFusion MX 6.1 is capable of sending more than 1,000,000 emails an hour!

I don't need to send 1,000,000 emails an hour, so although I'm glad I have that capability should I ever need it, I'm actually more excited about support for multipart mail messages and the new CFMAILPART tag. There are typically two types of email that people send: text and HTML. If you don't know what kind of email client your recipients are using, or whether they prefer text or HTML email, it used to be that you pretty much had to stick with text emails just to be on the safe side. That meant that even though most people use email clients which are fine with HTML email, and although ColdFusion supported the sending of HTML email, you would generally have to cater to the lowest common denominator and send everyone text email. Now, thanks to the CFMAILPART tag, you don't have to compromise anymore. When you send a multipart email message, you are actually sending both a text and an HTML version which means it is up to the email client to determine which part of the email message to display to the user. That means you can send one email out to your whole user base, and make sure everyone gets the best experience their email client is configured to deliver.

So now that CFMX 6.1 can send multipart email messages, what about being able to parse multipart email messages, as well? CFPOP now supports the ability to separately retrieve either the HTML or the text portions of a multipart email message through the new textBody and htmlBody properties. The body property is still there, so existing code won't break, but now you clearly have more options.

Another important addition to the CFMAIL tag is the ability to specify a username and password for authenticating against password protected mail servers. More and more SMTP servers are being secured in order to prevent unauthorized relaying of email messages by spammers. Now, ColdFusion gives you a way to interact with secured mail servers.

To learn more about the improved email functionality of CFMX 6.1, check out Ben Forta's new Breeze Presentation. To learn more about ColdFusion MX 6.1 in general, check out the CFMX 6.1 release notes.

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

August 6, 2003

Another Way to Continue in ColdFusion

Last Friday, I made a post about ColdFusion lacking a CFCONTINUE tag and showed a couple of ways to get around it. Thanks to erki for pointing out yet another method:

<cfloop from="1" to="10" index="i">
    <cftry>
        <cfif i eq 5>
            <cfthrow type="continue">
        </cfif>
        This number will never be 5: #i#<br>
        <cfcatch type="continue"><!--- ignore ---></cfcatch>
    </cftry>
</cfloop>

Posted by cantrell at 2:32 PM. Link | Comments (3) | References

August 5, 2003

Installing ColdFusion MX 6.1 on OS X

I have seen a few people experience difficulties installing ColdFusion MX 6.1 on OS X. Not to worry -- it works fine. You just have to make a few adjustments.

The problem people seem to be running into is with the graphical installer. There seems to be an issue with the graphical installer and Sun's 1.4.1 JVM for OS X. There are two ways to fix this:

  1. Run the installer in console mode like this:

    % java -jar ./coldfusion-61-other.jar -i console

    (Don't actually type the "%" -- that is meant to represent your command prompt.)

    This is not as scary as it might sound. The console installer is just as user friendly as the graphical version, except for the fact that you have to type paths in rather than navigate to them.

  2. Run the graphical installer with Java 1.3.1 rather than 1.4.1. This is perfectly safe and doable on most configurations since the OS X software updater does not remove the old version of Java when installing the new version (rather, it installs the new JVM right along side the old one and simply changes some symbolic links).

    Here is the command for running the graphical installer with Java 1.3.1:

    /System/Library/Frameworks/JavaVM.framework/Versions/1.3.1/Home/bin/java -jar ./coldfusion-61-other.jar -i gui

    The command above may have broken onto two lines in your browser -- make sure you run it as a single line.

Posted by cantrell at 3:06 PM. Link | Comments (20) | References

Red Sky is Live!

The wait is over, and all information is now public. Macromedia released Red Sky, or Macromedia ColdFusion MX 6.1, early this morning. ColdFusion MX 6.1 is a free upgrade for existing ColdFusion MX customers and delivers significant performance enhancements, improved stability, and some extremely cool new features. Check out the ColdFusion MX 6.1 Product Page, the CFMX 6.1 FAQ, and the all-important CFMX 6.1 Release Notes to find out more.

Here are a few of my favorite things about ColdFusion MX 6.1:

I could go on and on, but I'll leave a few things for you to discover for yourself. If you are a Dreamweaver user, don't forget the CFMX 6.1 tag updater.

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

August 4, 2003

Living Without "continue" in ColdFusion

A decided to try to implement a custom ColdFusion loop tag that would support a custom CFCONTINUE tag. To continue within a loop is similar to breaking (which you can do with CFBREAK) except rather than breaking out of the loop, execution starts again from the top of the loop on the next iteration. Unfortunately, there is no CFCONTINUE tag, so this is something you cannot do in ColdFusion. The following illustrates the use of "continue" in Java:

for (int i = 0; i < 10; ++i) {
	if (i == 5) {
		continue;
	}
	System.out.println("This number will never be 5: " + i);
}

Anyway, it hasn't occurred to me how to implement continue functionality in 100% ColdFusion (without using a JSP custom tag), however there is usually an easy way to get around CF's lack of "continue". Here is the loop above rewritten without continuing:

for (int i = 0; i < 10; ++i) {
	if (i != 5) {
		System.out.println("This number will never be 5: " + i);
	}
}

And, of course, the ColdFusion version:

<cfloop from="1" to="10" index="i">
    <cfif i ne 5>
        This number is not 5: #i#<br>
    </cfif>
</cfloop>

Here's another interesting approach:

<cfset i = 1/>
<cfloop condition="#i# le 10">
    <cfif i eq 5>
        <cfset i = i + 1/>
    </cfif>
    This number is not 5: #i#<br>
    <cfset i = i + 1/>
</cfloop>

A CFCONTINUE would still be a nice tag to have, but I have yet to run into a situation where I couldn't pretty easily work around its absence.

Posted by cantrell at 1:26 PM. Link | Comments (6) | References

July 31, 2003

Using ColdFusion Server Variables

Most of you probably know that you can get a lot of information about your server environment from the implicit "server" variable scope, however what is not so obvious is why this information is useful. First of all, here is everything you can find out, and their values on my weblog server:

server.coldfusion.appserver #server.coldfusion.appserver#
server.coldfusion.expiration #server.coldfusion.expiration#
server.coldfusion.productlevel #server.coldfusion.productlevel#
server.coldfusion.productname #server.coldfusion.productname#
server.coldfusion.productversion #server.coldfusion.productversion#
server.coldfusion.rootdir (not available)
server.coldfusion.serialnumber (not available)
server.coldfusion.supportedlocales #server.coldfusion.supportedlocales#
server.os.additionalinformation #server.os.additionalinformation#
server.os.arch #server.os.arch#
server.os.buildnumber #server.os.buildnumber#
server.os.name #server.os.name#
server.os.version #server.os.version#

Server variables are most often useful when your code needs to run in multiple environments, and you are not able to develop in a completely platform independent manner. For instance, you might need to to know what the server's path separator is so that you can reference files on the file system. One way to get this information is from the server.name.os variable, like this:

<cfset pathSep = iif(server.os.name eq "UNIX",de("/"),de("\"))/>

You can also use the server.os.additionalinformation and server.os.version variables to determine if certain ColdFusion functionality (like Verity searches) are supported, or the server.coldfusion.productversion variable to make sure the user has installed your application with the right version of ColdFusion. If you are writing an application that you intend to distribute, and that can potentially be run on any platform that supports ColdFusion, a little platform validation can go a long way toward making installations more user friendly.

What other uses do people have for server variables?

Posted by cantrell at 3:04 PM. Link | Comments (5) | References

July 29, 2003

Getting a Client's IP Address With Flash Remoting

I recently found that in remote ColdFusion functions invoked by Flash Remoting, I was not able to get the client's IP address from the CGI variable CGI.REMOTE_ADDR or CGI.REMOTE_HOST, however I was able to get it in Java by using getPageContext().getRequest().getRemoteAddr(). Strange, huh? I haven't check Red Sky for the same issue yet, so it might have been resolved (I'll try that this afternoon), but for how, getPageContext() saves the day once again.

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

July 25, 2003

Follow-up on Session Variables vs. Hidden Inputs

A few people posted some very good comments to yesterday's post on session variables versus hidden inputs. I want to highlight two very import points that were made.

  1. Put data in structs, and put the structs in users' sessions. Rather than putting dozens of name/value pairs directly in users' sessions, consider putting them all in a struct, and putting the struct in the session instead. This will help you avoid inadvertently stomping on existing name/value pairs, and makes it easier to clean up should you decide to clear the struct. It's the same idea behind creating directories on your computer and organizing files logically and hierarchically rather than putting them all in a single directory where they are difficult to manage and you are likely to run into naming conflicts.
  2. CFC instances fit nicely in sessions. Even better than putting data in structs and putting structs in sessions is putting data in components and putting components in sessions. Why is it better? Think of a component as being a struct with optional logic. In addition to simple properties (essentially name/value pairs), you can add logic and functionality. For instance, I'm currently working on an application that creates a user component and puts it in all users' sessions once they have successfully authenticated. The component has get and set functions for all the properties of a user, including ID, name, encrypted password, last login date, etc. So far, a struct would have worked fine, however I also wanted a property for the user's current IP address, so inside of the getIpAddress function, I have logic to extract the user's IP address out of the request (with Flash Remoting, you want to get the user's IP address from the request because the CGI variable does not get properly populated). By using a component rather than a struct, not only am I able to add logic for functionality that I need now, but I have a good hook for extending the component's functionality in the future. For instance, I'm considering adding a toString function, or a getUserHash which would return a string that uniquely identifies a particular user.

Posted by cantrell at 11:41 AM. Link | Comments (7) | References

July 24, 2003

Session Variables vs. Hidden Inputs

I often see people asking about how to make data persist across multiple pages of forms, and the two options that inevitably come up are using session variables and using hidden form inputs. Using session variable refers to the practice of saving your form variables as session variables, then accessing them all at once from the session scope at the appropriate time. Using hidden input refers to the practice of accumulating data from previous form in hidden inputs so that it looks to your action page or component that the user just submitted one big form (which, in fact, they technically did).

There's nothing wrong with using hidden inputs, but using session variables is really the better solution. For one thing, it makes the code more versatile and gives you the flexibility to make your application less linear if you want to, or to more easily rearrange your forms. Additionally, the code is much more maintainable and easier to follow.

Some people use the argument of memory usage to suggest that hidden inputs are better since session variables are stored in your server's RAM. Unless you are running ColdFusion off an Apple Newton, RAM is not going to be an issue. Let's prove the point by doing the numbers:

Let's say that a fully filled out form is about 500 bytes of data, or to make the math a little cleaner, let's say 512 bytes, which means that for every kilobyte of RAM allocated to your JVM, you can handle two simultaneous sessions. That means to use a single megabyte of RAM, you would have to have 2048 simultaneous sessions. Admittedly, session data structures themselves (Hashtables) use RAM, so we're not just talking about the bytes of form data, but considering the fact that I have 512MB of RAM allocated to the JVM on my production server, I don't worry much about these details.

If you are concerned about RAM -- if your application use huge sessions and your servers are 10 years old with tiny amounts of memory -- just buy another stick of RAM. In the long run (and maybe even the short run), it will be much cheaper than avoiding session variables.

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

July 21, 2003

Learning to Like the Var Keyword

Coming from four years of Java programming, I was a little annoyed at first back in the Neo days when I discovered that local variable declarations using the keyword "var" had to come at the top of your functions. It seemed primitive and inconvenient. I have since come to appreciate it, however, and now I actually like it. Once your component functions get long and involved enough, it is sometimes easy to forget whether a particular variable name has already been used in a function. In most cases, it wouldn't matter if you were to inadvertently reuse a variable name, however in some cases, it could certainly cause unexpected and unintended behavior (aka bugs). When encountering the same situation in Java, I used to do a quick search within the scope of a function before declaring a new variable (although with Java, the compiler will catch errors like that for you). In ColdFusion MX, I now go the top of the function and add the variable declaration in alphabetical order, and if the variable name is already in use, I will notice right away. After quite a bit of component development, I now find that variable declaration at the top of my functions is completely natural and actually helpful.

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

July 18, 2003

ColdFusion and Graphics on Linux

Anyone out there have problems using image manipulation libraries -- or even just CFCHART, for that matter -- on a Linux server? If you aren't running an X server on your Linux box (which you most likely are not) and/or do not have the XFree86 libraries installed, you are not going to be able to use tags like CFCHART, or the upcoming Jimg package on DRK 4 which lets you use ColdFusion tags or components to manipulate images in a variety of ways. The reason is that Java uses native graphic libraries for many graphic operations, so in come cases, either X needs to be running, or a virtual X server (like the X Virtual Frame Buffer, or Xvfb).

These are not fun issues to solve. Daemonite posted about this back in April in the context of CFCHART and offers some advice, and thanks to Ben Simon, I recently found a very comprehensive resource on how to solve the issue.

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

July 7, 2003

Adding Enhanced Rounding Support to ColdFusion

Over the weekend, I ran into a situation where I needed more fine-grained rounding than ColdFusion supports. Rather than rounding to the closest whole number, I wanted to be able to round to a specific decimal place. For instance, given the number 2.345, I didn't want the number 2; I wanted the number 2.35. Fortunately, Java picks up where ColdFusion leaves off. The following UDF lets you specify the number of places to round to:

// mode can be "up", "down", or "even".  Even is the default.
function decimalRound(numberToRound, numberOfPlaces, mode)
{   
    var bd = createObject("java", "java.math.BigDecimal");
    bd.init(arguments.numberToRound);

    if (structCount(arguments) eq 1)
    {   
        mode = "even";
    } 

    if (mode is "up")
    {   
        bd = bd.setScale(arguments.numberOfPlaces,
                         bd.ROUND_HALF_UP);
    } 
    else if (mode is "down")
    {   
        bd = bd.setScale(arguments.numberOfPlaces,
                         bd.ROUND_HALF_DOWN);
    } 
    else
    {   
        bd = bd.setScale(arguments.numberOfPlaces,
                         bd.ROUND_HALF_EVEN);
    } 
    return bd.toString();
}

The mode is an interesting argument. Its meaning is clear for "up" and "down", but "even" is a little more involved. What "even" means is that if the last digit in your number (the number to the left of the discarded portion of the original number) is even, round down, and if it's odd, round up. In other words, half the time, act as through the mode were "up" and the other half, act as though the mode were "down". This is the best way to eliminate cumulative round errors over a series of calculations, and worked perfectly for me.

Posted by cantrell at 12:55 PM. Link | Comments (4) | References

July 3, 2003

Rolling Your Own CFPAUSE Tag

Somehow it came to my attention recently that BlueDragon supports a CFPAUSE tag. According to the documentation:

The CFPAUSE tag allows you to pause the execution of a page for a specified number of seconds. The interval attribute is required and must specify an integer value.

I'm not sure why you would want to do this (if your application is just too darn fast?), but if it appeals to you for some reason, and you're using ColdFusion MX, here is my own CFPAUSE tag:

<cfparam name="attributes.interval" default="1"/>

<cfscript>
    thread = createObject("java", "java.lang.Thread");
    thread.sleep(javaCast("long", 1000*attributes.interval));
</cfscript>

Here is the dynamic new CFPAUSE tag in action:

<cfimport taglib="/cf_tags" prefix="mm"/>
<html>
    <cflog text="this"/>
    <mm:pause interval="5"/>
    <cflog text="is"/>
    <mm:pause interval="5"/>
    <cflog text="slow"/>
</html>

Posted by cantrell at 12:34 PM. Link | Comments (9) | References

July 2, 2003

How to Snoop on ColdFusion Data Types

Last week, I made a couple of posts about ColdFusion Arrays, and how they are actually java.util.Vectors, which means that you can convert them to Java arrays by calling toArray(). How did I figure that out? I didn't ask the ColdFusion engineers. That's cheating. The first thing I did was find out what type of class we are actually dealing with when we have a reference to an array. The Java object "Object" (which all objects extend) has a method called getClass() which returns the runtime class of an object. Calling toString() on the class (or simply the act of outputting it, which automatically calls toString()) will reveal the class name:

<cfset cfArray = arrayNew(1)/>
<cfset cfArray[1] = "c"/>
<cfset cfArray[2] = "b"/>
<cfset cfArray[3] = "a"/>
<html>
    <cfoutput>
        #cfArray.getClass()#
    </cfoutput>
</html>

The result of the code above is:

class coldfusion.runtime.Array

So now I know that I'm dealing with a coldfusion.runtime.Array, however that information doesn't do me any good by itself. What I need to know is what a coldfusion.runtime.Array really is, and what its public interface looks like. That's where "javap" comes in. javap is a program that comes installed with your JDK that most people actually don't know about. I don't know what the "p" stands for (any ideas?), but javap is essentially a Java class disassembler. Running it against any class in your classpath will, by default, output public and protected method signatures along with other class information (use the -private flag to see private method signatures). If you have java installed and in your path, at the command line, type:

javap java.lang.String

And you will get something like:

Compiled from String.java
public final class java.lang.String extends java.lang.Object implements 
java.io.Serializable, java.lang.Comparable, java.lang.
CharSequence {
    public static final java.util.Comparator CASE_INSENSITIVE_ORDER;
    public java.lang.String();
    public java.lang.String(java.lang.String);
    public java.lang.String(char[]);
    public java.lang.String(char[],int,int);
    public java.lang.String(byte[],int,int,int);
    public java.lang.String(byte[],int);
    public java.lang.String(byte[],int,int,java.lang.String)
        throws java.io.UnsupportedEncodingException;
    public java.lang.String(byte[],java.lang.String) throws
        java.io.UnsupportedEncodingException;
    public java.lang.String(byte[],int,int);
    public java.lang.String(byte[]);
    public java.lang.String(java.lang.StringBuffer);
    java.lang.String(int,int,char[]);
    public int length();
...
}

So to find out more about coldfusion.runtime.Array, I used the following command:

javap -classpath /path/to/your/cfusion.jar coldfusion.runtime.Array

The output is:

No sourcepublic final class coldfusion.runtime.Array extends java.util.Vector {
    public coldfusion.runtime.Array();
    public coldfusion.runtime.Array(int);
    static coldfusion.runtime.Array copy(coldfusion.runtime.Array);
    static coldfusion.runtime.Array copy(java.util.List);
    public int getDimension();
...
}

Since I could see from the output above that coldfusion.runtime.Array extends java.util.Vector, I knew that I had access to all of Vector's public methods, as well, such as toArray(), which was precisely the method I was looking for.

Posted by cantrell at 12:45 PM. Link | Comments (4) | References

July 1, 2003

New Addition to Macromedia Weblogs

Ben Forta launched his new weblog just about a week ago. If you haven't been following it, take a look. Although it has only been up for a relatively short time, it is already full of some great content. Ben's weblog is powered by Ray Camden's ColdFusion blogging software.

On a completely unrelated note, after I learned last week that Casio's website is built in ColdFusion (using Fusebox), Ben pointed out to me yesterday that Sanyo's site is done completely in ColdFusion, as well. If you want to test out Sayno's ColdFusion shopping cart code, I highly recommend picking up this exclusive Hello Kitty toaster (available in white or pink) which actually toasts Hello Kitty's face on every slice.

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

June 30, 2003

Ping MXNA from ColdFusion

Scott Keene has just released MXNAPing 1.0, a ColdFusion component for pinging the Macromedia XML News Aggregator. "Pinging" refers to the process of sending MXNA an XML-RPC request with a special ID in it that tells MXNA that you have just updated your blog. MXNA then knows to go pick up your RSS feed and get your new post aggregated immediately. MXNA checks all of its feeds twice an hour, however by pinging MXNA, you can make sure your posts are picked up instantly. For more information about pinging MXNA, including instructions on how to configure Movable Type for pings, see the MXNA FAQ. For information on pinging MXNA from PHP, see Rob Hall's recent work. Anyone want to have a go at Java support?

Posted by cantrell at 11:17 AM. Link | References

June 27, 2003

Sorting Two Dimensional Arrays

Yesterday I wrote about how to sort ColdFusion arrays using the static sort() method on the java.util.Arrays object. The original question that inspired the post was actually about sorting 2-dimensional arrays. The answer is that you can sort 2-dimensional arrays using the technique I wrote about yesterday, but only in one dimension.

A ColdFusion 2-dimensional array is actually a java.util.Vector of java.util.Vectors. In other words, if you think of a 2-dimensional array as a table, the rows are Vectors, but the columns are not. If you take a slice of data in any particular column, none of the data is actually in the same data structure because the data actually spans as many Vectors as rows in your column. Maybe a diagram will help:

Array #1: [1][1] [1][2] [1][3] [1][4]
Array #2: [2][1] [2][2] [2][3] [2][4]
Array #3: [3][1] [3][2] [3][3] [3][4]
Array #4: [4][1] [4][2] [4][3] [4][4]

So as you can see, if you want to sort your 2-dimensional array horizontally, you are in luck, but if you want to sort it "by column", or vertically, I think you will have to massage the data quite a bit first. Probably better to build a query object than a 2-dimensional array, in that case.

Posted by cantrell at 12:10 PM. Link | Comments (4) | References

June 26, 2003

Macromedia Opensources Spectra

Macromedia recently announced that Spectra will be opensourced, which means that you will be able to download the source code for free, and both build and deploy Spectra applications under the macromedia Spectra Software License, which is based on the Apache Software Foundation license. I haven't played with Spectra myself, however now that it looks like it might come back to life, I'll have to give it a shot.

This is the full post that Tim Buntel made to the spectra-talk list yesterday:

As you know, Macromedia announced in May 2001 that there would be no new feature-additive releases of Macromedia Spectra. To allow Spectra applications to run on top of ColdFusion MX, Spectra 1.5.2 was made available in December 2002 as an update release distributed through SpectraSource for existing Spectra 1.5.1 customers.

Macromedia is now pleased to announce that the full source of Macromedia Spectra is to be released under a public open-source license. The source will be available as a free download with which you can build and redistribute Spectra applications as allowed by the Macromedia Spectra Software License (based on the Apache Software Foundation license).

We plan to release the full product as soon as possible as a free download from the SpectraSource site (http://spectrasource.macromedia.com). The final scheduling is still being planned, but we anticipate release by fall of 2003. Watch SpectraSource for details as they become available. This notice will be posted there within the next day or so.

If you have any questions or comments, email spectraopensource@macromedia.com.

Macromedia Spectra Open-source FAQ

What does this open source announcement mean for me?

If you already have an investment in Spectra, you can maintain or expand your applications as well as benefit from the support of the Spectra community. If you do not have an investment in Spectra, give it a try - you can now use as many or as few parts of the framework as you like in your ColdFusion applications.

What will the free download contain?

The full Spectra product code will be available with the exception of several OEM technologies, namely the Ektron HTML editor and the Sybase SQL Anywhere database.

Will this version require an existing installation of Spectra? Will it require ColdFusion MX?

Details regarding the distribution have not yet been finalized, but our intention is to provide a version of Spectra that does not require anything besides ColdFusion.

When will it be available?

Final release scheduling is still being planned, but we anticipate release by this fall. Watch SpectraSource for more details.

Will macromedia continue to offer technical support for Spectra?

We will continue to provide technical support for Macromedia Spectra through December 31, 2003 to customers holding a purchased license of Spectra 1.5.1. Please note, however, that support will not be available if you modify the core application source code.

How does Open Source compare to Community Source?

Originally, Spectra was organized around a community source model where Macromedia owned the software source, but contributions come from the developer community and were vetted against the company's own standards, and then included in future releases. Once the open source version of Spectra is released, the complete source will be available as a free download with which you can build and redistribute Spectra applications as allowed by the Macromedia Spectra Software License (based on the Apache Software Foundation license).

Thanks!

Tim Buntel
Product Manager
Macromedia ColdFusion Server

Posted by cantrell at 11:46 AM. Link | Comments (5) | References

June 24, 2003

Sorting 2-Dimensional Arrays

There was a post on the BACFUG mailing list yesterday which I think makes for a good tip. Someone was asking how to use the arraySort function to sort two-dimensional arrays, which it does not support. The response was a recommendation to create a query instead, then use query of query to get the record set in the correct order. What would you suggest?

Posted by cantrell at 12:17 PM. Link | Comments (7) | References

June 19, 2003

Another Way to Serve Binary Data

I made a post recently on using ColdFusion to write out binary data to the output stream in order to allow me to serve an image or other binary file that doesn't exist on disk. The original code I posted looked like this:

<cffile action="readbinary" file="/home/cantrell/Pictures/Corrs2.jpg" variable="pic"/>

<cfscript>
    context = getPageContext();
    context.setFlushOutput(false);
    response = context.getResponse().getResponse();
    out = response.getOutputStream();
    response.setContentType("image/jpeg");
    response.setContentLength(arrayLen(pic));
    out.write(pic);
    out.flush();  
    out.close();
</cfscript>

In the example above, I'm reading the file from disk, but in a real-life situation, I would be getting the bytes from a URL or a database. Anyway, Spike Washburn (you guys know Spike?) was able to reduce the code above to just this:

<cffile action="readbinary" file="/home/cantrell/Pictures/Corrs2.jpg" variable="pic"/>
<cfcontent type="image/gif; charset=8859_1">
<CFSCRIPT>
    writeOutput(toString(pic));
</cfscript>

Very cool concept. (Hint: the key is in the character encoding.) Thanks for the fresh perspective, Spike!

Posted by cantrell at 5:15 PM. Link | Comments (26) | References

June 17, 2003

Data Connection Kit and ColdFusion

Macromedia DevNet just published an excellent tutorial on using the Data Connection Kit with ColdFusion written by Ben Forta. I read through the article and worked through the examples over the weekend, and I found it to be very informative. If you have been wondering what the Data Connection Kit and FireFly components are all about, check out what Ben has to say.

Posted by cantrell at 3:58 PM. Link | References

Geoff Bowers Explains the CFMX Administrator

Geoff Bowers of Daemon Internet Consultants has recently released an excellent Breeze presentation on the CFMX administrator. If you have questions or doubts about CFMX administration, Geoff's presentation is likely to clear them up. He goes into just enough detail to make the information valuable, however he also keeps it at a high enough level that he is able to cover the entire administrator in just a little over 15 minutes. Thanks for putting so much time into this, Geoff.

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

June 16, 2003

Casio.com Uses ColdFusion and Fusebox

I discovered over the weekend that Casio's site is implemented in ColdFusion, and seems to use Fusebox. Anyone know the folks who built it? It's a very well-built, well-designed, functional application.

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

June 12, 2003

Curious about Royale?

Who isn't? We have some information posted on our site now. It starts out:

Royale is the internal code name for a new initiative at Macromedia that will address the requirements of enterprise programmers who want to develop rich client applications.

There is also a FAQ available.

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

IBM Promotes ColdFusion MX and WebSphere

IBM recently published an article on the advantages of integrating CFMX and WebSphere. The article starts:

The ColdFusion markup language (CFML) has a reputation for being an easy scripting language to learn. The ColdFusion tag-based programming model allows for rapid Web development, and the inherent simplicity of this model makes Internet application development possible for a wider population of developers.

It's great to see how invested IBM is in ColdFusion MX. The article continues:

In this article, we show how Macromedia ColdFusion MX for IBM WebSphere Application Server (Application Server) can share session variables between ColdFusion and J2EE components. We show the synergy achieved by using these two powerful products in tandem.

Posted by cantrell at 11:02 AM. Link | Comments (1) | References

June 10, 2003

Using ColdFusion to Write Out Binary Data

I have been trying to get ColdFusion to write binary data (image bytes) out to my browser on and off for the last couple of weeks using several different techniques. Thanks to some internal help, this morning, I finally got it.

The idea is that I want to take a byte array and write it directly to the output stream between the server and client and have the image render properly in the browser. That means the data and the output stream can't be at all corrupted by whitespace, new lines or line returns like it can be if you are only sending back text. The following code illustrates how to get this to work:

<cffile action="readbinary" file="/home/cantrell/Pictures/Corrs2.jpg" variable="pic"/>

<cfscript>
    context = getPageContext();
    context.setFlushOutput(false);
    response = context.getResponse().getResponse();
    out = response.getOutputStream();
    response.setContentType("image/jpeg");
    response.setContentLength(arrayLen(pic));
    out.write(pic);
    out.flush();
    out.close();
</cfscript>

It wasn't the process of writing a byte array to the output stream that had me stumped for so long. My problem was that I wasn't getting my hands on the right output stream, or more specifically, the right response. Notice this line:

response = context.getResponse().getResponse();

I was only calling getResponse() once, which returned a response object with an output stream that would always corrupt binary data because it was always expecting character data. By calling getResponse() twice, I am able to get to the underlying output stream which I can use to write bytes with no problems.

So why do something like this? If all I wanted to do is essentially move a binary file from disk to the client, I would use the cfcontent tag, but what if the file doesn't exist on disk? What if the image is in the database, or you got the bytes from a URL? The only way (as far as I know) to send the bytes to a client without creating a temporary file is using the technique above.

I should point out that this is not an officially supported technique. Use it at your own risk, and encapsulate it well so that if it doesn't work in future versions of CFMX, you can fix it easily.

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

May 23, 2003

Closing Tags with Slashes: An Informal Survey

How many ColdFusion programers out there are religious about closing their tags? In other words, are you more likely to do this...

<cfreturn foo>

... or this ...

<cfreturn foo/>

How about your HTML tags? Strict, transitional, or "freestyle"?

Posted by cantrell at 6:05 PM. Link | Comments (15) | References

New ColdFusion TechNote: Incorrect output behavior when using Sitewide Error Handler

Macromedia has published a new ColdFusion TechNote:

Incorrect output behavior when using Sitewide Error Handler

If you are having problems using a site-side error handler in CFMX, have a look. The TechNote provides a work-around.

Posted by cantrell at 11:36 AM. Link | Comments (1) | References

May 21, 2003

Ben Forta's Presentation on ColdFusion MX for J2EE

Check out Ben's Breeze presentation on ColdFusion MX for J2EE, The Marriage of Power and Productivity:

http://www.macromedia.com/software/coldfusion/j2ee/special/presentations/tech_intro/

Good stuff, Ben.

Posted by cantrell at 2:18 PM. Link | References

May 19, 2003

Using structKeyExists Rather Than isDefined

If you have ever tried using the isDefined function like this:

<cfif isDefined("url['foo']")>

Then you have probably seen this error:

Parameter 1 of function IsDefined, which is now "url['foo']", must be a syntactically valid variable name.

In situations where you either have to use bracketed syntax, or simply prefer it, try using the structKeyExists function instead, like this:

<cfif structKeyExists(url, "foo")>

Since variable scopes are actually structs, the above syntax works with all scopes exactly like the isDefined function would.

Posted by cantrell at 6:47 PM. Link | Comments (2) | References

May 13, 2003

New TechNote: ColdFusion MX and JRun 4 Support for Windows 2003

From Macromedia's webiste:

Both ColdFusion MX and JRun4 will provide support for Microsoft's newest operating system, Windows 2003. This TechNote will discuss the availability of this enhancement to these Macromedia server products.

You can find the entire TechNote here:

http://www.macromedia.com/support/jrun/ts/documents/2003_support.htm

Posted by cantrell at 10:11 AM. Link | References

May 12, 2003

TheServerSide Features Talk By Macromedia Software Architect

TheServerSide.com is featuring a talk by Sean Neville, the JCP Executive Committee representative for Macromedia and Flash Remoting software architect. From TheServerSide's site:

Sean talks about Rich Internet Applications (RIAs), how they can be used to aggregate the business tier and enterprise applications using the client and looks at architectural approaches and technologies used for designing RIAs. He discusses how the J2EE Petstore was implemented in Flash, how the Flash Remoting product enables interoperability between J2EE and rich clients, and examines why vendors are trying to attract a new 'VB-style' group of developers. He also looks at changes that need to occur in the industry for RIAs to become mainstream.

Check it out here:

http://www.theserverside.com/events/index.jsp

Posted by cantrell at 1:48 PM. Link | References

May 8, 2003

Jeremy Allaire Discusses ColdFusion Past And Present, and What's Next for the Web

In this interview, Jeremy discusses:

http://www.meet-the-makers.com/conversations/allaire/

Posted by cantrell at 12:37 PM. Link | References

May 6, 2003

Tons of New ColdFusion Content on DevNet

Macromedia just published several very high-quality ColdFusion (with a little Java thrown in) articles on DevNet:

Advanced ColdFusion: Simplicity Is Just the Start of It
Ben Forta
http://www.macromedia.com/devnet/logged_in/bforta_advcf.html

Building ColdFusion MX and J2EE Hybrid Applications
Drew Falkman
http://www.macromedia.com/devnet/mx/coldfusion/j2ee/articles/hybrid.html

Controlling Database Transactions in ColdFusion MX
Simon Horwith
http://www.macromedia.com/devnet/mx/coldfusion/articles/cftransaction.html

Improving Performance of Rich Internet Applications with Flash Communication Server MX
Giacomo 'Peldi' Guilizzoni
http://www.macromedia.com/devnet/mx/flashcom/articles/improving_ria.html

Building an Object-Oriented User Interface in ColdFusion MX
Dave Friedel
http://www.macromedia.com/devnet/mx/coldfusion/articles/oo_interface.html

Caching in ColdFusion
Matt Boles
http://www.macromedia.com/devnet/mx/coldfusion/articles/cfcaching.html

Posted by cantrell at 11:40 AM. Link | References

May 3, 2003

Unit Testing ColdFusion Components

Unit testing is a great way to black-box test your components. By "black-box testing," I mean that you are only testing the results of function calls as opposed to white-box testing which actually exposes the inter-workings of components and functions.

Unit test is code written to test other code by simulating a real use case and comparing the results of function calls to expected results. These types of tests are most often done with languages that are object oriented, which means that unit testing code is appropriate for ColdFusion components. There is a unit testing framework on DRK 3 called cfunit (named after the very popular JUnit testing framework for Java). Read more about cfunit on Macromedia's website.

Raymond Camden came across cfunit last week. You can read his reaction here:

http://www.camdenfamily.com/morpheus/blog/index.cfm?mode=entry&entry=60

Posted by cantrell at 6:22 PM. Link | Comments (3) | References

April 30, 2003

Three New TechNotes

cfform errors with ColdFusion MX on multihomed servers
http://www.macromedia.com/support/coldfusion/ts/documents/cfform_multihomed.htm

Configuring the Microsoft SQL Server 2000 JDBC driver
http://www.macromedia.com/support/coldfusion/ts/documents/cfmx_config_mssql2000.htm

Data source verification fails for Oracle JDBC Thin Driver
http://www.macromedia.com/support/coldfusion/ts/documents/oracle_thin_ds_fails.htm

Posted by cantrell at 11:56 PM. Link | Comments (1) | References

Controlling Whitespace in ColdFusion

With browsers being as generous as they are about whitespace, ColdFusion, like every other scripting language I have used, doesn't seem to make much of an effort to keep it to a minimum. Typically, whitespace is not a concern since browsers handle it so well, however if you are trying to generate an XML document, it can be a big problem. That's why we have tags like cfsilent, cfprocessingdirective, and cfsetting, and that's why we have the ability to enable whitespace management in the ColdFusion administrator. However, CFMX for J2EE doesn't seem to come with the whitespace management option, and sometimes no matter what combination of whitespace management tags I use, I simply cannot prevent the server from writing out a few carriage returns at the top of the document (which makes for invalid XML). I finally discovered the ultimate solution.

The best way I have found to prevent whitespace is to manage the buffer and the output stream yourself. When a page is being executed, generated content is being written to a buffer, and that buffer gets flushed to the output stream which represents the connection between your server and a browser. You can use the cfflush tag to flush that buffer if you need data to reach the client faster (for instance, if you want to give them feedback about a process which might take several seconds to complete), and you can also clear that buffer as well, which means you can get rid of unwanted whitespace! The only way I have found to do it is to resort to Java. The following does the trick:

<cfscript>
        getPageContext().getOut().clearBuffer();
        writeOutput(someContent);
</cfscript>

The most bullet proof way I have found for generating valid XML in ColdFusion is to use a combination of the cfsavecontent tag and the Java code above, like this:

<cfset someVar = "Whitespace can be a pain."/>
<cfsavecontent variable="responseXml"><?xml version="1.0"?>
<root>
    <element><cfoutput>#someVar#</cfoutput></element>
</root></cfsavecontent>
<cfscript>
        getPageContext().getOut().clearBuffer();
        writeOutput(responseXml);
</cfscript>

Feel free to share your whitespace techniques here. I'm interested in knowing how others solve this problem.

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

April 29, 2003

XML-RPC and ColdFusion

Roger Benningfield of JournURL has created a nice component interface for using XML-RPC with ColdFusion MX. I haven't tried it yet, but I'm about to. I will let you know what I find. You can find information on his project here:

http://journurl.com/support/users/admin/index.cfm?mode=article&entry=362

Thanks for this contribution to the ColdFusion community, Roger. This has the potential to save a lot of people a lot of time.

Posted by cantrell at 1:56 PM. Link | Comments (3) | References

April 28, 2003

Ben & Jerry's Switches to CFMX, Flash MX and DW MX

Ben and Jerry's Ice Cream recently "went dynamic" by upgrading their
static 600 HTML page site to a full database driven CF MX, Flash MX and
DW MX powered site. Check it out:

http://www.benandjerrys.com

But even more important is the fact that tomorrow (4/29) is free cone day, so
go get yourself some free ice-cream at any Ben and Jerry's between noon and 8PM!

Posted by cantrell at 11:40 PM. Link | References

April 25, 2003

Crystal Reports -- An Informal Survey

I have a few questions about the cfreport tag and the use of Crystal Reports in general.

  1. How many of you out there use the cfreport tag to generate Crystal Reports?
  2. What version of reports do you generate?
  3. What do you use the reports for?
  4. How important is the cfreport tag to you?

Feel free to answer here or email me directly.

Posted by cantrell at 5:39 PM. Link | Comments (10) | References

April 23, 2003

Uploading a File with Mac IE 5.1

It seems that the Macintosh version of Internet Explorer 5.1 adds spaces to the end of parameter values that are submitted with an enctype of multipart/form-data (in other words, when a file is being uploaded). I have seen people ask about this on various lists, so I thought I would address it here.

The fix seems to be to trim all your form variables. Normally I would not advocate coding around a single bug in a single obsolete browser, however I have found that trimming form variables is pretty good practice anyway, so this is just one more reason to do it.

The good news is that I cannot reproduce this problem in IE 5.2, so it looks like it's been fixed. Even better news is that with Mozilla and Safari out there, there's no need to even use IE anymore!

Posted by cantrell at 3:47 PM. Link | Comments (1) | References

April 18, 2003

CF_Europe 2003

Who's going? I was just looking through the list of speakers, and I'm impressed. Too bad it's only two days! You can find details here:

http://www.cf-europe.org/

Here's the important stuff:

CF_Europe is a yearly European Macromedia Developer Conference organised and run by the CFUGs and MMUGs of Europe.

CF_Europe 2003 (our 2nd year) is being held at Olympia Conference Centre, London, UK on Thursday 29th May to Friday 30th May 2003.

The event features numerous workshops on ColdFusion Development, Server Management, User Interfaces, and Web Development Solutions. The conference program is designed to enable emerging and seasoned developers extend their skill sets and expand their knowledgebase.

Posted by cantrell at 4:05 PM. Link | References

April 15, 2003

CFMX for J2EE License Transfer Program Extended

Anyone interested in going from ColdFusion Server to CFMX for J2EE should check this out. From Macromedia's website:

"For a limited time, Macromedia ColdFusion Server Enterprise customers can transfer their licenses to ColdFusion MX for J2EE and receive up to a 30% discount through the Macromedia Volume License Program (MVLP).

Now, ColdFusion Server 4.5 (and later) Enterprise Edition (English version) customers can begin developing, deploying, and migrating their ColdFusion applications on their preferred J2EE application server at a significant savings."

Offer good through 6/31/2003. Details here:
http://www.macromedia.com/software/coldfusion/j2ee/special/license_transfer/

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

April 9, 2003

No More OutOfMemory Errors

Some of you may have noticed that our weblog server was occasionally down last month. Traffic to our weblogs really started picking up at the end of February and in early March, and we were finding that we were having to restart the server occasionally due to OutOfMemroyErrors. I was surprised when bumping up the JVM's memory allocation to 512MB didn't seem to have any effect at all. After doing a little research, I discovered that the problem was the server's permanent memory size. A Macromedia TechNote describes permanent memory like this:

"The permanent generation is the area of the heap where the JVM stores its internal information, such as information about loaded Java classes. This memory is involved in the garbage collection of persistent objects. Because ColdFusion MX loads a large number of classes over time, the default size may be too small. Most application server vendors suggest increasing this parameter when encountering an out of memory condition."

The default allocation is only 64MB, which often isn't enough to run large-scale applications like CFMX (along with several smaller, high-traffic applications like our weblogs). I bumped the permanent memory size up to 192MB (128MB would probably have been fine) and the server has been running beautifully ever since. I made the change about a month ago, and haven't touched the server since, even as traffic continues to increase. Check out the TechNote here:

http://www.macromedia.com/support/coldfusion/ts/documents/java_lang_outofmemory.htm

Posted by cantrell at 9:52 AM. Link | Comments (5) | References

April 7, 2003

CFDJ Interview

CFDJ recently published an interview with Sarge and myself. Check it out here:
http://www.sys-con.com/coldfusion/article.cfm?id=586

Posted by cantrell at 2:55 PM. Link | References

EditPlus ColdFusion Syntax File

Sam Neff, who I recently met in San Francisco, put together an EditPlus syntax file for ColdFusion MX. You can find it here:
http://www.editplus.com/others.html

Posted by cantrell at 2:54 PM. Link | References

April 5, 2003

My Flashforward Presentation is Online

I posted my latest Flashforward 2003 (San Francisco) presentation online today. It focuses on ColdFusion and Flash integration through Flash Remoting with a discussion of RSS at the end. I don't know how useful it is by itself without me standing next to it talking, but I have had sever requests to post it, so here it is:

http://www.markme.com/cantrell/flashforward2003/

Posted by cantrell at 3:33 PM. Link | References

April 1, 2003

Remember that JSP eq Java

I was talking to someone last week who needed to use some Java in his ColdFusion application, but couldn't because of limitations with his hosting provider's configuration which prevented him from making changes to the ColdFusion server's classpath. I actually don't know how much freedom developers who use shared hosting environments have when it comes to integrating Java and ColdFusion (perhaps some people can comment here), however it occurred to me that one possible work-around is to embed all your Java in JSPs (assuming the hosting provider is using ColdFusion Enterprise). JSPs get compiled into Java classes, so as long as you are doing something relatively simple, there is really no reason why you can't simply include your Java between scriptlet tags. Scriptlet tags look like this:

<%
    // java code here
%>

You can declare members (methods and variables) using declaration tags, like this:

<%!
    String foo = "bar";
    private String getFoo()
    {
        return foo;
    }
%>

Use an expression tag to access members:

<%= getFoo() %>

For an explanation of all JSP tags, see:
http://java.sun.com/products/jsp/syntax/1.2/syntaxref12.html

Again, you're not going to write an entire application like this (eventually, you are going to need access to the classpath), but in a pinch, you might find this technique useful.

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

March 28, 2003

Using cflogin with Flash Remoting

I did a session on Flash Remoting with ColdFusion at Flashforward here in San Francisco, and I got a pretty good question from someone in the audience. He wanted to know how to use ColdFusion's built-in authentication mechanism with ColdFusion components and Flash Remoting. Fortunately, ColdFusion and Flash make it very easy.

First of all, CFC functions have an optional "roles" attribute which you can use to limit access to that specific function. So the first thing you do is specify a coma-delimited list of roles which are valid for your function. The example function I wrote is below:

<cfcomponent>
    <cffunction name="getDate"
                access="remote"
                roles="admin"
                returnType="date">
        <cfreturn #now()# />
    </cffunction>
</cfcomponent>

The next thing you do is use the setCredentials function on a NetConnection instance in ActionScript. Example code below:

var gw = "http://localhost/flashservices/gateway";
var con = NetServices.createGatewayConnection(gw);
// username and password are text fields... 
con.setCredentials(username.text, password.text);
var serv = con.getService("com.macromedia.tests.auth_test", this);
serv.getDate();

The last thing you have to do is map your username and your password to one or more roles, which you do using cflogin and cfloginuser. I put the following code in an example Application.cfm file:

<cfapplication name="authTest" />
<cflogin>
    <cfif isDefined("cflogin")>
        <cfif cflogin.name eq "someUsername" and
              cflogin.password eq "somePassword">
            <cfloginuser name="#cflogin.name#"
                         password="#cflogin.password#"
                         roles="admin" />
        </cfif>
    </cfif>
</cflogin>

That's all you have to do.

Posted by cantrell at 6:10 PM. Link | Comments (5) | References

March 25, 2003

Getting JRun and CFMX to Work With Java 1.4.1 on OS X

Thanks to Woojin Choi for posting information on getting JRun to work with Java 1.4.1 on OS X. I have made a couple of adjustment to what Woojin posted to match what I found to be effective:

First, back up the jvm.cfg file found here (you will need to use 'sudo' to make these changes):

/System/Library/Frameworks/JavaVM.framework/Versions/1.4.1/Home/lib/jvm.cfg

Edit jvm.cfg. Change this...

-client KNOWN
-jvm ALIASED_TO -client
-hotspot ALIASED_TO -client
-server KNOWN
-classic WARN

... to this ...

-client
-jvm
-hotspot
-server
-classic

Edit {jrun_installation_dir}/bin/jvm.config, and change this...

java.home=/System/Library/Frameworks/JavaVM.framework/Versions/1.3.1/Home

... to this ...

#java.home=/System/Library/Frameworks/JavaVM.framework/Versions/1.3.1/Home
java.home=/System/Library/Frameworks/JavaVM.framework/Versions/1.4.1/Home

Give it a try and see what happens!

Posted by cantrell at 2:44 AM. Link | References

March 24, 2003

Making Your ColdFusion Applications More Platform Independent (Part II)

Last Friday, I made a post about writing platform-independent ColdFusion code, and specifically how important it is to be consistent with case when you are naming and referencing files since Unix file systems are case sensitive. The other practice I often see people do which keeps code from being platform independent is hardcoding file separators. The Windows file separator is a "\" (backslash character), however the file separator on Unix file systems is a "/" (forward slash character). The Macintosh file separator is a ":" (colon character), however the OS X file system will let you get away with a Unix-like "/" file separator. If your application needs to construct file paths, and you want your code to be truly platform independent, you will need to take these differences into account.

There are two good ways to make your file separators dynamic. The first is to define the system's file separator in the Application.cfm file or other file where you keep configuration parameters. For instance, if you add this to your Application.cfm file...

<cfset request.FILE_SEPARATOR = "/" />

... rather than hardcoding slashes throughout your code, you can then simply refer to the request.FILE_SEPARATOR variable.

You can make your life even easier by letting ColdFusion (or, more precisely, Java) figure out what the system's default file separator is for you with the following function:

function getFileSeparator()
{
    var fileObj = "";
    if (isDefined("application._fileSeparator"))
    {   
        return application._fileSeparator;
    }
    else
    {   
        fileObj = createObject("java", "java.io.File");
        application._fileSeparator = fileObj.separator;
        return getFileSeparator();
    }
}

This function actually caches the file separator for you the first time you call it so that you are not instantiating a new java.io.File object each time you call it, however if you prefer to have your calling code do the caching, naturally you can re-factor the function appropriately. The point is that by not hardcoding your file separators, your code is much more platform independent, and much easier to port from one OS to another.

Posted by cantrell at 2:21 PM. Link | References

March 20, 2003

Macromedia Releases ColdFusion Updater 3

Macromedia has just released ColdFusion MX Updater 3. The updater applies to ColdFusion MX Server Professional Edition, ColdFusion MX Server Enterprise Edition and ColdFusion MX for J2EE. Macromedia strongly encourages its customers to download and install updater 3 as it contains the latest security and stability functionality. The updater can be downloaded here:
http://www.macromedia.com/software/coldfusion/special/updater/faq/

Read the updater release notes here:
http://www.macromedia.com/support/coldfusion/releasenotes/mx/releasenotes_mx_updater.html

Note that updater 3 contains all the updates and fixes of the previous two updaters, so if you install updater 3, you do not need to install the first two.

Posted by cantrell at 11:22 PM. Link | References

March 18, 2003

How to Migrate or Switch to ColdFusion MX

If you have been thinking about migrating to ColdFusion MX from previous versions of ColdFusion, or switching to ColdFusion from other technologies, Macromedia just made it a lot easier. This morning, two new sections of the DevNet Center were launched to help developers make the leap to ColdFusion MX:

Migrating to ColdFusion MX (from pervious versions of ColdFusion)
http://www.macromedia.com/devnet/mx/coldfusion/migrating.html

Switching to ColdFusion MX (from other technologies)
http://www.macromedia.com/devnet/mx/coldfusion/switching.html

Additionally, Macromedia published a couple of articles on the topic, as well:

ColdFusion MX Migration Overview
http://www.macromedia.com/devnet/mx/coldfusion/articles/migration_overview.html

Switching From JSP to ColdFusion MX
http://www.macromedia.com/devnet/mx/coldfusion/articles/jsp_cfmx.html

Posted by cantrell at 9:33 AM. Link | References

March 17, 2003

Using the createUUID Function

I was recently developing a small application which I needed to be as database independent as possible. My goal was for the same code to run on top of the four most popular databases without having to change any SQL at all. The biggest problem I was running into was the fact that one of my component functions needed to insert a record, then return the ID of the record it just inserted. Most databases let you select the variable @@identity immediately following an insert statement, however not all. I decided to try to create a unique ID using ColdFusion's createUUID() function, and use it as my primary key. The technique has worked out quite well. Below are some interesting points about the createUUID function: