PureMVC Architects Lounge

Announcements and General Discussion => General Discussion => Topic started by: danieleUg on July 07, 2007, 05:18:01



Title: first project with pureMVC
Post by: danieleUg on July 07, 2007, 05:18:01
Hi Cliff,
I just starting a new project and I have chosen PureMVC instead Cairngorm. I have read all documentations and play a but with the demo (very usefull, thanks).
Now in this project I have some points and I would like to have a suggestion what's the best way to achieve:
- the APP_STARTUP must to read a XML config file
- I must to wait that the config is loaded, parse it and read some resources (other XML and background images)
- when all is loaded I can show the view.

What is the best way to make it?

Best,
   Daniele


Title: Re: first project with pureMVC
Post by: puremvc on July 07, 2007, 09:15:57
Although you may not be intending to build an AIR app here, it would be worth your time to:

  • Install the AIR Runtime and the CodePeek Demo from here: http://codepeek.futurescale.com/download.html (http://codepeek.futurescale.com/download.html)
  • Run Codepeek
  • Study the code here: http://codepeek.futurescale.com/source.html (http://codepeek.futurescale.com/source.html)

CodePeek does exactly what you are describing. The application:

  • Is not visible to start with (nor is its NativeWindow, so you can't even see it at all yet.) In Flex, you'd have something like a ViewStack with a splash screen as your first child.
  • Instantiates the ApplicationFacade
  • Application creationComplete handler sends APP_STARTUP Notification
  • Controller executes ApplicationStartupCommand
  • ApplicationStartupCommand calls ModelPrepCommand
  • ModelPrepCommand registers Proxies
  • Two of those Proxies read XML files (from the disk with AIR, you'd call a service with Flex)
  • One of those XML files is the Preferences XML db, which has the WindowMetrics data for positioning the window on the desktop. The CodePeekPrefsProxy creates and registers a WindowMetricsProxy to handle that entity in the Prefs file.
  • ApplicationStartupCommand calls ViewPrepCommand
  • ViewPrepCommand gets the WindowMetricsProxy, and sends an appropriate Notification
  • The StageMediator listens for the various notifications for affecting the desktop window position and display state
  • Once the window position has been restored, the StageMediator will detect a DISPLAY_STATE_CHANGE, MOVE and/or RESIZE events and will issue the VIEW_SHOW_WINDOW notification.
  • The StageMediator listens for this Notification (yes, its perfectly fine for a Mediator to Notify itself), and will make the Window visible.
  • The ApplicationMediator is also listening for VIEW_SHOW_WINDOW, and sets the Application's showControls property to true
  • The Application has its visible property bound to showControls, so it shows itself (within the Window which is now visible as well). There is an associated effect that causes the whole app to slide in at this point.

You wouldn't need the StageMediator or WindowMetrics stuff in your Flex app but much of this is the same. Essentially we don't show the goods till everything is on the shelves and we're ready open the doors to the public. You'll want to prep your Model followed by the View. so the startup sequence is the same.

However, the XML database Proxy creation and registration is synchronous in CodePeek. That is to say, when we register those Proxies, they read the stuff off disk in a blocking fashion and our code follows along. When the Proxy is created, the data is there. If you examine the CodePeekSearchProxy, you'll see how you might work your async service stuff. The CodeSearchProxy doesn't get called at startup, but it shows how to do an asyncrhonous RemoteProxy.

Some of your Proxies will send off requests to remote services when they are created. You'll create and register them just the same. However, when their services return, they will send Notifications that either a Command and or various Mediators will respond to, and eventually 'turn on' the UI by doing something like sending a Notification that the ApplicationMediator responds to by setting a value on the Application that causes the ViewStack selectedIndex to change, for instance.

You might have a complex startup situation where the creation of Proxies send off multiple requests for data and you want to turn on the UI only after ALL the services have returned and been properly responded to.

In this case, I suggest having a StartupMonitorProxy created and registered that holds a simple count of the number of startup services which must return before turning on the View.

Have each of the services called at startup send a STARTUP_RESULT notification when the data comes in, which is listened for by a StartupMonitorCommand.

The StartupMonitorCommand will, each time it is executed, get the StartupMonitorProxy and call a decrement method.

After calling the decrement method, the StartupMonitorCommand will ask the StartupMonitorProxy for the count and if the count has reached zero then we know all the services have returned, and so it will send a VIEW_SHOW_CONTROLS Notification, which will be responded to by one or more Mediators who 'turn on' the View by setting properties on their stewarded View Components.

Hope this helps!







Title: Re: first project with pureMVC
Post by: danieleUg on July 09, 2007, 07:59:37
Hi Cliff,
thanks a lot for you help!


Title: Re: first project with pureMVC
Post by: danieleUg on July 14, 2007, 04:46:26
Hi Cliff,
I have other questions for you:

- my Flex applycation read a config file using a Proxy. When a part of application (Mediator or other Proxy) need to get a config value can retrieve the proxy and call it?
ie:
configProxy = configProxy ( facade.retrieveProxy( configProxy .NAME ) );
configProxy.getValue('myValueKey');

- my application have a chat build with Flash Media Server, I think that also in this case I must to have a proxy class that make the connection with FMS and talk with it, right? But when a Mediator need to send a message to FMS (ie send the chat text) is better that retrieve the Proxy and call a method or send a notification for the proxy?

Thanks
   Daniele


Title: Re: first project with pureMVC
Post by: puremvc on July 14, 2007, 08:42:42
You have it just right. Retrieve the Proxy from anywhere, and act upon the methods and properties you choose to expose for manipulating and referring to its Data Object.

A Proxy should talk to FDS and expose a getter cast to ArrayCollection that your Mediator can retrieve a reference and set as a property on its View Component, which is in turn has, for instance, an editable DataGrid's dataProvider bound to it.

-=Cliff>


Title: Re: first project with pureMVC
Post by: danieleUg on July 17, 2007, 07:46:52
Hi Cliff,
I have made a little demo called Application Skeleton and I have implemented the startup sequence that read some resources:
- a configuration file
- a XML with localized text
- and other.

In the main view there is a example how to read localized text from the proxy.
I don't know if I have made all well, but I hope that it can help other people.

Best
  Daniele


Title: Re: first project with pureMVC
Post by: puremvc on July 17, 2007, 09:24:33
Daniele,

Sounds great, where can we see it?

-=Cliff>


Title: Re: first project with pureMVC
Post by: danieleUg on July 17, 2007, 09:50:35
Cliff,
there is the attach with source in my last post, but you can see it online:

Demo:
http://dev.ugoletti.com/puremvc/ApplicationSkeleton.swf

Source:
http://dev.ugoletti.com/puremvc/ApplicationSkeleton.zip


Title: Re: first project with pureMVC
Post by: puremvc on July 18, 2007, 10:37:30
Daniele,

You've really done a great job here! It looks like something people could build off of pretty easily.

Here are my suggestions:

  • Zip the project folder rather than its contents, so when someone unzips it, they get one folder, and don't have to create one first. This cost me a Version point on PureMVC  :P


  • Move the business package under Model. Only a Proxy talks to it, so it shouldn't clutter the namespace at the MVC level. (the CafeTownsend demo has it at that level to make friendly with the Cairngorm folk, but it's not really a recommended practice I'd want to perpetuate with PureMVC.

    The Model tier is roundly in charge of communicating with remote services if necessary. It could be done inside the Proxy, as with CodePeek, or with a Business Delegate, as you've done here, but either way it will happen within the Model tier.

    Further, the Delegate pattern is only really useful to us if multiple Proxies will communicate with the same service the Delegate talks to, although it's not improper to use it if only one Proxy talks to it. It's a good division of responsibility, and I'm not suggesting its removal, only noting here for posterity that a good way to begin an app is to have the service logic inside the Proxy, and then later refactor it into a Delegate at the first call for reuse.

    One goal of the framework is to promote a 'simple as possible but no simpler' approach. Fewer actors will help newbies to design patterns and n-tier architecture grasp what's going on faster.


  • And for the same reason, move the flex/helpers package to  model/helpers, since it is the Proxies that use it to parse their data files.

Again, Daniele, you did a super job here. The implementation of the StartupMonitorProxy is especially well done illustrating the use of data from the first loaded file affecting the subsequent calls.

If you wouldn't mind writing a little something about it, I'd love to feature it as a demo. It would be most helpful for people to get a feel for how to turn it into their own thing.

-=Cliff>


Title: Re: first project with pureMVC
Post by: danieleUg on July 18, 2007, 02:24:36
  • Zip the project folder rather than its contents, so when someone unzips it, they get one folder, and don't have to create one first. This cost me a Version point on PureMVC  :P



ok

  • Move the business package under Model. Only a Proxy talks to it, so it shouldn't clutter the namespace at the MVC level. (the CafeTownsend demo has it at that level to make friendly with the Cairngorm folk, but it's not really a recommended practice I'd want to perpetuate with PureMVC.

    The Model tier is roundly in charge of communicating with remote services if necessary. It could be done inside the Proxy, as with CodePeek, or with a Business Delegate, as you've done here, but either way it will happen within the Model tier.
this means that we have model/business folder with delegate files.

Further, the Delegate pattern is only really useful to us if multiple Proxies will communicate with the same service the Delegate talks to, although it's not improper to use it if only one Proxy talks to it. It's a good division of responsibility, and I'm not suggesting its removal, only noting here for posterity that a good way to begin an app is to have the service logic inside the Proxy, and then later refactor it into a Delegate at the first call for reuse.

you are right, but in this example we have 2 proxy that use the same delegate

  • And for the same reason, move the flex/helpers package to  model/helpers, since it is the Proxies that use it to parse their data files.

ok

If you wouldn't mind writing a little something about it, I'd love to feature it as a demo. It would be most helpful for people to get a feel for how to turn it into their own thing.

sure, I have posted the example because I think that can be usefull for others. I will try to write something but my english isn't so good :)
Where I can send the final file?

Daniele
[/list]


Title: Re: first project with pureMVC
Post by: puremvc on July 18, 2007, 02:39:12
Daniele,

I will be happy to help with getting some documentation together and present it here as a demo people can actually get started from. It might be helpful to create a second demo based upon this one, to show the direction someone might take to use it.

You can email me at cliff@puremvc.org

Also, I see you're using Flash Develop. I haven't tried it yet, but it looks good. Did you use Michael Ramirez's PureMVC Project plugin?

-=Cliff>


Title: Re: first project with pureMVC
Post by: danieleUg on July 18, 2007, 02:50:03
Daniele,

I will be happy to help with getting some documentation together and present it here as a demo people can actually get started from. It might be helpful to create a second demo based upon this one, to show the direction someone might take to use it.

You can email me at cliff@puremvc.org

thanks I will contact in private.

Also, I see you're using Flash Develop. I haven't tried it yet, but it looks good. Did you use Michael Ramirez's PureMVC Project plugin?

unfortunaly no, I have tried but I get a lot of errors, I don't have time to write to him but I will do ASAP.


Daniele


Title: Re: first project with pureMVC
Post by: danieleUg on July 22, 2007, 07:00:18
Hi Cliff,
I have update the demo:

http://dev.ugoletti.com/puremvc/ApplicationSkeleton.zip

Changelog:
- updated to pureMVC 1.5
- now the ApplicationFacade.getConfigProxy() and ApplicationFacade.getResourceProxy() are static methods
- removed unused code

Daniele


Title: Re: first project with pureMVC
Post by: achegedus on September 17, 2007, 01:35:30
Hey Cliff and Daniele,
I'm having trouble with this demo.  I keep getting a sandbox security error when i'm trying to load an xml file.  The xml isn't on a different domain, so I'm not sure what's happening.

Any suggestions?

Thanks,
Adam


Title: Re: first project with pureMVC
Post by: danieleUg on October 12, 2007, 03:34:45
Hi Adam,
I hope that you have already solved you issue, sorry but I'm very busy.
I think that you have to manage your player security settings:

http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager.html

Best
  Daniele


Title: Re: first project with pureMVC
Post by: meekgeek on October 30, 2007, 02:51:56
I have a question about the demo...

Where is com.ugoletti.controller.StartupMonitorCommand implemented?  I can't find it.


Title: Re: first project with pureMVC
Post by: puremvc on October 31, 2007, 10:56:29
In the ApplicationSkeleton.zip, StartupMonitorCommand is in ApplicationSkeleton\com\ugoletti\controller\

-=Cliff>


Title: Re: first project with pureMVC
Post by: meekgeek on October 31, 2007, 11:35:24
Yeah, I see that, but in the code, ApplicationFacade calls ApplicationStartupCommand which add two sub commands, ModelPrepCommand and ViewPrepCommand.  I can't find where StartupMonitorCommand is used.  Am I downloading a different zip?

Sorry if I'm missing something right in front of my face.  I'm new to this framework.  Heard this was better than cairngorm ;)


Title: Re: first project with pureMVC
Post by: puremvc on October 31, 2007, 01:01:37
Actually, that's a good question. Looking through the code, it looks like it might be an unused bit that was refactored out.

I'm hoping Daniele can chime in here on this one.

-=Cliff>


Title: Re: first project with pureMVC
Post by: meekgeek on October 31, 2007, 02:32:59
I just created this...

I thought this might be a little more reusable then counting.

If someone can advise if it's complying to best practice  :)  I'd like to contribute something to this post.  8)

:
package com.meekgeek.model
{
import flash.utils.Dictionary;

import org.puremvc.interfaces.IProxy;
import org.puremvc.patterns.proxy.Proxy;

import com.meekgeek.ApplicationFacade;

public class StartupMonitorProxy extends Proxy implements IProxy
{
public static const NAME:String = "StartupMonitorProxy";

private var resourceList:Dictionary;

public function StartupMonitorProxy(proxyName:String=null, data:Object=null)
{
super(proxyName, data);
resourceList = new Dictionary();
}

override public function getProxyName():String
{
return StartupMonitorProxy.NAME;
}

public function addResource(name:String):void
{
resourceList[name] = false;
}

public function loadResources():void
{
trace('loading resources');
for(var key:String in resourceList)
{
trace('load resource: '+key);
var proxy:* = facade.retrieveProxy( key ) as Proxy;
proxy.load();
}
}

public function resourceComplete( name:String ):void
{
resourceList[name] = true;
checkResources();
}

private function checkResources():void
{
var resourcesLoaded:Boolean = true;
for(var key:String in resourceList)
{
if(!resourceList[key])
{
resourcesLoaded = false;
break;
}
}
if(resourcesLoaded)this.sendNotification( ApplicationFacade.LOADING_COMPLETE);
}
}
}

It's the first proxy to be registered.  All other proxies that need to be loaded before moving on, will call addResource() which adds them to a list of resources.  Once all proxies have been added, you execute a command to call loadResources() which calls load() on all proxies in the list.  Once the individual proxies complete the load process, they call resourceComplete() to advise StartupMonitorProxy that something has finished loading.  It then checks to see if all proxies are ready.  If all proxies check out, it notifies the framework to move on :)

If this is looking like something that other's can use I can upload the files I'm using.


Title: Re: first project with pureMVC
Post by: puremvc on October 31, 2007, 06:20:45
This is a really elegant solution. I like it much better than counting as well.

In Cairngorm on a big project a couple of years ago, I did a take on this resource loading problem based on a counter being preset to the number of resources to load and each resource loaded decrementing the counter, etc. It's a little better than the counting approach, possibly, but your class above is really the cleanest take on the problem I've seen yet.

Great work! Please do post what you've got working here. Soon (really, I promise) there is going to be a much better way for the community to contribute.

-=Cliff>


Title: Re: first project with pureMVC
Post by: danieleUg on November 05, 2007, 02:34:04
Yeah, I see that, but in the code, ApplicationFacade calls ApplicationStartupCommand which add two sub commands, ModelPrepCommand and ViewPrepCommand.  I can't find where StartupMonitorCommand is used.  Am I downloading a different zip?

Sorry if I'm missing something right in front of my face.  I'm new to this framework.  Heard this was better than cairngorm ;)

Hi meekgeek,
the file StartupMonitorCommand  isn't used, you can delete it, sorry but I forgot to delete before post the zip :)


Daniele


Title: Re: first project with pureMVC
Post by: danieleUg on November 05, 2007, 04:26:37
Hi meekgeek,
your suggestion is very cool and I have modify my ApplicationSkeloton code, the new version can be downloaded here:

http://dev.ugoletti.com/puremvc/ApplicationSkeleton_v1.3.zip (http://dev.ugoletti.com/puremvc/ApplicationSkeleton_v1.3.zip)

I have based the new version to your code but with few differences:
- I have add a parameter to addResource function, because some resources can be loaded before others, ie in my example the config.xml must be read before the other resources.
- I have used a Array insteed a Dictionary becase during the iteration the keys are in different order how are created


I just created this...

I thought this might be a little more reusable then counting.

If someone can advise if it's complying to best practice  :)  I'd like to contribute something to this post.  8)

......

It's the first proxy to be registered.  All other proxies that need to be loaded before moving on, will call addResource() which adds them to a list of resources.  Once all proxies have been added, you execute a command to call loadResources() which calls load() on all proxies in the list.  Once the individual proxies complete the load process, they call resourceComplete() to advise StartupMonitorProxy that something has finished loading.  It then checks to see if all proxies are ready.  If all proxies check out, it notifies the framework to move on :)

If this is looking like something that other's can use I can upload the files I'm using.


Title: Re: first project with pureMVC
Post by: meekgeek on November 08, 2007, 11:03:25
I'm glad I could help in some way. :)


Title: Re: first project with pureMVC
Post by: deltajam on November 22, 2007, 09:38:00
Why is the swf footprint so big?  When I compile the project ... it seems to be a massive 346kb.  When I extract the files it seems to be 222kb (which is still pretty big don't you think) and when I compile it, it's 346kb.  What gives?  Is there a setting in Flashdevelop that I'm not aware of?


Title: Re: first project with pureMVC
Post by: danieleUg on November 22, 2007, 09:59:01
Hi deltajam,
if you are using FlexBuilder 3 try to read this: http://www.buntel.com/blog/index.cfm/2007/10/15/The-Export-Release-Wizard (http://www.buntel.com/blog/index.cfm/2007/10/15/The-Export-Release-Wizard)


Daniele


Title: Re: first project with pureMVC
Post by: puremvc on November 22, 2007, 10:27:47
Here's a video that explains everything pretty well:
http://labs.adobe.com/technologies/flex/videos/exportreleasewizard/

-=Cliff>


Title: Re: first project with pureMVC
Post by: Joel Hooks on December 20, 2007, 05:10:01
I'm refactoring my application, and used this instead of chaining remote service calls in a single proxy. it really ( really ) cleaned up my code and made it easier to understand. Prior to this I had one single 'DataProxy' to facilitate this, and it led to one monster class that was starting to get confusing.

Anyways, thanks!

I just created this...

I thought this might be a little more reusable then counting.

If someone can advise if it's complying to best practice  :)  I'd like to contribute something to this post.  8)

It's the first proxy to be registered.  All other proxies that need to be loaded before moving on, will call addResource() which adds them to a list of resources.  Once all proxies have been added, you execute a command to call loadResources() which calls load() on all proxies in the list.  Once the individual proxies complete the load process, they call resourceComplete() to advise StartupMonitorProxy that something has finished loading.  It then checks to see if all proxies are ready.  If all proxies check out, it notifies the framework to move on :)

If this is looking like something that other's can use I can upload the files I'm using.


Title: Re: first project with pureMVC
Post by: philipSe on January 28, 2008, 09:23:47
Thanks to Cliff for Puremvc and for these forums etc., and to danieleUg and to meekgeek for the StartupMonitorProxy solution, as implemented in the ApplicationSkeleton code.

My application requires a more powerful method of sequencing the loading of data resources at startup.  Specifically, I want to be able to specify that a resource cannot be loaded until specific other resources have been loaded. The dependencies are such that use of the blockChain boolean on the resource would result in sub-optimal loading, in that loading of some resources would be unnecessarily delayed.

I am presenting the basics of my code here, in case it is of interest to others.

My resource is called StartupResource, as follows.
:
package com...model
{
/*
*  From original code of Daniele Ugoletti and Meekgeek
*  on the puremvc forums, modified to use 'requires' instead
*  of blocking boolean.  Also have a multi-valued status instead
*  of a 'loaded' boolean.

* @author Philip Sexton
* @since  11.01.2008
*/
public class StartupResource
{
        private static const EMPTY :int = 1;
        private static const LOADING :int = 2;
        private static const LOADED :int = 3;

public var proxyName:String;

private var status :int;

// StartupResources, pre-requisites for this resource, if any.
// These pre-requisites must be loaded before this resource can be loaded.
private var _requires :Array;

public function StartupResource( proxyName:String )
{
this.proxyName = proxyName;
this.status = EMPTY;
this.requires = new Array();
}
public function setStatusToLoading() :void {
    status = LOADING;
}
public function setStatusToLoaded() :void {
    status = LOADED;
}
public function isLoaded() :Boolean {
    return status == LOADED;
}
public function set requires( resources :Array ) :void {
    _requires = resources;
}
public function get requires() :Array {
    return _requires;
}
public function isOkToLoad() :Boolean {
    if ( status != EMPTY ) return false;
    for( var i:int =0; i < requires.length; i++) {
        if ( ! (requires[i] as StartupResource).isLoaded() )
            return false;
    }
    return true;
}
}

}

StartupMonitorProxy is as follows.  Note that method addResource() is not called from the individual resource proxies; it is called from the startup command.  In fact, the individual resource proxies contain no code specific to the startup monitor.

:
package com...model
{
import org.puremvc.interfaces.*;
    import org.puremvc.patterns.proxy.Proxy;
import com...model.StartupResource;

/*
*  A proxy for the startup loading process.
*  From original code of Daniele Ugoletti and Meekgeek
*  on the puremvc forums, modified to use a StartupResource
*  designed to cater for more complex constraints.

* @author Philip Sexton
* @since  11.01.2008
*/
    public class StartupMonitorProxy extends Proxy implements IProxy
    {
public static const NAME:String = "StartupMonitorProxy";
// array listing all the resources to be loaded
private var resourceList:Array;
//---- total resource to read
//-----private var totalResources:int = 0;
// number of loaded resources
private var loadedResources:int = 0;

public function StartupMonitorProxy ( data:Object = null )
        {
            super ( NAME, data );
this.resourceList = new Array();
        }


/**
         * Add a resource to be loaded
         */
public function addResource( r :StartupResource ):void
{
this.resourceList.push( r );
}

/**
         * Start/Continue to load all resources
         */
public function loadResources():void
{
for( var i:int = 0; i < this.resourceList.length; i++)
{
var r:StartupResource = this.resourceList[i] as StartupResource;
if ( r.isOkToLoad() )
{
var proxy:* = facade.retrieveProxy( r.proxyName ) as Proxy;
r.setStatusToLoading();
proxy.load();
}
}
}

/**
         * The resource is loaded, update the state and check if the loading process is completed
*
         * @param name proxy name
         */
public function resourceLoaded( proxyName :String ):void
{
for( var i:int = 0; i < this.resourceList.length; i++)
{
var r:StartupResource = this.resourceList[i] as StartupResource;
if ( r.proxyName == proxyName )
{
r.setStatusToLoaded();
this.loadedResources++;

// send the notification for update the progress bar
//this.sendNotification( ApplicationFacade.LOADING_STEP, this.resourceList.length / this.loadedReources * 100 );

// if not all loaded, continue load.
if ( !allResourcesLoaded() )
{
this.loadResources();
}
break;
}
}

}

/**
         * Check if the loading process is completed
*
         * @return boolean process is completed
         */
private function allResourcesLoaded():Boolean
{
for( var i:int = 0; i < this.resourceList.length; i++)
{
var r:StartupResource = this.resourceList[i] as StartupResource;
if ( !r.isLoaded() )
{
return false;
}
}
//this.sendNotification( ApplicationFacade.LOADING_COMPLETE );
return true;
}
}
}

The StartupCommand has code as follows, here presented in pseudo-code.
:
public class StartupCommand extends SimpleCommand implements ICommand {

private var monitor :StartupMonitorProxy;

override public function execute( note:INotification ) : void {

    facade.registerProxy( new StartupMonitorProxy() );
    this.monitor = facade.retrieveProxy( StartupMonitorProxy.NAME ) as StartupMonitorProxy;
            ... register other proxies ...

            var rA :StartupResource = makeAndRegisterStartupResource( ProxyA.NAME );
            var rB :StartupResource = makeAndRegisterStartupResource( ProxyB.NAME );
            var rC :StartupResource = makeAndRegisterStartupResource( ProxyC.NAME );
            var rD :StartupResource = makeAndRegisterStartupResource( ProxyD.NAME );
            var rE :StartupResource = makeAndRegisterStartupResource( ProxyE.NAME );
            var rF :StartupResource = makeAndRegisterStartupResource( ProxyF.NAME );
            var rG :StartupResource = makeAndRegisterStartupResource( ProxyG.NAME );
            var rH :StartupResource = makeAndRegisterStartupResource( ProxyH.NAME );

            rC.requires = [ rA, rB ];
            rD.requires = [ rC ];
            rE.requires = [ rD ];
            rH.requires = [ rE, rF, rG ];
            monitor.loadResources();

... register mediator(s) ...
}
private function makeAndRegisterStartupResource( proxyName :String ) :StartupResource {
    var r :StartupResource = new StartupResource( proxyName );
    monitor.addResource( r );
    return r;
}
}

With the completion of each resource load, in the proxy/responder objects, a 'loaded' notification specific to the resource is sent.  All such notifications are handled by a StartupResourceLoadedCommand.  The application facade has registered this command against each of the notifications.  The command code is as follows.

:
public class StartupResourceLoadedCommand extends SimpleCommand {

/**
* Inform the startup monitor that a resource is now loaded.
* The notification body identifies the particular resource.
*/
override public function execute( note:INotification ) : void {
    ( facade.retrieveProxy( StartupMonitorProxy.NAME ) as StartupMonitorProxy).
        resourceLoaded( note.getBody() as String );
}
}


I hope the above makes sense.  Some people may think it unnecessary.  Any comments are welcome.

Thank you
    Philip


Title: Re: first project with pureMVC
Post by: puremvc on January 28, 2008, 12:58:16
Phillip,

This is great work. Could you send me a copy of the code as a demo so that I can look it over more closely? My net connection is dead and I read this post on my phone. I like the way you set the dependencies on resources needing to be loaded.

I'd like to see if we can extract some of this into an off the rack utility with a demo that uses the utility. Are you up for that? Perhaps you could do the utility and work with daniele to modify his demo to use your utility. Or do another demo that uses the utility but with a more complex  requirement showing off the dependency handling.

Of course to really make it complete we'd want to be able to implement timeout and retry policies or each resource...

:)
-=Cliff>


Title: Re: first project with pureMVC
Post by: danieleUg on January 28, 2008, 03:10:29
Hi Philip,
thank for the suggestion, we look on it in depth.

For now I can say that I already have a similar implementation that is in the demo repository that Cliff will release soon.

In StartupMonitorProxy there is the addReesource method that have blockChain parameter

:
public function addResource( proxyName:String, blockChain:Boolean = false ):void
{
this.resourceList.push( new ResourceVO( proxyName, blockChain ) );
}

Your implementation is interesting because you can specify the the resources dependancy.





Title: Re: first project with pureMVC
Post by: puremvc on January 29, 2008, 07:30:02
Hi guys,

Phillip just sent ma a copy of his code with a description of which classes could be extracted into a utility.

I wonder if we could turn this into a util nd refactor your demo to use it? Perhaps we could add some requirements that show how to use the dependency stuff too.

Demos will be far more useful if the special functionalities can be reused easily.

-=Cliff> 


Title: Re: first project with pureMVC
Post by: philipSe on January 30, 2008, 03:43:18
Cliff /Daniele /others

Following on Cliff's comments, I have been thinking about this utility/demo suggestion and whether I should offer to contribute.  So, if you like, I would be willing to go ahead and...
1. package the relevant classes into a separate utility, with class level comments to explain usage
2. create a simple demo app to use this utility and show off the dependency feature.

Utility...
I could package this using my own company naming e.g. com.xyz.utils...., but I presume we want a generic naming so that more utilities can be added, code can be modified etc.
What about org.puremvc.forums as the base package?  Then we could have <base>.utils and <base>.demos as the next levels.  I'm new to this, so maybe I'm missing the point, or maybe I've missed some posts regarding this.

Anyway, for this case, say we have <base>.utils.startupWithDependencies.  The relevant classes (3 I believe) could then sit directly in that package, or do we prefer sub-folders for controller and model?

Is startupMonitor a better name for the utility? - I am avoiding this because I don't want to present this as the only startup solution.

Demo...
This would be packaged as <base>.demos.startupWithDependencies, with sub-folders for model/view/controller.  A demo app does not have to have the same name as a utility, of course, though I propose it in this case.

Finally I would zip all this to Cliff, with a .swf for the app, and presumably a .swc for the utility.  This code could then be enhanced (or ignored!), by others.

I am very aware that all I've done is adapt code originally created by daniele and meekgeek, and use daniele's ApplicationSkeleton demo as a reference.  So, if anyone else would like to take the lead on one or both of these items, that is fine by me.

Regards
    Philip


Title: Re: first project with pureMVC
Post by: puremvc on January 30, 2008, 06:32:05
Phillip,

For the packaging we're using in the rpository, as well as the general details of contributing to the project, have a look at the Contributor Central board.

I would call the project StartupManager - it does more than monitor it actively manages the startup process.

Once extracted from the demo is it dependent on Flex or is it possible to use with Flash? This will determine the package space:

org.puremvc.as3.utilities.startupmanager.*

Or

org.puremvc.as3.utilities.flex.startupmanager.*

-=Cliff>


Title: Re: first project with pureMVC
Post by: philipSe on January 30, 2008, 07:34:44
Ok, Cliff, I'll take a look at Contributor Central.


Title: Re: first project with pureMVC
Post by: meekgeek on January 31, 2008, 12:27:04
This is great!  Just what I needed.  I will be implementing timeouts for my project.  This is beautiful.  Thanks philipSe.


Title: Re: first project with pureMVC
Post by: danieleUg on February 04, 2008, 10:32:53
Hi Cliff,
if you want I can work with Phillip and integrate him code in AppSkeleton, have sense?

Daniele


Title: Re: first project with pureMVC
Post by: meekgeek on February 04, 2008, 11:26:42
So over the weekend I started to add the Time out functionality.  I have a site that did not load completely because a streaming server somewhere was turned off.  Needless to say, people were upset. :)

My delima is that until now, there was no flash spicific code in the framework.  I thought that best place to put the timer was in Phillip's StartupResource class, but this brings up other things like, "what's going to be listening for timer event?"  Does this really matter now that the framework is being ported to all these other languages and this version is more specifically the as3 version?

Probablly being the biggest newbe of the bunch, I'd like to know what's best practice, and if any body has any suggestions on how to implement the timeout functionallity.  The more I think about it, the more important it is to have this on a site that loads in data from other servers.


Title: Re: first project with pureMVC
Post by: puremvc on February 04, 2008, 12:53:50
meekgeek,

There should be a configurable retry policy for each resource that determines how many times (if at all) it is allowed to retry before giving up and sending a fault notification. It should also govern the time between retries and the message to send when it fails.

The resource should send progress notifications as it is loading. It should also send notifications when it retries so that a mediator/view component that displays progress can indicate retries elapsed per resource. There should also be a message that is sent as a notification. Listen to these with the Proxy and turn them into Notifications.

It should contain its own system for displaying progress. True the developer could do this, but we could save them a lot of time by building it in and letting them control the look and feel of it.

A Mediator could pop up a TitleWindow that it displays progress in. If this resource loading process is supposed to complete before we register Mediators, then you can still register a Mediator prior to starting this process that listens for progress notifications and handles displaying them.

In fact you probably want a PrepStartupManagerCommand that is used to create and register the StartupProgressMediator, followed by the StartupMonitorProxy, and doing any other kick off operations.

For bonus points, you could pass true or false as an argument to the PrepStartupManagerCommand (in the notification body) that tells it whether or not to create and register the StartupProgressMediator as well as the StartupMonitorProxy. Send true and it starts the visual progress monitoring, fals and it doesn't. The notifications are still sent, so the user could do their own progress display or none at all.

The ApplicationFacade of the implementing app would do:

:
registerCommand( PrepStartupManagerCommand.NAME, PrepStartupManagerCommand)
The StartupCommand of the application that is using this utility would simply
:
sendNotification(PrepStartupManagerCommand.NAME)

-=Cliff>


Title: Re: first project with pureMVC
Post by: judholliday on February 05, 2008, 01:04:59
I've been following this post with interest as I (and a couple co-workers) are working on setting up a Flash application using PureMVC.

The work that has been done with the StartupMonitorProxy so far has been great. However, I have a question about how you might go about passing data in to the proxies that are being managed by the StartupMonitorProxy.

In my example case the first proxy I want to load (ConfigProxy) is going to load in a configuration xml file. I would like to be able to specify the location of this xml file via FlashVars. Previously I was accomplishing this by passing in the app.loadInfo object when I called the 'load' method on ConfigProxy. But now that StartupMonitorProxy is in place it is calling 'load' automatically and obviously is not setup to pass information that way.

Is there a way to pass in data to the Proxy on load? Or is there another preferred way you could do something like this? It's entirely possible that I am missing an obvious answer because I am fairly new to PureMVC.

Thanks,
Jud


Title: Re: first project with pureMVC
Post by: philipSe on February 05, 2008, 03:01:11
Jud
Is it a solution for you to set the file location info as a property of ConfigProxy, before starting the load of resources?  Then the load method of ConfigProxy can use that info.  Am I missing something?
    Philip


Title: Re: first project with pureMVC
Post by: judholliday on February 05, 2008, 09:42:42
No, you are not missing something, and that is most definitely a possibility. I guess what I am looking for is a consistent way to pass information to a proxy before load. Creating and setting different properties on the proxies didn't seem like the most elegant solution because the interface for the class would essentially be different for each proxy. A new developer coming in might not know what properties have to be set before 'load' can be called. But maybe just adding an init method or something of the sort would work just as well.


Title: Re: first project with pureMVC
Post by: philipSe on February 07, 2008, 02:52:27
Jud
Presumably, as an alternative to an init method, you could pass the file location info as an argument to the constructor of ConfigProxy.  This makes it very plain that it is essential to that proxy.  I'm assuming this does not contravene best practice.
    Philip


Title: Re: first project with pureMVC
Post by: meekgeek on February 07, 2008, 01:35:13
Ok, I figured something out.  This is what I came up with for timing out.  I might be going in a different direction so feel free to pull me in.

I didn't want to get to far from where Philip was heading but I did want to keep things in reach of the ApplicationFacade so I could send notifications.

So here's what I did different.  Seeing as all these examples have the proxies using the same method ( loading, onComplete, etc).  I created the StartupResourceProxy which extends Proxy. All proxies that now work with the StartupMonitorProxy extend StartupResourceProxy in my project.  I also moved Philips StartupResource class in here.

Here's the code.
:
package org.puremvc.utilities.startupmanager
{
import com....ApplicationFacade;

import flash.events.TimerEvent;
import flash.utils.Timer;

import org.puremvc.interfaces.IProxy;
import org.puremvc.patterns.proxy.Proxy;

public class StartupResourceProxy extends Proxy implements IProxy
{
private static const EMPTY :String = 'empty';
        private static const LOADING :String = 'loading';
        private static const LOADED :String = 'loaded';
        private static const TIMED_OUT:String = 'timed_out';

private var status :String;

private var _timeout:int;
private var timer:Timer;

// StartupResources, pre-requisites for this resource, if any.
// These pre-requisites must be loaded before this resource can be loaded.
private var _requires :Array;

public function StartupResourceProxy(proxyName:String=null, data:Object=null)
{
super(proxyName, data);

this.status = EMPTY;
this.requires = new Array();
}

public function setStatusToLoading() :void
{
    status = LOADING;
   
    if(this._timeout != 0)
    startTimer();
}

public function setStatusToLoaded() :void
{
    status = LOADED;
    if(this._timeout != 0)
    timer.stop();
}

public function setStatusToTimedOut() :void
{
status = TIMED_OUT;
}

public function isLoaded() :Boolean
{
    return status == LOADED;
}

public function isTimedOut() :Boolean
{
return status == TIMED_OUT;
}

public function set requires( resources :Array ) :void
{
    _requires = resources;
}

public function get requires() :Array
{
    return _requires;
}

public function isOkToLoad() :Boolean
{
    if ( status != EMPTY ) return false;
    for( var i:int =0; i < requires.length; i++) {
    var r:StartupResourceProxy = requires[i] as StartupResourceProxy;
        if ( !r.isLoaded())
        return false;
    }
    return true;
}

public function set timeout(value:int):void
{
this._timeout = value;
}

private function startTimer():void
{
    timer = new Timer(this._timeout*1000, 1);
        timer.addEventListener(TimerEvent.TIMER, timedOut);
        timer.start();
}

private function timedOut(e:TimerEvent):void
{
this.sendNotification( ApplicationFacade.STARTUP_RESOURCE_TIMEDOUT, this.getProxyName());
}
}
}
and here's the interface you can implement:
:
package org.puremvc.utilities.startupmanager
{
import flash.events.Event;

public interface IStartupResourceProxy
{
/**
* Get the Proxy name
*
* @return the Proxy instance name
*/
function getProxyName():String;

function onComplete(e:Event):void;
function load():void;
}
}

I've added some code to Philips StartupResouce class which handles the timer event.  If the resource times out before it's finished loading, it notifies the StartupResourceCommand as follows.

:
package com....controller
{
import com....ApplicationFacade;
import com....model.StartupMonitorProxy;

import org.puremvc.interfaces.ICommand;
import org.puremvc.interfaces.INotification;
import org.puremvc.patterns.command.SimpleCommand;

public class StartupResourceTimedOutCommand extends SimpleCommand implements ICommand
{
override public function execute(notification:INotification):void
{
( facade.retrieveProxy( StartupMonitorProxy.NAME ) as StartupMonitorProxy).
    resourceTimedOut( notification.getBody() as String );
}

}
}

This lets the monitor know what just timed out.  I added a few things to the monitor to work with the resources that have timed out. It primarily just adds the resource to a list and allows the system to keep going if it doesn't finish loading.

Here's the code:
:
package com....model
{

import com....ApplicationFacade;

import org.puremvc.interfaces.*;
import org.puremvc.patterns.proxy.Proxy;
import org.puremvc.utilities.startupmanager.StartupResourceProxy;


    public class StartupMonitorProxy extends Proxy implements IProxy
    {
public static const NAME:String = "StartupMonitorProxy";
// array listing all the resources to be loaded
private var resourceList:Array;
// array listing all the resources that timed out.
private var timedOutResourcesList:Array;
// number of loaded resources
private var loadedResources:int = 0;

public function StartupMonitorProxy ( data:Object = null )
        {
            super ( NAME, data );
this.resourceList = new Array();
this.timedOutResourcesList = new Array();
        }


/**
*Add a resource to be loaded

* @param r
*
*/
public function addResource( r :StartupResourceProxy, timeout:int=0 ):void
{
this.resourceList.push( r );

//If timeout included, add a timer;
if(timeout!=0)
r.timeout = timeout;
}

/**
         * Start/Continue to load all resources
         */
public function loadResources():void
{
for( var i:int = 0; i < this.resourceList.length; i++)
{
var r:StartupResourceProxy = this.resourceList[i] as StartupResourceProxy;
if ( r.isOkToLoad() )
{
var proxy:* = facade.retrieveProxy( r.getProxyName() ) as Proxy;
r.setStatusToLoading();
proxy.load();
}
}
}

/**
*The resource timed out, adds proxy to a list of any timed out proxies.

* @param proxyName
*
*/
public function resourceTimedOut(proxyName :String ):void
{

for( var i:int = 0; i < this.resourceList.length; i++)
{
var r:StartupResourceProxy = this.resourceList[i] as StartupResourceProxy;
if ( r.getProxyName() == proxyName )
{
r.setStatusToTimedOut();
timedOutResourcesList.push(r.getProxyName());
this.loadedResources++;

// if not all loaded, continue load.
if ( !allResourcesLoaded() )
{
this.loadResources();
}
break;
}
}
}

/**
         * The resource is loaded, update the state and check if the loading process is completed
*
         * @param name proxy name
         */
public function resourceLoaded( proxyName :String ):void
{
for( var i:int = 0; i < this.resourceList.length; i++)
{
var r:StartupResourceProxy = this.resourceList[i] as StartupResourceProxy;
if ( r.getProxyName() == proxyName )
{
r.setStatusToLoaded();
this.loadedResources++;

// send the notification for update the progress bar
//this.sendNotification( ApplicationFacade.LOADING_STEP, this.resourceList.length / this.loadedReources * 100 );

// if not all loaded, continue load.
if ( !allResourcesLoaded() )
{
this.loadResources();
}
break;
}
}

}

/**
         * Check if the loading process is completed
*
         * @return boolean process is completed
         */
private function allResourcesLoaded():Boolean
{
for( var i:int = 0; i < this.resourceList.length; i++)
{
var r:StartupResourceProxy = this.resourceList[i] as StartupResourceProxy;
if ( !r.isLoaded() && !r.isTimedOut() )
{
return false;
}
}

this.sendNotification( ApplicationFacade.LOADING_COMPLETE );
return true;
}

public function timeOutList():Array
{
return timedOutResourcesList;
}
}
}

And here's the command that starts it all up.

:
package com....controller
{

public class ModelPrepCommand extends SimpleCommand implements ICommand
{

override public function execute( note:INotification ):void
{
/* ... register monitor proxies ... */
facade.registerProxy( new StartupMonitorProxy() );
    var monitor:StartupMonitorProxy = facade.retrieveProxy( StartupMonitorProxy.NAME ) as StartupMonitorProxy;
   
            /* ... register other proxies ... */
            facade.registerProxy( new ProxyA() );
            facade.registerProxy( new ProxyB() );
           
            var rA:StartupResourceProxy = facade.retrieveProxy( ProxyA.NAME ) as StartupResourceProxy;
            var rB:StartupResourceProxy = facade.retrieveProxy( ProxyB.NAME ) as StartupResourceProxy;

monitor.addResource( rA, 10);
monitor.addResource( rB, 10 );

          rA.requires = [ rB ];
           
          monitor.loadResources();
}
}
}

Sorry for the long post.  This seems to work for me and I like how it hide most of the code by just extending the StartupResourceProxy. I tought about getting the retry policies going but wanted to get some feed back about this first.  Let me know if this helps anybody. PUREMVC RULES!!  ;D


Title: Re: first project with pureMVC
Post by: Joel Hooks on February 07, 2008, 05:44:58
meekgeek,

The timers all fire right out of the gate, so if they are set to 10, then it starts counting immediately, which is something I could plan for, but as the sequence goes it started adding them as completed resources and fired the LOADING_COMPLETE note when they weren't actually loaded.

It is also incrementing the completed resources when they time out. A timed out resource is not complete ;)

I'm loading a large dataset from multiple MySQL tables, so this is partly to blame. Works great otherwise.


Title: Re: first project with pureMVC
Post by: puremvc on February 07, 2008, 06:05:49
So, I think I mentioned this above but the threads and projects are getting out of control!

Philip Sexton has the code worked into a utility and demo, both ready to go into the repository. I told him since he did the work to turn it into a conforming utility and demo it, I'd set him up as Project Owner. Someone has to own it. But obviously the work is still continuing in this thread and the retry policy stuff would be good to have in there. Phil is assuming that you guys will make this work and it looks as if that's happening. So I'll be happy to make everyone who wants to contribute have write access to the repository. Some projects will need several folks working on them and this may be a pilot for us to see how well we can get folks coordinated.

Philip, can you reconcile this contribution from meekgeek ? Does it make sense with what you have?

-=Cliff>


Title: Re: first project with pureMVC
Post by: meekgeek on February 07, 2008, 10:17:57
You don't have to change anything.  It's not even perfect.  Just finished it today and I thought I would share.  ;)  I needed something quick so this is what I came up with.  I don't even take ownership.  Like I said, this code was going in a different direction and is probably not the best way to go.


Title: Re: first project with pureMVC
Post by: philipSe on February 08, 2008, 10:27:15
Thanks to meekgeek for sharing his work incorporating timeout into the previously posted startup monitor code.  I am here responding to Cliff's "can you reconcile..." above.  I am interpreting the timeout requirement as set out in the meekgeek posting.  There is no connection with the app resource's actual loading process, which, once started, runs on independently of the startup manager.

The Startup Manager Utility is currently the following 4 classes:
StartupResource, StartupMonitorProxy, IStartupProxy, StartupResourceLoadedCommand.

Taking this new work into account, I think the list of classes would become:
StartupResourceProxy, StartupMonitorProxy, IStartupProxy, StartupResourceLoadedCommand, StartupResourceTimedOutCommand; plus retain StartupResource, see below.

StartupResourceProxy
StartupResourceProxy has the advantage that the client app can name it and can retrieve it, assuming it is registered of course, and can thus have access to certain properties.  I would prefer not to require that the client's own resource proxy has to extend StartupResourceProxy, since that may impose on the client app design.  Instead, say the constructor is:
:
public function StartupResourceProxy( proxyName:String, appResourceProxy :IStartupProxy )
The cient app must instantiate its app resource proxies before the StartupResourceProxys.  The loadResources method of StartupMonitorProxy can now invoke the client loads via the IStartupProxy reference held by the StartupResourceProxy.  The StartupResourceProxy and the appResourceProxy must have different names, assigned by the client app.

In thinking about the internals of StartupResourceProxy, I think it makes sense to keep the StartupResource as a separate class: the proxy is a front for the StartupResource, the data property of the proxy is of type StartupResource, the proxy constructor creates the StartupResource. So, that takes us to 6 classes in the utility.  StartupResource would no longer have the 'proxyName' property.

Let this StartupResourceProxy have
- public methods for client use, e.g.: read/write 'requires', read/write 'timeout', read accessors for 'status', maybe also a setForRetry() to cause status change from TimedOut back to Empty
- internal methods for utility own use, as in access from StartupMonitorProxy.

StartupResource
This has a new timeout property, and a new TIMED_OUT status value, with associated access methods, per meekgeek's posting. The setStatusToLoading method starts the timer.  On timeout, a notification is sent e.g. STARTUP_RESOURCE_TIMED_OUT.  This is handled by the StartupResourceTimedOutCommand, which in turn calls the StartupMonitorProxy#resourceTimedOut method.  Questions: is there a non-zero default timeout? a timeout of zero means we ignore timeout? For now, my default would be zero.

StartupMonitorProxy
- resourceList is now a list of StartupResourceProxys
- let addResource() continue to have just one arg; let the client app set the timeout for the resource directly via the StartupResourceProxy
- resourceTimedOut(): set resource status, add to timedOutResourcesList
- allResourcesLoaded() is renamed to something like isLoadingFinished(), because some resources may have timed out and other resources may require those and so on, so we may be finished even though all resources are not loaded.

How does the client app know we're finished but not complete? Say we send a LOADING_FINISHED_INCOMPLETE note instead of a LOADING_COMPLETE note.  In the incomplete case, we could send in the note body an array of the incomplete StartupResourceProxys, to make it easy for the client to set those for retry if desired.  And if retry is desired, the client invokes monitor.loadResources() again to try the outstanding resources.  I know Cliff expects features that cause the utility itself to retry a number of times before reverting to the client, but I'm ignoring that for now.

IStartupProxy
Continues to just have the 'load' method, I don't see an example use of 'onComplete'.


Cliff/Meekgeek/others - any comments on the above?  Subject to your comments, if this is worth doing, it may be easiest for me to incorporate this into the utility at this time, since I have my hands on it.

Regards
    Philip


Title: Re: first project with pureMVC
Post by: puremvc on February 08, 2008, 01:01:07
I like the resposibilities of these actors. And retry policy management doesn't necessarily need to be there, just a sound way for the app to handle it as you described.

And definitely I'd default retry to 0.

Retry Policy, even if a separate util,  needs to handle throttling by controlling not only timeout and number of retries but also time between retries. Also, some  services want a minimum time between requests successful or not. So perhaps this is really another utility.

-=Cliff>   


Title: Re: first project with pureMVC
Post by: philipSe on February 09, 2008, 07:31:17
I just want to add a correction and an addition to my post above regarding timeout and the StartupManager utility.

1. Forget the setForRetry() idea.  Better to leave the resource status as timed out.  Then the client app simply invokes retry by a retryLoadResources method on StartupMonitorProxy.  The client doesn't have to reset individual resources.

2. We need to allow the client app to notify when a load process fails, e.g. <resourceABC>_LOAD_FAILED and have a new class in the utility StartupResourceLoadFailedCommand to handle such notifications.  Such failures are like timeouts in that they result in the LOADING_FINISHED_INCOMPLETE notification from the utility.

Regards, Philip