Railo 3.1: Building your own Built-In-Function

July 23, 2009 · By webrat · 20 Comments

Ever wish you could just install a frequently used UDF to the server since you use it so much? Take any of the numerous UDFs found at CFLib.org for example. How about... QueryRowToStruct()? That's a pretty useful function. Wonder why they didn't build this in? With Railo 3.1 RC, you can build this in yourself. With this blog post, I'm going to outline two different installation concepts, server wide and local context.

First, server wide:

  1. Click on the "Download" link on QueryRowToStruct and you'll be prompted to download QueryRowToStruct.cfm
  2. For server wide installation, you'll want to put this in the following directory:
    {railo installation directory}/lib/railo-server/context/library/function/
  3. Restart the server (I had to, I'm going to verify if this step is really necessary or if it can be fixed :) )

Once installed, I shouldn't have to cfinclude or copy/paste that function anywhere. I can create a test.cfm in my localhost and run the example code on QueryRowToStruct description page.

Now, you may be in a particular situation where you can't have this server-wide because you share the server with other people or because there's a conflict. You could just install it to your local context. Each virtual host you make should have its own WEB-INF directory, so you have a global admin and a local admin.

You would repeat all of the steps above, except for #2, you'll want to install this here instead:

{your website root directory}/WEB-INF/railo/library/function/

Remember, you don't have to use anything specific from CFLib.org. You can write your own user defined function or install the one that you frequently use. I bet this makes you wonder if Railo 3.1 could give you the ability to create your own Built-In-Tag? ;) You can and there's been some changes, so I plan on investigating and outlining in a new blog post. If you want to see if you can figure it out for yourself, you can use Andrea Campolonghi's <cfajaxproxy> as a great example. This example includes installation directions and will only work on Railo 3.1.020 build or higher.

Update: The resin webserver doesn't need to be restarted, but the Railo servlet engine does. You can do this one of two ways, log into the admin portal and click Restart or via code: <cfadmin action="restart" type="server" password="serverPassword">

Tags: CFML · HowTo · Railo 3.1

20 responses so far ↓

  • 1 todd sharp // Jul 23, 2009 at 3:36 PM

    I think this is an absolutely horrid idea. Imagine the utter confusion when a developer sees foo() in an application that he works on and tries to go home and call foo() on his local install of Railo. Built in functions are global to all installs of a given version and (should be) well documented in the 'official' documentation. This just opens the door to some serious confusion, especially for less experienced devs. Or does Railo only market to the (5-10%) uber-smart 1337 devs??
  • 2 Garrett Johnson // Jul 23, 2009 at 3:45 PM

    Awesome yall!
  • 3 Dan G. Switzer, II // Jul 23, 2009 at 3:54 PM

    That's awful swank--this should be in every CF engine.
  • 4 Peter Bell // Jul 23, 2009 at 5:30 PM

    Hi Todd,

    Understand where you're coming from but that's just how CF is. It's a powerful, dynamic language and you can already do plenty of stuff to confuse the heck out of people. For some, oMM() will be pretty confusing as they try to find the methods that don't exist. If that isn't enough, try some object based mixins where you pass methods to objects at runtime. Again a powerful tool that can make an awful mess if it is misused.

    This is one more tool in the toolbox and comes with the same caveat as all power tools - be careful how you use it.
  • 5 Mark Drew // Jul 23, 2009 at 5:47 PM

    @Todd: Yes there is documentation, if you then go to the server administrator and look under the Documentation-&gt; function Documentation you will now see which functions are supported.

    Its a nice way to extend the functionality of the engine with out having to write more code.

    You could say the same thing for custom tags in any version of CF, where you can add random files in the /cf/CustomTags directory.

    Ok, the directory path isn't as nice but if it is a documented feature, surely its all good?
  • 6 Sean Corfield // Jul 23, 2009 at 6:38 PM

    @Todd, I'll just add that many people have been clamoring for ways to extend the core CFML engine for years. You could add built-in custom tags in Adobe ColdFusion by dropping your tag into cftags but you couldn't add built-in functions. So you could say we're following Adobe's lead but rounding out the feature set in a logical way!
  • 7 Gerald // Jul 23, 2009 at 7:37 PM

    Shwwweeeet. I have been wanting to do this for a long time.
  • 8 Dave Shuck // Jul 23, 2009 at 7:39 PM

    I think this is an excellent idea. Have you considered an approach where /lib/railo-server/context/library/function/ is the default directory, but you could define additional directories either in the admin or defined in the application source? Perhaps an additional attribute in the Application.cfc similar to how application specific mappings are defined?
  • 9 todd sharp // Jul 23, 2009 at 8:30 PM

    Hope I didn't come off rude guys - I guess I could have left the last sentence out.

    If I look at it like Peter laid out (be careful how you use it) then I guess it makes sense. Maybe there could be _some_ indicator though - perhaps exposed as metadata or some standard naming convention that would easily cue developers in on a custom function?

    Also, what happens if I try to override an existing built in function?
  • 10 Todd Rafferty // Jul 23, 2009 at 8:54 PM

    @Todd Sharp: It will override.
    ==================
    iif.cfm:
    &lt;cffunction name=&quot;iif&quot; access=&quot;public&quot; returntype=&quot;string&quot;&gt;
    &lt;cfreturn &quot;iif() sucks anyways. Use the ternary operator instead!&quot;&gt;
    &lt;/cffunction&gt;

    test.cfm:
    &lt;cfset foobar = true&gt;
    &lt;cfoutput&gt;#iif(foobar IS TRUE,DE('true'),DE('false'))#&lt;/cfoutput&gt;

    Result:
    iif() sucks anyways. Use the ternary operator instead!
  • 11 Todd Rafferty // Jul 23, 2009 at 8:55 PM

    Now, I need to find out if I can extend default functions. :D
  • 12 Todd Rafferty // Jul 23, 2009 at 8:58 PM

    @Dave Shuck: Feel free to suggest it via https://jira.jboss.org/jira/browse/RAILO or http://railo.uservoice.com/ or send me an email todd at getRailo.ORG with your request and I'll post it on your behalf.
  • 13 Todd Rafferty // Jul 23, 2009 at 9:08 PM

    I think the end result we all have to remember about this feature: With great power comes great responsibility. IMHO, I think the option to have that responsibility is awesome. This isn't required for you to use and you can certainly code without ever thinking about this option. I just know that, shoving UDFs into the application / request scope or create an object that holds a bunch of UDFs just to make sure you &lt;abbr text=&quot;Don't Repeat Yourself&quot;&gt;DRY&lt;/abbr&gt; seems a little silly.
  • 14 Oscar Arevalo // Jul 24, 2009 at 8:11 AM

    In my opinion, a much more nicer and cleaner route would be to make the developer &quot;import&quot; the custom functions (or packages) using some sort of declaration or keyword; that way the UDFs could be used directly on the code, but there would be an explicit declaration that tells anyone who sees that code where those foreign functions come from.
    In fact I think this should be the way any further extensions to the language should be made, instead of creating more and more functions (i.e. all those imageXXX() functions)
  • 15 denny // Aug 1, 2009 at 8:31 AM

    It might be worth mentioning that, as far as coolness from magical places is concerned, editing Component.cfc has been an option since 6.1 or so.
  • 16 Sean Corfield // Aug 1, 2009 at 9:45 AM

    @Denny, true, but that only makes UDFs available inside your CFCs, not within all CFML pages.

    Also, would you want to edit a core installed component like that? On the other hand, Railo lets you specify any CFC as the uber-base-class so you can easily redefine the behavior per-web-context which is much safer and more flexible.
  • 17 denny // Aug 1, 2009 at 8:16 PM

    @Sean, for development, and things like custom dump functions? Sure.
    Really tho, either way, you're doing a trade. Pragmatism vs. pattern.
    Sometimes it's a good trade, sometimes not. When is it which?
    To quote a famous CFer, &quot;it depends&quot;. =]
  • 18 David McGuigan // Aug 14, 2009 at 7:39 AM

    This is bad ass!!! I can't believe this got past Sean ( bravo Sean, I would've thought you'd've opposed something like this )! This capability is so appealing it hurts me slightly.

    I think for consistency's sake, though, you should implement it parallel to custom tags. A set of managed directories ( with a starter default sibling to the default custom tags store ) in the administrator as well as a per-app option ( this.customFunctionsPaths ). You should also be able to just add .cfc files and have it parse and use all cffunctions within it/them. Breaking up well-organized, related libraries from existing CFCs into 1 cff per .cfm is benefitless.

    Again, SPECTACULAR FEATURE. I tip my hat.
  • 19 Todd Rafferty // Aug 19, 2009 at 4:02 PM

    @David: I disagree that it should be implemented like custom tags, etc. This is something that has to be a conscience decision to use and abuse. Unfortunately, the Railo context needs to be restarted when you put the custom tag / function into those magic directories. Now, that being said, I'm sure Railo team will create a way to do this via cfadmin tag.
  • 20 Swapnil // Aug 27, 2012 at 7:01 AM

    Jul07steve miller I think it is all in the woridng. I would say, If this is your first time do not feel compelled to give. You are our guest. Give them the option, but even for Christians, we are to give out of a thankful heart not guilt.This is so much better than one well known mega church I visited where the pastor instructed the audience, If this is your first time here and don't know what to give you are to give at least 10% of your gross, not your net. Then we were instructed to wave our offering over our heads and turn to the person next to us, look at their money, and say, Is that all you are going to give? Don't you trust God more than that? We never went back.

Leave a Comment

Leave this field empty: