ColdSpring in Five Minutes

To demonstrate how ColdSpring works, let's start with a very simple example. Let's say we have 3 CFCs: a UserService, a UserGateway, and a ConfigBean. Here is the code for these, and you can find the actual CFCs in the quickstart/components folder:

If you aren't familiar with Model-View-Controller (MVC) or object-oriented programming, don't worry. These are very simple CFCs with just one or two methods in them. The names don't really matter at this point. Just follow along since right now all we're doing is explaining what ColdSpring can do.

UserService.cfc

<cfcomponent name="User Service" hint="I am an example User Service, which is how external things interact with my Model.">
	
	<cffunction name="init" access="public" returntype="any" hint="Constructor.">
		<cfreturn this />
	</cffunction>
	
	<cffunction name="getUserGateway" access="public" returntype="any" output="false" hint="I return the UserGateway.">
		<cfreturn variables.instance['userGateway'] />
	</cffunction>
		
	<cffunction name="setUserGateway" access="public" returntype="void" output="false" hint="I set the UserGateway.">
		<cfargument name="userGateway" type="any" required="true" hint="UserGateway" />
		<cfset variables.instance['userGateway'] = arguments.userGateway />
	</cffunction>
	
</cfcomponent>

UserGateway.cfc

<cfcomponent name="User Gateway" hint="I am an example User Gateway for interacting with a database.">
	
	<cffunction name="init" access="public" returntype="any" hint="Constructor.">
		<cfreturn this />
	</cffunction>
	
	<cffunction name="getConfigBean" access="public" returntype="any" output="false" hint="I return the ConfigBean.">
		<cfreturn variables.instance['configBean'] />
	</cffunction>
		
	<cffunction name="setConfigBean" access="public" returntype="void" output="false" hint="I set the ConfigBean.">
		<cfargument name="configBean" type="any" required="true" hint="ConfigBean" />
		<cfset variables.instance['configBean'] = arguments.configBean />
	</cffunction>

</cfcomponent>

ConfigBean.cfc

<cfcomponent name="Config Bean" hint="I contain application configuration info such as datasource name.">
	
	<cffunction name="init" access="public" returntype="any" hint="Constructor.">
		<cfargument name="datasourceName" type="string" required="false" default="fakeDSN" />
		<cfset setDatasourceName(arguments.datasourceName) />
		<cfreturn this />
	</cffunction>

	<cffunction name="getDatasourceName" access="public" returntype="string" output="false" hint="I return the DatasourceName.">
		<cfreturn variables.instance['datasourceName'] />
	</cffunction>
		
	<cffunction name="setDatasourceName" access="public" returntype="void" output="false" hint="I set the DatasourceName.">
		<cfargument name="datasourceName" type="string" required="true" hint="DatasourceName" />
		<cfset variables.instance['datasourceName'] = arguments.datasourceName />
	</cffunction>

</cfcomponent>

As you might notice, the components are related to each other. In other words, they have dependencies on each other. The UserService needs the UserGateway, and the UserGateway needs the ConfigBean. It may be that UserService will make calls to the UserGateway to run some database queries. And it may be that the UserGateway makes calls to the ConfigBean to determine what datasource to use when it executes queries.

Without something like ColdSpring, creating and configuring these components can be quite a chore. We'd have to do something like:

<cfscript>
configBean = CreateObject('component', 'coldspring.examples.quickstart.components.ConfigBean').init();
userGateway = CreateObject('component', 'coldspring.examples.quickstart.components.UserGateway').init();
userService = CreateObject('component', 'coldspring.examples.quickstart.components.UserService').init();
userGateway.setConfigBean(configBean);
userService.setUserGateway(userGateway);
</cfscript>

Notice that we have to create the CFCs in the right order, and that we have to manually pass the dependent components into each CFC. As you might imagine, in larger applications with lots of CFCs and lots of dependencies, this can turn into a nightmare pretty quickly. Luckily, we have ColdSpring to manage all of this for us!

Instead of doing things manually, we can tell ColdSpring about our components and their dependencies. This is typically done using an XML configuration file. Don't worry, just because it's XML doesn't mean it's a pain to use. Here is a simple ColdSpring configuration file:

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans default-autowire="byName">
	
	<bean id="userService" class="coldspring.examples.quickstart.components.UserService" />
	<bean id="userGateway" class="coldspring.examples.quickstart.components.UserGateway" />
	<bean id="configBean" class="coldspring.examples.quickstart.components.ConfigBean" />
	
</beans>

You can see that we're just defining our component paths and giving each one an identifier, called a 'bean ID'. The 'default-autowire="byName"' attribute tells ColdSpring to look at the setters in our CFCs and try to find a CFC whose bean ID matches the setter. So if it sees setUserGateway(), ColdSpring looks for a bean named "userGateway". If it finds a match, it sets it automatically!

Once you have your ColdSpring XML written, all you have to do is create an instance of the ColdSpring factory. You specify the configuration file when you create ColdSpring. The code is very simple:

<cfset coldspringConfig = '/coldspring/examples/quickstart/config/coldspring.xml' />
<cfset beanFactory = CreateObject('component', 'coldspring.beans.DefaultXmlBeanFactory').init() />
<cfset beanFactory.loadBeans(coldspringConfig) />

Now that we have an instance of the ColdSpring factory, we can ask it for our CFC instances. Our CFCs will be fully initialized, with all dependencies resolved, and ready for use! For example, if we call:

<!--- Get the User Service CFC from ColdSpring. --->
<cfset userService = beanFactory.getBean('userService') />	
<cfdump var="#userService#" />

<!--- Now get the Gateway that ColdSpring set into the User Service. --->
<cfset userGateway = userService.getUserGateway() />	
<cfdump var="#userGateway#" />

<!--- Now get the Config Bean that ColdSpring set into my User Gateway. --->
<cfset configBean = userGateway.getConfigBean() />
<cfdump var="#configBean#" />

You'll see three CFCs dumped using CFDump:

component coldspring.examples.quickstart.components.UserService
METHODS
GETUSERGATEWAY
function getUserGateway
Arguments:none
ReturnType: any
Roles:  
Access: public
Output: false
DisplayName:  
Hint: I return the UserGateway.
Description:  
INIT
function init
Arguments:none
ReturnType: any
Roles:  
Access: public
Output:  
DisplayName:  
Hint: Constructor.
Description:  
SETUSERGATEWAY
function setUserGateway
Arguments:
Name Required Type Default
userGateway Required any  
ReturnType: void
Roles:  
Access: public
Output: false
DisplayName:  
Hint: I set the UserGateway.
Description:  

component coldspring.examples.quickstart.components.UserGateway
METHODS
GETCONFIGBEAN
function getConfigBean
Arguments:none
ReturnType: any
Roles:  
Access: public
Output: false
DisplayName:  
Hint: I return the ConfigBean.
Description:  
INIT
function init
Arguments:none
ReturnType: any
Roles:  
Access: public
Output:  
DisplayName:  
Hint: Constructor.
Description:  
SETCONFIGBEAN
function setConfigBean
Arguments:
Name Required Type Default
configBean Required any  
ReturnType: void
Roles:  
Access: public
Output: false
DisplayName:  
Hint: I set the ConfigBean.
Description:  

component coldspring.examples.quickstart.components.ConfigBean
METHODS
GETDATASOURCENAME
function getDatasourceName
Arguments:none
ReturnType: string
Roles:  
Access: public
Output: false
DisplayName:  
Hint: I return the DatasourceName.
Description:  
INIT
function init
Arguments:
Name Required Type Default
datasourceName Optional string fakeDSN
ReturnType: any
Roles:  
Access: public
Output:  
DisplayName:  
Hint: Constructor.
Description:  
SETDATASOURCENAME
function setDatasourceName
Arguments:
Name Required Type Default
datasourceName Required string  
ReturnType: void
Roles:  
Access: public
Output: false
DisplayName:  
Hint: I set the DatasourceName.
Description:  

That's it! See, using ColdSpring is actually pretty easy. We defined our XML config file, created the ColdSpring factory, and ColdSpring did the rest. ColdSpring worries about creating the components in the correct order and resolving the dependencies between them. And we can get on with the fun part of coding: building applications!