##// END OF EJS Templates
Added 'Fail' method to RunnableComponent which allows component to move from...
cin -
r203:4d9830a9bbb8 v2
parent child
Show More
@@ -0,0 +1,71
1 using System;
2 using Implab.Components;
3
4 namespace Implab.Test.Mock {
5 class MockPollingComponent : PollingComponent {
6 public MockPollingComponent(TimeSpan interval, Func<Func<ICancellationToken, IPromise>, IPromise> dispatcher, bool initialized) : base(interval, dispatcher, initialized) {
7 }
8
9 public Action MockInit {
10 get;
11 set;
12 }
13
14 public Action<Exception> MockOnError {
15 get;
16 set;
17 }
18
19 public Action<Exception> MockOnCancel {
20 get;
21 set;
22 }
23
24 public Func<IPromise> MockStart {
25 get;
26 set;
27 }
28
29 public Func<IPromise> MockStop {
30 get;
31 set;
32 }
33
34 public Func<ICancellationToken, IPromise> MockTick {
35 get;
36 set;
37 }
38
39 protected override IPromise OnStart() {
40 return MockStart != null ? Safe.Run(MockStart).Chain(base.OnStart) : Safe.Run(base.OnStart);
41 }
42
43 protected override IPromise OnStop() {
44 return MockStop != null ? Safe.Run(MockStop).Chain(base.OnStop) : Safe.Run(base.OnStop);
45 }
46
47 protected override void OnInitialize() {
48 if (MockInit != null)
49 MockInit();
50 }
51
52 protected override IPromise OnTick(ICancellationToken cancellationToken) {
53 return MockTick != null ? Safe.Run(() => MockTick(cancellationToken)) : Promise.SUCCESS;
54 }
55
56 protected override void OnTickCancel(Exception error) {
57 if (MockOnCancel != null)
58 MockOnCancel(error);
59 }
60
61 protected override void OnTickError(Exception error) {
62 if (MockOnError != null)
63 MockOnError(error);
64 }
65
66 public void CallComponentFail(Exception error) {
67 Fail(error);
68 }
69 }
70 }
71
@@ -0,0 +1,38
1 using System;
2 using Implab.Components;
3
4 namespace Implab.Test.Mock {
5 class MockRunnableComponent : RunnableComponent {
6 public MockRunnableComponent(bool initialized) : base(initialized) {
7 }
8
9 public Action MockInit {
10 get;
11 set;
12 }
13
14 public Func<IPromise> MockStart {
15 get;
16 set;
17 }
18
19 public Func<IPromise> MockStop {
20 get;
21 set;
22 }
23
24 protected override IPromise OnStart() {
25 return MockStart != null ? Safe.Run(MockStart).Chain(base.OnStart) : Safe.Run(base.OnStart);
26 }
27
28 protected override IPromise OnStop() {
29 return MockStop != null ? Safe.Run(MockStop).Chain(base.OnStop) : Safe.Run(base.OnStop);
30 }
31
32 protected override void OnInitialize() {
33 if (MockInit != null)
34 MockInit();
35 }
36 }
37 }
38
@@ -0,0 +1,230
1 using System;
2 using System.Reflection;
3 using System.Threading;
4 using Implab.Parallels;
5 using Implab.Components;
6 using Implab.Test.Mock;
7
8 #if MONO
9
10 using NUnit.Framework;
11 using TestClassAttribute = NUnit.Framework.TestFixtureAttribute;
12 using TestMethodAttribute = NUnit.Framework.TestAttribute;
13 using AssertFailedException = NUnit.Framework.AssertionException;
14 #else
15
16 using Microsoft.VisualStudio.TestTools.UnitTesting;
17
18 #endif
19
20 namespace Implab.Test {
21 [TestClass]
22 public class PollingComponentTests {
23 static void ShouldThrow(Action action) {
24 try {
25 action();
26 Assert.Fail();
27 } catch (AssertFailedException) {
28 throw;
29 } catch {
30 }
31 }
32
33 [TestMethod]
34 public void NormalFlowTest() {
35 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, false);
36
37 Assert.AreEqual(ExecutionState.Created, comp.State);
38
39 comp.Init();
40
41 Assert.AreEqual(ExecutionState.Ready, comp.State);
42
43 comp.Start().Join(1000);
44
45 Assert.AreEqual(ExecutionState.Running, comp.State);
46
47 comp.Stop().Join(1000);
48
49 Assert.AreEqual(ExecutionState.Disposed, comp.State);
50
51 }
52
53 [TestMethod]
54 public void ShouldStartTicks() {
55 var signal = new Signal();
56
57 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
58 comp.MockTick = ct => {
59 signal.Set();
60 return Promise.SUCCESS;
61 };
62
63 comp.Start().Join(1000);
64 signal.Wait(1000);
65 comp.Stop().Join(1000);
66 }
67
68 [TestMethod]
69 public void StopShouldWaitForTickToComplete() {
70 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
71 var signal = new Signal();
72 var promise = new Promise();
73
74 // timer should tick once
75 comp.MockTick = ct => {
76 signal.Set();
77 return promise;
78 };
79
80 // start timer
81 comp.Start().Join(1000);
82
83 signal.Wait(); // wait for tick
84
85 // try to stop component
86 var stopping = comp.Stop();
87
88 Assert.AreEqual(ExecutionState.Stopping, comp.State);
89 ShouldThrow(() => stopping.Join(100));
90 Assert.AreEqual(ExecutionState.Stopping, comp.State);
91
92 // complete operation
93 promise.Resolve();
94
95 // the component should stop normally
96 stopping.Join(1000);
97
98 Assert.AreEqual(ExecutionState.Disposed, comp.State);
99 }
100
101 [TestMethod]
102 public void ShouldRecoverAfterTickError() {
103 var ticks = 0;
104
105 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
106 var signal = new Signal(); // will signal when timer fires 10 times
107
108 comp.MockTick = ct => {
109 ticks++;
110 if (ticks == 10)
111 signal.Set();
112 // each time handler dies
113 throw new Exception("tainted handler");
114 };
115
116 comp.Start();
117
118 signal.Wait(1000);
119
120 comp.Stop().Join(1000);
121
122 Assert.AreEqual(ExecutionState.Disposed, comp.State);
123 }
124
125 [TestMethod]
126 public void StopCancelHandlerOnStop() {
127 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
128 var started = new Signal();
129 bool cancelled = false;
130
131 // timer should tick once
132 comp.MockTick = ct => {
133 started.Set();
134
135 while(!ct.IsCancellationRequested) {
136 Thread.Sleep(1);
137 }
138
139 cancelled = true;
140
141 throw new OperationCanceledException();
142 };
143
144 // start timer
145 comp.Start().Join(1000);
146
147 started.Wait(); // wait for tick
148
149 // try to stop component
150 comp.Stop().Join(1000);
151
152 Assert.AreEqual(true, cancelled);
153
154 Assert.AreEqual(ExecutionState.Disposed, comp.State);
155 }
156
157 [TestMethod]
158 public void FailTickOnStopShouldBeIgnored() {
159 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
160 var started = new Signal();
161 var finish = new Signal();
162
163 // timer should tick once
164 comp.MockTick = ct => {
165 started.Set();
166 finish.Wait();
167 // component is in stopping state here
168 throw new Exception("Die, die, die!!!");
169 };
170
171
172 comp.MockOnError = comp.CallComponentFail;
173
174 // start timer
175 comp.Start().Join(1000);
176
177 started.Wait(); // wait for tick
178
179 // try to stop component
180 var stopping = comp.Stop();
181
182 // the component is in stopping state but it is waiting for the tick handler to complete
183 finish.Set(); // signal the tick handler to finish
184
185 // tick handler should stop rather soon
186 stopping.Join(1000);
187
188 // validate the component is disposed
189 Assert.AreEqual(ExecutionState.Disposed, comp.State);
190 }
191
192 [TestMethod]
193 public void FailTickShouldFailComponent() {
194 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
195 var started = new Signal();
196 var finish = new Signal();
197
198 // timer should tick once
199 comp.MockTick = ct => {
200 started.Set();
201 throw new Exception("Die, die, die!!!");
202 };
203
204
205 comp.MockOnError = err => {
206 comp.CallComponentFail(err);
207 finish.Set();
208 };
209
210 // start timer
211 comp.Start().Join(1000);
212
213 started.Wait(); // wait for tick
214
215 finish.Wait();
216
217 // try to stop component
218 ShouldThrow(() => comp.Stop());
219
220 Assert.AreEqual(ExecutionState.Failed, comp.State);
221 Assert.IsNotNull(comp.LastError);
222 Assert.AreEqual("Die, die, die!!!", comp.LastError.Message);
223
224 comp.Dispose();
225 Assert.AreEqual(ExecutionState.Disposed, comp.State);
226 }
227
228 }
229 }
230
@@ -0,0 +1,155
1 using System;
2 using System.Threading;
3 using Implab.Diagnostics;
4
5 namespace Implab.Components {
6 public class PollingComponent : RunnableComponent {
7 readonly Timer m_timer;
8 readonly Func<Func<ICancellationToken, IPromise>, IPromise> m_dispatcher;
9 readonly TimeSpan m_interval;
10
11 readonly object m_lock = new object();
12
13 ActionTask m_pending;
14
15 protected PollingComponent(TimeSpan interval, Func<Func<ICancellationToken, IPromise>, IPromise> dispatcher, bool initialized) : base(initialized) {
16 m_timer = new Timer(OnInternalTick);
17
18 m_interval = interval;
19 m_dispatcher = dispatcher;
20 }
21
22 protected override IPromise OnStart() {
23 m_timer.Change(TimeSpan.Zero, m_interval);
24
25 return base.OnStart();
26 }
27
28 void OnInternalTick(object state) {
29 if (StartTick()) {
30 try {
31 if (m_dispatcher != null) {
32 var result = m_dispatcher(OnTick);
33 m_pending.CancellationRequested(result.Cancel);
34 AwaitTick(result);
35 } else {
36 AwaitTick(OnTick(m_pending));
37 }
38 } catch (Exception error) {
39 HandleTickError(error);
40 }
41 }
42 }
43
44 /// <summary>
45 /// Checks wheather there is no running handler in the component and marks that the handler is starting.
46 /// </summary>
47 /// <returns>boolean value, true - the new tick handler may be invoked, false - a tick handler is already running or a component isn't running.</returns>
48 /// <remarks>
49 /// If the component is stopping no new handlers can be run. Every successful call to this method must be completed with either AwaitTick or HandleTickError handlers.
50 /// </remarks>
51 protected virtual bool StartTick() {
52 lock (m_lock) {
53 if (State != ExecutionState.Running || m_pending != null)
54 return false;
55 // actually the component may be in a not running state here (stopping, disposed or what ever),
56 // but OnStop method also locks on the same object and will handle operation in m_pending
57 m_pending = new ActionTask(
58 () => {
59 // only one operation is running, it's safe to assing m_pending from it
60 m_pending = null;
61 },
62 ex => {
63 try {
64 OnTickError(ex);
65 // Analysis disable once EmptyGeneralCatchClause
66 } catch {
67 } finally {
68 m_pending = null;
69 }
70 // suppress error
71 },
72 ex => {
73 try {
74 OnTickCancel(ex);
75 // Analysis disable once EmptyGeneralCatchClause
76 } catch {
77 } finally {
78 m_pending = null;
79 }
80 // supress cancellation
81 },
82 false
83 );
84 return true;
85 }
86 }
87
88 /// <summary>
89 /// Awaits the tick.
90 /// </summary>
91 /// <param name="tick">Tick.</param>
92 /// <remarks>
93 /// This method is called only after StartTick method and m_pending will hold the promise which should be fulfilled.
94 /// </remarks>
95 void AwaitTick(IPromise tick) {
96 if (tick == null) {
97 m_pending.Resolve();
98 } else {
99 tick.On(
100 m_pending.Resolve,
101 m_pending.Reject,
102 m_pending.CancelOperation
103 );
104 }
105 }
106
107 /// <summary>
108 /// Handles the tick error.
109 /// </summary>
110 /// <remarks>
111 /// This method is called only after StartTick method and m_pending will hold the promise which should be fulfilled.
112 /// </remarks>
113 void HandleTickError(Exception error) {
114 m_pending.Reject(error);
115 }
116
117 protected virtual void OnTickError(Exception error) {
118 }
119
120 protected virtual void OnTickCancel(Exception error) {
121 }
122
123 /// <summary>
124 /// Invoked when the timer ticks, use this method to implement your logic
125 /// </summary>
126 protected virtual IPromise OnTick(ICancellationToken cancellationToken) {
127 return Promise.SUCCESS;
128 }
129
130 protected override IPromise OnStop() {
131 m_timer.Change(-1, -1);
132
133 // the component is in the stopping state
134 lock (m_lock) {
135 // after this lock no more pending operations could be created
136 var pending = m_pending;
137 // m_pending could be fulfilled and set to null already
138 if (pending != null) {
139 pending.Cancel();
140 return pending.Then(base.OnStop);
141 }
142 }
143
144 return base.OnStop();
145 }
146
147 protected override void Dispose(bool disposing, Exception lastError) {
148 if (disposing)
149 Safe.Dispose(m_timer);
150
151 base.Dispose(disposing, lastError);
152 }
153 }
154 }
155
@@ -0,0 +1,100
1 using System;
2 using System.Reflection;
3
4 namespace Implab {
5 public class FailedPromise : IPromise {
6 readonly Exception m_error;
7 public FailedPromise(Exception error) {
8 Safe.ArgumentNotNull(error, "error");
9 m_error = error;
10 }
11
12 #region IPromise implementation
13
14 public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) {
15 if (error != null) {
16 try {
17 error(m_error);
18 // Analysis disable once EmptyGeneralCatchClause
19 } catch {
20 }
21 }
22 return this;
23 }
24
25 public IPromise On(Action success, Action<Exception> error) {
26 if (error != null) {
27 try {
28 error(m_error);
29 // Analysis disable once EmptyGeneralCatchClause
30 } catch {
31 }
32 }
33 return this;
34 }
35
36 public IPromise On(Action success) {
37 return this;
38 }
39
40 public IPromise On(Action handler, PromiseEventType events) {
41 if ((events & PromiseEventType.Error) != 0) {
42 try {
43 handler();
44 // Analysis disable once EmptyGeneralCatchClause
45 } catch {
46 }
47 }
48 return this;
49 }
50
51 public IPromise<T> Cast<T>() {
52 return (IPromise<T>)this;
53 }
54
55 public void Join() {
56 throw new TargetInvocationException(Error);
57 }
58
59 public void Join(int timeout) {
60 throw new TargetInvocationException(Error);
61 }
62
63 public virtual Type PromiseType {
64 get {
65 return typeof(void);
66 }
67 }
68
69 public bool IsResolved {
70 get {
71 return true;
72 }
73 }
74
75 public bool IsCancelled {
76 get {
77 return false;
78 }
79 }
80
81 public Exception Error {
82 get {
83 return m_error;
84 }
85 }
86
87 #endregion
88
89 #region ICancellable implementation
90
91 public void Cancel() {
92 }
93
94 public void Cancel(Exception reason) {
95 }
96
97 #endregion
98 }
99 }
100
@@ -0,0 +1,65
1 using System;
2 using System.Reflection;
3
4 namespace Implab {
5 public class FailedPromise<T> : FailedPromise, IPromise<T> {
6 public FailedPromise(Exception error) : base(error) {
7 }
8
9 public IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel) {
10 if (error != null) {
11 try {
12 error(Error);
13 // Analysis disable once EmptyGeneralCatchClause
14 } catch {
15 }
16 }
17 return this;
18 }
19
20 public IPromise<T> On(Action<T> success, Action<Exception> error) {
21 if (error != null) {
22 try {
23 error(Error);
24 // Analysis disable once EmptyGeneralCatchClause
25 } catch {
26 }
27 }
28 return this;
29 }
30
31 public IPromise<T> On(Action<T> success) {
32 return this;
33 }
34
35 T IPromise<T>.Join() {
36 throw new TargetInvocationException(Error);
37 }
38
39 T IPromise<T>.Join(int timeout) {
40 throw new TargetInvocationException(Error);
41 }
42
43
44 IPromise<T> IPromise<T>.On(Action success, Action<Exception> error, Action<Exception> cancel) {
45 On(success, error, cancel);
46 return this;
47 }
48
49 IPromise<T> IPromise<T>.On(Action success, Action<Exception> error) {
50 On(success, error);
51 return this;
52 }
53
54 IPromise<T> IPromise<T>.On(Action success) {
55 On(success);
56 return this;
57 }
58
59 IPromise<T> IPromise<T>.On(Action handler, PromiseEventType events) {
60 On(handler, events);
61 return this;
62 }
63 }
64 }
65
@@ -59,6 +59,9
59 <Compile Include="Properties\AssemblyInfo.cs" />
59 <Compile Include="Properties\AssemblyInfo.cs" />
60 <Compile Include="CancelationTests.cs" />
60 <Compile Include="CancelationTests.cs" />
61 <Compile Include="RunnableComponentTests.cs" />
61 <Compile Include="RunnableComponentTests.cs" />
62 <Compile Include="PollingComponentTests.cs" />
63 <Compile Include="Mock\MockRunnableComponent.cs" />
64 <Compile Include="Mock\MockPollingComponent.cs" />
62 </ItemGroup>
65 </ItemGroup>
63 <ItemGroup>
66 <ItemGroup>
64 <ProjectReference Include="..\Implab\Implab.csproj">
67 <ProjectReference Include="..\Implab\Implab.csproj">
@@ -66,4 +69,7
66 <Name>Implab</Name>
69 <Name>Implab</Name>
67 </ProjectReference>
70 </ProjectReference>
68 </ItemGroup>
71 </ItemGroup>
72 <ItemGroup>
73 <Folder Include="Mock\" />
74 </ItemGroup>
69 </Project> No newline at end of file
75 </Project>
@@ -10,5 +10,13 namespace Implab.Test {
10 return retVal;
10 return retVal;
11 });
11 });
12 }
12 }
13
14 public static IPromise Sleep(int timeout) {
15 return AsyncPool.Invoke((ct) => {
16 ct.CancellationRequested(ct.CancelOperation);
17 Thread.Sleep(timeout);
18 return 0;
19 });
13 }
20 }
14 }
21 }
22 }
@@ -3,6 +3,7 using System.Reflection;
3 using System.Threading;
3 using System.Threading;
4 using Implab.Parallels;
4 using Implab.Parallels;
5 using Implab.Components;
5 using Implab.Components;
6 using Implab.Test.Mock;
6
7
7 #if MONO
8 #if MONO
8
9
@@ -30,42 +31,11 namespace Implab.Test {
30 }
31 }
31 }
32 }
32
33
33 class Runnable : RunnableComponent {
34 public Runnable(bool initialized) : base(initialized) {
35 }
36
34
37 public Action MockInit {
38 get;
39 set;
40 }
41
42 public Func<IPromise> MockStart {
43 get;
44 set;
45 }
46
47 public Func<IPromise> MockStop {
48 get;
49 set;
50 }
51
52 protected override IPromise OnStart() {
53 return MockStart != null ? MockStart() : base.OnStart();
54 }
55
56 protected override IPromise OnStop() {
57 return MockStop != null ? MockStop() : base.OnStart();
58 }
59
60 protected override void OnInitialize() {
61 if (MockInit != null)
62 MockInit();
63 }
64 }
65
35
66 [TestMethod]
36 [TestMethod]
67 public void NormalFlowTest() {
37 public void NormalFlowTest() {
68 var comp = new Runnable(false);
38 var comp = new MockRunnableComponent(false);
69
39
70 Assert.AreEqual(ExecutionState.Created, comp.State);
40 Assert.AreEqual(ExecutionState.Created, comp.State);
71
41
@@ -85,7 +55,7 namespace Implab.Test {
85
55
86 [TestMethod]
56 [TestMethod]
87 public void InitFailTest() {
57 public void InitFailTest() {
88 var comp = new Runnable(false) {
58 var comp = new MockRunnableComponent(false) {
89 MockInit = () => {
59 MockInit = () => {
90 throw new Exception("BAD");
60 throw new Exception("BAD");
91 }
61 }
@@ -110,7 +80,7 namespace Implab.Test {
110 [TestMethod]
80 [TestMethod]
111 public void DisposedTest() {
81 public void DisposedTest() {
112
82
113 var comp = new Runnable(false);
83 var comp = new MockRunnableComponent(false);
114 comp.Dispose();
84 comp.Dispose();
115
85
116 ShouldThrow(() => comp.Start());
86 ShouldThrow(() => comp.Start());
@@ -122,7 +92,7 namespace Implab.Test {
122
92
123 [TestMethod]
93 [TestMethod]
124 public void StartCancelTest() {
94 public void StartCancelTest() {
125 var comp = new Runnable(true) {
95 var comp = new MockRunnableComponent(true) {
126 MockStart = () => PromiseHelper.Sleep(100000, 0)
96 MockStart = () => PromiseHelper.Sleep(100000, 0)
127 };
97 };
128
98
@@ -140,7 +110,7 namespace Implab.Test {
140 [TestMethod]
110 [TestMethod]
141 public void StartStopTest() {
111 public void StartStopTest() {
142 var stop = new Signal();
112 var stop = new Signal();
143 var comp = new Runnable(true) {
113 var comp = new MockRunnableComponent(true) {
144 MockStart = () => PromiseHelper.Sleep(100000, 0),
114 MockStart = () => PromiseHelper.Sleep(100000, 0),
145 MockStop = () => AsyncPool.RunThread(stop.Wait)
115 MockStop = () => AsyncPool.RunThread(stop.Wait)
146 };
116 };
@@ -160,7 +130,7 namespace Implab.Test {
160
130
161 [TestMethod]
131 [TestMethod]
162 public void StartStopFailTest() {
132 public void StartStopFailTest() {
163 var comp = new Runnable(true) {
133 var comp = new MockRunnableComponent(true) {
164 MockStart = () => PromiseHelper.Sleep(100000, 0).Then(null,null,x => { throw new Exception("I'm dead"); })
134 MockStart = () => PromiseHelper.Sleep(100000, 0).Then(null,null,x => { throw new Exception("I'm dead"); })
165 };
135 };
166
136
@@ -175,7 +145,7 namespace Implab.Test {
175
145
176 [TestMethod]
146 [TestMethod]
177 public void StopCancelTest() {
147 public void StopCancelTest() {
178 var comp = new Runnable(true) {
148 var comp = new MockRunnableComponent(true) {
179 MockStop = () => PromiseHelper.Sleep(100000, 0)
149 MockStop = () => PromiseHelper.Sleep(100000, 0)
180 };
150 };
181
151
@@ -2,8 +2,14
2
2
3 namespace Implab.Components {
3 namespace Implab.Components {
4 public interface IRunnable {
4 public interface IRunnable {
5 /// <summary>
6 /// Starts this instance.
7 /// </summary>
5 IPromise Start();
8 IPromise Start();
6
9
10 /// <summary>
11 /// Stops this instance. After the instance is stopped it can't be started again, stopping should be treated as gracefull and async dispose.
12 /// </summary>
7 IPromise Stop();
13 IPromise Stop();
8
14
9 ExecutionState State { get; }
15 ExecutionState State { get; }
@@ -71,12 +71,15 namespace Implab.Components {
71
71
72 protected RunnableComponent(bool initialized) {
72 protected RunnableComponent(bool initialized) {
73 m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created);
73 m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created);
74 DisposeTimeout = 10000;
74 }
75 }
75
76
76 protected virtual int DisposeTimeout {
77 /// <summary>
77 get {
78 /// 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.
78 return 10000;
79 /// </summary>
79 }
80 protected int DisposeTimeout {
81 get;
82 set;
80 }
83 }
81
84
82 void ThrowInvalidCommand(Commands cmd) {
85 void ThrowInvalidCommand(Commands cmd) {
@@ -91,6 +94,23 namespace Implab.Components {
91 ThrowInvalidCommand(cmd);
94 ThrowInvalidCommand(cmd);
92 }
95 }
93
96
97 /// <summary>
98 /// Moves the component from running to failed state.
99 /// </summary>
100 /// <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 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;
112 }
113
94 void Invoke(Commands cmd, Action action) {
114 void Invoke(Commands cmd, Action action) {
95 lock (m_stateMachine)
115 lock (m_stateMachine)
96 Move(cmd);
116 Move(cmd);
@@ -210,7 +230,6 namespace Implab.Components {
210
230
211 public ExecutionState State {
231 public ExecutionState State {
212 get {
232 get {
213 lock (m_stateMachine)
214 return m_stateMachine.State;
233 return m_stateMachine.State;
215 }
234 }
216 }
235 }
@@ -225,6 +244,18 namespace Implab.Components {
225
244
226 #region IDisposable implementation
245 #region IDisposable implementation
227
246
247 /// <summary>
248 /// Releases all resource used by the <see cref="Implab.Components.RunnableComponent"/> object.
249 /// </summary>
250 /// <remarks>
251 /// <para>Will not try to stop the component, it will just release all resources.
252 /// To cleanup the component gracefully use <see cref="Stop()"/> method.</para>
253 /// <para>
254 /// In normal cases the <see cref="Dispose()"/> method shouldn't be called, the call to the <see cref="Stop()"/>
255 /// method is sufficient to cleanup the component. Call <see cref="Dispose()"/> only to cleanup after errors,
256 /// especially if <see cref="Stop"/> method is failed. Using this method insted of <see cref="Stop()"/> may
257 /// lead to the data loss by the component.
258 /// </para></remarks>
228 public void Dispose() {
259 public void Dispose() {
229 IPromise pending;
260 IPromise pending;
230 lock (m_stateMachine) {
261 lock (m_stateMachine) {
@@ -194,7 +194,9
194 <Compile Include="Components\LazyAndWeak.cs" />
194 <Compile Include="Components\LazyAndWeak.cs" />
195 <Compile Include="AbstractTask.cs" />
195 <Compile Include="AbstractTask.cs" />
196 <Compile Include="AbstractTaskT.cs" />
196 <Compile Include="AbstractTaskT.cs" />
197 <Compile Include="Components\PollingRunnableComponent.cs" />
197 <Compile Include="FailedPromise.cs" />
198 <Compile Include="FailedPromiseT.cs" />
199 <Compile Include="Components\PollingComponent.cs" />
198 </ItemGroup>
200 </ItemGroup>
199 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
201 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
200 <ItemGroup />
202 <ItemGroup />
@@ -45,9 +45,7 namespace Implab {
45 }
45 }
46
46
47 public static IPromise<T> FromException(Exception error) {
47 public static IPromise<T> FromException(Exception error) {
48 var p = new Promise<T>();
48 return new FailedPromise<T>(error);
49 p.Reject(error);
50 return p;
51 }
49 }
52
50
53 public virtual void Resolve(T value) {
51 public virtual void Resolve(T value) {
@@ -67,55 +67,41 namespace Implab
67 }
67 }
68
68
69 [DebuggerStepThrough]
69 [DebuggerStepThrough]
70 public static IPromise<T> WrapPromise<T>(Func<T> action) {
70 public static IPromise<T> Run<T>(Func<T> action) {
71 ArgumentNotNull(action, "action");
72
73 var p = new Promise<T>();
74 try {
75 p.Resolve(action());
76 } catch (Exception err) {
77 p.Reject(err);
78 }
79
80 return p;
81 }
82
83 [DebuggerStepThrough]
84 public static IPromise WrapPromise(Action action) {
85 ArgumentNotNull(action, "action");
86
87 var p = new Promise();
88 try {
89 action();
90 p.Resolve();
91 } catch (Exception err) {
92 p.Reject(err);
93 }
94
95 return p;
96 }
97
98 [DebuggerStepThrough]
99 public static IPromise InvokePromise(Func<IPromise> action) {
100 ArgumentNotNull(action, "action");
71 ArgumentNotNull(action, "action");
101
72
102 try {
73 try {
103 var p = action();
74 return Promise<T>.FromResult(action());
104 if (p == null) {
105 var d = new Promise();
106 d.Reject(new Exception("The action returned null"));
107 p = d;
108 }
109 return p;
110 } catch (Exception err) {
75 } catch (Exception err) {
111 var p = new Promise();
76 return Promise<T>.FromException(err);
112 p.Reject(err);
113 return p;
114 }
77 }
115 }
78 }
116
79
117 [DebuggerStepThrough]
80 [DebuggerStepThrough]
118 public static IPromise<T> InvokePromise<T>(Func<IPromise<T>> action) {
81 public static IPromise Run(Action action) {
82 ArgumentNotNull(action, "action");
83
84 try {
85 action();
86 return Promise.SUCCESS;
87 } catch (Exception err) {
88 return new FailedPromise(err);
89 }
90 }
91
92 [DebuggerStepThrough]
93 public static IPromise Run(Func<IPromise> action) {
94 ArgumentNotNull(action, "action");
95
96 try {
97 return action() ?? new FailedPromise(new Exception("The action returned null"));
98 } catch (Exception err) {
99 return new FailedPromise(err);
100 }
101 }
102
103 [DebuggerStepThrough]
104 public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
119 ArgumentNotNull(action, "action");
105 ArgumentNotNull(action, "action");
120
106
121 try {
107 try {
@@ -8,16 +8,10 namespace Implab {
8 if (success != null) {
8 if (success != null) {
9 try {
9 try {
10 success();
10 success();
11 } catch(Exception err) {
12 if (error != null) {
13 try {
14 error(err);
15 // Analysis disable once EmptyGeneralCatchClause
11 // Analysis disable once EmptyGeneralCatchClause
16 } catch {
12 } catch {
17 }
13 }
18 }
14 }
19 }
20 }
21 return this;
15 return this;
22 }
16 }
23
17
@@ -25,16 +19,10 namespace Implab {
25 if (success != null) {
19 if (success != null) {
26 try {
20 try {
27 success();
21 success();
28 } catch(Exception err) {
29 if (error != null) {
30 try {
31 error(err);
32 // Analysis disable once EmptyGeneralCatchClause
22 // Analysis disable once EmptyGeneralCatchClause
33 } catch {
23 } catch {
34 }
24 }
35 }
25 }
36 }
37 }
38 return this;
26 return this;
39 }
27 }
40
28
@@ -12,16 +12,10 namespace Implab {
12 if (success != null) {
12 if (success != null) {
13 try {
13 try {
14 success(m_value);
14 success(m_value);
15 } catch(Exception err) {
16 if (error != null) {
17 try {
18 error(err);
19 // Analysis disable once EmptyGeneralCatchClause
15 // Analysis disable once EmptyGeneralCatchClause
20 } catch {
16 } catch {
21 }
17 }
22 }
18 }
23 }
24 }
25 return this;
19 return this;
26 }
20 }
27
21
@@ -29,16 +23,10 namespace Implab {
29 if (success != null) {
23 if (success != null) {
30 try {
24 try {
31 success(m_value);
25 success(m_value);
32 } catch(Exception err) {
33 if (error != null) {
34 try {
35 error(err);
36 // Analysis disable once EmptyGeneralCatchClause
26 // Analysis disable once EmptyGeneralCatchClause
37 } catch {
27 } catch {
38 }
28 }
39 }
29 }
40 }
41 }
42 return this;
30 return this;
43 }
31 }
44
32
@@ -65,16 +53,10 namespace Implab {
65 if (success != null) {
53 if (success != null) {
66 try {
54 try {
67 success();
55 success();
68 } catch(Exception err) {
69 if (error != null) {
70 try {
71 error(err);
72 // Analysis disable once EmptyGeneralCatchClause
56 // Analysis disable once EmptyGeneralCatchClause
73 } catch {
57 } catch {
74 }
58 }
75 }
59 }
76 }
77 }
78 return this;
60 return this;
79 }
61 }
80
62
@@ -82,16 +64,10 namespace Implab {
82 if (success != null) {
64 if (success != null) {
83 try {
65 try {
84 success();
66 success();
85 } catch(Exception err) {
86 if (error != null) {
87 try {
88 error(err);
89 // Analysis disable once EmptyGeneralCatchClause
67 // Analysis disable once EmptyGeneralCatchClause
90 } catch {
68 } catch {
91 }
69 }
92 }
70 }
93 }
94 }
95 return this;
71 return this;
96 }
72 }
97
73
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now