comparison Implab/Components/RunnableComponent.cs @ 184:d6a8cba73acc ref20160224

working on runnable component
author cin
date Sat, 16 Apr 2016 03:23:26 +0300
parents c32688129f14
children 822aab37b107
comparison
equal deleted inserted replaced
183:4f82e0f161c3 184:d6a8cba73acc
1 using System; 1 using System;
2 using Implab.Formats; 2 using Implab.Formats;
3 3
4 namespace Implab.Components { 4 namespace Implab.Components {
5 public class RunnableComponent : Disposable, IRunnable, IInitializable { 5 public class RunnableComponent : Disposable, IRunnable, IInitializable {
6 6 enum Commands {
7 Ok = 0,
8 Fail,
9 Init,
10 Start,
11 Stop,
12 Dispose,
13 Last = Dispose
14 }
15
16 class StateMachine {
17 static readonly ExecutionState[,] _transitions;
18
19 static StateMachine() {
20 _transitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
21
22 Edge(ExecutionState.Created, ExecutionState.Ready, Commands.Ok);
23 Edge(ExecutionState.Created, ExecutionState.Failed, Commands.Fail);
24
25 Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start);
26 Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose);
27
28 Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok);
29 Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail);
30 Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop);
31 Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose);
32
33 Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail);
34 Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop);
35 Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose);
36
37 Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail);
38 Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok);
39 Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose);
40 }
41
42 static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
43 _transitions[(int)s1, (int)cmd] = s2;
44 }
45
46 public ExecutionState State {
47 get;
48 private set;
49 }
50
51 public StateMachine(ExecutionState initial) {
52 State = initial;
53 }
54
55 public bool Move(Commands cmd) {
56 var next = _transitions[(int)State, (int)cmd];
57 if (next == ExecutionState.Undefined)
58 return false;
59 State = next;
60 return true;
61 }
62 }
63
64 IPromise m_pending;
65 Exception m_lastError;
66
67 readonly StateMachine m_stateMachine;
68
69 protected RunnableComponent(bool initialized) {
70 m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created);
71 }
72
73 void ThrowInvalidCommand(Commands cmd) {
74 throw new InvalidOperationException(String.Format("Commnd {0} is not allowed in the state {1}", cmd, m_stateMachine.State));
75 }
76
77 protected void Move(Commands cmd) {
78 lock (m_stateMachine)
79 if (!m_stateMachine.Move(cmd))
80 ThrowInvalidCommand(cmd);
81 }
82
83 protected void Fail(Exception err) {
84 lock (m_stateMachine) {
85 if (!m_stateMachine.Move(Commands.Fail))
86 ThrowInvalidCommand(Commands.Fail);
87
88 m_lastError = err;
89 }
90 }
91
92 protected void Success() {
93 Move(Commands.Ok);
94 }
95
96 protected void Invoke(Commands cmd, Action action) {
97 Move(cmd);
98 try {
99 action();
100 Move(Commands.Ok);
101 } catch (Exception err) {
102 Fail(err);
103 throw;
104 }
105 }
106
107 protected IPromise InvokeAsync(Commands cmd, Func<IPromise> action) {
108 Move(cmd);
109 var medium = new Promise();
110
111 IPromise promise = null;
112
113 promise = medium.Then(
114 () => {
115 lock(m_stateMachine) {
116 if (m_pending == promise) {
117 m_pending = null;
118 Move(Commands.Ok);
119 }
120 }
121 }, e => {
122 if (m_pending == promise) {
123 m_pending = null;
124 Fail(
125 }
126 }
127 );
7 128
8 129
9 130
10 131 return Safe.InvokePromise(action).Then(
11 IPromise m_pending; 132 Success,
12 Exception m_lastError; 133 Fail
134 );
135 }
13 136
14 protected RunnableComponent(bool initialized) { 137 void AddPending(IPromise result) {
15 138
16 } 139 }
140
17 141
18 #region IInitializable implementation 142 #region IInitializable implementation
19 143
20 public void Init() { 144 public void Init() {
21 145 Invoke(Commands.Init, OnInitialize);
146 }
147
148 protected virtual void OnInitialize() {
22 } 149 }
23 150
24 #endregion 151 #endregion
25 152
26 #region IRunnable implementation 153 #region IRunnable implementation
27 154
28 public IPromise Start() { 155 public IPromise Start() {
29 throw new NotImplementedException(); 156 Move(Commands.Start);
157
158 return Safe.InvokePromise(OnStart).Then(
159 () => {
160 Move(Commands.Ok);
161 Run();
162 },
163 () => {
164 Move(Commands.Fail);
165 }
166 );
30 } 167 }
31 168
32 protected virtual IPromise OnStart() { 169 protected virtual IPromise OnStart() {
33 return Promise.SUCCESS; 170 return Promise.SUCCESS;
34 } 171 }