Remote Synthesis
Search my blog:
Viewing By Entry / Main
Aug 20, 2009

A Beginner's Guide to the ColdSpring Framework for ColdFusion

If you ask a ColdFusion developer what they think of the ColdSpring framework, chances are that you will get one of two answers. Either they will gush about how useful it is and how they couldn't imagine building large-scale applications without it or they will say they don't really understand the point. In my experience this is because until you encounter the problems that ColdSpring solves, it can seem like a complex solution to a problem you never had. However, when you begin building more complex applications, the benefits of a framework like ColdSpring quickly become apparent.

This guide aims to introduce the problems that ColdSpring can help to solve and provide enough information to get started using it. We'll begin by looking at how these problems are generally managed without ColdSpring and then compare that to a sample with ColdSpring to hopefully illustrate some of the benefits. While I won't go into great depth and our example applications are simple, we'll cover a number of areas including configuring ColdSpring for managing dependencies, aspect oriented programming and generating remote proxies.

Note: this article and samples are based upon a presentation I have developed, so if you have a user group that you think would benefit from this information, feel free to contact me about presenting.

What Problems Does ColdSpring Solve?
Where most people get the most mileage out of ColdSpring is specifically its ability to centralize and simplify management of complex object dependencies. For example, if you have an application that has an authentication service component (CFC) that is dependent on a user service, ColdSpring can help you manage that.

You may wonder why you need a framework to manage something so simple as passing an dependency in via a constructor/method or initializing it in the constructor. The thing is that this example, where service A is dependent on service B is far too simplistic to cover the benefits of using the framework. In a real world application, service A is dependent on services B through L and vice-versa. It is when you start dealing with this web of dependencies in a typical large application that using ColdSpring really pays off. In fact, I think its safe to say that the larger your application, the bigger the payoff.

Managing Dependencies Without ColdSpring
First, let's look at the problem by examining how you might manage dependencies without ColdSpring. Our example "application" is has uses the sample "cfartgallery" datasource that is installed by default with ColdFusion. Our code has two objects, "art" and "artist" whereby an art has an artist. Furthermore, we have created a DAO and Gateway CFC for the art and artist objects as well as a service which is our API for accessing both art and artists. The code for all these examples is available as a zip or via SVN at my Google Code repository.

The dependencies that exist within this simplistic example are as follows:

  • ArtDAO requires ArtistDAO;
  • ArtService requires ArtDAO, ArtGateway, ArtistDAO and ArtistGateway;
  • ArtService, ArtDAO, ArtGateway, ArtistDAO and ArtistGateway all require a string for the DSN.

Keep in mind that this example is simple and we already have a good number of dependencies to handle. If you extrapolate that out for a typical application you can see how complex this issue can get.

I have developed two variations of handling these sorts of dependencies without ColdSpring. The first is where we put all the createObject code in the constructor (i.e. init) and the second has the dependencies passed in. Let's look at the init() method of the service in the first option:

<cffunction name="init" access="public" output="false" returntype="com.nocs.artGalleryServiceOption1">
   <cfargument name="dsn" type="String" required="true" />

   <cfset variables.artDAO = createObject("component","com.nocs.art.artDAO").init(arguments.dsn) />
   <cfset variables.artGateway = createObject("component","com.nocs.art.artGateway").init(arguments.dsn) />
   <cfset variables.artistDAO = createObject("component","com.nocs.artists.artistDAO").init(arguments.dsn) />
   <cfset variables.artistGateway = createObject("component","com.nocs.artists.artistGateway").init(arguments.dsn) />

   <cfreturn this />
</cffunction>

As you can see, while we pass in the datasource string to the service and then to each of the objects, we then create each of the dependencies independently. The same goes for the init() of artDAO which, as we mentioned, requires the artistDAO:

<cffunction name="init" access="public" output="false" returntype="com.nocs.art.artDAO">
   <cfargument name="dsn" type="string" required="true">

   <cfset variables.dsn = arguments.dsn />
   <cfset variables.artistDAO = createObject("component","com.nocs.artists.artistDAO").init(arguments.dsn) />

   <cfreturn this>
</cffunction>

This, in and of itself, poses one of the issues with this approach, which is that we duplicate creating the artistDAO when we could reuse that. Additionally, if we were to make a change to where artistDAO is stored or what arguments it requires, we already need to replicate those changes to all copies of the createObject code. In a large application, this can become unmanageable.

Perhaps, you say, we can mitigate some of these problems by passing in the dependencies instead. Personally, if I am forced to build an application without ColdSpring, this is my preferred solution. In this case, the service's constructor looks like this:

<cffunction name="init" access="public" output="false" returntype="com.nocs.artGalleryServiceOption2">
   <cfargument name="artDAO" type="com.nocs.art.artDAO" required="true" />
   <cfargument name="artGateway" type="com.nocs.art.artGateway" required="true" />
   <cfargument name="artistDAO" type="com.nocs.artists.artistDAO" required="true" />
   <cfargument name="artistGateway" type="com.nocs.artists.artistGateway" required="true" />

   <cfset variables.artDAO = arguments.artDAO />
   <cfset variables.artGateway = artGateway />
   <cfset variables.artistDAO = artistDAO />
   <cfset variables.artistGateway = artistGateway />

   <cfreturn this />
</cffunction>

However, the logic for creating those objects still needs to exist, so, in the case of the example code, we have it in nocsoption2.cfm:

<cfset dsn = "cfartgallery" />
<cfset artistDAO = createObject("component","com.nocs.artists.artistDAO").init(dsn) />
<cfset artDAO = createObject("component","com.nocs.art.artDAO").init(dsn,artistDAO) />
<cfset artGateway = createObject("component","com.nocs.art.artGateway").init(dsn) />
<cfset artistGateway = createObject("component","com.nocs.artists.artistGateway").init(dsn) />
<cfset artGalleryService = createObject("component","com.nocs.artGalleryServiceOption2").init(artDAO,artGateway,artistDAO,artistGateway) />

While this, in my opinion, is preferable to the creatObjects in the constructor, you'll notice that it can get messy and complex as the application grows. Another issue is that the order is important. For example, since artDAO needs artistDAO, we create artistDAO first. This is simple to resolve, but once you have a large number of components each with their own dependencies it can become complicated to ensure that everything is created in the proper order to accommodate those dependencies.

Simple Dependency Injection with ColdSpring
Now let's take a look at how you can manage these same dependencies using ColdSpring. Of course, your first step is to download the latest version of ColdSpring from the ColdSpringFramework.org site (note that as of this writing, the version is 1.2) and add it to your site.

Next, let's take a look at how to configure ColdSpring. ColdSpring is configured using an XML file. In the example below I have explicitly defined the dependencies of each object ColdSpring manages as constructor arguments (i.e. passed to the init() method) - as you can see, for example, in the artDAO definition which includes a reference to artistDAO. One important thing to note is that the order in which the objects are defined is no longer a concern.

<?xml version="1.0" encoding="UTF-8"?>

<beans>
   <bean id="artDAO" class="com.withcs.art.artDAO">
      <constructor-arg name="dsn"><value>${dsn}</value></constructor-arg>
      <constructor-arg name="artistDAO">
         <ref bean="artistDAO"/>
      </constructor-arg>
   </bean>
   <bean id="artGateway" class="com.withcs.art.artGateway">
      <constructor-arg name="dsn"><value>${dsn}</value></constructor-arg>
   </bean>
   <bean id="artGalleryService" class="com.withcs.artGalleryService">
      <constructor-arg name="artDAO">
         <ref bean="artDAO"/>
      </constructor-arg>
      <constructor-arg name="artGateway">
         <ref bean="artGateway"/>
      </constructor-arg>
      <constructor-arg name="artistDAO">
         <ref bean="artistDAO"/>
      </constructor-arg>
      <constructor-arg name="artistGateway">
         <ref bean="artistGateway"/>
      </constructor-arg>
   </bean>
   <bean id="artistDAO" class="com.withcs.artists.artistDAO">
      <constructor-arg name="dsn"><value>${dsn}</value></constructor-arg>
   </bean>
   <bean id="artistGateway" class="com.withcs.artists.artistGateway">
      <constructor-arg name="dsn"><value>${dsn}</value></constructor-arg>
   </bean>
</beans>

I should note at this point that if you think its too much work to write this (and your DAO's and other components) by hand, my Illudium PU-36 Code Generator will handle much of this for you (and it has a handy ColdFusion Builder extension now as well). Another item you may notice is the use of a constructor argument for DSN that passes a value "${dsn}". This is a handy feature in ColdSpring whereby you can create a structure containing property keys that can be referenced in your configuration file like that for handling constants, such as your DSN. So "${dsn}" is mapped to the "dsn" key on my properties structure defined below.

<cfset properties = StructNew() />
<cfset properties.dsn = "cfartgallery" />
<cfset beanFactory = CreateObject('component', 'coldspring.beans.DefaultXmlBeanFactory').init(defaultProperties=properties) />
<cfset beanFactory.loadBeans('/config/coldspring-option1.xml') />

The code above is the code used to instantiate the ColdSpring "beanfactory" where you will get any of the components managed by ColdSpring. For example, the following line loads the artGalleryService defined in the above configuration with all its dependencies already injected:

<cfset artGalleryService = beanFactory.getBean("artGalleryService") />

Now, I already mentioned that, if you thought the configuration file was too verbose or too much work, you could have Illudium do much of the work for you. However, ColdSpring itself has an "autowiring" feature that eliminates the need to explicitly define dependencies in your configuration file, eliminating much of the XML configuration needed. You simply need to have a setter method in your ColdSpring managed service for each dependency. For instance, the method below, when added to our ArtDAO will automatically have the ArtistDAO dependency injected into it without it being defined in the configuration file (keep in mind that the naming of the method is important).

<cffunction name="setArtistDAO" access="public" output="false" returntype="void">
   <cfargument name="artistDAO" type="com.withcsoption2.artists.artistDAO" required="true" />
      
   <cfset variables.artistDAO = arguments.artistDAO />
</cffunction>

To see how much leaner our XML configuration becomes, here is the same configuration file as above, but using autowiring.

<?xml version="1.0" encoding="UTF-8"?>

<beans default-autowire="byName">
   <bean id="artDAO" class="com.withcsoption2.art.artDAO">
      <constructor-arg name="dsn"><value>${dsn}</value></constructor-arg>
   </bean>
   <bean id="artGateway" class="com.withcsoption2.art.artGateway">
      <constructor-arg name="dsn"><value>${dsn}</value></constructor-arg>
   </bean>
   <bean id="artGalleryService" class="com.withcsoption2.artGalleryService">
   </bean>
   <bean id="artistDAO" class="com.withcsoption2.artists.artistDAO">
      <constructor-arg name="dsn"><value>${dsn}</value></constructor-arg>
   </bean>
   <bean id="artistGateway" class="com.withcsoption2.artists.artistGateway">
      <constructor-arg name="dsn"><value>${dsn}</value></constructor-arg>
   </bean>
</beans>

Our configuration went from 33 lines (for this very simple example) to only 18 but all the dependencies will still be injected just the same. Now, that's easy!


Handling "Aspects" with ColdSpring
The concept of aspects are something that is difficult to explain since it is, to me, very loosely defined. Other times you will hear aspects referred to as "cross-cutting concerns" which is a little more descriptive. Basically, it is some process that occurs throughout many portions of your application. I told you it was difficult to define!

The typical example used for a common aspect is logging. This is because all portions of your application would require access to logging regardless of the types of objects they manage. For instance, if you want to log all data writes for your application you'd find yourself copying the logging code into every DAO within your application (probably you'd have a logging CFC but the code to reference and call that CFC would appear in every DAO).

The problem with this example, to me, is that it becomes hard for someone new to the concept to see where you would use this other than logging. So let me explain a usage I had on a recent project. This project had versioning logic information for every database record insert, update and delete. This presented not just the problem of repeating the versioning code in every DAO but also it referenced the users ID which was stored in the session and which I wanted to keep out of my DAOs. Thus, by putting this logic inside an "advice" for AOP I was not only able to remove the need to add this logic to every DAO but also kept references to this session variable out of my DAOs (this is considered a best practice).

Let's see how this works. First you create an advice component like the one below. Advice can be called before, after or around the method calls you specify - for example, your logging you would probably want to happen after but my versioning example needed to happen before. The example below is for a before advice. This is definitely not a useful example as its purpose is simply to increment whatever ID you passed by 1, but its intended to offer a simple example of how AOP functions and how to configure it.

<cfcomponent output="false" extends="coldspring.aop.MethodInterceptor">

   <cffunction name="init" returntype="any" output="false" access="public">
      <cfreturn this />
   </cffunction>
   
   <cffunction name="invokeMethod" returntype="any" access="public" output="false">
         <cfargument name="methodInvocation" type="coldspring.aop.MethodInvocation" required="true" />
         <cfset var local = structNew() />
         
         <cfif structKeyExists(arguments.methodInvocation.getArguments(),"art")>
            <cfset arguments.methodInvocation.getArguments()["art"].setArtID(arguments.methodInvocation.getArguments()["art"].getArtID()+1) />
         </cfif>
         
         <!--- Proceed with the method call to the underlying CFC. --->
          <cfset local.result = arguments.methodInvocation.proceed() />
         
         <!--- Return the result of the method call. --->
         <cfreturn local.result />
   </cffunction>

</cfcomponent>

As you can see, first our method checks to see whether an argument called "art" was passed and, if so, increments the ArtID by one. Now let's see how you would configure this advice. First we define the advice object and then we define the "advisor" which points at this advice object and also defines which methods it applies to via the mappedNames property. In this case, we are using the asterisk to indicate that we want it to apply to all methods of whatever object we apply the advice to.

<bean id="sampleAdvice" class="com.withcsoption2.sampleAdvice" />

<bean id="sampleAdvisor" class="coldspring.aop.support.NamedMethodPointcutAdvisor">
   <property name="advice">
      <ref bean="sampleAdvice" />
   </property>
   <property name="mappedNames">
      <value>*</value>
   </property>
</bean>

At this point, we have defined the advice/advisor but not actually applied it to any ColdSpring managed object. To do that, we first define the original bean as before (see first 2 lines below) but call it something else (in this case we appended "proxy"). We do this because when we ask for the bean "artGalleryService" we want ColdSpring to return the version with the AOP advice added in, which you can see defined below. We simply tell ColdSpring which bean to reference (i.e. artGalleryServiceProxy) and what advice to use (i.e. sampleAdvice).

<bean id="artGalleryServiceProxy" class="com.withcsoption2.artGalleryService">
</bean>
<bean id="artGalleryService" class="coldspring.aop.framework.ProxyFactoryBean">
   <property name="target">
      <ref bean="artGalleryServiceProxy" />
   </property>
   <property name="interceptorNames">
      <list>
         <value>sampleAdvice</value>
      </list>
   </property>
</bean>

Now when we call any method in artGalleryService that has an art argument, an artID of 1 will actually become an artID of 2 - like I said, not useful in this case. One important thing to notice is that my service methods have not changed at all nor are they even aware that my advice is manipulating the data. This means that I can apply this advice to any components where it is needed without changing them and I can centralize this logic and change it whenever necessary without a major rewrite.

Generating "Remote Proxies" with ColdSpring
The last feature I will discuss is one that I admittedly don't use often but can be handy in some situations; this is ColdSpring's ability to auto-generate remote proxies for A remote proxy is a component that is used to make certain methods within your services API available to Flash/Flex remoting or web services. This is done rather than directly adding access="remote" to the service method.

Using ColdSpring we can automatically make any or all methods within a service component it manages available as remote. To configure this feature, you define your remote bean and target the service you wish to make available as remote. As you might assume with the serviceName and relativePath properties below, ColdSpring actually does create a physical file for you though you cannot edit it as it may be overwritten. The remoteMethodNames property functions just like the mappedNames value in AOP whereby it determines which methods the remote proxy will apply to (in this case, I specified all). The beanFactoryName is the name of the application scoped variable containing the ColdSpring bean factory within your application.

<bean id="artGalleryServiceRemote" class="coldspring.aop.framework.RemoteFactoryBean" lazy-init="false">
   <property name="target">
      <ref bean="artGalleryService" />
   </property>
   <property name="serviceName">
      <value>artGalleryServiceRemote</value>
   </property>
   <property name="relativePath">
      <value>/com/withcsoption2/</value>
   </property>
   <property name="remoteMethodNames">
      <value>*</value>
   </property>
   <property name="beanFactoryName">
      <value>beanFactory</value>
   </property>
</bean>

Its worth noting that this remote proxy still uses the AOP advice I defined elsewhere in the configuration for the artGalleryService - this being one of the benefits of using the auto-generated proxies. However, as I mentioned I don't use this feature much, in part because you cannot modify the generated file. In part this is because remote proxies are simply far too easy to build but, more importantly, in many cases my remoting proxy methods actually do some data massaging for passing data to Flex or JavaScript, which becomes difficult when you auto-generate.

Conclusion
There's obviously more to ColdSpring than I was able to cover here. But, as I am sure you can see, it is very powerful and can become a major time-saver, especially on larger projects. If you are looking for more, be sure to reference the online documentation for the project. Also, I highly recommend Brian Kotek's blog for ColdSpring related tutorials and discussions - specifically on many of the more advanced possibilities the framework offers.

Special thanks to Peter Bell for reviewing this article before publishing.

Comments
Sami Hoda
Nice!


Jamie Krug
Good stuff! I hope this encourages more CFML developers experiment with ColdSpring if they haven't already.

The ColdSpring Quickstart Guide, by Brian Kotek, is also a great resource:
http://coldspringframework.org/coldspring/examples/quickstart/


Drew
I don't really find CS too complicated to use, and I certainly fall into that category of not having felt the pain that it helps out with yet... but I do have a fundamental n00b question that I just cannot wrap my head around and I am hoping you can help me?

Why is it so wrong to access application scoped singletons within your CFCs? Whether an artService.cfc accesses variables.instance.artDAO.read() or application.artDAO.read() the 2 are still coupled aren't they? Everything is being accessed/passed by reference anyways, right?

Aside from an encapsulation purity standpoint, where and at what point does that practice break down?

Because if it doesn't -- or doesn't very often, wouldn't I be using a framework to uncomplicate a practice (injecting dependencies) that in and of itself is an un-necessary complication?

To be clear: I'm not asserting - I know I am missing the picture -- I just want to know why I need to do this in the first place?

Thanks for the help!
Drew


Jose Galdamez
I've got a similar question to Drew's. Currently, I have a collection of related functions wrapped up inside separate CFCs. For example, I have a List.cfc that does special list-related functions. These are very general purpose and not tied to any specific application.

So far I only have three of these implemented as application-scoped singletons, so it's not too bad (String, Date, List). It's a nice way to keep certain pieces of code in one place and just call the functions from anywhere as needed. Plus, keeping the objects in the application scope avoids the problem of having to instantiate and object every time you need it, thus reducing performance and coupling more pages to the objects.

Anyway, I recently had to use some of these functions within a bean I created. I wanted to avoid a direct call to the application-scoped object within the bean, but I just couldn't see how. I found this post by Dan Wilson.

http://www.nodans.com/index.cfm/2009/5/3/Hard-Coding-Scopes-In-CFCs-Is-A-No-No

OK, so I shouldn't be using the application scope directly within a CFC. I get that. But now what? What is the right way to call a particular function within an object? I could use cfinvoke and call the method directly, but that doesn't do much for decoupling.

Is the expectation here that the bean instantiate every object it's ever going to need on its own? So within the init() constructor, a variables.foo would created an instantiated object?

This sounds like it could get just as messy. Let me guess, this is where ColdSpring comes in :-)

Thanks for the guide, Brian!


Jose Galdamez
On a side note, Brian.

I spaced out my response in paragraphs and what not. It doesn't seem like the line breaks got converted though. (Hence, everything I wrote clumped up into one paragraph.)


Brian Rinaldi
Thanks for the comments! Usually I write these long (and time consuming) posts and get no response :)

@Drew - the issue is that in keeping your CFCs dumb to implementation details like that you improve reusability as well as avoid tying them into aspects of your architecture that may change. So, to give a dumb example, your CFC becomes not only dependent on dsn but the fact that dsn is in a variable named "dsn" in the application scope.

However, from a purely practical standpoint, in order to place all these dependencies in the application scope to implement things in this manner, you'd still have to go through the steps I walk through in the "without coldspring" section (i.e. instantiating each item, and potentially in the right order so as not to encounter errors due to missing dependencies when instantiated). The net result is, you've now tied your CFC into specific implementation details and you really haven't saved any time or complexity in my opinion.

@jose - yes, it can get messy and that's exactly why I show how its generally done without coldspring to illustrate that. That is usually the point when you realize why ColdSpring is so useful.


Brian Rinaldi
@jose - on another note, my commenting seems to have gotten messed up since I upgraded my Mango install. I will look into it.


Drew
thx Brian! Standing back, I kind of get what you are saying, but I keep thinking that if my Art service requires my Art DAO and DSN (as an example) it is tied to them anyways (i.e. throughout the cfc it will reference variables.ArtDAO) so whether it's referencing it in the private scope or the app scope -- it's still "dependent" upon it and "most" changes I make would have to be reflected in it anyways? I know I am being obtuse here, but that's where I fall short of "getting it." Another example is why wouldn't I just put ALL my singletons in an app scoped object (call it a factory I suppose?) and then just pass that into every cfc so that everyone has access to anything they might need? Assuming that these are all passed by reference - and we are talking about singletons - then what does dealing with the minutiae of injecting specific cfc's gain you over injecting the one god-obj? Again, I know in my gut this is not right, I just don't really understand why in "practical terms" for say 90% of apps built by developers? I'm real sorry to trouble you with what I am sure are "101, obvious on its face" questions!!!


Sameer
I still need good reasons to use ColdSpring and also reasons that I can put forth to clients. The prequel to this guide is missing - the real benefits of learning ColdSpring. I knew the benefits of PHP, or CF, or AS3.0 before getting into the bandwagon and that kept me excited plus motivated throughout the learning process. Today I am passionate about those techs. Today I use CFCs in all projects, I have created several ones that I can re-use to manupilate strings, cfqueries, structures, formdata, and also manipulate html output. The development of a new project hardly has any glitches. So, at that stage why bother about using ColdSpring and not learn something else?


Brian Rinaldi
@Drew - ColdSpring is effectively a factory...so perhaps you are going down the same road. You could build your own factory but ColdSpring does a lot of things (as explained above - like DI, AOP, etc.) that you might end up recreating.

@sameer - if your CFCs are all just function libraries, then you probably won't benefit from ColdSpring. Its really designed for wiring services that access an object oriented model.


Glyn Jackson
Very well written and really helps me, thank you :)


Kevan Stannard
@Brian, nice introduction. I've been looking for a ColdSpring intro to reference, and this is just what I need, thanks!

@Drew, @Jose, @Sameer, some extra info on the problem that ColdSpring solves is over here:

http://learn.objectorientedcoldfusion.org/wiki/Dependency_Injection


Write your comment



(it will not be displayed)