##// END OF EJS Templates
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin -
r196:40d7fed4a09e default
parent child
Show More
@@ -1,195 +1,195
1 1 using System;
2 2 using System.Reflection;
3 3 using System.Threading;
4 4 using Implab.Parallels;
5 5 using Implab.Components;
6 6
7 7 #if MONO
8 8
9 9 using NUnit.Framework;
10 10 using TestClassAttribute = NUnit.Framework.TestFixtureAttribute;
11 11 using TestMethodAttribute = NUnit.Framework.TestAttribute;
12 12 using AssertFailedException = NUnit.Framework.AssertionException;
13 13 #else
14 14
15 15 using Microsoft.VisualStudio.TestTools.UnitTesting;
16 16
17 17 #endif
18 18
19 19 namespace Implab.Test {
20 20 [TestClass]
21 21 public class RunnableComponentTests {
22 22
23 23 static void ShouldThrow(Action action) {
24 24 try {
25 25 action();
26 26 Assert.Fail();
27 27 } catch (AssertFailedException) {
28 28 throw;
29 29 } catch {
30 30 }
31 31 }
32 32
33 33 class Runnable : RunnableComponent {
34 34 public Runnable(bool initialized) : base(initialized) {
35 35 }
36 36
37 37 public Action MockInit {
38 38 get;
39 39 set;
40 40 }
41 41
42 42 public Func<IPromise> MockStart {
43 43 get;
44 44 set;
45 45 }
46 46
47 47 public Func<IPromise> MockStop {
48 48 get;
49 49 set;
50 50 }
51 51
52 52 protected override IPromise OnStart() {
53 53 return MockStart != null ? MockStart() : base.OnStart();
54 54 }
55 55
56 56 protected override IPromise OnStop() {
57 57 return MockStop != null ? MockStop() : base.OnStart();
58 58 }
59 59
60 60 protected override void OnInitialize() {
61 61 if (MockInit != null)
62 62 MockInit();
63 63 }
64 64 }
65 65
66 66 [TestMethod]
67 67 public void NormalFlowTest() {
68 68 var comp = new Runnable(false);
69 69
70 70 Assert.AreEqual(ExecutionState.Created, comp.State);
71 71
72 72 comp.Init();
73 73
74 74 Assert.AreEqual(ExecutionState.Ready, comp.State);
75 75
76 76 comp.Start().Join(1000);
77 77
78 78 Assert.AreEqual(ExecutionState.Running, comp.State);
79 79
80 80 comp.Stop().Join(1000);
81 81
82 82 Assert.AreEqual(ExecutionState.Disposed, comp.State);
83 83
84 84 }
85 85
86 86 [TestMethod]
87 87 public void InitFailTest() {
88 88 var comp = new Runnable(false) {
89 89 MockInit = () => {
90 90 throw new Exception("BAD");
91 91 }
92 92 };
93 93
94 94 ShouldThrow(() => comp.Start());
95 95 ShouldThrow(() => comp.Stop());
96 96 Assert.AreEqual(ExecutionState.Created, comp.State);
97 97
98 98 ShouldThrow(comp.Init);
99 99
100 100 Assert.AreEqual(ExecutionState.Failed, comp.State);
101 101
102 102 ShouldThrow(() => comp.Start());
103 103 ShouldThrow(() => comp.Stop());
104 104 Assert.AreEqual(ExecutionState.Failed, comp.State);
105 105
106 106 comp.Dispose();
107 107 Assert.AreEqual(ExecutionState.Disposed, comp.State);
108 108 }
109 109
110 110 [TestMethod]
111 111 public void DisposedTest() {
112 112
113 113 var comp = new Runnable(false);
114 114 comp.Dispose();
115 115
116 116 ShouldThrow(() => comp.Start());
117 117 ShouldThrow(() => comp.Stop());
118 118 ShouldThrow(comp.Init);
119 119
120 120 Assert.AreEqual(ExecutionState.Disposed, comp.State);
121 121 }
122 122
123 123 [TestMethod]
124 124 public void StartCancelTest() {
125 125 var comp = new Runnable(true) {
126 126 MockStart = () => PromiseHelper.Sleep(100000, 0)
127 127 };
128 128
129 129 var p = comp.Start();
130 130 Assert.AreEqual(ExecutionState.Starting, comp.State);
131 131 p.Cancel();
132 132 ShouldThrow(() => p.Join(1000));
133 133 Assert.AreEqual(ExecutionState.Failed, comp.State);
134 134
135 Assert.IsInstanceOfType(comp.LastError, typeof(OperationCanceledException));
135 Assert.IsTrue(comp.LastError is OperationCanceledException);
136 136
137 137 comp.Dispose();
138 138 }
139 139
140 140 [TestMethod]
141 141 public void StartStopTest() {
142 142 var stop = new Signal();
143 143 var comp = new Runnable(true) {
144 144 MockStart = () => PromiseHelper.Sleep(100000, 0),
145 145 MockStop = () => AsyncPool.RunThread(stop.Wait)
146 146 };
147 147
148 148 var p1 = comp.Start();
149 149 var p2 = comp.Stop();
150 150 // should enter stopping state
151 151
152 152 ShouldThrow(p1.Join);
153 153 Assert.IsTrue(p1.IsCancelled);
154 154 Assert.AreEqual(ExecutionState.Stopping, comp.State);
155 155
156 156 stop.Set();
157 157 p2.Join(1000);
158 158 Assert.AreEqual(ExecutionState.Disposed, comp.State);
159 159 }
160 160
161 161 [TestMethod]
162 162 public void StartStopFailTest() {
163 163 var comp = new Runnable(true) {
164 164 MockStart = () => PromiseHelper.Sleep(100000, 0).Then(null,null,x => { throw new Exception("I'm dead"); })
165 165 };
166 166
167 167 comp.Start();
168 168 var p = comp.Stop();
169 169 // if Start fails to cancel, should fail to stop
170 170 ShouldThrow(() => p.Join(1000));
171 171 Assert.AreEqual(ExecutionState.Failed, comp.State);
172 172 Assert.IsNotNull(comp.LastError);
173 173 Assert.AreEqual("I'm dead", comp.LastError.Message);
174 174 }
175 175
176 176 [TestMethod]
177 177 public void StopCancelTest() {
178 178 var comp = new Runnable(true) {
179 179 MockStop = () => PromiseHelper.Sleep(100000, 0)
180 180 };
181 181
182 182 comp.Start();
183 183 var p = comp.Stop();
184 184 Assert.AreEqual(ExecutionState.Stopping, comp.State);
185 185 p.Cancel();
186 186 ShouldThrow(() => p.Join(1000));
187 187 Assert.AreEqual(ExecutionState.Failed, comp.State);
188 Assert.IsInstanceOfType(comp.LastError, typeof(OperationCanceledException));
188 Assert.IsTrue(comp.LastError is OperationCanceledException);
189 189
190 190 comp.Dispose();
191 191 }
192 192
193 193 }
194 194 }
195 195
@@ -1,36 +1,34
1 1 using System;
2 2
3 3 namespace Implab {
4 4 public class ActionChainTask : ActionChainTaskBase, IDeferred {
5 5 readonly Func<IPromise> m_task;
6 6
7 7 /// <summary>
8 8 /// Initializes a new instance of the <see cref="Implab.ActionChainTask"/> class.
9 9 /// </summary>
10 10 /// <param name="task">The operation which will be performed when the <see cref="Resolve()"/> is called.</param>
11 11 /// <param name="error">The error handler which will invoke when the <see cref="Reject(Exception)"/> is called or when the task fails with an error.</param>
12 12 /// <param name="cancel">The cancellation handler.</param>
13 13 /// <param name="autoCancellable">If set to <c>true</c> will automatically accept
14 14 /// all cancel requests before the task is started with <see cref="Resolve()"/>,
15 15 /// after that all requests are directed to the task.</param>
16 16 public ActionChainTask(Func<IPromise> task, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
17 17 m_task = task;
18 18 }
19 19
20 20 public void Resolve() {
21 21 if (m_task != null && LockCancelation()) {
22 22 try {
23 23 var p = m_task();
24 24 p.On(SetResult, HandleErrorInternal, HandleCancelInternal);
25 25 CancellationRequested(p.Cancel);
26 } catch (OperationCanceledException reason){
27 HandleCancelInternal(reason);
28 26 } catch(Exception err) {
29 HandleErrorInternal(err);
27 SetErrorInternal(err);
30 28 }
31 29 }
32 30 }
33 31
34 32 }
35 33 }
36 34
@@ -1,62 +1,62
1 1 using System;
2 2 using System.Threading;
3 3
4 4 namespace Implab {
5 5 public class ActionChainTaskBase : AbstractTask {
6 6 readonly Func<Exception, IPromise> m_error;
7 7 readonly Func<Exception, IPromise> m_cancel;
8 8
9 9 protected ActionChainTaskBase(Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) {
10 10 m_error = error;
11 11 m_cancel = cancel;
12 12 if (autoCancellable)
13 13 CancellationRequested(CancelOperation);
14 14 }
15 15
16 16 public void Reject(Exception error) {
17 17 if (LockCancelation())
18 18 HandleErrorInternal(error);
19 19 }
20 20
21 21 public override void CancelOperation(Exception reason) {
22 22 if (LockCancelation())
23 23 // отмена вызвана до начала выполнения задачи
24 24 HandleCancelInternal(reason);
25 25 }
26 26
27 27 protected void HandleCancelInternal(Exception reason) {
28 28 if (m_cancel != null) {
29 29 try {
30 30 // вызываем обработчик отмены
31 31 var p = m_cancel(reason);
32 32 p.On(SetResult, HandleErrorInternal, SetCancelledInternal);
33 33 // сообщаем асинхронной операции, что клиент уже не хочет получать результат
34 34 // т.е. если он инициировал отмену, задача отменилась, вызвался обрабочик отмены
35 35 // отбработчику сообщили, что результат уже не нужен и уже сам обработчик решает
36 36 // отдавать ли результат или подтвердить отмену (или вернуть ошибку).
37 37 CancellationRequested(p.Cancel);
38 38 } catch (Exception err) {
39 HandleErrorInternal(err);
39 SetErrorInternal(err);
40 40 }
41 41 } else {
42 HandleErrorInternal(reason ?? new OperationCanceledException());
42 SetCancelledInternal(reason);
43 43 }
44 44 }
45 45
46 46 protected void HandleErrorInternal(Exception error) {
47 47 if (m_error != null) {
48 48 try {
49 49 var p = m_error(error);
50 50 p.On(SetResult, SetErrorInternal, SetCancelledInternal);
51 51 CancellationRequested(p.Cancel);
52 52 } catch (Exception err) {
53 53 SetErrorInternal(error);
54 54 }
55 55 } else {
56 56 SetErrorInternal(error);
57 57 }
58 58 }
59 59
60 60 }
61 61 }
62 62
@@ -1,27 +1,25
1 1 using System;
2 2
3 3 namespace Implab {
4 4 public class ActionChainTask<T> : ActionChainTaskBase, IDeferred<T> {
5 5 readonly Func<T, IPromise> m_task;
6 6
7 7 public ActionChainTask(Func<T, IPromise> task, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
8 8 m_task = task;
9 9 }
10 10
11 11 public void Resolve(T value) {
12 12 if (m_task != null && LockCancelation()) {
13 13 try {
14 14 var p = m_task(value);
15 15 p.On(SetResult, HandleErrorInternal, HandleCancelInternal);
16 16 CancellationRequested(p.Cancel);
17 } catch (OperationCanceledException reason) {
18 HandleCancelInternal(reason);
19 17 } catch(Exception err) {
20 HandleErrorInternal(err);
18 SetErrorInternal(err);
21 19 }
22 20 }
23 21 }
24 22
25 23 }
26 24 }
27 25
@@ -1,24 +1,22
1 1 using System;
2 2
3 3 namespace Implab {
4 4 public class ActionTask : ActionTaskBase, IDeferred {
5 5 readonly Action m_task;
6 6 public ActionTask(Action task, Action<Exception> error, Action<Exception> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
7 7 m_task = task;
8 8 }
9 9
10 10 public void Resolve() {
11 11 if (m_task != null && LockCancelation()) {
12 12 try {
13 13 m_task();
14 14 SetResult();
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
17 15 } catch(Exception err) {
18 HandleErrorInternal(err);
16 SetErrorInternal(err);
19 17 }
20 18 }
21 19 }
22 20 }
23 21 }
24 22
@@ -1,53 +1,53
1 1 using System;
2 2
3 3 namespace Implab {
4 4 public class ActionTaskBase : AbstractTask {
5 5 readonly Action<Exception> m_cancel;
6 6 readonly Action<Exception> m_error;
7 7
8 8 protected ActionTaskBase( Action<Exception> error, Action<Exception> cancel, bool autoCancellable) {
9 9 m_error = error;
10 10 m_cancel = cancel;
11 11 if (autoCancellable)
12 12 CancellationRequested(CancelOperation);
13 13 }
14 14
15 15 public void Reject(Exception error) {
16 16 Safe.ArgumentNotNull(error, "error");
17 17 if (LockCancelation())
18 18 HandleErrorInternal(error);
19 19 }
20 20
21 21 public override void CancelOperation(Exception reason) {
22 22 if (LockCancelation())
23 23 HandleCancelInternal(reason);
24 24 }
25 25
26 26 protected void HandleErrorInternal(Exception error) {
27 27 if (m_error != null) {
28 28 try {
29 29 m_error(error);
30 30 SetResult();
31 31 } catch(Exception err) {
32 32 SetErrorInternal(err);
33 33 }
34 34 } else {
35 35 SetErrorInternal(error);
36 36 }
37 37 }
38 38
39 39 protected void HandleCancelInternal(Exception error) {
40 40 if (m_cancel != null) {
41 41 try {
42 42 m_cancel(error);
43 43 SetResult();
44 44 } catch(Exception err) {
45 HandleErrorInternal(err);
45 SetErrorInternal(err);
46 46 }
47 47 } else {
48 HandleErrorInternal(error ?? new OperationCanceledException());
48 SetCancelledInternal(error);
49 49 }
50 50 }
51 51 }
52 52 }
53 53
@@ -1,24 +1,22
1 1 using System;
2 2
3 3 namespace Implab {
4 4 public class ActionTask<T> : ActionTaskBase, IDeferred<T> {
5 5 readonly Action<T> m_task;
6 6 public ActionTask(Action<T> task, Action<Exception> error, Action<Exception> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
7 7 m_task = task;
8 8 }
9 9
10 10 public void Resolve(T value) {
11 11 if (m_task != null && LockCancelation()) {
12 12 try {
13 13 m_task(value);
14 14 SetResult();
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
17 15 } catch(Exception err) {
18 HandleErrorInternal(err);
16 SetErrorInternal(err);
19 17 }
20 18 }
21 19 }
22 20 }
23 21 }
24 22
@@ -1,257 +1,264
1 1 using System;
2 2
3 3 namespace Implab.Components {
4 4 public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable {
5 5 enum Commands {
6 6 Ok = 0,
7 7 Fail,
8 8 Init,
9 9 Start,
10 10 Stop,
11 11 Dispose,
12 12 Last = Dispose
13 13 }
14 14
15 15 class StateMachine {
16 16 static readonly ExecutionState[,] _transitions;
17 17
18 18 static StateMachine() {
19 19 _transitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
20 20
21 21 Edge(ExecutionState.Created, ExecutionState.Initializing, Commands.Init);
22 22 Edge(ExecutionState.Created, ExecutionState.Disposed, Commands.Dispose);
23 23
24 24 Edge(ExecutionState.Initializing, ExecutionState.Ready, Commands.Ok);
25 25 Edge(ExecutionState.Initializing, ExecutionState.Failed, Commands.Fail);
26 26
27 27 Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start);
28 28 Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose);
29 29
30 30 Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok);
31 31 Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail);
32 32 Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop);
33 33 Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose);
34 34
35 35 Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail);
36 36 Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop);
37 37 Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose);
38 38
39 39 Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail);
40 40 Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok);
41 41
42 42 Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose);
43 43 }
44 44
45 45 static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
46 46 _transitions[(int)s1, (int)cmd] = s2;
47 47 }
48 48
49 49 public ExecutionState State {
50 50 get;
51 51 private set;
52 52 }
53 53
54 54 public StateMachine(ExecutionState initial) {
55 55 State = initial;
56 56 }
57 57
58 58 public bool Move(Commands cmd) {
59 59 var next = _transitions[(int)State, (int)cmd];
60 60 if (next == ExecutionState.Undefined)
61 61 return false;
62 62 State = next;
63 63 return true;
64 64 }
65 65 }
66 66
67 67 IPromise m_pending;
68 68 Exception m_lastError;
69 69
70 70 readonly StateMachine m_stateMachine;
71 71
72 72 protected RunnableComponent(bool initialized) {
73 73 m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created);
74 74 }
75 75
76 76 protected virtual int DisposeTimeout {
77 77 get {
78 78 return 10000;
79 79 }
80 80 }
81 81
82 82 void ThrowInvalidCommand(Commands cmd) {
83 83 if (m_stateMachine.State == ExecutionState.Disposed)
84 84 throw new ObjectDisposedException(ToString());
85 85
86 86 throw new InvalidOperationException(String.Format("Commnd {0} is not allowed in the state {1}", cmd, m_stateMachine.State));
87 87 }
88 88
89 89 void Move(Commands cmd) {
90 90 if (!m_stateMachine.Move(cmd))
91 91 ThrowInvalidCommand(cmd);
92 92 }
93 93
94 94 void Invoke(Commands cmd, Action action) {
95 95 lock (m_stateMachine)
96 96 Move(cmd);
97 97
98 98 try {
99 99 action();
100 100 lock(m_stateMachine)
101 101 Move(Commands.Ok);
102 102
103 103 } catch (Exception err) {
104 104 lock (m_stateMachine) {
105 105 Move(Commands.Fail);
106 106 m_lastError = err;
107 107 }
108 108 throw;
109 109 }
110 110 }
111 111
112 112 IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) {
113 113 IPromise promise = null;
114 114 IPromise prev;
115 115
116 116 var task = new ActionChainTask(action, null, null, true);
117 117
118 118 lock (m_stateMachine) {
119 119 Move(cmd);
120 120
121 121 prev = m_pending;
122 122
123 Action<Exception> errorOrCancel = e => {
124 if (e == null)
125 e = new OperationCanceledException();
126
127 lock (m_stateMachine) {
128 if (m_pending == promise) {
129 Move(Commands.Fail);
130 m_pending = null;
131 m_lastError = e;
132 }
133 }
134 throw new PromiseTransientException(e);
135 };
136
123 137 promise = task.Then(
124 138 () => {
125 139 lock(m_stateMachine) {
126 140 if (m_pending == promise) {
127 141 Move(Commands.Ok);
128 142 m_pending = null;
129 143 }
130 144 }
131 }, e => {
132 lock(m_stateMachine) {
133 if (m_pending == promise) {
134 Move(Commands.Fail);
135 m_pending = null;
136 m_lastError = e;
137 }
138 }
139 throw new PromiseTransientException(e);
140 }
145 },
146 errorOrCancel,
147 errorOrCancel
141 148 );
142 149
143 150 m_pending = promise;
144 151 }
145 152
146 153 if (prev == null)
147 154 task.Resolve();
148 155 else
149 156 chain(prev, task);
150 157
151 158 return promise;
152 159 }
153 160
154 161
155 162 #region IInitializable implementation
156 163
157 164 public void Init() {
158 165 Invoke(Commands.Init, OnInitialize);
159 166 }
160 167
161 168 protected virtual void OnInitialize() {
162 169 }
163 170
164 171 #endregion
165 172
166 173 #region IRunnable implementation
167 174
168 175 public IPromise Start() {
169 176 return InvokeAsync(Commands.Start, OnStart, null);
170 177 }
171 178
172 179 protected virtual IPromise OnStart() {
173 180 return Promise.SUCCESS;
174 181 }
175 182
176 183 public IPromise Stop() {
177 184 return InvokeAsync(Commands.Stop, OnStop, StopPending).Then(Dispose);
178 185 }
179 186
180 187 protected virtual IPromise OnStop() {
181 188 return Promise.SUCCESS;
182 189 }
183 190
184 191 /// <summary>
185 192 /// Stops the current operation if one exists.
186 193 /// </summary>
187 194 /// <param name="current">Current.</param>
188 195 /// <param name="stop">Stop.</param>
189 196 protected virtual void StopPending(IPromise current, IDeferred stop) {
190 197 if (current == null) {
191 198 stop.Resolve();
192 199 } else {
193 200 // связваем текущую операцию с операцией остановки
194 201 current.On(
195 202 stop.Resolve, // если текущая операция заверщилась, то можно начинать остановку
196 203 stop.Reject, // если текущая операция дала ошибку - то все плохо, нельзя продолжать
197 204 e => stop.Resolve() // если текущая отменилась, то можно начинать остановку
198 205 );
199 206 // посылаем текущей операции сигнал остановки
200 207 current.Cancel();
201 208 }
202 209 }
203 210
204 211 public ExecutionState State {
205 212 get {
206 213 return m_stateMachine.State;
207 214 }
208 215 }
209 216
210 217 public Exception LastError {
211 218 get {
212 219 return m_lastError;
213 220 }
214 221 }
215 222
216 223 #endregion
217 224
218 225 #region IDisposable implementation
219 226
220 227 public void Dispose() {
221 228 IPromise pending;
222 229 lock (m_stateMachine) {
223 230 if (m_stateMachine.State == ExecutionState.Disposed)
224 231 return;
225 232
226 233 Move(Commands.Dispose);
227 234
228 235 GC.SuppressFinalize(this);
229 236
230 237 pending = m_pending;
231 238 m_pending = null;
232 239 }
233 240 if (pending != null) {
234 241 pending.Cancel();
235 242 pending.Timeout(DisposeTimeout).On(
236 243 () => Dispose(true, null),
237 244 err => Dispose(true, err),
238 245 reason => Dispose(true, new OperationCanceledException("The operation is cancelled", reason))
239 246 );
240 247 } else {
241 248 Dispose(true, m_lastError);
242 249 }
243 250 }
244 251
245 252 ~RunnableComponent() {
246 253 Dispose(false, null);
247 254 }
248 255
249 256 #endregion
250 257
251 258 protected virtual void Dispose(bool disposing, Exception lastError) {
252 259
253 260 }
254 261
255 262 }
256 263 }
257 264
@@ -1,26 +1,24
1 1 using System;
2 2
3 3 namespace Implab {
4 4 public class FuncChainTask<TResult> : FuncChainTaskBase<TResult>, IDeferred {
5 5 readonly Func<IPromise<TResult>> m_task;
6 6
7 7 public FuncChainTask(Func<IPromise<TResult>> task, Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable)
8 8 : base(error, cancel, autoCancellable) {
9 9 m_task = task;
10 10 }
11 11
12 12 public void Resolve() {
13 13 if (m_task != null && LockCancelation()) {
14 14 try {
15 15 var operation = m_task();
16 16 operation.On(SetResult, HandleErrorInternal, HandleCancelInternal);
17 17 CancellationRequested(operation.Cancel);
18 } catch (OperationCanceledException reason) {
19 HandleCancelInternal(reason);
20 18 } catch (Exception err) {
21 HandleErrorInternal(err);
19 SetErrorInternal(err);
22 20 }
23 21 }
24 22 }
25 23 }
26 24 } No newline at end of file
@@ -1,54 +1,54
1 1 using System;
2 2
3 3 namespace Implab {
4 4 public class FuncChainTaskBase<TResult> : AbstractTask<TResult> {
5 5 readonly Func<Exception, IPromise<TResult>> m_error;
6 6 readonly Func<Exception, IPromise<TResult>> m_cancel;
7 7
8 8 protected FuncChainTaskBase( Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable) {
9 9 m_error = error;
10 10 m_cancel = cancel;
11 11 if (autoCancellable)
12 12 CancellationRequested(CancelOperation);
13 13 }
14 14
15 15 public void Reject(Exception error) {
16 16 if (LockCancelation())
17 17 HandleErrorInternal(error);
18 18 }
19 19
20 20 public override void CancelOperation(Exception reason) {
21 21 if (LockCancelation())
22 22 HandleCancelInternal(reason);
23 23 }
24 24
25 25 protected void HandleErrorInternal(Exception error) {
26 26 if (m_error != null) {
27 27 try {
28 28 var p = m_error(error);
29 29 p.On(SetResult, SetErrorInternal, SetCancelledInternal);
30 30 CancellationRequested(p.Cancel);
31 31 } catch(Exception err) {
32 32 SetErrorInternal(err);
33 33 }
34 34 } else {
35 35 SetErrorInternal(error);
36 36 }
37 37 }
38 38
39 39 protected void HandleCancelInternal(Exception reason) {
40 40 if (m_cancel != null) {
41 41 try {
42 42 var p = m_cancel(reason);
43 43 p.On(SetResult, HandleErrorInternal, SetCancelledInternal);
44 44 CancellationRequested(p.Cancel);
45 45 } catch (Exception err) {
46 HandleErrorInternal(err);
46 SetErrorInternal(err);
47 47 }
48 48 } else {
49 HandleErrorInternal(reason ?? new OperationCanceledException());
49 SetCancelledInternal(reason);
50 50 }
51 51 }
52 52 }
53 53 }
54 54
@@ -1,25 +1,23
1 1 using System;
2 2
3 3 namespace Implab {
4 4 public class FuncChainTask<TArg,TResult> : FuncChainTaskBase<TResult>, IDeferred<TArg> {
5 5 readonly Func<TArg, IPromise<TResult>> m_task;
6 6
7 7 public FuncChainTask(Func<TArg, IPromise<TResult>> task, Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable) : base(error, cancel, autoCancellable){
8 8 m_task = task;
9 9 }
10 10
11 11 public void Resolve(TArg value) {
12 12 if (m_task != null && LockCancelation()) {
13 13 try {
14 14 var operation = m_task(value);
15 15 operation.On(SetResult, HandleErrorInternal, SetCancelled);
16 16 CancellationRequested(operation.Cancel);
17 } catch (OperationCanceledException reason) {
18 HandleCancelInternal(reason);
19 17 } catch (Exception err) {
20 HandleErrorInternal(err);
18 SetErrorInternal(err);
21 19 }
22 20 }
23 21 }
24 22 }
25 23 } No newline at end of file
@@ -1,25 +1,23
1 1 using System;
2 2 using System.Threading;
3 3
4 4 namespace Implab {
5 5 public class FuncTask<T> : FuncTaskBase<T>, IDeferred {
6 6 readonly Func<T> m_task;
7 7
8 8 public FuncTask(Func<T> task, Func<Exception, T> error, Func<Exception, T> cancel, bool autoCancellable) : base(error, cancel, autoCancellable) {
9 9 m_task = task;
10 10 }
11 11
12 12 public void Resolve() {
13 13 if (m_task != null && LockCancelation()) {
14 14 try {
15 15 SetResult(m_task());
16 } catch(OperationCanceledException reason) {
17 HandleCancelInternal(reason);
18 16 } catch(Exception err) {
19 HandleErrorInternal(err);
17 SetErrorInternal(err);
20 18 }
21 19 }
22 20 }
23 21 }
24 22 }
25 23
@@ -1,52 +1,52
1 1 using System;
2 2
3 3 namespace Implab {
4 4 public class FuncTaskBase<TResult> : AbstractTask<TResult> {
5 5 readonly Func<Exception, TResult> m_cancel;
6 6 readonly Func<Exception, TResult> m_error;
7 7
8 8 protected FuncTaskBase( Func<Exception, TResult> error, Func<Exception, TResult> cancel, bool autoCancellable) {
9 9 m_error = error;
10 10 m_cancel = cancel;
11 11 if (autoCancellable)
12 12 CancellationRequested(CancelOperation);
13 13 }
14 14
15 15 public void Reject(Exception error) {
16 16 Safe.ArgumentNotNull(error, "error");
17 17 if (LockCancelation())
18 18 HandleErrorInternal(error);
19 19 }
20 20
21 21 protected void HandleErrorInternal(Exception error) {
22 22 if (m_error != null) {
23 23 try {
24 24 SetResult(m_error(error));
25 25 } catch(Exception err) {
26 26 SetErrorInternal(err);
27 27 }
28 28 } else {
29 29 SetErrorInternal(error);
30 30 }
31 31 }
32 32
33 33 public override void CancelOperation(Exception reason) {
34 34 if (LockCancelation())
35 35 HandleCancelInternal(reason);
36 36 }
37 37
38 38 protected void HandleCancelInternal(Exception reason) {
39 39 if (m_cancel != null) {
40 40 try {
41 41 SetResult(m_cancel(reason));
42 42 } catch (Exception err) {
43 HandleErrorInternal(err);
43 SetErrorInternal(err);
44 44 }
45 45 } else {
46 HandleErrorInternal(reason ?? new OperationCanceledException());
46 SetCancelledInternal(reason);
47 47 }
48 48 }
49 49
50 50 }
51 51 }
52 52
@@ -1,24 +1,22
1 1 using System;
2 2
3 3 namespace Implab {
4 4 public class FuncTask<TArg, TResult> : FuncTaskBase<TResult>, IDeferred<TArg> {
5 5 readonly Func<TArg, TResult> m_task;
6 6
7 7 public FuncTask(Func<TArg, TResult> task, Func<Exception, TResult> error,Func<Exception, TResult> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
8 8 m_task = task;
9 9 }
10 10
11 11 public void Resolve(TArg value) {
12 12 if (m_task != null && LockCancelation()) {
13 13 try {
14 14 SetResult(m_task(value));
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
17 15 } catch(Exception err) {
18 HandleErrorInternal(err);
16 SetErrorInternal(err);
19 17 }
20 18 }
21 19 }
22 20 }
23 21 }
24 22
General Comments 0
You need to be logged in to leave comments. Login now