├── src_test ├── testutils │ ├── modules │ │ ├── ModuleAView.as │ │ ├── ModuleAMediator.as │ │ ├── ModuleAContext.as │ │ └── FixedModuleAContext.as │ └── TestStage.as ├── LaunchTestSuite.as └── org │ └── robotlegs │ └── utilities │ └── modular │ └── mvcs │ └── ModuleContextTest.as ├── .gitignore ├── src └── org │ └── robotlegs │ └── utilities │ └── modular │ ├── core │ ├── IModuleCommandMap.as │ ├── IModuleEventDispatcher.as │ ├── IModuleContext.as │ └── IModule.as │ ├── base │ ├── ModuleViewMap.as │ ├── ModuleMediatorMap.as │ ├── ModuleEventDispatcher.as │ └── ModuleCommandMap.as │ └── mvcs │ ├── ModuleCommand.as │ ├── FixedModuleContext.as │ ├── ModuleActor.as │ ├── ModuleMediator.as │ └── ModuleContext.as ├── README.textile └── LICENSE /src_test/testutils/modules/ModuleAView.as: -------------------------------------------------------------------------------- 1 | package testutils.modules 2 | { 3 | import flash.display.Sprite; 4 | 5 | /** 6 | * @author dlaurent 7 juin 2012 7 | */ 8 | public class ModuleAView extends Sprite 9 | { 10 | public function ModuleAView() 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src_test/testutils/TestStage.as: -------------------------------------------------------------------------------- 1 | package testutils 2 | { 3 | 4 | import flash.display.Stage; 5 | 6 | /** 7 | * Used to access stage while running unit tests. 8 | * @author dlaurent 7 juin 2012 9 | */ 10 | public class TestStage 11 | { 12 | public static var stage : Stage; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.settings/* 2 | 3 | /html-template/* 4 | /bin-debug/* 5 | /bin-release/* 6 | /bin/* 7 | docs/* 8 | obj/* 9 | 10 | .actionScriptProperties 11 | .flexProperties 12 | .flexLibProperties 13 | .FlexUnitSettings 14 | .project 15 | 16 | Icon 17 | Thumbs.db 18 | .DS_Store 19 | dist/* 20 | report/* 21 | doc/* 22 | 23 | src/FlexUnitApplication.mxml 24 | *.iml 25 | *.ipr 26 | *.iws -------------------------------------------------------------------------------- /src_test/testutils/modules/ModuleAMediator.as: -------------------------------------------------------------------------------- 1 | package testutils.modules 2 | { 3 | import org.robotlegs.utilities.modular.mvcs.ModuleMediator; 4 | 5 | /** 6 | * @author dlaurent 7 juin 2012 7 | */ 8 | public class ModuleAMediator extends ModuleMediator 9 | { 10 | public static var numInstances : int = 0; 11 | 12 | public function ModuleAMediator( view : ModuleAView ) 13 | { 14 | numInstances++; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/core/IModuleCommandMap.as: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 the original author or authors 3 | * 4 | * Permission is hereby granted to use, modify, and distribute this file 5 | * in accordance with the terms of the license agreement accompanying it. 6 | */ 7 | 8 | package org.robotlegs.utilities.modular.core 9 | { 10 | import org.robotlegs.core.ICommandMap; 11 | 12 | public interface IModuleCommandMap extends ICommandMap 13 | { 14 | } 15 | } -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/core/IModuleEventDispatcher.as: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 the original author or authors 3 | * 4 | * Permission is hereby granted to use, modify, and distribute this file 5 | * in accordance with the terms of the license agreement accompanying it. 6 | */ 7 | 8 | package org.robotlegs.utilities.modular.core 9 | { 10 | import flash.events.IEventDispatcher; 11 | 12 | public interface IModuleEventDispatcher extends IEventDispatcher 13 | { 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/core/IModuleContext.as: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 the original author or authors 3 | * 4 | * Permission is hereby granted to use, modify, and distribute this file 5 | * in accordance with the terms of the license agreement accompanying it. 6 | */ 7 | 8 | package org.robotlegs.utilities.modular.core 9 | { 10 | import org.robotlegs.core.IContext; 11 | 12 | public interface IModuleContext extends IContext 13 | { 14 | function dispose():void; 15 | } 16 | } -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/base/ModuleViewMap.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.modular.base 2 | { 3 | import org.robotlegs.base.ViewMap; 4 | import org.robotlegs.core.IInjector; 5 | 6 | import flash.display.DisplayObjectContainer; 7 | 8 | /** 9 | * @author dlaurent 7 juin 2012 10 | */ 11 | public class ModuleViewMap extends ViewMap 12 | { 13 | public function ModuleViewMap( contextView : DisplayObjectContainer, injector : IInjector ) 14 | { 15 | super( contextView, injector ); 16 | } 17 | 18 | public function dispose() : void 19 | { 20 | removeListeners(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/base/ModuleMediatorMap.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.modular.base 2 | { 3 | import org.robotlegs.base.MediatorMap; 4 | import org.robotlegs.core.IInjector; 5 | import org.robotlegs.core.IReflector; 6 | 7 | import flash.display.DisplayObjectContainer; 8 | 9 | /** 10 | * @author dlaurent 7 juin 2012 11 | */ 12 | public class ModuleMediatorMap extends MediatorMap 13 | { 14 | public function ModuleMediatorMap( contextView : DisplayObjectContainer, injector : IInjector, 15 | reflector : IReflector ) 16 | { 17 | super( contextView, injector, reflector ); 18 | } 19 | 20 | public function dispose() : void 21 | { 22 | removeListeners(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/base/ModuleEventDispatcher.as: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 the original author or authors 3 | * 4 | * Permission is hereby granted to use, modify, and distribute this file 5 | * in accordance with the terms of the license agreement accompanying it. 6 | */ 7 | 8 | package org.robotlegs.utilities.modular.base 9 | { 10 | import flash.events.EventDispatcher; 11 | import flash.events.IEventDispatcher; 12 | 13 | import org.robotlegs.utilities.modular.core.IModuleEventDispatcher; 14 | 15 | public class ModuleEventDispatcher extends EventDispatcher implements IModuleEventDispatcher 16 | { 17 | public function ModuleEventDispatcher(target:IEventDispatcher = null) 18 | { 19 | super(target); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src_test/LaunchTestSuite.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import testutils.TestStage; 4 | 5 | import org.flexunit.internals.TraceListener; 6 | import org.flexunit.runner.FlexUnitCore; 7 | import org.robotlegs.utilities.modular.mvcs.ModuleContextTest; 8 | 9 | import flash.display.Sprite; 10 | 11 | public class LaunchTestSuite extends Sprite 12 | { 13 | public function LaunchTestSuite() 14 | { 15 | TestStage.stage = stage; 16 | 17 | var uniqueTestClass : Class = null; 18 | 19 | core = new FlexUnitCore(); 20 | core.addListener( new TraceListener() ); 21 | 22 | if ( uniqueTestClass == null ) 23 | core.run( ModuleContextTest ); 24 | else 25 | core.run( uniqueTestClass ); 26 | } 27 | 28 | private var core : FlexUnitCore; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/mvcs/ModuleCommand.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.modular.mvcs 2 | { 3 | import flash.events.Event; 4 | 5 | import org.robotlegs.mvcs.Command; 6 | import org.robotlegs.utilities.modular.core.IModuleCommandMap; 7 | import org.robotlegs.utilities.modular.core.IModuleEventDispatcher; 8 | 9 | public class ModuleCommand extends Command 10 | { 11 | [Inject] 12 | public var moduleEventDispatcher:IModuleEventDispatcher; 13 | 14 | [Inject] 15 | public var moduleCommandMap:IModuleCommandMap; 16 | 17 | protected function dispatchToModules(event:Event):Boolean 18 | { 19 | if(moduleEventDispatcher.hasEventListener(event.type)) 20 | return moduleEventDispatcher.dispatchEvent(event); 21 | return true; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | Some helper classes for building modular apps with RobotLegs. 2 | 3 | h1. Usage 4 | 5 | Modules should implement IModule which provides a setter for an IInjector as well as a dispose method for cleanup. 6 | 7 | Each module requires a context, which should extend ModuleContext. This context should be instantiated when the module is provided with an injector. The ModuleContext uses the injector to provide the module with a child injector that maintains the mappings of the provided injector. 8 | 9 | The IModuleCommandMap and IModuleEventDispatcher work together to provide the modules with a shared event/command bus for inter-module events to take place. Each module has an individual ModuleCommandMap, but unlike the normal CommandMap this triggers module level commands in response to mapped events that occur over the shared IModuleEventDispatcher. 10 | 11 | "Here is an example of using this library":http://joelhooks.com/2010/05/02/modular-robotlegs/ 12 | 13 | Please see the "RobotLegs framework":http://www.robotlegs.org for more info. 14 | 15 | These classes were compiled to work with RobotLegs v1.1.0. -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/core/IModule.as: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 the original author or authors 3 | * 4 | * Permission is hereby granted to use, modify, and distribute this file 5 | * in accordance with the terms of the license agreement accompanying it. 6 | */ 7 | package org.robotlegs.utilities.modular.core 8 | { 9 | import org.robotlegs.core.IInjector; 10 | 11 | public interface IModule 12 | { 13 | /** 14 | * Use this setter to provide the module with an injector. 15 | * This setter should initiate the context of the module 16 | * via a ModuleContext that accepts the injector through its 17 | * constructor. The ModuleContext will create a child injector. 18 | * @param value 19 | * 20 | */ 21 | function set parentInjector(value:IInjector):void; 22 | 23 | /** 24 | * Modules need a method for cleanup and removal of the module from 25 | * memory to make them available for garbage collection. 26 | * 27 | */ 28 | function dispose():void; 29 | } 30 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 the original author or authors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/base/ModuleCommandMap.as: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 the original author or authors 3 | * 4 | * Permission is hereby granted to use, modify, and distribute this file 5 | * in accordance with the terms of the license agreement accompanying it. 6 | */ 7 | package org.robotlegs.utilities.modular.base 8 | { 9 | import flash.utils.Dictionary; 10 | 11 | import org.robotlegs.base.CommandMap; 12 | import org.robotlegs.core.IInjector; 13 | import org.robotlegs.core.IReflector; 14 | import org.robotlegs.utilities.modular.core.IModuleCommandMap; 15 | import org.robotlegs.utilities.modular.core.IModuleEventDispatcher; 16 | 17 | /** 18 | * Create command mappings that can be triggered by events dispatched on the 19 | * shared ModuleEventDispatcher. 20 | * 21 | * @author Joel Hooks 22 | * 23 | */ 24 | public class ModuleCommandMap extends CommandMap implements IModuleCommandMap 25 | { 26 | public function ModuleCommandMap(eventDispatcher:IModuleEventDispatcher, injector:IInjector, reflector:IReflector) 27 | { 28 | super(eventDispatcher, injector, reflector); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src_test/testutils/modules/ModuleAContext.as: -------------------------------------------------------------------------------- 1 | package testutils.modules 2 | { 3 | import org.robotlegs.core.IInjector; 4 | import org.robotlegs.utilities.modular.mvcs.ModuleContext; 5 | 6 | import flash.display.DisplayObjectContainer; 7 | import flash.system.ApplicationDomain; 8 | 9 | /** 10 | * @author dlaurent 7 juin 2012 11 | */ 12 | public class ModuleAContext extends ModuleContext 13 | { 14 | public function ModuleAContext( contextView : DisplayObjectContainer = null, autoStartup : Boolean = true, 15 | parentInjector : IInjector = null, applicationDomain : ApplicationDomain = null ) 16 | { 17 | super( contextView, autoStartup, parentInjector, applicationDomain ); 18 | } 19 | 20 | override public function startup() : void 21 | { 22 | injector.mapSingleton( ModuleAView ); 23 | mediatorMap.mapView( ModuleAView, ModuleAMediator ); 24 | 25 | contextView.addChild( injector.getInstance( ModuleAView ) ); 26 | 27 | super.startup(); 28 | } 29 | 30 | override public function shutdown() : void 31 | { 32 | contextView.removeChild( injector.getInstance( ModuleAView ) ); 33 | 34 | super.shutdown(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src_test/testutils/modules/FixedModuleAContext.as: -------------------------------------------------------------------------------- 1 | package testutils.modules 2 | { 3 | import org.robotlegs.core.IInjector; 4 | import org.robotlegs.utilities.modular.mvcs.FixedModuleContext; 5 | 6 | import flash.display.DisplayObjectContainer; 7 | import flash.system.ApplicationDomain; 8 | 9 | /** 10 | * @author dlaurent 7 juin 2012 11 | */ 12 | public class FixedModuleAContext extends FixedModuleContext 13 | { 14 | public function FixedModuleAContext( contextView : DisplayObjectContainer = null, autoStartup : Boolean = true, 15 | parentInjector : IInjector = null, applicationDomain : ApplicationDomain = null ) 16 | { 17 | super( contextView, autoStartup, parentInjector, applicationDomain ); 18 | } 19 | 20 | override public function startup() : void 21 | { 22 | injector.mapSingleton( ModuleAView ); 23 | mediatorMap.mapView( ModuleAView, ModuleAMediator ); 24 | 25 | contextView.addChild( injector.getInstance( ModuleAView ) ); 26 | 27 | super.startup(); 28 | } 29 | 30 | override public function shutdown() : void 31 | { 32 | contextView.removeChild( injector.getInstance( ModuleAView ) ); 33 | 34 | super.shutdown(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/mvcs/FixedModuleContext.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.modular.mvcs 2 | { 3 | import org.robotlegs.core.IInjector; 4 | import org.robotlegs.core.IMediatorMap; 5 | import org.robotlegs.core.IViewMap; 6 | import org.robotlegs.utilities.modular.base.ModuleMediatorMap; 7 | import org.robotlegs.utilities.modular.base.ModuleViewMap; 8 | 9 | import flash.display.DisplayObjectContainer; 10 | import flash.system.ApplicationDomain; 11 | 12 | /** 13 | * @author dlaurent 7 juin 2012 14 | */ 15 | public class FixedModuleContext extends ModuleContext 16 | { 17 | public function FixedModuleContext( contextView : DisplayObjectContainer = null, autoStartup : Boolean = true, 18 | parentInjector : IInjector = null, applicationDomain : ApplicationDomain = null ) 19 | { 20 | super( contextView, autoStartup, parentInjector, applicationDomain ); 21 | } 22 | 23 | override public function dispose() : void 24 | { 25 | ModuleMediatorMap( _mediatorMap ).dispose(); 26 | ModuleViewMap( _viewMap ).dispose(); 27 | super.dispose(); 28 | } 29 | 30 | override protected function get mediatorMap() : IMediatorMap 31 | { 32 | return _mediatorMap || 33 | ( _mediatorMap = 34 | new ModuleMediatorMap( contextView, injector.createChild( _applicationDomain ), reflector ) ); 35 | } 36 | 37 | override protected function get viewMap() : IViewMap 38 | { 39 | return _viewMap || ( _viewMap = new ModuleViewMap( contextView, injector.createChild( _applicationDomain ) ) ); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/mvcs/ModuleActor.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.modular.mvcs 2 | { 3 | import flash.events.Event; 4 | 5 | import org.robotlegs.mvcs.Actor; 6 | import org.robotlegs.utilities.modular.core.IModuleEventDispatcher; 7 | 8 | public class ModuleActor extends Actor 9 | { 10 | /** 11 | * @private 12 | */ 13 | protected var _moduleEventDispatcher:IModuleEventDispatcher; 14 | 15 | //--------------------------------------------------------------------- 16 | // Constructor 17 | //--------------------------------------------------------------------- 18 | 19 | public function ModuleActor() 20 | { 21 | } 22 | 23 | //--------------------------------------------------------------------- 24 | // API 25 | //--------------------------------------------------------------------- 26 | 27 | /** 28 | * @inheritDoc 29 | */ 30 | public function get moduleEventDispatcher():IModuleEventDispatcher 31 | { 32 | return _moduleEventDispatcher; 33 | } 34 | 35 | [Inject] 36 | /** 37 | * @private 38 | */ 39 | public function set moduleEventDispatcher(value:IModuleEventDispatcher):void 40 | { 41 | _moduleEventDispatcher = value; 42 | } 43 | 44 | protected function dispatchToModules(event:Event):Boolean 45 | { 46 | if(moduleEventDispatcher.hasEventListener(event.type)) 47 | return moduleEventDispatcher.dispatchEvent(event); 48 | return true; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/mvcs/ModuleMediator.as: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 the original author or authors 3 | * 4 | * Permission is hereby granted to use, modify, and distribute this file 5 | * in accordance with the terms of the license agreement accompanying it. 6 | */ 7 | 8 | package org.robotlegs.utilities.modular.mvcs 9 | { 10 | import flash.events.Event; 11 | 12 | import org.robotlegs.mvcs.Mediator; 13 | import org.robotlegs.utilities.modular.core.IModuleCommandMap; 14 | import org.robotlegs.utilities.modular.core.IModuleEventDispatcher; 15 | 16 | public class ModuleMediator extends Mediator 17 | { 18 | [Inject] 19 | public var moduleDispatcher:IModuleEventDispatcher; 20 | 21 | [Inject] 22 | public var moduleCommandMap:IModuleCommandMap; 23 | 24 | /** 25 | * Map an event type to globally redispatch to all modules within an application. 26 | *

27 | *

28 | * mapRedispatchToModules(MyEvent.SOME_EVENT); 29 | * 30 | * 31 | * @param event 32 | * 33 | */ 34 | protected function addModuleListener(type:String, listener:Function, eventClass:Class = null, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = true):void 35 | { 36 | eventMap.mapListener(moduleDispatcher, type, listener, eventClass, useCapture, priority, useWeakReference); 37 | } 38 | 39 | /** 40 | * Globally redispatch an event to all modules within an application. 41 | *

42 | *

43 | * eventMap.mapEvent(view, MyEvent.SOME_EVENT, redispatchToModule); 44 | * 45 | * 46 | * @param event 47 | * 48 | */ 49 | protected function dispatchToModules(event:Event):Boolean 50 | { 51 | if(moduleDispatcher.hasEventListener(event.type)) 52 | return moduleDispatcher.dispatchEvent(event); 53 | return false; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src_test/org/robotlegs/utilities/modular/mvcs/ModuleContextTest.as: -------------------------------------------------------------------------------- 1 | package org.robotlegs.utilities.modular.mvcs 2 | { 3 | import testutils.TestStage; 4 | import testutils.modules.FixedModuleAContext; 5 | import testutils.modules.ModuleAContext; 6 | import testutils.modules.ModuleAMediator; 7 | 8 | import org.flexunit.asserts.assertEquals; 9 | import org.flexunit.asserts.assertFalse; 10 | import org.flexunit.asserts.assertTrue; 11 | import org.flexunit.async.Async; 12 | 13 | import flash.events.Event; 14 | import flash.events.TimerEvent; 15 | import flash.system.System; 16 | import flash.utils.Timer; 17 | 18 | /** 19 | * @author dlaurent 7 juin 2012 20 | */ 21 | public class ModuleContextTest 22 | { 23 | 24 | [Before( async )] 25 | public function setup() : void 26 | { 27 | System.gc(); 28 | ModuleAMediator.numInstances = 0; 29 | 30 | // This strange thing is intended to let the time for the GC to clean memory (sometimes 31 | // it is a bit more longer and listeners from the first test are still there when running the second test). 32 | var delayer : Timer = new Timer( 2000, 1 ); 33 | Async.proceedOnEvent( this, delayer, TimerEvent.TIMER_COMPLETE, 3000 ); 34 | delayer.start(); 35 | } 36 | 37 | /** 38 | * With the original ModuleContext, we see that the ADDED_TO_STAGE listeners (viewMap and mediatorMap) 39 | * are not unregistered if the GC didn't pass after the dispose of moduleAContext. 40 | * 41 | * NOTE : This test is a bit random, it can fail if the GC does the garbage collection just after the 42 | * "moduleAContext.dispose()" instruction. 43 | */ 44 | [Test] 45 | public function after_ModuleContext_shutdown__contextView_still_have_ADDED_TO_STAGE_listener() : void 46 | { 47 | // --o Setup 48 | var moduleAContext : ModuleAContext = new ModuleAContext( TestStage.stage, false ); 49 | moduleAContext.startup(); 50 | // --o Exercise 51 | moduleAContext.dispose(); 52 | // --o Verify 53 | assertTrue( TestStage.stage.hasEventListener( Event.ADDED_TO_STAGE ) ); 54 | } 55 | 56 | /** 57 | * With the fix, the ADDED_TO_STAGE listeners (viewMap and mediatorMap) are released. 58 | */ 59 | [Test] 60 | public function after_FixedModuleContext_shutdown__contextView_shouldnt_have_ADDED_TO_STAGE_listener() : void 61 | { 62 | // --o Setup 63 | var moduleAContext : FixedModuleAContext = new FixedModuleAContext( TestStage.stage, false ); 64 | moduleAContext.startup(); 65 | // --o Exercise 66 | moduleAContext.dispose(); 67 | // --o Verify 68 | assertFalse( TestStage.stage.hasEventListener( Event.ADDED_TO_STAGE ) ); 69 | } 70 | 71 | /** 72 | * Here, we can see that the memory leak issue has the consequence to instanciate too much mediators 73 | * for a unique view instance. 74 | * 75 | * NOTE : This test is a bit random, it can fail if the GC does the garbage collection just after the 76 | * "moduleAContext.dispose()" instruction. 77 | */ 78 | [Test] 79 | public function with_memory_leak_issue__too_much_mediators_are_created_after_second_instanciation() : void 80 | { 81 | // --o Setup 82 | var moduleAContext : ModuleAContext = new ModuleAContext( TestStage.stage, false ); 83 | moduleAContext.startup(); 84 | moduleAContext.dispose(); 85 | // --o Exercise 86 | assertEquals( 1, ModuleAMediator.numInstances ); 87 | // --o Verify 88 | moduleAContext = new ModuleAContext( TestStage.stage, false ); 89 | moduleAContext.startup(); 90 | // Two mediators have been created for this single module startup. 91 | assertEquals( 3, ModuleAMediator.numInstances ); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/org/robotlegs/utilities/modular/mvcs/ModuleContext.as: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 the original author or authors 3 | * 4 | * Permission is hereby granted to use, modify, and distribute this file 5 | * in accordance with the terms of the license agreement accompanying it. 6 | */ 7 | 8 | package org.robotlegs.utilities.modular.mvcs 9 | { 10 | import flash.display.DisplayObjectContainer; 11 | import flash.events.Event; 12 | import flash.system.ApplicationDomain; 13 | 14 | import org.robotlegs.adapters.SwiftSuspendersInjector; 15 | import org.robotlegs.base.CommandMap; 16 | import org.robotlegs.base.ContextEvent; 17 | import org.robotlegs.base.MediatorMap; 18 | import org.robotlegs.core.ICommandMap; 19 | import org.robotlegs.core.IInjector; 20 | import org.robotlegs.core.IMediatorMap; 21 | import org.robotlegs.mvcs.Context; 22 | import org.robotlegs.utilities.modular.base.ModuleCommandMap; 23 | import org.robotlegs.utilities.modular.base.ModuleEventDispatcher; 24 | import org.robotlegs.utilities.modular.core.IModuleCommandMap; 25 | import org.robotlegs.utilities.modular.core.IModuleContext; 26 | import org.robotlegs.utilities.modular.core.IModuleEventDispatcher; 27 | 28 | /** 29 | * Contains additional mappings and facilitates the use of a parent injector 30 | * to create a child injector for a module. 31 | * @author Joel Hooks 32 | * 33 | */ 34 | public class ModuleContext extends Context implements IModuleContext 35 | { 36 | protected var _applicationDomain:ApplicationDomain; 37 | 38 | protected var _moduleDispatcher:IModuleEventDispatcher; 39 | 40 | protected function get moduleDispatcher():IModuleEventDispatcher 41 | { 42 | return _moduleDispatcher; 43 | } 44 | 45 | protected function set moduleDispatcher(value:IModuleEventDispatcher):void 46 | { 47 | _moduleDispatcher = value; 48 | } 49 | 50 | protected var _moduleCommandMap:IModuleCommandMap; 51 | 52 | protected function get moduleCommandMap():IModuleCommandMap 53 | { 54 | return _moduleCommandMap || (_moduleCommandMap = new ModuleCommandMap(moduleDispatcher, injector.createChild(_applicationDomain), reflector)); 55 | } 56 | 57 | protected function set moduleCommandMap(value:IModuleCommandMap):void 58 | { 59 | _moduleCommandMap = value; 60 | } 61 | 62 | /** 63 | * The ICommandMap for this IContext 64 | */ 65 | override protected function get commandMap():ICommandMap 66 | { 67 | return _commandMap || (_commandMap = new CommandMap(eventDispatcher, injector.createChild(_applicationDomain), reflector)); 68 | } 69 | 70 | /** 71 | * @private 72 | */ 73 | override protected function set commandMap(value:ICommandMap):void 74 | { 75 | _commandMap = value; 76 | } 77 | 78 | /** 79 | * @private 80 | */ 81 | override protected function set mediatorMap(value:IMediatorMap):void 82 | { 83 | _mediatorMap = value; 84 | } 85 | /** 86 | * The IMediatorMap for this IContext 87 | */ 88 | override protected function get mediatorMap():IMediatorMap 89 | { 90 | return _mediatorMap || (_mediatorMap = new MediatorMap(contextView, injector.createChild(_applicationDomain), reflector)); 91 | } 92 | 93 | public function ModuleContext(contextView:DisplayObjectContainer=null, autoStartup:Boolean=true, parentInjector:IInjector = null, applicationDomain:ApplicationDomain = null) 94 | { 95 | _applicationDomain = applicationDomain || ApplicationDomain.currentDomain; 96 | if(parentInjector) 97 | { 98 | _injector = parentInjector.createChild(_applicationDomain); 99 | } 100 | super(contextView, autoStartup); 101 | } 102 | 103 | override protected function mapInjections():void 104 | { 105 | super.mapInjections(); 106 | initializeModuleEventDispatcher(); 107 | injector.mapValue(IModuleCommandMap, moduleCommandMap); 108 | } 109 | 110 | protected function initializeModuleEventDispatcher():void 111 | { 112 | if(injector.hasMapping(IModuleEventDispatcher) ) 113 | { 114 | moduleDispatcher = injector.getInstance(IModuleEventDispatcher); 115 | } 116 | else 117 | { 118 | moduleDispatcher = new ModuleEventDispatcher(this); 119 | injector.mapValue(IModuleEventDispatcher, moduleDispatcher); 120 | } 121 | } 122 | 123 | protected function dispatchToModules(event:Event):Boolean 124 | { 125 | if(moduleDispatcher.hasEventListener(event.type)) 126 | return moduleDispatcher.dispatchEvent(event); 127 | return true; 128 | } 129 | 130 | public function dispose():void 131 | { 132 | dispatchEvent(new ContextEvent(ContextEvent.SHUTDOWN)); 133 | _commandMap.unmapEvents(); 134 | _moduleCommandMap.unmapEvents(); 135 | _moduleCommandMap = null; 136 | _moduleDispatcher = null; 137 | _contextView = null; 138 | _injector = null; 139 | _reflector = null; 140 | _commandMap = null; 141 | _mediatorMap = null; 142 | _viewMap = null; 143 | _eventDispatcher = null; 144 | _applicationDomain = null; 145 | } 146 | } 147 | } --------------------------------------------------------------------------------