Archive for the 'railo' Category

The Latest ColdFusion Mindƒµ©Ҝ

It's pretty common knowledge that ColdFusion passes arrays to UDF by value, and not by reference like pretty much every other language.  It's a weird behaviour, but as long as you remember to write array-processing functions to be used like this:

<cfset myArray = modifyArray(myArray) />

instead of like this:

<cfset modifyArray(myArray) />

you'll be fine.  However, someone pointed out on the Railo mailing list that this behaviour is not constrained to UDFs.  Assignment behave the same way!  Yes, if you assign an array to another variable, you get a copy.  The only "assignment" that is exempt from this behaviour is if you use structInsert.

Consider this code:

<cfset a = [37] />
<cfset a2 = a />
<cfset s1 = {array = a} />
<cfset s2 = {} />
<cfset s3 = {} />
<cfset s4 = {} />
<cfset s2.array = a />
<cfset s3["array"] = a />
<cfset structInsert(s4, "array", a) />
<cfset arrayAppend(a, 42) />
<cfset System = createObject("java", "java.lang.System") />
<cfoutput>
<p>#System.identityHashcode(a)# - #a.toString()#               <!--- [37, 42] --->
<p>#System.identityHashcode(a2)# - #a2.toString()#             <!--- [37]     --->
<p>#System.identityHashcode(s1.array)# - #s1.array.toString()# <!--- [37]     --->
<p>#System.identityHashcode(s2.array)# - #s2.array.toString()# <!--- [37]     --->
<p>#System.identityHashcode(s3.array)# - #s3.array.toString()# <!--- [37]     --->
<p>#System.identityHashcode(s4.array)# - #s4.array.toString()# <!--- [37, 42] --->
</cfoutput>

At the end of this code, there are five distinct arrays, one containing 37 and 42, and the other four containing only 37.  The blue lines create the four copies, and the red line creates a new "pointer" to the existing array.  Then when the green line executes the original array has 42 added to it, which only affects 'a' and 's4.array', because the rest are copies.

On Railo, arrays are universally reference types, so there would only be a single array in the above example.  This is consistent with most other languages.

Ben Nadel - At It Again

Ben Nadel posted another interesting code snippet this moring.  I think Ben and I stand in agreement on the technique: NEVER EVER USE IT.  It leverages a horrible bug in ColdFusion's implementation of struct literals that I've blogged about previously.

Here's the snippet:

<cfset objConfig = {
  root = getDirectoryFromPath(getCurrentTemplatePath()),
  tags = objConfig.root & "tags/",
  com = objConfig.root & "com/"
} />

Yes, that actually works.  Let me repeat, NEVER EVER USE IT.  It is the devil incarnate, and only works because of a horrible implementation error in Adobe ColdFusion.  Note this is a ColdFusion bug, not a CFML language issue.  Railo implements struct literals correctly (as well as treating them as expressions instead of statements).  I don't know about OBD - the last time I used it there wasn't struct literal support at all, but it's been a while.

CFCOOKIE Bug in Railo

Found another minor bug in Railo today: CFCOOKIE doesn't accept a date passed to it's 'expires' attribute.  It happily accepts 'now', 'never', and a number of days, but not an actual date.  Submitted as JIRA-149.

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).

No MXUnit For Railo

I just pulled down the 1.0 release of MX Unit, and was most disappointed to see that it only works on ColdFusion:

...blah...
no definition for the class ... [coldfusion.cfc.CFCProxy] could be found
...blah...

Since I do most of my CFML development on Railo now, it kind of leaves me stuck.  Fortunately, CFCUnit works flawlessly, but with it's definitely the less compelling choice of the two.

ColdFusion Struct Literals Fail Again

ColdFusion introduced CFML struct and array literals in CF 8.  They sucked.  Assignment only, no nesting, and the use of '=' for key-name pairs instead of ':', like every other language including other parts of CFML.  CF 8.0.1 fixed the nesting issue, but not the others.  I've been trying to figure out why it's an assignment-only construct since CF 8 was released, and today I figured it out.  It's stupid.  Take this code (which fails on CF8):

<cfset s = "cat,dog,bird" />
<cfset s = {
  first = listFirst(s),
  rest = listRest(s)
}/>

If you were to convert that to the old non-struct-literal syntax, it'd probably look like this:

<cfset s = "cat,dog,bird" />
<cfset temp = structNew() />
<cfset temp.first = listFirst(s) />
<cfset temp.rest = listRest(s) />
<cfset s = temp />

That's what Railo does (or the equivalent), but ColdFusion evaluates it like this:

<cfset s = "cat,dog,bird" />
<cfset s = structNew() />
<cfset s.first = listFirst(s) />
<cfset s.rest = listRest(s) />

This will obviously fail, because ColdFusion is reassigning the 's' variable too early in the process.  In most cases it doesn't matter, but not all cases.  Worse, it doesn't give you a useful error.  Instead, it says "Complex object types cannot be converted to simple values", which while accurate, is totally perplexing if you consider the original snippet.

Note that this is a ColdFusion problem, not a CFML one.  Railo compiles it correctly (and it doesn't share the assignment-only requirement either).  OBD doesn't support literals at the moment.

Edit 2009/04/07: revised some text slightly.

CF Groovy 1.0RC (With Hibernate!)

I've just released 1.0RC of CF Groovy, including Hibernate support.  You can download it, or view the demo app.  The download includes both the demo and the runtime engine.

The big new feature is Hibernate support, of course.  Here are a couple snippets from the demo app.  First, the entity class:

package com.barneyb

import javax.persistence.*

@Entity
class User extends AbstractEntity {

    String firstName
    String lastName
    String email

    @Column(unique = true)
    String username
}

Then the engine setup (in code here, ColdSpring would be better):

<cfset application.cfhibernate = createObject("component", "HibernatePlugin").init() />
<cfset application.cfhibernate.setEntityPath(
    getDirectoryFromPath(getCurrentTemplatePath()) & "entities"
) />
<cfset application.cfhibernate.setColdFusionDsn("cfgroovydemo") />
<cfset application.cfhibernate.setAnnotatedClasses(listToArray("com.barneyb.User")) />
<cfset application.cfgroovy = createObject("component", "cfgroovy").init() />
<cfset application.cfgroovy.addPlugin(application.cfhibernate) />

Finally, doing some persistence operations:

<cfset request.sess = application.cfhibernate.getSessionForRequest() />
<g:script>
import com.barneyb.*

variables.user = new User([
    firstName: attributes.firstName,
    lastName: attributes.lastName,
    username: attributes.username,
    email: attributes.email
])
request.sess.save(variables.user)
request.sess.flush()
</g:script>
<cfset userList = request.sess.createQuery(
    "from User order by lastName, firstName, username"
).list() />

As you can see, very minimal fuss to do some pretty powerful things.  This only scratches the surface of what Hibernate can do; the full power of the tool is available (custom annotations, the full XML mapping capabilities, caching, etc.).

Another significant change is that all non-inline Groovy is precompiled into Java classes and loaded dynamically.  This gives you compiler checks on your Groovy code and engine startup, more helpful message for code errors, and some performance improvements.

Finally, as illustrated above, the <g:setPath> tag has been superceded by an explicitly managed CF Groovy runtime.  This gives you complete control over the lifecycle of the engine, which lets you target performance in production and development speed in development.  You can still use <g:setPath> instead of managing the runtime yourself, but that should be considered a deprecated practice.

CF Groovy Takes a Nap

After close to two weeks of struggling, I finally managed to deploy pure source to a CFML runtime (Railo, in this case), and get Groovy entities in and out of the database with Hibernate.  No compliation, no IDE, no development-mode server, just my Groovy source along with a hacked up CF Groovy.  This is very exciting for me, because while Groovy is cool and all, CF's dynamic nature has become a must have.

I don't have source to download yet, just a horribly hacky proof of concept, but here's what the user of the "framework" does.  First, create your entity:

package com.barneyb
import javax.persistence.*

@Entity
class Person {

  @Id
  @GeneratedValue
  Long id
  Long version
  String name
  Date dob

  def getAgeInSeconds() {
    (new Date().getTime() - dob.getTime()) / 1000
  }

  def getAgeInDays() {
    ageInSeconds / 86400
  }

  def getAgeInYears() {
    ageInDays / 365.249
  }

  String toString() {
    "$name is $ageInYears years ($ageInDays days) old"
  }

}

That's the same class as my initial CF Groovy demo used, except with the of JPA annotations added.  Because I'm binding to Hibernate, you can use any Hibernate-supported annotations, but I opted to stick with vanilla JPA.  Now we need our hibernate.cfg.xml, which is totally stock:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
  "-//Hibernate/Hibernate Configuration DTD//EN"
  "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

  <session-factory>

    <property name="current_session_context_class">thread</property>
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    <property name="show_sql">true</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/dbname</property>
    <property name="hibernate.connection.username">username</property>
    <property name="hibernate.connection.password">password</property>
    <property name="hibernate.hbm2ddl.auto">update</property>

    <mapping class="com.barneyb.Person" />

  </session-factory>

</hibernate-configuration>

You could also map your classes manually with XML, if you wanted, but for the sake of simplicitly, I've done it all with annotations.  You'll also notice the database connection information embedded directly in the file. This is far from ideal.  I'm hoping to extract it from a CFML DSN, but that might only be possible on Adobe ColdFusion (via the Admin API).  The last thing is the test script:

<g:script>
  import java.text.SimpleDateFormat

  import org.hibernate.*
  import org.hibernate.cfg.*

  import com.barneyb.Person

  sdf = new java.text.SimpleDateFormat("yyy/MM/dd")
  sdf.lenient = true

  def sf = new AnnotationConfiguration()
      .configure().buildSessionFactory()
  def sess = sf.openSession()
  def tx  = sess.beginTransaction()
  sess.createQuery("delete Person").executeUpdate()
  sess.save(new Person(
    name: attributes.name ?: "Barney",
    dob: sdf.parse(attributes.dob ?: "1980/06/10")
  ))
  tx.commit()
  sess.close()
  sf.close()
</g:script>

No need to compile anything, no need to drop JARs all over your server, nothing.  Write, refresh, persist.  That includes adding new entities, new properties to existing entities, etc.

It's not ready for public consumption at the moment, but that's my top "free time" priority.  For the incredibly impatient, there's a branch in my SVN repository with the current source.  Don't expect anything pretty.  ;)

Railo 3 Beta 2

Railo dropped a second beta last night. Get it here. They've also added a WAR download, though it only works when installed into an existing "express" installation. Hopefully that'll get addressed for the next release.

A couple shining points about the runtime:

  • Array and Struct literals (the [...] and {…} notation) are expressions, exactly as they should be, unlike other CFML runtimes (cough…Coldfusion…cough).
  • Arrays and Structs now implement java.util.List and java.util.Map respectively, greatly easing Java integration. This also allows the Comparators CF Groovy example I published to work correctly on Railo.