The Space For App Developers

Beyond Plain Old HTML Objects

UnFramework – or how to work without any frameworks

with 8 comments

Those who know me or at least subscribe to my blog know that I’m a big fan of Flex/AS3 frameworks. At this year’s Adobe MAX conference I even had my own session where I covered five major DI frameworks. Usually these frameworks provide a lot of productivity features and helpers like: IoC/DI, Event/Messaging bus, implementation of some architectural or design patterns (MVC, Command…), and many others. But what happens if we can’t or don’t want to use any of these frameworks?

Well, we fall back to pure Flex and we start missing things…

This is something that happened to me very recently when I started to play with Flex Hero and I wanted to build my first Flex mobile application. As the targeted runtimes are rather constrained in processing power I knew I would have to make certain sacrifices in order to make things as light as possible.

First I started to wonder what general architectural pattern I should follow. After looking at Flex Hero and its new MobileApplication, ViewNavigator and View concepts, I knew that I was still okay with using the Presentation Model pattern.

Next I took a look at DI frameworks – well here I really didn’t find a suitable candidate. Most of these rely heavily on reflection, metadata processing, or stage events capturing for view wiring, and these unfortunately are not really very lightweight. That is why at the end of the day I made a decision not to use any of these, and instead decided to substitute some of their features with simple helpers or pure Flex functionality.

Global Event Dispatcher

The thing I missed most thing was a global dispatcher that I could use to dispatch events from my Presentation Model or any other pure AS3 classes. The approach I took was as simple as creating a global eventDispatcher property in the default package in a eventDispatcher.as file, as follows:

// eventDispatcher.as script file
 
package 
{
	import flash.events.IEventDispatcher;
 
	public function get eventDispatcher():IEventDispatcher
	{
		return _eventDispatcher;
	}
}
 
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
 
var _eventDispatcher:IEventDispatcher = new EventDispatcher();

That step gave me access to eventDispatcher object anywhere in my code:

public class MyViewPM
{
    public function btn_clickHandler():void
    {
        eventDispatcher.dispatchEvent(new MyEvent(MyEvent.EVENT_TYPE));
    }
}

RemoteObject’s handling

The next thing I wanted was a clean and simple way of handling RemoteObject calls and configuration. What I really missed here was the approach from the Swiz Framework with its ServiceHelper.executeServiceCall function where you can pass an AsyncToken object returned from the RemoteObject call together with the ResultEvent and FaultEvent handlers as the other two parameters.

Another thing I really wanted was a declarative (MXML based) configuration of my RemoteObjects and to have a services registry without the use of ServiceLocator pattern. That is why the following code is a bit more complex but I think it’s still worth it and of course very light:

// remoteService.as script file
 
package
{
	import com.riaspace.un.IRemoteService;
 
	public function get remoteService():IRemoteService
	{
		return _remoteService;
	}
}
 
var _remoteService:IRemoteService = new RemoteService();
 
import com.riaspace.un.IRemoteService;
 
import mx.rpc.AsyncToken;
import mx.rpc.Responder;
import mx.rpc.remoting.Operation;
import mx.rpc.remoting.RemoteObject;
 
internal class RemoteService implements IRemoteService
{
	private var configObj:Object;
 
	public function set config(value:Class):void
	{
		configObj = new value();
	}
 
	public function getRemoteObject(remoteObjectId:String):RemoteObject
	{
		if (configObj)
			return configObj[remoteObjectId];
		return null;
	}
 
	public function callDirectly(token:AsyncToken, resultHandler:Function, faultHandler:Function):void
	{
		token.addResponder(new Responder(resultHandler, faultHandler));
	}
 
	public function call(remoteObjectId:String, methodName:String, args:Array = null, resultHandler:Function = null, faultHandler:Function = null):void
	{
		var remoteObject:RemoteObject = getRemoteObject(remoteObjectId);
		if (!remoteObject)
			throw new Error(remoteObjectId + " not configured!");
 
		var method:Operation = remoteObject[methodName];
		method.arguments = args;
		callDirectly(method.send(), resultHandler, faultHandler);
	}
}

As you can see you can use the above code in multiple ways. The first one requires no additional configuration and uses only remoteService.callDirectly function:

// some AS3 class
 
...
remoteService.callDirectly(myRemoteObject.remoteMethod(param), remoteMethod_resultHandler, 
    remoteMethod_faultHandler);
...
 
private function remoteMethod_resultHandler(event:ResultEvent):void
{
    // Handle remote method call result
}
 
private function remoteMethod_faultHandler(event:ResultEvent):void
{
    // Handle remote method call fault
}

The next option requires defining a config class that should extend simple Object; the best way is to do it in MXML like this:

// RemoteServiceConfig.mxml file
 
<?xml version="1.0" encoding="utf-8"?>
<fx:Object xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark">
 
	<fx:Declarations>
 
		<s:ChannelSet id="channels">
			<s:AMFChannel url="http://yourhost.tld/services/amf" />
		</s:ChannelSet>
 
		<s:RemoteObject id="myRemoteObject" destination="someDestination" channelSet="{channels}" />
 
	</fx:Declarations>
 
</fx:Object>

After you have your configuration class defined you can set it to the remoteService.config property, most probably somewhere at the very beginning of your application lifecycle:

// Main.mxml file
...
 
protected function mobileapplication_creationCompleteHandler(event:FlexEvent):void
{
    remoteService.config = RemoteServiceConfig;
}
 
...

So now you are ready to call the RemoteObject methods, and you can do that like this:

// some AS3 class
 
...
remoteService.call("myRemoteObject", "remoteMethod", [param], remoteMethod_resultHandler, 
    remoteMethod_faultHandler);
...
 
private function remoteMethod_resultHandler(event:ResultEvent):void
{
    // Handle remote method call result
}
 
private function remoteMethod_faultHandler(event:ResultEvent):void
{
    // Handle remote method call fault
}

Application context

The last thing I was really missing was some type of global application context/registry where I could read or write application objects. The approach I took goes beyond a simple singleton dynamic object. It is actually a bindable (event dispatching) singleton dynamic object ;) You can see it’s implementation below:

// applicationContext.as file
 
package
{
	public function get applicationContext():ApplicationContext
	{
		return _applicationContext;
	}
}
 
var _applicationContext:ApplicationContext = new ApplicationContext();
 
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.utils.Proxy;
import flash.utils.flash_proxy;
 
import mx.events.PropertyChangeEvent;
import mx.events.PropertyChangeEventKind;
 
use namespace flash_proxy;
 
internal dynamic class ApplicationContext extends Proxy implements IEventDispatcher
{
 
	private var values:Object;
 
	private var contextEventHandler:IEventDispatcher;
 
	public function ApplicationContext()
	{
		contextEventHandler = new EventDispatcher(this);
		values = new Object();
	}
 
	flash_proxy override function getProperty(name:*):*
	{
		return values[name];
	}
 
	flash_proxy override function setProperty(name:*, value:*):void
	{
		var oldValue:* = values[name];
		values[name] = value;
		var kind:String = PropertyChangeEventKind.UPDATE;
		dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE, false, false, kind, name, oldValue, value, this));
	}
 
	public function hasEventListener(type:String):Boolean
	{
		return contextEventHandler.hasEventListener(type);
	}
 
	public function willTrigger(type:String):Boolean
	{
		return contextEventHandler.willTrigger(type);
	}
 
	public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0.0, useWeakReference:Boolean=false):void
	{
		contextEventHandler.addEventListener(type, listener, useCapture, priority, useWeakReference);
	}
 
	public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
	{
		contextEventHandler.removeEventListener(type, listener, useCapture);
	}
 
	public function dispatchEvent(event:Event):Boolean
	{
		return contextEventHandler.dispatchEvent(event);
	}
}

The way to use this is, of course, very simple:

// some AS3 class
...
applicationContext.myObject = new MyObject();
...
 
 
// another AS3 class
...
var myObject:MyObject = applicationContext.myObject;
...

The cool thing about this approach is that you can actually bind to your applicationContext.myObject without getting this nasty warning: unable to bind to property 'foo' on class 'Object' (class is not an IEventDispatcher).

Also if you would like to listen for changes done to applicationContext properties you can do it like this (in order to make code completion work you need to cast applicationContext to IEventDispatcher):

// some AS3 class
...
IEventDispatcher(applicationContext).addEventListener(
    PropertyChangeEvent.PROPERTY_CHANGE, applicationContext_changeHandler);
...

My UnFramework approach summary

So in the end you can see there is actually life ;) without frameworks, especially when you are building not very complex applications that don’t require module support (in that case the singleton approach used here would fail).

Now please don’t accuse me of building yet another framework (we already have plenty of really great ones available) but I have packaged all these helper functions into a Flex Library project and pushed it into a GitHub repository. As I said this is not a framework so its called un-framework and it is available for download from here and as a swc from here.

Stay tuned for my upcoming posts where you will see these functions in action on some of my Flex Mobile apps.

Written by Piotr Walczyszyn

November 16th, 2010 at 4:45 pm

Posted in Articles,Examples,Releases

Tagged with , ,

8 Responses to 'UnFramework – or how to work without any frameworks'

Subscribe to comments with RSS or TrackBack to 'UnFramework – or how to work without any frameworks'.

  1. Very good post,

    julien

    16 Nov 10 at 7:03 pm

  2. Great tutorial on creating our own “not” framework, thanks a lot.
    How about the performance impact? Is global event handler, remote service, and app contect has performance impact???

    HERLoct_HENT

    16 Nov 10 at 7:35 pm

  3. Hi,
    for your global event dispatcher, i believe you should only use the EventController Library (not a framework). It’s light and does the job well:
    http://fla.as/ec/

    Fabien

  4. [...] video recording with an un-framework overview. This simple library has evolved a little bit from my previous post but I expect it will stay in this form for good I don’t think it can evolve to anything more [...]

  5. In reading your post I had to pause at eventDispatcher.as and go do some googling. I did not know you could create a package-level variable that could be accessed globally like that. I was not able to find any documentation on package-level variables, although I found a section on package-level functions in Moock’s “Essential ActionScript 3.0″ page 88. Interesting.

    Jamie McDaniel

    30 Nov 10 at 5:41 pm

  6. Great site keep going good work.

    Raja

    18 Jan 11 at 2:59 pm

  7. This blogpost is fantastic.

    Revan

    29 Jan 11 at 11:10 pm

  8. Great Tutorial…I really like RemoteObject’s handling section.
    Thanks

    Raja

    23 Feb 11 at 9:45 am

Leave a Reply