diff Implab/Components/RunnableComponent.cs @ 244:eee3e49dd1ff v3

working on promises
author cin
date Thu, 25 Jan 2018 19:09:16 +0300
parents 5dc21f6a3222
children
line wrap: on
line diff
--- a/Implab/Components/RunnableComponent.cs	Wed Jan 24 19:24:10 2018 +0300
+++ b/Implab/Components/RunnableComponent.cs	Thu Jan 25 19:09:16 2018 +0300
@@ -1,6 +1,6 @@
 using System;
-using System.Diagnostics.CodeAnalysis;
-
+using System.Diagnostics.CodeAnalysis;
+
 namespace Implab.Components {
     public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable {
         enum Commands {
@@ -18,28 +18,28 @@
             public static readonly ExecutionState[,] ReusableTransitions;
             public static readonly ExecutionState[,] NonreusableTransitions;
 
-            class StateBuilder {
-                readonly ExecutionState[,] m_states;
-
-                public ExecutionState[,] States {
-                    get { return m_states; }
-                }
-                public StateBuilder(ExecutionState[,] states) {
-                    m_states = states;
-                }
-
-                public StateBuilder() {
-                    m_states = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
-                }
-
-                public StateBuilder Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
-                    m_states[(int)s1, (int)cmd] = s2;
-                    return this;
-                }
-
-                public StateBuilder Clone() {
-                    return new StateBuilder((ExecutionState[,])m_states.Clone());
-                }
+            class StateBuilder {
+                readonly ExecutionState[,] m_states;
+
+                public ExecutionState[,] States {
+                    get { return m_states; }
+                }
+                public StateBuilder(ExecutionState[,] states) {
+                    m_states = states;
+                }
+
+                public StateBuilder() {
+                    m_states = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
+                }
+
+                public StateBuilder Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
+                    m_states[(int)s1, (int)cmd] = s2;
+                    return this;
+                }
+
+                public StateBuilder Clone() {
+                    return new StateBuilder((ExecutionState[,])m_states.Clone());
+                }
             }
 
             static StateMachine() {
@@ -65,8 +65,8 @@
                     .Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose)
 
                     .Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose)
-                    .Edge(ExecutionState.Failed, ExecutionState.Initializing, Commands.Reset)
-
+                    .Edge(ExecutionState.Failed, ExecutionState.Initializing, Commands.Reset)
+
                     .Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail)
                     .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose)
 
@@ -74,11 +74,11 @@
 
                 var reusable = common
                     .Clone()
-                    .Edge(ExecutionState.Stopping, ExecutionState.Ready, Commands.Ok);
-
-                var nonreusable = common
-                    .Clone()
-                    .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok);
+                    .Edge(ExecutionState.Stopping, ExecutionState.Ready, Commands.Ok);
+
+                var nonreusable = common
+                    .Clone()
+                    .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok);
                 
                 NonreusableTransitions = nonreusable.States;
                 ReusableTransitions = reusable.States;
@@ -109,45 +109,45 @@
         IPromise m_pending;
         Exception m_lastError;
 
-        readonly StateMachine m_stateMachine;
-        readonly bool m_reusable;
-        public event EventHandler<StateChangeEventArgs> StateChanged;
-
-        /// <summary>
-        /// Initializes component state. 
-        /// </summary>
-        /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param>
-        /// <param name="reusable">If set, the component may start after it has been stopped, otherwise the component is disposed after being stopped.</param>
-        protected RunnableComponent(bool initialized, bool reusable) {
+        readonly StateMachine m_stateMachine;
+        readonly bool m_reusable;
+        public event EventHandler<StateChangeEventArgs> StateChanged;
+
+        /// <summary>
+        /// Initializes component state. 
+        /// </summary>
+        /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param>
+        /// <param name="reusable">If set, the component may start after it has been stopped, otherwise the component is disposed after being stopped.</param>
+        protected RunnableComponent(bool initialized, bool reusable) {
             m_stateMachine = new StateMachine(
                 reusable ? StateMachine.ReusableTransitions : StateMachine.NonreusableTransitions,
                 initialized ? ExecutionState.Ready : ExecutionState.Created
             );
             m_reusable = reusable;
-        }
-
-        /// <summary>
-        /// Initializes component state. The component created with this constructor is not reusable, i.e. it will be disposed after stop.
-        /// </summary>
-        /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param>
+        }
+
+        /// <summary>
+        /// Initializes component state. The component created with this constructor is not reusable, i.e. it will be disposed after stop.
+        /// </summary>
+        /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param>
         protected RunnableComponent(bool initialized) : this(initialized, false) {
         }
 
         void ThrowInvalidCommand(Commands cmd) {
             if (m_stateMachine.State == ExecutionState.Disposed)
-                throw new ObjectDisposedException(ToString());
-
+                throw new ObjectDisposedException(ToString());
+
             throw new InvalidOperationException(String.Format("Command {0} is not allowed in the state {1}", cmd, m_stateMachine.State));
         }
 
         bool MoveIfInState(Commands cmd, IPromise pending, Exception error, ExecutionState state) {
             ExecutionState prev, current;
-            lock (m_stateMachine) {
-                if (m_stateMachine.State != state)
-                    return false;
-
-                prev = m_stateMachine.State;
-                if (!m_stateMachine.Move(cmd))
+            lock (m_stateMachine) {
+                if (m_stateMachine.State != state)
+                    return false;
+
+                prev = m_stateMachine.State;
+                if (!m_stateMachine.Move(cmd))
                     ThrowInvalidCommand(cmd);
                 current = m_stateMachine.State;
 
@@ -161,46 +161,46 @@
 
         bool MoveIfPending(Commands cmd, IPromise pending, Exception error, IPromise expected) {
             ExecutionState prev, current;
-            lock (m_stateMachine) {
-                if (m_pending != expected)
-                    return false;
-                prev = m_stateMachine.State;
-                if (!m_stateMachine.Move(cmd))
+            lock (m_stateMachine) {
+                if (m_pending != expected)
+                    return false;
+                prev = m_stateMachine.State;
+                if (!m_stateMachine.Move(cmd))
                     ThrowInvalidCommand(cmd);
                 current = m_stateMachine.State;
                 m_pending = pending;
                 m_lastError = error;
-            }
+            }
             if (prev != current)
-                OnStateChanged(prev, current, error);
+                OnStateChanged(prev, current, error);
             return true;
         }
 
         IPromise Move(Commands cmd, IPromise pending, Exception error) {
             ExecutionState prev, current;
             IPromise ret;
-            lock (m_stateMachine) {
-                prev = m_stateMachine.State;
-                if (!m_stateMachine.Move(cmd))
+            lock (m_stateMachine) {
+                prev = m_stateMachine.State;
+                if (!m_stateMachine.Move(cmd))
                     ThrowInvalidCommand(cmd);
                 current = m_stateMachine.State;
 
                 ret = m_pending;
                 m_pending = pending;
-                m_lastError = error;
-
+                m_lastError = error;
+
             }
             if (prev != current)
                 OnStateChanged(prev, current, error);
             return ret;
         }
 
-        /// <summary>
-        /// Handles the state of the component change event, raises the <see cref="StateChanged"/>  event, handles
-        /// the transition to the <see cref="ExecutionState.Disposed"/> state (calls <see cref="Dispose(bool)"/> method).
-        /// </summary>
-        /// <param name="previous">The previous state</param>
-        /// <param name="current">The current state</param>
+        /// <summary>
+        /// Handles the state of the component change event, raises the <see cref="StateChanged"/>  event, handles
+        /// the transition to the <see cref="ExecutionState.Disposed"/> state (calls <see cref="Dispose(bool)"/> method).
+        /// </summary>
+        /// <param name="previous">The previous state</param>
+        /// <param name="current">The current state</param>
         /// <param name="error">The last error if any.</param>
         /// <remarks>
         /// <para>
@@ -212,31 +212,31 @@
         /// the wrong behavior of the component.
         /// </para>
         /// </remarks>
-        protected virtual void OnStateChanged(ExecutionState previous, ExecutionState current, Exception error) {
-            StateChanged.DispatchEvent(
-                this,
-                new StateChangeEventArgs {
-                    State = current,
-                    LastError = error
-                }
-            );
-            if (current == ExecutionState.Disposed) {
-                GC.SuppressFinalize(this);
-                Dispose(true);
-            }
+        protected virtual void OnStateChanged(ExecutionState previous, ExecutionState current, Exception error) {
+            StateChanged.DispatchEvent(
+                this,
+                new StateChangeEventArgs {
+                    State = current,
+                    LastError = error
+                }
+            );
+            if (current == ExecutionState.Disposed) {
+                GC.SuppressFinalize(this);
+                Dispose(true);
+            }
         }
 
         /// <summary>
         /// Moves the component from running to failed state.
         /// </summary>
         /// <param name="error">The exception which is describing the error.</param>
-        protected bool Fail(Exception error) {
-            return MoveIfInState(Commands.Fail, null, error, ExecutionState.Running);
+        protected bool Fail(Exception error) {
+            return MoveIfInState(Commands.Fail, null, error, ExecutionState.Running);
         }
 
-        /// <summary>
-        /// Tries to reset <see cref="ExecutionState.Failed"/> state to <see cref="ExecutionState.Ready"/>.
-        /// </summary>
+        /// <summary>
+        /// Tries to reset <see cref="ExecutionState.Failed"/> state to <see cref="ExecutionState.Ready"/>.
+        /// </summary>
         /// <returns>True if component is reset to <see cref="ExecutionState.Ready"/>, false if the componet wasn't
         /// in <see cref="ExecutionState.Failed"/> state.</returns>
         /// <remarks>
@@ -246,10 +246,10 @@
         /// to <see cref="ExecutionState.Ready"/> state, otherwise the component is moved to <see cref="ExecutionState.Failed"/>
         /// state. If <see cref="OnResetState()"/> throws an exception it will be propagated by this method to the caller.
         /// </remarks>
-        protected bool ResetState() {
-            if (!MoveIfInState(Commands.Reset, null, null, ExecutionState.Failed))
-                return false;
-
+        protected bool ResetState() {
+            if (!MoveIfInState(Commands.Reset, null, null, ExecutionState.Failed))
+                return false;
+
             try {
                 OnResetState();
                 Move(Commands.Ok, null, null);
@@ -257,38 +257,38 @@
             } catch (Exception err) {
                 Move(Commands.Fail, null, err);
                 throw;
-            }
+            }
         }
 
-        /// <summary>
-        /// This method is called by <see cref="ResetState"/> to reinitialize component in the failed state.
+        /// <summary>
+        /// This method is called by <see cref="ResetState"/> to reinitialize component in the failed state.
         /// </summary>
         /// <remarks>
         /// Default implementation throws <see cref="NotImplementedException"/> which will cause the component
         /// fail to reset it's state and it left in <see cref="ExecutionState.Failed"/> state.
         /// If this method doesn't throw exceptions the component is moved to <see cref="ExecutionState.Ready"/> state.
         /// </remarks>
-        protected virtual void OnResetState() {
-            throw new NotImplementedException();
+        protected virtual void OnResetState() {
+            throw new NotImplementedException();
         }
 
-        IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) {
+        IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IResolvable> chain) {
             IPromise promise = null;
             IPromise prev;
 
             var task = new ActionChainTask(action, null, null, true);
 
-            Action<Exception> errorOrCancel = e => {
-                if (e == null)
-                    e = new OperationCanceledException();
-                MoveIfPending(Commands.Fail, null, e, promise);
-                throw new PromiseTransientException(e);
+            Action<Exception> errorOrCancel = e => {
+                if (e == null)
+                    e = new OperationCanceledException();
+                MoveIfPending(Commands.Fail, null, e, promise);
+                throw new PromiseTransientException(e);
             };
 
             promise = task.Then(
                 () => MoveIfPending(Commands.Ok, null, null, promise),
                 errorOrCancel,
-                errorOrCancel
+                errorOrCancel
             );
 
             prev = Move(cmd, promise, null);
@@ -305,8 +305,8 @@
         #region IInitializable implementation
 
         public void Initialize() {
-            Move(Commands.Init, null, null);
-
+            Move(Commands.Init, null, null);
+
             try {
                 OnInitialize();
                 Move(Commands.Ok, null, null);
@@ -344,7 +344,7 @@
         /// </summary>
         /// <param name="current">Current.</param>
         /// <param name="stop">Stop.</param>
-        protected virtual void StopPending(IPromise current, IDeferred stop) {
+        protected virtual void StopPending(IPromise current, IResolvable stop) {
             if (current == null) {
                 stop.Resolve();
             } else {
@@ -398,11 +398,11 @@
 
         #endregion
 
-        /// <summary>
-        /// Releases all resources used by the component, called automatically, override this method to implement your cleanup.
-        /// </summary>
-        /// <param name="disposing">true if this method is called during normal dispose process.</param>
-        /// <param name="pending">The operation which is currenty pending</param>
+        /// <summary>
+        /// Releases all resources used by the component, called automatically, override this method to implement your cleanup.
+        /// </summary>
+        /// <param name="disposing">true if this method is called during normal dispose process.</param>
+        /// <param name="pending">The operation which is currenty pending</param>
         protected virtual void Dispose(bool disposing) {
         }