Modular Injection Mappings

Tyler's Avatar

Tyler

30 Jul, 2014 08:27 PM

Hello, I am building a multi-modular application using Robotlegs 1.4 and the modular utility.

I'm running into a problem where the suspenders are complaining that they don't have injection mappings for the core robotlegs components, like contextView, mediatorMap, etc....

I am passing in a parent injector and application domain into the context of every loaded module.

  1. Support Staff 1 Posted by Ondina D.F. on 31 Jul, 2014 07:51 AM

    Ondina D.F.'s Avatar

    Hello Tyler,

    If you're using FlashBuilder, these answers might help you:

    http://knowledge.robotlegs.org/discussions/problems/336-1070-contex...

    http://knowledge.robotlegs.org/discussions/problems/246-the-definit...

    Let me know whether that solved your problem or not.

    For your information, you can download the latest version of robotlegs 1, which is 1.5.2 from here:
    http://www.robotlegs.org/

    Ondina

  2. 2 Posted by Tyler on 31 Jul, 2014 12:08 PM

    Tyler's Avatar

    I've tried with Robotlegs 1.5.2, to no avail. It's not that it's missing the classes, it's that it tries to satisfy the "IMediatorMap" injection mapping and failing...

  3. 3 Posted by Tyler Padley on 31 Jul, 2014 12:14 PM

    Tyler Padley's Avatar

    Ondina,

    Thanks for the reply, but this is not my issue.

    Everything builds and runs fine, but when the child module is loaded it tries to satisfy the IMediatorMap injection mapping and says that it is missing that mapping. Sometimes it will say it’s missing the DisplayObjectContainer mapping.

    --

    Tyler Padley

    Solutions Architect | Leonardo<http://www.leonardo.com/>

    T 416-272-5495 | [email blocked]<mailto:[email blocked]>

    [http://www.leonardo.com/mkt/sig/2014/sig2014.jpg]<http://blog.leonardo.com/say-hello-to-leonardo/>

  4. Support Staff 4 Posted by Ondina D.F. on 31 Jul, 2014 01:47 PM

    Ondina D.F.'s Avatar

    I've attached Joel's demo, using rl 1.5.2. It works fine on my end. Try it out.

    Are you compiling against the source instead of the swc? If so, have a look at Metadata Stripping:
    https://github.com/robotlegs/robotlegs-framework/wiki/Common-Proble...
    Are you keeping a reference to your context?

    If you're compiling against the source, what version of Swiftsuspenders are you using? It might be the one, where IInjector is used instead of Injector?

    If you can't find the cause of your issues after reading the Common-Problems, the best thing to do is to attach a bare-bone project that reproduces your issues, and I'd take a look at it, later today.

  5. 5 Posted by Tyler on 31 Jul, 2014 02:02 PM

    Tyler's Avatar

    I have the 1.5.2 RL and the 1.5.1 swift suspenders, but I've also got the modular utility source, signal source and variant source since I couldn't find swcs for them.

    My context creation worked fine until I passed a separate application domain in, so it's not getting the application domain from ApplicationDomain.currentDomain anymore.

  6. Support Staff 6 Posted by Ondina D.F. on 31 Jul, 2014 02:17 PM

    Ondina D.F.'s Avatar

    Well, as I said, it would be easier for me to help you, if I could see the code:)
    You have lots of libraries there, that might not be compatible with each other ( because they are old?). If you can't attach you app or one that has all your libraries included, then try to use the modularity utility without the extra libraries in a very simple project and see how it goes. Is Joel's demo working for you?
    You might want to try Swiftsuspenders 1.6...
    If you want, I can make the discussion private, if you don't want others to see your code. I'll download the app, then delete it, and then make the discussion public again..

  7. 7 Posted by Tyler on 31 Jul, 2014 02:21 PM

    Tyler's Avatar

    I appreciate the help Ondina, but it's not a privacy thing, the app and framework that we have in place is massive in scope.

    Everything was working fine but we were running into memory issues so we decided to load the modules into child application domains. Once we realized we had to pass the child application domain into the module context creation because "getApplicationDomainFromContextView" wasn't working (there was no loaderInfo object since we are using ModuleManager.getModule() to load our modules.

    So that cleared up the application domain errors we were receiving, but now we get this error, in which it cannot satisfy an injection mapping for "contextView", in the first loaded module's Context. So the shell application context, in the main application domain, is still fine. This error occurs when the first module is loaded and that context is created with the child application domain passed to it.

  8. 8 Posted by Tyler on 31 Jul, 2014 02:22 PM

    Tyler's Avatar

    When I breakpoint in the context creation routine I can see the injector and all of its parent mappings, including DisplayObjectCOntainer and IMediatorMap, exist in the parentInjector mappings collection. It seems that putting a break point in makes it work, but running it in real time throws this error every time.

    Is there a race condition here?

  9. Support Staff 9 Posted by Ondina D.F. on 31 Jul, 2014 02:32 PM

    Ondina D.F.'s Avatar

    it's not a privacy thing, the app and framework that we have in place is massive in scope.

    It's alright, Tyler.

    I have to discontinue our discussion for now. I'll be back later...

  10. 10 Posted by Tyler on 31 Jul, 2014 02:35 PM

    Tyler's Avatar

    Ok, I'm trying the keep metadata and 1.6 suggestions, I'll let you know if they work.

  11. 11 Posted by Tyler on 31 Jul, 2014 05:56 PM

    Tyler's Avatar

    Ok, I'm almost to the point of pulling my hair out over here.... I grabbed the swift 1.5.1 source to get into the hooks and see what was happening. It's an intermittent race condition.

    It seems that it failing in the getResponse method as it fails to find the mapping in either the injector, or the m_injector, or the parent... even though in my traces out in the context injector creation indicates clearly that it does have the mapping... somehow that's not getting passed in... but only intermittently...

  12. Support Staff 12 Posted by Ondina D.F. on 31 Jul, 2014 06:53 PM

    Ondina D.F.'s Avatar

    Ok, I'm almost to the point of pulling my hair out over here..

    I'm sorry for you. It might be very frustrating. Taking a break may be helpful:)

    In the below linked discussion there is an example of a modular app that you can download (Ondina_ModularExperiment_taketwo.zip ).
    Don't forget to add the modules and to set the compiler options (metatdata...)
    You can use it to experiment with different settings in order to reproduce your issue:

    http://knowledge.robotlegs.org/discussions/questions/1361-loading-m...

    I suspect there is something wrong with your libraries and maybe with the way you're passing the applicationDomain, even though you said you solved that one.

    I won't be able to talk to you until tomorrow (it's 9 p.m. here where I live).
    I wish you luck.

  13. 13 Posted by Tyler on 31 Jul, 2014 06:56 PM

    Tyler's Avatar

    From what I'm seeing as I dig further, it's that an InjectionConfig is created with a "null" request object, and this is coming from the injector.getApplicationDomain().getDefinition() result.

    so there's something wrong with the definition.

  14. Support Staff 14 Posted by Ondina D.F. on 01 Aug, 2014 11:04 AM

    Ondina D.F.'s Avatar

    Hmm, it is really hard to know what's going on in your project without seeing at least some relevant code.
    The ApplicationDomain problem can occur under different circumstances, and it is impossible for me to mention all possible scenarios. There are several discussions on this topic on the forum. Not sure if you've seen them..

    A few things to consider (some of them were already mentioned before) :

    • simplify the use case - create your own mini-project or use the one I've uploaded

    • use the modularity utility + robotlegs + swiftsuspenders without any other libraries involved.

    • use a Swiftsuspender version that is compatible with the modularity utility. In my example I used the source code for rl and swiftsuspenders. I don't remember which versions they were, but they work well together. It's been quite a while since I worked with robotlegs v.1. Swiftsuspenders latest version is 2.1.0, but I have no idea if it is compatible with the modular utility and rl 1.5. I'm currently using robotlegs 2' ModularityExtension, which by the way is much easier to set up.

    • compiler arguments : -keep-as3-metadata+=Inject -keep-as3-metadata+=PostConstruct

    • add the modules to the project in your IDE

    • make sure the module / moduleLoader is added to the stage

    • modules should implement IModule or an interface of your own where you set the parent injector:

    s:Module
    implements="org.robotlegs.utilities.modular.core.IModule"
    
    • in the shell's context config:
    override public function startup():void
    {
       viewMap.mapType(IModule);
    }
    
    • the module's context implements IModuleContext: protected var context:IModuleContext;

    • use this setter to provide the module with an injector. This setter should initiate the context of the module via a ModuleContext that accepts the injector through its constructor. The ModuleContext will create a child injector:

    protected var context:IModuleContext;
    
    [Inject]
    public function set parentInjector(value:IInjector):void
    {
                    
        context = new SomeModuleContext(this, true, value, ApplicationDomain.currentDomain);            }
    
    • if you use an ApplicationDomain, other than the currentDomain, see if this workaround is solving your problem:
    public function SomeModuleContext(contextView:DisplayObjectContainer=null, autoStartup:Boolean=true, parentInjector:IInjector=null, applicationDomain:ApplicationDomain=null)
    {
        var applicationDomain : ApplicationDomain =
        (contextView["moduleFactory"] && contextView["moduleFactory"].info) ? 
        contextView["moduleFactory"].info().currentDomain :
        contextView.loaderInfo.applicationDomain;
    
        super(contextView, autoStartup, parentInjector, applicationDomain); 
    }
    
    • or find another way to inform the injector about the module's ApplicationDomain

    You said you used ModuleManager? Like this?

    moduleInfo = ModuleManager.getModule("yourPath/SomeModule.swf");
    moduleInfo.addEventListener(ModuleEvent.READY, onModuleReady);
    moduleInfo.addEventListener(ModuleEvent.ERROR, onModuleError);
    moduleInfo.load(ApplicationDomain.currentDomain, null, null, moduleFactory);
    

    What kind of errors do you get when you use ApplicationDomain.currentDomain for your modules? Could you paste the text of the error?

    It seems that putting a break point in makes it work, but running it in real time throws this error every time. Is there a race condition here?

    I have no idea what that could be. Which error are you referring to? Are there some asynchronous processes going on? Maybe it's not related to the modular utility at all?
    If you can't post some code (context initialization, moduleLoader settings, how you set the applicationDomain, etc ) or describe the workflow of loading your modules, I'm afraid that I can't really help you.
    Please let me know if you found a solution.

  15. 15 Posted by Tyler on 01 Aug, 2014 01:20 PM

    Tyler's Avatar

    Ondina,

    Thanks for all of your assistance with this.... we were using ModuleManager which meant that the loaderInfo object didn't exist. The errors being thrown by swift suspenders and RL were caused by the ApplicationDomain not having the definition, so there's certainly an issue with the ApplicationDomain settings, and we explored a few different options for loading modules into their own application domain to no avail.

    It seems that we can't really move forward on this without going to RL 2.0 and higher version of flex as these issues are largely framework related. Since the work involved to swap out our codebase to meet these two requirements is so high we've decided to delay that part as the codebase is already being partially converted to Angular regardless.

    Thanks again for your assistance,

    Tyler

  16. Support Staff 16 Posted by Ondina D.F. on 02 Aug, 2014 11:17 AM

    Ondina D.F.'s Avatar

    Hey Tyler,

    I'm sorry to hear that you're giving up already.

    I used my example to test the case of loading a module using ModuleManager. It works well.

    Here some code:

    private var moduleInfo:IModuleInfo;
    
    private function onLoadModule():void
    {
    moduleInfo = ModuleManager.getModule("modules/someModules/SomeModule.swf");
    moduleInfo.addEventListener(ModuleEvent.READY, onSomeModuleReady);
    
    moduleInfo.load(new ApplicationDomain(ApplicationDomain.currentDomain), null, null, moduleFactory);
    //or
    //moduleInfo.load(ApplicationDomain.currentDomain, null, null, moduleFactory);
    }
    
    • Option 1:

    Use ISomeModule to pass the applicationDomain to the Module's contextView.

    public interface ISomeModule
    {
        function set applicationDomain(value:ApplicationDomain):void;
            
        function set parentInjector(value:IInjector):void;
            
        function dispose():void;
    }
    

    In the Shell's context: viewMap.mapType(ISomeModule);

    In the view loading the module you set the applicationDomain using the interface:

    private function onSomeModuleReady(event:ModuleEvent):void
    {
        var iSomeModule:ISomeModule = moduleInfo.factory.create() as ISomeModule;
        iSomeModule.applicationDomain = moduleInfo.factory.info().currentDomain;                        
        modulesContainer.addElement(iSomeModule as IVisualElement);
    }
    

    SomeModule implements="interfaces.ISomeModule"

    private var context:IModuleContext;
    private var _applicationDomain:ApplicationDomain;
    
    [Inject]
    public function set parentInjector(value:IInjector):void
    {
        context = new SomeModuleContext( this, true, value, _applicationDomain);
    }
    
    public function set applicationDomain(value:ApplicationDomain):void
    {
        _applicationDomain = value;
    }
    
    public function dispose():void
    {
        context.dispose();
        context = null;
    }
    
    • Option 2: use moduleFactory to get loader's applicationDomain
    private function onSomeModuleReady(event:ModuleEvent):void
    {
        var module:IVisualElement = moduleInfo.factory.create() as IVisualElement;                      
        modulesContainer.addElement(module);
    }
    
    [Inject]
    public function set parentInjector(value:IInjector):void
    {
        context = new SomeModuleContext(this, true, value, this["moduleFactory"].info().currentDomain);
    }
    

    I used rl 1.5.2 swc and the source of modular utility. I'll attach them to this post.

    So, that shows that it is possible to set the ApplicationDomain even when ModuleManager is used instead of ModuleLoader. I wouldn't blame robotlegs as a framework for the issues you've encountered, but rather the combination of utilities or some special settings in your project. You've tried so many combinations of libraries already, so it is quite normal to get stuck, especially when the different versions aren't compatible with each other. It's a pity that there are no up-to-date libraries/utilities for robotlegs 1, but that's a fact and we have to live with it:) Many of rl-utilities authors or rl contributors aren't around anymore...

    So, I suggest you try one more time the combination of rl 1.5.2 swc and the source of the modular utility before giving up:) The ApplicationDomain is an issue that many others have encountered in the past, but it was and still is solvable.

    Migrating a project from rl1 to rl2 is pretty easy. Let me know if/when you need assistance with it. There are also some discussion on that topic.

    I'm sorry that I couldn't help you more.
    Anyway, I wish you luck with the Angular version of your app:)

    Ondina

    P.S. If you don't have any further questions, you can close the discussion

  17. Support Staff 17 Posted by Ondina D.F. on 09 Aug, 2014 08:22 AM

    Ondina D.F.'s Avatar

    I'm going to close this discussion. You can re-open it at any time, if need be.

  18. Ondina D.F. closed this discussion on 09 Aug, 2014 08:22 AM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac