The Space For App Developers

Beyond Plain Old HTML Objects

Swiz 1.0 Chaining API explained

with 8 comments

Yesterday I was tasked to find the best way to bootstrap a Flex application that uses Swiz 1.0 RC1. The challenge was to initialize application controllers and data model in the right sequence. This is an AIR application so it had to initialize data from an SQLite database, make few calls to remote services to check for data updates and do couple of other things before user could actually see first screen. My initial thought was to create a StartupController that would invoke the proper functions in a right order. That was a good initial direction but things started to get more difficult when I had to deal with async remote calls and local async APIs such as the one from the SQLite database.

So my next thought was, why not to try the new Chaining API that comes with Swiz? After my first look at the documentation I wasn’t really sure how I should approach it but after more digging I managed to figure it out ;) Here is what I did. I kept my StartupController with its init function that gets called after the controller is constructed and all its dependencies are injected. This was ensured by the [PostConstruct] metadata that comes with latest version of Swiz. Next that function creates a chains of function calls, remote invocations and events that bootstrap my application.

This is my StartupController where everything starts:

package controllers
{
	import delegates.RemoteServiceDelegate;
 
	import flash.events.IEventDispatcher;
 
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
 
	import org.swizframework.events.ChainEvent;
	import org.swizframework.utils.chain.AsyncCommandChainStep;
	import org.swizframework.utils.chain.ChainType;
	import org.swizframework.utils.chain.CommandChain;
	import org.swizframework.utils.chain.EventChain;
	import org.swizframework.utils.chain.EventChainStep;
	import org.swizframework.utils.chain.FunctionChainStep;
 
	public class StartupController
	{
		[Dispatcher]
		public var dispatcher:IEventDispatcher;
 
		[Inject]
		public var remoteServiceDelegate:RemoteServiceDelegate;
 
		[PostConstruct]
		public function init():void
		{
			// Initializing sequential CommandChain, that will stop on errors
			var commandChain:CommandChain = new CommandChain(ChainType.SEQUENCE, true);
			// Registering event listener when chain execution is complete
			commandChain.addEventListener(ChainEvent.CHAIN_COMPLETE, commandChainComplete);
			// Registering event listener in case chain execution fails
			commandChain.addEventListener(ChainEvent.CHAIN_FAIL, commandChainFail);
 
			// Adding async chain step that invokes remote AMF service
			commandChain.addStep(
				new AsyncCommandChainStep(
					remoteServiceDelegate.ping,
					["ping param value"],
					pingResultHandler,
					pingFaultHandler));
			// Adding function step that calls local function
			commandChain.addStep(new FunctionChainStep(this.localFunction));
 
			// Initializing parallel event chain that will be nested in command chain
			var eventChain:EventChain = new EventChain(dispatcher, ChainType.PARALLEL, true);
			// Registering event listener when event chain execution is complete
			eventChain.addEventListener(ChainEvent.CHAIN_COMPLETE, eventChainComplete);
			// Registering event listener in case chain execution fails
			eventChain.addEventListener(ChainEvent.CHAIN_FAIL, eventChainFail);
 
			// Adding event chain step that will dispatch INIT_PERSISTENCE event,
			// this event is mediated in PersistenceController
			eventChain.addEvent(new EventChainStep("INIT_PERSISTENCE"));
			// Adding event chain step that will dispatch INIT_SOMETHING_ELSE event,
			// this event is NOT mediated anywhere, this just for example and better understanding
			// eventChain.addEvent(new EventChainStep("INIT_SOMETHING_ELSE"));
 
			// Nesting event chain in parent command chain
			commandChain.addStep(eventChain);
			// Starting whole command chain
			commandChain.start();
		}
 
		private function localFunction():void
		{
			trace("Running localFunction");
		}
 
		public function pingResultHandler(event:ResultEvent):void
		{
			trace("Received result from remote ping call:", event.result);
		}
 
		public function pingFaultHandler(event:FaultEvent):void
		{
			trace(event.fault.faultDetail);
		}
 
		private function commandChainComplete(event:ChainEvent):void
		{
			trace("CommandChain complete");
		}
 
		private function eventChainComplete(event:ChainEvent):void
		{
			trace("EventChain complete");
		}
 
		private function commandChainFail(event:ChainEvent):void
		{
			trace("CommandChain failed");
		}
 
		private function eventChainFail(event:ChainEvent):void
		{
			trace("EventChain failed");
		}
	}
}

Below is my PersistenceController that will initialize the local database; its init function is called when the INIT_PERSISTENCE event is dispatched. When the database initialization is finished event.complete(); has to be called in order to proceed with chain execution:

package controllers
{
	import flash.events.IEventDispatcher;
 
	import org.swizframework.utils.chain.EventChainStep;
 
	public class PersistenceController
	{
		[Dispatcher]
		public var dispatcher:IEventDispatcher;
 
		[Mediate("INIT_PERSISTENCE")]
		public function init(event:EventChainStep):void
		{
			trace("Initializing PersistenceController...");
			event.complete();
		}
 
	}
}

This last snippet demonstrates the RemoteServiceDelegate class, which can be used to invoke remote services. It works with AsyncCommandChainStep:

package delegates
{
	import mx.rpc.AsyncToken;
	import mx.rpc.remoting.RemoteObject;
 
	public class RemoteServiceDelegate
	{
		[Inject]
		public var remoteObject:RemoteObject;
 
		public function ping(param:String):AsyncToken
		{
			return remoteObject.ping(param);
		}
	}
}

You can download my demo project source code from here; note that it doesn’t do anything except print out traces to the console. This zip contains a build of latest Swiz source code from GitHub that has some FunctionChainStep fixes.

Written by Piotr Walczyszyn

August 11th, 2010 at 3:51 pm

Posted in Examples

Tagged with ,

8 Responses to 'Swiz 1.0 Chaining API explained'

Subscribe to comments with RSS or TrackBack to 'Swiz 1.0 Chaining API explained'.

  1. This is great, Piotr! I am curious about your comment on FunctionChainStep fixes. Can you send me a link to your fork or send me the code? I couldn’t find it on GitHub.

    Thanks!
    Ben

    Ben Clinkinbeard

    12 Aug 10 at 9:56 pm

  2. @Ben I updated the post, I actually used wrong wording. What I ment was a build of latest source from GitHub that had FunctionChainStep fixed. In the RC1 package available for download FunctionChainStep wasn’t completing and the chain was hanging.

    Piotr Walczyszyn

    13 Aug 10 at 8:32 am

  3. @Piotr,

    Often [in Flex] I use the “exercise” of transforming AS3 code to its MXML equivalent. This exercise [of using MXML tags instead of programmatic approaches] significantly improves the understanding of usages and highlights the relationships of the code parts.

    As such I converted your sample above to MXML:

    This code above is certainly more readable and clearly shows the nesting relationships. It is also more maintainable.

    Unfortunately it does NOT work!

    Often when converting AS3 code to/from MXML tags, developers can identify problems with the API (properties not being public, constructors not having default params, etc). When both usages [programmatic and MXML tag] work seemlessly, then the API is [guaranteed to be] a much more stable and robust implementation.

    This excercise – for me – highlighted several issues with the Chaining API in Swiz. I will bring this up with the Swiz team.

    Meanwhile, thanks very much for your example of using Swiz chaining.

    - ThomasB

    Thomas Burleson

    22 Aug 10 at 4:45 pm

  4. In my previous comment, my MXML tags obviously do not work. Here is the HTML-encoded version for the MXML snippet:

    <CommandChain id="commandChain"
    chainComplete="{commandChainComplete}"
    chainFail="{commandChainFail}">

    <AsynchCommandChainStep asyncMethod="{remoteServiceDelete.ping}"
    asyncMethodArgs="{['ping param value']}"
    resultHandler="{pingResultHandler}"
    faultHandler="{pingFaultHandler}" />

    <FunctionChainStep functionRef="{this.localFunction}" />

    <EventChain mode="{ChainType.PARALLEL}"
    chainComplete="{eventChainComplete}"
    chainFail="eventChainFail">

    <EventChainStep type="INIT_PERSISTENCE" />
    </EventChain>

    </CommandChain>

    Thomas Burleson

    22 Aug 10 at 4:47 pm

  5. [...] [and programmatic] samples. Recently Piotr Walczyszyn posted a great article on using the Swiz Chaining API. Swiz is a fantastic IoC/Injection MVC framework for Flex and Flash. While Piotr’s sample was [...]

  6. @Piotr,

    I thought this was great material for another blog article called “Creating great Flex libraries & APIs“.

    Thomas Burleson

    23 Aug 10 at 12:15 am

  7. @Thomas, thanks for your comments and your great blog post!

    Piotr Walczyszyn

    23 Aug 10 at 9:50 am

  8. Helpful information. Lucky me I discovered your site by chance, and I’m shocked why this twist of fate didn’t took place earlier! I bookmarked it.

    url shortener

    29 Oct 11 at 7:54 am

Leave a Reply