Adobe ColdFusion 10 to Railo 4

I’ve recently ported a moderately large ColdFusion application from Adobe ColdFusion 10 (ACF) to Railo 4.0.2. The whole process took about two days, including regression testing and fixes. Overall, I was very impressed with the level of compatibility, with almost all the issues arising from one of two things: the app server configuration, and very recent code written to the latest CFML standards. Even the latter was by no means bad. For example, anonymous functions declared in struct literals, something even ACF can be a little twitchy about, gave Railo no problems at all.

By far the most time-consuming issue was Apache mod_alias issue listed first. I spent the whole of a long day on this, with many a blind alley due to my imperfect understanding of how Apache and Tomcat work together. I finally pulled the plug when I caught myself about to download the Tomcat source code. I learnt a lot, but at the end of the day my preferred approach (which is to define all virtual directories in just one place, the Apache configuration) simply doesn’t work with Railo. Plan B works just fine, so all’s well that ends well.

So, here’s the list of (mostly minor) issues I encountered. Some of these may become bug reports when they grow up, some are just for noting.

Apache mod_alias

Apache Alias directives are ignored by Railo – which is completely expected behavior for an application server. Less understandably, Tomcat context aliases are also ignored, which leaves us with just Railo mappings. In ACF you can manage everything with Apache Alias directives (or IIS virtual directories), and ACF then uses these for all path resolution. Which is a pretty neat trick, really. I’d love to know how ACF does it, but I’m guessing it goes back and queries the apache virtual host for its mappings. In effect, ACF completely hides the distinction between file-oriented web serving, and URI-oriented application serving.

Function variables implicit toString()

ACF can interpolate function variables into a string. Railo crashes.

Use case: I use this for writing a trace log of what controller functions are invoked, useful for debugging routing.


	



	
	myfunc = test;
	
	writeoutput ("my func is #myfunc#"); // crash on Railo, on ACF prints something like "my func is cftest2ecfm1234911533$funcTEST@95a943"


Fix: use #myfunc.toString()#. ACF output is unchanged, Railo output is “test()”.

Nested functions

Railo crashes with a cryptic java.lang.ArrayIndexOutOfBoundsException, evidently straight out of the compiler.
Use case: nested functions are handy because they have access to the enclosing function’s arguments scope and local variables.


	
		
	
	
	



#test()#


Fix: refactor by promoting the nested functions to top-level functions and explicitly passing local variables to them as arguments.

Component search paths

ACF seems to search for components in the customtags directories. Railo by default does not.
Use case: no real use case. I suspect for most of us, the various flavours of name and path resolution are something we don’t comprehensively understand, we just tweak until things work.

Fix: There may be a way to get Railo to do this, but it’s just as easy (and a lot less magical) to add a cfimport tag.

“Is” test with java objects

ACF allows you to use java objects in “is” statements where strict type checking would suggest they can’t be used.
Use case: One way to deal with optional arguments is to set a default value of “”, and then check to see if the argument passed is “” or not.





	a string

	not a string


ACF will give “not a string”. Railo throws the “can’t compare complex object types as simple value” error. Note that for some built-in Java types (e.g. java.util.ArrayList) ACF will respond with the same error as Railo, no doubt because those types have special meaning in CFML.

Fix: Do the test using isObject(tmp) instead of tmp is "". Or, stop using empty string to mean undefined.

Equality of java objects

Even where java objects are type compatible, Railo won’t allow the use of “is”.


a = CreateObject("java", "com.medeserv.meseduframe.InteractionType").init("test");
b = a;

if (a is b) {
	writeoutput("same");
}

Crashes in Railo but works in ACF.

Fix: use a.equals(b) instead.

For/in loop with list


	for (i in "a,b,c") {
		writeoutput(i);
	}

Crashes in Railo, works in ACF 10.

Fix: Replace "a,b,c" with ListToArray("a,b,c")

Non-standard syntax for function argument default values


public void function test(
	required string a,
	any b default=""
) {
	variables.a = arguments.a;
	variables.b = arguments.b;
}

test("a");

if (variables.b is "") {
	writeoutput("empty");
}

Crashes in Railo, works in ACF. This is not the documented syntax for ACF, so the fix is obvious.

Fix: use the documented syntax i.e. string b="" rather than string b default="".

Whitespace in functions

(Added 30/5/2014)

If I do, for example:


   
   
   


#blah()#

Railo will output all the whitespace in the function. That is, the actual output will be:

.. 
.. 
..bogus

(using dots for spaces so you can see them). ACF by default will just output “bogus”. Add the output=”false” attribute to get rid of the whitespace. See https://issues.jboss.org/browse/RAILO-142 for some discussion of whose bug this is.

This is no biggy, but it can be very hard to debug if you don’t know about it. Log the return value of the function – no whitespace. Assign the return value the function to a variable then output the variable – no whitespace. Just to mess with your head even more, if you do this:

#Len(blah())#

the output is

.. 
.. 
..5

So basically, functions are potentially doing two things at once: the usual function-y things; and, if they are called in a cfoutput-like context, emitting bytes to the browser output. I’m a little surprised that being evaluated inside a parameter list of another function can be regarded as a cfoutput-like context, but really I only found this one because I got slack with my output attributes.

Leave a Reply

Your email address will not be published. Required fields are marked *