Monday, October 31, 2005

Joe Rinehart introduces Arf!

With all of the hubbub about Ruby on Rails running around, it was only a matter of time until some smart person came along and wrote an implementation of Active Record for codfusion. Well it looks like that smart person is Joe Rinehart! Congratulations Joe, I’ve though a bit about active record myself and I’m sure that it was a lot of work. I’m really excited about messing around with it, and I think it’s another great step for the language in general. These are exciting times for coldfusion!

Friday, October 28, 2005

ColdSpring has a new home!

Dave has just announced the opening of www.coldspringframework.org, where you can get the latest stable release as well as cvs access to bleeding edge versions. You'll also find documentation as well as api docs, forums and a listserve. Dave really put a lot of hard work into the site, and I did a little design work as well. It looks great and I think it will be a great resource, so check it out!

Sunday, October 23, 2005

Announcing Team Fusion!

I’m not sure how people get into these super-hero programming alliances, so I started my own, Team Fusion! We’re very serious and action oriented, so we get an exclamation point as well as a star. Ok, I just wanted a cool logo for my coldfusion friends’ links and it sounded funny to me, so I killed an hour making it. But if anybody thinks I should add someone to the all powerful Team Fusion!, let me know!

Sunday, October 16, 2005

A few picks...

I just added a few picks from the frameworks conference and the following friday night to my flickr site. Dave and I split kind of early and went to my friend Erik's house in baltimore. Erik has somehow become the caretaker of a small circus train once owned by the famous side show attraction and baltimore native Johnny Eck. We had an amazing time drinking lots of beer, driving the train around his backyard, and getting a significant and well earned lecturing by Erik's wife. Sorry Charlotte!

Thursday, October 13, 2005

Model Glue is Good!

Ok, you already know that, but I've never worked with model glue before. I've been a mach-ii guy for a while and I like it. But now that coldspring is said to be super easy to integrate with mg, I figured, I better take a look. So here's a quick rundown of the day. 10:00, I slept late, OK? My kids stayed at their grandparents last night, it's the first day I've slept passed 7:00 in years! Anyway, at 10:00 I got model glue from svn, went straight for the ber! I figured I better clean up my dev machine at this point because I had 3 versions of coldspring and 2 versions of the record store example app on there, so that took a little while. I changed the layout of the model components a little and shifted around my root folder so both controller apps could share a config folder, as well as the coldspring config file.

After initial set up, I decided to read the quickstart guide, OK skimmed it, and figured I'd jump in and see if things would just work. I copied the 2 listeners in to the controllers.mg folder, replaced all the event.getArgs() with event.setValue() and put return values back in the event instead of returning them. I really like this part. I have had numerous discussions with mach-ii developers about putting data in the event in listeners, instead of all the request scope stuff. I have apps that do this exclusively, so this fits perfectly to me. I hit the views next, this was basically nothing. I just switched my event.getArg() to viewState.getValue(), which I do first thing anyway to get local references, so that was simple. I did all this before creating the xml, since I figured that's where the differences would lie.

Working with the xml file was really pretty easy, my only big problem was I read the quickstart guide too fast and didn't put my message tags in a broadcast block, so when I fired up the app, I got my layout view with nothing. Then I figured out the proper way to use the ViewCollection.getView() method and got my nice layout page with my error template. However, looking at some debugging I did see that my model components were completely wired up through coldspring no problem! After a little more kludging and some teasing in the coldspring irc channel I think I got into the swing of things pretty well. Since mg has no filters, that means more control logic in the controller, so it's a little heftier that the corresponding listener. Is that a bad thing? I don't think so. Why do I need xml to tie all that logic together anyway? A few things here and there kind of tripped me up, but after I felt a little more comfortable, I stopped trying to make mg fit the app that I already had written, and worked on it as a mg app instead. So after all that, I had a completely functioning app at 5, inheriting all the model goodness from the mach-ii app, logging, security and caching.

Overall impressions? I like it, as a matter of fact I really like it. One of the things that's great about coldspring is it's very lightweight, especially if you're using Sean's autowire controller for mg or our autowiring plugin for mach-ii (which will be in the next release). Coldspring just does its work and gets out of your way. Model glue seems to follow right along with that mantra, it's nice and light. Filters and plugins are very powerful, but maybe we don't need them so much. Maybe we don't need to rely on them so much, to be more precise. You need to concentrate on business logic, and model glue gets right out of your way, and lets you get to it!

Sunday, October 09, 2005

ColdSpring 0.2.1 with AOP Released!

Emerging from the depths of vaporware the coldspring.aop packages have been released along with a point release of ColdSpring! Dave has also included a Model Glue adapter, which you can read about on his blog here.

Download ColdSpring 0.2.1

Saturday, October 08, 2005

ColdSpring AOP Tutorial – Part One

Since I have already given an overview of ColdSpring’s AOP concepts, I’m going to just dive right into things. For part one of the developing with ColdSpring AOP, I’ll show how you can use a simple form of Advice called Before Advice to provide logging services to a model component. These examples are from the Klondike Records application that I showed at the frameworks conference last week, which we will also be releasing as an example application. I’ll show you how to define an Advice cfc, which will extends coldspring.aop.BeforeAdvice, how to define Pointcuts via Advisors in a standard ColdSpring config file, and how to use coldspring.aop.ProxyFactoryBean to wrap the Advice around methods of a target object by creating a Proxy object, containing the target. Think about the proxy object like an egg. The object you want to apply logging to would be the yoke and the Advice that provides the logging functionality is the egg white surrounding it. When the proxy factory creates this egg, and this is the great part, everything in you application thinks that it’s the same object that’s in the yoke! OK, so so let’s get right into it. First we’ll define a model component, which will be called CatalogDAO.cfc which we’ll then add logging services to.

<cfcomponent name="CatalogDAO" output="false">

  <cffunction name="init" access="public" returntype="Any" output="false">
    <cfreturn this />
  </cffunction>

  <!--- setters for dependencies --->
  <cffunction name="setDataSource" returntype="void" access="public" output="false" hint="Dependency: datasource name">
    <cfargument name="dsn" type="string" required="rue"/>
    <cfset variables.m_dsn = arguments.dsn />
  </cffunction>

  <!--- fetch a record --->
  <cffunction name="fetch" returntype="query" access="public" output="false">
    <cfargument name="recordID" type="numeric" required="true" />
    <cfquery name="qrySelect" maxrows="1" datasource="#variables.m_dsn#">
    SELECT QUERY …
    </cfquery>
    <cfreturn qrySelect />
  </cffunction>

  <!--- insert record --->
  <cffunction name="create" returntype="void" access="public" output="false">
    <cfargument name="record" type="net.klondike.component.Record" required="true" />
    <cfset var qryInsert = 0 />
    <cfquery name="qryInsert" datasource="#variables.m_dsn#">
    INSERT QUERY …
    </cfquery>
  </cffunction>

  <!--- update record --->
  <cffunction name="update" returntype="void" access="public" output="false">
    <cfargument name="record" type="net.klondike.component.Record" required="true" />
    <cfset var qryUpdate = 0 />
    <cfquery name="qryUpdate" datasource="#variables.m_dsn#">
    UPDATE QUERY …
    </cfquery>
  </cffunction>
</cfcomponent>


Obviously we’re skipping some details, but the point is that this is just a standard model component; we don’t extend anything or put any special code here. The component should be completely usable with or without AOP. In my example app you will see that this dao is used as part of a service component, which is used by the catalogListener in the mach-ii app. The nice thing about using AOP to provide logging is that neither the dao nor the service component that uses it will have any code in them pertaining to logging. They are only concentrated on fetching and storing records, cohesion. I like to use log4j, so I’ll create a LoggingService cfc to handle the configuration details and provide a common api to my Aspects. Also, if I want to switch this out to use cflog or another implementation, I can do that in one place. So here’s the LoggingService cfc, but I’ll skip showing how to actually configure log4j, since I have already shown that in an earlier post. This service basically just retrieves the logger and wraps its info() method.

<cfcomponent name="LoggingService" output="false">

  <cffunction name="init" returntype="net.klondike.service.LoggingService" access="public" output="false">
    <cfset var category = CreateObject("java", "org.apache.log4j.Category") />
    <cfset variables.logger = category.getInstance('net.klondike') />
    <cfreturn this />
  </cffunction>

  <cffunction name="info" access="public" returntype="void" output="false">
    <cfargument name=message" type="string" required="true" />
    <cfif variables.logger.isInfoEnabled()>
    <cfset variables.logger.info(arguments.message) />
    </cfif>
  </cffunction>

</cfcomponent>


Ok, now onto the AOP part. I will first create a Before Advice to retrieve information about the current method being invoked and send it off as the message argument to the logging service’s info() method. Here’s the loggingBeforeAdvice cfc.

<cfcomponent name="loggingBeforeAdvice" extends="coldspring.aop.BeforeAdvice">

  <!--- setters for dependencies --->
  <cffunction name="setLoggingService" returntype="void" access="public" output="false" hint="Dependency: security service">
    <cfargument name="loggingService" type="net.klondike.service.LoggingService" required="true"/>
    <cfset variables.m_loggingService = arguments.loggingService />
  </cffunction>
  <cffunction name="getLoggingService" returntype="net.klondike.service.LoggingService" access="public" output="false" hint="Dependency: security service">
    <cfreturn variables.m_loggingService />
  </cffunction>

  <!--- before() is called by the aop framework before method invocation --->
  <cffunction name="before" access="public" returntype="any">
    <cfargument name="method" type="coldspring.aop.Method" required="true" />
    <cfargument name="args" type="struct" required="true" />
    <cfargument name="target" type="any" required="true" />

    <cfset var arg = '' />
    <cfset var argString = '' />
    <cfset var objName = getMetadata(arguments.target).name />
    <cfloop collection="#args#" item="arg">
      <cfif isSimpleValue(args[arg])>
        <cfif len(argString)>
          <cfset argString = argString & ', ' />
        </cfif>
        <cfset argString = argString & arg & '=' & args[arg] >
      </cfif>
    </cfloop>

    <cfset variables.m_loggingService.info("[" & objName & "] " & method.getMethodName() & "(" & argString & ") called!") />

  </cffunction>

</cfcomponent>


This probably looks more complicated that it really is, so I’ll walk through it. First off we extend coldspring.aop.BeforeAdvice, which provides typing for the aop framework, and the ‘before’ method which you will overwrite. Next we have a setter and a getter which ColdSpring will use to inject the LoggingService, and the AOP framework will use to clone the Advice. The heart of this cfc, however, is the before() method, which gets passed a Method object, responsible for handling the actual method call, the argument collection passed to the method, and the target object which receives the method call. You can see that you have an amazing amount of power at this point. But all I’m going to do here is get the name of the target object through metadata, the name of the method from the Method object, and I’ll loop through the arguments to find simple values that I can print as strings. From this I make a string to pass to my loggingService that will look something like this: ‘[net.klondike.component.catalogGateway] getGenres() called!’. One important thing to note here is that Before Advice can alter the arguments going into the method at this point, but is not responsible for actually executing the method, even though it does have access to it. There is another type of Advice that should be used if you want control over method execution, called Around Advice, but I will delay that discussion until part two. Here’s where the advice of ‘be really careful’ comes in. No other object in you application has any idea of what is going on at this point, so you can really cause havoc, so be careful!

Ok, so now we have a DAO that we want to apply logging to, a simple loggingService, and a Before Advice to apply the logging service with. Now this may seem like a lot of work to add logging to a method, and that’s true. But this Advice can be applied to ALL you model components without writing any more code, logging method calls across your entire application. All that’s left is configuring these components. As I wrote in my earlier post, this is a matter of identifying Join Points, methods that you want to log in objects, which is done through Pointcuts, with an Advisor. An Advisor is basically a collection of methods and advice to apply to them. OK, so here’s the ColdSpring config file that will tie all this together.

<beans>

  <!—define the logging service -->
  <bean id="loggingService"
class="net.klondike.component.LoggingService" />

  <!--define the loggingBeforeAdvice and set its logging service property to reference the bean above -->
  <bean id="loggingBeforeAdvice"
class="net.klondike.aspects.loggingBeforeAdvice">
    <property name="loggingService">
      <ref bean="loggingService" />
    </property>
  </bean>

  <!—now define a NamedMethodPointcutAdvisor, set the advice property to the bean above, and set its mappedNames property to ‘*’ which will create a pointcut to match all methods excluding any init method -->
  <bean id="loggingAdvisor"
class="coldspring.aop.support.NamedMethodPointcutAdvisor">
    <property name="advice">
      <ref bean="loggingBeforeAdvice" />
    </property>
    <property name="mappedNames">
      <value>*</value>
    </property>
  </bean>

  <!-- to create the proxy object, first create our dao as the target object -->
  <bean id="catalogDaoTarget"
class="net.klondike.component.catalogDAO">
    <property name="dsn">
      <value>klondike</value>
    </property>
  </bean>

  <!-- now create a ProxyFactoryBean with the id catalogDAO, set the target to the catalogDaoTarget bean above, and give it ,the id of the NamedMethodPointcutAdvisor above in the list of interceptorNames -->
  <bean id="catalogDAO"
class="coldspring.aop.framework.ProxyFactoryBean">
    <property name="target">
      <ref bean="catalogDaoTarget" />
    </property>
    <property name="interceptorNames">
      <list>
        <value>loggingAdvisor</value>
      </list>
    </property>
  </bean>

  <!--now to use the proxy DAO, we give the id of the ProxyFactoryBean to the catalog service as the reference for the property catalogDAO -->
  <bean id="catalogService"
class="net.klondike.component.CatalogService">
    <property name="catalogDAO">
      <ref bean="catalogDAO" />
    </property>
  </bean>

</beans>


That’s it for the configuration. When you ask the ColdSpring bean factory for your catalogService, ColdSpring will create the ProxyFactoryBean and ask it to return a proxy object. The ProxyFactoryBean will in turn get a reference to the target object, the real DAO object, get the Advisor which contains the Aspect we created, causing the loggingService to be created, and will finally generate an entirely new cfc, which contains the target object, the proxy for the catalogDAO. This proxy object will be the same type as the target object and will contain all the same methods as the target, except that it will now flow every method through an instance of the loggingBeforeAdvice. If I want to add the same advice say to a gatewayObject, all I have to do is create another target object, and another ProxyFactoryBean and give it the same Advisor. If this doesn’t seem powerful enough for you, you can also create a new Advice, say a securityAdvice, and create a new Advisor, matching only the ‘save’ method, and give this to the ProxyBeanFactory we defined above. That would make that bean definition look something like this:

<bean id="catalogDAO"
class="coldspring.aop.framework.ProxyFactoryBean">
  <property name="target">
    <ref bean="catalogDaoTarget" />
  </property>
  <property name="interceptorNames">
    <list>
      <value>loggingAdvisor</value>
      <value>securityAdvisor</value>
    </list>
  </property>
</bean>


Adding the securityAdvisor after the loggingAdvisor causes it to be chained after the loggingAdvice, so if that Advice does something like throw an ‘InvalidCredentials’ error, the loggingAdvice will get a chance to write to the log before the method execution stops. So that’s just a small piece of the framework, the least powerful type of Advice we have available. After Advice is very similar to Before Advice, except that it occurs after method execution, giving you access to the return variable from the method as well as argument collection that was passed into the method. Wow, so that’s a pretty big blog post! I hope I’ve wet your appetite, and stay tuned because a super-prealpha-ubermethodology-oops-sorry-release is just around the corner!

Friday, October 07, 2005

Whoa, there’s a lot of code in there!

I just popped over to the fisheye site that Dave and I use to track development and there’s a lot of code going into that there cvs! From mid September there have been over 10K lines added! We’re closing in on 20K in the ColdSpring repository! Now granted, there’s a whole bunch of example apps, tests apps, and I think maybe Dave added the Macromedia pet store app, but the point is ColdSpring is very active right now. Expect big releases very, very soon. I’m doing my best to release the AOP framework this weekend, so stay tuned! I swear we’re not sleeping…

Bye the way, incase you haven’t been told this before, Fisheye’s the bomb! If you use cvs or subversion, you have to take a look at Fisheye. Of course if you don’t use some type of source control, um, I have no idea how you are managing your software development, you shouldn’t be doing that. Go get cvs. Right now!