PureMVC Architects Lounge

Announcements and General Discussion => General Discussion => Topic started by: Sh0rtWave on August 20, 2008, 07:07:24

Title: StartupManager magic (as3) and a question or two.
Post by: Sh0rtWave on August 20, 2008, 07:07:24
I like StartupManager. It's cool. I, however, am in a unique situation when it comes to my resource loading needs. As I see it, I have 6 problems.

Problem # 1. One proxy that loads all my resources. The remote endpoint is a VMWare server (that hosts a truly obscene number of webservice methods, 750 to be exact).

Problem # 2. The same proxy makes decisions based on the remote server state on other resources to load (mostly based on permissions & running state, but there's "pre login" state information I need to retrieve as well).

Problem # 3. I need to keep that StartupManager utility up and running, because lots of the operations I perform rely upon sequenced loads of data to get some piece of information or another. (Like when I go to create a virtual machine, I have to fetch back the server's capability, available resources, permissions, etc. etc., it's a LOT of data I need).

Problem # 4. A lot of the methods I use remotely take variable lists of arguments to retrieve some piece of information or another. The server uses some "multifunctional" methods to retrieve data based on filter specifications provided in XML, and in some cases, it wants *arrays* of filter specifications.

Problem # 5. I'm interested in supporting more than just VMWare. I'm also targetting Xen, VirtualBox, and Microsoft Windows, and any CIM-based server to manage with my application along with VMWare. This almost certainly means that the way I'm going to formulate requests is going to be dramatically different from vendor to vendor, and the order in which I load things will be different as well, so I will need vendor-specific proxies.

Problem # 6: I seriously need rapid, and immediate feedback to report to my users the stage of operations, as well as a robust method of deciding what are critical errors, and what aren't, and a means of reporting those.

So, problem description complete...now how do I handle that mess?

StartupManager to the rescue! keepResourceListOpen() neatly solves the issue of dealing with the issue of variable resources to load. Problems 2, 3, and 6, done...sort of. Problem #3 leaves me with a requirement to be able to understand what state I'm in when I receive WAITING_FOR_MORE_RESOURCES. I have an idea tho...

What about the rest of those issues? I beat my head on the desk for a while, and then it occurred to me, I can make vendor-specific loading commands, and make a simple "resource proxy" like this:

import org.puremvc.as3.multicore.interfaces.IProxy;
import org.puremvc.as3.multicore.patterns.proxy.Proxy;
import org.puremvc.as3.multicore.utilities.startupmanager.interfaces.IStartupProxy;

public class ResourceProxy extends Proxy implements IStartupProxy {
private var taskTarget:String;
private var proxy:Proxy;
private var args:Array;

* ResourceProxy - this is needed just for the magical voodoo of the StartupManager.

public function ResourceProxy( target:String, monitoredProxy:HypervisorProxy, ... argList ) {
super(target, monitoredProxy);
proxy = monitoredProxy;
taskTarget = target;
args = argList;
// GOTTA have this
override public function getProxyName():String {
return taskTarget;

// Does the magic we need
public function load() : void {
var f:Function = proxy[taskTarget];
f.apply( proxy, args ); // black magic, v00d00

The magic key is in load(). Because we've told the ResourceProxy about the target function we want to call (and optionally, given it a set of arguments), we can then access that function by using the Function.apply() method, giving me a way of using the same proxy for multiple resources.

And then I slapped myself in the head, and realized I only needed one command, because in my vendor-specific proxy, I can generate the list of resources I need (because it's the thing that has to know), and push those into my command. So in my RetrieveServerResourcesCommand, I can do this.

var index:int = 0;
for each (var target:String in proxy.getResourceTargets(state)) {
var resource_rp:ResourceProxy = new ResourceProxy( target, proxy );
var resource:StartupResourceProxy = initResourceLoader( target + "SR", resource_rp);
resourceProxies[ target ] = resource;
if (index > 0)
resourceProxies[ target ].requires = [ resourceProxies[ lastTarget ] as StartupResourceProxy];
lastTarget = target;

Four caveats here:

First, my StartupMonitorProxy is created by a separate command and retrieved into this one. That'll make sense in a minute.

Second, initResourceLoader is functionally the same as makeAndRegisterStartupResource.

Third, the "state" variable references the current loading operation that I'm working with, in this case it will be "startupPhaseI".

Fourth, because my Hypervisor proxy result handler knows what function called it, it handles the issue of sending the notification with the target name (which is the proxy name, incidentally) so the StartupResourceLoadedCommand gets handled correctly.

Since my application is interested in sequenced loads of properties (each following property depends upon information from the one in front of it) building the requirements for each proxy is pretty easy. I chose an array-based method.

Ok then, magic performed. I now have a way of coercing StartupManager into loading a variable list of items, based on knowledge from the server, from the same proxy. Win!

So that's a few problems solved. Phase I startup, it's good. Phase II startup, whoah Nellie! I have variable lists of stuff to load here. That's not so hard, because the proxy has already determined in phase I what it's going to need for phase II, so I just invoke RetrieveServerResourcesCommand AGAIN (this time with state == "startupPhaseII"), and the server goes about doing its thing.

Thus, all started up.

Now I want to create a virtual machine, and I need to load some server stuff, and the tricky part, the Hypervisor has no idea what I want this time, so I can't depend upon it to get this info for me. I have to build a list.

So I make myself a new command RetrieveUserResourcesCommand, that runs off, and uses the same technique, except this time I've put the list of proxy functions that need to be called in the notification as an array, thus my code becomes:

var index:int = 0;
for each (var target:String in notification.getBody() as Array) {
var resource_rp:ResourceProxy = new ResourceProxy( target, proxy );
var resource:StartupResourceProxy = initResourceLoader( target + "SR", resource_rp);
resourceProxies[ target ] = resource;
if (index > 0)
resourceProxies[ target ].requires = [ resourceProxies[ lastTarget ] as StartupResourceProxy];
lastTarget = target;

Annnd voila. I should point out here for consistency's sake that any arguments supplied to the hypervisor proxy from the "view" part of the application comply with an IHypervisor interface, so there's no funny vendor-specific business here. The proxy will know what to do, and the view doesn't care!

So, that last bit leaves me in a pickle. When I cranked everything up, I had a command registered for WAITING_FOR_MORE_RESOURCES that causes the application to move to the "main state", because once my server data is loaded, I'm golden and can start doing stuff. Once I get that command, I unregister the WAITING_FOR_MORE_RESOURCES observer. But this is where it gets dicey...For the next set of resources I need to load, I need to register a new observer (i.e. command) that jumps into action when it gets WAITING_FOR_MORE_RESOURCES. This just feels cumbersome.

Based on the experience I've had thus far, I feel that StartupManager has great use as not just a startup loader/pre-loader, but as a faithful tool to continually load resources and report status across large applications very powerfully. I think it would be useful if StartupManager had some method of registering a custom message to fire, instead of "WAITING_FOR_MORE_RESOURCES", once the current list of resources is loaded, you could then cause it to fire off "PHASE_II_RESOURCES_LOADED" so you have an understanding of where you are. I plan on making this addition to it myself, but I'm curious if anyone else would be interested in it?

Title: Re: StartupManager magic (as3) and a question or two.
Post by: philipSe on August 21, 2008, 02:54:16
Great creative stuff!  Well done!

I note what you say about the custom message - seems like a reasonable idea.

It occurs to me to point out that you don't necessarily have to keep the resource list open across phases.  You are probably well aware that the StartupManager can reach the 'loading complete' state and you can subsequently start it again with the reset() operation.  I'm not saying that this has any advantage for you, but maybe a command on 'loading complete' could manage the phase advances and the registering of a new command for the waiting notification.  I'm assuming there are no mediators listening for these notifications; if there were, that would offer other possibilities regarding management of the phases.

Title: Re: StartupManager magic (as3) and a question or two.
Post by: Sh0rtWave on August 21, 2008, 05:55:47
Hrm, that's an idea...although with a command looking for LOADING_COMPLETE, I'm still left with the problem of determining state, and the next command to assign to listen for the notification. Unless I'm misunderstanding you, this would seem to require that each phase completion command would have to then know that the next command in line to register is Phase_N, which I suppose isn't bad if I'm only managing a few phases, but could get quickly cumbersome. This is why I lean towards registering a custom message for that completion notification, since the mechanism for "knowing" then becomes the facade, and the problem is solved cleanly.

My mother used to say "necessity is the mother of invention.". Truer words ne'er spoken. If I didn't have these monstrous server proxies, I'd never have come up with this craziness.

Incidentally, here's a screenshot of the application in action so you get a feel for what I'm up to here: http://www.stormwind-studios.com/public/Kodiak5.jpg

This is fully multicore + pipes, so I can support multiple servers(each in their own core) that all communicate with the global application via pipes. (Putting windows on the screen, logging, browsing across servers, etc.).

And by the way..Awesome job on StartupManager!