I've been working towards this for quite some time, and last night I finally replaced ColdFusion with Railo on my personal server. By and large the switch went flawlessly. I made a few compatibility changes ahead of time and found and fixed a few issues subsequently, but really smooth overall. Even better, the memory footprint is significantly reduced with Railo, and I'm always memory constrained. I'll run through the migration process and the issues I had in a moment, but first a couple memory charts:
Conversion, as you might imagine, happend right about 20:30. The jaggies you see on the MySQL line are from me manually reducing and then reincreasing it's memory caches. I wanted to make sure it was mostly out of the way while I was converting, and willing to pay a little performance to get it. Unfortunately it makes the charts a little dirtier, but oh well.
The actual migration process was really simple. I spun up a Railo instance on my home computer, configured the server settings, set up my DSNs and mappings, and then shut it down. Then I stopped Tomcat on my production server, moved the WEB-INF folder out of the way, rsynced up Railo's WEB-INF from my home machine to take it's place, and restarted Tomcat. Done.
As for the CFML itself, I ran into a very small number of distinct issues, though they manifested in different ways:
- Railo doesn't support the column-as-array notation for queries that ColdFusion does (e.g. arrayMax(query["column"])), which I had used extensively in building Google Charts. Fortunately they expose valueArray to compliment valueList, as well as supporting a string (static or dynamic) rather than just the reference (all CF allows). This change made most of the instances cleaner, though you have to use a temp variable if your query isn't in an implicitly referenceable scope or nested within a complex structure, because the string must two-part.
- Railo doesn't support escaping keywords in queries of queries. Fortunately it's not as anal about keywords (e.g., allowing "get"), but if you want to alias a column to "count", you're screwed. Interestingly, you can happily select from a column named "count", just not alias to it. It also has some weird issues when combining aggregation and union on timestamp fields (they get truncated to dates).
- Railo arrays don't support the .subList method from java.util.List. It's implemented, but is hard coded to throw a RuntimeException. I beat this via a subList UDF:
<cffunction name="subList" output="false"> <cfargument name="a" /> <cfargument name="s" /> <cfargument name="e" /> <cfset var aa = [] /> <cfset var i = "" /> <cfloop from="#s + 1#" to="#e#" index="i"> <cfset arrayAppend(aa, a[i]) /> </cfloop> <cfreturn aa /> </cffunction>
It doesn't carry the same semantic as List.subList (which returns a view of the original list, not a new list), but for my purposes it was sufficient.
- Inline CFMAILPARAM attachments that use a contentId must have the id manually wrapped with angle brackets as Railo doesn't do the wrapping for you like ColdFusion does. Easily fixed, though this one was actually caught by an end user. Oops.
- "url is not a valid unscoped variable name as Railo assumes it means the url scope. You must either qualify it with a scope, or avoid the name. "cluster" has the same problem. As you might imagine, the url-scraping acquisition and cluster-based prioritization of PotD made these two names quite common, so I had to fix a lot of instances. But it was my fault for being lazy and not scoping to begin with.
- Railo respects and enforces an "abstract" attribute on CFFUNCTION that requires the body to be empty (just like CFFUNCTION within CFINTERFACE). I use an "abstract" attribute frequently for metadata inspection, but always implement the method with a single CFTHROW tag (since CF doesn't understand abstractness). The error message Railo generates is misleading ("cannot nest CFTHROW within CFFUNCTION" rather than "abstract functions cannot have a body"), but once I figured out what the issue was fixing it was simple.
- imageSetDrawingColor accepts three comma-seperated decimal values (e.g., "128,128,256″ for a blueish hue), but Railo does not. Easily fixed with formatBaseN.
All in all, a pretty transparent migration. I'm quite pleased. And now I'm in a position to get CFML-based ORM without having to fork over the $4,000 to upgrade to CF9, which is a big win for me. I'm sure little stuff will probably crop up over the next week or two, but all the major pieces (and all the minor bits I checked) seem to have worked flawlessly.
What monitoring script did you use to create those graphs? Looks rather useful!
Tom,
It's a little app I built myself: http://www.barneyb.com/mem_state/. It parses the output of `ps v -A O-v` and generates charts. Source can be found at https://ssl.barneyb.com/svn/barneyb/mem_state/trunk/ if you're interested.
Barney,
one sidenote. Railo does support the column-as-array notation for queries. I am using this myself a lot. So you can do something like queryname.columname[6] or so. Or isn't this what you were aiming at?
Gert Franz
Railo Technologies
gert@getrailo.com
Gert,
Sorry, I wasn't very clear. I wasn't referring to array notation to dereference a row's value from a column, but rather column-as-array notation for doing the same thing as Railo's valueArray. I.e. arrayMax(query["column"]) is valid on CF, while on Railo you need arrayMax(valueArray("query.column")). The complex case is nastier: arrayMax(struct.query["column"]) works on CF, but on Railo you need a temp variable temp = struct.query; arrayMax(valueArray("temp.column")).
That make more sense?
OK… I'll pass it on to Dev :-) Thanks for the clarification.
Gert
I already opened a ticket for it a few weeks ago. I think it was closed as wont-fix, but I can't recall for sure. It's a total hack that CF treats query.column and query["column"] in totally different ways depending on context, just handy in some cases.
Great and informative post. Thanks mucho.
Barney, I went to check out the source and it's prompting for a username/password.
Chris,
Did you get the right URL (https://ssl.barneyb.com/svn/barneyb/mem_state/trunk/)? Did you try to navigate upward (which WILL give you an auth prompt)? I checked the config and it's correct, and tried connecting and was not prompted for authorization, so I'm not sure what's wrong. But if you can help me understand the issue, I'll certainly get it fixed so can check the code (and no one else has the problem either).
Barney, I just tried again and it works. I was using the TortiseSVN Client. Weird. Thanks.
Hi Barney,
In your testing of Railo have you come across the issue of attaching a PDF created in memory to an email. In CF8 you can do CFMAILPARAM content="#pdfcontent_created_with_cfdocument#" but I'm unsure if this works in Railo. Before trying I thought I'd ask you, otherwise I'll have to resort to the good old CFMAILPARAM file="#pdf_created_by_cfdocument.pdf#". Would be nice if Railo supported this, the Wiki is somewhat unclear about this (or I don't fully understand what it says) ;-)
I know this is an old article, but this may help someone else looking for a solution coming from CF. Railo has a function called "arraySlice" that works pretty much the same way.