PureMVC
Cross-language implementation of the MVC meta-pattern - PureMVC. Supported languages:
- ActionScript 2
- ActionScript 3
- C#
- ColdFusion
- haXe
- Java
- Perl
- PHP
- Python
- Ruby
Cross-language implementation of the MVC meta-pattern - PureMVC. Supported languages:
For my latest project I’ve been working on a set of related portals with the UI written in Adobe Flex, communicating with a set of REST services. A common requirement that I’ve seen amongst these are to call a set of services at startup to load various initialization and configuration data, use that data to initialize a set of controls, and then allow the user to begin interacting with the app.
Given the asynchronous nature of making service calls in Flex (or Ajax apps or any other RIA technology) you can run into race conditions if you simply fire off all of the service calls at once, especially if the result handler of one service has a dependency on a piece of data that was loaded from a different service. Additionally, you need to be notified of when all the initialization services have finished so you can perform any rendering actions to make the app available for business.
(A concrete example of this would be an app that needs to load a list of position dates from a service, and will then pick the latest position date as a parameter into a number of other service calls that populate DataGrids on the screen. You must defer the calls to load each grid until the positionDates service has returned).
The first approach that my team had to implementing this would be to fire off the first service in the creationComplete handler of the application, then at the end of that service’s result handler fire off the second service, and so on. Given an application with two HTTPServices (svc1 and svc2) declared and a creationComplete event handler to kick the processing off, a contrived example of this would look like this:
private function onCreateComplete(event:Event):void
{
// wire service result handlers
svc1.addEventListener(ResultEvent.RESULT, result1);
svc2.addEventListener(ResultEvent.RESULT, result2);
// invoke first service
svc1.send();
}
private function result1(event:ResultEvent):void
{
// do something with the result of svc1, then invoke
// svc2
svc2.send();
}
private function result2(event:ResultEvent):void
{
// do something with the results of service 2, then
// perform actions to make app available
}
This type of design quickly grew brittle and unmanageable. Readability is forfeited as you need to navigate around all of your event handling methods to discern the ordering of events. Adding new service calls or changing the order becomes an exercise in figuring out where to insert the next call and how to hook it up into the flow. If you have certain subclasses of your application class that needed additional service calls (as my project does), it is difficult to insert a new service into the flow.
As a piece of refactoring, I created a neat little class to give us an easy way to put the ordering of the services in one central location, decoupling the service flow from the result handlers. It maintains an internal list of services to call, in the order that they are added to the chain. When you add an HTTPService (and it’s corresponding event handler) to the chain, a generic event handler is added to listen for the result event. When this handler is invoked, it’ll call the actual event handler that you provided for that service, and will then pop the next service off the chain and call it. You can also specify a final handler method to be called once all the services in the chain are finished:
public class ServiceChain
{
private var _chain:Array = new Array();
private var _curEntry:Object;
private var _chainFinishedHandler:Function;
public function ServiceChain()
{
super();
}
/**
* @param f
* Setter for the chainFinishedHandler, a method that will be
* invoked when the final service has returned.
*/
public function set chainFinishedHandler(f:Function):void {
_chainFinishedHandler = f;
}
/**
* @param svc
* @param resultHandler
*
* Adds a chain entry for the HTTPService and resultHandler pair
* (added as an anonymous object with svcclass and handler
* properties). An event listener is added to the svc class to
* invoke the genericOnServiceResult when the service returns.
*/
public function add(svc:HTTPService, resultHandler:Function):void
{
// redirect the results of all service calls to the generic handler
svc.addEventListener(ResultEvent.RESULT, genericOnServiceResult);
_chain.push({svcclass: svc, handler: resultHandler});
}
/**
* Pick the next service off the chain and invoke it's send method.
* If there is no service on the queue, we are finished. Invoke the
* chainFinishedHandler if present.
*/
public function run():void
{
_curEntry = _chain.shift();
if (_curEntry == null) {
if (_chainFinishedHandler != null)
_chainFinishedHandler();
return;
}
_curEntry.svcclass.send();
}
/**
* @param event
*
* The service has returned, so invoke the actual event handler for the
* service, then call run() to pick the next service from the chain.
*/
private function genericOnServiceResult(event:ResultEvent):void
{
_curEntry.handler(event);
run();
}
}
Then the application code simplifies to:
private function onCreateComplete(event:Event):void
{
var chain:ServiceChain = new ServiceChain();
chain.add(svc1, result1);
chain.add(svc2, result2);
chain.chainFinishedHandler = chainFinished;
chain.run();
}
private function result1(event:ResultEvent):void
{
// ... do something with the result of svc1
}
private function result2(event:ResultEvent):void
{
// ... do something with the result of service 2
}
private function chainFinished():void
{
// make app available
}
We’ve now decoupled the ordering of service calls from the handling of each service result, have a way for subclasses to insert their own calls to the chain (making the chain a protected member), and have an easy way to execute logic when service calls have finished. This pattern I suppose is something akin to a Chain of Responsibility with a different flavor to handle the asynchronicity of each operation. I’d imagine this type of thing could be useful in Flex, Silverlight, or any other rich client app which must initialize itself from remote services called asynchronously.
I've recently started a project (top secret!) using the new Adobe Integrated Runtime (AIR), Flex and ActionScript 3.0. Coming from a .NET and WPF world. this has been a step in a very different direction. There are a lot of things I don't really love about ActionScript, however it does do its job, and the Adobe AIR deployment strategy (along with its SQLLite database) is pretty damn good. One of the first things any developer will realize when trying to build a real Rich Internet Application (RIA) in ActionScript is the lack of threading. This makes doing background tasks very difficult. ActionScript, and its class library, works largely with callback methods (either from calling setInterval, using a Timer class, calling a SQLConnection or using the HTTPService or other class to make a data call). From what I can tell, this works much like the Windows message loop, inurrupting synchronous code on your UI thread to process the callback. While this is great for simple actions (say, a UI that calls a web service or REST service ), building a background process (such as a SQL Server synchronization engine) can get complicated. Due to the number of callbacks you'll receive each time you make a request (to SQLConnection or HTTPService ), there is a great amount of complexity in writing simple procedual background processes (that don't freeze up the UI). To better handle this situation, and ensure that your discrete functions run in the proper order (for example, Authenticate -> Get Data), a command pattern in ActionScript will become your best friend. You can string together multiple callbacks, and ensure that the code for these operations stay in one logical class. Furthermore, by using a queue, you can order your commands such that they run synchronously. This provides much more flexibility than the traditional scripting approach in ActionScript. Unfortunately, I cannot currently provide code samples, as I do not want to compromise the intellectual property of my project, however, I hope that this will help you get an idea of how to best manage your code and synchronous operations in .NET. Side Note: If you're using WCF I suggest you use the Basic HTTP Binding with Flex, as FlexBuilder gets confused with .NET Web Services