Friday, November 13, 2009

Enhancing coldbox - adding core Environment Safe logic without touching the core

Background
I know this is a no no, but our office uses subset of production data in our test system to have final sign off on new or changing applications. So when we decided to move to coldBox for a framework, I wasn't sure how environment safe coding was accomplished.

I quickly learned about the interceptor EnvironmentControl, which was a great first start. But there wasn't any settings for plugin MailService to stop emails from being sent. So my first inclination (and coding attempt) was to change mailService.cfc directly. Well I learned that is a mistake. We are now moving from 3b1 to 3b3 and realizing it is a pain when you change the core.

Enhancing Coldbox
Now that I understand a lot more on how Coldbox is running, i realized that my solution can be handle by an interceptor.  Using the announcement of afterPluginCreation, I created a EnvironmentSafeMailService.cfc interceptor that inject methods and properties into MailService plugin.  THIS IS AWESOME!

So how did I do it?  First I realized I have to add and replace functions and properties within MailService, therefore, the plugin MethodInjector came in handy.  But I needed to rename the send function in mailService.  So I can create my own logic and when appropriate call the original send function.

Ignoring the functionality I created for the environment safe feature, here is my code to override functionality with mailService.  All the methods and properties i'm inserting exist in the interceptor class I created.

<cffunction name="afterPluginCreation" access="public" returntype="void" hint="Executes after the framework and application configuration loads, but before the aspects get configured. " output="false" >
 <!--- ************************************************************* --->
 <cfargument name="event" required="true" default="" type="any" hint="path to plugin.">
 <cfargument name="interceptData" required="true" type="any" hint="path to plugin.">

 <cfscript>
  var local = StructNew();

  // ONLY AFFECT mailService plugin
  if ( compareNoCase(arguments.interceptData.pluginPath,"mailService") EQ 0 ) {

   //get plugin methodInjector to make our lives easier
   local.methodInject = getPlugin("MethodInjector");
   local.methodInject.start(arguments.interceptData.oPlugin);

   //make copy of original send
   this['MailServiceSend'] = arguments.interceptData.oPlugin['send'];
   local.md = getMetaData(this['mailServiceSend']);
   local.md.NAME = "mailServiceSend";
   arguments.interceptData.oPlugin.injectMixin( this['MailServiceSend'] );

   //inject new metdata (properties and methods) into MailService
   arguments.interceptData.oPlugin.injectPropertyMixin( "emailDebug", this.getEmailDebug(), "variables.instance" );
   arguments.interceptData.oPlugin.injectPropertyMixin( "emailDebugTOAddress", this.getEmailDebugTOAddress(), "variables.instance" );
   arguments.interceptData.oPlugin.injectMixin( this['getEmailDebug'] );
   arguments.interceptData.oPlugin.injectMixin( this['setEmailDebug'] );
   arguments.interceptData.oPlugin.injectMixin( this['getEmailDebugTOAddress'] );
   arguments.interceptData.oPlugin.injectMixin( this['setEmailDebugTOAddress'] );
   arguments.interceptData.oPlugin.injectMixin( variables['debugConfigured'] );
   arguments.interceptData.oPlugin.injectMixin( variables['traceIt'] );
   arguments.interceptData.oPlugin.injectMixin( this['send'] );

   local.methodInject.stop(arguments.interceptData.oPlugin);
   getPlugin("logger").tracer("EnvSafe MailService Functions Loaded");

  }
 </cfscript>
</cffunction>

Here is the interceptor and a quick guide on how to use it.

No comments:

Post a Comment