Mercurial > pub > ImplabNet
annotate Implab/Components/RunnableComponent.cs @ 208:7d07503621fe v2
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
IRunnable is now disposable
Code cleanups, suppressed some CodeAnalysis warnings
| author | cin | 
|---|---|
| date | Sun, 13 Nov 2016 18:28:17 +0300 | 
| parents | 8200ab154c8a | 
| children | 5dc21f6a3222 | 
| rev | line source | 
|---|---|
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 1 using System; | 
| 208 
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
 cin parents: 
205diff
changeset | 2 using System.Diagnostics.CodeAnalysis; | 
| 
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
 cin parents: 
205diff
changeset | 3 | 
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 4 namespace Implab.Components { | 
| 185 | 5 public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable { | 
| 184 | 6 enum Commands { | 
| 7 Ok = 0, | |
| 8 Fail, | |
| 9 Init, | |
| 10 Start, | |
| 11 Stop, | |
| 12 Dispose, | |
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 13 Reset, | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 14 Last = Reset | 
| 184 | 15 } | 
| 16 | |
| 17 class StateMachine { | |
| 18 static readonly ExecutionState[,] _transitions; | |
| 19 | |
| 20 static StateMachine() { | |
| 21 _transitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1]; | |
| 22 | |
| 185 | 23 Edge(ExecutionState.Created, ExecutionState.Initializing, Commands.Init); | 
| 24 Edge(ExecutionState.Created, ExecutionState.Disposed, Commands.Dispose); | |
| 25 | |
| 26 Edge(ExecutionState.Initializing, ExecutionState.Ready, Commands.Ok); | |
| 27 Edge(ExecutionState.Initializing, ExecutionState.Failed, Commands.Fail); | |
| 184 | 28 | 
| 29 Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start); | |
| 30 Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose); | |
| 31 | |
| 32 Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok); | |
| 33 Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail); | |
| 34 Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop); | |
| 35 Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose); | |
| 36 | |
| 37 Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail); | |
| 38 Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop); | |
| 39 Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose); | |
| 40 | |
| 41 Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail); | |
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 42 Edge(ExecutionState.Stopping, ExecutionState.Ready, Commands.Ok); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 43 Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose); | 
| 185 | 44 | 
| 45 Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose); | |
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 46 Edge(ExecutionState.Failed, ExecutionState.Initializing, Commands.Reset); | 
| 184 | 47 } | 
| 48 | |
| 49 static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) { | |
| 50 _transitions[(int)s1, (int)cmd] = s2; | |
| 51 } | |
| 52 | |
| 53 public ExecutionState State { | |
| 54 get; | |
| 55 private set; | |
| 56 } | |
| 57 | |
| 58 public StateMachine(ExecutionState initial) { | |
| 59 State = initial; | |
| 60 } | |
| 61 | |
| 62 public bool Move(Commands cmd) { | |
| 63 var next = _transitions[(int)State, (int)cmd]; | |
| 64 if (next == ExecutionState.Undefined) | |
| 65 return false; | |
| 66 State = next; | |
| 67 return true; | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 IPromise m_pending; | |
| 72 Exception m_lastError; | |
| 73 | |
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 74 readonly StateMachine m_stateMachine; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 75 readonly bool m_reusable; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 76 public event EventHandler<StateChangeEventArgs> StateChanged; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 77 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 78 /// <summary> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 79 /// Initializes component state. | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 80 /// </summary> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 81 /// <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> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 82 /// <param name="reusable">If set, the component may start after it has been stopped, otherwise the component is disposed after being stopped.</param> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 83 protected RunnableComponent(bool initialized, bool reusable) { | 
| 184 | 84 m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created); | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 85 m_reusable = reusable; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 86 DisposeTimeout = 10000; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 87 } | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 88 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 89 /// <summary> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 90 /// Initializes component state. The component created with this constructor is not reusable, i.e. it will be disposed after stop. | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 91 /// </summary> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 92 /// <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> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 93 protected RunnableComponent(bool initialized) : this(initialized, false) { | 
| 184 | 94 } | 
| 95 | |
| 203 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 96 /// <summary> | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 97 /// Gets or sets the timeout to wait for the pending operation to complete. If the pending operation doesn't finish than the component will be disposed anyway. | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 98 /// </summary> | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 99 protected int DisposeTimeout { | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 100 get; | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 101 set; | 
| 185 | 102 } | 
| 103 | |
| 184 | 104 void ThrowInvalidCommand(Commands cmd) { | 
| 185 | 105 if (m_stateMachine.State == ExecutionState.Disposed) | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 106 throw new ObjectDisposedException(ToString()); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 107 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 108 throw new InvalidOperationException(String.Format("Command {0} is not allowed in the state {1}", cmd, m_stateMachine.State)); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 109 } | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 110 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 111 bool MoveIfInState(Commands cmd, IPromise pending, Exception error, ExecutionState state) { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 112 ExecutionState prev, current; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 113 lock (m_stateMachine) { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 114 if (m_stateMachine.State != state) | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 115 return false; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 116 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 117 prev = m_stateMachine.State; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 118 if (!m_stateMachine.Move(cmd)) | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 119 ThrowInvalidCommand(cmd); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 120 current = m_stateMachine.State; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 121 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 122 m_pending = pending; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 123 m_lastError = error; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 124 } | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 125 if (prev != current) | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 126 OnStateChanged(prev, current, error); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 127 return true; | 
| 184 | 128 } | 
| 129 | |
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 130 bool MoveIfPending(Commands cmd, IPromise pending, Exception error, IPromise expected) { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 131 ExecutionState prev, current; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 132 lock (m_stateMachine) { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 133 if (m_pending != expected) | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 134 return false; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 135 prev = m_stateMachine.State; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 136 if (!m_stateMachine.Move(cmd)) | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 137 ThrowInvalidCommand(cmd); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 138 current = m_stateMachine.State; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 139 m_pending = pending; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 140 m_lastError = error; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 141 } | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 142 if (prev != current) | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 143 OnStateChanged(prev, current, error); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 144 return true; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 145 } | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 146 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 147 IPromise Move(Commands cmd, IPromise pending, Exception error) { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 148 ExecutionState prev, current; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 149 IPromise ret; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 150 lock (m_stateMachine) { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 151 prev = m_stateMachine.State; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 152 if (!m_stateMachine.Move(cmd)) | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 153 ThrowInvalidCommand(cmd); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 154 current = m_stateMachine.State; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 155 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 156 ret = m_pending; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 157 m_pending = pending; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 158 m_lastError = error; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 159 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 160 } | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 161 if(prev != current) | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 162 OnStateChanged(prev, current, error); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 163 return ret; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 164 } | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 165 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 166 protected virtual void OnStateChanged(ExecutionState previous, ExecutionState current, Exception error) { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 167 var h = StateChanged; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 168 if (h != null) | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 169 h(this, new StateChangeEventArgs { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 170 State = current, | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 171 LastError = error | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 172 }); | 
| 184 | 173 } | 
| 174 | |
| 203 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 175 /// <summary> | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 176 /// Moves the component from running to failed state. | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 177 /// </summary> | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 178 /// <param name="error">The exception which is describing the error.</param> | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 179 protected bool Fail(Exception error) { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 180 return MoveIfInState(Commands.Fail, null, error, ExecutionState.Running); | 
| 203 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 181 } | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 182 | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 183 /// <summary> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 184 /// Tries to reset <see cref="ExecutionState.Failed"/> state to <see cref="ExecutionState.Ready"/>. | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 185 /// </summary> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 186 /// <returns>True if component is reset to <see cref="ExecutionState.Ready"/>, false if the componet wasn't | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 187 /// in <see cref="ExecutionState.Failed"/> state.</returns> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 188 /// <remarks> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 189 /// This method checks the current state of the component and if it's in <see cref="ExecutionState.Failed"/> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 190 /// moves component to <see cref="ExecutionState.Initializing"/>. | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 191 /// The <see cref="OnResetState()"/> is called and if this method completes succesfully the component moved | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 192 /// to <see cref="ExecutionState.Ready"/> state, otherwise the component is moved to <see cref="ExecutionState.Failed"/> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 193 /// state. If <see cref="OnResetState()"/> throws an exception it will be propagated by this method to the caller. | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 194 /// </remarks> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 195 protected bool ResetState() { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 196 if (!MoveIfInState(Commands.Reset, null, null, ExecutionState.Failed)) | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 197 return false; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 198 | 
| 184 | 199 try { | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 200 OnResetState(); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 201 Move(Commands.Ok, null, null); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 202 return true; | 
| 184 | 203 } catch (Exception err) { | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 204 Move(Commands.Fail, null, err); | 
| 184 | 205 throw; | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 206 } | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 207 } | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 208 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 209 /// <summary> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 210 /// This method is called by <see cref="ResetState"/> to reinitialize component in the failed state. | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 211 /// </summary> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 212 /// <remarks> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 213 /// Default implementation throws <see cref="NotImplementedException"/> which will cause the component | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 214 /// fail to reset it's state and it left in <see cref="ExecutionState.Failed"/> state. | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 215 /// If this method doesn't throw exceptions the component is moved to <see cref="ExecutionState.Ready"/> state. | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 216 /// </remarks> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 217 protected virtual void OnResetState() { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 218 throw new NotImplementedException(); | 
| 184 | 219 } | 
| 220 | |
| 185 | 221 IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) { | 
| 222 IPromise promise = null; | |
| 223 IPromise prev; | |
| 184 | 224 | 
| 185 | 225 var task = new ActionChainTask(action, null, null, true); | 
| 226 | |
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 227 Action<Exception> errorOrCancel = e => { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 228 if (e == null) | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 229 e = new OperationCanceledException(); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 230 MoveIfPending(Commands.Fail, null, e, promise); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 231 throw new PromiseTransientException(e); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 232 }; | 
| 184 | 233 | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 234 promise = task.Then( | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 235 () => MoveIfPending(Commands.Ok, null, null, promise), | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 236 errorOrCancel, | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 237 errorOrCancel | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 238 ); | 
| 196 
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
 cin parents: 
187diff
changeset | 239 | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 240 prev = Move(cmd, promise, null); | 
| 157 | 241 | 
| 185 | 242 if (prev == null) | 
| 243 task.Resolve(); | |
| 244 else | |
| 245 chain(prev, task); | |
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 246 | 
| 185 | 247 return promise; | 
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 248 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 249 | 
| 184 | 250 | 
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 251 #region IInitializable implementation | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 252 | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 253 public void Initialize() { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 254 Move(Commands.Init, null, null); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 255 | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 256 try { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 257 OnInitialize(); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 258 Move(Commands.Ok, null, null); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 259 } catch (Exception err) { | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 260 Move(Commands.Fail, null, err); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 261 throw; | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 262 } | 
| 184 | 263 } | 
| 264 | |
| 265 protected virtual void OnInitialize() { | |
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 266 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 267 | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 268 #endregion | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 269 | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 270 #region IRunnable implementation | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 271 | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 272 public IPromise Start() { | 
| 185 | 273 return InvokeAsync(Commands.Start, OnStart, null); | 
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 274 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 275 | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 276 protected virtual IPromise OnStart() { | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 277 return Promise.Success; | 
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 278 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 279 | 
| 185 | 280 public IPromise Stop() { | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 281 var pending = InvokeAsync(Commands.Stop, OnStop, StopPending); | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 282 return m_reusable ? pending : pending.Then(Dispose); | 
| 185 | 283 } | 
| 284 | |
| 285 protected virtual IPromise OnStop() { | |
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 286 return Promise.Success; | 
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 287 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 288 | 
| 185 | 289 /// <summary> | 
| 290 /// Stops the current operation if one exists. | |
| 291 /// </summary> | |
| 292 /// <param name="current">Current.</param> | |
| 293 /// <param name="stop">Stop.</param> | |
| 294 protected virtual void StopPending(IPromise current, IDeferred stop) { | |
| 295 if (current == null) { | |
| 296 stop.Resolve(); | |
| 297 } else { | |
| 187 
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
 cin parents: 
186diff
changeset | 298 // связваем текущую операцию с операцией остановки | 
| 
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
 cin parents: 
186diff
changeset | 299 current.On( | 
| 
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
 cin parents: 
186diff
changeset | 300 stop.Resolve, // если текущая операция заверщилась, то можно начинать остановку | 
| 
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
 cin parents: 
186diff
changeset | 301 stop.Reject, // если текущая операция дала ошибку - то все плохо, нельзя продолжать | 
| 
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
 cin parents: 
186diff
changeset | 302 e => stop.Resolve() // если текущая отменилась, то можно начинать остановку | 
| 
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
 cin parents: 
186diff
changeset | 303 ); | 
| 
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
 cin parents: 
186diff
changeset | 304 // посылаем текущей операции сигнал остановки | 
| 185 | 305 current.Cancel(); | 
| 306 } | |
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 307 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 308 | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 309 public ExecutionState State { | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 310 get { | 
| 203 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 311 return m_stateMachine.State; | 
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 312 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 313 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 314 | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 315 public Exception LastError { | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 316 get { | 
| 185 | 317 return m_lastError; | 
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 318 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 319 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 320 | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 321 #endregion | 
| 185 | 322 | 
| 323 #region IDisposable implementation | |
| 324 | |
| 203 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 325 /// <summary> | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 326 /// Releases all resource used by the <see cref="Implab.Components.RunnableComponent"/> object. | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 327 /// </summary> | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 328 /// <remarks> | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 329 /// <para>Will not try to stop the component, it will just release all resources. | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 330 /// To cleanup the component gracefully use <see cref="Stop()"/> method.</para> | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 331 /// <para> | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 332 /// In normal cases the <see cref="Dispose()"/> method shouldn't be called, the call to the <see cref="Stop()"/> | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 333 /// method is sufficient to cleanup the component. Call <see cref="Dispose()"/> only to cleanup after errors, | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 334 /// especially if <see cref="Stop"/> method is failed. Using this method insted of <see cref="Stop()"/> may | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 335 /// lead to the data loss by the component. | 
| 
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
 cin parents: 
202diff
changeset | 336 /// </para></remarks> | 
| 208 
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
 cin parents: 
205diff
changeset | 337 [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Dipose(bool) and GC.SuppessFinalize are called")] | 
| 185 | 338 public void Dispose() { | 
| 339 IPromise pending; | |
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 340 | 
| 185 | 341 lock (m_stateMachine) { | 
| 342 if (m_stateMachine.State == ExecutionState.Disposed) | |
| 343 return; | |
| 208 
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
 cin parents: 
205diff
changeset | 344 Move(Commands.Dispose, null, null); | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 345 } | 
| 185 | 346 | 
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 347 GC.SuppressFinalize(this); | 
| 208 
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
 cin parents: 
205diff
changeset | 348 Dispose(true); | 
| 185 | 349 } | 
| 350 | |
| 351 ~RunnableComponent() { | |
| 208 
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
 cin parents: 
205diff
changeset | 352 Dispose(false); | 
| 185 | 353 } | 
| 354 | |
| 355 #endregion | |
| 356 | |
| 205 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 357 /// <summary> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 358 /// Releases all resources used by the component, called automatically, override this method to implement your cleanup. | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 359 /// </summary> | 
| 
8200ab154c8a
Added ResetState to RunnableComponent to reset in case of failure
 cin parents: 
203diff
changeset | 360 /// <param name="disposing">true if this method is called during normal dispose process.</param> | 
| 208 
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
 cin parents: 
205diff
changeset | 361 /// <param name="pending">The operation which is currenty pending</param> | 
| 
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
 cin parents: 
205diff
changeset | 362 protected virtual void Dispose(bool disposing) { | 
| 185 | 363 | 
| 364 } | |
| 365 | |
| 156 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 366 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 367 } | 
| 
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
 cin parents: diff
changeset | 368 | 
