Monthly Archive for November, 2008

Railo-147 Resolved

To quote my post Tuesday about Railo bug 147:

Railo has an issue with non-defaulted, non-required, numeric method arguments that are omitted from a call.  I added it as bug 147 in JIRA.

Turns out I was a bit incorrect - I'd forgotten that method was proxied by ColdSpring's AOP engine (which is exactly what's supposed to happen with AOP), and that's where the bug actually resided.  Railo was returning "[runtime expression]" as the default value for the argument within the function metadata, which ColdSpring was faithfully writing into the proxy method that it generates.

In any case, got a JIRA update from Michael to say it's been resolved, so the next build should have it fixed up.

ColdFusion to Railo

Just completed my first port of a major app from ColdFusion to Railo.  Time elapsed from downloading the Railo WAR to my dev box to see if the app would run to reenabling the prod instance: 1.5 hours.

Downloaded the WAR, unpacked it into my webroot, unzipped a new Tomcat, set up a Context pointer to my webroot, and fired it up.  Worked like a charm, and after adding my DSN to the config file, the app was running.

I had to make a couple minor tweaks for Railo compatibility:

  1. Railo seems to stick getContextRoot() into cgi.script_name automatically, so I had to remove the function calls in my 'self' variable's definition
  2. Railo has an issue with non-defaulted, non-required, numeric method arguments that are omitted from a call.  I added it as bug 147 in JIRA.

After that I just checked /WEB-INF/ and the tweaks into Subversion for deployment to production.  On my prod server I did basically the same process: unzip  a Tomcat, set up a Context pointer to the existing webroot, configure an init script, and fire it up.  Once Tomcat was happy (first try!), I took the Alias directive out of my Apache config, replaced it with a mod_rewrite proxy directive, redeployed the app (to get /WEB-INF/ and the tweaks), changed the DSN credentials, and bounced Apache.  Done.  Live.  No errors.  And cookie-based session tracking worked flawlessly across the engine replacement.

Needless to say this is a HUGE win for both me and Railo.  I've been writing new stuff to Railo, but hadn't ported anything substantial because I didn't want to deal with the pain.  But with how minor the pain is, it's totally overshadowed by the benefits of separate contexts (or VMs!) per app.  That was never really an option with CF because of the memory footprint (350MB for CF vs 60MB for Railo).

jQuery's Autocomplete's Undocumented source Option

Yesterday I replaced an instance of my ComboBox widget with a jQuery Autocomplete.  A sad day it was.  However, I saved a JS file and a few K of download, so it was worth it.  Unfortunately, it's missing a fairly important bit of functionality: the ability to order the list of options.

If you're doing an Ajax-based complete, you can obviously order the options server-side and jQuery will happily spit them out in the same order.  In my case, however, the list of choices is static and fully known in the client.  jQuery only provides options for "url" (the URL to request for options) and "data" (a static array of options).  There's no half-way, where you can supply a function to return for the current term.

However, after spending a while digging around inside the internals of the widget, I discovered the undocumented "source" option (and it's complement, the "parse" option).  It's a function that will be called to get the options for the current term.  However, it seems to be undocumented, and is pretty tightly bound to the internal implementation of the widget.  Specifically, your return value structure has to be the same as the structure returned by the internal "parse" method.  Note this is NOT the 'parse' option I mentioned above.

If you don't supply data or a URL, the function passed as "source" will be invoked, and it's result will be either passed through the function passed as "parse" (if there is one), or returned directly.  That result must be an array of objects that represent the options.  Each object must have "data", "value", and "result" keys.  The first is an array of row data (passed as "row" to various callbacks), the second is the display value (what would come back from "formatItem"), and the third is the result value (what would have come back from "formatResult").

Mess though this is, it does let you execute arbitrary code to build the option list, including supplying a custom order, which is what I needed.  More specifically, I wanted to order tags that began with the search value before those that contained the search value in the middle.  Here's my code, just for reference.  "tagList" is an array of strings that are available for selection and the "tag" argument is the current value to be autocompleted.

jQuery("selector").autocomplete({
  source: function(tag) {
    var map = {
      first: [],
      internal: []
    }
    for (var i = 0; i < tagList.length; i++) {
      var pos = tagList[i].toLowerCase().indexOf(tag.toLowerCase());
      if (pos >= 0) {
        map[pos == 0 ? "first" : "internal"].push({
          data: [tagList[i]],
          value: tagList[i],
          result: tagList[i]
        });
      }
    }
    return map.first.concat(map.internal);
  },
  matchSubset: false // this is important
})

Eclipse and JUnit

I started building a little Java app this evenings.  First time I've done Java SE work in a long time, and it's kind of nice.  Not sure why I picked Java instead of Groovy, but whatever.  Probably the same reason people go home for the holidays.

In any case, being the good developer I am, after designing the core interfaces, I wrote some unit tests using JUnit 4.  Right click on the file in Package Explorer, hit "Run as JUnit Test" and it fires up in a fast view to show you how you did.  All very handy.  After a few tests, i figured I should build some test suites, but I really didn't want to.  I don't know about anyone else, but I always end up forgetting to register some test or another, and then I create a regression that would get caught by that test, but since it's not registered it doesn't run, and it's just bad.  So I didn't, and continued to run the tests individually.

After half an hour or so so, I had the idea to try right clicking on a package and see if I could run all the test in that package.  I was quite pleased to see that you can.  Same thing works at the source folder and project levels.  Little efficiency improvements like that make Barney a happy boy.  Of course, still have to write the suites if I want to run them from CI or the like, but this project at least will very likely never get there.

Are you a CF Rock Star?

Mentor Graphics (where I work) is looking for a top-notch CF/Flex/Java architect/developer to join our team.  There are five of us at the moment, and we need another one.  This is an on-site position in Wilsonville, OR (just south of Portland), and relocation assistance is available.

The "official" qualifications are pretty typical, and largely waive-able for the right candidate.  So here are the "real" ones:

  • know what ColdSpring (or Spring) is and understand why you'd use it
  • be able to compare and contrast, at least at a high level, a few Front Controller frameworks
  • articulate a considered opinion on JS vs. Flash for RIAs in different scenarios
  • know your way around Java SE and the Servlet API (more of JEE a plus)
  • explain why you'd use SOAP in a pure-CFML application that a single team owns from top to bottom
  • use CFEclipse because of Eclipse, not the reverse

Our work environment is casual.  We share a single "office" and spend a lot of time sitting at each other's desks working together and we have a dedicated "war room" for more in-depth discussion and planning (and a Wii for unwinding).  If you tuck your shirt in, you're probably overdressed.

Compensation is quite good, both the raw salary and the myriad benefits.  Mentor is a large, stable company, but without the Dilbert-esque nature.  The org chart is a meritocracy, pragmatism reigns supreme, and most of of the decisions (technical, architectural, etc.) are driven from the bottom up, not top down.

If this sounds like a place you want to work, shoot me a resume at bboisvert@gmail.com and I'll forward it to Ron.  The hiring process is simple: resume, phone screen, on-site interview.

Joe on ORM

Joe Rinehart made a very good post about the state of "ORM" in CFML.  Namely, that there isn't any.  There are several abstract persistence frameworks for CFCs, but no real ORM solutions.

Like Joe, I've been using Hibernate/Groovy to back a lot of CFML applications of late and it's wonderful.  Certainly not without some downsides, but having transitive state-based persistence is absolutely fantastic.  And Goovy makes implementing your entities so much easier with implicit getters/setters, non-tag-based syntax, rich types (for building schemas automatically), and a whole pile of syntactic sugar.