Enterprise Flex, , " />

FlashPlatformist
Articles, Information, News, & Tutorials for Adobe Flash Platform Developers and Architects

Architectural Analysis of the Swiz Framework, Part 2: Central Event Control

In this segment, we will analyze how Swiz handles events, and how to utilize this feature of Swiz in an enterprise level application. Before moving any further however, here is the “more advanced version” of the Swiz architectural diagram I created for Linux magazine once again:

Architectural Diagram of the Swiz Framework

Architectural Diagram of the Swiz Framework

In the diagram, the Bean Factory represents a pool of MXML Beans that extend the Swiz BeanLoader class. As stated in Part 1 of this series, the purpose of Beans is simply to declare objects that will be used in the application and to assign IDs to them so they can be referenced by name later when they are autowired. The interesting thing about Swiz is that when it does its introspection on the BeanLoader, it instantiates all of the objects and creates a pool, or “factory”, where the objects are handed over on demand. For larger applications, this could potentially result in a very slightly extended load time, but the benefit is immeasurable because the result is that the application runs noticeably smoother and considerably faster.

In order to simulate a somewhat larger-scale application, the diagram displays four beans, which have only been separated as a matter of convenience. In essence, beans hold a strong resemblance to object registries, especially when you consider that you are essentially registering the objects declared in the beans to be managed by Swiz.

Swiz includes a class called the CentralDispatcher, which can be accessed directly through the Swiz.as class. The CentralDispatcher extends the Flex EventDispatcher and implements a Singleton pattern. I refer to this class as the “Event Bus” because it is a centralized place in which all events can be fired from.  This makes things nice and easy for managing the code base. Consider the following example:

  1. In the main application MXML file, set an event handler on the applicationComplete event of <mx:Application/>, like so:
    applicationComplete="applicationCompleteHandler(event)"
  2. Place the following code in the event handler function:
    protected function applicationCompleteHandler(event:FlexEvent):void {
         var del:XMLParserUtil = new XMLParserUtil();
         uiController.delegate = del;
         Swiz.addEventListener(DataReadyEvent.CORE_READY, setDataProviders);
    }
  3. Create a controller class that extends the Swiz AbstractController. Here is an example:
    package com.danorlando.controller
    {
       import com.danorlando.controller.events.DataReadyEvent;
       import com.danorlando.model.Globals;
       import com.danorlando.model.MediaObject;
       import com.danorlando.model.ViewStackDataCollectionObject;
       import com.danorlando.util.XMLFactory;
       import com.danorlando.util.XMLParserUtil;
       import mx.collections.ArrayCollection;
       import org.swizframework.Swiz;
       import org.swizframework.controller.AbstractController;
    
       public class UIController extends AbstractController
       {
          public static const GLOBAL_SETTINGS:String = "config/globals.xml";
    
          private var _mediaDP1:ArrayCollection = new ArrayCollection();
          private var _mediaDP2:ArrayCollection = new ArrayCollection();
          private var _mediaDP3:ArrayCollection = new ArrayCollection();
          private var _globals:Globals;
          private var _delegate:XMLParserUtil;
    
          //getters
          public function get mediaDP1():ArrayCollection { return _mediaDP1 }
          public function get mediaDP2():ArrayCollection { return _mediaDP2 }
          public function get mediaDP3():ArrayCollection { return _mediaDP3 }
          public function get delegate():XMLParserUtil { return _delegate }
          public function get globals():Globals { return _globals }
    
          //setters
          public function set mediaDP1(ac:ArrayCollection):void { _mediaDP1 = ac }
          public function set mediaDP2(ac:ArrayCollection):void { _mediaDP2 = ac }
          public function set mediaDP3(ac:ArrayCollection):void { _mediaDP3 = ac } 
    
          [Autowire]
          public function set delegate(del:XMLParserUtil):void {
             _delegate = del
             XMLFactory.parseXML(GLOBAL_SETTINGS, _delegate.parseGlobalSettingsXML);
      // listening to the Swiz event bus for GLOBALS_READY, which informs the controller
             // that the global config file has been parsed and loaded...
             Swiz.addEventListener(DataReadyEvent.GLOBALS_READY, initGlobals);
          }
    
          public function UIController()
          {
             _globals = Globals.getInstance();
          }
    
          protected function initGlobals(event:DataReadyEvent):void {
             var dbpath:String = _globals.mediaDatabasePath + _globals.mediaDatabaseFile;
             XMLFactory.parseXML(dbpath, _delegate.parseMediaDatabaseXML);
             // listening for DATA_READY, which will be fired when the media database has been loaded
             Swiz.addEventListener(DataReadyEvent.DATA_READY, delegateData);
          }
    
          protected function delegateData(event:DataReadyEvent):void {
             if (event.collection == null) {
                throw new Error("NO MEDIA COLLECTION!"); return;
             }
             var data:ArrayCollection = event.collection;
             for each(var o:Object in data) {
             var obj:ViewStackDataCollectionObject = o as ViewStackDataCollectionObject;
             var name:String = obj.name;
             var coll:ArrayCollection = obj.collection;
             if (name == "Video Production") {
                for each(var ob1:Object in coll) {
                   var mo1:MediaObject = ob1 as MediaObject;
                   _mediaDP1.addItem(mo1);
                }
             }
             else if (name == "Video Art") {
                for each(var ob2:Object in coll) {
                   var mo2:MediaObject = ob2 as MediaObject;
                   _mediaDP2.addItem(mo2);
                }
             }
             else if (name == "Music Production") {
                for each(var ob3:Object in coll) {
                   var mo3:MediaObject = ob3 as MediaObject;
                   _mediaDP3.addItem(mo3);
                }
             }
          }
          // the main application class is listening for CORE_READY, which essentially
          // lets the application know that the data has been loaded and is ready to
          // be used. Again, the Swiz event bus is used as a way of keeping things
          // tidy and under control by ensuring that events aren't firing all over the place.
          Swiz.dispatchEvent(new DataReadyEvent(DataReadyEvent.CORE_READY));
        }
      }
    }
  4. The final piece of the equation is the XMLParserUtil, which fires two events through the Swiz event bus, GLOBALS_READY and DATA_READY, as seen in the following code:
    package com.danorlando.util
    {
       import com.danorlando.controller.events.DataReadyEvent;
       import com.danorlando.model.Globals;
       import com.danorlando.model.MediaObject;
       import com.danorlando.model.ViewStackDataCollectionObject;
       import mx.collections.ArrayCollection;
       import mx.core.IUIComponent;
       import org.swizframework.Swiz;
    
       public class XMLParserUtil
       {
          public function XMLParserUtil() { }
    
          public function parseGlobalSettingsXML(xml:XML):void {
             var globals:Globals = Globals.getInstance();
             globals.mediaDatabasePath = xml.mediaDatabasePath;
             globals.mediaDatabaseFile = xml.mediaDatabaseFile;
             globals.mediaBaseUrl = xml.mediaBaseUrl;
             globals.contentPath = xml.contentPath;
             globals.thumbsPath = xml.thumbsPath;
            // firing the event through Swiz to let the controller know that
             // the global configuration info is ready
             Swiz.dispatchEvent(new DataReadyEvent(DataReadyEvent.GLOBALS_READY));
          }
    
          public function parseMediaDatabaseXML( db:XML ):void {
             var mediaCollection:ArrayCollection = new ArrayCollection();
             for each(var x:XML in db..view) {
                var collObj:ViewStackDataCollectionObject = new ViewStackDataCollectionObject();
                collObj.id = x..@id;
                collObj.name = x..@name;
    	    for(var i:Number = 0 ; i < x.children().length(); i++) {
                   var obj:MediaObject = new MediaObject()
                   obj.type = x..mimetype[i];
                   obj.file = x..file[i];
                   obj.thumb = x..thumb[i];
                   obj.title = x..title[i];
                   obj.description = x..description[i];
                   obj.credits = x..credits[i];
                   collObj.collection.addItem( obj );
                }
               mediaCollection.addItem(collObj);
             }
           // creating a DATA_READY event and firing it through the Swiz event bus;
             // the data collection is sent along with the event when it is dispatched.
             var evt:DataReadyEvent = new DataReadyEvent(DataReadyEvent.DATA_READY);
             evt.collection = mediaCollection;
             Swiz.dispatchEvent(evt);
          }
       }
    }

The important thing here is to pay attention to the event flow between the main application file, the controller class, and the business delegate. The advantage of structuring it like this is that by centralizing the event flow, you maintain a higher level of control over what is happening and when it happens within the application. It also keeps things a lot tidier, which becomes more noticeable as the application grows.

Stay tuned for the final part to my series on the Swiz framework, where we’ll discuss the best part of the framework – autowiring.

Additionally, my article on Swiz should be published shortly by Linux magazine, in which case I will post that link here as well.

Possibly Related Posts:



Posted by Dan Orlando on May 16th, 2009 :: Filed under General
Tags :: , ,
You can leave a response, or trackback from your own site.

3 Responses to “Architectural Analysis of the Swiz Framework, Part 2: Central Event Control”

  1. Architecture Blogs
    May 23rd, 2009

    Architecture Blogs…

    [...] Architectural Analysis of the Swiz Framework, Part 2: Central Event Control – FlashPlatformist Articles, Information, News, & Tutorials for Adobe Flash Platform Developers and Architects. [...]…

  2. Tim Oxley
    October 6th, 2009

    But couldn’t you arbitrarily choose any object that extends EventDispatcher to centralise your events?

    Without looking at the Swiz source, can you please explain the benefit of choosing the Swiz object over say, the main application class?

  3. Dan Orlando
    October 8th, 2009

    To answer your first question, yes, anything that extends EventDispatcher can be used as an event bus. The objective here is to show the value in the design pattern really. The benefit of choosing the swiz object is in the ability to just call Swiz.dispatchEvent… so… A) you’ve got everything running through a single event bus, B) there is less code to write and less to keep track of, and C) this makes profiling the application for performance a lot more straight-forward, since a lot of system resources are required as the number of events scales.

    At the same time, this is merely a small part of Swiz… there is a much greater benefit to using the [Mediate] metadata with your events. That is part of what makes Swiz so unique and useful. I am currently writing a chapter on using Swiz, which will be published in “Flex 4 in Action”, and I’ll be doing additional posts in the not to distant future to help make this a lot clearer, so check back soon.

    Thanks for the questions!

Leave a Reply

Type your comment in the box below: