New features introduced with Railo

December 19, 2006 · By Gert Franz · 17 Comments

New Features for CFML with Railo OK, new engine... New features? Absolutely.
Since we started developing Railo as an improvement of other CFML engines and ourselves beeing kind of fond to CFML, its only natural that we wanted our own small improvements to be included in Railo. So we tried to look for things that bother us when using CFMX or BD. Below you will find a list of my top 5 improvements in Railo compared to the other CFML engines.

1. Creating populated Arrays, Queries and Structs

With Railo you have a very easy way of generating populated Array, Queries or Structs. Just compare the following two code fragments:
<cfset aNames = ArrayNew(1)>
<cfset aNames[1] = "John">
<cfset aNames[2] = "Tom">
<cfset aNames[3] = "Stephen">
<cfset stNames = StructNew()>
<cfset stNames.FirstName = "John">
<cfset stNames.LastName = "Wayne">
<cfset stNames.Children = ArrayNew(1)>
<cfset stNames.Children[1] = StructNew()>
<cfset stNames.Children[1].Name = "William">
<cfset stNames.Children[2] = StructNew()>
<cfset stNames.Children[2].Name = "Andrew">

Instead of this in Railo you can write the following:
<cfset aNames = array("John","Tom","Stephen")>
<cfset stNames = struct("Firstname":"John","Lastname":"Wayne","Children":array(struct("Name":"William"),struct("Name":"Andrew")))>

Or just imagine creating a Query from scratch:
<cfset qry = QueryNew("Name,Firsname,Age","String,String,Numeric")>
<cfset QueryAddRow(qry, 3)>
<cfset QuerySetCell(qry, "Name", "Wayne", 1)>
<cfset QuerySetCell(qry, "FirstName", "John", 1)>
<cfset QuerySetCell(qry, "Age", 47, 1)>
<cfset QuerySetCell(qry, "Name", "Riddle", 1)>
<cfset QuerySetCell(qry, "FirstName", "Tom", 1)>
<cfset QuerySetCell(qry, "Age", 16, 1)>
<cfset QuerySetCell(qry, "Name", "Potter", 1)>
<cfset QuerySetCell(qry, "FirstName", "Harry", 1)>
<cfset QuerySetCell(qry, "Age", 17, 1)>

Now the same thing in Railo:
<cfset qry = Query("Name":Array("Wayne","Riddle","Potter"),"FirstName":Array("John","Tom","Harry"),"Age":Array(47,16,17))>
Now that's a little shorter I guess. But this coding brings you one hickup. You will not be compatible to the other CFML engines unless you write three UDF()'s named Array() Struct() and Query() and build the functionality in there. But I guess it is not easy.
So just use Railo :-)

1a. The serialize function

Since this function is the reason we invented the functions array(), struct() and query(), I will address her a separate entry labeled 1a. This function turns everything it get's passed into a understandeable string. You can afterwards use this string in order to genearate the same variable content. Serialize() indeed generates correct CFCode. It is the opposite to evaluate(). Check this out: <cfquery name="getBlogEntries" datasource="blog">
   SELECT id, title FROM tblBlogEntries
</cfquery>
<cfdump eval="serialize(getBlogEntries)">

This ouputs the following:
serialize(getBlogEntries)
string query('id':array('C9495405-ABEB-4BC7-A0A6986ACC6E0326', 'A17DB4D2-1AC8-4ED3-B7342A55B5C68C0F', 'C635123B-8FE9-45E4-AC115A48422D2AA3', 'FA3B20D6-0797-48E9-A28FEC1064EE0A09'),'title':array('Railo archives', 'Railo Performance Test', 'Railo 1.1 Beta 1', 'New features introduced with Railo'))

This feature can be wonderfully used when storing content in a CF way. You can also use CFWDDX but the created string can be used anywhere.

2. CFDUMP with attribute eval

This is a short but handy one. I use it so often that it's one of my favorite enhancements. The following code lines are identical:
<cfdump var="#variables#" label="variables">
<cfdump eval="variables">

Short and easy. In addition to that Railo adds the function dump() to CFML which can be used inside CFScript and does exactly the same:
<cfscript>
   dump(variables);
</cfscript>
<cfdump eval="variables">

3. Enhancement to <cfloop>

I have often read newgroup entries concerning the reading of large files (often logfiles) in order to do something with the content. This is not easy to do using CFML. You can use Java for this purpose but you have to know how. So we invented three new attributes to the tag cfloop. The following code will explain the functionality:
The lines in the log from Line 500 to 560 are:<br>
<cfloop file="myLogFile.log" index="line" startLine="500" endLine="560">
   <cfoutput>#line#</cfoutput><br>
</cfloop>

The size of the file is not important. Railo loops row by row through the file and returns a line each loop iteration. Very handy.

4. <cffile action="info">


Very often you need to know the dimensions of images. Therefore you can use some java CFX or other Java code. With Railo you have the ability to read this information with the help of the tag cffile. The following example shows the usage:
<cffile action="info" file="railo.jpg" variable="info">
<cfdump eval="info">

The result is quite interesting:

Contents of the variable "info":
info.img.width:Image width
info.img.height:Image height
info.attributes:File attributes
info.datelastmodified:Date of last modification
info.name:Filename
info.size:Filesize in bytes

5. <cfadmin>

In order to access the Railo environment, the settings for a global and a local web you normally use one of the administrators. This is good but not enough, if you would like an installation routine to add a mapping, a datasource or something else. Therefore other engines use kind of undocumented features, partly useable without even having to know the administrator password. I find this extremly risky. Since when I'm a hoster, I don't want anyone to mess around with the settings I made. Therefore we introduced the tag <cfadmin>.
This tag is the only connection Railo has to the user in order to allow him to change settings within Railo (Ok, you could change the corresponding XML files and restart the server, but this is not an issue). So if a user wants to change the behaviour of Railo at runtime, he has to do it with the help of the tag <cfadmin>. The tag allways requires the password for the corresponding administrator.
Since the tag is so powerful and has so many attributes and actions, I will adress him an extra blog entry in one of my future posts. To give you a taste of what the tag <cfadmin> is capable of doing here is a list of all supported actions:

Possible actions for the tag CFADMIN
compileMappinggetLocalesremoveMappingupdateDefaultSecurityManager
ConnectgetMailServersremoveSecurityManagerupdateJavaCFX
createSecurityManagergetMailSettingremoveUpdateupdateMailServer
defaultSecurityManagergetMappingsresetPasswordupdateMailSetting
getComponentgetRegionalRestartupdateMapping
getContextesgetScoperunUpdateupdatePassword
getCustomTagMappingsgetSecurityManagersecurityManagerupdatePSQ
getDatasourcegetSerialstorageGetupdateRegional
getDatasourcesgetTimeZonesstorageSetupdateScope
getDatasourceSettinggetTLDsupdateComponentupdateSecurityManager
getDebuggetUpdateupdateCustomTagupdateSerial
getDefaultPasswordhasPasswordupdateDatasourceUpdateUpdate
getDefaultSecurityManagerremoveCFXupdateDebugverifyDatasource
getFLDsremoveCustomTagupdateDefaultPasswordverifyMailServer
getJavaCFXTagsremoveDatasourceupdateDefaultSecurity


BTW: The complete Railo Web and Server Administrators are written entirely with the help of the tag <cfadmin>. Well of course and with the help of HTML and other stuff. But there is no trick, no undocumented function used in these Administrators.

Tags: Features

17 responses so far ↓

  • 1 Andy Jarrett // Dec 19, 2006 at 12:40 PM

    I love the idea of looping a file line by line. What about XML files though? would there a way by doing them by node??
  • 2 Streit // Dec 19, 2006 at 1:28 PM

    Hi Andy

    Sure we have ;-)

    in Coldfusion the DOM (http://en.wikipedia.org/wiki/Document_Object_Model) is used to manipulate XML Objects (in all java based CF Engines).
    DOM first reads the full xml, translates it into a structure and then you can then use it. But with DOM you always first load the full xml into memory, even when you only want to read one single attribute. For large XML files this can cause problems.

    On the other hand in java we have the SAX parser (http://en.wikipedia.org/wiki/Simple_API_for_XML). Sax doesn't read the complete XML into memory and translates it afterwards. SAX only traverses the XML (like the cfloop-file), tag by tag, attribute by attribute, you can now register an event listener that will be invoked when traversing every tag or attribute.

    In Java this &quot;EventListener&quot; is a Java Class that extends the DefaultHandler (http://java.sun.com/j2se/1.4.2/docs/api/org/xml/sax/helpers/DefaultHandler.html)

    For Railo we have written a &quot;helper class&quot; that does the same with a Component (CFC).
    First you have to load the helper class &quot;railo.runtime.helpers.XMLEventParser&quot;, then you can register a CFC that is listening for speficic events and define the xml to read.

    Check out our example at http://www.railo.ch/download/XMLEventHandler-example.zip, this example only dumps out the xml, but you can also write to a db, create further components or whatever you want.

    greetings Michael
  • 3 Jeff Gladnick // Dec 19, 2006 at 3:28 PM

    Wow, the array/query creation is much improved very impressive.

    One suggestion: Your blog entries are getting a bit long, and in this case, somewhat unrelated. Why not break that blog entry into 5 separate entries.

    The blog will be updated more often, and users will come more frequently (im checking almost every day now), and it will be easier to read and comment on the topic you're interested in.

    Great job and keep up the good work!
  • 4 Gert Franz // Dec 19, 2006 at 4:03 PM

    Yes, Jeff you're right. This will make it a little easier to read.

    And I will pop up the comments in one of the future releases. I have to check how you do that with Raymond's blogCFC...
  • 5 Tom Chiverton // Dec 20, 2006 at 10:28 AM

    &quot;you cannot pass an undefined number of arguments to Functions&quot;
    Not true. If I write
    foo(bar)
    and
    foo(bar,baz)
    then the foo() method can look in the arguments structure.
  • 6 Gert Franz // Dec 20, 2006 at 1:32 PM

    Yes, Tom, you are absolutely right.
    It is possible to build the functions Array(), Struct() and Query() as UDF()'s. I removed that part assuming it would not be possible from the blog entry.

    Gert
  • 7 johnb // Dec 20, 2006 at 2:59 PM

    &lt;more /&gt; in your entry will split it into an intro and body style post.
  • 8 Gert Franz // Dec 20, 2006 at 3:31 PM

    Thanks John,
    I just started working with Raymond's blogCFC and I still do not know all the features. But as you can see I used your tip.

    Gert
  • 9 Christian Meis // Dec 20, 2006 at 10:35 PM

    Is the &lt;cffile action=&quot;info&quot;&gt; something only implemented in Railo 1.1? This isn't mentioned in the blog entry, but a 1.0.0.29 is throwing an error (&quot;source file xxx is not a file&quot;) for that - no matter if using GIF or JPEG files...
  • 10 Streit // Dec 20, 2006 at 10:59 PM

    Hi Christian

    are you shure that the file exist, this Exception is throwed when the file not exists

    in the exception you have a detailed path to the file that should be invoked
    for example in my case:
    &quot;source file [/Users/mic/Projects/Railo/webroot/railo.gif] is not a file&quot;
  • 11 Christian // Dec 20, 2006 at 11:25 PM

    You're right - I tripple-checked, and there's something wrong with the path (which does extend over about 10 directories deep, which made in less obvious).
    But the real reason seems to something else I stumbled over:
    This is a FuseBox 4.1 app. I.e. everything is included from the index.cfm effectively. I was working with the GetBaseTemplatePath() function, which should return the index.cfm in every nested file, but obviously doesn't.
    The &quot;GetDirectoryFromPath(GetBaseTemplatePath())&quot; I have in there does return the path to the subdirectory where the included file sits, not the path to the main index.cfm (which it should). I used this directory to construct the absolute path to the image in question. That was the reason that the path to my image was wrong.

    Can you confirm this is a bug?
  • 12 Christian // Dec 20, 2006 at 11:30 PM

    More strange things...
    As I was experimenting with Railo archives, I was clearing out the compiled cfclasses directory for the app. Now GetBaseTemplatePath() is returning the correct path always.
    I'll try to reproduce the error - further discussion by e-mail, as this is getting way off-topic here ;-)
  • 13 Paul Klinkenberg // Apr 11, 2009 at 3:27 AM

    Hi,

    The blog post you were talking about for the cfadmin tag, will you ever write it? I can't find any documentation about railo's code; am I missing something?
    Specifically, I want to use the 'enable/disable debug output' setting, and don't know where to start.
    Could you help me out here?
    Much appreciated!
  • 14 Erik-Jan Jaquet // Jan 14, 2010 at 5:23 PM

    Hi,

    In your blog entry you mention that you can use the CFADMIN tag to create a datasource. I see a getDatasource and a updateDatasource, but I do not see a setDatasource. How do I accomplish this?

    Kind regards,

    Erik-Jan
  • 15 Todd Rafferty // Jan 14, 2010 at 8:42 PM

    @Erik-Jan: As weird as this is going to sound, you would use updateDatasource to create a new datasource.
  • 16 Todd Rafferty // Jan 14, 2010 at 8:43 PM

    @Paul: CFAdmin tag documentation - http://www.getrailo.org/index.cfm/documentation/cfadmin-doc/
  • 17 Paul Klinkenberg // Jan 15, 2010 at 1:10 PM

    Hi Todd, thanks for the reply!
    In the meanwhile, I found it out, blogged about it, and even wrote a component to enable/disable debug output in both Railo and Adobe CF: http://www.coldfusiondeveloper.nl/post.cfm/enable-or-disable-debugging-output-in
    But great to get your reply; you are everywhere :-)

Leave a Comment

Leave this field empty: