Hi All,
I want to present a new PureMVC utility called Fabrication. The objective of Fabrication is to simplify the process of developing modular PureMVC multicore applications.
Fabrication is a collection of common ideas that I was using in applications built on top of PureMVC multicore. A Fabrication application is just like any other PureMVC application, with a few optimizations and shortcuts. It is based on the Pipes utility of PureMVC multicore, and some other related ideas I found in the open source video conferencing project,
Blindside.
I found that the Puremvc Facade's behaviour is common across most applications. A facade.startup(app:Object) call initializes the PureMVC apparatus, A startup command is registered with it to do bootstrap work. This process was common to almost all my applications. So I decided to create a standard Facade implementation with a StartupCommand registration and a STARTUP notification.
By eliminating the need for a concrete facade, the work of bootstrapping Proxies, Mediators, etc was shifted to the StartupCommand. Since this is common for all applications I implemented a FabricationApplication extending mx:Application. In the process I was also able to setup automatic multiton key generation. With Fabrication, the only thing needed to hook into the PureMVC apparatus is to override the FabricationApplication's getStartupCommand method. Sample code is below,
<?xml version="1.0" encoding="utf-8"?>
<fab:FabricationApplication
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:fab="org.puremvc.as3.multicore.utilities.Fabrication.components.*">
<mx:Script>
<![CDATA[
import myapp.controller.MyAppStartupCommand;
override protected function getStartupCommand():Class {
return MyAppStartupCommand;
}
]]>
</mx:Script>
</fab:FabricationApplication>
An important part of Fabrication is its support for modules. Fabrication comes with a custom FabricationModule class that extends mx:Module. It also bootstraps in the same way as a FabricationApplication, with the getStartupCommand() method.
FabricationModules come fitted with standard pipe fittings. However instead of creating manual fittings to establish communication between modules, a principle of routing is used. The routing metaphor eliminates the need to create JunctionMediators and the translation of pipe messages into internal module notifications and vice-versa. The corresponding mxml code for the module is,
<?xml version="1.0" encoding="utf-8"?>
<fab:FabricationModule
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:fab="org.puremvc.as3.multicore.utilities.Fabrication.components.*">
<mx:Script>
<![CDATA[
import mymodule.controller.MyModuleStartupCommand;
override protected function getStartupCommand():Class {
return MyModuleStartupCommand;
}
]]>
</mx:Script>
</fab:FabricationModule>
The module is loaded into the application using the FabricationModuleLoader which extends mx:ModuleLoader. Since typical configuration in modular applications is shell-module, the default communication route for the module is set to the shell. The module loading code is,
var moduleLoader:FabricationModuleLoader = new FabricationModuleLoader();
moduleLoader.url = moduleDescriptor.url;
moduleLoader.router = applicationRouter;
moduleLoader.setDefaultRoute(applicationModuleAddress.getInputName());
moduleLoader.addEventListener(FabricationModuleEvent.MODULE_INITIALIZED, moduleInitializedListener);
moduleLoader.loadModule();
The most interesting part of all this is the communication between module and shell. Instead of sending and receiving messages via the junction.sendMessage and handlePipeMessages, messages are routed as standard PureMVC notifications. To send messages to other modules you call routeNotification. And to receive messages from different modules you simply add the notification name in listNotificationInterests of your Mediator. Or instead you can register that notification name with a command. The routing code is below,
// to listen to a routed notification from the shell, in the module's mediators use,
override public function listNotificationInterests():Array {
return ["MESSAGE_FROM_SHELL"];
}
// and handle the notification as you would in PureMVC
override public function handleNotification(note:INotification):void {
if (note.getName() == "MESSAGE_FROM_SHELL") {
}
}
// to send a notification to the shell use,
override public function onClick():Array {
routeNotification("MESSAGE_FROM_MODULE", {foo:"bar"});
}
The routeNotification method has an additional 4th parameter, "to". Use "to" for specifying the module to which you wish to send the message. This method is provided by extending FabricatonMediator or via facade.routeNotification.
// to send a message to all modules, use *
routeNotification(noteName, noteBody, noteType, "*");
// to send a message to all instances of a specific module use, ModuleName/*
routeNotification(noteName, noteBody, noteType, "ModuleName/*");
// to send a message to a specific module use
routeNotification(noteName, noteBody, noteType, "ModuleName/ModuleInstanceID");
In summary to build modular Fabrication applications you need to do the following,
- In the shell, extend FabricationApplication and implement getStartupCommand.
- In the module, extend FabricationModule and implement getStartupCommand.
- Mediators extend FabricationMediator.
- To send notifications between modules use routeNotification.
- To listen to routed notifications use, listNotificationInterests or map a command to that notification.
Fabrication also contains some other useful features like multi-level undo, routing firewall for controlling communication between modules etc. I will talk about some of these things in future posts.
I want to thank Cliff Hall for creating PureMVC. It has made my Flex programming much more fun. Also thanks to the folks behind the
Blindside project. The routing principles mentioned above are adapted from Blindside.
Download the Fabrication utility
here.
Download the Fabrication routing demo application with the binaries
here.
The live demo is
here.
I would love to get feedback from the community about Fabrication. Thanks.
peace,
darshan