Permalink
Browse files

message dispatcher: makes halt-on-error optional (off by default) usi…

…ng bitflag param
  • Loading branch information...
1 parent 62a7046 commit 434842a98fd0544fe2870b1d11aa0232109135cd @darscan committed Apr 10, 2012
@@ -38,8 +38,8 @@ package robotlegs.bender.core.messaging
* Dispatches a message into the message flow.
* @param message The interesting message
* @param callback The completion callback function
- * @param reverse Reverse the dispatch order
+ * @param flags Bitflag
*/
- function dispatchMessage(message:Object, callback:Function = null, reverse:Boolean = false):void;
+ function dispatchMessage(message:Object, callback:Function = null, flags:uint = 0):void;
}
}
@@ -17,6 +17,14 @@ package robotlegs.bender.core.messaging
{
/*============================================================================*/
+ /* Public Static Properties */
+ /*============================================================================*/
+
+ public static const HALT_ON_ERROR:uint = 1;
+
+ public static const REVERSE:uint = 2;
+
+ /*============================================================================*/
/* Private Properties */
/*============================================================================*/
@@ -77,82 +85,17 @@ package robotlegs.bender.core.messaging
/**
* @inheritDoc
*/
- public function dispatchMessage(message:Object, callback:Function = null, reverse:Boolean = false):void
+ public function dispatchMessage(message:Object, callback:Function = null, flags:uint = 0):void
{
- if (_handlers[message])
+ const handlers:Array = _handlers[message];
+ if (handlers)
{
- // note: list is cloned and reversed because elements are popped
- const handlers:Array = _handlers[message].concat();
- reverse || handlers.reverse();
- next(message, handlers, callback);
+ new MessageRunner(message, handlers, callback, flags).run();
}
else
{
callback && safelyCallBack(callback);
}
}
-
- /*============================================================================*/
- /* Private Functions */
- /*============================================================================*/
-
- /**
- * Helper method to dispatch to a handler in one of the 3 handler forms:
- *
- * (), (message), (message, callback)
- *
- * @param message The message being dispatched
- * @param handlers The list of handlers that need to be called
- * @param callback The eventual callback
- */
- private function next(message:Object, handlers:Array, callback:Function):void
- {
- // Try to keep things synchronous with a simple loop,
- // forcefully breaking out for async handlers and recursing.
- // We do this to avoid increasing the stack depth unnecessarily.
- var handler:Function;
- while (handler = handlers.pop())
- {
- if (handler.length == 0) // sync handler: ()
- {
- handler();
- }
- else if (handler.length == 1) // sync handler: (message)
- {
- handler(message);
- }
- else if (handler.length == 2) // sync or async handler: (message, callback)
- {
- var handled:Boolean;
- handler(message, function(error:Object = null, msg:Object = null):void
- {
- // handler must not invoke the callback more than once
- if (handled)
- return;
-
- handled = true;
-
- if (error || handlers.length == 0)
- {
- callback && safelyCallBack(callback, error, message);
- }
- else
- {
- next(message, handlers, callback);
- }
- });
- // IMPORTANT: MUST break this loop with a RETURN. See above.
- return;
- }
- else // ERROR: this should NEVER happen
- {
- throw new Error("Bad handler signature");
- }
- }
- // If we got here then this loop finished synchronously.
- // Nobody broke out, so we are done.
- // This relies on the various return statements above. Be careful.
- callback && safelyCallBack(callback, null, message);
- }
}
}
@@ -0,0 +1,111 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2011 the original author or authors. All Rights Reserved.
+//
+// NOTICE: You are permitted to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//------------------------------------------------------------------------------
+
+package robotlegs.bender.core.messaging
+{
+ import robotlegs.bender.core.async.safelyCallBack;
+
+ public class MessageRunner
+ {
+
+ /*============================================================================*/
+ /* Private Properties */
+ /*============================================================================*/
+
+ private var _message:Object;
+
+ private var _handlers:Array;
+
+ private var _callback:Function;
+
+ private var _halt:Boolean;
+
+ private var _errors:Array;
+
+ /*============================================================================*/
+ /* Constructor */
+ /*============================================================================*/
+
+ public function MessageRunner(message:Object, handlers:Array, callback:Function, flags:uint)
+ {
+ _message = message;
+ _handlers = handlers.concat();
+ _callback = callback;
+ _halt = Boolean(flags & MessageDispatcher.HALT_ON_ERROR);
+ const reverse:Boolean = Boolean(flags & MessageDispatcher.REVERSE);
+ reverse || _handlers.reverse();
+ }
+
+ /*============================================================================*/
+ /* Public Functions */
+ /*============================================================================*/
+
+ public function run():void
+ {
+ next();
+ }
+
+ /*============================================================================*/
+ /* Private Functions */
+ /*============================================================================*/
+
+ private function next():void
+ {
+ // Try to keep things synchronous with a simple loop,
+ // forcefully breaking out for async handlers and recursing.
+ // We do this to avoid increasing the stack depth unnecessarily.
+ var handler:Function;
+ while (handler = _handlers.pop())
+ {
+ if (handler.length == 0) // sync handler: ()
+ {
+ handler();
+ }
+ else if (handler.length == 1) // sync handler: (message)
+ {
+ handler(_message);
+ }
+ else if (handler.length == 2) // sync or async handler: (message, callback)
+ {
+ var handled:Boolean;
+ handler(_message, function(error:Object = null, msg:Object = null):void
+ {
+ // handler must not invoke the callback more than once
+ if (handled)
+ return;
+
+ handled = true;
+ if (error && !_halt)
+ {
+ _errors ||= [];
+ _errors.push(error);
+ error = null;
+ }
+ if (error || _handlers.length == 0)
+ {
+ _callback && safelyCallBack(_callback, error || _errors, _message);
+ }
+ else
+ {
+ next();
+ }
+ });
+ // IMPORTANT: MUST break this loop with a RETURN. See top.
+ return;
+ }
+ else // ERROR: this should NEVER happen
+ {
+ throw new Error("Bad handler signature");
+ }
+ }
+ // If we got here then this loop finished synchronously.
+ // Nobody broke out, so we are done.
+ // This relies on the various return statements above. Be careful.
+ _callback && safelyCallBack(_callback, null, _message);
+ }
+ }
+}
@@ -74,7 +74,7 @@ package robotlegs.bender.core.objectProcessor.impl
_messageDispatcher.removeMessageHandler(object, matchingHandler.closure);
}
callback && safelyCallBack(callback, error, object);
- });
+ }, MessageDispatcher.HALT_ON_ERROR);
}
/**
@@ -144,10 +144,12 @@ package robotlegs.bender.core.stateMachine.impl
// todo: can optimise by checking if any of the steps have handlers
const definition:StateDefinition = getState(state);
-
+ const flags:uint = definition.reverseNotify
+ ? MessageDispatcher.REVERSE | MessageDispatcher.HALT_ON_ERROR
+ : MessageDispatcher.HALT_ON_ERROR;
next(
definition.steps.reverse(),
- definition.reverseNotify,
+ flags,
function(error:Object = null):void {
_stateChanging = false;
callback && safelyCallBack(callback, error);
@@ -174,10 +176,10 @@ package robotlegs.bender.core.stateMachine.impl
* Possibly recursive step runner
*
* @param steps The remaining steps to notify
- * @param reverseDispatch Reverse notification order
+ * @param flags MessageDispatcher flags
* @param callback The eventual callback
*/
- private function next(steps:Array, reverseDispatch:Boolean, callback:Function):void
+ private function next(steps:Array, flags:uint, callback:Function):void
{
// Try to keep things synchronous with a simple loop,
// forcefully breaking out for async handlers and recursing.
@@ -196,9 +198,9 @@ package robotlegs.bender.core.stateMachine.impl
}
else
{
- next(steps, reverseDispatch, callback);
+ next(steps, flags, callback);
}
- }, reverseDispatch);
+ }, flags);
// IMPORTANT: MUST break this loop with a RETURN. See above.
return;
}
Oops, something went wrong.

0 comments on commit 434842a

Please sign in to comment.