Archive for the ‘Transfer ORM’ Category

TransferObject Decorators and the Mach-II Event-Bean

Saturday, November 7th, 2009

If you’ve been following this blog, you know I’ve been trying to get TransferObjects to function as Mach-II event-beans. A problem that has been solved, I’m happy to say, with the help of Transfer Decorators.

The approach I took was to supplement my TransferObjects with methods that would only be used by the event-bean during form-to-bean population, and only for non-string methods. For example, my Course object has a ‘cost’ associated with it, which is a numeric. I added the following to my Course decorator:

  <cffunction name="getCostString" returntype="string" output="false">
    <cfreturn getCost()/>
  </cffunction>
 
  <cffunction name="setCostString" returntype="void" output="false">
    <cfargument name="costString" type="string" required="true"/>
    <cfif isNumeric(arguments.costString)>
      <cfset setCost(arguments.costString)/>
    </cfif>
  </cffunction>

Note that the functions and argument both reference a costString instead of just a cost. The costString will only be used by the event-bean population code, which means you need to modify your form:input tag as well:

      <label for="costString">Cost to Participants</label>
      $<form:input path="costString"/>

Once this code is in place, the event-bean works like a charm, populating all the fields you need without throwing those pesky errors due to string-to-numeric or string-to-date mistypes. It even works for checkboxes:

      <label for="educationFormatString">Education Format</label>
      <cfloop query="educationFormatQuery">
	<form:checkbox path="educationFormatString" value="#educationFormatQuery.id#"/>#educationFormatQuery.format#
      </cfloop>
  <cffunction name="getEducationFormatString" returntype="string" output="false">
    <cfset var returnString = ""/>
    <cfset var formats = getEducationFormatsArray()/>
    <cfloop from="1" to="#ArrayLen(formats)#" index="i">
      <cfif returnString neq ""><cfset returnString = returnString & ","/></cfif>
      <cfset returnString = returnString & formats[i].getId()/>
    </cfloop>
    <cfreturn returnString/>
  </cffunction>
 
  <cffunction name="setEducationFormatString" returntype="void" output="false">
    <cfargument name="educationFormatString" type="string" required="true"/>
    <cfset var array = ListToArray(arguments.educationFormatString)/>
    <cfset clearEducationFormats()/>
    <cfloop from="1" to="#ArrayLen(array)#" index="i">
      <cfset addEducationFormats(getTransfer().get("gorgon.EducationFormat", array[i]))/>
    </cfloop>
  </cffunction>

Since I’m using decorators anyway, why not just overwrite the methods for setting/getting numeric/date/checkboxes and be done with it? Well, I figured the solutions for populating event-beans and regular TransferObject usage might be completely different depending on the complexity of the bean; why go cluttering up a bean with extraneous method overloading and type-checking when I could just add a couple of methods that are only specifically used by one instance of the framework, and then ignored the rest of the time? Basically it’s a trade-off, and neither side is well explored territory so I erred on what I thought was the side of caution. I’m completely open to trying it the other way if the data suggest I made a design mistake.

So there you have it, after three iterations of attempts I’m finally binding forms to TransferObjects without writing too much code. Now we get to move out of the kiddy-pool and start coding for real. Hopefully this project will go forward more smoothly and will be much more maintainable now that I have what I consider a clean design from the start.

We shall see.

You Can’t Proxy TransferObjects in ColdSpring

Thursday, November 5th, 2009

In an attempt to use TransferObjects as event-beans I created a class called TransferObjectBindingAdvice that would wrap around the setter methods called by the Mach-II event-beans, to be installed and called via the AOP hooks in ColdSpring. I had high hopes that this proxied object would be able to take the place of the more advanced data binding hooks that I would’ve liked to see in the upcoming 1.9 release of Mach-II.

I wanted to be able to verify that setters expecting a Date object would get a valid date string, sure; but I also wanted to be able to bind more complex objects to the event-beans. For example, I could pass in the TransferFactory in the aspect’s declaration in the ColdSpring configuration file, and use it on a setter for a many-to-many relationship which would be represented as a checkbox group on a form. Simply loop through the list of IDs passed as that checkbox group and build your relationship, all before the controller gets called.

Unfortunately Sean Corfield pointed out this approach was technically impossible. He told me that TransferObjects are generated dynamically and the methods only exist at runtime, so they can’t be proxied by ColdSpring.

Which brings me back to square one. What is the best way to handle form-binding cleanly in Mach-II? Do I need to create model objects and be done with it? Should I use Transfer decorators? Should I give up hope of using TransferObjects, the event-bean command, and the <form> taglib in harmony?

Nah. Next up: decorators!