Frank Fusion

Sunday, 20 April 2008

Scatting with ColdSpring

I really like ColdSpring - quiet, clean and powerful - mmmm (forgive me, I'm very tired). There is one thing that I have found that bugs me a little however; the verbosity of defining aspects and advisors.

Here's a quick xml sample of creating a really simple aspect and applying its advice to a bean:


<beans>
<!-- state checker advice and advisor -->
<bean id="stateChecker" class="aopxml.stateChecker" />
<bean id="stateCheckerAdvisor" class="coldspring.aop.support.NamedMethodPointcutAdvisor">
<property name="advice">
<ref bean="stateChecker" />
</property>
<property name="mappedNames">
<value>*</value>
</property>
</bean>

<!-- test component with proxy -->
<bean id="testerTarget" class="aopxml.tester" singleton="false" />
<bean id="tester" class="coldspring.aop.framework.ProxyFactoryBean" singleton="false">
<property name="target">
<ref bean="testerTarget" />
</property>
<property name="interceptorNames">
<list>
<value>stateCheckerAdvisor</value>
</list>
</property>
</bean>

</beans>

This is example is from my blogpost http://fusion.dominicwatson.co.uk/2008/03/stricter-oop-using-aop.html.

Worse still, if I want to apply my aspect to any another beans, I would have to explicitly do so by defining a proxy for each bean.

So what's the solution?

The first thing I thought was to have specific AOP xml tags for the configuration that would allow you to define aspects and instruct ColdSpring to automagically create proxies for you based on the component name rules you supply it.

I posted this thought on the ColdSpring google group and the reply made me look to the Spring framework (on which ColdSpring is based) - what does the Spring framework do? Well, it does pretty much exactly as I suggested:

http://static.springframework.org/spring/docs/2.5.x/reference/aop.html#aop-schema

So, with a minor adaption for ColdFusion (though not budging from the Spring Xml schema), here is how the above Xml example could look:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop">
<!-- 'new' aop tags -->
<aop:config>
<aop:aspect id="stateCheckerAspect" ref="stateChecker">
<aop:around pointcut="*.*" method="invokeMethod"/>
</aop:aspect>
</aop:config>

<!-- 'aspect' beans -->
<bean id="stateChecker" class="temp.stateChecker" />

<!-- 'regular' beans -->
<bean id="tester" class="temp.tester"/>
</beans>

The above XML defines an Around advice that will be applied to every bean and every method in the factory. Of course, different rules could be setup and I think the benefit is quite graphical.

This got me all excited and sent me on an all night coding spree. The result was a new ColdSpring bean factory that would take the Xml above and make it work. Its just a proof of concept and a little rough around the edges but it shows what can be done with reasonable ease (thanks to the excellent codebase already in ColdSpring).

The extended factory will indeed parse most of the aop elements defined in the Spring schema. I won't go into detail as they are very well documented in the Spring documentation that I linked to. However, here is a quick example of an aop:config that the extended factory will do stuff with:

<aop:config>
<aop:pointcut id="aopxmlPackagePC" expression="aopxml.*.Add*"/>
<aop:aspect id="stateCheckerAspect" ref="stateChecker">
<aop:around pointcut-ref="aopxmlPackagePC" method="invokeMethod"/>
</aop:aspect>
<aop:aspect id="someErrorCatchingAspect" ref="someAdviceBean">
<aop:pointcut id="thisAppServices" expression="com.myCo.thisApp.services.*.*"/>
<aop:after-throwing pointcut-ref="thisAppServices" method="afterThrowing"/>
</aop:aspect>
</aop:config>

You can download the simple working example here. You may need to create a mapping to whereever you unzip it (mapping called 'aopxml').

A disclaimer: this is completely unofficial and just a proof of concept - I'm just scatting. Enjoy :)

Labels: , , , ,

Saturday, 5 April 2008

Stricter OOP without AOP! Sort of ;)

I've been playing around with the idea of forcing my components not to add or remove variables from their 'variables' scope, other than when instantiated. Its something I'd like not to be possible and I'd like a ColdFusion error if it happens. I blogged my first effort at cracking it here:

Stricter OOP using AOP!

The biggest downside to this was complexity of implementation. While I don't mind hidden complexity, using AOP meant that I would have to explicitly declare that each of my objects was wanting to use this feature/'aspect' - the effort in doing so using ColdSpring far outweighed any benefit. This was a 'global aspect' that would be best placed in a global base class if possible.

So, how to wrap all of a component's methods automatically using a base class that it extended? The concept is similar to AOP but it would lack the hassle of having to apply AOP to my model. Of course, the hassle would be figuring out how to do it!

A very long and steep-learning-curved night later and I have a working version. It borrows from the concept used in ColdSpring's AOP implementation of creating a temporary file in order to create component methods on the fly (mixins). The use is slightly different however. The following is an attempt to explain the base class constructor as concicely as possible:

  1. Store copy of self in a state variable.

  2. Create temporary cfc file with methods of the same name as those in this component. The body of these methods have a single line that calls a 'CallMethod()' method, passing the method name and any args as arguments.

  3. Instantiate temporary cfc and delete the file.

  4. Overwrite the original component methods with those in the temporary component

  5. Removed methods used in this process from the component

The result is a component that appears unchanged (from the outside) but that has each of its methods replaced with a wrapper that invokes the samed named method on a copy of the original component.

Once this component has been written, implementation couldn't be much easier. Simply extend the component and call it's constructor from within the extended component and you're done.

Rather than have all that code be used specifically for monitoring a component's variables, I first created an uber-base class which for now I have called selfproxy. This does what I have described above but does nothing useful in the 'self proxied' methods. To do something useful (such as monitor the variables scope), I just extend the component and override its method interceptor.

This 'self proxying' mullarky lacks the precision and flexibility of AOP, but if you're painting with a broad brush it might be a useful thing.

A working example (tested on ColdFusion 8 running on Windows XP).

I'm just scatting on a theme here and would be interested to hear any constructive criticism ;)

Anyways, time for bed!

Labels: , , ,

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: , , , ,