tag:robotlegs.tenderapp.com,2009-10-18:/discussions/robotlegs-2/10314-chaining-startup-commandsservicesRobotlegs: Discussion 2014-04-28T08:13:33Ztag:robotlegs.tenderapp.com,2009-10-18:Comment/320445372014-03-12T10:09:39Z2014-03-12T10:09:39ZChaining Startup Commands/Services<div><p>Hi Valley,</p>
<blockquote>
<p>I don't think it's a good idea if every service knows about the
next step in the mentioned startup sequence</p>
</blockquote>
<p>You're right, services shouldn't have to know about the flow of
your loading process or the state of your app.</p>
<blockquote>
<p>The better way is in my opinion if every service just dispatches
a notify signal after finishing its work and with that it stays
independent and can also be used as a single service, if
needed.</p>
</blockquote>
<p>Exactly.</p>
<blockquote>
<p>How can the chaining of these ordered commands/services be
performed</p>
</blockquote>
<p>I'll give you a list of utilities/ extensions that may be of use
to you:</p>
<p><strong>DirectCommandMap</strong>:</p>
<p><a href=
"https://github.com/robotlegs/robotlegs-framework/tree/master/src/robotlegs/bender/extensions/directCommandMap">
https://github.com/robotlegs/robotlegs-framework/tree/master/src/ro...</a></p>
<p><strong>Macro command</strong> utility for Robotlegs 2 which
provides the ability to execute batches of commands in sequential
or parallel fashion:</p>
<p><a href=
"https://github.com/alebianco/robotlegs-utilities-macrobot">https://github.com/alebianco/robotlegs-utilities-macrobot</a></p>
<p><strong>AS3StateMachine</strong>:</p>
<p><a href=
"https://github.com/AS3StateMachine">https://github.com/AS3StateMachine</a></p>
<p><strong>DeferredCommandQueue</strong>:</p>
<p><a href=
"https://github.com/DavidWhittingham/robotlegs-utilities-DeferredCommandQueue">
https://github.com/DavidWhittingham/robotlegs-utilities-DeferredCom...</a><br>
<a href=
"https://github.com/DavidWhittingham/robotlegs-extensions-SignalStateMachine">
https://github.com/DavidWhittingham/robotlegs-extensions-SignalStat...</a></p>
<p><strong>SignalResponder</strong>:</p>
<p><a href=
"https://github.com/creynders/SignalResponder">https://github.com/creynders/SignalResponder</a><br>
<a href=
"https://github.com/creynders/RelaxedSignalsDemo">https://github.com/creynders/RelaxedSignalsDemo</a></p>
<p><strong>Bootstrap</strong>:</p>
<p><a href=
"https://github.com/creynders/robotlegs-demo-bootstrap">https://github.com/creynders/robotlegs-demo-bootstrap</a></p>
<p><strong>Promises</strong>:</p>
<p><a href=
"https://github.com/darscan/robotlegs-extensions-Oil">https://github.com/darscan/robotlegs-extensions-Oil</a></p>
<p><a href=
"http://knowledge.robotlegs.org/discussions/questions/115-using-the-asynccommand-with-services-callbacksdiscussion">
http://knowledge.robotlegs.org/discussions/questions/115-using-the-...</a><br>
There are more discussions on this topic on this forum. Search for
'Promises'.</p>
<p><a href=
"https://github.com/jonnyreeves/as3-async">https://github.com/jonnyreeves/as3-async</a></p>
<p><a href=
"https://github.com/CodeCatalyst/promise-as3">https://github.com/CodeCatalyst/promise-as3</a></p>
<p><a href=
"https://gist.github.com/darscan/4519372">https://gist.github.com/darscan/4519372</a></p>
<p>Ondina</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/320445372014-03-13T08:04:11Z2014-04-19T18:08:44ZChaining Startup Commands/Services<div><p>Great, thank you Ondina.<br>
I will have a look at the projects you mentioned.<br>
Hopefully there are some approaches which support chaining commands
AND<br>
the combination of a command which invokes a service...</p>
<p>valley</p></div>rivella50tag:robotlegs.tenderapp.com,2009-10-18:Comment/320445372014-03-14T12:46:43Z2014-03-14T12:46:43ZChaining Startup Commands/Services<div><p>Hey Valley,</p>
<p>Macrobot does exactly what you want, it allows creating command
chains. You can mix and match synced and async operations as you
please.</p>
<p>For more complex flows I'd definitely recommend a state
machine.</p></div>creynderstag:robotlegs.tenderapp.com,2009-10-18:Comment/320445372014-03-14T21:08:56Z2014-04-19T18:08:44ZChaining Startup Commands/Services<div><p>Hi creynders,</p>
<p>with RL2 and Macrobot i would use AsyncCommand's to perform
stuff like login at a remote server or download some data, and not
that the command invokes a service which does that work ? Or how
would that work properly, with a callback proxy ?</p>
<p>And do i understand it correctly that an AsyncCommand handles
the detain/release part transparently and i only need to implement
the listeners and the final complete dispatch signal ?</p>
<p>Thank you.<br>
valley</p></div>rivella50tag:robotlegs.tenderapp.com,2009-10-18:Comment/320445372014-03-15T07:14:55Z2014-03-15T07:14:55ZChaining Startup Commands/Services<div><p>No, the asynccomand calls the service and listens to its
completion. Then it dispatches its complete event.<br>
Something like this:</p>
<pre>
<code>public function execute():void{
service.addEventListener(ServiceEvent.FINISHED, finishedHandler);
service.doYourThing();
}
private function finishedHandler(result){
dispatchComplete(true);
}</code>
</pre>
<p>That's all there is to it really. Personally I use signals or
promises for messaging from services to commands and only use
events for system-wide messaging. But the service could also
dispatch a system event in which case you don't let the command
listen to the service directly but to the injected
eventDispatcher.</p></div>creynderstag:robotlegs.tenderapp.com,2009-10-18:Comment/320445372014-03-16T19:54:30Z2014-04-19T18:08:44ZChaining Startup Commands/Services<div><p>Works like a charm, thank you very much, creynders!<br>
I'm using the signal approach to let the command get notified about
the completed service.<br>
Since i mapped the service as follows i had to cast the interface
to the service class for getting access to the signal in the
command, but this should be no problem i guess:<br></p>
<pre>
<code>injector.map( IServiceCommandA ).toSingleton( ServiceCommandA );</code>
</pre>
and in the command:<br>
<pre>
<code>[Inject]
public var service:IServiceCommandA;
...
ServiceCommandA(service).finishedSignal.add(completeHandler);</code>
</pre></div>rivella50tag:robotlegs.tenderapp.com,2009-10-18:Comment/320445372014-03-16T21:38:09Z2014-03-16T21:38:09ZChaining Startup Commands/Services<div><p>I wouldn't upcast, but rather add a getter for the signal to the
iface.</p>
<p>On Sunday, March 16, 2014, valley <<br>
<a href=
"mailto:tender+d1f667e771e99f7cd6d91feccb313d96e917ce9e0@tenderapp.com">
tender+d1f667e771e99f7cd6d91feccb313d96e917ce9e0@tenderapp.com</a>>
wrote:</p></div>creynderstag:robotlegs.tenderapp.com,2009-10-18:Comment/320445372014-03-17T10:50:08Z2014-03-17T10:50:08ZChaining Startup Commands/Services<div><p>Hey Vallye,</p>
<p>I'll expand a little on why I wouldn't upcast. Upcasting is
always a bit fishy and a code smell (except in a few very rare
cases). The problem is that you couple the command tightly to the
concrete service class, which means that if you need to swap
service classes you'll need to update your command as well. On top
of that if the original service class remains in the code base and
you forgot to update the command, then this will not generate a
CTE, but only fails at run-time. Potentially pretty dangerous.</p>
<p>There's a few approaches you can take:</p>
<p>1/ Drop the interface and map the concrete service instead.
Least preferable.<br>
2/ Add a getter for the signal to the interface and concrete
service class.<br>
3/ Extend the original interface in a new interface which exposes a
getter to the signal and use this new interface instead.</p>
<p>I'd definitely go with 2/ in almost all cases. It's one of the
benefits of signals that you can add your messaging mechanism to
your interface. I'd only use 3 if I'm using an application-specific
wrapper for a more generic interface/class.</p></div>creynderstag:robotlegs.tenderapp.com,2009-10-18:Comment/320445372014-03-17T19:14:36Z2014-04-19T18:08:45ZChaining Startup Commands/Services<div><p>Ok, i think you are right, thank you for your thoughts.<br>
I will choose one of points 2) and 3) for my concrete app.</p>
<p>Regards<br>
valley</p></div>rivella50tag:robotlegs.tenderapp.com,2009-10-18:Comment/320445372014-03-25T21:35:17Z2014-04-19T18:08:45ZChaining Startup Commands/Services<div><p>Now i just ran into an error which i couldn't solve quickly.<br>
Let's say we have an authentication mechanism with a command and a
related service, where the command registers to be notified on the
service's complete action.<br>
Since the service is handled as a Singleton with<br></p>
<pre>
<code>injector.map( IAuthenticateUserService ).toSingleton( AuthenticateUserService );</code>
</pre>
the offered signal to the command stays there as well.<br>
Now if the command runs several times it registers again and again
as a listener for that complete signal and will be notified more
than once when the command is invoked several times:<br>
<pre>
<code>public class AuthenticateUserCommand extends AsyncCommand {
[Inject]
public var authenticateService:IAuthenticateUserService;
[Inject]
public var notifySignal:NotifyUserAuthenticatedSignal;
override public function execute():void {
authenticateService.doAuthenticate();
authenticateService.getNotifyCommandSignal().add(onCompleteService);
}
private function onCompleteService(statusVo:StatusVO):void {
notifySignal.dispatch(statusVo);
}
}</code>
</pre>
Therefore i'm removing now all listeners for the service signal in
function onCompleteService with:<br>
<pre>
<code>authenticateService.getNotifyCommandSignal().removeAll();</code>
</pre>
I'm not sure if this is the best way to do this, but now it works
fine.<br>
Another possibility could be not to use Singleton services but
services which will be instantiated again on every new run?</div>rivella50tag:robotlegs.tenderapp.com,2009-10-18:Comment/320445372014-03-26T06:38:39Z2014-03-26T06:38:39ZChaining Startup Commands/Services<div><p>Another approach would be to use addOnce:
authenticateService.<br>
getNotifyCommandSignal().addOnce(onCompleteService);</p></div>creynders