changeset 208:7d07503621fe v2

RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool) IRunnable is now disposable Code cleanups, suppressed some CodeAnalysis warnings
author cin
date Sun, 13 Nov 2016 18:28:17 +0300
parents 558f34b2fb50
children a867536c68fc
files Implab.Test/Mock/MockRunnableComponent.cs Implab.Test/RunnableComponentTests.cs Implab/Components/Disposable.cs Implab/Components/IRunnable.cs Implab/Components/PollingComponent.cs Implab/Components/RunnableComponent.cs Implab/Formats/JSON/JSONParser.cs Implab/Formats/JSON/JSONScanner.cs Implab/PromiseExtensions.cs
diffstat 9 files changed, 66 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/Implab.Test/Mock/MockRunnableComponent.cs	Wed Nov 09 12:03:22 2016 +0300
+++ b/Implab.Test/Mock/MockRunnableComponent.cs	Sun Nov 13 18:28:17 2016 +0300
@@ -24,7 +24,7 @@
             set;
         }
 
-        public Action<bool, Exception> MockDispose {
+        public Action<bool> MockDispose {
             get;
             set;
         }
@@ -42,10 +42,10 @@
                 MockInit();
         }
 
-        protected override void Dispose(bool disposing, Exception lastError) {
+        protected override void Dispose(bool disposing) {
             if (MockDispose != null)
-                MockDispose(disposing, lastError);
-            base.Dispose(disposing, lastError);
+                MockDispose(disposing);
+            base.Dispose(disposing);
         }
     }
 }
--- a/Implab.Test/RunnableComponentTests.cs	Wed Nov 09 12:03:22 2016 +0300
+++ b/Implab.Test/RunnableComponentTests.cs	Sun Nov 13 18:28:17 2016 +0300
@@ -95,7 +95,7 @@
             var comp = new MockRunnableComponent(true);
 
             bool disposed = false;
-            comp.MockDispose = (disposing, error) => {
+            comp.MockDispose = (disposing) => {
                 disposed = true;
             };
 
@@ -115,7 +115,7 @@
             var comp = new MockRunnableComponent(true, true);
 
             bool disposed = false;
-            comp.MockDispose = (disposing, error) => {
+            comp.MockDispose = (disposing) => {
                 disposed = true;
             };
 
@@ -131,10 +131,8 @@
             var comp = new MockRunnableComponent(true, true);
 
             bool disposed = false;
-            Exception lastError = null;
-            comp.MockDispose = (disposing, error) => {
+            comp.MockDispose = (disposing) => {
                 disposed = true;
-                lastError = error;
             };
 
             comp.Start().Join(1000);
--- a/Implab/Components/Disposable.cs	Wed Nov 09 12:03:22 2016 +0300
+++ b/Implab/Components/Disposable.cs	Sun Nov 13 18:28:17 2016 +0300
@@ -1,5 +1,6 @@
 using Implab.Diagnostics;
 using System;
+using System.Diagnostics.CodeAnalysis;
 using System.Threading;
 
 namespace Implab.Components {
@@ -81,6 +82,7 @@
             }
         }
 
+        [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Dipose(bool) and GC.SuppessFinalize are called")]
         public void Dispose() {
             if (Interlocked.Increment(ref m_disposed) == 1) {
                 Dispose(true);
--- a/Implab/Components/IRunnable.cs	Wed Nov 09 12:03:22 2016 +0300
+++ b/Implab/Components/IRunnable.cs	Sun Nov 13 18:28:17 2016 +0300
@@ -1,14 +1,22 @@
 using System;
 
 namespace Implab.Components {
-    public interface IRunnable {
+    /// <summary>
+    /// Interface for the component which performs a long running task.
+    /// </summary>
+    /// <remarks>
+    /// <para>The component also should implement <see cref="IDisposable"/> interface to be able to release used resources.</para>
+    /// <para>All methods of this interface must be a thread safe. If the operation is not applicable in the current state the
+    /// method should throw an exception and keep the current state unchanged.</para>
+    /// </remarks>
+    public interface IRunnable : IDisposable {
         /// <summary>
-        /// Starts this instance.
+        /// Starts this instance
         /// </summary>
         IPromise Start();
 
         /// <summary>
-        /// Stops this instance. After the instance is stopped it can't be started again, stopping should be treated as gracefull and async dispose.
+        /// Stops this instance, after the instance is stopped it can move to Failed, Ready or Disposed state, in case with the last it can't be reused.
         /// </summary>
         IPromise Stop();
 
--- a/Implab/Components/PollingComponent.cs	Wed Nov 09 12:03:22 2016 +0300
+++ b/Implab/Components/PollingComponent.cs	Sun Nov 13 18:28:17 2016 +0300
@@ -144,11 +144,11 @@
             return base.OnStop();
         }
 
-        protected override void Dispose(bool disposing, Exception lastError) {
+        protected override void Dispose(bool disposing) {
             if (disposing)
-                Safe.Dispose(m_timer);
+                m_timer.Dispose();
             
-            base.Dispose(disposing, lastError);
+            base.Dispose(disposing);
         }
     }
 }
--- a/Implab/Components/RunnableComponent.cs	Wed Nov 09 12:03:22 2016 +0300
+++ b/Implab/Components/RunnableComponent.cs	Sun Nov 13 18:28:17 2016 +0300
@@ -1,5 +1,6 @@
 using System;
-
+using System.Diagnostics.CodeAnalysis;
+
 namespace Implab.Components {
     public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable {
         enum Commands {
@@ -333,30 +334,22 @@
         /// especially if <see cref="Stop"/> method is failed. Using this method insted of <see cref="Stop()"/> may
         /// lead to the data loss by the component.
         /// </para></remarks>
+        [SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Dipose(bool) and GC.SuppessFinalize are called")]
         public void Dispose() {
             IPromise pending;
 
             lock (m_stateMachine) {
                 if (m_stateMachine.State == ExecutionState.Disposed)
                     return;
-                pending = Move(Commands.Dispose, null, null);
+                Move(Commands.Dispose, null, null);
             }
 
             GC.SuppressFinalize(this);
-            if (pending != null) {
-                pending.Cancel();
-                pending.Timeout(DisposeTimeout).On(
-                    () => Dispose(true, null),
-                    err => Dispose(true, err),
-                    reason => Dispose(true, new OperationCanceledException("The operation is cancelled", reason))
-                );
-            } else {
-                Dispose(true, null);
-            }
+            Dispose(true);
         }
 
         ~RunnableComponent() {
-            Dispose(false, null);
+            Dispose(false);
         }
 
         #endregion
@@ -365,8 +358,8 @@
         /// Releases all resources used by the component, called automatically, override this method to implement your cleanup.
         /// </summary>
         /// <param name="disposing">true if this method is called during normal dispose process.</param>
-        /// <param name="lastError">The last error which occured during the component stop.</param>
-        protected virtual void Dispose(bool disposing, Exception lastError) {
+        /// <param name="pending">The operation which is currenty pending</param>
+        protected virtual void Dispose(bool disposing) {
 
         }
 
--- a/Implab/Formats/JSON/JSONParser.cs	Wed Nov 09 12:03:22 2016 +0300
+++ b/Implab/Formats/JSON/JSONParser.cs	Sun Nov 13 18:28:17 2016 +0300
@@ -274,7 +274,7 @@
 
         protected override void Dispose(bool disposing) {
             if (disposing)
-                Safe.Dispose(m_scanner);
+                m_scanner.Dispose();
         }
 
         /// <summary>
--- a/Implab/Formats/JSON/JSONScanner.cs	Wed Nov 09 12:03:22 2016 +0300
+++ b/Implab/Formats/JSON/JSONScanner.cs	Sun Nov 13 18:28:17 2016 +0300
@@ -102,7 +102,7 @@
 
         protected override void Dispose(bool disposing) {
             if (disposing)
-                Safe.Dispose(m_scanner);
+                m_scanner.Dispose();
             base.Dispose(disposing);
         }
     }
--- a/Implab/PromiseExtensions.cs	Wed Nov 09 12:03:22 2016 +0300
+++ b/Implab/PromiseExtensions.cs	Sun Nov 13 18:28:17 2016 +0300
@@ -120,8 +120,12 @@
         }
 
         public static IPromise<T[]> PromiseAll<T>(this IEnumerable<IPromise<T>> that) {
+            return PromiseAll(that, null);
+        }
+
+        public static IPromise<T[]> PromiseAll<T>(this IEnumerable<IPromise<T>> that, Action<T> cleanup) {
             Safe.ArgumentNotNull(that, "that");
-            return PromiseAll(that.ToList());
+            return PromiseAll(that.ToList(), cleanup);
         }
 
         public static IPromise PromiseAll(this ICollection<IPromise> that) {
@@ -164,17 +168,35 @@
             return medium;
         }
 
-        public static IPromise<T[]> PromiseAll<T>(this ICollection<IPromise<T>> that) {
+        public static IPromise<T[]> PromiseAll<T>(this ICollection<IPromise<T>> that) {
+            return PromiseAll(that, null);
+        }
+
+        /// <summary>
+        /// Creates a new promise which will be satisfied when all promises are satisfied.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="that"></param>
+        /// <param name="cleanup">A callback used to cleanup already resolved promises in case of an error</param>
+        /// <returns></returns>
+        public static IPromise<T[]> PromiseAll<T>(this ICollection<IPromise<T>> that, Action<T> cleanup) {
             Safe.ArgumentNotNull(that, "that");
+            
+            int count = that.Count;
 
-            int count = that.Count;
+            if (count == 0)
+                return Promise<T[]>.FromResult(new T[0]);
+
             int errors = 0;
             var medium = new Promise<T[]>();
             var results = new T[that.Count];
 
             medium.On(() => {
-                foreach (var p2 in that)
-                    p2.Cancel();
+                foreach (var p2 in that) {
+                    p2.Cancel();
+                    if (cleanup != null)
+                        p2.On(cleanup);
+                }
             }, PromiseEventType.ErrorOrCancel);
 
             int i = 0;
@@ -414,6 +436,12 @@
             return new PromiseAwaiter<T>(that);
         }
 
+        public static PromiseAwaiter GetAwaiter(this IPromise that) {
+            Safe.ArgumentNotNull(that, "that");
+
+            return new PromiseAwaiter(that);
+        }
+
 #endif
     }
 }