Environment Control Via Interceptors

Introduction

One of the cool things about interceptors is that so much can be done with them. This little interceptor is very useful when you are dealing with multiple environments and you would like different settings or aspects according to environment. Therefore, ColdBox comes with a basic environment control interceptor that you can use for your projects. Below is a quick guide to show you how to use it.

How to Configure it?

The way to configure the environment interceptor is via your configuration file. Look below for the sample:

<Interceptor class="coldbox.system.interceptors.environmentControl">
  <Property name='configFile'>config/environments.xml.cfm</Property>
  <Property name='fireOnInit'>false</Property>
</Interceptor>
Important Note: The environment control interceptor fires at the afterConfigurationLoad interception point. This way, you can override any aspect configuration before it gets configured and fired. You can also set the fireOnInit property to true, to fire on interceptor creation.

This declares that you want to use the environment control interceptor and assign a configFile property to where you environment settings xml exists. I usually place all my configuration files in my config directory. You also need to set the fireOnInit Boolean flag. This flag, tells the interceptor to fire itself on creation also. This is useful, if you are declaring a chain of interceptors that also need settings as per their environments. The default value is true. Why? Well, because, this way, all the interceptors can make use of per-environment settings. Just make sure that the first declared interceptor is this one.

That's it, this configures your application for using the interceptor, now to the fun stuff.

The Environments Configuration

In order for the interceptor to know which environments you want, where you are and what settings to override, you must fill out an xml file similar to the following:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Declare as many tiers as you like with a unique name -->
<environmentcontrol>
        
  <!-- give an environment a name and a comma delimited list of url snippets to match -->
  <environment name="development" urls="localhost,dev,jfetmac">
        <!--ColdBoxSpecific Settings -->
        <Setting name="HandlerCaching"                  value="false" />
        <Setting name="HandlersIndexAutoReload" value="false" />
        <Setting name="IOCObjectCaching"                value="false" />
        <Setting name="DebugMode"                               value="false" />
        <Setting name="DebugPassword"                   value="" />
        <Setting name="ReinitPassword"                  value="" />
        <Setting name="EnableDumpVar"                   value="false" />
        <Setting name="EnableColdboxLogging"    value="false" />
        <Setting name="onInvalidEvent"                  value="" />
        
        <!--
                AppSpecific Settings: <Setting name="MySetting" value="Hello" />
        -->             
  </environment>
        
</environmentcontrol>

As you can see from the sample xml, you need to define the following:

<environment> element

This element tells the interceptor to look for this environment. You can create as many environment elements as you like and it has the following attributes:

  • Attributes
Attribute Description
@name The name of the environment
@urls The url snippets (comma-delimited) to look for in the CGI.HTTP_HOST

The interceptor grabs the urls attribute and scans the CGI.HTTP_HOST variable to see if the snippets can be found. If it is, then it will set the following in the application configuration settings:

  • ENVIRONMENT = The @name attribute of the environment element.

It will then read in all the Setting elements and place them in your configuration structure. You can also use complex variable declarations as defined in the Configuration Guide which by default uses JSON syntax notation.

Important Note: This process will override any previously defined setting.

If you would like to see the entire structure graph for all the settings that you can override, you can dump the actual configuration structure and see the path of all the variables by using the controller.getConfigSettings() method. For example, to override a particular nested setting, I can just say:

<Setting name="CacheSettings.ObjectDefaultTimeout"  value="0" />
<Setting name="Datasources.myAlias.password"            value="" />

You can also define settings in JSON notation:

<Setting name="Datasources" 
                 value="{'MyDSNAlias': {'Alias': 'MyDSNAlias' , 'Name': 'MyDSN', 'DBType': 'mssql', 'Username': 'dbusername', 'Password': 'dbpass'}}" />

That setting overrides all of the Datasources defined in your configuration file by using a JSON nested structure.

Important:: If the first request is using flash remoting,event gateways or any type of remoting, keep in mind you will have a totally different set of cgi values, and you shouldn't detect environments using those. Please be aware that flash remoting changes the entire story on detection. This also affects pathing.

Extending The Interceptor

The interceptor has a separate function for environment detection called detectEnvironment. You can now extend the interceptor an just override this method and you can have your own detection schemas at your disposal. Below is the method that you can override:

<cffunction name="detectEnvironment" access="private" returntype="string" hint="Detect the running environment and return the name" output="false" >
<!--- *********************************************************************** --->
<cfargument name="environmentsArray" required="true" type="array" hint="The environment array">
<!--- *********************************************************************** --->
<cfscript>
for(i=1; i lte ArrayLen(arguments.environmentsArray); i=i+1){
        if ( listFindNoCase(trim(arguments.environmentsArray[i].XMLAttributes.urls),cgi.http_host) ){
                //Place the ENVIRONMENT on the settings structure.
                setSetting("ENVIRONMENT", trim(arguments.environmentsArray[i].XMLAttributes.name));
                return trim(arguments.environmentsArray[i].XMLAttributes.name);
                break;
        }
}
return "";
</cfscript>
</cffunction>