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