The primary focal point for aMVC is the anaonymous controller. this class is in fact the motivator for the creation of the aMVC architecture. The basic underlying motivation was a centralized point of control for messaging that was not dependent on global constants, or a priori knowledge of events or functional commands.
This is one of the major drawbacks of architectures like Cairngorm (other than class overload). In Cairngorm, the FrontController class is a central mechanism in  the application that links events to responders (Commands). In a shared production environment, this requires an integration step in development work to capture all communication in a central place. In the original formulation there was also a conflict introduced by using Modular development, where there was conflict between the central application controller, and those built to support Module functionality. This conflict was resolved, thanks to work by groups such as Universal Mind, by allowing the application controller to register the FrontControllers of individual modules

In the aMVC formulation, the Controller class acts as a message gateway. Events, defined as constants elsewhere in application, are registered with the controller anonymously via the use of a Dictionary. As part of this registration (via the EventRegistrationDTO), a responder is passed and assigned via the Dictionary to this event. This initial registration and that of other interested parties are captured in the same Dictionary entry. When an event of this type is dispatched, all interested parties are notified of the event via the registered responder.

The controller neither knows nor cares who is doing the registration, who dispatched the event (is is dispatched directly on the controller, which is a Singleton), or who will handle (or initiate) actions that correspond to this event.  As outlined in the function relationship diagram, a typical flow would have a Command instance registering interest with the Controller for an event that is dispatched by a view component that responds to user interaction. This is not the only scenario e.g. view registers response handler from an event dispatch elsewhere in the application.

The framework relies on a single event Class the DataTransportEvent that can be utilized to pass any data or none. These classes are outlined here:

Controller.as

/*
 * Controller.as
 *
 * Copyleft(c) 2010 Darin Kohles.  All Rights Reserved.
 *                        www.dkohles.com
 *
 * Date: April 10, 2010
 * Author: darin@dkohles.com
 *
 */
package com.dkohles.core.control
{
import com.dkohles.core.base.SingletonBase;
import com.dkohles.core.events.DataTransportEvent;
import com.dkohles.core.events.EventRegistrationDTO;

import flash.utils.Dictionary;

import mx.rpc.IResponder;

public class Controller extends SingletonBase
{
private var responseDirectory:Dictionary;
private var eventDirectory:Dictionary;

protected var svc:M3RemoteServices;
protected var model:M3Model;

public function M3Controller()
{
super();
}

/**
* Add a responder to an event type. Used by module classes to register interest in
* external events.
* @param reg pass through object containing event type information and the responder for the event.
*
*/
public function registerHandler( reg:EventRegistrationDTO ):void
{
if( eventDirectory == null ){
eventDirectory = new Dictionary();
}

if( eventDirectory[ reg.eventName ] == null ){
eventDirectory[ reg.eventName ] = true;
addEventListener( reg.eventName, handleEvent );
}

if( responseDirectory == null ){
responseDirectory = new Dictionary();
}

if( responseDirectory[ reg.eventName ] == null ){
responseDirectory[ reg.eventName ] = new Array();
}

( responseDirectory[ reg.eventName ] as Array).push( reg.responder );
}

/**
* Remove notification interest by responder. Used to decouple component from external
* events that had been previously been tracked. Also clean up the controller dictionary
* if no other parties are interested.
*
* @param reg pass through object containing event type information and the responder for the event.
*
*/
public function deRegisterHandler( reg:EventRegistrationDTO ):void
{
var index:int = (responseDirectory[ reg.eventName ] as Array).indexOf( reg.responder );
if(index >=0 ) (responseDirectory[ reg.eventName ] as Array).splice( index, 1 );

if( (responseDirectory[ reg.eventName ] as Array).length == 0)
{
responseDirectory[ reg.eventName ] = null;
this.removeEventListener( reg.eventName, handleEvent );
}
}

/**
* Pass the event directly to the responder(s) directly.
*
* @param evt event fired by normal application flow or user gesture
*
*/
private function handleEvent( evt:DataTransportEvent ):void
{
var respArray:Array = responseDirectory[ evt.type ];
if( respArray != null && respArray.length > 0 ){
for(var i:int = 0 ; i < respArray.length ; i++ ){
if( (respArray[i] as IResponder).result != null ){
(respArray[i] as IResponder).result( evt.data );
}
}
}
}

/**
* Retrieve responders for a given event.
*
* @param evt event type of interest.
*
*/
private function getResponders( type:String ):Array
{
var respArray:Array;
if( eventDirectory[ type ] ){
respArray = responseDirectory[ type ];
}
}
}
}

EventRegistrationDTO.as

/*
* EventRegistrationDTO.as
*
* Copyleft(c) 2010 Darin Kohles.  All Rights Reserved.
*                        www.dkohles.com
 *
* Date: April 10, 2010
* Author: darin@dkohles.com
*
*/
package com.dkohles.core.events
{
import mx.rpc.IResponder;
import mx.rpc.Responder;

public class EventRegistrationDTO
{
public var responder:Responder;
public var eventName:String;

public function EventRegistrationDTO( evt:String, resp:Responder )
{
this.eventName = evt;
this.responder = resp;
}

}
}

DataTransportEvent.as

/*
* DataTransportEvent.as
*
* Copyleft(c) 2010 Darin Kohles.  All Rights Reserved.
*                        www.dkohles.com
 *
* Date: April 10, 2010
* Author: darin@dkohles.com
*
*/
package com.dkohles.core.events
{
import flash.events.Event;

public class DataTransportEvent extends Event
{
public var data:*;

public function DataTransportEvent(type:String, data:*, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);

this.data = data;
}

}
}

SingletonBase is the fundamental underlying class for the Anonymous MVC framework. All of the major support components of the framework extending this class. In this implementation, a single instance is spawned that parents all sub-class children. By adopting this approach items such as the Controller can register without conflict with co-existing Controllers from other parts of the application when used in Modular development. This allows applications to be sub-divided and developed independently without fear of naming conflict as singletons are recorded by fully qualified Class. This leaves centralization of functionality as an option to the development and not a requirement.

/*
 * SingletonBase.as
 *
 * Copyleft(c) 2010 Darin Kohles.  All Rights Reserved.
 *                        www.dkohles.com
 *
 * Date: April 10, 2010
 * Author: www.dkohles.com
 *
 */
package com.dkohles.core.base
{
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;

	/**
	 * Base class implementation of Singleton pattern. Single static storage for
	 * extending Class instances are stored via Dictionary.
	 *
	 */
	public class SingletonBase extends EventDispatcher
	{
		private static var instanceDict:Dictionary = new Dictionary();

		/**
		 * Public constructor. Never called directly, only through a reference call to super()
		 * from an extending sub class.
		 *
		 */
		public function SingletonBase()
		{
			var className:String = getQualifiedClassName( this );
			var clss:Class = getDefinitionByName( className ) as Class;

			if( clss == SingletonBase ){
				throw("SingletonBase is a base class that cannot be instantiated");
			}

			var instance:Object = instanceDict[clss];
			if( instance != null ){
				throw("Classes extending SingletonBase can only be instantiated once by the getInstance method");
			}else{
				instanceDict[clss] = this;
			}
		}

		public static function getInstance( clss:Class ):Object
		{
			var instance:Object = instanceDict[clss];

			if( instance == null ){
				// create a new instance of the given class
				instance = Object( new clss() );

				var singleton:SingletonBase = instance as SingletonBase;
				if( singleton == null ){
					throw("getInstance can only be called for Classes extending SingletonBase");
				}
			}

			return instance;
		}
	}
}

Please notice that the singleton base extends EventDispatcher. This allows instances to act as event capture points, which will be further illustrated in future posts.

The motivation behind the Anonymous MVC Framework (aMVC), was to separate the aspects of frameworks like Cairngorm and Pure MVC that simplify and empower application development, while avoiding the pitfalls of “centralization” that come with these implementations. The “Anonymous” portion of this framework is the use of a centralized control mechanism that simply acts as a traffic monitor for user and application initiated events.

The basic concept here is that “players” will register their interest in various events via the central controller. “Players” can be individual view components, or more commonly a command class representing a portion of the view (or it’s entirety). Part of the registration process is the pass-through of a callback function. It is in this callback that the actual activity triggered by the event is done. The callback can act within the command class, via a delegate, or directly within a view.

The framework advocates the use of a central application model (singleton), but does not preclude multiple models representing distinct portions of the application. This same holds true of all aspects of the framework, as each portion, instantiated as a singleton, is based on the qualified class. If you want to use the centralized version, call the base class, if you want to divide responsibility, simple extend the base for local use (as in Modules etc..).  The overall structure is as follows:

Framework Overview

Because of the anonymous nature of this framework, the components can be wired together with many variations:

In future posts I will elucidate further the components of this framework.

Anonymous MVC

October 15

Since I haven’t blown the dust off my blog in some time (cough). I thought I’d finally put out access to and a description of a framework I’ve been working on. The basic motivation was implementation of a basic messaging framework that is simpler and more loosely coupled than Cairngorm. The result utilizes Singletons as the basis for Command, Control and Service (as well as Model if desired) nodes that act without specific knowledge of the View components that will utilize their functionality. By decoupling this functionality, development work on projects with broad scope, and many developers can proceed very easily. Each individual contributors work can be instantly integrated.

I hope this teaser will have you checking back soon, as I will start with the basics, including code. This framework can easily be scaled from small projects to large, which I will explain in future posts.

I recently wanted to wrap a ColdFusion webservice in a single point-of entry interface. In ColdFusion 8, they have introduced the “missing method” design pattern, such that a call that tries to reach a function that does not exist can be handled without a harsh error return. So I thought to myself: “Self, this could be the lazy mans way of making an interface.” I don’t have to write stubs for function calls that get forwarded.

And it works great!!!     (for cfm pages)

But for one caveat. I’m trying to use it with Flash Remoting through calls from a Flex app.

The experience that I’ve encountered was basically that a call through this interface would execute fine: The code would execute for a function call (I could step through it within a ColdFusion debug session in Eclipse), but the interface via Flash Remoting, would have already reported back the ‘function not found’, so when the server side code tried to report back, it was too late, the initial error message was already processed.

Filed Bug: https://bugs.adobe.com/jira/browse/FP-1455

Please Comment, and/or vote!!

Shockingly, your Flex (or Flash) application will not take center stage for all clients and all situations. Frequently the application simply provides a useful interface for some utility, but is not or does not contain, the featured content itself. In this situation you’ll only want/need to have the application loaded or visible when the user requires interaction with the provided functionality. Often there will be a central location (page) where the application is available. The underlying reasons for this, especially for assets embedded in a web site, is the fact that the application has a footprint that pushes out the surrounding content, or prevents interaction with content that may be visible ‘beneath’ the application when the wmode is set.

On a recent client e-commerce implementation the requirement was for their shopping cart to be ubiquitous, but not overbearing. In this case the normal HTML content of the site was what the client wanted featured, not the cart that would only be used occasionally by some visitors. In other situations, the approach is to either have a fully integrated shopping experience where products are displayed and managed within the application, or to have a single cart/check out page for the application that is displayed when the user wants to view the current contents and to place their order. In this case the ‘products’ were not visual and didn’t lend themselves to an all-in application approach, also the client wanted ready access to their cart without having to redirect to a dedicated page. So the approach taken was to ‘hide’ the cart.

In this situation, we chose to leverage the browser to achieve our ends. This involved the use of layering and absolute positioning via interaction with the ExternalInterface class and css and JavaScript in the browser. The basic idea here is to push the application ‘off’ the page and only make it visible when it is needed. This also allows the entire web page to be interactive when the application is hidden, while at the same time having the application standing by when it is needed.

The fully realized application lives Here. And a toned down version with source code can be found Here.

One further feature of this application was the use of the iframe to provide regular form processing for cart items that require further user input. The client wanted to be able to add and customize these forms through the CMS which precluded making them pre-compiled within the application and budget prevented dynamically building them. The compromise was to intercept the form post on the back end, and feed the results back into the application.

Demo application source.

If you’ve ever wanted to refresh a tired web interface by replacing your traditional HTML forms with a more user friendly interface, you may have encountered some of the thoughts which are addressed here. I’ll describe a method to utilize the power of Flex components in conjunction with some simple ColdFusion tags to make this process as simple as possible. You’ll end up with (hopefully) a better user inteface; and be able to centralize multiple forms into a refreshless (page that is) interface.

The Black Box Approach

One of the first things that you’ll encounter is a list of questions:

  • What does this form capture?
  • What validation is being used on the data input (e.g. o.length>6?b7(o):false;)?
  • What is returned to the user when the form is posted? What if there is an error?
  • What server side technology is used to process the form data (php, asp, jsp, cf, perl, vb.net, c#, tcl, cgi)?
  • What business logic is used on the data to generate the response the user gets from their submission?
  • What databases etc… are effected by this form post?

As the above questions show, you can quickly come to realize that you don’t necesarily want to have to reproduce what the form does, and in many cases you don’t actually know the answers to some of these questions. Wouldn’t it be easier to treat the form as a Black Box, and send it one it’s merry way? Yep, and here’s how.

The Example

In the example shown here, I wanted to make my case as simply as possible. To this end I chose a web based form that provided some simple feedback for valid posts, and an easy way to determine if it wasn’t; it’s also a very tolerant form in that it didn’t impose things like captcha if you put in bad form data as a form of punishment (well, ok security). With this in mind, I decided to use the Weather Channel’s ® form at the top of their home page where you enter your city (I’m using the zipcode option for, again, simplicity)

The Code

The simplicity of this example is that fact that I’m using Flash Remoting via the RemoteObject mxml tag.

<mx:RemoteObject id=”blackBoxRO” destination=”ColdFusion” source=”BlackBox.components.blackbox” showBusyCursor=”true” >
<mx:method name=”getTemp” result=”handeResult(event)” fault=”doh(event)” />
</mx:RemoteObject>

If you don’t happen to have ColdFusion on your own server, but have say a rich uncle who does, you can use the same CFC (ColdFusion component for the uninformed) to provide a Web Service that will accomplish the same task. Just update the path information and the local variable serverURL (can be passed as flashVar) to your ColdFusion web root.

<mx:WebService id=”blackBoxWS” wsdl=”{serverURL}/blackbox/components/blackbox.cfc?wsdl” >
<mx:operation name=”getTemp” result=”handeResult(event)” fault=”doh(event)” showBusyCursor=”true” />
</mx:RemoteObject>

The magic all happens inside the ColdFusion function with the call that populates the “real” form with the data you send from Flex and posts your submission. All you have to do now is look at the response and what it means for success or failure, which you then return to Flex to do with as you please.

<cfcomponent>
<cffunction name=”getTemp” access=”remote” returntype=”string” output=”yes”>
<cfargument name=”zipcode” type=”string” required=”yes”>
<cfset var returnValue = “”>
<cftry>
<!— use CF http request to post form data —>
<cfhttp url=”http://www.weather.com/search/enhanced&#8221; method=”post” delimiter=”,” resolveurl=”no” >
<cfhttpparam type=”formfield” name=”where” value=”#ARGUMENTS.zipcode#”>

The key thing to look for in using this technique is to make sure that you capture all the form inputs and spell them exactly as they appear in the “real” form (this includes hidden fields! so don’t over look these). You can usually easily determine what fields are present by viewing the source of the web page with the form, or using a tool like FireBug to peruse the html.

Get the source.