Blog Projects
Escape Keys
A ColdFusion and Web Development Blog by Tom de Manincor
 

We know how to use the Coldbox environment interceptor to load different values for datasources. We know how to circumvent datasource.xml files with Transfer by using a datasource bean. Now, how can we use ColdSpring to put it all together for us.

<!-- coldbox -->
   <bean id="ColdboxFactory" class="coldbox.system.extras.ColdboxFactory" />
   <bean id="Coldbox" factory-bean="ColdBoxFactory" factory-method="getColdbox" singleton="true" />
   
   <!-- transfer -->
   <bean id="TransferFactory" class="transfer.TransferFactory" singeleton="true">
      <constructor-arg name="configuration">
         <bean class="model.TransferConfig">
            <constructor-arg name="DSNBean">
               <bean factory-bean="ColdBoxFactory" factory-method="getDatasource">
                  <constructor-arg name="alias">
                     <value>${Transfer_DSNAlias}</value>
                  </constructor-arg>
               </bean>
            </constructor-arg>
            <constructor-arg name="configPath">
             <value>${Transfer_ConfigPath}</value>
            </constructor-arg>
            <constructor-arg name="definitionPath">
             <value>${Transfer_DefinitionPath}</value>
            </constructor-arg>
         </bean>
       </constructor-arg>
   </bean>
      
   <bean id="Transfer" factory-bean="TransferFactory" factory-method="getTransfer" singleton="true" />
   <bean id="Datasource" factory-bean="TransferFactory" factory-method="getDatasource" singleton="true" />

That's what my coldspring.xml file would look like. There are a few things to note. I use Coldbox to get the Datasource information I need because it has already been defined in the Coldbox config or environment file. This is the reason I wanted to avoid a datasource.xml file for Transfer. Otherwise, I'd have the same DSN info repeated all over the place.

I also point to model.TransferConfig. A simple extension of the Transfer Configuration bean. You can learn more about that from my previous post.

If you notice, there is a Transfer_DSNAlias argument being passed into the Coldbox getDatasource method. This tells CB which DSN you want to load up and pass on to Transfer. Coldbox allows for multiple datasources to be stored for use in your App. But Transfer only connects to one at a time. So I made it a setting in the config/environment.

Here's a peak at my environements.xml file.

<environment name="development" urls="" patterns=".local">
   <Setting name="DebugMode"               value="true" />
   <Setting name="DebugPassword"               value="" />
   <Setting name="ReinitPassword"               value="" />
   <Setting name="EnableDumpVar"               value="true" />
   <Setting name="HandlersIndexAutoReload"          value="true" />
   <Setting name="ConfigAutoReload"            value="true" />
   <Setting name="HandlerCaching"               value="false" />
   <Setting name="EventCaching"               value="false" />
   
   <Setting name="Datasources" value="{'MyDSNAlias': {'Alias': 'MyDSNAlias' , 'Name': 'MyDSN', 'DBType': 'mssql', 'Username': 'dbusername', 'Password': 'dbpass'}}" />
   
   <Setting name="Transfer_ConfigPath" value="/config/transfer.xml.cfm" />
   <Setting name="Transfer_DefinitionPath" value="/model/definition" />
   <Setting name="Transfer_DSNAlias" value="MyDSNAlias" />
</environment>

That's it.

By default Transfer expects a path to a datasource.xml file. However, the TransferFactory.init() method will accept a configuration bean. Which you can find in the transfer.com.config path. The Configuration.cfc init() method is only looking for paths as arguments, and sets the DSN username and password to blank on creation. The object does have a hasDatasourceName() method, so how do we utilize this?

Well, I extended the object and overwrite the init() method. It now accepts a datasource bean and sets the DSN info in Transfer with it. When Transfer natively calls hasDatasourceName() it will bypass checking the datasourcePath.

<cfcomponent displayname="TransferConfig" hint="This is a TransferConfig Bean" output="false" extends="transfer.com.config.Configuration">
   
   <cffunction name="init" hint="Constructor" access="public" returntype="model.TransferConfig" output="false">
      <cfargument name="dsnBean"            type="any"      required="no"   default="" />
      <cfargument name="datasourcePath"      type="string"   required="no"   default="" />
      <cfargument name="configPath"         type="string"   required="no"   default="" />
      <cfargument name="definitionPath"      type="string"   required="no"   default="" />
      
      <cfscript>
         variables.instance = StructNew();
         
         setConfigPathCollection(ArrayNew(1));
   
         setDatasourceName(arguments.dsnBean.getName());
         setDatasourceUsername(arguments.dsnBean.getUsername());
         setDatasourcePassword(arguments.dsnBean.getPassword());

         setDataSourcePath(arguments.datasourcePath);
         setConfigPath(arguments.configPath);
         setDefinitionPath(arguments.definitionPath);
   
         return this;
      </cfscript>
   </cffunction>
   
</cfcomponent>

I talked previously about the abilities of the new Environment Interceptor in Coldbox. The next step was to wire it up so I could automate the initialization of Transfer using ColdSpring and these environment specific values from Coldbox.

Before I get into that I needed to know how to overwrite complex values, like Datasources, set in the Coldbox config file with those from the environments.xml.

Luis was kind enough to point me in the right direction, and said dump the ConfigSettings struct and Transverse whatever you want. That I did, using JSON notation. Just substitute single quotes for double quotes maintaining valid XML format.

<environment name="development" urls="" patterns=".local">
   <Setting name="DebugMode"                  value="true" />
   <Setting name="DebugPassword"               value="" />
   <Setting name="ReinitPassword"               value="" />
   <Setting name="EnableDumpVar"               value="true" />
   <Setting name="HandlersIndexAutoReload"         value="true" />
   <Setting name="ConfigAutoReload"            value="true" />
   <Setting name="HandlerCaching"               value="false" />
   <Setting name="EventCaching"               value="false" />
   
   <Setting name="Datasources" value="{'MyDSNAlias': {'Alias': 'MyDSNAlias' , 'Name': 'MyDSN', 'DBType': 'mssql', 'Username': 'dbusername', 'Password': 'dbpass'}}" />
</environment>