Frank Fusion

Sunday, 30 March 2008

Stricter OOP using AOP!

An application I wrote recently was exhibiting a strange bug. When a user added contacts to the contacts database, details from previously entered contacts were being inserted in fields that were left blank for the new contact. The client had entered over a hundred contacts before they realised that this was happening and were somewhat worried. After some investigation, I tracked down the cause of the problem: an accidentally unscoped variable in a CFC method.

In Object Oriented languages, an object's properties are explicitly declared in its definition; they are integral to the make-up of the object. To add or remove an object's properties during its life could be seen as mutating the object and an undesirable behaviour in a strict OO design (I do not believe it is possible to do this in C++ but I may be mistaken).

Due to the way we emulate OO in ColdFusion, such mutation is exactly what happened when I clumsily used an unscoped variable in my CFC; the variable became part of my object's 'integral make-up' resulting in the sneaky bug.

This made me wonder: how could I restrict my objects from ever modifiying their definitions by deleting or creating new variables in the variables or this scope during their existance?

The first, and so far only, useable answer I have arrived at is through using Aspect Oriented Programming (AOP). My implementation uses the ColdSpring framework although it could be done without it. For the AOP savvy, I simply created an around advice object that checks the target object's properties before and after any method execution - if there is an inconsistency, an appropriate error is thrown. The pseudo code looks like this:

BEGIN
SET variablesBefore = Get object's variables
EXECUTE object's method
SET variablesAfter = Get object's variables

IF variablesBefore <> variablesAfter THEN throw error
END


If anyone is interested in the Source code I can post it, just a PITA to put code up using blogger! Better solutions on a postcard.

Dominic

Labels: , , , ,

Tuesday, 25 March 2008

XmlSearch and default Namespaces

This pops up frequently enough on the cf-talk list and around the blogosphere. To get an idea of the problem you can read this blog post that usually gets quoted as the answer:

http://www.talkingtree.com/blog/index.cfm/2005/11/18/XmlSearchNoNameNamespace

If you were keen, you may have noted the comments that refer to the technique not working when there are multiple, nested default namespaces. Take the following Xml for example:

<?xml version="1.0"?>
<foo xmlns="http://dominicwatson.co.uk/foo/">
<foochild>
<bar xmlns="http://dominicwatson.co.uk/bar/">
<barchild>lamb</barchild>
</bar>
</foochild>
</foo>

Doing XmlSearch(theXml, '//:foochild')will return results but XmlSearch(theXml, '//:barchild') will not. There are ways around this using XPath but they can become very cumbersome if your XPath is anything like complicated.

The source of the problem is ColdFusion's pretty poor provision of XPath goodiness. Other languages provide XPath querying methods that take a namespace mapping object as an argument. This allows you to define custom prefixes to use with the namespace URIs in your XPath queries. Here is a .net blog post as an example:

http://weblogs.asp.net/wallen/archive/2003/04/02/4725.aspx

Enter BetterXml 1.0!

In version 1 of my BetterXml components, just released, I have added the ability to add custom prefix mappings to Xml documents in ColdFusion (much in the way other languages allow). Using a betterXml object loaded with the xml above, we can now do something like this:

<cfscript>
oXml.MapNamespace('http://dominicwatson.co.uk/foo/', 'f');
oXml.MapNamespace('http://dominicwatson.co.uk/bar/', 'b');
results = oXml.Search('//b:barchild);
</cfscript>


Problem solved! You can download the latest version of the project on riaforge:

http://betterXml.riaforge.org/

Labels: , ,