##// END OF EJS Templates
working on runnable component
cin -
r184:d6a8cba73acc ref20160224
parent child
Show More
@@ -10,7 +10,7 namespace Implab.Format.Test {
10 10 public void TestScannerValidTokens() {
11 11 using (var scanner = new JSONScanner(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
12 12
13 Tuple<JsonTokenType,object>[] expexted = new [] {
13 Tuple<JsonTokenType,object>[] expexted = {
14 14 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
15 15 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
16 16 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
@@ -1,14 +1,24
1 1 namespace Implab.Components {
2 2
3 3 public enum ExecutionState {
4 Reserved = 0,
5 Uninitialized,
4 Undefined = 0,
5
6 Created,
7
8 Initializing,
9
6 10 Ready,
11
7 12 Starting,
13
8 14 Running,
15
9 16 Stopping,
10 Stopped,
17
18 Failed,
19
11 20 Disposed,
12 Failed
21
22 Last = Disposed
13 23 }
14 24 } No newline at end of file
@@ -11,7 +11,7 namespace Implab.Components {
11 11 /// Completes initialization.
12 12 /// </summary>
13 13 /// <remarks>
14 /// Normally virtual shouldn't be called from the constructor, due to the incomplete object state, but
14 /// Normally virtual methods shouldn't be called from the constructor, due to the incomplete object state, but
15 15 /// they can be called from this method. This method is also usefull when we constructing a complex grpah
16 16 /// of components where cyclic references may take place.
17 17 /// </remarks>
@@ -3,22 +3,149 using Implab.Formats;
3 3
4 4 namespace Implab.Components {
5 5 public class RunnableComponent : Disposable, IRunnable, IInitializable {
6 enum Commands {
7 Ok = 0,
8 Fail,
9 Init,
10 Start,
11 Stop,
12 Dispose,
13 Last = Dispose
14 }
6 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);
7 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);
8 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 }
9 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 }
10 63
11 64 IPromise m_pending;
12 65 Exception m_lastError;
13 66
67 readonly StateMachine m_stateMachine;
68
14 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 );
128
129
130
131 return Safe.InvokePromise(action).Then(
132 Success,
133 Fail
134 );
135 }
136
137 void AddPending(IPromise result) {
15 138
16 139 }
17 140
141
18 142 #region IInitializable implementation
19 143
20 144 public void Init() {
145 Invoke(Commands.Init, OnInitialize);
146 }
21 147
148 protected virtual void OnInitialize() {
22 149 }
23 150
24 151 #endregion
@@ -26,7 +153,17 namespace Implab.Components {
26 153 #region IRunnable implementation
27 154
28 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 169 protected virtual IPromise OnStart() {
General Comments 0
You need to be logged in to leave comments. Login now