Getting Started with the PureMVC Startup Manager - Part 2
The StartupMonitorProxy
A PureMVC-based application typically has a startup command that instantiates some basic proxies and mediators. In our sample project we want to load a CSS stylesheet and an XML file with content before allowing any user interaction (see part 1). The important thing here is to make sure that everything gets loaded in the proper order and is fully loaded before it is accessed. Here is where the StartupMonitorProxy steps in. This class is at the core of the Startup Manager utility.
The StartupMonitorProxy takes care of how the resource loading should be sequenced so that dependent resources are loaded in correct order. It also keeps track of the progress of the resource loading, and it knows when the resource loading is complete. The way you use the StartupMonitorProxy is pretty straightforward:
- A single instance of the
StartupMonitorProxyis registered which is usually referred to as the monitor. - Each startup resource is registered with the monitor, using the
addResource()method. - The loading process is started by calling the monitor’s
loadResources()method.
(For a more detailed description please refer to the excellent API documentation.)
Now let’s take a quick look at the other actors that are needed to make the startup utility work.
The StartupResourceProxy
For each startup resource the application must instantiate a StartupResourceProxy object. These objects are required only by the utility and must not be confused with the normal resource proxies that represent the data carrier objects of the model. The regular proxies are instantiated and registered with the application first. After that the StartupResourceProxy objects are instantiated, receiving the resource proxy instance and a separate startup resource name. The two proxy types are like twins, but they live in different worlds. We will shortly see what this looks like in code.
“Loaded” and “Failed” Notifications
In order to inform the monitor that a resource has been loaded successfully or that the resource load has failed, the application must register the utility commands StartupResourceLoadedCommand and StartupResourceFailedCommand. These commands are responsible for sending “Loaded” and “Failed” notifications to the monitor whereby the notification body identifies the particular resource.
Updating the Project Space
Before we continue with the actual ActionScript code, let’s create some more class files in our project space.
- Create a file with the name StartupCommand.as in the controller folder.
- Create three new files in the model folder and name them EntityProxy.as, SiteDataProxy.as, StyleSheetProxy.as.
- Create a new folder vo under the model folder.
- Create a file with the name SectionVO in the vo folder.
Your project panel should look like this now:

The ApplicationFacade
We are starting with the ApplicationFacade class (if you followed part 1 of this tutorial you can paste the code below into the already existing empty ApplicationFacade.as file). It pretty much looks like a typical PureMVC facade:
-
package com.log2e.puremvcdemo
-
{
-
import org.puremvc.as3.interfaces.IFacade;
-
import org.puremvc.as3.patterns.facade.Facade;
-
import org.puremvc.as3.utilities.startupmanager.controller.StartupResourceLoadedCommand;
-
import org.puremvc.as3.utilities.startupmanager.controller.StartupResourceFailedCommand;
-
import com.log2e.puremvcdemo.controller.StartupCommand;
-
-
public class ApplicationFacade extends Facade implements IFacade
-
{
-
public static const STARTUP:String = "startup";
-
public static const STYLE_SHEET_LOADING:String = "styleSheetLoading";
-
public static const STYLE_SHEET_LOADED:String = "styleSheetLoaded";
-
public static const STYLE_SHEET_FAILED:String = "styleSheetFailed";
-
public static const SITE_DATA_LOADING:String = "siteDataLoading";
-
public static const SITE_DATA_LOADED:String = "siteDataLoaded";
-
public static const SITE_DATA_FAILED:String = "siteDataFailed";
-
-
public static function getInstance(): ApplicationFacade
-
{
-
if (instance == null)
-
{
-
instance = new ApplicationFacade();
-
}
-
return instance as ApplicationFacade;
-
}
-
-
override protected function initializeController():void
-
{
-
super.initializeController();
-
registerCommand( STARTUP, StartupCommand );
-
-
registerCommand( STYLE_SHEET_LOADED, StartupResourceLoadedCommand );
-
registerCommand( SITE_DATA_LOADED, StartupResourceLoadedCommand );
-
-
registerCommand( STYLE_SHEET_FAILED, StartupResourceFailedCommand );
-
registerCommand( SITE_DATA_FAILED, StartupResourceFailedCommand );
-
}
-
-
public function startup( stage:Object ):void
-
{
-
sendNotification( STARTUP, stage );
-
}
-
-
}
-
}
Lines 12-17: Three notification names are defined for each of both resources, the stylesheet (STYLE_SHEET_LOADING, STYLE_SHEET_LOADED, STYLE_SHEET_FAILED) and the site data (SITE_DATA_LOADING, SITE_DATA_LOADED, SITE_DATA_FAILED). Please note that the ..._LOADING notifications are not necessarily required by the Startup Manager utility, they are just sent as additional information, using the regular PureMVC sendNotification() method every time a load attempt is made.
Lines 33-37: The before mentioned utility commands are registered. It’s important that the commands are registered separately with the “Loaded” and “Failed” notification names for every single startup resource.
The StartupCommand
The StartupCommand is the place where we define the proxies and instantiate the StartupMonitorProxy object:
-
package com.log2e.puremvcdemo.controller
-
{
-
import com.log2e.puremvcdemo.model.SiteDataProxy;
-
import flash.display.Stage;
-
import org.puremvc.as3.interfaces.ICommand;
-
import org.puremvc.as3.interfaces.INotification;
-
import org.puremvc.as3.patterns.command.SimpleCommand;
-
import org.puremvc.as3.utilities.startupmanager.model.StartupResourceProxy;
-
import org.puremvc.as3.utilities.startupmanager.model.StartupMonitorProxy;
-
import org.puremvc.as3.utilities.startupmanager.interfaces.IStartupProxy;
-
import com.log2e.puremvcdemo.model.StyleSheetProxy;
-
import com.log2e.puremvcdemo.view.StageMediator;
-
-
public class StartupCommand extends SimpleCommand implements ICommand
-
{
-
private var _monitor:StartupMonitorProxy;
-
-
override public function execute( note:INotification ):void
-
{
-
var stage:Stage = note.getBody() as Stage;
-
facade.registerMediator( new StageMediator( stage ) );
-
-
facade.registerProxy( new StartupMonitorProxy() );
-
_monitor = facade.retrieveProxy( StartupMonitorProxy.NAME ) as StartupMonitorProxy;
-
_monitor.defaultTimeout = 30;
-
-
var styleSheetProxy:IStartupProxy = new StyleSheetProxy();
-
var siteDataProxy:IStartupProxy = new SiteDataProxy();
-
-
facade.registerProxy( styleSheetProxy );
-
facade.registerProxy( siteDataProxy );
-
-
var rStyleSheetProxy:StartupResourceProxy = makeAndRegisterStartupResource( StyleSheetProxy.SRNAME, styleSheetProxy );
-
var rSiteDataProxy:StartupResourceProxy = makeAndRegisterStartupResource( SiteDataProxy.SRNAME, siteDataProxy );
-
-
rSiteDataProxy.requires = [ rStyleSheetProxy ];
-
-
_monitor.loadResources();
-
}
-
-
private function makeAndRegisterStartupResource( proxyName:String, appResourceProxy:IStartupProxy ):StartupResourceProxy
-
{
-
var r:StartupResourceProxy = new StartupResourceProxy( proxyName, appResourceProxy );
-
facade.registerProxy( r );
-
_monitor.addResource( r );
-
return r;
-
}
-
-
}
-
}
Lines 23-24: An instance of the StartupMonitorProxy class is created and registered with the application. The proxy is assigned to the private property _monitor.
Line 25: A default timeout is set. You can set individual timeout values for each startup resource. If you do not set timeouts on the resource level the monitor’s default timeout is used. (For more information on the use of timeouts take a look at the StartupResourceProxy API documentation.)
Lines 27-28: The proxies for the stylesheet and the site data are instantiated. Please note that they are typed as IStartupProxy because the proxies are supposed to implement the IStartupProxy interface in addition to the usual PureMVC IProxy interface. We will return to this topic when we look at the implementation of the proxies.
Lines 30-31: Like any other PureMVC proxy the styleSheetProxy and the siteDataProxy are registered with the application.
Lines 33-34: Whereas instances of the StyleSheetProxy and the SiteDataProxy are supposed to be used throughout the whole application, the rStyleSheetProxy and the rSiteDataProxy objects are only needed in the context of the startup utility.
Line 36: The dependency between the two resources is specified. The site data requires that the stylesheet must be loaded first.
Line 38: Calling loadResources() on the monitor instance triggers the loading of all startup resources.
Lines 41-47: This is a helper function that I borrowed from the Startup As Ordered demo. It creates and registers a StartupResourceProxy object and adds it to the monitor’s list of resources.
The Resource Proxies
Generally speaking, a proxy in a PureMVC-based application manages a piece of the data model. The same proxy might also be responsible for retrieving its data from a remote location during startup. The PureMVC Startup Manager utility supports this pattern by providing the IStartupProxy interface which strictly requires the implementation of a load() method. Any resource proxy that is part of the initial loading process monitored by the utility must implement this interface.
On the other hand, the proxies must work in the usual PureMVC environment where they are supposed to extend the framework’s Proxy class and to implement the IProxy interface. To make the resource proxies work in both contexts, the utitliy author uses an abstract class that facilitates the cooperation between the Startup Manager and the application. You can find this class in the Startup As Ordered demo, the class name is EntityProxy. It extends Proxy and implements IProxy like a normal PureMVC proxy. But this proxy class isn’t instantiated and registered with the application itself, it only serves as a helper class for the actual resource proxies. The resource proxies extend EntityProxy and implement IStartupProxy. This way they become part of both contexts.
Here’s the code of the EntityProxy class:
-
package com.log2e.puremvcdemo.model
-
{
-
import org.puremvc.as3.interfaces.IProxy;
-
import org.puremvc.as3.patterns.proxy.Proxy;
-
import org.puremvc.as3.utilities.startupmanager.model.StartupResourceProxy;
-
import com.log2e.puremvcdemo.ApplicationFacade;
-
-
public class EntityProxy extends Proxy implements IProxy
-
{
-
public function EntityProxy( name :String )
-
{
-
super( name );
-
}
-
-
protected function sendLoadedNotification( noteName:String, noteBody:String, srName:String ):void
-
{
-
var srProxy:StartupResourceProxy = facade.retrieveProxy( srName ) as StartupResourceProxy;
-
if ( ! srProxy.isTimedOut() )
-
{
-
sendNotification( noteName, noteBody );
-
}
-
}
-
-
}
-
}
Lines 15-22: The sendLoadedNotification() method is a helper function that is used by the actual resource proxies to send “Loaded” or “Failed” notifications. These notifications are only sent if the Startup Manager hasn’t timed out the resource. In order to get the timeout information, the resource proxy’s “twin object” (srProxy) is retrieved. By the way, accessing this state information is the only reason why the StartupResourceProxy objects have been registered with the application in the StartupCommand class (see above, line 44: facade.registerProxy( r );). The utility itself does not require that they are registered with the PureMVC model.
The resource proxies finally implement the actual loading mechanisms. I hope you remember that the proxies in our sample project are responsible for loading an external CSS stylesheet and an XML file. Here’s the code of the two proxies.
StyleSheetProxy
-
package com.log2e.puremvcdemo.model
-
{
-
import flash.events.*;
-
import flash.net.URLLoader;
-
import flash.net.URLRequest;
-
import flash.text.StyleSheet;
-
import org.puremvc.as3.interfaces.IProxy;
-
import org.puremvc.as3.patterns.proxy.Proxy;
-
import org.puremvc.as3.utilities.startupmanager.interfaces.IStartupProxy;
-
import com.log2e.puremvcdemo.ApplicationFacade;
-
import com.log2e.puremvcdemo.model.EntityProxy;
-
-
public class StyleSheetProxy extends EntityProxy implements IStartupProxy
-
{
-
public static const NAME:String = "StyleSheetProxy";
-
public static const SRNAME:String = "StyleSheetSRProxy";
-
-
public function StyleSheetProxy()
-
{
-
super( NAME );
-
}
-
-
public function load() :void
-
{
-
sendNotification( ApplicationFacade.STYLE_SHEET_LOADING );
-
-
var request:URLRequest = new URLRequest("styles.css");
-
var loader:URLLoader = new URLLoader();
-
-
loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
-
loader.addEventListener(Event.COMPLETE, loaderCompleteHandler);
-
-
loader.load(request);
-
}
-
-
private function loaderCompleteHandler(event:Event):void
-
{
-
data = new StyleSheet();
-
data.parseCSS( URLLoader(event.target).data );
-
sendLoadedNotification( ApplicationFacade.STYLE_SHEET_LOADED, NAME, SRNAME );
-
}
-
-
private function errorHandler(e:IOErrorEvent):void
-
{
-
sendLoadedNotification( ApplicationFacade.STYLE_SHEET_FAILED, NAME, SRNAME );
-
}
-
-
public function get css():StyleSheet
-
{
-
return data as StyleSheet;
-
}
-
-
}
-
}
Line 16: The SRNAME constant holds the name of the StartupResourceProxy twin.
Line 40, line 45: The helper method in the parent EntityProxy class is called to send “Loaded”/”Failed” notifications.
Lines 48-51: The getter method returns the internal data property as a typed StyleSheet object.
The SiteDataProxy class works in a similar fashion:
-
package com.log2e.puremvcdemo.model
-
{
-
import flash.events.*;
-
import flash.net.URLLoader;
-
import flash.net.URLRequest;
-
import org.puremvc.as3.interfaces.IProxy;
-
import org.puremvc.as3.patterns.proxy.Proxy;
-
import org.puremvc.as3.utilities.startupmanager.interfaces.IStartupProxy;
-
import com.log2e.puremvcdemo.ApplicationFacade;
-
import com.log2e.puremvcdemo.model.EntityProxy;
-
iimport com.log2e.puremvcdemo.model.vo.SectionVO;
-
-
public class SiteDataProxy extends EntityProxy implements IStartupProxy
-
{
-
public static const NAME:String = "SiteDataProxy";
-
public static const SRNAME:String = "SiteDataSRProxy";
-
-
public function SiteDataProxy()
-
{
-
super( NAME );
-
}
-
-
public function load() :void
-
{
-
sendNotification( ApplicationFacade.SITE_DATA_LOADING );
-
-
var request:URLRequest = new URLRequest("data.xml");
-
var loader:URLLoader = new URLLoader();
-
-
loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
-
loader.addEventListener(Event.COMPLETE, loaderCompleteHandler);
-
-
loader.load(request);
-
}
-
-
private function loaderCompleteHandler(event:Event):void
-
{
-
var xml:XML = new XML( event.target.data );
-
xml.ignoreWhitespace = true;
-
-
var title:String = xml.title.children().toXMLString();
-
var sections:Array = new Array();
-
var sectionsXMLList:XMLList = xml.sections.section;
-
-
for ( var i:uint=0; i<sectionsXMLList.length(); i++ )
-
{
-
var section:XML = sectionsXMLList[i];
-
var id:uint = section.@id;
-
var sectionVO:SectionVO = new SectionVO( id, section.@label, section.content );
-
sections.push( sectionVO );
-
}
-
-
data = new Object();
-
data.title = title;
-
data.sections = sections;
-
-
sendLoadedNotification( ApplicationFacade.SITE_DATA_LOADED, NAME, SRNAME );
-
}
-
-
private function errorHandler(e:IOErrorEvent):void
-
{
-
sendLoadedNotification( ApplicationFacade.SITE_DATA_FAILED, NAME, SRNAME );
-
}
-
-
public function get title():String
-
{
-
return data.title as String;
-
}
-
-
public function get sections():Array
-
{
-
return data.sections as Array;
-
}
-
-
}
-
}
Lines 38-51: Please refer to the data.xml file described in part 1 of this tutorial.
Line 49: The SiteDataProxy class makes use of a simple value object class (SectionVO):
-
package com.log2e.puremvcdemo.model.vo
-
{
-
-
public class SectionVO
-
{
-
private var _id:uint;
-
private var _label:String;
-
private var _content:String;
-
-
public function SectionVO( id:uint, label:String, content:String )
-
{
-
_id = id;
-
_label = label;
-
_content = content;
-
}
-
-
public function get id():uint
-
{
-
return _id;
-
}
-
-
public function get label():String
-
{
-
return _label;
-
}
-
-
public function get content():String
-
{
-
return _content;
-
}
-
-
}
-
}
In the third and last part of this tutorial we will be creating a rudimentary view to test our efforts.
You can download the sample files from here (the ZIP archive includes a FlashDevelop project file). If you want to comment on this tutorial please post in the comments section at the end of the introductory post.
Tags: ActionScript, Flash, FlashDevelop, Flex, PureMVC
July 4th, 2008 at 12:18 am
[...] den StartupManager empfehle ich die 3-teilige Anleitung aus Stefan Schmalhaus’ log2e Blog: Teil 1, Teil 2 und Teil 3. Obwohl er laut Blog aus Krefeld kommt, sind diese Anleitungen allerdings in [...]