<strong>In the beginning...</strong>


...there was Model-Glue and ChiliBeans.  It was good.  You could ask for a ConfigBean, and use it as configuration.  That was handy, but it didn't really get the full point of IoC:  the bean could be a lot more than a representation of a datasource, etc.  

<strong>So I shifted the branding message...</strong>

GetConfigBean ("Get Configuration Bean") slowly became GetConfigBean ("Get Configured Bean").  To use the (overused now!) contact manager example, instead of asking for something like GetConfigBean("datasource.xml"), you could ask for something like GetConfigBean("ContactManagerService.xml"), and ChiliBeans would load a ContactManagerService with methods like saveContact(), loadContact(), and listContacts(). 

This change was enabled by allowing properties defined in ChiliBeans to refer to other chilibeans xml files.  This means you could define your ContactService as a config'd bean and tell it to use the bean defined by Datasource.xml as its datasource.

In code, this represented a shift from this:

<div class="code"><FONT COLOR=GRAY><I>&lt;!--- ContactController.cfc ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cffunction name=<FONT COLOR=BLUE>"Init"</FONT>&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfargument name=<FONT COLOR=BLUE>"ModelGlue"</FONT>&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfset super.Init(arguments.ModelGlue) /&gt;</FONT><br>
<br>
  <FONT COLOR=GRAY><I>&lt;!--- Get our datasource ---&gt;</I></FONT><br>
  <FONT COLOR=MAROON>&lt;cfset var Datasource= getModelGlue().getConfigBean(<FONT COLOR=BLUE>"Datasource.xml"</FONT>) /&gt;</FONT><br>
<br>
  <FONT COLOR=GRAY><I>&lt;!--- Create the service and init it with the datasource ---&gt;</I></FONT><br>
  <FONT COLOR=MAROON>&lt;cfset variables.ContactService = createObject(<FONT COLOR=BLUE>"component"</FONT>, <FONT COLOR=BLUE>"contactmanager.model.service.Contactservice"</FONT>).init(variables.datasource) /&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfreturn this /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;/cffunction&gt;</FONT></div>

To this:

<div class="code"><FONT COLOR=GRAY><I>&lt;!--- ContactController.cfc ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cffunction name=<FONT COLOR=BLUE>"Init"</FONT>&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfargument name=<FONT COLOR=BLUE>"ModelGlue"</FONT>&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfset super.Init(arguments.ModelGlue) /&gt;</FONT><br>
<br>
  <FONT COLOR=GRAY><I>&lt;!--- Create the service---&gt;</I></FONT><br>
  <FONT COLOR=MAROON>&lt;cfset variables.ContactService = getModelGlue().getConfigBean(<FONT COLOR=BLUE>"ContactService.xml"</FONT>) /&gt;</FONT><br>
<br>
  <FONT COLOR=MAROON>&lt;cfreturn this /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;/cffunction&gt;</FONT></div>

<strong>Then ColdSpring showed up...</strong>

One issue I had with Chilibeans was that it was tied directly to the filesystem.  ColdSpring solves this by removing the filesystem nature of its BeanFactory - generally, a file is loaded when the factory is constructed that contains all of the beans the factory can create.  That means I could replace the two files needed for my existing setup (Datasource.xml and ContactService.xml) with a single definition file that shows ContactService needing Datasource in its constructor:

<div class="code"><FONT COLOR=NAVY>&lt;beans&gt;</FONT><br>
  <FONT COLOR=NAVY>&lt;bean id=<FONT COLOR=BLUE>"ContactService"</FONT> class=<FONT COLOR=BLUE>"contactmanager.model.service.Contactservice"</FONT>&gt;</FONT><br>
    &lt;constructor-arg name=<FONT COLOR=BLUE>"Datasource"</FONT>&gt;<br>
      <FONT COLOR=NAVY>&lt;ref bean=<FONT COLOR=BLUE>"Datasource"</FONT> /&gt;</FONT><br>
    &lt;/constructor-arg&gt;<br>
  <FONT COLOR=NAVY>&lt;/bean&gt;</FONT><br>
<br>
  <FONT COLOR=NAVY>&lt;bean id=<FONT COLOR=BLUE>"Datasource"</FONT> class=<FONT COLOR=BLUE>"contactmanager.model.data.Datasource"</FONT>&gt;</FONT><br>
    <FONT COLOR=NAVY>&lt;property name=<FONT COLOR=BLUE>"DSN"</FONT>&gt;</FONT><br>
      <FONT COLOR=NAVY>&lt;value&gt;</FONT>ContactManager<FONT COLOR=NAVY>&lt;/value&gt;</FONT><br>
    <FONT COLOR=NAVY>&lt;/property&gt;</FONT><br>
  <FONT COLOR=NAVY>&lt;/bean&gt;</FONT><br>
<FONT COLOR=NAVY>&lt;/beans&gt;</FONT></div>

It's a very small change in code:

<div class="code"><FONT COLOR=GRAY><I>&lt;!--- Create the service---&gt;</I></FONT><br>
  <FONT COLOR=MAROON>&lt;cfset variables.ContactService = getModelGlue().getConfigBean(<FONT COLOR=BLUE>"ContactService.xml"</FONT>) /&gt;</FONT></div>

Becomes:

<div class="code"><FONT COLOR=GRAY><I>&lt;!--- Create the service---&gt;</I></FONT><br>
  <FONT COLOR=MAROON>&lt;cfset variables.ContactService = getModelGlue().getConfigBean(<FONT COLOR=BLUE>"ContactService"</FONT>) /&gt;</FONT></div>

However, my controller is no longer tied to the filesystem, and it has a much more powerful BeanFactory behind it.

<strong>Life was good, but repetitive...</strong>

If my contact manager grew, I'd probably start needing things like an EmailService, an AuthenticationService, a LoggingService...and I'd need to add some constructor code for each of these.  My constructor would start to look like this:

<div class="code"><FONT COLOR=GRAY><I>&lt;!--- ContactController.cfc ---&gt;</I></FONT><br>
<FONT COLOR=MAROON>&lt;cffunction name=<FONT COLOR=BLUE>"Init"</FONT>&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfargument name=<FONT COLOR=BLUE>"ModelGlue"</FONT>&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfset super.Init(arguments.ModelGlue) /&gt;</FONT><br>
<br>
  <FONT COLOR=GRAY><I>&lt;!--- Create services ---&gt;</I></FONT><br>
  <FONT COLOR=MAROON>&lt;cfset variables.ContactService = getModelGlue().getConfigBean(<FONT COLOR=BLUE>"ContactService"</FONT>) /&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfset variables.EmailService= getModelGlue().getConfigBean(<FONT COLOR=BLUE>"EmailService"</FONT>) /&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfset variables.AuthenticationService= getModelGlue().getConfigBean(<FONT COLOR=BLUE>"AuthenticationService"</FONT>) /&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfset variables.LoggingService= getModelGlue().getConfigBean(<FONT COLOR=BLUE>"LoggingService"</FONT>) /&gt;</FONT><br>
<br>
  <FONT COLOR=MAROON>&lt;cfreturn this /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;/cffunction&gt;</FONT></div>

<strong>Behold, the autowire...</strong>

Now, autowiring doesn't do much to cut down on this repetitive code.  What it does do, however, is delegate the entire creation of these services to something else.  It serves to <strong>dumb down</strong> your controller - in MVC, a dumb, skinny controller is better than a fat, smart controller.

To make my ContactController an "autowired" controller, I'd do the following:


<ol>
<li>Make sure I was using the Model-Glue BER, available at svn://clearsoftware.net/clearsoftware.net . (Yes, 1.1 is coming, so this'll remove this step.  I just need to finish unpacking and my cfunited presos.)</li>
<li>Write a "setter" function for each of these services named Set[BeanIdFromColdSpring]:

<div class="code"><FONT COLOR=MAROON>&lt;cffunction name=<FONT COLOR=BLUE>"setContactService"</FONT>&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfargument name=<FONT COLOR=BLUE>"contactService"</FONT>&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfset variables.contactService = arguments.contactService /&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;/cffunction&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;cffunction name=<FONT COLOR=BLUE>"setEmailService"</FONT>&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfargument name=<FONT COLOR=BLUE>"EmailService"</FONT>&gt;</FONT><br>
  <FONT COLOR=MAROON>&lt;cfset variables.EmailService= arguments.EmailService/&gt;</FONT><br>
<FONT COLOR=MAROON>&lt;/cffunction&gt;</FONT><br>
<FONT COLOR=GRAY><I>&lt;!--- And so on... ---&gt;</I></FONT></div>
</li>
<li>Delete my constructor ("init" method) entirely.</li>
</ol>

Now, when Model-Glue loads your controller, it'll look at it for any methods named "Set[something]", and see if ColdSpring has a bean named "something".  If it does, it'll ask ColdSpring for that bean, and call the Set[Something] method, passing it the bean.

<strong>Wait - autowiring is more code?</strong>

Yep, I did a double-take too.  It *is* more code to autowire.  However, as your app grows, you're likely to start to "mash up" more services.  I have one application that has about nine different "NnnnService" CFCs, and each controller needs its own subset of those (sometimes one, sometimes all nine!).

What I've done there is move all of these "set[Something" functions to a file called /model/mixin/applicationServices.cfm that each of my controllers <cfincludes> (becoming a "static mixin").  That way, if a new service pops up, I add a setter function to one file, and it's available in all services!  Now that's much nicer writing init() plumbing code in specific controllers!!