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]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
- Existing ColdFusion Caching (query caching and cfcache)
- Persistant Scopes
- The ScopeCache Custom Tag
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:
- Macromedia ColdFusion Goes Mobile (CNET)
- ColdFusion MX 7 Builds SMS Apps For Mobile Phones (TechWeb)
- ColdFusion MX 7 Takes on a New Set of Problems (Database Journal)
- Macromedia Releases ColdFusion MX 7 (TechSpot)
- Macromedia ColdFusion Goes Mobile (IT Observer)
- Macromedia Embellishes ColdFusion MX 7 (Globe and Mail)
- ColdFusion MX 7: The Newest Version of ColdFusion (Community MX)
- Macromedia Dialing Mobile Devices (Computerwire, reprinted at Computer Business Review)
- CFMX 7: This Is the Release That Will Make You a Hero Again (ColdFusion Developer's Journal, reprinted at MX Developer's Journal)
- It's Here! (ColdFusion Developer's Journal, reprinted at MX Developer's Journal)
- Macromedia Adds Mobile Support to ColdFusion (eWeek)
- Macromedia heats up ColdFusion MX 7 (InfoWorld, reprinted at MacWorld)
- Macromedia's ColdFusion Looks Beyond the Web (InternetNews.com, reprinted at DevX.com)
- Interview with Dave Gruber (Sys-Con TV, reprinted at MX Developer's Journal and ColdFusion Developer's Journal)
- Macromedia Announces ColdFusion MX 7 (CFDJ)
- Macromedia Software Pushes Internet Apps Onto Phones (CRN)
- Macromedia Stresses Innovation with ColdFusion MX 7 (eChannelLine)
- Macromedia Software Pushes Internet Apps Onto Phones (CRN)
- Updated Macromedia Development Platform Focuses on Internet and Mobiles (Computer Weekly)
- ColdFusion MX 7 Hits the Streets (Builder.com)
- Macromedia Stresses Innovation with ColdFusion MX 7 (eChannelLine)
- ColdFusion MX 7 builds SMS apps for mobile phones (ITNews.com)
- Macromedia Announces Immediate Availability of ColdFusion MX 7 (ComputerWorld Australia)
- ColdFusion MX 7 Announced and Released (Fusion Authority)
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:
- The ColdFusion Product Page
- SYS-CON TV Interview with Dave Gruber (ColdFusion Product Manager)
- License Changes in ColdFusion MX 7 (via Talking Tree)
- With the release of a new version comes new tech notes.
- If you're not already subscribed to the ColdFusion Product RSS feed (or other Macromedia product RSS feeds), what are you waiting for?
- Blackstone Locales by Paul Hastings
- Learn More About ColdFusion MX by Ben Forta
- Warning About Flash Forms (Ray Camden)
- Installing CFMX 7 on Mac OS X
- Warning About Application Events (Ray Camden)
- Find everything else ColdFusion related in the ColdFusion category of MXNA
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:
- Using a CFQUERY tag, I executed an insert statement.
- Used Thread.sleep() to make the page hang for 10 seconds.
- Inserted ten additional rows from the command line (using the MySQL command line tool).
- 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:
- Executed an insert statement in ColdFusion.
- Slept for 10 seconds.
- Ran a second CFM page that inserted 10 rows while the first page was hung.
- 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:
- You insert a record into the database.
- 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.
- 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:
- 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.
- 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.
- 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:
- 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.
- 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
- 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.
- 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.
- 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.
- 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
- 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.
- 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.)
- 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.
- 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.)
- 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:
- Download and use as-is.
- Download and customize.
- Download and cannibalize.
- 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:
- 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).
- I haven't tested this with jar files, but it should work fine.
- 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:
- toCharArray()
- endsWith()
- startsWith()
- getBytes()
- lastIndexOf()
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:
- The
randomize()function only takes in an int. The best way to generate a unique number is by callinggetTickCount()which returns a long. The two functions cannot be used together. - 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()orrandRange()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:
- 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.
- 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.) - Allows you to easily set bounds for your random numbers using the
setBounds()andsetMax()functions. These can be changed without having to create a new instance of the Randomize component. - 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:
- Required fields in cfform / cfinput are not processed in the order they are defined within the form.
- When more than one image is specified for cftreeitem, the first specified image is displayed for all levels.
- 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:
- ColdFusion is quick and easy to learn.
- You don't have to trade power for simplicity.
- CFMX 6.1 is incredibly feature rich.
- CFMX 6.1 supports all the right acronyms.
- Platform independence.
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:
- Gives your users instant feedback.
- Saves CPU cycles.
- Lowers bandwidth use.
While all of these things are true, it is also true that:
- Client-side validation adds coding and QA time to the development process.
- Large amounts of JavaScript (which are often required for validation frameworks) also use bandwidth.
- Thanks to CSS-P, pages can be small enough that reloading them doesn't have to take as long as loading Amazon.com.
- You have to do server-side validation in addition to client-side validation anyway since client-side validation can always be bypassed.
- 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 | Comments (18) | 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:
- Are you just looking for a convenient way to deploy your ColdFusion applications?
- Are you looking for a secure way to distribute your applications (which implies encryption or obfuscation in addition to compilation)?
- 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)?
- 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:
- CFX tags
- JSP tags
- Using
CFOBJECTorcreateObject()to accesses custom classes in your classpath - 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:
- Siteless file editing (thank you!)
- Keyboard shortcuts for snippets
- CSS support (including CSS code hints and cross-browser validation)
- Secure FTP
- Built-in graphics editor (very cool!)
- Right-click coder tools
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:
- How often do you use it?
- What types of things do you use it for?
- Do you primarily use it for GET or POST operations?
- 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:
- I like the flexibility it gives me in terms of where I can put my custom tags (without having to create mappings).
- 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:
- People who have cookies disabled can still use your application just like people with cookies enabled.
- 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:
- Windows 2000: Approximately 23 times faster than ColdFusion 4.5, 3 times faster than ColdFusion 5, and 2.5 times faster than ColdFusion MX
- Windows 2003: Approximately 3 times faster than ColdFusion 5
- Linux: Approximately 5 times faster than ColdFusion 5
- Solaris: Approximately 4 times faster than ColdFusion 5
- Dynamic email delivery capability increased as much as 50 times more than CF 5.
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:
-
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.
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 guiThe 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:
- Simplified installation. I have installed MX 6.1 several times now with several different configurations, and I'm amazed at how simple and straightforward it is. The new installer is intuitive, user-friendly, streamlined and effective.
- Improved compilation process. It used to be that CFML would be translated into Java code, then the Java code would be compiled into byte code, which is why there was always a few seconds of waiting whenever you made a change to a file and reloaded the page. With ColdFusion MX 6.1, CFML is compiled directly into byte code, so you can see your changes about 10 times faster than before.
- CFMAIL enhancements. Not only is CFMAIL faster in MX 6.1, but it now supports redundancy (multiple email servers can be specified), spooling, replyto and failto headers, secure SMTP server support, and multipart MIME messages (both text and HTML simultaneously). And did I mention that it's faster? The CFMAIL tag in CFMX 6.1 is capable of sending more than 1 million emails per hour.
- CFPOP enhancements. CFPOP now supports multiple MIME types so you can retrieve both text and HTML email bodies.
- CFHTTP enhancements. CFHTTP now supports the following operations: HEAD, PUT, DELETE, OPTIONS and TRACE. It has support for proxies, and the timeout attribute even works now!
- ColdFusion component enhancements. CFMX 6.1 will allow you to call methods that have been overridden in parent components using the keyword "super".
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.
- 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.
- 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:
- The history of ColdFusion.
- What his and JJ's roles were in its creation.
- Some interesting fact about Microsoft and ASP.
- Jeremy's background before the days of ColdFusion.
- HTML and CFML editors.
- Jeremy's new role at General Catalyst.
- The next big web technologies.
- Weblogs and RSS.
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:
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.
- How many of you out there use the cfreport tag to generate Crystal Reports?
- What version of reports do you generate?
- What do you use the reports for?
- 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:
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:
- The algorithm that createUUID uses combines the time and date, the server's IEEE 802 host ID and a random number, so theoretically, the numbers should be unique in all the world. I say "theoretically" because I have already seen people point out situations where MAC addresses might not be unique. But statistically speaking, they are pretty darn unique.
- There is really no significant performance overhead in generating the IDs. The first time you use createUUID, you might notice a pause as the software uses a JNI call to access your hardware configuration, however that value is cached so subsequent calls are fast.
- You are much more likely to run into performance issues when selecting data that uses a UUID for a primary key than inserting it simply because your primary key is a 35 digit string. For relatively small applications, you are not likely to notice any degradation, however this is not the right solution for enterprise level applications.
- If you want the convenience of generating your own primary key without the performance degradation of selecting from a table with a 35 character primary key, you can let your database create a normal auto-incrementing ID field as you normally would to use as your primary key, and insert a UUID at the same time. Then, just select the ID of the row that has the UUID that you just generated, and you are guaranteed (statistically) to have selected the right ID without having to use vendor specific SQL.
- You can always just turn around and select the max ID from the table that you just inserted data into (which means you don't to generate a UUID at all), though you have to make sure that it is not possible that another thread could have inserted a record between the time you inserted your record and the time you selected the max ID. In other words, you have a potential race condition.
Posted by cantrell at 2:48 PM. Link | Comments (5) | References
March 12, 2003
Flash Remoting Update
Macromedia released an update for Flash Remoting yesterday which fixes quite a few issues. The update is not for the version of Flash Remoting that comes with JRun or ColdFusion -- it is only for .NET and Java. The Flash Remoting updates for ColdFusion will be contained in the next updater. Remember that you will need to download the Flash Remoting UI components separately. I will post here the very moment they become available.
Release Notes:
http://www.macromedia.com/support/flash_remoting/releasenotes/mx/releasenotes_updater.html
Remoting Download Page:
http://www.macromedia.com/support/flash_remoting/updaters.html
Components Download Page:
http://www.macromedia.com/software/flashremoting/downloads/components/
Posted by cantrell at 4:06 PM. Link | References
March 5, 2003
Macromedia Launches Entirely New Site
I know it's old news at this point, but I've been so busy today that I haven't had a chance to write about it here. Macromedia launched their new web site last night, and at the same time launched an amazing reaction from the community. Enough has been said on the forums and lists today that the last thing I want to do is rehash what has already been covered, however I would like to mention two things that I think were largely missed in the community.
One of the biggest complaints about the new site was speed. It's important to remember, though, that loading a page with an RIA is very different from loading a simple HTML page. The advantage of using an RIA is that although you are loading more data upfront, ultimately you end up loading less, clicking less, and waiting less, because once the shell of the RIA is loaded, you only need to load data from then on as opposed to several kilobytes of HTML tags, JavaScript, styles, images, etc. I'm not saying that parts of the site can't be optimized; what I'm saying is that a lot of the traditional metrics we use to gauge web site usability need to evolve along with Internet technology.
Another point that I don't think was adequately covered today is that almost the entire back-end was completely rewritten in ColdFusion. We believe macromedia.com is one of (if not the) largest collections of RIAs in production today, and one of the most visited sites on the Internet. According to Penny Wilson's article on DevNet, we reach one million customers a day. Additionally, 250,000 people download software from macromedia.com each day, and 4 million people download the Flash player. All that is done with ColdFusion on the back-end. If there was any question whether CFMX was ready for the enterprise market, I think we now have an answer.
Posted by cantrell at 10:45 PM. Link | References
March 4, 2003
ColdFusion 5 and Apache 2.x.x
Macromedia does not support connectors for ColdFusion 5 and Apache 2.x.x, however since we released the source code for mod_coldfusion, a couple of developers in the community have made the necessary modifications themselves. If you are using ColdFusion 5 and are interested in upgrading to Apache 2.x.x, check out the URLs below:
Windows:
http://home.nextron.ch/coldfusion/
Linux:
http://www.ernst.ca/projects.html
Posted by cantrell at 6:00 PM. Link | Comments (4) | References
February 28, 2003
Couple of Useful Custom Tags
It was pointed out the other day on a list that cfinclude doesn't let you include JSP pages and that there is no cfforward tag to forward a request on to another resource (CFM, JSP, servlet, etc.). BlueDragon apparently does have this functionality. Well, now ColdFusion does, too, with the extremely simple tags below. And ColdFusion also has getPageContext(), as well.
<!---
The includeanything tag will include any type of page, not just a
CFM template.
@attribute page (required) Relative path to the template you want
to include.
--->
<cfif thisTag.executionMode is "start">
<cfparam name="attributes.page" />
<cfscript>
getPageContext().include(attributes.page);
</cfscript>
</cfif>
<!---
The forward tag will perform a server-side redirect.
@attribute page (required) Relative path to the template you want
to forward to.
--->
<cfif thisTag.executionMode is "start">
<cfparam name="attributes.page" />
<cfscript>
getPageContext().forward(attributes.page);
</cfscript>
</cfif>
Posted by cantrell at 11:57 AM. Link | Comments (2) | References
February 26, 2003
cfform Work-around
There was some discussion on cf-talk today about getting cfform to work with CFMX for J2EE. The problem is that the cfform.js file does not get loaded properly. The work-around is to do one of the following three things:
- Copy the cfform.js file out of the CFIDE/scripts directory into some directory in your webroot and use the scriptSrc attribute of the cfform tag to reference it.
- Create a symbolic link in your webroot that points to to the cfform.js file in the CFIDE/scripts directory (Unix only) and reference it using the scriptSrc attribute of the cfform tag.
- Create a mapping in the administrator to the cfform file.
Posted by cantrell at 6:37 PM. Link | References
February 20, 2003
Don't Forget About "contains"
I have seen several people use functions like find, findNoCase and findOneOf to search strings for substrings. Don't forget about the "contains" comparison operator. It lets you do things like this:
<cfif string1 contains string2>
It's in there.
</cfif>
... as opposed to ...
<cfif findNoCase(string1, string2) neq 0>
It's in there.
</cfif>
Keep in mind that "contains" does not compare case.
Posted by cantrell at 1:01 PM. Link | References
February 18, 2003
Why Use cftry and cfcatch?
Someone on a mailing list asked today for an explanation of cftry and cfcatch, and examples of when to use them. Although I don't think it ever made it to the list (the server seems to be down), this was my response:
I have found the try/catch framework to be most useful in two circumstances:
- When your code could encounter an error that you either expect or can recover from, you can trap and handle it with cftry and cfcatch. For instance, I wrote some code recently that checks if a specific file exists on the file system. If it does, the file gets included, but if it doesn't exist, I just include another file that I know will exist. I put a cftry and cfcatch around the include code to accomplish this.
- If you want to add more information to an error. At any particular point in your code, you usually know more about the code than the CF server would if it were to throw an error at that particular point. Usually, that's fine because the chance of an error being thrown is very small, or the additional information you have would not necessarily be useful in fixing the error, however sometimes you might want to include this additional information in the even of an error. For instance, if you are trying to include a page with a URL from a database, rather than just hoping that the page exists or letting ColdFusion formulate an error message if it is not there, you might wrap your cfinclude in a try/catch block, then re-throw the error (assuming you have no way to recover from it) with an additional message explaining that the URL that was retrieved from the database (might even include database information like the data source and the query) is out of synch with the file system.
Posted by cantrell at 12:31 AM. Link | References
February 6, 2003
Shared Variable Scopes and Locking
This is a post I made this morning on cf-talk in response to a thread on locking shared variable scopes. The short answer is that you don't need to unless you are preventing a race condition. For the long answer, read on:
Just some additional interesting information on shared variable scopes: the reason you do not need to lock them (unless you are attempting to prevent a race condition) is that their underlying Java implementations use java.util.Hashtables. Hashtables are synchronized so that two threads cannot modify the same instance of a Hashtable concurrently. So Tony, you are right that Macromedia engineers did the right thing here, otherwise there would be a lot more cflocking going on. For instance, if they had used a HashMap, all access/modification would have to be locked (to prevent actual exceptions as opposed to just unexpected behavior), which would make for a lot more code with no advantages.
Another thing to note is that synchronization at such a low level is very fast and efficient; faster than using cflocks.
Posted by cantrell at 5:53 PM. Link | Comments (2) | References
February 5, 2003
Pet Market Blueprint Application on Mac OS X
In my spare time, I have been trying to get the Pet Market Blueprint app (Flash version) running on CFMX and JRun 4 on my Mac. As it turns out, the Unix version technically works just fine right out of the box -- just follow the instructions, and even the datasource will be set up properly since Pointbase is a 100% pure Java implementation. There is one little detail, however, that actually has more to do with JRun configuration than the Pet Market app itself, but boy is it a tricky one.
JRun comes with it's own version of Flash Remoting which is mapped to flashservices/gateway. It is a Java-only version of Flash remoting, meaning it will not find and delegate to ColdFusion components. Of course, ColdFusion for J2EE servers comes with Flash Remoting as well, so you have to find a way for the two of them to coexist. I found that both of the options below worked, depending on how I had CFMX configured:
- If you are using a context root for ColdFusion (like "cfmx" or "cfusion"), edit the shell_init.xml file in the petmarket web directory. You can continue to use the "default" backend (you do not have to use j2ee), but you will need to add your context root before the flashservices/gateway reference in the gatewayURI tag. For instance, if your context root is "cfmx", your tag should look like this:
<gatewayURI dir="cfmx/flashservices/gateway" />
Save the file and everything should run fine. You don't even have to restart anything.
- If you do not use a context path for ColdFusion (more properly stated, if your context root is "" or "/"), you simple need to make sure that the Flash Remoting gateway that came with JRun does not intercept your requests. The easiest way to do this is to go into the JRun administrator (http://localhost:8000) and change the context root of the Flash Remoting Enterprise application to anything other than flashservices (for instance, I changed it to "flash-services"). Then redeploy the Flash Remoing application or restart JRun and you should be good to go.
If you want to give it a try, download the necessary files here:
http://www.macromedia.com/desdev/mx/blueprint/
Posted by cantrell at 6:00 PM. Link | Comments (7) | References
February 4, 2003
Calling CFCs Directly From Your Browser
I was debugging something the other day with a friend of mine, and I made a request for a CFC directly from my browser. My friend had never seen that before, so I thought I'd blog the technique in case others might have missed it, as well.
If your CFCs are located in your web root, you can reference them directly from your browser like this:
http://server.domain.com/path/to/my.cfc
A request like this will redirect you to a component called cfcexplorer.cfc (you will be required to authenticate while being redirected) which will auto-generate documentation for your component similar to Javadoc. It's a great way to browse your API.
Another technique you can use is to actually invoke a function from your browser, like this:
http://server.domain.com/path/to/my.cfc?method=init
A request like this will not redirect you to the cfcexplorer, but will actually invoke the method specified as the value of the "method" parameter (note that the method's access must be specified as remote). This is a great way to test your CFCs, or even to write entire applications (though latter would be an unusual architecture). If output is enabled in both your component and your function, you can output HTML from your components.
I should add that outputting HTML from your components is an unusual practice, and typically presentation logic is contained in CFM and HTML files rather than CFCs, but occasionally it's worth doing. I should also note that a new instance of the CFC gets created on every request, so although that happens very quickly and efficiently, it is something to take into consideration while designing your overall architecture.
Posted by cantrell at 5:40 PM. Link | Comments (1) | References
January 31, 2003
How To Never Have to Write Another Get or Set Method Again
If you don't need your setters and getters to do anything more than just set and get properties (without modifying those properties), you might be able to save yourself the hassle of implementing all those set and get functions by building a little support framework. In the example below, there is a component called "support.cfc" which all components that need a lot of get and set methods should extend. Notice how the component "test_support.cfc" is free to set and get arbitrary properties without those set and get methods actually having been implemented. (This will also hold true if your component contains an instance of a component that extends support as opposed to extending support itself as in the example below.) I believe you can even scope variables (with or without "this") using this technique:
support.cfc
<cfcomponent>
<cffunction name="setter" access="public">
<cfargument name="varName" type="string" required="yes" />
<cfargument name="varValue" required="yes" />
<cfscript>
setVariable(varName, varValue);
</cfscript>
</cffunction>
<cffunction name="getter" access="public">
<cfargument name="varName" type="string" required="yes" />
<cfreturn evaluate(varName) />
</cffunction>
</cfcomponent>
support_test.cfc
<cfcomponent extends="com.macromedia.util.support">
<cffunction name="init" access="remote">
<cfinvoke method="setter" varName="this.foo" varValue="bar" />
<cfinvoke method="getter" varName="this.foo"
returnVariable="baz" />
<cflog text="#baz#" />
</cffunction>
</cfcomponent>
I'm sure there are better ways to implement this type of technique, but you get the idea.
Posted by cantrell at 6:49 PM. Link | References
January 30, 2003
Windows NT Authentication Security Bulletin
If you have trying to get Windows NT Authentication to with CFMX the way it used to with CF 5, you will want to check this out:
http://www.macromedia.com/v1/handlers/index.cfm?ID=23734
Posted by cantrell at 11:59 PM. Link | References
January 28, 2003
How To Limit File Upload Sizes
There was some discussion a while back on a possible vulnerability in CFMX. I was worried that a denial of service attack would be possible by uploading a single very large file. My fear was that the ColdFusion server was buffering files in RAM before writing them out to the file system, however I was relieved when two people from the ColdFusion team confirmed that the files were written directly to disk and not buffered in RAM. In other words, the input stream from the request is written directly to a file output stream (without being buffered more than just a few K), which means you cannot cause the JVM to run out of memory by uploading a file. Very good implementation.
The next question, however, was whether or not it was possible to create a DOS attack by making the server run out of disk space. Could someone upload enough gigabytes of data to fill an entire partition? Shouldn't there be a way to guard against this type of issue?
Fortunately, there is. On the advice of Laurent Rouquette, I confirmed this morning that you can use the variable cgi.CONTENT_LENGTH to decide if you want to allow a file to be uploaded or not. The code below only allows files less than 25,000 bytes to be saved:
<cfif cgi.CONTENT_LENGTH lt 25000>
<cffile action="upload"
fileField="testFile"
destination="/tmp"
nameConflict="overwrite" />
</cfif>
Note that the file will still be uploaded and saved in a temporary location, but if the cffile tag does not get executed, the temp file will simply be deleted after the upload is complete.
I recommend that anyone who has an application that allows files to be uploaded use this technique as an extra level of security. Remember, though, that the content length of the request contains all the information in the request, so allow a little extra space for other data, as well.
Posted by cantrell at 12:33 PM. Link | Comments (5) | References
January 22, 2003
Macromedia Releases a Pure CFMX Version of the Pet Market App
Macromedia recently released a pure CFMX version of the blueprint Pet Market application. Tim Buntel, Senior Product Manager for ColdFusion MX, has good article at the URL below:
http://www.macromedia.com/desdev/mx/coldfusion/articles/petmarket.html
Posted by cantrell at 2:43 PM. Link | References
January 17, 2003
Answer a Few Questions About How You Use ColdFusion and Enter to Win $100
The following was posted by Phil Costa, the ColdFusion Product Manager:
On the Macromedia server product teams, we believe in delivering tools and technologies that solve real-world problems for web application developers. To help us plan future releases of Macromedia server products, we'd like you to answer a few questions about your web development projects and your use of ColdFusion and JRun for database reporting applications.
HELP SHAPE THE FUTURE OF MACROMEDIA SERVERS AND MAYBE WIN $100 AT AMAZON
http://www.macromedia.com/go/reportsurvey
With your valuable feedback, we can ensure that Macromedia servers continue to meet your development needs. And if you complete the survey, you'll be automatically entered in a contest to win one of two $100 gift certificates at Amazon.com.
Thanks again for your continued enthusiasm and support. We look forward to reviewing your feedback.
Regards,
Phil Costa
Posted by cantrell at 8:42 PM. Link | References
January 16, 2003
How To Get Around the Linux/Solaris and ColdFusion Installation Bug
The bug manifests itself only on Linux and Solaris platforms when you install ColdFusion and then Updater 2 without starting ColdFusion and going to the Administrator between the two steps. If you do not go to the Administrator between the steps, all requests for CFM pages (whether you use Apache or the default web server) will come back as 404s.
If you are installing CFMX on Linux or Solaris from scratch, you must do so in this order:
- Install ColdFusion MX.
- Load the Administrator. (Log in for good measure.)
- Install updater 2.
- Install Apache 1.3.27 or 2.0.43.
- To configure CFMX to work with Apache, start ColdFusion MX (/opt/coldfusionmx/bin/coldfusion start) and run the wsconfig program to install the Apache connector. The command should look something like this:
/opt/coldfusionmx/jre/bin/java -jar \ /opt/coldfusionmx/runtime/lib/wsconfig.jar -ws apache \ -dir /usr/local/apache/conf -a -bin \ /usr/local/apache/bin/httpd -script /usr/local/apache/bin/apachectl -v
I'm not sure if it's simply starting the server between installs, loading a single CFM page, or specifically loading the Administrator, but it works if you load the Administrator, so I would stick with what works for now. Macromedia is aware of the bug and is able to reproduce it, which is the first step toward fixing it.
Please let me know if you have any additional information regarding this problem.
Posted by cantrell at 2:40 PM. Link | References
January 15, 2003
10% off ColdFusion MX or JRun MX Until January 15th
Use the promotion codes below to save on various Macromedia products (including server products like ColdFusion and JRun).
US Codes:
10% off Tools Products:
SP23CMMRTL
10% Off Server Products:
SP23CMMRSV
UK Codes:
10% off Auhtorware, Director, Fontographer, Freehand, Homesite, Fireworks and Dreamweaver:
SP23CMMRTL1
10% off Flash:
SP23CMMRTL2
Posted by cantrell at 12:05 AM. Link | References
January 11, 2003
Patch Available For ColdFusion MX Enterprise Edition Sandbox Security Issue
The <cfinclude> tag and the <cfmodule> tag will accept filenames with relative paths as arguments. ColdFusion MX does not check the Sandbox Security Files/Dirs permissions before including files with these tags. This could allow a template to access unauthorized data using these tags.
Find out more (and download the patch) at the URL below:
http://www.macromedia.com/v1/handlers/index.cfm?ID=23638
Posted by cantrell at 9:10 PM. Link | References
January 10, 2003
Some Tips on Installing JRun 4 and CFMX on OS X
Where is java_home? I can't find the Java binary!
Most people shouldn't actually need to know where it is. Open up the terminal and just type "java". If you see some usage instructions printed out, you are all set. Type "jar" and you should see something similar. Continue with the installation instructions and just leave out the "java_home" portion. In other words, the following command will work (assuming you are in the same directory as your jar file):
% java -jar coldfusion-j2ee-java.jar -i gui
(Don't actually type the "%". That represents your command prompt.) If, on the other hand, you see a "command not found" message, don't worry. Try typing this, instead:
% /usr/bin/java
and
% /usr/bin/jar
Now you should see the usage information. If it still doesn't work, however, type this:
% locate java | grep bin
This command will show you where any file called "java" is located in a directory with the word "bin" in it. If this doesn't work for you, you better just email me.
The files "java" and "jar" aren't actually located in /usr/bin -- they are symbolically linked from another directory. Although you don't need to know this, in case you are curious, the actual files are located here:
/System/Library/Frameworks/JavaVM.framework/Commands/
By the way, symbolic links (commonly referred to as "soft links") are a very convenient way to make files appear as though they are in different directories than they actually are (or even multiple directories). They are similar to shortcuts on Windows. To learn more, type "man ln" at the command prompt.
What am I supposed to do with this file called "index.cgi"?
If you downloaded a file called index.cgi from Macromedia's website, I'm guessing you are using Internet Explorer. "index.cgi" is the name of the program on Macromedia's server than initiates the download, and IE mistakes that for the name of the file being downloaded. Not to worry. Just rename it by your favorite renaming process to whatever the documentation tells you it should be named.
If you have other FAQs, email me, and I'll post answers.
Posted by cantrell at 1:13 PM. Link | References
January 9, 2003
New ColdFusion MX for JRun Performance Brief Published
See how ColdFusion MX for JRun performs and scales on platforms and multiple server installations. Go to the URL below and look under the "White Papers" section on the left-hand side:
http://www.macromedia.com/desdev/mx/coldfusion/j2ee/
Posted by cantrell at 9:12 PM. Link | References
January 7, 2003
Macromedia Announces CFMX and JRun for Mac OS X!
Yes, it's all true. Macromedia is releasing JRun 4 and ColdFusion MX for J2EE Application Servers for Mac OS X today. Below we see an enthralled audience of future ColdFusion developers learn how straightforward and powerful ColdFusion is during the CFMX portion of the DMX presentation (picture courtesy of Matt Brown). Here are some relevant links:
Press Release:
http://www.macromedia.com/macromedia/proom/pr/2003/jrun_osx.html
Download Page:
http://www.macromedia.com/software/servers/macintosh/
Installation Instructions:
http://www.macromedia.com/support/coldfusion/j2ee/cfmx-mac-onjrunandtomcat.html
DesDev Article:
http://www.macromedia.com/desdev/logged_in/ccantrell_macosx.html

Please note that the following ColdFusion MX features are not supported by the OS X version:
- Verity full-text search
- C++ CFX (and any Windows-specific features, includilng ODBC services)
- Crystal Reports integration
- COM connectivity
Nobody gives a more exciting keynotes than Steve Jobs (except Kevin Lynch, Rob Burgess and Jeremy Allaire, of course). Send me your ideas on what you think will be unveiled by Steve Jobs at Macworld (hardware or software), and the first two people to get it right will win a free DRK CD. I only have two to give away, so get your guesses in quickly. (I was guessing iSync 1.0 and a new version iCal, but those have already been announced.) I will announce winners here on the 8th or 9th.
Posted by cantrell at 9:12 PM. Link | References
January 3, 2003
Using the "var" Keyword to Scope Variables in ColdFusion Components
I've seen a fair number of posts recently regarding the use of the "var" keyword inside of ColdFusion components. I posted a pretty comprehensive explanation on cfcdev, but both for posterity and for those who might have missed it, I will re-post it here (along with some additional information).
All local variables used within a cffunction should be declared at the top of your function (under your cfargument tags), including query names. For instance:
<cffunction...>
<cfargument ... />
<cfset var queryName = "" />
<cfquery name="queryName">
some query...
</cfquery>
</cffunction>
It is a matter of scoping. Using "var" makes variables local to the function rather than being global in scope where they can stomp on other variables. It's the same in JavaScript:
function returnFoo()
{
var myVar = "foo";
return myVar;
}
In the function above, if you were to remove the var keyword, myVar would be a global variable, which you rarely want. Though it usually does not cause a problem in either JavaScript or ColdFusion, when it does, it can be extremely difficult to find the bug. You are much better off coding your CFCs, UDFs and JavaScript functions as tightly as you can.
The big difference between JavaScript and CFC functions regarding the use of var is that in ColdFusion, all variables declared using the var keyword have to be declared at the top of the function, whereas in JavaScript, you can declare them anywhere inside of a function.
User defined functions are similar to CFCs in that declarations must be made at the top of the function. They cannot be made anywhere else and they must be contained within a function (as opposed to just cfscript tags).
Posted by cantrell at 1:21 PM. Link | Comments (5) | References