Best practice for sharing mappings between contexts
Hi.
New to the forum. This may be more of a swift suspenders query. Please let me know if there is a better location for this question.
Im working on a modular app where the application shell defines a parent context that has mappings shared between modules and individual module contexts for local data. The module mediators need to have both values from the parent and local context injected into them. What is the standard practice / idiom for achieving this?
Thanks in advance for any advice or pointers to existing documentation on the subject,
Tod
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
Support Staff 1 Posted by Ondina D.F. on 01 Oct, 2013 05:47 PM
Hey Tod,
It's getting late here, where I live. I'll answer your question tomorrow, if you don't get any help until then.
Which version of robotlegs are you using, 1 or 2? There are different modular utilities for each version.
In case you didn't find them already, here are some links to modular examples:
rl1:
http://joelhooks.com/2010/05/02/modular-robotlegs/
http://knowledge.robotlegs.org/discussions/resources/33-links-to-ro... (look for modular)
rl2:
https://github.com/dotdotcommadot/ModularRL
https://github.com/Ondina/robotlegs-bender-modular-air (work in progress)
Till tomorrow,
Ondina
2 Posted by tod.antilla on 01 Oct, 2013 05:51 PM
Thanks Ondina,
I'm using RL2, I'll browse your links.
Update:
It looks the RL2 modularity extension primarily deals with event mapping, whereas I'm looking to share mappings in context injectors. Assuming I have access to the parent context while configuring a child context I would like to do something like :
childContext.injector.inheritFrom(parentContext.injector)
It appears I have to remap and inject items individually:
var api: IParentAPI = parentContext.injector.getInstance(IParentAPI);
childContext.injector.map(IParentAPI).toValue(api);
However I am having issues obtaining instances of parent context interfaces. It may have something to do with the application domain, but so far in other cases I have been able to avoid class definition conflicts if I create class references for all the shared classes in the parent application. I guess a work around would be creating strongly typed interfaces for the modules and manually setting parent instances there.
Support Staff 3 Posted by Ondina D.F. on 02 Oct, 2013 09:01 AM
First, let's take a look at the ModularityExtension's constructor:
If you use the MVCSBundle, the ModularityExtension will be installed with the default values: the context inherits from a parent context all the dependencies defined there, and will expose its own mappings to its children.
Now, let's create a ShellModel with a mapping like this one :
injector.map(ShellModel).asSingleton();
[1] ShellModel mapped only in the ShellContext
[2] ShellModel mapped in the ShellContext and in ModuleContext
We inject ShellModel into a Shell class and into a Module class.
[1]
The module will inherit the mappings from shell. If you change shellModel.someProperty inside a shell class before creating the module, module's ShellModel will reflect those changes.
[2]
The mappings inside of the ModuleContext will override shell's mappings. The Module will get its own instance of ShellModel.
Of course, you can map the model as an interface, which is btw. a recommended practice:
injector.map(ISomeModel).toSingleton(ShellModel);
and inject the interface wherever you need it, and it will work just the same.
If you need parent's injector, for some reason, you can access it like this:
injector.parent or context.injector.parent
Does that answer your question?
Ondina
4 Posted by tod.antilla on 02 Oct, 2013 01:30 PM
Im using the MVCS bundle, and I've tried explicitly instantiating the
ModularityExtension as well, but the child context is still throwing errors
that it doesn't have mappings that parent context has. However if I call
childContext.configure(ParentConfig) where ParentConfig has already been
configured in the parent context, ParentConfig.configure doesn't execute
which perhaps means ParentConfig is being managed by
the ModularityExtension. Are there any caveats to the creation of the child
context which might vary the behavior of the ModularityExtension? Ill build
from the RL source so I can put break points in and create a simpler test
example to see what I might be doing wrong.
Thanks,
Tod
Support Staff 5 Posted by Ondina D.F. on 02 Oct, 2013 01:39 PM
You shouldn't use ParentConfig in your Modules. Each context should have its own config with its own contextView.
Would it be possible for you to attach a simple app which reproduces the issues and where I can see your setup for the Shell and Modules' configs?
Or to paste all relevant code?
I can assure you, that, when the contexts are configured correctly, the mappings from the shell context will be inherited by the child contexts.
Support Staff 6 Posted by Ondina D.F. on 02 Oct, 2013 02:42 PM
I've attached an extremely simple example (AIR project) with 2 contexts, a parent and a child context. The ShellMainView adds SomeView, which is just a simple component and not a Flex Module.
ISomeModel is mapped inside Shell's context, and then injected into ShellMainMediator and SomeMediator.
You can play around with the mappings inside the parent's and child's context, to see what happens.
I injected ISomeModel into mediators, just to keep it simple!! As you probably know, injecting models into mediators is a disputed practice ;)
Hopefully, my example will help you.
7 Posted by tod.antilla on 02 Oct, 2013 05:21 PM
Thanks much Ondina for your prompt and detailed responses.
Working up from a smaller test app I found that some mappings that were not being inherited were manual injections in non view mediated objects - which makes sense ( a disputed practice :) I now have things running again but now that you've introduced me to the options of the ModularityExtension I'm considering a different approach.
Perhaps overriding the defaults to ensure the parent context is not inherited is a safer way of allowing flexible, reusable configuration across modules. When you mentioned that you shouldn't use ParentConfig in your Modules I understand the case for that, however one the great thing s about RL2 is creating custom bundles and configs that can be reused. We have rather large component libraries with complex configs that need to be shared by multiple modules. I'm hoping to achieve a drop in functionality by using local contexts in the following manner: localContext.install(CustomBundle); where CustomBundle might be initialized by more than one team member working on different modules and the runtime wont produce vigilance errors about duplicate mappings because the module context is isolated from the shared application context. I hope this a valid approach for sharing complex components across modules, I'm open to suggestions if there is a more canonical idiom.
Thanks again,
Tod
Support Staff 8 Posted by Ondina D.F. on 02 Oct, 2013 05:56 PM
You're welcome, Tod:)
It's late here (again), so I'll address your questions about a shared custom bundle tomorrow.
Have you seen the attached example?
9 Posted by tod.antilla on 02 Oct, 2013 06:30 PM
Yep, the attached example worked fine. Now Im expanding it to test
configuration options by installing components from other flex library
projects before deciding on the strategy for the existing apps going
forward. (a sprawling set of deprecated Flex 2.0 and cairngorm[ugh] libs
and applications that we are porting to RL2)
Support Staff 10 Posted by Ondina D.F. on 03 Oct, 2013 12:55 PM
I made another example this morning, based on the first one. There are 4 child-contexts: Alfa, Beta, Charlie, and Zulu, with different setups.
In the 'commons' folder there are 3 shared bundles/configs: sharedOne, sharedTwo and sharedThree. Btw, the names of all the folders and/or classes are not optimal, but without a concrete use case, it's difficult to find descriptive names. I hope that they aren't too confusing, though.
sharedOne contains a custom MVCS bundle, MVCSBundleOne, with a new ModularityExtension(true, false), that inherits dependencies from a parent context.
sharedTwo contains MVCSBundleTwo, with a new ModularityExtension(false, false), that does not inherit any dependencies from a parent context.
sharedThree contains MVCSBundleThree, with a new ModularityExtension(false, true), that does not inherit any dependencies from a parent context, but exposes dependencies to children.
RobotlegsContextOne uses MVCSBundleOne and RobotlegsContextTwo uses MVCSBundleTwo.
AlfaView uses its own AlfaRobotlegsContext, where it installs MVCSBundleOne and maps AlfaView to AlfaMediator in AlfaMediatorsConfig. It will inherit the mapping for ISomeModel from shell. In AlfaRobotlegsContext you can use the setting that are commented out instead of the ones I used, and you'll see what happens.
BetaView is similar to AlfaView. It uses the shared MVCSBundleOne.
CharlieView - CharlieRobotlegsContext uses MVCSBundleTwo, not inheriting from parent, and the shared ModelsConfig. But since there are no mappings for CharlieMediator, it won't be created, so the mapping of the Model is useless.
ZuluView with ZuluRobotlegsContext and an MVCSBundleThree, simply adds SomeView from the common folder (which could be extracted into a library as well). SomeView is instantiating its own context (RobotlegsContextOne or RobotlegsContextTwo)-see the comments in SomeView. Also, see what happens if you comment out the mapping inside ModelsConfig.
You can play around with the different settings until you get dizzy;)
Conclusion: it is possible to share a custom bundle and also configs classes for contexts with an identical setup. If a context needs some special or additional configuration, I'd prefer to let it have its own config classes, like Alfa and Beta.
11 Posted by tod.antilla on 04 Oct, 2013 02:43 PM
Well done! Thanks for combinatorially exhausting the rest of the non
default settings of the Modularity extension(nice color coding). With this
kind of flexibility I could see runtime composition of components similar
to what many entity system game frameworks use. Consider my mind and this
issue a' splode:) Now for some kind of FSM integration so modules can
receive and request generic state changes from the shell without being
tightly coupled to it.
Have a great weekend.
Support Staff 12 Posted by Ondina D.F. on 04 Oct, 2013 03:52 PM
Thanks!
I hope you'll be able to reclaim your mind soon and that your weekend will be great as well :)
Ondina D.F. closed this discussion on 04 Oct, 2013 03:52 PM.