Fusioncube

The online journey of a technophile, by Steve Brownlee

Archive for June, 2009

ColdFusion Event Gateway for Flex Messaging

Monday
Jun 8,2009

Update

I’ve resolved the issue described in this article and wrote a tutorial based on my research:
Tutorial: Flex and ColdFusion Communication via Event Gateways

Problem

I’ve run into a snag getting ColdFusion to send messages to a destination set up for Flex Messaging. I’ve gone through all the tutorials and set up an event gateway in my local admin using the FlexMessaging type…
flex_messaging_cf_gateway

but any attempt to send a message to it….

x = structNew();
x.body = "hello world";
x.destination = "ColdFusionGateway";
sendGatewayMessage("test", x);

results in the following message…

Unable to find the Flex adapter for destination ColdFusionGateway
 in the RMI registry on localhost:1099.

The Flex adapter may not be running or the destination may be incorrect.

The error occurred in C:\ColdFusion8\servers\cfusion\cfusion-ear\cfusion-war\webapps\test\scribble.cfm: line 24

22 : x.body = "hello world";
23 : x.destination = "ColdFusionGateway";
24 : sendGatewayMessage("test", x);
25 :
26 :</cfscript>

I have modified my ColdFusion server to run BlazeDS, and I’m hoping that is not the issue. I’ll perform a clean installation and see if it works that way. The strangest thing about this is that when I send a message from a Flex client to the same destination, it finds the adapter just fine (this is all set up on a ColdFusion application server) so the fact that FMS works, but ColdFusion Event Gateways don’t is troubling.

Cairngorm: Abstract Events Updated

Wednesday
Jun 3,2009

Purpose

The intended purpose for the AbstractEvent class in Cairngorm was three-fold:

  1. Reduce the number of files needed to manage business events by organizing Events into domains
  2. Implement a callback feature so that a view can specify another action to perform upon the successful completion of an event
  3. Make each domain event class as lightweight as possible

Related Posts

Abstract Commands | Abstract Delegates

Concept

To accomplish these goals, each domain event (e.g. ProjectEvent, PaymentEvent, etc.) would be polymorphic (kinda) in that there is no longer just one identifier designated with the EVENT_ID constant. In addition, I wanted to abstract as much functionality and classification as possible into a common class that each domain event would extend.
abstract_event

Lightweight, Polymorphic Event Class

Here’s an example of a domain event. It has three public identifiers – CREATE_PROJECT, LOAD_PROJECTS, DEACTIVATE_PROJECT- and has no logic other than to pass its constructor’s arguments to AbstractEvent.

ProjectEvent.as

package business.events
{
   import com.adobe.cairngorm.control.CairngormEvent;

   public class ProjectEvent extends AbstractEvent
   {
      public static const CREATE_PROJECT:String = "createProject";
      public static const LOAD_PROJECTS:String = "getProjects";
      public static const DEACTIVATE_PROJECT:String = "deactivateProject";

      public function ProjectEvent(type:String, data:Object = null, callbacks:Array=null)
      {
         super(type, data, callback);
      }
   }
}

AbstractEvent Class

The AbstractEvent class itself isn’t much more complicated at all. It simply has three public variables to hold the type of the event, an object containing key/value pairs for the data, and the reference to the callback function in the view (if specified).

AbstractEvent.as

package business.events
{
   import com.adobe.cairngorm.control.CairngormEvent;

   public class AbstractEvent extends CairngormEvent
   {
      public var callbacks:Array = null;

      public function AbstractEvent(type:String, data:Object = null, callbacks:Array=[])
      {
         super(type);

         this.data = data;
         this.callbacks = callbacks;
      }
   }
}

Example View – Projects

Here’s some snippets of code from my project view. One piece of functionality is for a user to disable a selected project from a list in an AdvancedDataGrid. When the user clicks on the “Disable Project” button, the btnDeactivateProject_Click() function fires and creates a new Project event in which the loadProjects() function is specified as the callback function.

Projects.mxml

private function btnDeactivateProject_Click(e:Event):void
{
   var thisProject:Project = gridProjects.selectedItem as Project;
   new ProjectEvent(ProjectEvent.DEACTIVATE_PROJECT,
            {project:thisProject},
            [loadProjects]).dispatch();
}

public function loadProjects():void
{
   new ProjectEvent(ProjectEvent.LOAD_PROJECTS).dispatch();
}

<mx:Button id="btnDeactivateProject"
	click="btnDeactivateProject_Click(event)"
	x="10" y="393"
	label="Deactivate Project"/>

Mapping Events to Commands

Your controller logic doesn’t change. The only difference is that you’re using one domain event, with specified identities, mapped to different Commands.

Controller.as

package business
{
   import business.commands.*;
   import business.events.*;
   import com.adobe.cairngorm.control.FrontController;

   public class Controller extends FrontController
   {
      public function Controller()
      {
         super();
         addCommand(ProjectEvent.LOAD_PROJECTS, LoadProjectsCommand);
         addCommand(ProjectEvent.CREATE_PROJECT, CreateProjectCommand);
         addCommand(ProjectEvent.DEACTIVATE_PROJECT, DeactivateProjectCommand);
      }
   }
}

Cairngorm: Abstract Commands Updated

Wednesday
Jun 3,2009

Purpose

The intended purpose for the AbstractCommand class in Cairngorm is three-fold:

  1. Further implementation of a callback feature – in conjunction with the AbstractEvent – so that a view can specify other actions to perform upon the successful completion of business event
  2. Create a Responder object for the Delegate to use
  3. Make each Command class as lightweight as possible

Related Posts

Batch Commands | Abstract Events | Abstract Delegates

Concept

abstract_command

Standard, Responseful Command

Below is an example Command in my system, it extends AbstractCommand which in turn implements the ICustomCommand interface. To make the Command responseful, an array of functions is passed from the Event to the Command, which will execute them upon success (see more below). Here’s an example call:

new EmployeeEvent(EmployeeEvent.GET_DETAILS,
         {employee_id:params.empID},
         [showEmployeeDetails, updateEmployeeGraph])

To implement a very basic command, it is only required to set the delegate property to a new instance of the appropriate Delegate class, and then invoke the needed method. The AbstractCommand will automatically create a new Responder object and assign it to the delegate.

LoadProjectCommand.as

public class LoadProjectCommand extends AbstractCommand
{
   private var _model:ModelLocator = ModelLocator.getInstance();

   override public function execute():void
   {
      delegate = new ProjectDelegate();
      (delegate as ProjectDelegate).loadProject(invoker.data);
   }

   override public function commandSuccess(event:Event):void
   {
      if (event.result.success)
      {
         _model.project = (event as ResultEvent).result.data;
         notifyInvoker();
      }
   }
}
}

The invoker object is a reference to the original Event that was called, and to get it assigned as a property of the Command, I extended the FrontController class so that it is assigned before the Command is executed.

protected function executeAbstractCommand(event:AbstractEvent):void
{
   var commandRef:Class = getCommand(event.type);
   var commandToExecute:ICustomCommand = new commandRef();

   commandToExecute.invoker = event;
   commandToExecute.execute();
}

AbstractCommand Class

This class is straightforward and handles the tedious aspects of creating a Command. The notifyInvoker() method simply loops through the array of callback functions – if they exist – and runs them.

AbstractCommand.as

public class AbstractCommand
{
   private var _callbacks:Array = null;
   private var _invoker:AbstractEvent = null;
   private var _delegate:AbstractDelegate = null;

   public function AbstractCommand() { }
   public function execute():void { }
   public function commandSuccess(event:Event):void { }
   public function commandFault(event:Event):void { }

   public function set delegate(d:*):void
   {
      _delegate = d;
      _delegate.setResponder(new Responder(commandSuccess, commandFault));
   }

   public function get delegate():*
   {
      return _delegate;
   }

   public function set invoker(e:AbstractEvent):void
   {
      _invoker = e;
      if (e.callbacks != null) _callbacks = e.callbacks;
   }

   public function get invoker():AbstractEvent
   {
      return _invoker;
   }

   public function notifyInvoker(info:Object = null):void
   {
      if (_callbacks != null)
      {
         for (var i:uint = 0; i < _callbacks.length; i++)
         {
            var callback:Function = _callbacks[i];
           (info != null) ? callback.call(this, info) : callback.call(this);
         }
      }
   }
}

ICustomCommand Interface

ICustomCommand.as

package business.commands
{
   import business.events.AbstractEvent;
   import flash.events.Event;

   public interface ICustomCommand
   {
      function commandSuccess(event:Event):void;
      function commandFault(event:Event):void;
      function execute():void;
      function set invoker(event:AbstractEvent):void;
      function set delegate(delegate:*):void;
   }
}

Latest Tweets

  • Ok geek night completed. New #LOTRO area explored, new items acquired. Headed to bed.
  • @cfjedimaster yes case matters. Just like you couldn't - var Object:Object;
  • Oh, and the guy who randomly got the #1 pick, the one who said he's never done a draft before? #1 pick was........ Tony Romo!! #ffl #what?
  • Damn, just drafted monster fantasy team. Mendenhall, Gore, Grant, Brady, Steve Smith, Favre, Moreno, Harvin, et al. #sick #ffl
  • My dog eating a mouse in my bathroom @ 11:20 PM http://twitpic.com/2kpw7s