Auto status change to "Under Review"
@@ -0,0 +1,4 | |||
|
1 | <?xml version="1.0" encoding="utf-8"?> | |
|
2 | <packages> | |
|
3 | <package id="NUnit" version="2.6.4" targetFramework="net45" /> | |
|
4 | </packages> No newline at end of file |
@@ -0,0 +1,16 | |||
|
1 | using System; | |
|
2 | ||
|
3 | namespace Implab.Components | |
|
4 | { | |
|
5 | public class StateChangeEventArgs { | |
|
6 | /// <summary> | |
|
7 | /// The error information if any | |
|
8 | /// </summary> | |
|
9 | public Exception LastError { get; set; } | |
|
10 | ||
|
11 | /// <summary> | |
|
12 | /// The state of the service corresponding to this event | |
|
13 | /// </summary> | |
|
14 | public ExecutionState State { get; set; } | |
|
15 | } | |
|
16 | } |
@@ -336,7 +336,7 namespace Implab.Test { | |||
|
336 | 336 | Console.WriteLine("done reader #2: {0} ms", Environment.TickCount - t1); |
|
337 | 337 | } |
|
338 | 338 | ) |
|
339 |
. |
|
|
339 | .PromiseAll() | |
|
340 | 340 | .Join(); |
|
341 | 341 | |
|
342 | 342 | Assert.AreEqual(count * 3, res1 + res2); |
@@ -414,7 +414,7 namespace Implab.Test { | |||
|
414 | 414 | Console.WriteLine("done reader #2: {0} ms", Environment.TickCount - t1); |
|
415 | 415 | } |
|
416 | 416 | ) |
|
417 |
. |
|
|
417 | .PromiseAll() | |
|
418 | 418 | .Join(); |
|
419 | 419 | |
|
420 | 420 | Assert.AreEqual(summ , r1 + r2); |
@@ -490,7 +490,7 namespace Implab.Test { | |||
|
490 | 490 | Console.WriteLine("done reader #2: {0} ms, avg chunk size: {1}", Environment.TickCount - t1, avgchunk); |
|
491 | 491 | } |
|
492 | 492 | ) |
|
493 |
. |
|
|
493 | .PromiseAll() | |
|
494 | 494 | .Join(); |
|
495 | 495 | |
|
496 | 496 | Assert.AreEqual(summ , r1 + r2); |
@@ -593,7 +593,7 namespace Implab.Test { | |||
|
593 | 593 | Console.WriteLine("done reader #2: {0} ms, {1} items", Environment.TickCount - t1, count); |
|
594 | 594 | } |
|
595 | 595 | ) |
|
596 |
. |
|
|
596 | .PromiseAll() | |
|
597 | 597 | .Join(); |
|
598 | 598 | |
|
599 | 599 | Assert.AreEqual(summ , r1 + r2); |
@@ -835,7 +835,7 namespace Implab.Test { | |||
|
835 | 835 | log.Enqueue("Writer #1 lock released"); |
|
836 | 836 | } |
|
837 | 837 | } |
|
838 |
). |
|
|
838 | ).PromiseAll().Join(1000); | |
|
839 | 839 | log.Enqueue("Done"); |
|
840 | 840 | } catch(Exception error) { |
|
841 | 841 | log.Enqueue(error.Message); |
@@ -1,4 +1,4 | |||
|
1 | <?xml version="1.0" encoding="utf-8"?> | |
|
1 | <?xml version="1.0" encoding="utf-8"?> | |
|
2 | 2 | <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|
3 | 3 | <PropertyGroup> |
|
4 | 4 | <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
@@ -49,4 +49,7 | |||
|
49 | 49 | <ItemGroup> |
|
50 | 50 | <None Include="packages.config" /> |
|
51 | 51 | </ItemGroup> |
|
52 | <ItemGroup> | |
|
53 | <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> | |
|
54 | </ItemGroup> | |
|
52 | 55 | </Project> No newline at end of file |
@@ -1,4 +1,4 | |||
|
1 | <?xml version="1.0" encoding="utf-8"?> | |
|
1 | <?xml version="1.0" encoding="utf-8"?> | |
|
2 | 2 | <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|
3 | 3 | <PropertyGroup> |
|
4 | 4 | <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
@@ -49,8 +49,11 | |||
|
49 | 49 | <ConsolePause>false</ConsolePause> |
|
50 | 50 | </PropertyGroup> |
|
51 | 51 | <ItemGroup> |
|
52 | <Reference Include="nunit.framework, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL"> | |
|
53 | <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath> | |
|
54 | <Private>True</Private> | |
|
55 | </Reference> | |
|
52 | 56 | <Reference Include="System" /> |
|
53 | <Reference Include="nunit.framework" /> | |
|
54 | 57 | </ItemGroup> |
|
55 | 58 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
|
56 | 59 | <ItemGroup> |
@@ -70,6 +73,9 | |||
|
70 | 73 | </ProjectReference> |
|
71 | 74 | </ItemGroup> |
|
72 | 75 | <ItemGroup> |
|
73 | <Folder Include="Mock\" /> | |
|
76 | <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> | |
|
77 | </ItemGroup> | |
|
78 | <ItemGroup> | |
|
79 | <None Include="packages.config" /> | |
|
74 | 80 | </ItemGroup> |
|
75 | 81 | </Project> No newline at end of file |
@@ -50,7 +50,7 namespace Implab.Test.Mock { | |||
|
50 | 50 | } |
|
51 | 51 | |
|
52 | 52 | protected override IPromise OnTick(ICancellationToken cancellationToken) { |
|
53 |
return MockTick != null ? Safe.Run(() => MockTick(cancellationToken)) : Promise.S |
|
|
53 | return MockTick != null ? Safe.Run(() => MockTick(cancellationToken)) : Promise.Success; | |
|
54 | 54 | } |
|
55 | 55 | |
|
56 | 56 | protected override void OnTickCancel(Exception error) { |
@@ -6,6 +6,9 namespace Implab.Test.Mock { | |||
|
6 | 6 | public MockRunnableComponent(bool initialized) : base(initialized) { |
|
7 | 7 | } |
|
8 | 8 | |
|
9 | public MockRunnableComponent(bool initialized, bool reusable) : base(initialized, reusable) { | |
|
10 | } | |
|
11 | ||
|
9 | 12 | public Action MockInit { |
|
10 | 13 | get; |
|
11 | 14 | set; |
@@ -21,6 +24,11 namespace Implab.Test.Mock { | |||
|
21 | 24 | set; |
|
22 | 25 | } |
|
23 | 26 | |
|
27 | public Action<bool, Exception> MockDispose { | |
|
28 | get; | |
|
29 | set; | |
|
30 | } | |
|
31 | ||
|
24 | 32 | protected override IPromise OnStart() { |
|
25 | 33 | return MockStart != null ? Safe.Run(MockStart).Chain(base.OnStart) : Safe.Run(base.OnStart); |
|
26 | 34 | } |
@@ -33,6 +41,12 namespace Implab.Test.Mock { | |||
|
33 | 41 | if (MockInit != null) |
|
34 | 42 | MockInit(); |
|
35 | 43 | } |
|
44 | ||
|
45 | protected override void Dispose(bool disposing, Exception lastError) { | |
|
46 | if (MockDispose != null) | |
|
47 | MockDispose(disposing, lastError); | |
|
48 | base.Dispose(disposing, lastError); | |
|
49 | } | |
|
36 | 50 | } |
|
37 | 51 | } |
|
38 | 52 |
@@ -36,7 +36,7 namespace Implab.Test { | |||
|
36 | 36 | |
|
37 | 37 | Assert.AreEqual(ExecutionState.Created, comp.State); |
|
38 | 38 | |
|
39 | comp.Init(); | |
|
39 | comp.Initialize(); | |
|
40 | 40 | |
|
41 | 41 | Assert.AreEqual(ExecutionState.Ready, comp.State); |
|
42 | 42 | |
@@ -57,7 +57,7 namespace Implab.Test { | |||
|
57 | 57 | var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true); |
|
58 | 58 | comp.MockTick = ct => { |
|
59 | 59 | signal.Set(); |
|
60 |
return Promise.S |
|
|
60 | return Promise.Success; | |
|
61 | 61 | }; |
|
62 | 62 | |
|
63 | 63 | comp.Start().Join(1000); |
@@ -39,7 +39,7 namespace Implab.Test { | |||
|
39 | 39 | |
|
40 | 40 | Assert.AreEqual(ExecutionState.Created, comp.State); |
|
41 | 41 | |
|
42 | comp.Init(); | |
|
42 | comp.Initialize(); | |
|
43 | 43 | |
|
44 | 44 | Assert.AreEqual(ExecutionState.Ready, comp.State); |
|
45 | 45 | |
@@ -65,7 +65,7 namespace Implab.Test { | |||
|
65 | 65 | ShouldThrow(() => comp.Stop()); |
|
66 | 66 | Assert.AreEqual(ExecutionState.Created, comp.State); |
|
67 | 67 | |
|
68 | ShouldThrow(comp.Init); | |
|
68 | ShouldThrow(comp.Initialize); | |
|
69 | 69 | |
|
70 | 70 | Assert.AreEqual(ExecutionState.Failed, comp.State); |
|
71 | 71 | |
@@ -85,9 +85,74 namespace Implab.Test { | |||
|
85 | 85 | |
|
86 | 86 | ShouldThrow(() => comp.Start()); |
|
87 | 87 | ShouldThrow(() => comp.Stop()); |
|
88 | ShouldThrow(comp.Init); | |
|
88 | ShouldThrow(comp.Initialize); | |
|
89 | ||
|
90 | Assert.AreEqual(ExecutionState.Disposed, comp.State); | |
|
91 | } | |
|
92 | ||
|
93 | [TestMethod] | |
|
94 | public void ShouldCallDisposeOnStop() { | |
|
95 | var comp = new MockRunnableComponent(true); | |
|
96 | ||
|
97 | bool disposed = false; | |
|
98 | comp.MockDispose = (disposing, error) => { | |
|
99 | disposed = true; | |
|
100 | }; | |
|
101 | ||
|
102 | comp.Start().Join(1000); | |
|
103 | comp.Stop().Join(1000); | |
|
104 | ||
|
105 | ShouldThrow(() => comp.Start()); | |
|
106 | ShouldThrow(() => comp.Stop()); | |
|
107 | ShouldThrow(comp.Initialize); | |
|
89 | 108 | |
|
90 | 109 | Assert.AreEqual(ExecutionState.Disposed, comp.State); |
|
110 | Assert.IsTrue(disposed); | |
|
111 | } | |
|
112 | ||
|
113 | [TestMethod] | |
|
114 | public void ShouldNotCallDisposeOnStop() { | |
|
115 | var comp = new MockRunnableComponent(true, true); | |
|
116 | ||
|
117 | bool disposed = false; | |
|
118 | comp.MockDispose = (disposing, error) => { | |
|
119 | disposed = true; | |
|
120 | }; | |
|
121 | ||
|
122 | comp.Start().Join(1000); | |
|
123 | comp.Stop().Join(1000); | |
|
124 | ||
|
125 | Assert.AreEqual(ExecutionState.Ready, comp.State); | |
|
126 | Assert.IsFalse(disposed); | |
|
127 | } | |
|
128 | ||
|
129 | [TestMethod] | |
|
130 | public void SelfDisposeOnStop() { | |
|
131 | var comp = new MockRunnableComponent(true, true); | |
|
132 | ||
|
133 | bool disposed = false; | |
|
134 | Exception lastError = null; | |
|
135 | comp.MockDispose = (disposing, error) => { | |
|
136 | disposed = true; | |
|
137 | lastError = error; | |
|
138 | }; | |
|
139 | ||
|
140 | comp.Start().Join(1000); | |
|
141 | comp.Stop().Join(1000); | |
|
142 | ||
|
143 | Assert.AreEqual(ExecutionState.Ready, comp.State); | |
|
144 | Assert.IsFalse(disposed); | |
|
145 | ||
|
146 | comp.MockStop = () => { | |
|
147 | comp.Dispose(); | |
|
148 | return Promise.Success; | |
|
149 | }; | |
|
150 | ||
|
151 | comp.Start().Join(1000); | |
|
152 | comp.Stop().Join(1000); | |
|
153 | ||
|
154 | Assert.AreEqual(ExecutionState.Disposed, comp.State); | |
|
155 | Assert.IsTrue(disposed); | |
|
91 | 156 | } |
|
92 | 157 | |
|
93 | 158 | [TestMethod] |
@@ -28,6 +28,14 namespace Implab.Automaton { | |||
|
28 | 28 | public override int GetHashCode() { |
|
29 | 29 | return s1 + s2 + edge; |
|
30 | 30 | } |
|
31 | ||
|
32 | public static bool operator == (AutomatonTransition rv, AutomatonTransition lv) { | |
|
33 | return rv.Equals(lv); | |
|
34 | } | |
|
35 | ||
|
36 | public static bool operator !=(AutomatonTransition rv, AutomatonTransition lv) { | |
|
37 | return rv.Equals(lv); | |
|
38 | } | |
|
31 | 39 | } |
|
32 | 40 | } |
|
33 | 41 |
@@ -3,8 +3,8 | |||
|
3 | 3 | namespace Implab.Components { |
|
4 | 4 | /// <summary> |
|
5 | 5 | /// Initializable components are created and initialized in two steps, first we have create the component, |
|
6 | /// then we have to complete it's creation by calling an <see cref="Init()"/> method. All parameters needed | |
|
7 | /// to complete the initialization must be passed before the calling <see cref="Init()"/> | |
|
6 | /// then we have to complete it's creation by calling an <see cref="Initialize()"/> method. All parameters needed | |
|
7 | /// to complete the initialization must be passed before the calling <see cref="Initialize()"/> | |
|
8 | 8 | /// </summary> |
|
9 | 9 | public interface IInitializable { |
|
10 | 10 | /// <summary> |
@@ -12,10 +12,10 namespace Implab.Components { | |||
|
12 | 12 | /// </summary> |
|
13 | 13 | /// <remarks> |
|
14 | 14 | /// Normally virtual methods shouldn't be called from the constructor, due to the incomplete object state, but |
|
15 | /// they can be called from this method. This method is also usefull when we constructing a complex grpah | |
|
15 | /// they can be called from this method. This method is aьуерщlso usefull when we constructing a complex grpah | |
|
16 | 16 | /// of components where cyclic references may take place. |
|
17 | 17 | /// </remarks> |
|
18 | void Init(); | |
|
18 | void Initialize(); | |
|
19 | 19 | } |
|
20 | 20 | } |
|
21 | 21 |
@@ -14,6 +14,8 namespace Implab.Components { | |||
|
14 | 14 | |
|
15 | 15 | ExecutionState State { get; } |
|
16 | 16 | |
|
17 | event EventHandler<StateChangeEventArgs> StateChanged; | |
|
18 | ||
|
17 | 19 | Exception LastError { get; } |
|
18 | 20 | } |
|
19 | 21 | } |
@@ -124,7 +124,7 namespace Implab.Components { | |||
|
124 | 124 | /// Invoked when the timer ticks, use this method to implement your logic |
|
125 | 125 | /// </summary> |
|
126 | 126 | protected virtual IPromise OnTick(ICancellationToken cancellationToken) { |
|
127 |
return Promise.S |
|
|
127 | return Promise.Success; | |
|
128 | 128 | } |
|
129 | 129 | |
|
130 | 130 | protected override IPromise OnStop() { |
@@ -9,7 +9,8 namespace Implab.Components { | |||
|
9 | 9 | Start, |
|
10 | 10 | Stop, |
|
11 | 11 | Dispose, |
|
12 |
|
|
|
12 | Reset, | |
|
13 | Last = Reset | |
|
13 | 14 | } |
|
14 | 15 | |
|
15 | 16 | class StateMachine { |
@@ -37,9 +38,11 namespace Implab.Components { | |||
|
37 | 38 | Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose); |
|
38 | 39 | |
|
39 | 40 | Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail); |
|
40 |
Edge(ExecutionState.Stopping, ExecutionState. |
|
|
41 | Edge(ExecutionState.Stopping, ExecutionState.Ready, Commands.Ok); | |
|
42 | Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose); | |
|
41 | 43 | |
|
42 | 44 | Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose); |
|
45 | Edge(ExecutionState.Failed, ExecutionState.Initializing, Commands.Reset); | |
|
43 | 46 | } |
|
44 | 47 | |
|
45 | 48 | static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) { |
@@ -68,13 +71,28 namespace Implab.Components { | |||
|
68 | 71 | Exception m_lastError; |
|
69 | 72 | |
|
70 | 73 | readonly StateMachine m_stateMachine; |
|
74 | readonly bool m_reusable; | |
|
75 | public event EventHandler<StateChangeEventArgs> StateChanged; | |
|
71 | 76 | |
|
72 | protected RunnableComponent(bool initialized) { | |
|
77 | /// <summary> | |
|
78 | /// Initializes component state. | |
|
79 | /// </summary> | |
|
80 | /// <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> | |
|
81 | /// <param name="reusable">If set, the component may start after it has been stopped, otherwise the component is disposed after being stopped.</param> | |
|
82 | protected RunnableComponent(bool initialized, bool reusable) { | |
|
73 | 83 | m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created); |
|
84 | m_reusable = reusable; | |
|
74 | 85 | DisposeTimeout = 10000; |
|
75 | 86 | } |
|
76 | 87 | |
|
77 | 88 | /// <summary> |
|
89 | /// Initializes component state. The component created with this constructor is not reusable, i.e. it will be disposed after stop. | |
|
90 | /// </summary> | |
|
91 | /// <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> | |
|
92 | protected RunnableComponent(bool initialized) : this(initialized, false) { | |
|
93 | } | |
|
94 | ||
|
95 | /// <summary> | |
|
78 | 96 | /// 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. |
|
79 | 97 | /// </summary> |
|
80 | 98 | protected int DisposeTimeout { |
@@ -86,89 +104,139 namespace Implab.Components { | |||
|
86 | 104 | if (m_stateMachine.State == ExecutionState.Disposed) |
|
87 | 105 | throw new ObjectDisposedException(ToString()); |
|
88 | 106 | |
|
89 | throw new InvalidOperationException(String.Format("Commnd {0} is not allowed in the state {1}", cmd, m_stateMachine.State)); | |
|
107 | throw new InvalidOperationException(String.Format("Command {0} is not allowed in the state {1}", cmd, m_stateMachine.State)); | |
|
108 | } | |
|
109 | ||
|
110 | bool MoveIfInState(Commands cmd, IPromise pending, Exception error, ExecutionState state) { | |
|
111 | ExecutionState prev, current; | |
|
112 | lock (m_stateMachine) { | |
|
113 | if (m_stateMachine.State != state) | |
|
114 | return false; | |
|
115 | ||
|
116 | prev = m_stateMachine.State; | |
|
117 | if (!m_stateMachine.Move(cmd)) | |
|
118 | ThrowInvalidCommand(cmd); | |
|
119 | current = m_stateMachine.State; | |
|
120 | ||
|
121 | m_pending = pending; | |
|
122 | m_lastError = error; | |
|
123 | } | |
|
124 | if (prev != current) | |
|
125 | OnStateChanged(prev, current, error); | |
|
126 | return true; | |
|
90 | 127 | } |
|
91 | 128 | |
|
92 | void Move(Commands cmd) { | |
|
129 | bool MoveIfPending(Commands cmd, IPromise pending, Exception error, IPromise expected) { | |
|
130 | ExecutionState prev, current; | |
|
131 | lock (m_stateMachine) { | |
|
132 | if (m_pending != expected) | |
|
133 | return false; | |
|
134 | prev = m_stateMachine.State; | |
|
93 | 135 | if (!m_stateMachine.Move(cmd)) |
|
94 | 136 | ThrowInvalidCommand(cmd); |
|
137 | current = m_stateMachine.State; | |
|
138 | m_pending = pending; | |
|
139 | m_lastError = error; | |
|
140 | } | |
|
141 | if (prev != current) | |
|
142 | OnStateChanged(prev, current, error); | |
|
143 | return true; | |
|
144 | } | |
|
145 | ||
|
146 | IPromise Move(Commands cmd, IPromise pending, Exception error) { | |
|
147 | ExecutionState prev, current; | |
|
148 | IPromise ret; | |
|
149 | lock (m_stateMachine) { | |
|
150 | prev = m_stateMachine.State; | |
|
151 | if (!m_stateMachine.Move(cmd)) | |
|
152 | ThrowInvalidCommand(cmd); | |
|
153 | current = m_stateMachine.State; | |
|
154 | ||
|
155 | ret = m_pending; | |
|
156 | m_pending = pending; | |
|
157 | m_lastError = error; | |
|
158 | ||
|
159 | } | |
|
160 | if(prev != current) | |
|
161 | OnStateChanged(prev, current, error); | |
|
162 | return ret; | |
|
163 | } | |
|
164 | ||
|
165 | protected virtual void OnStateChanged(ExecutionState previous, ExecutionState current, Exception error) { | |
|
166 | var h = StateChanged; | |
|
167 | if (h != null) | |
|
168 | h(this, new StateChangeEventArgs { | |
|
169 | State = current, | |
|
170 | LastError = error | |
|
171 | }); | |
|
95 | 172 | } |
|
96 | 173 | |
|
97 | 174 | /// <summary> |
|
98 | 175 | /// Moves the component from running to failed state. |
|
99 | 176 | /// </summary> |
|
100 | 177 | /// <param name="error">The exception which is describing the error.</param> |
|
101 | /// <returns>Returns true if the component is set to the failed state, false - otherwise. | |
|
102 | /// This method works only for the running state, in any other state it will return false.</returns> | |
|
103 | 178 | protected bool Fail(Exception error) { |
|
104 | lock (m_stateMachine) { | |
|
105 | if(m_stateMachine.State == ExecutionState.Running) { | |
|
106 | m_stateMachine.Move(Commands.Fail); | |
|
107 | m_lastError = error; | |
|
108 | return true; | |
|
109 | } | |
|
110 | } | |
|
111 | return false; | |
|
179 | return MoveIfInState(Commands.Fail, null, error, ExecutionState.Running); | |
|
112 | 180 | } |
|
113 | 181 | |
|
114 | void Invoke(Commands cmd, Action action) { | |
|
115 | lock (m_stateMachine) | |
|
116 | Move(cmd); | |
|
182 | /// <summary> | |
|
183 | /// Tries to reset <see cref="ExecutionState.Failed"/> state to <see cref="ExecutionState.Ready"/>. | |
|
184 | /// </summary> | |
|
185 | /// <returns>True if component is reset to <see cref="ExecutionState.Ready"/>, false if the componet wasn't | |
|
186 | /// in <see cref="ExecutionState.Failed"/> state.</returns> | |
|
187 | /// <remarks> | |
|
188 | /// This method checks the current state of the component and if it's in <see cref="ExecutionState.Failed"/> | |
|
189 | /// moves component to <see cref="ExecutionState.Initializing"/>. | |
|
190 | /// The <see cref="OnResetState()"/> is called and if this method completes succesfully the component moved | |
|
191 | /// to <see cref="ExecutionState.Ready"/> state, otherwise the component is moved to <see cref="ExecutionState.Failed"/> | |
|
192 | /// state. If <see cref="OnResetState()"/> throws an exception it will be propagated by this method to the caller. | |
|
193 | /// </remarks> | |
|
194 | protected bool ResetState() { | |
|
195 | if (!MoveIfInState(Commands.Reset, null, null, ExecutionState.Failed)) | |
|
196 | return false; | |
|
117 | 197 | |
|
118 | 198 | try { |
|
119 |
|
|
|
120 | lock(m_stateMachine) | |
|
121 | Move(Commands.Ok); | |
|
122 | ||
|
199 | OnResetState(); | |
|
200 | Move(Commands.Ok, null, null); | |
|
201 | return true; | |
|
123 | 202 | } catch (Exception err) { |
|
124 | lock (m_stateMachine) { | |
|
125 | Move(Commands.Fail); | |
|
126 | m_lastError = err; | |
|
127 | } | |
|
203 | Move(Commands.Fail, null, err); | |
|
128 | 204 | throw; |
|
129 | 205 | } |
|
130 | 206 | } |
|
131 | 207 | |
|
208 | /// <summary> | |
|
209 | /// This method is called by <see cref="ResetState"/> to reinitialize component in the failed state. | |
|
210 | /// </summary> | |
|
211 | /// <remarks> | |
|
212 | /// Default implementation throws <see cref="NotImplementedException"/> which will cause the component | |
|
213 | /// fail to reset it's state and it left in <see cref="ExecutionState.Failed"/> state. | |
|
214 | /// If this method doesn't throw exceptions the component is moved to <see cref="ExecutionState.Ready"/> state. | |
|
215 | /// </remarks> | |
|
216 | protected virtual void OnResetState() { | |
|
217 | throw new NotImplementedException(); | |
|
218 | } | |
|
219 | ||
|
132 | 220 | IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) { |
|
133 | 221 | IPromise promise = null; |
|
134 | 222 | IPromise prev; |
|
135 | 223 | |
|
136 | 224 | var task = new ActionChainTask(action, null, null, true); |
|
137 | 225 | |
|
138 | lock (m_stateMachine) { | |
|
139 | Move(cmd); | |
|
140 | ||
|
141 | prev = m_pending; | |
|
142 | ||
|
143 | 226 |
|
|
144 | 227 |
|
|
145 | 228 |
|
|
146 | ||
|
147 | lock (m_stateMachine) { | |
|
148 | if (m_pending == promise) { | |
|
149 | Move(Commands.Fail); | |
|
150 | m_pending = null; | |
|
151 | m_lastError = e; | |
|
152 | } | |
|
153 | } | |
|
229 | MoveIfPending(Commands.Fail, null, e, promise); | |
|
154 | 230 |
|
|
155 | 231 |
|
|
156 | 232 | |
|
157 | 233 |
|
|
158 | () => { | |
|
159 | lock(m_stateMachine) { | |
|
160 | if (m_pending == promise) { | |
|
161 | Move(Commands.Ok); | |
|
162 | m_pending = null; | |
|
163 | } | |
|
164 | } | |
|
165 | }, | |
|
234 | () => MoveIfPending(Commands.Ok, null, null, promise), | |
|
166 | 235 |
|
|
167 | 236 |
|
|
168 | 237 |
|
|
169 | 238 | |
|
170 |
|
|
|
171 | } | |
|
239 | prev = Move(cmd, promise, null); | |
|
172 | 240 | |
|
173 | 241 | if (prev == null) |
|
174 | 242 | task.Resolve(); |
@@ -181,8 +249,16 namespace Implab.Components { | |||
|
181 | 249 | |
|
182 | 250 | #region IInitializable implementation |
|
183 | 251 | |
|
184 | public void Init() { | |
|
185 |
|
|
|
252 | public void Initialize() { | |
|
253 | Move(Commands.Init, null, null); | |
|
254 | ||
|
255 | try { | |
|
256 | OnInitialize(); | |
|
257 | Move(Commands.Ok, null, null); | |
|
258 | } catch (Exception err) { | |
|
259 | Move(Commands.Fail, null, err); | |
|
260 | throw; | |
|
261 | } | |
|
186 | 262 | } |
|
187 | 263 | |
|
188 | 264 | protected virtual void OnInitialize() { |
@@ -197,15 +273,16 namespace Implab.Components { | |||
|
197 | 273 | } |
|
198 | 274 | |
|
199 | 275 | protected virtual IPromise OnStart() { |
|
200 |
return Promise.S |
|
|
276 | return Promise.Success; | |
|
201 | 277 | } |
|
202 | 278 | |
|
203 | 279 | public IPromise Stop() { |
|
204 |
|
|
|
280 | var pending = InvokeAsync(Commands.Stop, OnStop, StopPending); | |
|
281 | return m_reusable ? pending : pending.Then(Dispose); | |
|
205 | 282 | } |
|
206 | 283 | |
|
207 | 284 | protected virtual IPromise OnStop() { |
|
208 |
return Promise.S |
|
|
285 | return Promise.Success; | |
|
209 | 286 | } |
|
210 | 287 | |
|
211 | 288 | /// <summary> |
@@ -258,17 +335,14 namespace Implab.Components { | |||
|
258 | 335 | /// </para></remarks> |
|
259 | 336 | public void Dispose() { |
|
260 | 337 | IPromise pending; |
|
338 | ||
|
261 | 339 | lock (m_stateMachine) { |
|
262 | 340 | if (m_stateMachine.State == ExecutionState.Disposed) |
|
263 | 341 | return; |
|
264 | ||
|
265 | Move(Commands.Dispose); | |
|
342 | pending = Move(Commands.Dispose, null, null); | |
|
343 | } | |
|
266 | 344 | |
|
267 | 345 |
|
|
268 | ||
|
269 | pending = m_pending; | |
|
270 | m_pending = null; | |
|
271 | } | |
|
272 | 346 | if (pending != null) { |
|
273 | 347 | pending.Cancel(); |
|
274 | 348 | pending.Timeout(DisposeTimeout).On( |
@@ -277,7 +351,7 namespace Implab.Components { | |||
|
277 | 351 | reason => Dispose(true, new OperationCanceledException("The operation is cancelled", reason)) |
|
278 | 352 | ); |
|
279 | 353 | } else { |
|
280 |
Dispose(true, |
|
|
354 | Dispose(true, null); | |
|
281 | 355 | } |
|
282 | 356 | } |
|
283 | 357 | |
@@ -287,6 +361,11 namespace Implab.Components { | |||
|
287 | 361 | |
|
288 | 362 | #endregion |
|
289 | 363 | |
|
364 | /// <summary> | |
|
365 | /// Releases all resources used by the component, called automatically, override this method to implement your cleanup. | |
|
366 | /// </summary> | |
|
367 | /// <param name="disposing">true if this method is called during normal dispose process.</param> | |
|
368 | /// <param name="lastError">The last error which occured during the component stop.</param> | |
|
290 | 369 | protected virtual void Dispose(bool disposing, Exception lastError) { |
|
291 | 370 | |
|
292 | 371 | } |
@@ -5,6 +5,7 using System.Text; | |||
|
5 | 5 | namespace Implab.Diagnostics { |
|
6 | 6 | public class TextFileListener: ListenerBase { |
|
7 | 7 | readonly TextWriter m_textWriter; |
|
8 | readonly object m_lock = new object(); | |
|
8 | 9 | |
|
9 | 10 | public TextFileListener(string fileName) { |
|
10 | 11 | m_textWriter = File.CreateText(fileName); |
@@ -20,7 +21,7 namespace Implab.Diagnostics { | |||
|
20 | 21 | msg.Append(" "); |
|
21 | 22 | msg.AppendFormat("[{0}]:{1}: {2}", args.ThreadId, args.Channel, entry); |
|
22 | 23 | |
|
23 |
lock (m_ |
|
|
24 | lock (m_lock) { | |
|
24 | 25 | if (!IsDisposed) { |
|
25 | 26 | // тут гарантировано еще не освобожден m_textWriter |
|
26 | 27 | m_textWriter.WriteLine(msg); |
@@ -35,7 +36,7 namespace Implab.Diagnostics { | |||
|
35 | 36 | base.Dispose(disposing); |
|
36 | 37 | if (disposing) { |
|
37 | 38 | // IsDisposed = true |
|
38 |
lock (m_ |
|
|
39 | lock (m_lock) { | |
|
39 | 40 | Safe.Dispose(m_textWriter); |
|
40 | 41 | } |
|
41 | 42 | } |
@@ -75,6 +75,7 | |||
|
75 | 75 | <Reference Include="mscorlib" /> |
|
76 | 76 | </ItemGroup> |
|
77 | 77 | <ItemGroup> |
|
78 | <Compile Include="Components\StateChangeEventArgs.cs" /> | |
|
78 | 79 | <Compile Include="CustomEqualityComparer.cs" /> |
|
79 | 80 | <Compile Include="Diagnostics\ConsoleTraceListener.cs" /> |
|
80 | 81 | <Compile Include="Diagnostics\LogChannel.cs" /> |
@@ -269,10 +270,5 | |||
|
269 | 270 | </Properties> |
|
270 | 271 | </MonoDevelop> |
|
271 | 272 | </ProjectExtensions> |
|
272 | <ItemGroup> | |
|
273 | <Folder Include="Components\" /> | |
|
274 | <Folder Include="Automaton\RegularExpressions\" /> | |
|
275 | <Folder Include="Formats\" /> | |
|
276 | <Folder Include="Formats\JSON\" /> | |
|
277 | </ItemGroup> | |
|
273 | <ItemGroup /> | |
|
278 | 274 | </Project> No newline at end of file |
@@ -3,11 +3,10 using Implab.Parallels; | |||
|
3 | 3 | |
|
4 | 4 | namespace Implab { |
|
5 | 5 | public class Promise : AbstractPromise, IDeferred { |
|
6 |
public static readonly Promise S |
|
|
6 | public static readonly IPromise Success; | |
|
7 | 7 | |
|
8 | 8 | static Promise() { |
|
9 |
S |
|
|
10 | SUCCESS.Resolve(); | |
|
9 | Success = new SuccessPromise(); | |
|
11 | 10 | } |
|
12 | 11 | |
|
13 | 12 | public void Resolve() { |
@@ -17,6 +16,10 namespace Implab { | |||
|
17 | 16 | public void Reject(Exception error) { |
|
18 | 17 | SetError(error); |
|
19 | 18 | } |
|
19 | ||
|
20 | public static IPromise FromException(Exception exception) { | |
|
21 | return new FailedPromise(exception); | |
|
22 | } | |
|
20 | 23 | } |
|
21 | 24 | } |
|
22 | 25 |
@@ -2,6 +2,7 | |||
|
2 | 2 | using System; |
|
3 | 3 | using Implab.Diagnostics; |
|
4 | 4 | using System.Collections.Generic; |
|
5 | using System.Linq; | |
|
5 | 6 | |
|
6 | 7 | namespace Implab { |
|
7 | 8 | public static class PromiseExtensions { |
@@ -88,7 +89,17 namespace Implab { | |||
|
88 | 89 | return that; |
|
89 | 90 | } |
|
90 | 91 | |
|
91 |
public static IPromise |
|
|
92 | public static IPromise PromiseAll(this IEnumerable<IPromise> that) { | |
|
93 | Safe.ArgumentNotNull(that, "that"); | |
|
94 | return PromiseAll(that.ToList()); | |
|
95 | } | |
|
96 | ||
|
97 | public static IPromise<T[]> PromiseAll<T>(this IEnumerable<IPromise<T>> that) { | |
|
98 | Safe.ArgumentNotNull(that, "that"); | |
|
99 | return PromiseAll(that.ToList()); | |
|
100 | } | |
|
101 | ||
|
102 | public static IPromise PromiseAll(this ICollection<IPromise> that) { | |
|
92 | 103 | Safe.ArgumentNotNull(that, "that"); |
|
93 | 104 | |
|
94 | 105 | int count = that.Count; |
@@ -128,7 +139,7 namespace Implab { | |||
|
128 | 139 | return medium; |
|
129 | 140 | } |
|
130 | 141 | |
|
131 |
public static IPromise<T[]> |
|
|
142 | public static IPromise<T[]> PromiseAll<T>(this ICollection<IPromise<T>> that) { | |
|
132 | 143 | Safe.ArgumentNotNull(that, "that"); |
|
133 | 144 | |
|
134 | 145 | int count = that.Count; |
General Comments 3
ok, latest stable version should be in default
You need to be logged in to leave comments.
Login now