tag:robotlegs.tenderapp.com,2009-10-18:/discussions/problems/252-singelton-in-modular-applicationRobotlegs: Discussion 2012-09-06T15:00:45Ztag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-26T17:39:37Z2011-01-26T17:39:38ZSingelton in Modular Application<div><p>Im currently having the same issue... need a way to access a
class which is mapped in the injector, though from a class not part
of my mappings.</p>
<p>...well, a not too hacky way to it that is.</p></div>filipelimatag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-27T16:03:25Z2011-01-27T16:03:25ZSingelton in Modular Application<div><p>is it just not possible to share singleton classes between
modularized SWFs?</p></div>digitaldavenyctag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-27T16:44:06Z2011-01-27T16:44:06ZSingelton in Modular Application<div><p>Parent injector mappings are picked up by the child swf's
injector, so while sibling-to-sibling injection isn't provided for
'automagically', shell-to-child mappings are.</p>
<p>If you want to share a singleton between sibling swfs and it's
created in one of them, here's how I would go about it:</p>
<p>1) Have the module context that 'owns' the singleton map it
normal - eg:</p>
<pre>
<code>injector.mapSingletonOf(SomeInterface, SomeImplementation);</code>
</pre>
<p>2) Dispatch a custom event on the module shared event
dispatcher, passing the instance as the payload.</p>
<pre>
<code>var instanceToShare:SomeInterface = injector.getInstance(SomeInterface);
var instanceEvent:SomeInterfaceSupplyEvent = new SomeInterfaceSupplyEvent(INSTANCE_SUPPLIED, instanceToShare);
dispatchToModules(instanceEvent);</code>
</pre>
<p>3) In the modules that want to use this instance, wire a command
on the ModuleCommandMap to this event.</p>
<pre>
<code>moduleCommandMap.mapEvent(SomeInterfaceSupplyEvent.INSTANCE_SUPPLIED, ReceiveSomeInterfaceInstance);</code>
</pre>
<p>4) Pick up the event, and map the payload to the correct
interface in the recipient module using</p>
<pre>
<code>instanceReceived:SomeInterface = instanceEvent.instance;
injector.mapValue(SomeInterface, instanceReceived);</code>
</pre>
<p>Always do these mappings to interfaces and not concrete types to
avoid class collisions.</p>
<p>You may wish to suspend the recipient module from starting until
any of this has happened - you can change the event you wire your
bootstrap commands to.</p>
<p>You'll need to be mindful of race conditions. This needs to
happen in the order [1 and 3] then [2]. [4] will be triggered by
[2] provided [3] has happened first.</p>
<p>For that reason I would consider making it a request-response
event so there's an INSTANCE_REQUESTED that is sent by the module
that wants access to the singleton, and then step 2 is in a Command
which is bound to this event. In [1] you'd add something like:</p>
<pre>
<code>moduleCommandMap.mapEvent(SomeInterfaceSupplyEvent.INSTANCE_REQUESTED, SupplySomeInterfaceInstance);</code>
</pre>
<p>The code for [2] would sit in the SupplySomeInterfaceInstance
Command.</p>
<p>If that's not clear let me know.</p>
<p>**An alternative approach:</p>
<p>Unfortunately sibling-to-sibling mappings are very hard to
implement automagically because mapping from the child to the
parent has the potential to overwrite all sorts of stuff.</p>
<p>There's no direct access AFAIK from the module context to the
parent Injector.</p>
<p>However, you could potentially expose the parent injector from
the shell using a method on the shell API, and then you could pass
the injection to the shell to fulfil. There are a number of reasons
why I prefer not to do it that way, and personally I think the
request-response pattern is easier to follow and less likely to
cause the kinds of problems that end up taking five hours to work
out, but you might prefer a less verbose approach.</p>
<p>I like to keep my modules ignorant of the shell (actually,
they're ignorant of the fact that they're modules too), but that's
just a preference really.</p>
<p>Hope that helps,</p>
<p>Stray</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-27T16:53:12Z2011-01-27T16:53:12ZSingelton in Modular Application<div><p>Hmm...</p>
<p>It looks like get and set parentInjector are available in
SwiftSuspenders, but not in the IInjector - let me chase that up a
little further...</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-27T17:12:45Z2011-01-27T17:12:45ZSingelton in Modular Application<div><p>You can use the parentInjector by either casting to Injector, or
by<br>
adding a mapping in the startup sequence<br>
injector.mapValue(Injector, injector);<br>
and directly injecting as the concrete type:<br>
[Inject] public var ssInjector : Injector; // has to have a
different name so as not to collide with the base class's
"injector" var</p></div>Till Schneidereittag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-27T18:09:21Z2011-01-27T18:09:21ZSingelton in Modular Application<div><p>Excellent! Thanks for that Till.</p>
<p>For clarification - set / get parentInjector isn't included in
the robotlegs IInjector because for a long time we've been trying
to ensure that the actual injector was interchangeable, so you
could switch out the swift-suspenders injector for a different
one.</p>
<p>However, this might not be a policy we continue with. So watch
this space for RL 1.5 complete with access to the
parentInjector.</p>
<p>In the meantime, any of the 3 approaches suggested will
work.</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-27T21:15:24Z2011-01-27T21:15:24ZSingelton in Modular Application<div><p>Stray thanks for the detailed post. I'm not sure I understand
Till's approach, how would you get access to the proxy via that
way?</p></div>digitaldavenyctag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-27T21:41:44Z2011-01-27T21:41:44ZSingelton in Modular Application<div><p>Here's a little more expansion on what Till was saying:</p>
<p>In theory you can access the parent Injector (which the child
injectors in the modules look to for mappings if they don't have
their own) via the injector in your module.</p>
<p>However - for various reasons - the api functions for set and
getParentInjector on the Injector aren't included in the robotlegs
IInjector interface. So you would need to cast your injector to be
a swift suspenders Injector (which it is, but your injector is
typed to the robotlegs IInjector interface):</p>
<pre>
<code>var ssInjector:Injector = Injector(injector)</code>
</pre>
<p>then you could access the parent Injector:</p>
<pre>
<code>var parentInjector:Injector = ssInjector.getParentInjector();</code>
</pre>
<p>and now you can make your mapping in a way that all the other
modules can share it too</p>
<pre>
<code>parentInjector.mapSingletonOf(IThingClass, ThingClass);</code>
</pre>
<p>You still need to be careful of race conditions, but provided
you make sure that the other modules don't request this mapping (ie
you don't create any objects that have this singleton injected)
until after this code has run, you should find that the singleton
is available in all the modules.</p>
<p>I've found that it's useful to have every module make its
mappings and then declare itself 'ready'. A utility I use tracks
all those "ready" events and when every module is "ready" then it
dispatches an "Ok! Everybody's ready! Let's go!" event and then the
modules are bootstrapped into actually starting from there. I use
the same utility on shutdown - so every module has done any clean
up stuff before my app actually quits. (It's an AIR app).</p>
<p>Happy to share that code if it's useful to you (you might prefer
to roll your own).</p>
<p>Let me know if that's still not clear,</p>
<p>Stray</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-27T21:56:35Z2011-01-27T21:56:35ZSingelton in Modular Application<div><p>Ah OK now I see what Till was saying that does make sense. Yeah
I'd love to see an example of that code, I'm going to be writing a
lot of modular apps for the next few months. Thanks so much for the
help.</p></div>digitaldavenyctag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-28T13:47:54Z2011-01-28T13:47:54ZSingelton in Modular Application<div><p>Now that Stray has already explained what I meant (but didn't
explain<br>
myself, sorry for that), let just quickly add that a future version
of<br>
SwiftSuspenders will support live injections that get updated<br>
automatically when the mapped value changes. With that ability,
the<br>
required boiler-plate for enabling the described scenario
should<br>
hopefully get much smaller.</p></div>Till Schneidereittag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-28T16:10:32Z2011-01-28T16:10:32ZSingelton in Modular Application<div><p>that sounds like an amazing new feature for swift suspenders, I
can't wait for it!</p></div>digitaldavenyctag:robotlegs.tenderapp.com,2009-10-18:Comment/49609312011-01-28T16:14:49Z2011-01-28T16:14:49ZSingelton in Modular Application<div><p>Thanks! Unfortunately, you'll have to wait at least some time: I
don't<br>
think I'll be able to release 2.0 before late Spring or so.</p>
<p>But I'll at least publish a roadmap over the next few days. Not
that<br>
that would help you in any way at all ...</p></div>Till Schneidereit