Skip to Navigation Skip to Content

When we modularize our code base into CFCs using Object-Oriented Programming principles, our objects will often begin to rely on other objects to function as intended. When one part of our application relies on another part of the application to function, we have what is called a dependency. While we want our objects to know how to use the objects that they depend on, we do not want our objects to be responsible for creating and configuring the objects that they need – we want to maintain loose coupling and keep a separation of concerns.

In order to keep a separation of concerns we want to manage any dependencies between objects outside of the objects themselves. This can be accomplished by leveraging an Inversion of Control (IoC) framework such as ColdSpring. ColdSpring features a design pattern called Dependency Injection (DI) to help to assemble the components needed for the application to work. Dependency Injection manages the dependencies between objects by … wait for it … injecting the dependencies into the objects that rely on the objects to function.

The following demo application is an simple example on how to use ColdSpring to manage your object dependencies in your application.

You can play along at home by downloading the Handling Object Dependencies with ColdSpring Zip Files. The contents of the zip file are:

Zip File Contents

You'll need to run the 'Demo Build.sql' SQL build script, set up a datsource called 'demo', and create the mappings for '/com' and '/coldspring' (if you are using CF8 then the mappings are created for you). The main files that we'll be going over are:

  • coldspring.xml
  • Application.cfc
  • index.cfm

Let's start going over our code by taking a look at an example ColdSpring configuration file.

coldspring.xml

Managing object dependencies with ColdSpring is typically done through an XML configuration file (the other two options are using an unparsed XML String or a parsed ColdFusion XML object). We will eventually supply the file path to the configuration file to a ColdSpring object (bean) factory that we will be instantiating. A by-product of the XML configuration file it that it provides a birds-eye view all the dependencies within your application.

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
   
    <bean id="productDao" class="com.domain.product.ProductDao">
        <constructor-arg name="dsn"
            <value>${dsn}</value> 
        </constructor-arg>        
    </bean>
   
    <bean id="productGateway" class="com.domain.product.ProductGateway">
        <constructor-arg name="dsn"
            <value>${dsn}</value> 
        </constructor-arg>            
    </bean>
   
    <bean id="productService" class="com.domain.product.ProductService">
        <constructor-arg name="productGateway"
            <ref bean="productDao" />  
        </constructor-arg>        
        <constructor-arg name="productGateway"
            <ref bean="productGateway" />  
        </constructor-arg>        
    </bean>
   
</beans>

In the coldspring.xml file, we are defining three objects (beans) that we want to be created and managed by ColdSpring. Each <bean> node represents an object that we want ColdSpring to instantiate. We provide the beans with attributes values for id (uniquely identifies our bean) and class (dot notation path to CFC).

In the first two bean nodes we are providing the contructors of the ProductDao and ProductGateway objects with the name of our datasource using the dynamic variable ${dsn}. The dynamic variable uses the ${ yourVar } syntax and its value will be assigned by the default properties set in the ColdSpring object factory.

The functionality of our ProductService object depends on the ProductDao and ProductGateway objects to function. Within the ProductService bean, we have configured the file to inject these dependecies (using Constructor Injection) through our references to the ProductDao and ProductGateway objects. This relieves our ProductService object of the responsibilty of creating and configuring these objects.

I mentioned earlier that we will be instantiating a ColdSpring object factory. We only want a single instance of the object factory in our application so we will be creating our instance as a Singelton during application start up in our Application.cfc file.

Application.cfc

<cfcomponent output="false">
   
    <cfscript>
        this.name = "HandlingObjectDependenciesWithColdSpring";
        this.applicationTimeout = CreateTimeSpan(2,0,0,0);
        //Set appplication mappings for CF8
        if ( Left( server.coldfusion.productversion, 1 ) EQ 8 ) {
            this.mappings["/coldspring"] = GetDirectoryFromPath( ExpandPath('*.*') ) & "frameworks\coldspring1.2";
            this.mappings["/com"] = GetDirectoryFromPath( ExpandPath('*.*') ) & "com";
        }
    </cfscript>
 
    <cffunction name="onApplicationStart" output="false" returntype="void">
        <cfscript>
            //Set defaults for ColdSpring
            properties = {};
            properties.dsn = "demo";   
            //Create factory singleton
   
        APPLICATION.beanFactory = CreateObject( 'component' , 'coldspring.beans.DefaultXmlBeanFactory' ).init( defaultProperties=properties );
            APPLICATION.beanFactory.loadBeans( "config/coldspring.xml" );
        </cfscript>
    </cffunction>
   
    <cffunction name="onRequestStart" output="false" returntype="void">
        <!--- Reload application --->
        <cfif StructKeyExists( URL, "initApp" )>
            <cfset onApplicationStart() />
        </cfif>
    </cffunction>

</cfcomponent>

Let's focus on what is happening in our onApplicationStart() method.

<cffunction name="onApplicationStart" output="false" returntype="void">
        <cfscript>
            //Set defaults for ColdSpring
            properties = {};
            properties.dsn = "demo";   
            //Create factory singleton
   
        APPLICATION.beanFactory = CreateObject( 'component' , 'coldspring.beans.DefaultXmlBeanFactory' ).init( defaultProperties=properties );
            APPLICATION.beanFactory.loadBeans( "config/coldspring.xml" );
        </cfscript>
    </cffunction>

In this method we are creating and configuring our ColdSpring object factory that will return all our instances defined in our XML configuration file with all of the dependencies resolved. The steps used are as follows:

  1. Create a default properties structure that contains properties such as our datasource names
  2. Create an object factory instance and pass in our default properties structure
  3. Store our factory in application scope as a Singleton
  4. Load the our XML configuration file

After we have our Singleton instance of the ColdSpring object (bean) factory, we can access the factory anywhere in our application to retrieve the objects we need. Let's take a look at the factory in action.

index.cfm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Using ColdFusion Remote Proxies with ExtJS</title>
<link href="assets/demos/HandlingObjectDependenciesWithColdSpring/livedemo.css" rel="stylesheet" type="text/css"  />
</head>
<body>

<cfscript>
    productService = APPLICATION.beanFactory.getBean( "productService" );
    qProduct = productService.getProduct( 3 );
    qProducts = productService.getProducts();
</cfscript>

<h3>Product</h3>

<table id="livedemo">
    <tr>
        <th>ID</th>
        <th>Name</th>
        <th>SKU</th>
        <th>Category ID</th>
    </tr>
    <cfoutput query="qProduct">
        <tr>
            <td>#ProductId#</td>
            <td>#Name#</td>
            <td>#SkuNumber#</td>
            <td>#ProductCategoryId#</td>
        </tr>
    </cfoutput>
</table>

<h3>Products</h3>

<table id="livedemo">
    <tr>
        <th>ID</th>
        <th>Name</th>
        <th>SKU</th>
        <th>Category</th>
    </tr>
    <cfoutput query="qProducts">
        <tr>
            <td>#ProductId#</td>
            <td>#ProductName#</td>
            <td>#SkuNumber#</td>
            <td>#ProductCategoryName#</td>
        </tr>
    </cfoutput>
</table>

</body>
</html>

We retrieve instances of our objects from the ColdSpring object factory by passing in an ID string to its getBean() method. We are passing in the ID of "productService" stated in our coldspring.xml configuration file. The ColdSpring factory returns our ProductService instance with all of its of dependencies of other objects resolved.

<cfscript>
    productService = APPLICATION.beanFactory.getBean( "productService" );
    qProduct = productService.getProduct( 3 );
    qProducts = productService.getProducts();
</cfscript>

Once we have our productService instance we call the service's getProduct() method that uses the ProductDao object that was injected by ColdSpring. The method returns a single product specifid by the ID number that we provide. We then call the getProducts() method that uses the ProductGateway object that was also injected by ColdSpring. This method returns all products in our database. We finally output our results to the page to illustrate that the dependecies were indeed resolved by ColdSpring.

Using ColdSpring to handle the dependencies in our code helps us keep a seperation of concerns and our objects loosely coupled. Handling depencies is just one of a few ways that we can leverage ColdSpring. In future posts I hope to show other features of the framework that help make the life of a developer much easier.

0 responses to “Handling Object Dependencies with ColdSpring”

Leave a comment