Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Pages: [1] 2
Print
Author Topic: Pipes Utility - Disconnecting Pipes  (Read 23625 times)
riafan
Courseware Beta
Jr. Member
***
Posts: 19


View Profile WWW Email
« on: June 11, 2008, 01:20:33 »

I refactored the MortgageApp to use the pipes utility.  I like the approach the Pipes utility takes - build the module-app app-module integration on top of the exisiting modules (i.e. add a junction  mediator to your exisiting module and ensure your module implements IPipeAware).

Cool stuff Cliff.

I did run into a question however.  I'm finding the need to disconnect individual 'pipes' from a TeeSplit or TeeMerge - not simply 'all' pipes. 

For example, my 'shell app' has an outbound (TeeSplit) and inbound (TeeMerge) pipe.  Dynamically loaded modules create pipes and connect to the latter 'shell' pipes.

When it comes time to unload a dynamically loaded module, I currently don't have a way to remove to the connection to the app's TeeSplit / TeeMerge without disconnecting all of the other modules' pipes as well. 

I simply subclassed TeeSplit and added function to disconnect the passed fitting. 

:
public function disconnectFitting(output:IPipeFitting):IPipeFitting
Doing so solved my problem.

*If* I'm not missing something, it might be worthwhile to add the latter function to TeeSplit.

Thanks
« Last Edit: June 12, 2008, 12:04:42 by riafan » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #1 on: June 13, 2008, 07:07:22 »

Excellent solution to the problem! I agree and will probably integrate this into the utility class as you suggest.

Glad to hear you've had a positive experience with it in your own app. And thanks for taking the time to report your findings and help improve the project.

-=Cliff>

Logged
riafan
Courseware Beta
Jr. Member
***
Posts: 19


View Profile WWW Email
« Reply #2 on: June 13, 2008, 08:03:07 »

No problem.  I've posted an architectural diagram over at http://joshuaostrom.com to help anyone working with the Pipes Utility.

Josh
Logged
sectore
Courseware Beta
Full Member
***
Posts: 29



View Profile WWW Email
« Reply #3 on: June 21, 2008, 12:38:21 »

Run into the same issue.

With a basic example using PureMVC MultiCore AS3, Pipes Utility and modules posted on my blog  I tried to figure out, what a good way to disconnect pipes connecting by a shell and a module (which is loaded by shell) could be.

So before unloading the module the shell disconnect the SHELL_TO_MODULE_PIPE (TeeSplit) and the module disconnects the MODULE_TO_SHELL_PIPE (Pipe). When the module is loaded again, these pipes will be connected again. That works fine.

However, is there anything to do to remove the other (unused) fittings of pipes which are used by module and shell together before the module is unloaded?

Feel free to check out the code of the example mentioned above, because "real" code is worth a thousand words ;) .

Any feedback are welcome!

-sectore
« Last Edit: June 21, 2008, 12:41:15 by sectore » Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #4 on: June 21, 2008, 01:24:41 »

is there anything to do to remove the other (unused) fittings of pipes which are used by module and shell together before the module is unloaded?

If you are unloading the module from code inside the shell, you presumably have a reference to the shell-end of the pipeline. What you could do is de-construct the pipeline by repeatedly calling 'disconnect' on the pipe fitting returned by the previous disconnect.

So if you had an output pipeline going from the shell into the module like:

:
Pipe + Filter + Queue + Pipe
And you have a reference to the first Pipe, then calling 'disconnect' on the Pipe will disconnect and return the Filter, which is still connected to the rest of the pipeline.

Now you have a reference to:

:
Filter + Queue + Pipe
calling 'disconnect' on the Filter will yield:

:
Queue + Pipe
and finally, calling 'disconnect' on the Queue will yield:

:
Pipe
Of course if you have a complex set of pipeworks you're going to need a smarter plumber. :)

However, I believe that removing the references to both ends of the pipe will suffice for the entire pipeline to be GC'd because there are no outside references to these objects.
The pipeline essentially becomes an 'unreachable island' in memory.

In addition to reference counting, the Flash Player GC also implements a two-pass 'mark and sweep' algorithm. First, beginning with the root object, it traverses all reachable objects and marks them. Then the sweep pass destroys any objects not marked and reclaims the memory.

-=Cliff>
Logged
sectore
Courseware Beta
Full Member
***
Posts: 29



View Profile WWW Email
« Reply #5 on: June 22, 2008, 01:21:39 »

Cliff, thanks for the detailed information I needed!

However, I believe that removing the references to both ends of the pipe will suffice for the entire pipeline to be GC'd because there are no outside references to these objects.

Ok, that's what I did. I removed only references of both ends of each pipe:

SHELL_TO_MODULE_PIPE:
- Shell disconnects its end (TeeSplit)
:
var shellOutPipe: TeeSplit = junction.retrievePipe( PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE ) as TeeSplit;
shellOutPipe.disconnect();

MODULE_TO_SHELL_PIPE:
- Module disconnects its end (Pipe)
:
var moduleOutPipe: Pipe = junction.retrievePipe( PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE ) as Pipe;
moduleOutPipe.disconnect();

Cliff, thanks for sharing the powerful Pipes Utility!

-Jens


Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #6 on: June 22, 2008, 05:04:09 »

Actually if you're just wanting to remove the entire pipeline, you can just do junction.removePipe(pipeName) on both ends.

The way you've done it, the junctions still retain a referenct to the pipe fittings on the ends, and only the middle goes away.

-=Cliff> 
Logged
sectore
Courseware Beta
Full Member
***
Posts: 29



View Profile WWW Email
« Reply #7 on: June 22, 2008, 09:09:37 »

Cliff, thanks for the tip!

I refactored the source using
:
junction.removePipe( PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE );
junction.removePipe( PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE );
to remove both unneeded pipes.

Last question: When a pipe is removed as you described, is there a need to remove any PipeListener as well?

-Jens

Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #8 on: June 22, 2008, 11:44:57 »

No, because the PipeListener has a reference to a reachable object, but not the other way around. It's the last pipe fitting on the pipeline and nothing has a reference to it, it just knows who to notify when a message comes down the pipeline.

-=Cliff>
Logged
ramanuja
Jr. Member
**
Posts: 17


View Profile Email
« Reply #9 on: August 01, 2008, 07:59:21 »

Hi,

With reference to post by rifian (http://forums.puremvc.org/index.php?topic=508.msg2165#msg2165), I have run into the same problem.

I have build a sample app which uses pipes and dynamic loading/unloading of modules. In the ShellJunctionMediator, I have the following code:
:
override public function onRegister():void {

// The SHELL_TO_MODULE_PIPE pipe from the shell to all modules.
junction.registerPipe(PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE, Junction.OUTPUT, new TeeSplit());

// The MODULE_TO_SHELL_PIPE pipe to the shell from all modules.
junction.registerPipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE, Junction.INPUT, new TeeMerge());

// Add a pipe listener for incoming messages to the shell.
junction.addPipeListener(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE, this, handlePipeMessage);

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

switch (note.getName()) {

case ApplicationFacade.MODULE_ADDED:
// Connect module passed in the notification body to shell.

// Connect a pipe from module to shell. This pipe is output pipe for module and tee merge for shell.
var module:IPipeAwareModule = note.getBody() as IPipeAwareModule;
var moduleToShell:Pipe = new Pipe();
module.acceptOutputPipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE, moduleToShell);
var shellIn:TeeMerge = junction.retrievePipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE) as TeeMerge;
shellIn.connectInput(moduleToShell);

// Connect a pipe from shell to module. This pipe is tee split for shell and input pipe for module.
var shellToModule:Pipe = new Pipe();
module.acceptInputPipe(PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE, shellToModule);
var shellOut:TeeSplit = junction.retrievePipe(PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE) as TeeSplit;
shellOut.connect(shellToModule);
break;

}
}
...
...
override public function handlePipeMessage(message:IPipeMessage):void {

switch (message.getType()) {

case PipeAwareModuleConstants.MODULE_DISPOSAL_MESSAGE:
// Call the dispose method of the module.

// HOW DO I REMOVE PIPES FROM THE SHELL TO THIS MODULE HERE??

var module:IPipeAwareModule = message.getBody() as IPipeAwareModule;
module.dispose();
break;
}

}

// HOW DO I REMOVE PIPES FROM THE SHELL TO THIS MODULE HERE??

I am doing, sendNotification(ApplicationFacade.MODULE_ADDED); each time I want to add a new module.

Now when it is time to remove module 'x', how do I remove the pipes attached to module 'x' in the TeeMerge and TeeSplit? I do not want to do:
:
junction.removePipe( PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE );
junction.removePipe( PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE );
because it will remove the pipes with other required modules as well.

rifian said subclassing TeeSplit and adding
:
public function disconnectFitting(output:IPipeFitting):IPipeFittinghelped.

But, how do I get a reference of the output:IPipeFitting that I must I pass to the above method?

Please help!!  :'(

Thanks,
Ramanuja
Logged
riafan
Courseware Beta
Jr. Member
***
Posts: 19


View Profile WWW Email
« Reply #10 on: August 01, 2008, 08:51:21 »

The approach I took was to have the module 'cache' the fittings when connecting them.

:
module.cacheFitting(moduleToApp,appIn);
:
public function cacheFitting(localFitting:IPipeFitting,remoteFitting:IPipeFitting):void
{
cachedFittings.push({local:localFitting,remote:remoteFitting});
}

Then, when it comes time to unload a loaded module, I simply 'cleanup'

:
public function cleanup():void
{
while(cachedFittings.length > 0)
{
var localFitting:IPipeFitting = cachedFittings[cachedFittings.length-1].local;
var remoteFitting:IPipeFitting = cachedFittings[cachedFittings.length-1].remote;

if(remoteFitting is DynamicTeeSplit)
   (remoteFitting as DynamicTeeSplit).disconnectFitting(localFitting);

localFitting.disconnect();
cachedFittings.pop();
       }
}

Hope that helps!!!
Logged
ramanuja
Jr. Member
**
Posts: 17


View Profile Email
« Reply #11 on: August 01, 2008, 11:42:26 »

Hi,

I like your implementation a LOT riafan. Its very neat.

I have a couple of doubts. I am sure you can solve them for me  :)

1. cachedFittings is a private var Array in the module right? So every module, has an array called cachedFittings that holds {local:localFitting,remote:remoteFitting}. Am I right here?

2. I have doubt with module.cacheFitting() method you mentioned. Should it not be
:
module.cacheFitting(appToModule,appOut); // It was ...(moduleToApp,appIn) before?

3. The DynamicTeeSplit which extends TeeSplit, has a method:
:
public function disconnectFitting(output:IPipeFitting):IPipeFittingIs this implementation correct?
:
public function disconnectFitting(output:IPipeFitting):IPipeFitting
{
for (var i:int=0;i<outputs.length;i++)
{
if (outputs[i] == output) {
// Remove the ith IPipeFitting.
outputs.splice(i, 1);
}
}
return output;
}

Does garbage collection happen for the ith element that is discarded above?


3. Is there no need for a DynamicTeeMerge? This question may be stupid but I just want to confirm. The moduleToApp pipe is connected to the TeeMerge of the app. I saw the implementation of TeeMerge.connectInput() method. The app maintains no reference to individual pipes that are merged right? How many ever modules may connect to the TeeMerge of the app. When unloading the module, it is sufficient to just execute the following?
:
// This is a method in the module's junction mediator.
override public function onRemove():void {
// Remove both pipes (shell -> module && module -> shell )
junction.removePipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE);
junction.removePipe(PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE);
}
junction.removePipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE); will remove the moduleToApp pipe completely? Will it be garbage collected?

I have asked a lot of questions   :-X
KEENLY awaiting your response.

Thanks,
Ramanuja.
Logged
newtriks
Courseware Beta
Full Member
***
Posts: 23


 - newtriks
View Profile WWW Email
« Reply #12 on: August 04, 2008, 03:33:10 »

Hi all,

I have been spending some time trying to delve into Garbage Collection for effective loading and unloading of modules within a MultiCore application and have achieved some good results.  I have made a blog post regarding my results and also build a demo application to help people further grasp techniques I have used:

http://www.nutrixinteractive.com/blog/?p=132

Cheers,

Simon

http://newtriks.com
Logged
ramanuja
Jr. Member
**
Posts: 17


View Profile Email
« Reply #13 on: August 04, 2008, 09:39:01 »

Hi,

Great learning for me from Simon's post about GC!

Is there a way to do this without the timer? I want the removeChild() to be executed as soon as the core is removed.

Lets say we want to remove a core CORE_NAME,

:
while (Facade.hasCore(CORE_NAME) != null) {
    // infinite loop
}

// Now remove child
app.removeChild(...);

Thanks,
Ramanuja.
Logged
ramanuja
Jr. Member
**
Posts: 17


View Profile Email
« Reply #14 on: August 04, 2008, 09:40:54 »

Cliff,

1. Does it make sense to have a Facade.hasCore() mehod to support the above post?
(if its correct  :-\)

2. In my ModuleJunctionMediator's onRemove() method:
:
override public function onRemove():void {
// Remove both pipes (shell -> module && module -> shell )
junction.sendMessage(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE,
new Message(PipeAwareModuleConstants.MODULE_DISPOSED_MESSAGE, null, 
        PipeAwareModuleConstants.MY_MODULE));
junction.removePipe(PipeAwareModuleConstants.MODULE_TO_SHELL_PIPE);
junction.removePipe(PipeAwareModuleConstants.SHELL_TO_MODULE_PIPE);
}
Will the message sent above reach the shell junction? This way, the hasCore() idea is not required. I feel the infinite loop is not a good design. Waiting to get your views on this.

Thanks,
Ramanuja.
« Last Edit: August 05, 2008, 05:30:32 by ramanuja » Logged
Pages: [1] 2
Print