Escape Keys - TomdeMan's Blog

I was using the Coldbox SES interceptor and the built in Coldcourse integration, and ran into a little snag the other day. Our production boxes are clustered behind a load balancer using sticky sessions. In order to, reinitialize the framework, I had to access each host by ip and port.

This causes an issue with the current integration with Coldcourse and the SES interceptor. What happens is your BaseURL gets set to 'http://localhost:1234'. Which is no good for those rewrites, since the address will not resolve.

The answer...

Use the config or environments.xml to specify a new setting 'BaseHostName'.

config.xml
<Setting name="BaseHostName"               value="www.mysite.com" />

environments.xml
<environment name="local" urls="" patterns=".local">
      <Setting name="BaseHostName"               value="mysite.local" />

While you are in the config, make sure you check the order of your interceptors. You will want the environment interceptor to come before the SES. Be sure to set the FireOnInit property to TRUE. This means that the load up of settings occurs once the interceptor get's created and NOT on the execution point.

<Interceptor class="interceptor.environmentControl">
         <Property name='configFile'>config/environments.xml.cfm</Property>
         <Property name='fireOnInit'>true</Property>
      </Interceptor>
      
      <Interceptor class="coldbox.system.interceptors.ses">
         <Property name="configFile">config/routes.cfm</Property>
      </Interceptor>

Then, modify the routes.cfm to accept the new setting.

<cfif not settingExists('BaseHostName')>
   <cfset setSetting('BaseHostName',cgi.HTTP_HOST) />
</cfif>

<cfif len(getSetting("AppMapping")) lte 1>
   <cfset setBaseURL("http://#getSetting('BaseHostName')#")>
<cfelse>
   <cfset setBaseURL("http://#getSetting('BaseHostName')#/#getSetting('AppMapping')#/index.cfm") />
</cfif>

That's it. Now whether you are clustered or not, you have control over the host name. Maybe this will make it into a future release of Coldbox.

Where is all the CF talent???

I am once again in a position where I have to hire some CF programmers. In the past, the pick-ins were slim, and I thought I was asking too much. Here we are almost a year and half later, and it's not improved much.

Are my expectations too high?

I evolved from good old procedural and spaghetti code, to working with design patterns and simulating OO programming. So I ask, where is everyone else?

There has been lots of talk recently about the advancement to OO and how CF developers are adapting. I will tell you, personally, it wasn't easy. I worked my butt off to get up to speed and I guess I am fortunate cause it was a passion of mine and I enjoyed the challenge and the results.

But now I feel like it is working against me. My efforts have put me in a position to build a team...

Except I can't find many who are familiar with the new technologies and frameworks I am using. I have had time to become comfortable with MVC, ORM, and IOC frameworks. I am looking for people who have experience with them as well, but now I am open to someone who has experience with ANY of them.

I feel bad when I look at a resume, and they have 10 or more years experience and a CF certification. It almost works against them. If you don't stay up-to-date on technologies, it will be hard to find a fit unless you jump into a legacy app.

CF certifications are another story these days. It's discouraging to think you have to know how to use new tags dealing with PDF and AJAX, to get certified, when you know how to program with CF in an OO approach and have 10 different ways to do AJAX without the new CF tags. So to me CF certification is irrelevant, nowadays. Not to mention, it's not going to help separate you from the competition, cause there isn't any.

I was psyched to hear Adobe's announcement about providing licenses for CF for educational purposes. Unfortunately, thats not gonna help much NOW.

What's been going on? How have people been learning, advancing, and making themselves more marketable??? (please comment with replies)

There are a handful of resources out there. Charlie's UGTV is great for those who don't have the time or money for classes, conferences, and training programs.

I don't know where to go with this exactly. I guess its a rant and a desperate cry for talent. Developers, push your bosses to get you and your co-workers to conferences, code reviews, and have training budgets setup and used up.

If you are up on the technologies and methodologies I mentioned, or familiar and looking to take it to the next level, contact me. I not only guarantee a great salary and working environment, but I promise to educate.

UPDATE: I am in located in California, South Bay Area. Manhattan Beach near El Segundo. You can email me tomdeman [at] gmail.com

Thanks to Oscar and Rob for the quick feedback. Both pointed out flaws that needed addressing immediately. I made the appropriate updates, and after a quick review with Luis, even more.

This release should be as optimized as it gets.

Oscar, indicated the importance of getting the accurate hostname when in a clustered environment. He suggested doing so with:

hostname = CreateObject("java", "java.net.InetAddress").getLocalHost().getHostName();

Which from my research, is the best approach. However, as Rob mentioned in his comment, the idea of creating an object on every exception could create a nasty performance drain. Well, we all know Luis has packed Coldbox with all kinds of goodies, and of course in his 'utilities' plugin he already had a method to getInetHost(), which does exactly what Oscar suggested. Except, since its a CB plugin, its already loaded and cached for us. So I now call a cached object's method when the BugLog plugin initializes and I store it in the instance data.

Next, had to get rid of the CFINVOKE, and not by replacing it with a CreateObject. The best way to do this is with lazy loading. You don't want to create and stash the webservice object in the plugin instance at creation, because CB plugins are initialized with the framework. Lazy loading will create the object the first time it is needed, and will persist as long as the plugin itself exists. Which you can define with the CACHE settings in the plugin metadata.

This is what the latest version looks like:

<cfcomponent hint="Passes Exceptions and Bug Reports to BugLog" extends="coldbox.system.plugin" output="false" cache="true" cachetimeout="20">

   <cffunction name="init" access="public" returntype="BugLog" output="false">
      <cfargument name="controller" type="any" required="true">
      
      <cfset super.Init(arguments.controller) />
      <cfset setPluginName("BugLog")>
      <cfset setPluginVersion("1.2")>
      <cfset setPluginDescription("This is the BugLog plugin.")>
      <cfset setHostName(getPlugin('utilities').getInetHost()) />
      
      <cfreturn this>
   </cffunction>
   
   <!--- creates and logs bug report --->
   <cffunction name="logError" access="public" output="No" returntype="boolean">
      <cfargument name="oExceptionBean" required="true" type="any" />
      <cfargument name="sMessage" required="true" type="string" />
      <cfargument name="sSseverityCode" type="string" default="error" />
      
      <cfparam name="session.cfid" default="" />
      <cfparam name="session.cftoken" default="" />
      
      <cfreturn getBugLogWS().logEntry(
                           dateTime = now(),
                           message = arguments.sMessage,
                           applicationCode = application.applicationname,
                           severityCode = arguments.sSseverityCode,
                           hostName = getHostName(),
                           exceptionMessage = arguments.oExceptionBean.getMessage(),
                           exceptionDetails = arguments.oExceptionBean.getDetail(),
                           CFID = session.CFID,
                           CFTOKEN = session.CFTOKEN,
                           userAgent = cgi.HTTP_USER_AGENT,
                           templatePath = cgi.SCRIPT_NAME,
                           HTMLReport = getController().getExceptionService().renderBugReport(arguments.oExceptionBean)
                           ) />

   </cffunction>
   
   <cffunction name="getBugLogWS" access="public" returntype="any" output="false">
      <cfif not structKeyExists(instance,'oBugLogWS')>
         <cfset setBugLogWS(getPlugin('webservices').getWSobj('BugLog')) />
      </cfif>
      <cfreturn instance.oBugLogWS />
   </cffunction>
   
   <cffunction name="setBugLogWS" access="public" returntype="void" output="false">
      <cfargument name="oBugLogWS" type="any" required="true" />
      <cfset instance.oBugLogWS = arguments.oBugLogWS />
   </cffunction>
   
   <cffunction name="getHostName" access="public" returntype="string" output="false">
      <cfreturn instance.sHostName />
   </cffunction>
   
   <cffunction name="setHostName" access="public" returntype="void" output="false">
      <cfargument name="sHostName" type="string" required="true" />
      <cfset instance.sHostName = arguments.sHostName />
   </cffunction>
   
</cfcomponent>

If you didn't notice, I now allow for you to pass in the Message, and Severity Code, along with the Exception Bean. The code in your exception handler should look something like this:

getPlugin('BugLog',true).logError(
                                 oExceptionBean = exceptionBean,
                                 sMessage = exceptionBean.getMessage(),
                                 sSeverityCode = 'onException');

Hope this helps out, I will be updating the original post. Be sure to check that out if you haven't it contains useful information for those who are just getting this setup.

I recently posted about the Coldbox 2.6 environment interceptor and how it allows you to set different config settings for your app. Then, I released a BugLogHQ plugin for Coldbox. After taking in some feedback, and chatting with Luis, I have made some modifications. This post will discuss the updated Webservice Plugin. I will post another to go over the updates to the BugLog plugin.

Currently the native Webservice support for Coldbox expects 2 WSDL URLs for each service, one for DEV and one for PROD. Looks like:

<WebServices>
      <WebService name="TESTWS" URL="http://www.test.com/test.cfc?wsdl" DevURL="http://dev.test.com/test.cfc?wsdl" />
   </WebServices>

Well, with the new environment specific settings, it defeats the purpose of defining them like this any longer. You can now set them in your environemnts.xml. Like so:

<Setting name="Webservices" value="{'BugLog': 'http://bugs.blush.com/listeners/bugLogListenerWS.cfc?wsdl'}" />

Luis plans to deprecate the current method, but not sure as to when. So implementing this can be done in a number of ways in the meantime.

First option: Overwrite existing Webservice plugin distributed with Coldbox and move your Webservice declarations out of the coldbox config file and into your environments.xml. ** You will not have to modify any application code **

Second Option: Place the updated version into your plugins folder, and call it by using getPlugin('webservices',true). This is for those who need some time to update for the deprecation. You can continue to use your existing Webservices from the coldbox config. Allowing you to add new ones to your environments.xml but remember to use the ',true' when calling the webserivce plugin.

Honestly, I recommend the first option, as it shouldn't take much effort to transfer Webservice WSDLs to the environments.xml, and you wont create a mesh of syntax with getPlugin() calls.

<cfcomponent name="webservices"
          hint="The webservices framework plugin."
          extends="coldbox.system.plugin"
          output="false"
          cache="true">


<!------------------------------------------- CONSTRUCTOR ------------------------------------------->

   <cffunction name="init" access="public" returntype="webservices" output="false">
      <cfargument name="controller" type="any" required="true">
      <cfset super.Init(arguments.controller) />
      <cfset setpluginName("Web Services")>
      <cfset setpluginVersion("1.0.a")>
      <cfset setpluginDescription("This is a very useful web services utility plugin.")>
      <cfreturn this>
   </cffunction>

<!------------------------------------------- PUBLIC ------------------------------------------->

   <cffunction name="getWS" returntype="any" access="Public" hint="Get a web service's wsdl url from the configStruct according to which environment you are on." output="false">
   <!--- ************************************************************* --->
      <cfargument name="name" hint="The name of the web service. If the web service is not found an exception is thrown." type="string" required="Yes">
   <!--- ************************************************************* --->
      <cfset var stLocal = structNew() />
      <cfset stLocal.stWSVC = getController().getSetting("WebServices") />
      <cfif structKeyExists(stLocal.stWSVC, arguments.name)>
         <cfreturn stLocal.stWSVC[arguments.name] />
      </cfif>
      <cfthrow type="ColdBox.plugins.webservices.WebServiceNotFoundException" message="The webservice #arguments.name# was not found in the configuration structure.">
   </cffunction>

   <!--- ************************************************************* --->

   <cffunction name="getWSobj" access="Public"   hint="Get a reference to a webservice obj according to which environment you are on." output="false" returntype="any">
   <!--- ************************************************************* --->
      <cfargument name="name" hint="The name of the web service. If the web service is not found an exception is thrown" type="string" required="Yes">
   <!--- ************************************************************* --->
      <cfset var stLocal = structNew() />
      <cfset stLocal.stWSVC = getController().getSetting("WebServices") />
      <cfif structKeyExists(stLocal.stWSVC, arguments.name)>
         <cfreturn CreateObject("webservice", stLocal.stWSVC[arguments.name] )>
      </cfif>
      <cfthrow type="ColdBox.plugins.webservices.WebServiceNotFoundException" message="The webservice #arguments.name# was not found in the configuration structure.">
   </cffunction>

   <!--- ************************************************************* --->

   <cffunction name="refreshWS" access="Public" hint="Refresh a web service stub object" output="false" returntype="void">
   <!--- ************************************************************* --->
      <cfargument name="webservice" hint="The name or wsdl URL of the web service to refresh" type="string" required="Yes">
   <!--- ************************************************************* --->
      <!--- Get the Webservice from the configStruct --->
      <cfset var ws = getWS(arguments.webservice)>
      <cfset var rpcService = "">
      <cfset var factory = 0>
      
      <cfif ws neq "">
         <cfobject type="java" action="create" name="factory" class="coldfusion.server.ServiceFactory">
         <cfset rpcService = factory.XmlRpcService>
         <cfset rpcService.refreshWebService(ws)>
      <cfelse>
         <cfobject type="java" action="create" name="factory" class="coldfusion.server.ServiceFactory">
         <cfset rpcService = factory.XmlRpcService>
         <cfset rpcService.refreshWebService(arguments.webservice)>
      </cfif>
   </cffunction>

   <!--- ************************************************************* --->

</cfcomponent>

BugLog and Coldbox Plugin

If you have heard of BugLogHQ, a nice centralized bug reporting application, written by Oscar Arevalo, and you want to integrate it with your Coldbox apps, then this article is for you.

Let's get started...

Be sure to set the Exception Handler in either the Coldbox config or your Environments.xml. For reference, 'main' is my handler and 'onException' is the method or event. By default, the value is blank in the config.

<Setting name="ExceptionHandler"         value="main.onException" />

Next, you need to add the WSDL URL to your Coldbox config file or your Environments.xml.

<Setting name="BugLogWSDL"                   value="http://bugs.mysite.com/listeners/bugLogListenerWS.cfc?wsdl" />

@UPDATE - ** WEBSERVICE PLUGIN UPDATED **

Now, go to that Exception Handler method we defined in the first step. Copy and paste this in there.

@UPDATE - UPDATED CODE HERE

Finally, create the BugLog.cfc and place it in your Plugins directory ('plugins' by default unless you specified otherwise in your CONVENTIONS).

Here's the code.

@UPDATE - UPDATED CODE HERE

That's it.

Now, Coldbox will deliver Bug Reports to the BugLog system, in addition to the internal Bug Reporting setting. If you don't want to use CB to deliver Email Reports then be sure to define that in your config or environments.xml.

<Setting name="EnableBugReports"          value="false" />

The Connect Recordings from CFUnited are now available on UGTV.

Even though I was unable to make the trip to DC, Rolando Lopez did an excellent job filling in for me. I will post the PowerPoint and Code Samples, as soon as I get Rolando's changes and updates.

In the meantime, here's the link to the recorded presentation from CFUnited. Adobe Connect

I have a handful of positions opening up here on the West Coast in Manhattan Beach, California.

If anyone is interested or knows anyone, please contact me for full job descriptions.

Senior & Junior CF Developer (experience with Coldbox a plus)

Front End Developer (jQuery, CSS, JS - Flash \ Flex a plus)

Quick Fix - Transfer and Reserverd Words

I ran in to this when I first started using Transfer ORM a while back, when I was building a new app. However, now I am curious for those working on an existing app and db structure.

If you have a table called User, for example, Transfer will throw an error. It generates the SQL without brackets [ ] and will usually indicate a syntax error. When really it's the reserved word USER that is throwing things off.

Originally, our team decided to rename the DB table to CoreUser and just map it in the XML to make the object look pretty. Again, this was for a new app we were building so it was early in the game and no additional refactoring was necessary at the time.

<object name="User" table="CoreUser">
<id name="UserId" type="GUID" column="UserId" generate="true" />

I did a quick Google search to see if any posts had mentioned another approach. Nothing new popped up, similar stories and struggles.

I happen to catch Mark online today and figured I'd run it by him. As always Mark hooked me up with a simple effective solution. So simple it made me feel stupid for not trying it.

Add the brackets to the table name in the transfer.xml file.

<object name="User" table="[User]">
   <id name="UserId" type="GUID" column="UserId" generate="true" />

Cake.

CFUnited Speaker Cancellation

Unfortunately, I had to cancel my trip to DC. A nasty case of Strep throat has me out of commission and living off of chicken soup right now.

I was really looking forward to the great opportunity and being a part this amazing event, Teratech worked so hard to put together.

I apologize to anyone who signed up for the session. In my place, I have asked Rolando Lopez, from About Web, to give my presentation.

Together IBM and AMD Break Speed Record

"A unique hybrid of Cell BE and AMD Opteron processors, has recorded an official throughput speed above one quadrillion floating point operations per second -- one petaflop."

You may have heard the phrase 'Cell technology' being thrown around before the Sony PS3 hit the shelfs. Well, sure enough the same basic architecture is being coupled with AMD Opteron processors to break new records when it comes to supercomputers and processing power.

The article goes on to mention that the tests were conducted last month at a benchmark of 1.026 petaflops. It notes Sun Microsystems has only a few weeks to make a run at there goal set back in June 2007 of 1.7 petaflops. But it looks like the DOE using IBM and AMD have set the bar fairly high.

Take a look at the full article: DOE supercomputer broke the petaflop barrier, conference acknowledges

More Entries