Wednesday, July 15, 2015

Reminder of Wirebox Dependency Injection Lifecycle

I remember reading it in the Wirebox Ref Card, but I actually ran into an issue with Wirebox dependency injection and a race condition today.  I wanted to blog about it just in case you started with Wirebox without reading the documentation end-to-end ;)

When you are using Wirebox mixin injection to autowire properties, dependencies are not injected until after your pseudo-constructor is called.  Here is an example that will fail:

 component accessors="true" {  
   property name="myDAO" inject="";  
   public function init() {  
     getMyDAO().myMethod();  
   }  
 }  

This will cause an error since myDAO has not been injected into the component before init() is called.  The solution is pretty simple:

 component accessors="true" {  
   property name="myDAO" inject="";  
   public function init () {  
   }  
   public function postInit() onDiComplete {  
    getMyDAO().myMethod();   
   }  
 }

Adding the onDiComplete annotation to the postInit() method tells Wirebox to run the method after it has instantiated the object and injected any dependencies.  I did notice that the method must be public which is unfortunate, but it makes sense.  This simple example is pretty useless, but in my case I needed to store a query into a singleton on instantiation so this was just the ticket.

Thursday, June 25, 2015

Wirebox: Creating a Transient Object in a Service

Today I had the need to create a transient object outside of the normal places Wirebox lives in a Coldbox application (handlers, interceptors, etc).  I come from a ColdSpring background, so I never used CS to handle any of my transients, but I wanted to see how Wirebox handled this so I could keep my object creation centralized.

There are several ways to handle creating a transient object in a ColdFusion service.  The easiest is to use createObject() or create a new object using the new keyword right where you need it like this:

var myObj = createObject("component", "path.to.my.Object");
 -or-
var myObj - new Object();

Another option is to have your service hand you a new object by defining a load() method:

public myObjectType function load () {
  return createObject("component", "path.to.my.Object");
}

The above method works best when using something like CF ORM, where you would specify an optional id parameter and use entityLoadByPK() and return a persistent object.  Overkill for what I need here (no persistence in this application).

What I ended up doing to keep my objects coming from a single source (Wirebox) was to inject Wirebox into my service and use the getInstance() method to hand me a transient instance of my object:

Wirebox.cfc
...
map("myObject").to("path.to.my.Object");
...

Service.cfc
component accessors="true" {
  property name="wb" inject="wirebox";
  ...
  function myFunc () {
    var myObj = getWB().getInstance("myObject");
  }
}

I figure doing it this way makes it much easier as I am presently moving around packages, so defining them once in Wirebox means I don't have to perform a search and replace once the packages settle - I just fix the path in the Wirebox configuration and all objects are updated when the application is reloaded.

Note that this works well for transient objects, but remember for singletons you would just inject them into a property in your service tier.

Tuesday, June 23, 2015

Maildev for Local Development

Recently at work I was tasked with finding a fake SMTP server that would capture emails for review for environments preceding Production. This is especially useful when you are importing production data for testing across environments and ensuring that your customers don't get test emails.  It's something we have all coded around with complex environment configurations in the past, and it offers a much simpler solution.

I looked around at quite a few solutions and most ended up being Windows service based. Being on a Mac they were less than useful, and given that my requirements included the need to move the configuration across multiple environments which are shared by a team of developers, those fell short as none included a web interface for reviewing emails. They all seemed to favor a desktop GUI which could not be viewed without logging in to each server for viewing.

Enter Maildev. Maildev is actively maintained and looks like it has been around for almost year now (probably longer, I'm just going by github commits).

There are a few ways to install, but I installed via npm.  It couldn't be simpler:

  1. Download and install NodeJS/NPM, unless you already have them (as you should!)
  2. Install Maildev using npm (npm install -g maildev).  You'll need to sudo for Mac/Linux.
  3. Start maildev by typing maildev
Pretty straightforward stuff.  Maildev starts on port 1025 by default.  The web interface is available at port 1080.  Maildev will listen on all IPs by default (0.0.0.0).  These are easy to configure using the command line options -s, -w, and --ip.

Installing this across environments permits you to capture emails on each specific environment, and binding Maildev instances to various IPs allows you to isolate email on a per application basis.  If you are on windows you can always install Maildev as a service using nssm.  On Linux you'd use a combination of forever (maybe) and upstart or chkconfig or whatever your flavor permits.  Let's face it, you're on Linux.  You'll figure it out.

Maildev also has some nice features like testing your emails in various viewports and viewing headers and attachments.

For my purposes using ACF or Railo, the mail config was moved to the app configuration and switches across environments using Ant filter tasks triggered by Jenkins.  I'm sure whatever language you are using has a similar simple configuration option to simplify the task.

Kudos to Dan Farrelly for creating such a useful development tool.

Friday, May 9, 2014

Quick ColdFusion WebSockets Gotcha

I've been playing around with CF WebSockets for a few days now and have just started to work on message filtering.  Through the use of a selector I can target messages to a single client (or range of clients).  This is great, as there was a bug in the implementation of Flash Remoting and ColdFusion that broke filtering.  This meant that I had to send messages to all connected clients and filter on the client side, which as you can imagine is noisy.

Here is the Javascript I am using to subscribe and publish where ws is the ColdFusion WebSocket object created with the cfwebsocket tag:
ws.subscribe("messaging.friends", {userid: $('#userid').val(), selector: "targetuser eq '"+userselector+"'"}, friendsCallback);

...

ws.publish("messaging.friends", $("#message").val(), {targetuser: $('#userid').val()});
The simple code above subscribes to the messaging.friends subchannel using a selector that jQuery grabs from a web form.  The second line of code published a message to that channel with the same targetuser to match the selection criteria.

When I tested filtering I found that all of my messages were being delivered regardless of filtering criteria.  I had read previously that if your channel listener CFC implemented the canSendMessage() method, that this would occur.  I had removed the offending function but all of my messages continued to arrive regardless of selector criteria.

After much frustration I restarted ColdFusion and everything started working.  What seems to have happened is that when CF the Java creates classes from your CFC it picks up on changes within a method, but does not pick up that a method has been removed until the server is restarted (or if the application ends would be my guess).  Hope this saves someone some time.

Friday, January 4, 2013

BlazeDS Error with an Illogical Fix

I've been having nothing but problems with BlazeDS lately, and I wanted to share an oddity I came across.

Configuration errors are the bane of my existence.  I don't want to know how BlazeDS works under the covers, it always just works.  That's why I use it, plus it's integration with Adobe ColdFusion and Grails (if you use the BlazeDS plugin).

For the past few days I have been receiving the error:
[BlazeDS]Exception occurred during serialization: java.lang.NullPointerException
NPE errors are always so helpful.  The basic setup is that CF sends an Apache Flex client messages.  Message1 occurs when a user signs in.  I notify the CF server via a RemoteObject call, and it then pushes a message out to all connected clients using BlazeDS the ColdFusionGateway channel.  This is working great and the Flex client receives the message via a consumer subscribed to an AMF polling channel.

The message in question occurs when a new person joins a group chat.  I send a DTO to CF via the sameRemoteObject, and then the CF sends a message to all clients that care about this specific group chat.  This fails with the above error when the client polls for its messages.  I am however, able to send the message from a browser test file through the same gateway and Flex receives the message and everyone is happy.

If I make the same call from Flex and disregard the DTO sent from Flex, creating my own DTO on the server side, I also get the error above.

What is weird is the first case works, and the second case does not.  The fix was to go into the config file that ColdFusion uses in its gateway config {cfroot}/WEB-INF/cfusion/gateway/config/flex-messaging-gateway.cfg and comment out the line "host=localhost".

The config file states:
# [Optional] The hostname or IP address of the Flex server.
# If omitted, the Flex server is expected to be installed as part
# of ColdFusion.  Specify 'localhost' if Flex is on this machine but
# not installed as part of ColdFusion.
I don't know what it means to install Flex as "part of ColdFusion" but the Flex client is running from the debugger, so it is definitely not part of ColdFusion.  I don;t think there has been a Flex Server component since version 1.5.  If they mean BlazeDS or Flash Remoting, then, maybe?  Either way, the configuration help needs improved upon.

While I can't explain what is going on here, I can at least provide the above solution so that someone else can save the 4 days it took me to figure this out.  Enjoy!

Thursday, January 3, 2013

ColdFusion 9 and ColdFusion 10 Together - Behind Apache HTTP Server

I have several projects using Adobe ColdFusion 9 and a new one starting on CF 10, so I needed to get CF 10 (running on Apache Tomcat of course) behind an Apache HTTP server.  I was having some issues finding anything via Google, but hidden behind a dead page that I could view only in text-mode via the cache was this gem from one of Adobe's ColdFusion engineers, Kavya: Co-existence of ColdFusion9 and ColdFusion10 using Apache web server

I was running a beta version of ColdFusion 10 so I had some issues initially, where the CF 10 instance ignoring the DocumentRoot directive and pushing me into the {cfwebroot}/cfusion/wwwroot directory.  One I reinstalled the latest release all was fine.

Two notes from Kavya's post:
  1. If you are not familiar with Apache HTTP server and are setting it up on multiple ports, you'll need to add Listen directives inside your httpd.conf file (e.g. Listen 81), one port per line.
  2. I set mine up all listening on port 80 and it worked beautifully.  Not sure if anyone still needs the workaround with multiple ports.
 Hope this cross-post will help Kavya's post get some traffic, as I couldn't find it on Google.

Monday, December 31, 2012

BlazeDS Error Solved

I have been working on a fun project that requires a streaming gateway between Adobe ColdFusion and Apache Flex.  I had a vanilla installation of CF 9.0.2 (after numerous attempts to configure my current setup) and was consistently getting the error:
Unable to find the Flex adapter for destination ColdFusionGateway in the RMI registry on localhost:1099
I haven't done much Java in some time and BlazeDS installed with CF 9 is generally pretty simple, so I correctly assumed the problem was configuration related instead of going down a rabbit hole.  The problem was that this code was working on another of my machines just fine, and this is a fresh install and the config files matched.

Googling brought up the same few posts which were not related to my situation, so I wanted to post the solution here quickly in case I can save someone else 3 days of hair-pulling.

In the end I had to change the definition for the ColdFusionGateway destination in messaging-config.xml.  I had to uncomment and set the gatewayhost property to localhost as shown below:
<gatewayhost>localhost</gatewayhost>
The help text states:
If ColdFusion is running on a different host, enter that here.  Default is to expect ColdFusion and Flex to share the same web application. You must enter 'localhost' if CF and Flex are not in the same web app.
This doesn't make sense since I am calling the messaging component from within ColdFusion (BlazeDS installs with CF 9+).  This is why I couldn't figure out what setting needed flipped.  I would understand if I was getting this message in my Flex application, as in my current test environment the Flex application I am working on I am running out of Flash Builder in debug mode.  The Flex project does not live anywhere within the context of ColdFusion so this setting would make sense.

I also don't recall ever having to do this prior to ColdFusion 9.0.2.  It is also worth noting that I am on Mac OS X Mountain Lion (10.8) and also reproduced this in 9.0.2 on OS X 10.7.

Regardless, I am back up and running, and if you are reading this I hope this helps you as well.