RSS
 

Archive for the ‘Pipes’ Category

Pipes Source Code

17 Oct

I’ve been heads down in development the past few months. During that time I’ve had numerous requests for the full source on the dynamically loaded modules ‘Pipes’ demo,MortgageApp.

I *finally* had time to upload that source, simply use the ‘View Source’ on the demo to view the source.

I’ve implemented a few enterprise RIAs using PureMVC pipes now. They work great, but I’m working on engineering (architecting) a new approach that I’ll post on the blog when it’s ready 🙂

 
No Comments

Posted in Pipes

 

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 🙂