Mercurial > pub > ImplabNet
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) { }