RSS
 

Archive for the ‘PureMVC’ Category

Pipe Demo: Mortgage App

17 Jun

I’ve posted a pipes version of the mortgage app.

Things to note:

You can load / unload the modules dynamically.

A junction mediator is defined for each ‘player.’ In the mortgage app context that’s a mediator for the application itself, the Acme widget and the Foo widget.

ApplicationJunctionMediator
ModuleJunctionMediator (Acme)
ModuleJunctionMediator (Foo)

To make our lives easier when it comes time to unload the module, the module caches the app’s pipe fitting it’s connected to. This allows the module to easily ‘cleanup’ (disconnect our fittings) should we want to unload the module. You may find a cleaner approach to this, feel free to post in comments – the ‘caching approach’ was simple and thus the road taken for the demo.

 
 

Understanding PureMVC Pipes

15 Jun

Disclaimer: This a bit of a longer post!!

The pipes utility is newer to PureMVC and as such, I’ve seen questions on the blogosphere regarding it’s use.

The plumbing metaphor should help wrap you head around this utility and it’s use. Keep in mind that a pipe allows for one-way message flow.

So let’s take a look at how the utility can be used.

One great features of ‘Pipes’ is that they can use used on top of an existing app. That is, you’ll simply need to define a JunctionMediator at/for each integration point.

Let’s look at the simplest case, an application that loads and communicates with a module. We’ll assume that at some point you’ll want to use this same app to use multiple modules down the road. You’ll need to create a JunctionMediator for the application and a JunctionMediator for the module. We’ll dive into the details for those mediators but at a high level, that’s it – we simply define a ‘JunctionMediator’ for each ‘player.’

Here’s a simple diagram

Simple Pipe

Our JunctionMediator’s will be connected together with pipes. We’ll have one pipe that allows for application-to-module message flows and another pipe that allows for module-to-application flows.

On the receiving end of a pipe, we’ll want a pipe listener (you’ll have only one pipe listener for a given pipe). We’ll use pipe listeners to handle incoming pipe messages.

To send messages down a pipeline, we’ll normally use the Junction’s ‘sendMessage’ function.

Back to our simple example, our app’s JunctionMediator would be responsible for creating the app’s pipe fittings, creating pipes to connect to those fittings to the module.

So the first thing our app’s JunctionMediator would do would be to create a new junction at creation.


public class ApplicationJunctionMediator extends JunctionMediator
{
public function ApplicationJunctionMediator()
{
super(NAME, new Junction());
}

Once this mediator is registered with our facade, we’d want to create the PipeFittings. We’ll use a TeeSplit for outgoing and TeeMerge for incoming. The TeeSplit will allow us to connect to multiple modules for outbound messages. The TeeMerge will allow multiple modules to send messages up to our main app. We’ll also want to add a pipe listener on our TeeMerge. This listener will allow us to handle the messages being sent up from the modules to the app.


override public function onRegister():void
{
junction.registerPipe( PipeAwareModule.APP_TO_MODULE_PIPE, Junction.OUTPUT, new TeeSplit() );
junction.registerPipe( PipeAwareModule.MODULE_TO_APP_PIPE, Junction.INPUT, new TeeMerge() );
junction.addPipeListener( PipeAwareModule.MODULE_TO_APP_PIPE, this, handlePipeMessage );
}

Our handlePipeMessage function is responsible for handling the messages coming up from our modules to our app.


function handlePipeMessage(message:IPipeMessage):void

Being a Mediator, we can define what application-level notifications we’re interested in and how to handle those notifications. That is, we’ll want to utilize listNotificationInterests() and handleNotification(note:INotification). We’ll use these to listen for notifications and turn desired notifications into messages to pass down our pipes.

For example, our Mortgage App would listens for request for loan notifications and turn those notifications into messages.


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

switch( note.getName() )
{
case MortgageAppEventNames.REQUEST_FOR_LOAN:
var loanMessage:Message = new Message(MortgageAppEventNames.REQUEST_FOR_LOAN,null,note);
junction.sendMessage(PipeAwareModule.APP_TO_MODULE_PIPE,loanMessage);
break;
}
}

Our application JunctionMediator will also typically listen for a notification that a module has been loaded. Our app’s JunctionMediator will then create new pipes to connect the app’s junctionMediator to the modules junctionMediator. Something along the lines of…


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

switch( note.getName() )
{
case MortgageAppEventNames.REQUEST_FOR_LOAN:
var loanMessage:Message = new Message(MortgageAppEventNames.REQUEST_FOR_LOAN,null,note);
junction.sendMessage(PipeAwareModule.APP_TO_MODULE_PIPE,loanMessage);
break;

case ModuleEvents.CONNECT_MODULE_JUNCTION:
var module:IPipeAwareModule = note.getBody() as IPipeAwareModule;

// Create the pipe
var moduleToApp:Pipe = new Pipe();
// Connect the pipe to our module
module.acceptOutputPipe(PipeAwareModule.MODULE_TO_APP_PIPE, moduleToApp);

// Connect the pipe to our app
var appIn:TeeMerge = junction.retrievePipe(PipeAwareModule.MODULE_TO_APP_PIPE) as TeeMerge;
appIn.connectInput(moduleToApp);

// Create the pipe
var appToModule:Pipe = new Pipe();
// Connect the pip to our module
module.acceptInputPipe(PipeAwareModule.APP_TO_MODULE_PIPE,appToModule);

// Connect the pipe to our app
var appOut:TeeSplit = junction.retrievePipe(PipeAwareModule.APP_TO_MODULE_PIPE) as TeeSplit;
appOut.connect(appToModule);

break;

// And let super handle the rest (ACCEPT_OUTPUT_PIPE, ACCEPT_INPUT_PIPE, SEND_TO_LOG)
default:
super.handleNotification(note);

}
}

Finally our application’s JunctionMediator will handle the incoming pipe messages.


override public function handlePipeMessage(message:IPipeMessage):void
{
// Handle our Module->Application integration
trace(message);
var note:INotification = message.getBody() as INotification;

switch(note.getName())
{
case MortgageAppEventNames.LOAN_QUOTE_READY:
sendNotification(note.getName(),note.getBody(),note.getType());
break;
default:
sendNotification(note.getName(),note.getBody(),note.getType());
break;
}
}

That covers the basic responsibilities for our app’s JunctionMediator.

Our module’s JunctionMediator would listen for messages coming in on the APP_TO_MODULE named pipe and send [outbound] messages on the MODULE_TO_APP pipe.


override public function handleNotification(note:INotification):void
{
// Handle our Module->Application integration
switch( note.getName() )
{
case ModuleFacade.QUOTE_GENERATED:
// convert our *local* notification into the application format
var quoteMessage:Message = new Message(MortgageAppEventNames.LOAN_QUOTE_READY,null,
new Notification(MortgageAppEventNames.LOAN_QUOTE_READY,note.getBody(),note.getType()));
junction.sendMessage(PipeAwareModule.MODULE_TO_APP_PIPE,quoteMessage);
break;
}
}

override public function handlePipeMessage( message:IPipeMessage ):void
{
// Handle our Application->Module integration
var note:INotification = message.getBody() as INotification;
switch(note.getName())
{
case MortgageAppEventNames.REQUEST_FOR_LOAN:
sendNotification(ModuleFacade.QUOTE_REQUESTED,note.getBody(),note.getType());
break;
}

}

If the app was to load another module our diagram would become…
Pipes App with Two Modules

If your still have questions – just ask :)

 
 

Pipe Architecture

13 Jun

Here’s a working architecture for modular applications utilizing PureMVC pipes.

Pipe Architecture

This allows you to have modules that load modules that load modules, etc. The modules communicate to each other via Pipes.

The sample diagram illustrates a parent, child, grandchild relationship (An app that loads a module that loads module). You can of course, have multiple siblings.

 

PureMVC Pipes

12 Jun

I had a chance to work with Cliff Hall’s PureMVC ‘Pipes’ utility this week. Highly recommended.

If your interested in utilizing modules in your PureMVC projects, you owe it to yourself to take a look at the Pipes utility.

What’s needed to integrate a module?

The requirements are very light. You module should:

Implement IPipeAware
Create a JunctionMediator.

Thats it.

I took some time and refactored the Mortgage app to use the Pipes utility.

I ran into a small bump after unloading widgets. If I unloaded a widget and then clicked “Quotes”, I still received a loan quote from what should have been an unloaded module. I ended up subclassing the ‘TeeSplit’ class to allow disconnecting a single known IPipeFitting. This allowed me to ‘cleanup’ the dynamic modules properly.

That aside, the utility was very easy to work with – the plumbing metaphors really make things clear.

I found the utility to be quite flexible as well. I just wrapped up working on some utility classes that allow modules to load modules that load modules etc. Getting this to work with direct core to core communications was at best ‘messy.’ Using the pipes made this very clean and simple.

 
 

PureMVC + Lazily [late] Instantiated Components

06 Jun

One small caveat when working with PureMVC – If your [view] component is defined at design time, but not created at application startup you’ll need to defer the

facade.registerMediator( )

This might happen, for example, when your component resides in a viewstack.

A simple work around is to dispatch an event (make sure it bubbles) on the component’s creationCompelete.

creationComplete="dispatchEvent(new Event(CommonEvents.COMPONENT_INITIALIZED,true))"

In the ‘application level’ mediator, create an event listener for this event

viewComponent.addEventListener(
CommonEvents.COMPONENT_INITIALIZED,onComponentReady,false,0,true);

When the event is picked up you’ll have to determine which [lazy] component is ready

public function onComponentReady(event:Event):void
{
var comp:UIComponent = event.target as UIComponent;

switch(comp.id)
{
case "userSearch":
facade.registerMediator(new UserSearchMediator(comp));
break;
case "serviceRecord":
facade.registerMediator(new ServiceRecordMediator(comp));
break;
case "appToolbar":
facade.registerMediator(new AppToolbarMediator(comp));
break;
}

}

So, in short, we simply defer creating the component’s mediator until the view component is ready :)

 
 

AS3 PureMVC Dynamic Modules

24 May

Okay, I’ve had some questions on refactoring my PureMVC dynamic modules classes to support AS3 projects (i.e. no flex).

I’ve posted a sample app that does just that.

I threw this together off the cuff, so don’t expect too much :)

The app (10K) simply loads 6 modules dynamically, 3 “RedTint” modules and 3 “GreenTint” modules (4k each). The app sends a notification every second containing a random color. The loaded modules pick up on this notification and display the color – each with their corresponding tint.

Keep a close eye on Cliff’s Pipe utility as these classes may soon be obsolete :) Until that time, I hope you might find this useful – if you do, drop me a line and let me know.

I’ve got some time between projects if anyone is looking for some RIA development…

 

Dynamic Modules … General Tips

21 May

Okay, for those of you getting ready to work with dynamic modules, I thought I’d share a few minor points I picked up on this past week.
Your application must include a reference to any interfaces the module implements.

<mx:Moudule implements"com.company.project.SomeInterface">

You’d want a reference to com.company.project.SomeInterface in your main app.
Likewise if the module has subclassed Module

public class MyModule extends Module

You’ll need a reference to MyModule in your main app as well.

There are compiler options to include these references, however I find it easiest to just declare a variable of the corresponding type.

i.e. var interfaceDef:ICustomInterface

If you find yourself wanting to create your own ‘View’ class in PureMVC it’s pretty straightforward. Just ensure that you subclass the controller as well.

Here’s a sample facade utilizing a custom view class…

protected override function initializeController( ):void
{
if ( controller != null )
return;
controller = CustomController.getInstance( multitonKey );
}

// Our custom View subclass in action
protected override function initializeView( ):void
{
if ( view != null )
return;
view = CustomView.getInstance( multitonKey );
}

And the custom controller…

public static function getInstance( key:String ) : IController
{
if ( instanceMap[ key ] == null )
instanceMap[ key ] = new CustomController( key );
return instanceMap[ key ];
}

override protected function initializeController( ) : void
{
view = CustomView.getInstance(multitonKey);
}

Finally, our custom View

public static function getInstance( key:String ) : IView
{
if ( instanceMap[ key ] == null )
instanceMap[ key ] = new CustomView( key );
return instanceMap[ key ];
}

In practice the view in initialized in the controller’s initializeController() method, so without subclassing your Controller you still maintain the standard View.

 
 

Dynamic Flex Modules with PureMVC

19 May

I’m rolling out a large project, and I wanted to utilize dynamic modules for scalability.

For those who aren’t familiar will modules, basically, there a great way to encapsulate “pieces” of your application. A trivial example would be a small ‘shell application’ that once the user logs in, loaded the appropriate use-case module. If your working in a team environment modules make for an easy project divide-and-conquer approach.

I’ve been using the PureMVC framework lately and figured adding support for dynamic modules wouldn’t be too difficult as Cliff and the gang have already been hard at working getting the framework changes in place to make this possible (replacing singletons with multitons etc).

Well after some working laying this out, I’m glad to say I’ve got it working. Check out this sample app Dynamic Mortgage Demo.

The demo allows the user to get loan quotes from [fictional] banks. The demo allows the user to dynamically load / unload bank “modules.”

The application and modules are very well encapsulated. Here’s whats required from each party…

Application:

Must compile with…

A reference to any interfaces the modules loaded at runtime implement (ILoadableModule in our case).

A reference to any subclasses of mx:Module the modules are using (PureMVCLoadableModule in our case). This is only necessary if your subclassing mx:Module.

That’s it.

Here’s the integration point on the modules end…

The modules facade implements an “InitializeMapping” function which maps application notification names to local (module) notification names [inbound mapping]. The function also defines module notification name to application notification name [outbound] mappings.

Here’s an example

override public function initializeMappings():void
{
outboundMappings:Array = new Array();
outboundMappings[QUOTE_GENERATED] = EventNames.LOAN_QUOTE_READY;

inboundMappings = new Array();
inboundMappings[EventNames.REQUEST_FOR_LOAN] = QUOTE_REQUESTED;
}

And thats the extent of what our application and modules know of each other. The rest of the ‘work’ is done automatically by a few interfaces / subclasses I wrote on top of PureMVC to make this possible. (i.e. your modules facade subclasses ModuleFacadeBase etc). No framework changes we’re required just some subclassing here and there.

 

And the framework is …

04 Jan

We’ll after studying Cairngorm and PureMVC for the past day or so I’ve decided to adopt PureMVC for my next Flex project.

Cairngorm had the scalability and robustness I was after but end the I went with the underdog. The best thing Cairngorm has going for it is the Adobe Machine and thus a large adoption pool. Kudos to Steve Webster and the rest of the Cairngorm authors, it is a well thought out and obviously scalable framework.

PureMVC seems cleaner to implement and addresses most of the issues you’ll find people gripping about with Cairngorm.

Anyways, time will tell, for now I’m jumping on the PureMVC bandwagon – thanks Cliff!!

 

Flex Architecture Frameworks

03 Jan

I’m gearing up to start some medium scale enterprise projects and thought I’d look up this “Cairngorm” thing I heard talked about at the MAX conference in Chicago. The developers either loved or hated it, so I figured I should check it out. Basically Cairngorm is a design pattern framework for flex, an architect’s tool chest if you will. We’ll it appears that Cairngorm isn’t alone, here’s the lineup I ran across today…

Cairngorm

PureMVC

APR

Tom Bray’s EasyMVC

Simeon Bateman’s EasyMVC

(EasyMVC’s share the same name but are, in fact, different frameworks)

The latter two (EasyMVC’s) appear to be lighter weight frameworks, while Cairngorm and PureMVC both seem to be a bit more robust. PureMVC isn’t just for flex it currently supports or is in the process of been implemented in … Flex, Flash, AIR, FlashLite, .NET, Windows Mobile, Silverlight, J2ME, SE, EE, JavaFX, and well… PHP and ColdFusion.

I’m reading into all four frameworks to decide which, if any to further evaluate. I may adopt one for my upcoming projects or use them as spring boards to writing my own framework to help enforce the DP’s I’ve been studying as of late.